]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/pass3.c
libext2fs: use the rbtree bitmap by default when initializing a file system
[thirdparty/e2fsprogs.git] / e2fsck / pass3.c
CommitLineData
3839e657
TT
1/*
2 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
3 *
c1faf9cc 4 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
21c84b71
TT
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
efc6f628 10 *
3839e657
TT
11 * Pass #3 assures that all directories are connected to the
12 * filesystem tree, using the following algorithm:
13 *
14 * First, the root directory is checked to make sure it exists; if
15 * not, e2fsck will offer to create a new one. It is then marked as
16 * "done".
efc6f628 17 *
3839e657
TT
18 * Then, pass3 interates over all directory inodes; for each directory
19 * it attempts to trace up the filesystem tree, using dirinfo.parent
20 * until it reaches a directory which has been marked "done". If it
21 * can not do so, then the directory must be disconnected, and e2fsck
22 * will offer to reconnect it to /lost+found. While it is chasing
23 * parent pointers up the filesystem tree, if pass3 sees a directory
24 * twice, then it has detected a filesystem loop, and it will again
25 * offer to reconnect the directory to /lost+found in to break the
26 * filesystem loop.
efc6f628 27 *
08b21301
TT
28 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
29 * reconnect inodes to /lost+found; this subroutine is also used by
30 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
31 * is responsible for creating /lost+found if it does not exist.
3839e657
TT
32 *
33 * Pass 3 frees the following data structures:
34 * - The dirinfo directory information cache.
35 */
36
d1154eb4 37#include "config.h"
50e1e10f
TT
38#ifdef HAVE_ERRNO_H
39#include <errno.h>
40#endif
3839e657
TT
41
42#include "e2fsck.h"
21c84b71 43#include "problem.h"
3839e657 44
1b6bf175 45static void check_root(e2fsck_t ctx);
28db82a8 46static int check_directory(e2fsck_t ctx, ext2_ino_t ino,
28ffafb0 47 struct problem_context *pctx);
28db82a8 48static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
3839e657 49
a02ce9df
TT
50static ext2fs_inode_bitmap inode_loop_detect = 0;
51static ext2fs_inode_bitmap inode_done_map = 0;
efc6f628 52
08b21301 53void e2fsck_pass3(e2fsck_t ctx)
3839e657 54{
1b6bf175 55 ext2_filsys fs = ctx->fs;
28db82a8 56 struct dir_info_iter *iter;
8bf191e8 57#ifdef RESOURCE_TRACK
3839e657 58 struct resource_track rtrack;
8bf191e8 59#endif
21c84b71
TT
60 struct problem_context pctx;
61 struct dir_info *dir;
7f813ba3 62 unsigned long maxdirs, count;
f8188fff 63
6d96b00d 64 init_resource_track(&rtrack, ctx->fs->io);
1b6bf175
TT
65 clear_problem_context(&pctx);
66
3839e657
TT
67#ifdef MTRACE
68 mtrace_print("Pass 3");
69#endif
70
1b6bf175
TT
71 if (!(ctx->options & E2F_OPT_PREEN))
72 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
3839e657
TT
73
74 /*
75 * Allocate some bitmaps to do loop detection.
76 */
0c4a0726 77 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
1b6bf175
TT
78 &inode_done_map);
79 if (pctx.errcode) {
80 pctx.num = 2;
81 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
08b21301 82 ctx->flags |= E2F_FLAG_ABORT;
a02ce9df 83 goto abort_exit;
3839e657 84 }
9facd076 85 print_resource_track(ctx, _("Peak memory"), &ctx->global_rtrack, NULL);
3839e657 86
1b6bf175 87 check_root(ctx);
a02ce9df
TT
88 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
89 goto abort_exit;
08b21301 90
c5d2f50d 91 ext2fs_mark_inode_bitmap2(inode_done_map, EXT2_ROOT_INO);
3839e657 92
7f813ba3 93 maxdirs = e2fsck_get_num_dirinfo(ctx);
f75c28de 94 count = 1;
f8188fff 95
f75c28de 96 if (ctx->progress)
7f813ba3 97 if ((ctx->progress)(ctx, 3, 0, maxdirs))
f75c28de 98 goto abort_exit;
efc6f628 99
28db82a8
TT
100 iter = e2fsck_dir_info_iter_begin(ctx);
101 while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) {
4cae0452
TT
102 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
103 goto abort_exit;
104 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
105 goto abort_exit;
c5d2f50d 106 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dir->ino))
28db82a8 107 if (check_directory(ctx, dir->ino, &pctx))
28ffafb0 108 goto abort_exit;
3839e657 109 }
28db82a8 110 e2fsck_dir_info_iter_end(ctx, iter);
a02ce9df 111
5a679c8f
TT
112 /*
113 * Force the creation of /lost+found if not present
114 */
115 if ((ctx->flags & E2F_OPT_READONLY) == 0)
850d05e9 116 e2fsck_get_lost_and_found(ctx, 1);
5a679c8f 117
850d05e9
TT
118 /*
119 * If there are any directories that need to be indexed or
120 * optimized, do it here.
121 */
122 e2fsck_rehash_directories(ctx);
efc6f628 123
a02ce9df 124abort_exit:
08b21301 125 e2fsck_free_dir_info(ctx);
28ffafb0 126 if (inode_loop_detect) {
a02ce9df 127 ext2fs_free_inode_bitmap(inode_loop_detect);
28ffafb0
TT
128 inode_loop_detect = 0;
129 }
130 if (inode_done_map) {
a02ce9df 131 ext2fs_free_inode_bitmap(inode_done_map);
28ffafb0
TT
132 inode_done_map = 0;
133 }
b7a00563 134
9facd076 135 print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io);
3839e657
TT
136}
137
138/*
139 * This makes sure the root inode is present; if not, we ask if the
140 * user wants us to create it. Not creating it is a fatal error.
141 */
1b6bf175 142static void check_root(e2fsck_t ctx)
3839e657 143{
1b6bf175 144 ext2_filsys fs = ctx->fs;
c5d2f50d 145 blk64_t blk;
3839e657
TT
146 struct ext2_inode inode;
147 char * block;
1b6bf175 148 struct problem_context pctx;
efc6f628 149
1b6bf175 150 clear_problem_context(&pctx);
efc6f628 151
c5d2f50d 152 if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) {
3839e657 153 /*
08b21301 154 * If the root inode is not a directory, die here. The
3839e657
TT
155 * user must have answered 'no' in pass1 when we
156 * offered to clear it.
157 */
c5d2f50d 158 if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map,
f8188fff
TT
159 EXT2_ROOT_INO))) {
160 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
161 ctx->flags |= E2F_FLAG_ABORT;
162 }
3839e657
TT
163 return;
164 }
165
f8188fff
TT
166 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
167 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
168 ctx->flags |= E2F_FLAG_ABORT;
169 return;
170 }
3839e657 171
f8188fff 172 e2fsck_read_bitmaps(ctx);
efc6f628 173
3839e657
TT
174 /*
175 * First, find a free block
176 */
c5d2f50d 177 pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
1b6bf175
TT
178 if (pctx.errcode) {
179 pctx.str = "ext2fs_new_block";
180 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
08b21301
TT
181 ctx->flags |= E2F_FLAG_ABORT;
182 return;
3839e657 183 }
c5d2f50d
VAH
184 ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
185 ext2fs_mark_block_bitmap2(fs->block_map, blk);
3839e657
TT
186 ext2fs_mark_bb_dirty(fs);
187
188 /*
189 * Now let's create the actual data block for the inode
190 */
1b6bf175
TT
191 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
192 &block);
193 if (pctx.errcode) {
194 pctx.str = "ext2fs_new_dir_block";
195 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
08b21301
TT
196 ctx->flags |= E2F_FLAG_ABORT;
197 return;
3839e657
TT
198 }
199
1b6bf175
TT
200 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
201 if (pctx.errcode) {
202 pctx.str = "ext2fs_write_dir_block";
203 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
08b21301
TT
204 ctx->flags |= E2F_FLAG_ABORT;
205 return;
3839e657 206 }
c4e3d3f3 207 ext2fs_free_mem(&block);
3839e657
TT
208
209 /*
210 * Set up the inode structure
211 */
212 memset(&inode, 0, sizeof(inode));
213 inode.i_mode = 040755;
214 inode.i_size = fs->blocksize;
1f3ad14a 215 inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
3839e657 216 inode.i_links_count = 2;
1ca1059f 217 ext2fs_iblk_set(fs, &inode, 1);
3839e657
TT
218 inode.i_block[0] = blk;
219
220 /*
221 * Write out the inode.
222 */
030970ed 223 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
1b6bf175
TT
224 if (pctx.errcode) {
225 pctx.str = "ext2fs_write_inode";
226 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
08b21301
TT
227 ctx->flags |= E2F_FLAG_ABORT;
228 return;
3839e657 229 }
efc6f628 230
3839e657
TT
231 /*
232 * Miscellaneous bookkeeping...
233 */
08b21301 234 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
1b6bf175
TT
235 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
236 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
3839e657 237
c5d2f50d
VAH
238 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO);
239 ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO);
240 ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO);
3839e657
TT
241 ext2fs_mark_ib_dirty(fs);
242}
243
244/*
245 * This subroutine is responsible for making sure that a particular
246 * directory is connected to the root; if it isn't we trace it up as
247 * far as we can go, and then offer to connect the resulting parent to
248 * the lost+found. We have to do loop detection; if we ever discover
249 * a loop, we treat that as a disconnected directory and offer to
250 * reparent it to lost+found.
efc6f628 251 *
28ffafb0
TT
252 * However, loop detection is expensive, because for very large
253 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
254 * is non-trivial. Loops in filesystems are also a rare error case,
255 * and we shouldn't optimize for error cases. So we try two passes of
256 * the algorithm. The first time, we ignore loop detection and merely
257 * increment a counter; if the counter exceeds some extreme threshold,
258 * then we try again with the loop detection bitmap enabled.
3839e657 259 */
28db82a8 260static int check_directory(e2fsck_t ctx, ext2_ino_t dir,
28ffafb0 261 struct problem_context *pctx)
3839e657 262{
28ffafb0 263 ext2_filsys fs = ctx->fs;
28db82a8 264 ext2_ino_t ino = dir, parent;
28ffafb0 265 int loop_pass = 0, parent_count = 0;
3839e657 266
28ffafb0 267 while (1) {
3839e657
TT
268 /*
269 * Mark this inode as being "done"; by the time we
270 * return from this function, the inode we either be
271 * verified as being connected to the directory tree,
272 * or we will have offered to reconnect this to
273 * lost+found.
28ffafb0
TT
274 *
275 * If it was marked done already, then we've reached a
276 * parent we've already checked.
3839e657 277 */
c5d2f50d 278 if (ext2fs_mark_inode_bitmap2(inode_done_map, ino))
28ffafb0 279 break;
7f813ba3 280
28db82a8
TT
281 if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) {
282 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
283 return 0;
284 }
285
3839e657
TT
286 /*
287 * If this directory doesn't have a parent, or we've
288 * seen the parent once already, then offer to
289 * reparent it to lost+found
290 */
28db82a8 291 if (!parent ||
efc6f628 292 (loop_pass &&
c5d2f50d 293 (ext2fs_test_inode_bitmap2(inode_loop_detect,
28db82a8
TT
294 parent)))) {
295 pctx->ino = ino;
7f813ba3 296 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
2e5fcce0 297 if (e2fsck_reconnect_file(ctx, pctx->ino))
7f813ba3
TT
298 ext2fs_unmark_valid(fs);
299 else {
efc6f628 300 fix_dotdot(ctx, pctx->ino,
28db82a8
TT
301 ctx->lost_and_found);
302 parent = ctx->lost_and_found;
7f813ba3
TT
303 }
304 }
3839e657 305 break;
7f813ba3 306 }
28db82a8 307 ino = parent;
28ffafb0 308 if (loop_pass) {
c5d2f50d 309 ext2fs_mark_inode_bitmap2(inode_loop_detect, ino);
28ffafb0
TT
310 } else if (parent_count++ > 2048) {
311 /*
312 * If we've run into a path depth that's
313 * greater than 2048, try again with the inode
314 * loop bitmap turned on and start from the
315 * top.
316 */
317 loop_pass = 1;
318 if (inode_loop_detect)
319 ext2fs_clear_inode_bitmap(inode_loop_detect);
320 else {
321 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
322 if (pctx->errcode) {
323 pctx->num = 1;
efc6f628 324 fix_problem(ctx,
28ffafb0
TT
325 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
326 ctx->flags |= E2F_FLAG_ABORT;
327 return -1;
328 }
329 }
28db82a8 330 ino = dir;
3839e657 331 }
21c84b71 332 }
3839e657
TT
333
334 /*
335 * Make sure that .. and the parent directory are the same;
336 * offer to fix it if not.
337 */
28db82a8
TT
338 pctx->ino = dir;
339 if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) ||
340 e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) {
341 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
342 return 0;
343 }
344 if (pctx->ino2 != pctx->dir) {
1b6bf175 345 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
28db82a8 346 fix_dotdot(ctx, dir, pctx->dir);
3839e657 347 }
28ffafb0 348 return 0;
b7a00563 349}
3839e657
TT
350
351/*
352 * This routine gets the lost_and_found inode, making it a directory
353 * if necessary
354 */
850d05e9 355ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
3839e657 356{
1b6bf175 357 ext2_filsys fs = ctx->fs;
86c627ec 358 ext2_ino_t ino;
c5d2f50d 359 blk64_t blk;
3839e657
TT
360 errcode_t retval;
361 struct ext2_inode inode;
362 char * block;
53ef44c4 363 static const char name[] = "lost+found";
1b6bf175 364 struct problem_context pctx;
3839e657 365
850d05e9
TT
366 if (ctx->lost_and_found)
367 return ctx->lost_and_found;
368
1b6bf175 369 clear_problem_context(&pctx);
efc6f628 370
21c84b71
TT
371 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
372 sizeof(name)-1, 0, &ino);
850d05e9
TT
373 if (retval && !fix)
374 return 0;
4a9f5936 375 if (!retval) {
c5d2f50d 376 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) {
850d05e9 377 ctx->lost_and_found = ino;
4a9f5936 378 return ino;
850d05e9 379 }
efc6f628 380
4a9f5936 381 /* Lost+found isn't a directory! */
850d05e9
TT
382 if (!fix)
383 return 0;
4a9f5936
TT
384 pctx.ino = ino;
385 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
386 return 0;
387
c54b3c3c 388 /* OK, unlink the old /lost+found file. */
4a9f5936
TT
389 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
390 if (pctx.errcode) {
391 pctx.str = "ext2fs_unlink";
392 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
393 return 0;
394 }
28db82a8 395 (void) e2fsck_dir_info_set_parent(ctx, ino, 0);
b0700a1b 396 e2fsck_adjust_inode_count(ctx, ino, -1);
4a9f5936 397 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
1b6bf175
TT
398 pctx.errcode = retval;
399 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
400 }
401 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
3839e657 402 return 0;
3839e657
TT
403
404 /*
405 * Read the inode and block bitmaps in; we'll be messing with
406 * them.
407 */
f8188fff 408 e2fsck_read_bitmaps(ctx);
efc6f628 409
3839e657
TT
410 /*
411 * First, find a free block
412 */
c5d2f50d 413 retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
3839e657 414 if (retval) {
1b6bf175
TT
415 pctx.errcode = retval;
416 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
3839e657
TT
417 return 0;
418 }
c5d2f50d 419 ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
48f23054 420 ext2fs_block_alloc_stats2(fs, blk, +1);
3839e657
TT
421
422 /*
423 * Next find a free inode.
424 */
b0700a1b 425 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
1b6bf175 426 ctx->inode_used_map, &ino);
3839e657 427 if (retval) {
1b6bf175
TT
428 pctx.errcode = retval;
429 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
3839e657
TT
430 return 0;
431 }
c5d2f50d
VAH
432 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
433 ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
0684a4f3 434 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
3839e657
TT
435
436 /*
437 * Now let's create the actual data block for the inode
438 */
439 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
440 if (retval) {
1b6bf175
TT
441 pctx.errcode = retval;
442 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
3839e657
TT
443 return 0;
444 }
445
50e1e10f 446 retval = ext2fs_write_dir_block(fs, blk, block);
c4e3d3f3 447 ext2fs_free_mem(&block);
3839e657 448 if (retval) {
1b6bf175
TT
449 pctx.errcode = retval;
450 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
3839e657
TT
451 return 0;
452 }
3839e657
TT
453
454 /*
455 * Set up the inode structure
456 */
457 memset(&inode, 0, sizeof(inode));
64aecc4d 458 inode.i_mode = 040700;
3839e657 459 inode.i_size = fs->blocksize;
1f3ad14a 460 inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
3839e657 461 inode.i_links_count = 2;
1ca1059f 462 ext2fs_iblk_set(fs, &inode, 1);
3839e657
TT
463 inode.i_block[0] = blk;
464
465 /*
466 * Next, write out the inode.
467 */
030970ed 468 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
1b6bf175
TT
469 if (pctx.errcode) {
470 pctx.str = "ext2fs_write_inode";
471 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
3839e657
TT
472 return 0;
473 }
474 /*
475 * Finally, create the directory link
476 */
6fdc7a32 477 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
1b6bf175
TT
478 if (pctx.errcode) {
479 pctx.str = "ext2fs_link";
480 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
3839e657
TT
481 return 0;
482 }
483
484 /*
485 * Miscellaneous bookkeeping that needs to be kept straight.
486 */
08b21301 487 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
b0700a1b 488 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
1b6bf175
TT
489 ext2fs_icount_store(ctx->inode_count, ino, 2);
490 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
850d05e9 491 ctx->lost_and_found = ino;
624e4a64
AK
492 quota_data_add(ctx->qctx, &inode, ino, fs->blocksize);
493 quota_data_inodes(ctx->qctx, &inode, ino, +1);
3839e657 494#if 0
f3db3566 495 printf("/lost+found created; inode #%lu\n", ino);
3839e657
TT
496#endif
497 return ino;
498}
499
500/*
501 * This routine will connect a file to lost+found
502 */
86c627ec 503int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
3839e657 504{
1b6bf175 505 ext2_filsys fs = ctx->fs;
3839e657
TT
506 errcode_t retval;
507 char name[80];
1b6bf175 508 struct problem_context pctx;
6fdc7a32
TT
509 struct ext2_inode inode;
510 int file_type = 0;
1b6bf175
TT
511
512 clear_problem_context(&pctx);
6fdc7a32 513 pctx.ino = ino;
1b6bf175 514
850d05e9
TT
515 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
516 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
517 ctx->bad_lost_and_found++;
1b6bf175 518 }
850d05e9 519 if (ctx->bad_lost_and_found) {
1b6bf175 520 fix_problem(ctx, PR_3_NO_LPF, &pctx);
3839e657
TT
521 return 1;
522 }
efc6f628 523
86c627ec 524 sprintf(name, "#%u", ino);
6fdc7a32
TT
525 if (ext2fs_read_inode(fs, ino, &inode) == 0)
526 file_type = ext2_file_type(inode.i_mode);
850d05e9 527 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
3839e657 528 if (retval == EXT2_ET_DIR_NO_SPACE) {
1b6bf175 529 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
3839e657 530 return 1;
efc6f628 531 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
850d05e9 532 1, 0);
3839e657 533 if (retval) {
1b6bf175
TT
534 pctx.errcode = retval;
535 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
3839e657
TT
536 return 1;
537 }
850d05e9
TT
538 retval = ext2fs_link(fs, ctx->lost_and_found, name,
539 ino, file_type);
3839e657
TT
540 }
541 if (retval) {
1b6bf175
TT
542 pctx.errcode = retval;
543 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
3839e657
TT
544 return 1;
545 }
b0700a1b 546 e2fsck_adjust_inode_count(ctx, ino, 1);
3839e657
TT
547
548 return 0;
549}
550
551/*
552 * Utility routine to adjust the inode counts on an inode.
553 */
b0700a1b 554errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
3839e657 555{
1b6bf175 556 ext2_filsys fs = ctx->fs;
3839e657
TT
557 errcode_t retval;
558 struct ext2_inode inode;
efc6f628 559
3839e657
TT
560 if (!ino)
561 return 0;
562
563 retval = ext2fs_read_inode(fs, ino, &inode);
564 if (retval)
565 return retval;
566
567#if 0
f3db3566 568 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
3839e657
TT
569 inode.i_links_count);
570#endif
571
21c84b71 572 if (adj == 1) {
1b6bf175 573 ext2fs_icount_increment(ctx->inode_count, ino, 0);
c1faf9cc
TT
574 if (inode.i_links_count == (__u16) ~0)
575 return 0;
1b6bf175 576 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
c1faf9cc
TT
577 inode.i_links_count++;
578 } else if (adj == -1) {
1b6bf175 579 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
c1faf9cc
TT
580 if (inode.i_links_count == 0)
581 return 0;
1b6bf175 582 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
c1faf9cc 583 inode.i_links_count--;
21c84b71 584 }
efc6f628 585
3839e657
TT
586 retval = ext2fs_write_inode(fs, ino, &inode);
587 if (retval)
588 return retval;
589
590 return 0;
591}
592
593/*
594 * Fix parent --- this routine fixes up the parent of a directory.
595 */
596struct fix_dotdot_struct {
597 ext2_filsys fs;
86c627ec 598 ext2_ino_t parent;
3839e657 599 int done;
1b6bf175 600 e2fsck_t ctx;
3839e657
TT
601};
602
603static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
54434927
TT
604 int offset EXT2FS_ATTR((unused)),
605 int blocksize EXT2FS_ATTR((unused)),
606 char *buf EXT2FS_ATTR((unused)),
54dc7ca2 607 void *priv_data)
3839e657 608{
54dc7ca2 609 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
3839e657 610 errcode_t retval;
1b6bf175 611 struct problem_context pctx;
3839e657 612
b6f79831 613 if ((dirent->name_len & 0xFF) != 2)
3839e657
TT
614 return 0;
615 if (strncmp(dirent->name, "..", 2))
616 return 0;
3839e657 617
1b6bf175 618 clear_problem_context(&pctx);
efc6f628 619
b0700a1b 620 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
1b6bf175
TT
621 if (retval) {
622 pctx.errcode = retval;
623 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
624 }
b0700a1b 625 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
1b6bf175
TT
626 if (retval) {
627 pctx.errcode = retval;
628 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
629 }
3839e657 630 dirent->inode = fp->parent;
56c8c592
TT
631 if (fp->ctx->fs->super->s_feature_incompat &
632 EXT2_FEATURE_INCOMPAT_FILETYPE)
efc6f628 633 dirent->name_len = (dirent->name_len & 0xFF) |
56c8c592
TT
634 (EXT2_FT_DIR << 8);
635 else
636 dirent->name_len = dirent->name_len & 0xFF;
3839e657
TT
637
638 fp->done++;
639 return DIRENT_ABORT | DIRENT_CHANGED;
640}
641
28db82a8 642static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
3839e657 643{
1b6bf175 644 ext2_filsys fs = ctx->fs;
3839e657
TT
645 errcode_t retval;
646 struct fix_dotdot_struct fp;
1b6bf175 647 struct problem_context pctx;
3839e657
TT
648
649 fp.fs = fs;
650 fp.parent = parent;
651 fp.done = 0;
1b6bf175 652 fp.ctx = ctx;
3839e657
TT
653
654#if 0
28db82a8 655 printf("Fixing '..' of inode %lu to be %lu...\n", ino, parent);
3839e657 656#endif
efc6f628 657
28db82a8
TT
658 clear_problem_context(&pctx);
659 pctx.ino = ino;
660 retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
3839e657
TT
661 0, fix_dotdot_proc, &fp);
662 if (retval || !fp.done) {
1b6bf175
TT
663 pctx.errcode = retval;
664 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
665 PR_3_FIX_PARENT_NOFIND, &pctx);
3839e657
TT
666 ext2fs_unmark_valid(fs);
667 }
28db82a8
TT
668 (void) e2fsck_dir_info_set_dotdot(ctx, ino, parent);
669 if (e2fsck_dir_info_set_parent(ctx, ino, ctx->lost_and_found))
670 fix_problem(ctx, PR_3_NO_DIRINFO, &pctx);
671
3839e657
TT
672 return;
673}
674
675/*
676 * These routines are responsible for expanding a /lost+found if it is
677 * too small.
678 */
679
680struct expand_dir_struct {
6dc64392
VAH
681 blk64_t num;
682 e2_blkcnt_t guaranteed_size;
683 blk64_t newblocks;
684 blk64_t last_block;
c1faf9cc
TT
685 errcode_t err;
686 e2fsck_t ctx;
3839e657
TT
687};
688
689static int expand_dir_proc(ext2_filsys fs,
6dc64392 690 blk64_t *blocknr,
133a56dc 691 e2_blkcnt_t blockcnt,
6dc64392 692 blk64_t ref_block EXT2FS_ATTR((unused)),
54434927 693 int ref_offset EXT2FS_ATTR((unused)),
54dc7ca2 694 void *priv_data)
3839e657 695{
54dc7ca2 696 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
c5d2f50d 697 blk64_t new_blk;
6dc64392 698 static blk64_t last_blk = 0;
3839e657
TT
699 char *block;
700 errcode_t retval;
1b6bf175
TT
701 e2fsck_t ctx;
702
703 ctx = es->ctx;
efc6f628 704
b7a00563
TT
705 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
706 return BLOCK_ABORT;
707
708 if (blockcnt > 0)
709 es->last_block = blockcnt;
3839e657
TT
710 if (*blocknr) {
711 last_blk = *blocknr;
712 return 0;
713 }
c5d2f50d 714 retval = ext2fs_new_block2(fs, last_blk, ctx->block_found_map,
1b6bf175 715 &new_blk);
3839e657
TT
716 if (retval) {
717 es->err = retval;
718 return BLOCK_ABORT;
719 }
720 if (blockcnt > 0) {
721 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
722 if (retval) {
723 es->err = retval;
724 return BLOCK_ABORT;
725 }
b7a00563 726 es->num--;
b8647faa 727 retval = ext2fs_write_dir_block(fs, new_blk, block);
3839e657 728 } else {
c4e3d3f3 729 retval = ext2fs_get_mem(fs->blocksize, &block);
08b21301
TT
730 if (retval) {
731 es->err = retval;
3839e657
TT
732 return BLOCK_ABORT;
733 }
734 memset(block, 0, fs->blocksize);
24a117ab 735 retval = io_channel_write_blk64(fs->io, new_blk, 1, block);
efc6f628 736 }
3839e657
TT
737 if (retval) {
738 es->err = retval;
739 return BLOCK_ABORT;
740 }
c4e3d3f3 741 ext2fs_free_mem(&block);
3839e657 742 *blocknr = new_blk;
c5d2f50d 743 ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk);
48f23054 744 ext2fs_block_alloc_stats2(fs, new_blk, +1);
c1faf9cc 745 es->newblocks++;
efc6f628 746
b7a00563 747 if (es->num == 0)
3839e657
TT
748 return (BLOCK_CHANGED | BLOCK_ABORT);
749 else
750 return BLOCK_CHANGED;
751}
752
b7a00563
TT
753errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
754 int num, int guaranteed_size)
3839e657 755{
1b6bf175 756 ext2_filsys fs = ctx->fs;
3839e657
TT
757 errcode_t retval;
758 struct expand_dir_struct es;
759 struct ext2_inode inode;
efc6f628 760
3839e657
TT
761 if (!(fs->flags & EXT2_FLAG_RW))
762 return EXT2_ET_RO_FILSYS;
763
b8647faa
TT
764 /*
765 * Read the inode and block bitmaps in; we'll be messing with
766 * them.
767 */
768 e2fsck_read_bitmaps(ctx);
c1faf9cc 769
3839e657
TT
770 retval = ext2fs_check_directory(fs, dir);
771 if (retval)
772 return retval;
efc6f628 773
b7a00563
TT
774 es.num = num;
775 es.guaranteed_size = guaranteed_size;
776 es.last_block = 0;
3839e657 777 es.err = 0;
c1faf9cc 778 es.newblocks = 0;
1b6bf175 779 es.ctx = ctx;
efc6f628 780
6dc64392 781 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
133a56dc 782 0, expand_dir_proc, &es);
3839e657
TT
783
784 if (es.err)
785 return es.err;
3839e657
TT
786
787 /*
788 * Update the size and block count fields in the inode.
789 */
790 retval = ext2fs_read_inode(fs, dir, &inode);
791 if (retval)
792 return retval;
efc6f628 793
b7a00563 794 inode.i_size = (es.last_block + 1) * fs->blocksize;
1ca1059f 795 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
624e4a64 796 quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);
3839e657 797
08b21301 798 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
3839e657
TT
799
800 return 0;
801}
b7a00563 802