Whamcloud - gitweb
Merge branch 'maint' into next
[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_block4(fs, blk, block, 0,
203                                                EXT2_ROOT_INO);
204         if (pctx.errcode) {
205                 pctx.str = "ext2fs_write_dir_block4";
206                 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
207                 ctx->flags |= E2F_FLAG_ABORT;
208                 return;
209         }
210         ext2fs_free_mem(&block);
211
212         /*
213          * Set up the inode structure
214          */
215         memset(&inode, 0, sizeof(inode));
216         inode.i_mode = 040755;
217         inode.i_size = fs->blocksize;
218         inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
219         inode.i_links_count = 2;
220         ext2fs_iblk_set(fs, &inode, 1);
221         inode.i_block[0] = blk;
222
223         /*
224          * Write out the inode.
225          */
226         pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
227         if (pctx.errcode) {
228                 pctx.str = "ext2fs_write_inode";
229                 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
230                 ctx->flags |= E2F_FLAG_ABORT;
231                 return;
232         }
233
234         /*
235          * Miscellaneous bookkeeping...
236          */
237         e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
238         ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
239         ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
240
241         ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO);
242         ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO);
243         ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO);
244         ext2fs_mark_ib_dirty(fs);
245 }
246
247 /*
248  * This subroutine is responsible for making sure that a particular
249  * directory is connected to the root; if it isn't we trace it up as
250  * far as we can go, and then offer to connect the resulting parent to
251  * the lost+found.  We have to do loop detection; if we ever discover
252  * a loop, we treat that as a disconnected directory and offer to
253  * reparent it to lost+found.
254  *
255  * However, loop detection is expensive, because for very large
256  * filesystems, the inode_loop_detect bitmap is huge, and clearing it
257  * is non-trivial.  Loops in filesystems are also a rare error case,
258  * and we shouldn't optimize for error cases.  So we try two passes of
259  * the algorithm.  The first time, we ignore loop detection and merely
260  * increment a counter; if the counter exceeds some extreme threshold,
261  * then we try again with the loop detection bitmap enabled.
262  */
263 static int check_directory(e2fsck_t ctx, ext2_ino_t dir,
264                            struct problem_context *pctx)
265 {
266         ext2_filsys     fs = ctx->fs;
267         ext2_ino_t      ino = dir, parent;
268         int             loop_pass = 0, parent_count = 0;
269
270         while (1) {
271                 /*
272                  * Mark this inode as being "done"; by the time we
273                  * return from this function, the inode we either be
274                  * verified as being connected to the directory tree,
275                  * or we will have offered to reconnect this to
276                  * lost+found.
277                  *
278                  * If it was marked done already, then we've reached a
279                  * parent we've already checked.
280                  */
281                 if (ext2fs_mark_inode_bitmap2(inode_done_map, ino))
282                         break;
283
284                 if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) {
285                         fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
286                         return 0;
287                 }
288
289                 /*
290                  * If this directory doesn't have a parent, or we've
291                  * seen the parent once already, then offer to
292                  * reparent it to lost+found
293                  */
294                 if (!parent ||
295                     (loop_pass &&
296                      (ext2fs_test_inode_bitmap2(inode_loop_detect,
297                                                parent)))) {
298                         pctx->ino = ino;
299                         if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
300                                 if (e2fsck_reconnect_file(ctx, pctx->ino))
301                                         ext2fs_unmark_valid(fs);
302                                 else {
303                                         fix_dotdot(ctx, pctx->ino,
304                                                    ctx->lost_and_found);
305                                         parent = ctx->lost_and_found;
306                                 }
307                         }
308                         break;
309                 }
310                 ino = parent;
311                 if (loop_pass) {
312                         ext2fs_mark_inode_bitmap2(inode_loop_detect, ino);
313                 } else if (parent_count++ > 2048) {
314                         /*
315                          * If we've run into a path depth that's
316                          * greater than 2048, try again with the inode
317                          * loop bitmap turned on and start from the
318                          * top.
319                          */
320                         loop_pass = 1;
321                         if (inode_loop_detect)
322                                 ext2fs_clear_inode_bitmap(inode_loop_detect);
323                         else {
324                                 pctx->errcode = e2fsck_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), EXT2FS_BMAP64_AUTODIR, "inode_loop_detect", &inode_loop_detect);
325                                 if (pctx->errcode) {
326                                         pctx->num = 1;
327                                         fix_problem(ctx,
328                                     PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
329                                         ctx->flags |= E2F_FLAG_ABORT;
330                                         return -1;
331                                 }
332                         }
333                         ino = dir;
334                 }
335         }
336
337         /*
338          * Make sure that .. and the parent directory are the same;
339          * offer to fix it if not.
340          */
341         pctx->ino = dir;
342         if (e2fsck_dir_info_get_dotdot(ctx, dir, &pctx->ino2) ||
343             e2fsck_dir_info_get_parent(ctx, dir, &pctx->dir)) {
344                 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
345                 return 0;
346         }
347         if (pctx->ino2 != pctx->dir) {
348                 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
349                         fix_dotdot(ctx, dir, pctx->dir);
350         }
351         return 0;
352 }
353
354 /*
355  * This routine gets the lost_and_found inode, making it a directory
356  * if necessary
357  */
358 ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
359 {
360         ext2_filsys fs = ctx->fs;
361         ext2_ino_t                      ino;
362         blk64_t                 blk;
363         errcode_t               retval;
364         struct ext2_inode       inode;
365         char *                  block;
366         static const char       name[] = "lost+found";
367         struct  problem_context pctx;
368
369         if (ctx->lost_and_found)
370                 return ctx->lost_and_found;
371
372         clear_problem_context(&pctx);
373
374         retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
375                                sizeof(name)-1, 0, &ino);
376         if (retval && !fix)
377                 return 0;
378         if (!retval) {
379                 if (ext2fs_check_directory(fs, ino) == 0) {
380                         ctx->lost_and_found = ino;
381                         return ino;
382                 }
383
384                 /* Lost+found isn't a directory! */
385                 if (!fix)
386                         return 0;
387                 pctx.ino = ino;
388                 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
389                         return 0;
390
391                 /* OK, unlink the old /lost+found file. */
392                 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
393                 if (pctx.errcode) {
394                         pctx.str = "ext2fs_unlink";
395                         fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
396                         return 0;
397                 }
398                 (void) e2fsck_dir_info_set_parent(ctx, ino, 0);
399                 e2fsck_adjust_inode_count(ctx, ino, -1);
400         } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
401                 pctx.errcode = retval;
402                 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
403         }
404         if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
405                 return 0;
406
407         /*
408          * Read the inode and block bitmaps in; we'll be messing with
409          * them.
410          */
411         e2fsck_read_bitmaps(ctx);
412
413         /*
414          * First, find a free block
415          */
416         retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
417         if (retval) {
418                 pctx.errcode = retval;
419                 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
420                 return 0;
421         }
422         ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
423         ext2fs_block_alloc_stats2(fs, blk, +1);
424
425         /*
426          * Next find a free inode.
427          */
428         retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
429                                   ctx->inode_used_map, &ino);
430         if (retval) {
431                 pctx.errcode = retval;
432                 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
433                 return 0;
434         }
435         ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
436         ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
437         ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
438
439         /*
440          * Now let's create the actual data block for the inode
441          */
442         retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
443         if (retval) {
444                 pctx.errcode = retval;
445                 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
446                 return 0;
447         }
448
449         retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
450         ext2fs_free_mem(&block);
451         if (retval) {
452                 pctx.errcode = retval;
453                 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
454                 return 0;
455         }
456
457         /*
458          * Set up the inode structure
459          */
460         memset(&inode, 0, sizeof(inode));
461         inode.i_mode = 040700;
462         inode.i_size = fs->blocksize;
463         inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
464         inode.i_links_count = 2;
465         ext2fs_iblk_set(fs, &inode, 1);
466         inode.i_block[0] = blk;
467
468         /*
469          * Next, write out the inode.
470          */
471         pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
472         if (pctx.errcode) {
473                 pctx.str = "ext2fs_write_inode";
474                 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
475                 return 0;
476         }
477         /*
478          * Finally, create the directory link
479          */
480         pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
481         if (pctx.errcode) {
482                 pctx.str = "ext2fs_link";
483                 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
484                 return 0;
485         }
486
487         /*
488          * Miscellaneous bookkeeping that needs to be kept straight.
489          */
490         e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
491         e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
492         ext2fs_icount_store(ctx->inode_count, ino, 2);
493         ext2fs_icount_store(ctx->inode_link_info, ino, 2);
494         ctx->lost_and_found = ino;
495         quota_data_add(ctx->qctx, &inode, ino, fs->blocksize);
496         quota_data_inodes(ctx->qctx, &inode, ino, +1);
497 #if 0
498         printf("/lost+found created; inode #%lu\n", ino);
499 #endif
500         return ino;
501 }
502
503 /*
504  * This routine will connect a file to lost+found
505  */
506 int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
507 {
508         ext2_filsys fs = ctx->fs;
509         errcode_t       retval;
510         char            name[80];
511         struct problem_context  pctx;
512         struct ext2_inode       inode;
513         int             file_type = 0;
514
515         clear_problem_context(&pctx);
516         pctx.ino = ino;
517
518         if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
519                 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
520                         ctx->bad_lost_and_found++;
521         }
522         if (ctx->bad_lost_and_found) {
523                 fix_problem(ctx, PR_3_NO_LPF, &pctx);
524                 return 1;
525         }
526
527         sprintf(name, "#%u", ino);
528         if (ext2fs_read_inode(fs, ino, &inode) == 0)
529                 file_type = ext2_file_type(inode.i_mode);
530         retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
531         if (retval == EXT2_ET_DIR_NO_SPACE) {
532                 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
533                         return 1;
534                 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
535                                                  1, 0);
536                 if (retval) {
537                         pctx.errcode = retval;
538                         fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
539                         return 1;
540                 }
541                 retval = ext2fs_link(fs, ctx->lost_and_found, name,
542                                      ino, file_type);
543         }
544         if (retval) {
545                 pctx.errcode = retval;
546                 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
547                 return 1;
548         }
549         e2fsck_adjust_inode_count(ctx, ino, 1);
550
551         return 0;
552 }
553
554 /*
555  * Utility routine to adjust the inode counts on an inode.
556  */
557 errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
558 {
559         ext2_filsys fs = ctx->fs;
560         errcode_t               retval;
561         struct ext2_inode       inode;
562
563         if (!ino)
564                 return 0;
565
566         retval = ext2fs_read_inode(fs, ino, &inode);
567         if (retval)
568                 return retval;
569
570 #if 0
571         printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
572                inode.i_links_count);
573 #endif
574
575         if (adj == 1) {
576                 ext2fs_icount_increment(ctx->inode_count, ino, 0);
577                 if (inode.i_links_count == (__u16) ~0)
578                         return 0;
579                 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
580                 inode.i_links_count++;
581         } else if (adj == -1) {
582                 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
583                 if (inode.i_links_count == 0)
584                         return 0;
585                 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
586                 inode.i_links_count--;
587         }
588
589         retval = ext2fs_write_inode(fs, ino, &inode);
590         if (retval)
591                 return retval;
592
593         return 0;
594 }
595
596 /*
597  * Fix parent --- this routine fixes up the parent of a directory.
598  */
599 struct fix_dotdot_struct {
600         ext2_filsys     fs;
601         ext2_ino_t      parent;
602         int             done;
603         e2fsck_t        ctx;
604 };
605
606 static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
607                            int  offset EXT2FS_ATTR((unused)),
608                            int  blocksize EXT2FS_ATTR((unused)),
609                            char *buf EXT2FS_ATTR((unused)),
610                            void *priv_data)
611 {
612         struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
613         errcode_t       retval;
614         struct problem_context pctx;
615
616         if (ext2fs_dirent_name_len(dirent) != 2)
617                 return 0;
618         if (strncmp(dirent->name, "..", 2))
619                 return 0;
620
621         clear_problem_context(&pctx);
622
623         retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
624         if (retval) {
625                 pctx.errcode = retval;
626                 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
627         }
628         retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
629         if (retval) {
630                 pctx.errcode = retval;
631                 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
632         }
633         dirent->inode = fp->parent;
634         if (fp->ctx->fs->super->s_feature_incompat &
635             EXT2_FEATURE_INCOMPAT_FILETYPE)
636                 ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
637         else
638                 ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
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         if (e2fsck_dir_will_be_rehashed(ctx, ino))
663                 ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
664         retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
665                                     0, fix_dotdot_proc, &fp);
666         if (e2fsck_dir_will_be_rehashed(ctx, ino))
667                 ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
668         if (retval || !fp.done) {
669                 pctx.errcode = retval;
670                 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
671                             PR_3_FIX_PARENT_NOFIND, &pctx);
672                 ext2fs_unmark_valid(fs);
673         }
674         (void) e2fsck_dir_info_set_dotdot(ctx, ino, parent);
675         if (e2fsck_dir_info_set_parent(ctx, ino, ctx->lost_and_found))
676                 fix_problem(ctx, PR_3_NO_DIRINFO, &pctx);
677
678         return;
679 }
680
681 /*
682  * These routines are responsible for expanding a /lost+found if it is
683  * too small.
684  */
685
686 struct expand_dir_struct {
687         blk64_t                 num;
688         e2_blkcnt_t             guaranteed_size;
689         blk64_t                 newblocks;
690         blk64_t                 last_block;
691         errcode_t               err;
692         e2fsck_t                ctx;
693         ext2_ino_t              dir;
694 };
695
696 static int expand_dir_proc(ext2_filsys fs,
697                            blk64_t      *blocknr,
698                            e2_blkcnt_t  blockcnt,
699                            blk64_t ref_block EXT2FS_ATTR((unused)),
700                            int ref_offset EXT2FS_ATTR((unused)),
701                            void *priv_data)
702 {
703         struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
704         blk64_t new_blk;
705         static blk64_t  last_blk = 0;
706         char            *block;
707         errcode_t       retval;
708         e2fsck_t        ctx;
709
710         ctx = es->ctx;
711
712         if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
713                 return BLOCK_ABORT;
714
715         if (blockcnt > 0)
716                 es->last_block = blockcnt;
717         if (*blocknr) {
718                 last_blk = *blocknr;
719                 return 0;
720         }
721         retval = ext2fs_new_block2(fs, last_blk, ctx->block_found_map,
722                                   &new_blk);
723         if (retval) {
724                 es->err = retval;
725                 return BLOCK_ABORT;
726         }
727         if (blockcnt > 0) {
728                 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
729                 if (retval) {
730                         es->err = retval;
731                         return BLOCK_ABORT;
732                 }
733                 es->num--;
734                 retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
735                                                  es->dir);
736         } else {
737                 retval = ext2fs_get_mem(fs->blocksize, &block);
738                 if (retval) {
739                         es->err = retval;
740                         return BLOCK_ABORT;
741                 }
742                 memset(block, 0, fs->blocksize);
743                 retval = io_channel_write_blk64(fs->io, new_blk, 1, block);
744         }
745         if (retval) {
746                 es->err = retval;
747                 return BLOCK_ABORT;
748         }
749         ext2fs_free_mem(&block);
750         *blocknr = new_blk;
751         ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk);
752         ext2fs_block_alloc_stats2(fs, new_blk, +1);
753         es->newblocks++;
754
755         if (es->num == 0)
756                 return (BLOCK_CHANGED | BLOCK_ABORT);
757         else
758                 return BLOCK_CHANGED;
759 }
760
761 /*
762  * Ensure that all blocks are marked in the block_found_map, since it's
763  * possible that the library allocated an extent node block or a block map
764  * block during the directory rebuilding; these new allocations are not
765  * captured in block_found_map.  This is bad since we could later use
766  * block_found_map to allocate more blocks.
767  */
768 static int find_new_blocks_proc(ext2_filsys fs,
769                                 blk64_t *blocknr,
770                                 e2_blkcnt_t     blockcnt,
771                                 blk64_t ref_block EXT2FS_ATTR((unused)),
772                                 int ref_offset EXT2FS_ATTR((unused)),
773                                 void    *priv_data)
774 {
775         struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
776         e2fsck_t        ctx = es->ctx;
777
778         ext2fs_mark_block_bitmap2(ctx->block_found_map, *blocknr);
779         return 0;
780 }
781
782 errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
783                                   int num, int guaranteed_size)
784 {
785         ext2_filsys fs = ctx->fs;
786         errcode_t       retval;
787         struct expand_dir_struct es;
788         struct ext2_inode       inode;
789         blk64_t         sz, before, after;
790
791         if (!(fs->flags & EXT2_FLAG_RW))
792                 return EXT2_ET_RO_FILSYS;
793
794         /*
795          * Read the inode and block bitmaps in; we'll be messing with
796          * them.
797          */
798         e2fsck_read_bitmaps(ctx);
799
800         retval = ext2fs_check_directory(fs, dir);
801         if (retval)
802                 return retval;
803
804         es.num = num;
805         es.guaranteed_size = guaranteed_size;
806         es.last_block = 0;
807         es.err = 0;
808         es.newblocks = 0;
809         es.ctx = ctx;
810         es.dir = dir;
811
812         before = ext2fs_free_blocks_count(fs->super);
813         retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
814                                        0, expand_dir_proc, &es);
815
816         if (es.err)
817                 return es.err;
818         after = ext2fs_free_blocks_count(fs->super);
819
820         /*
821          * If the free block count has dropped by more than the blocks we
822          * allocated ourselves, then we must've allocated some extent/map
823          * blocks.  Therefore, we must iterate this dir's blocks again to
824          * ensure that all newly allocated blocks are captured in
825          * block_found_map.
826          */
827         if ((before - after) > es.newblocks) {
828                 retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY,
829                                                0, find_new_blocks_proc, &es);
830                 if (es.err)
831                         return es.err;
832         }
833
834         /*
835          * Update the size and block count fields in the inode.
836          */
837         retval = ext2fs_read_inode(fs, dir, &inode);
838         if (retval)
839                 return retval;
840
841         sz = (es.last_block + 1) * fs->blocksize;
842         inode.i_size = sz;
843         inode.i_size_high = sz >> 32;
844         ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
845         quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);
846
847         e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
848
849         return 0;
850 }
851