blob: 7e3ad97ef0db05c9c44c490e90674abd6b3a8786 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
3 *
4 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
6 *
7 * Pass #3 assures that all directories are connected to the
8 * filesystem tree, using the following algorithm:
9 *
10 * First, the root directory is checked to make sure it exists; if
11 * not, e2fsck will offer to create a new one. It is then marked as
12 * "done".
13 *
14 * Then, pass3 interates over all directory inodes; for each directory
15 * it attempts to trace up the filesystem tree, using dirinfo.parent
16 * until it reaches a directory which has been marked "done". If it
17 * can not do so, then the directory must be disconnected, and e2fsck
18 * will offer to reconnect it to /lost+found. While it is chasing
19 * parent pointers up the filesystem tree, if pass3 sees a directory
20 * twice, then it has detected a filesystem loop, and it will again
21 * offer to reconnect the directory to /lost+found in to break the
22 * filesystem loop.
23 *
24 * Pass 3 also contains the subroutine, reconnect_file() to reconnect
25 * inodes to /lost+found; this subroutine is also used by pass 4.
26 * reconnect_file() calls get_lost_and_found(), which is responsible
27 * for creating /lost+found if it does not exist.
28 *
29 * Pass 3 frees the following data structures:
30 * - The dirinfo directory information cache.
31 */
32
33#include "et/com_err.h"
34
35#include "e2fsck.h"
36
37static void check_root(ext2_filsys fs, ino_t root_ino);
38static void check_directory(ext2_filsys fs, ino_t dir);
39static ino_t get_lost_and_found(ext2_filsys fs);
40static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent);
Theodore Ts'of3db3561997-04-26 13:34:30 +000041static errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj);
Theodore Ts'o3839e651997-04-26 13:21:57 +000042static errcode_t expand_directory(ext2_filsys fs, ino_t dir);
43
44static ino_t lost_and_found = 0;
45static int bad_lost_and_found = 0;
46
Theodore Ts'of3db3561997-04-26 13:34:30 +000047static ext2fs_inode_bitmap inode_loop_detect;
48static ext2fs_inode_bitmap inode_done_map;
Theodore Ts'o3839e651997-04-26 13:21:57 +000049
50void pass3(ext2_filsys fs)
51{
52 int i;
53 errcode_t retval;
54 struct resource_track rtrack;
55
56 init_resource_track(&rtrack);
57
58#ifdef MTRACE
59 mtrace_print("Pass 3");
60#endif
61
62 if (!preen)
63 printf("Pass 3: Checking directory connectivity\n");
64
65 /*
66 * Allocate some bitmaps to do loop detection.
67 */
Theodore Ts'of3db3561997-04-26 13:34:30 +000068 retval = ext2fs_allocate_inode_bitmap(fs,
69 "inode loop detection bitmap",
70 &inode_loop_detect);
Theodore Ts'o3839e651997-04-26 13:21:57 +000071 if (retval) {
72 com_err("ext2fs_allocate_inode_bitmap", retval,
73 "while allocating inode_loop_detect");
74 fatal_error(0);
75 }
Theodore Ts'of3db3561997-04-26 13:34:30 +000076 retval = ext2fs_allocate_inode_bitmap(fs, "inode done bitmap",
77 &inode_done_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +000078 if (retval) {
79 com_err("ext2fs_allocate_inode_bitmap", retval,
80 "while allocating inode_done_map");
81 fatal_error(0);
82 }
83 if (tflag) {
84 printf("Peak memory: ");
85 print_resource_track(&global_rtrack);
86 }
87
88 check_root(fs, EXT2_ROOT_INO);
Theodore Ts'of3db3561997-04-26 13:34:30 +000089 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
Theodore Ts'o3839e651997-04-26 13:21:57 +000090
91 for (i=1; i <= fs->super->s_inodes_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +000092 if (ext2fs_test_inode_bitmap(inode_dir_map, i))
Theodore Ts'o3839e651997-04-26 13:21:57 +000093 check_directory(fs, i);
94 }
95
96 free_dir_info(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +000097 ext2fs_free_inode_bitmap(inode_loop_detect);
98 ext2fs_free_inode_bitmap(inode_done_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +000099 if (tflag > 1) {
100 printf("Pass 3: ");
101 print_resource_track(&rtrack);
102 }
103}
104
105/*
106 * This makes sure the root inode is present; if not, we ask if the
107 * user wants us to create it. Not creating it is a fatal error.
108 */
109void check_root(ext2_filsys fs, ino_t root_ino)
110{
111 blk_t blk;
112 errcode_t retval;
113 struct ext2_inode inode;
114 char * block;
115 struct dir_info *dir;
116
Theodore Ts'of3db3561997-04-26 13:34:30 +0000117 if (ext2fs_test_inode_bitmap(inode_used_map, root_ino)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000118 /*
119 * If the root inode is a directory, die here. The
120 * user must have answered 'no' in pass1 when we
121 * offered to clear it.
122 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000123 if (!(ext2fs_test_inode_bitmap(inode_dir_map, root_ino)))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000124 fatal_error("Root inode not directory");
125
126 /*
127 * Set up the parent pointer for the root; this isn't
128 * done anywhere else, so we do it here.
129 */
130 dir = get_dir_info(root_ino);
131 dir->parent = root_ino;
132
133 return;
134 }
135
136 printf("Root inode not allocated. ");
137 preenhalt();
138 if (!ask("Rellocate", 1)) {
139 ext2fs_unmark_valid(fs);
140 fatal_error("Cannot proceed without a root inode.");
141 }
142
143 read_bitmaps(fs);
144
145 /*
146 * First, find a free block
147 */
148 retval = ext2fs_new_block(fs, 0, block_found_map, &blk);
149 if (retval) {
150 com_err("ext2fs_new_block", retval,
151 "while trying to create root directory");
152 fatal_error(0);
153 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000154 ext2fs_mark_block_bitmap(block_found_map, blk);
155 ext2fs_mark_block_bitmap(fs->block_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000156 ext2fs_mark_bb_dirty(fs);
157
158 /*
159 * Now let's create the actual data block for the inode
160 */
161 retval = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
162 &block);
163 if (retval) {
164 com_err("ext2fs_new_dir_block", retval,
165 "while creating new root directory");
166 fatal_error(0);
167 }
168
169 retval = io_channel_write_blk(fs->io, blk, 1, block);
170 if (retval) {
171 com_err("io_channel_write_blk", retval,
172 "while writing the root directory block");
173 fatal_error(0);
174 }
175 free(block);
176
177 /*
178 * Set up the inode structure
179 */
180 memset(&inode, 0, sizeof(inode));
181 inode.i_mode = 040755;
182 inode.i_size = fs->blocksize;
183 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
184 inode.i_links_count = 2;
185 inode.i_blocks = fs->blocksize / 512;
186 inode.i_block[0] = blk;
187
188 /*
189 * Write out the inode.
190 */
191 retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
192 if (retval) {
193 com_err("ext2fs_write_inode", retval,
194 "While trying to create /lost+found");
195 fatal_error(0);
196 }
197
198 /*
199 * Miscellaneous bookkeeping...
200 */
201 add_dir_info(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, &inode);
202 inode_count[EXT2_ROOT_INO] = 2;
203 inode_link_info[EXT2_ROOT_INO] = 2;
204
Theodore Ts'of3db3561997-04-26 13:34:30 +0000205 ext2fs_mark_inode_bitmap(inode_used_map, EXT2_ROOT_INO);
206 ext2fs_mark_inode_bitmap(inode_dir_map, EXT2_ROOT_INO);
207 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000208 ext2fs_mark_ib_dirty(fs);
209}
210
211/*
212 * This subroutine is responsible for making sure that a particular
213 * directory is connected to the root; if it isn't we trace it up as
214 * far as we can go, and then offer to connect the resulting parent to
215 * the lost+found. We have to do loop detection; if we ever discover
216 * a loop, we treat that as a disconnected directory and offer to
217 * reparent it to lost+found.
218 */
219static void check_directory(ext2_filsys fs, ino_t ino)
220{
221 struct dir_info *dir;
222 struct dir_info *p;
223 errcode_t retval;
224 char *path1, *path2, *path3;
225 static char unknown[] = "???";
226
227 dir = get_dir_info(ino);
228 if (!dir) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000229 printf("Internal error: couldn't find dir_info for %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000230 ino);
231 fatal_error(0);
232 }
233
Theodore Ts'of3db3561997-04-26 13:34:30 +0000234 ext2fs_clear_inode_bitmap(inode_loop_detect);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000235 p = dir;
236 while (p) {
237 /*
238 * If we find a parent which we've already checked,
239 * then stop; we know it's either already connected to
240 * the directory tree, or it isn't but the user has
241 * already told us he doesn't want us to reconnect the
242 * disconnected subtree.
243 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000244 if (ext2fs_test_inode_bitmap(inode_done_map, p->ino))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000245 goto check_dot_dot;
246 /*
247 * Mark this inode as being "done"; by the time we
248 * return from this function, the inode we either be
249 * verified as being connected to the directory tree,
250 * or we will have offered to reconnect this to
251 * lost+found.
252 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000253 ext2fs_mark_inode_bitmap(inode_done_map, p->ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000254 /*
255 * If this directory doesn't have a parent, or we've
256 * seen the parent once already, then offer to
257 * reparent it to lost+found
258 */
259 if (!p->parent ||
Theodore Ts'of3db3561997-04-26 13:34:30 +0000260 (ext2fs_test_inode_bitmap(inode_loop_detect,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000261 p->parent)))
262 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000263 ext2fs_mark_inode_bitmap(inode_loop_detect,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000264 p->parent);
265 p = get_dir_info(p->parent);
266 }
267 /*
268 * If we've reached here, we've hit a detached directory
269 * inode; offer to reconnect it to lost+found.
270 */
271 retval = ext2fs_get_pathname(fs, p->ino, 0, &path1);
272 if (retval)
273 path1 = unknown;
274
Theodore Ts'of3db3561997-04-26 13:34:30 +0000275 printf("Unconnected directory inode %lu (%s)\n", p->ino, path1);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000276 if (path1 != unknown)
277 free(path1);
278 preenhalt();
279 if (ask("Connect to /lost+found", 1)) {
280 if (reconnect_file(fs, p->ino))
281 ext2fs_unmark_valid(fs);
282 else {
283 p->parent = lost_and_found;
284 fix_dotdot(fs, p, lost_and_found);
285 }
286
287 } else
288 ext2fs_unmark_valid(fs);
289
290 /*
291 * Make sure that .. and the parent directory are the same;
292 * offer to fix it if not.
293 */
294check_dot_dot:
295 if (dir->parent != dir->dotdot) {
296 retval = ext2fs_get_pathname(fs, dir->parent, ino,
297 &path1);
298 if (retval)
299 path1 = unknown;
300 retval = ext2fs_get_pathname(fs, dir->dotdot, 0, &path2);
301 if (retval)
302 path2 = unknown;
303 retval = ext2fs_get_pathname(fs, dir->parent, 0, &path3);
304 if (retval)
305 path3 = unknown;
306
Theodore Ts'of3db3561997-04-26 13:34:30 +0000307 printf("'..' in %s (%lu) is %s (%lu), should be %s (%lu).\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000308 path1, ino, path2, dir->dotdot,
309 path3, dir->parent);
310 if (path1 != unknown)
311 free(path1);
312 if (path2 != unknown)
313 free(path2);
314 if (path3 != unknown)
315 free(path3);
316 if (ask("Fix", 1))
317 fix_dotdot(fs, dir, dir->parent);
318 else
319 ext2fs_unmark_valid(fs);
320 }
321}
322
323/*
324 * This routine gets the lost_and_found inode, making it a directory
325 * if necessary
326 */
327ino_t get_lost_and_found(ext2_filsys fs)
328{
329 ino_t ino;
330 blk_t blk;
331 errcode_t retval;
332 struct ext2_inode inode;
333 char * block;
334 const char * name = "lost+found";
335
336 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
337 if (!retval)
338 return ino;
339 if (retval != ENOENT)
340 printf("Error while trying to find /lost+found: %s",
341 error_message(retval));
342 else
343 printf("/lost+found not found. ");
344 preenhalt();
345 if (!ask("Create", 1)) {
346 ext2fs_unmark_valid(fs);
347 return 0;
348 }
349
350 /*
351 * Read the inode and block bitmaps in; we'll be messing with
352 * them.
353 */
354 read_bitmaps(fs);
355
356 /*
357 * First, find a free block
358 */
359 retval = ext2fs_new_block(fs, 0, block_found_map, &blk);
360 if (retval) {
361 com_err("ext2fs_new_block", retval,
362 "while trying to create /lost+found directory");
363 return 0;
364 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000365 ext2fs_mark_block_bitmap(block_found_map, blk);
366 ext2fs_mark_block_bitmap(fs->block_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000367 ext2fs_mark_bb_dirty(fs);
368
369 /*
370 * Next find a free inode.
371 */
372 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755, inode_used_map,
373 &ino);
374 if (retval) {
375 com_err("ext2fs_new_inode", retval,
376 "while trying to create /lost+found directory");
377 return 0;
378 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000379 ext2fs_mark_inode_bitmap(inode_used_map, ino);
380 ext2fs_mark_inode_bitmap(inode_dir_map, ino);
381 ext2fs_mark_inode_bitmap(fs->inode_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000382 ext2fs_mark_ib_dirty(fs);
383
384 /*
385 * Now let's create the actual data block for the inode
386 */
387 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
388 if (retval) {
389 com_err("ext2fs_new_dir_block", retval,
390 "while creating new directory block");
391 return 0;
392 }
393
394 retval = io_channel_write_blk(fs->io, blk, 1, block);
395 if (retval) {
396 com_err("io_channel_write_blk", retval,
397 "while writing the directory block for /lost+found");
398 return 0;
399 }
400 free(block);
401
402 /*
403 * Set up the inode structure
404 */
405 memset(&inode, 0, sizeof(inode));
406 inode.i_mode = 040755;
407 inode.i_size = fs->blocksize;
408 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
409 inode.i_links_count = 2;
410 inode.i_blocks = fs->blocksize / 512;
411 inode.i_block[0] = blk;
412
413 /*
414 * Next, write out the inode.
415 */
416 retval = ext2fs_write_inode(fs, ino, &inode);
417 if (retval) {
418 com_err("ext2fs_write_inode", retval,
419 "While trying to create /lost+found");
420 return 0;
421 }
422 /*
423 * Finally, create the directory link
424 */
425 retval = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0);
426 if (retval) {
427 com_err("ext2fs_link", retval, "While creating /lost+found");
428 return 0;
429 }
430
431 /*
432 * Miscellaneous bookkeeping that needs to be kept straight.
433 */
434 add_dir_info(fs, ino, EXT2_ROOT_INO, &inode);
435 adjust_inode_count(fs, EXT2_ROOT_INO, +1);
436 inode_count[ino] = 2;
437 inode_link_info[ino] = 2;
438#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000439 printf("/lost+found created; inode #%lu\n", ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000440#endif
441 return ino;
442}
443
444/*
445 * This routine will connect a file to lost+found
446 */
447int reconnect_file(ext2_filsys fs, ino_t inode)
448{
449 errcode_t retval;
450 char name[80];
451
452 if (bad_lost_and_found) {
453 printf("Bad or nonexistent /lost+found. Cannot reconnect.\n");
454 return 1;
455 }
456 if (!lost_and_found) {
457 lost_and_found = get_lost_and_found(fs);
458 if (!lost_and_found) {
459 printf("Bad or nonexistent /lost+found. Cannot reconnect.\n");
460 bad_lost_and_found++;
461 return 1;
462 }
463 }
464
Theodore Ts'of3db3561997-04-26 13:34:30 +0000465 sprintf(name, "#%lu", inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000466 retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
467 if (retval == EXT2_ET_DIR_NO_SPACE) {
468 if (!ask("No room in /lost+found; expand /lost+found", 1))
469 return 1;
470 retval = expand_directory(fs, lost_and_found);
471 if (retval) {
472 printf("Could not expand /lost+found: %s\n",
473 error_message(retval));
474 return 1;
475 }
476 retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
477 }
478 if (retval) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000479 printf("Could not reconnect %lu: %s\n", inode,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000480 error_message(retval));
481 return 1;
482 }
483
484 adjust_inode_count(fs, inode, +1);
485
486 return 0;
487}
488
489/*
490 * Utility routine to adjust the inode counts on an inode.
491 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000492static errcode_t adjust_inode_count(ext2_filsys fs, ino_t ino, int adj)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000493{
494 errcode_t retval;
495 struct ext2_inode inode;
496
497 if (!ino)
498 return 0;
499
500 retval = ext2fs_read_inode(fs, ino, &inode);
501 if (retval)
502 return retval;
503
504#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000505 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000506 inode.i_links_count);
507#endif
508
509 inode.i_links_count += adj;
510 inode_count[ino] += adj;
511 inode_link_info[ino] += adj;
512
513 retval = ext2fs_write_inode(fs, ino, &inode);
514 if (retval)
515 return retval;
516
517 return 0;
518}
519
520/*
521 * Fix parent --- this routine fixes up the parent of a directory.
522 */
523struct fix_dotdot_struct {
524 ext2_filsys fs;
525 ino_t parent;
526 int done;
527};
528
529static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
530 int offset,
531 int blocksize,
532 char *buf,
533 void *private)
534{
535 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) private;
536 errcode_t retval;
537
538 if (dirent->name_len != 2)
539 return 0;
540 if (strncmp(dirent->name, "..", 2))
541 return 0;
542
543 retval = adjust_inode_count(fp->fs, dirent->inode, -1);
544 if (retval)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000545 printf("Error while adjusting inode count on inode %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000546 dirent->inode);
547 retval = adjust_inode_count(fp->fs, fp->parent, 1);
548 if (retval)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000549 printf("Error while adjusting inode count on inode %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000550 fp->parent);
551
552 dirent->inode = fp->parent;
553
554 fp->done++;
555 return DIRENT_ABORT | DIRENT_CHANGED;
556}
557
558static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent)
559{
560 errcode_t retval;
561 struct fix_dotdot_struct fp;
562
563 fp.fs = fs;
564 fp.parent = parent;
565 fp.done = 0;
566
567#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000568 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000569#endif
570
571 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
572 0, fix_dotdot_proc, &fp);
573 if (retval || !fp.done) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000574 printf("Couldn't fix parent of inode %lu: %s\n\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000575 dir->ino, retval ? error_message(retval) :
576 "Couldn't find parent direntory entry");
577 ext2fs_unmark_valid(fs);
578 }
579 dir->dotdot = parent;
580
581 return;
582}
583
584/*
585 * These routines are responsible for expanding a /lost+found if it is
586 * too small.
587 */
588
589struct expand_dir_struct {
590 int done;
591 errcode_t err;
592};
593
594static int expand_dir_proc(ext2_filsys fs,
595 blk_t *blocknr,
596 int blockcnt,
597 void *private)
598{
599 struct expand_dir_struct *es = (struct expand_dir_struct *) private;
600 blk_t new_blk;
601 static blk_t last_blk = 0;
602 char *block;
603 errcode_t retval;
604
605 if (*blocknr) {
606 last_blk = *blocknr;
607 return 0;
608 }
609 retval = ext2fs_new_block(fs, last_blk, block_found_map, &new_blk);
610 if (retval) {
611 es->err = retval;
612 return BLOCK_ABORT;
613 }
614 if (blockcnt > 0) {
615 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
616 if (retval) {
617 es->err = retval;
618 return BLOCK_ABORT;
619 }
620 es->done = 1;
621 } else {
622 block = malloc(fs->blocksize);
623 if (!block) {
624 es->err = ENOMEM;
625 return BLOCK_ABORT;
626 }
627 memset(block, 0, fs->blocksize);
628 }
629 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
630 if (retval) {
631 es->err = retval;
632 return BLOCK_ABORT;
633 }
634 free(block);
635 *blocknr = new_blk;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000636 ext2fs_mark_block_bitmap(block_found_map, new_blk);
637 ext2fs_mark_block_bitmap(fs->block_map, new_blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000638 ext2fs_mark_bb_dirty(fs);
639 if (es->done)
640 return (BLOCK_CHANGED | BLOCK_ABORT);
641 else
642 return BLOCK_CHANGED;
643}
644
645static errcode_t expand_directory(ext2_filsys fs, ino_t dir)
646{
647 errcode_t retval;
648 struct expand_dir_struct es;
649 struct ext2_inode inode;
650
651 if (!(fs->flags & EXT2_FLAG_RW))
652 return EXT2_ET_RO_FILSYS;
653
654 retval = ext2fs_check_directory(fs, dir);
655 if (retval)
656 return retval;
657
658 es.done = 0;
659 es.err = 0;
660
661 retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
662 0, expand_dir_proc, &es);
663
664 if (es.err)
665 return es.err;
666 if (!es.done)
667 return EXT2_ET_EXPAND_DIR_ERR;
668
669 /*
670 * Update the size and block count fields in the inode.
671 */
672 retval = ext2fs_read_inode(fs, dir, &inode);
673 if (retval)
674 return retval;
675
676 inode.i_size += fs->blocksize;
677 inode.i_blocks += fs->blocksize / 512;
678
Theodore Ts'of3db3561997-04-26 13:34:30 +0000679 e2fsck_write_inode(fs, dir, &inode, "expand_directory");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000680
681 return 0;
682}
683
684
685