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