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