]>
git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - e2fsck/pass2.c
2 * pass2.c --- check directory structure
4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
7 * Pass 2 of e2fsck iterates through all active directory inodes, and
8 * applies to following tests to each directory entry in the directory
9 * blocks in the inodes:
11 * - The length of the directory entry (rec_len) should be at
12 * least 8 bytes, and no more than the remaining space
13 * left in the directory block.
14 * - The length of the name in the directory entry (name_len)
15 * should be less than (rec_len - 8).
16 * - The inode number in the directory entry should be within
18 * - The inode number should refer to a in-use inode.
19 * - The first entry should be '.', and its inode should be
20 * the inode of the directory.
21 * - The second entry should be '..'.
23 * To minimize disk seek time, the directory blocks are processed in
24 * sorted order of block numbers.
26 * Pass 2 also collects the following information:
27 * - The inode numbers of the subdirectories for each directory.
29 * Pass 2 relies on the following information from previous passes:
30 * - The directory information collected in pass 1.
31 * - The inode_used_map bitmap
32 * - The inode_bad_map bitmap
33 * - The inode_dir_map bitmap
34 * - The block_dup_map bitmap
36 * Pass 2 frees the following data structures
37 * - The inode_bad_map bitmap
40 #include "et/com_err.h"
45 * Keeps track of how many times an inode is referenced.
47 unsigned short * inode_count
;
49 static void deallocate_inode(ext2_filsys fs
, ino_t ino
,
51 static int process_bad_inode(ext2_filsys fs
, ino_t dir
, ino_t ino
);
52 static int check_dir_block(ext2_filsys fs
,
53 struct dir_block_struct
*dir_blocks_info
,
56 void pass2(ext2_filsys fs
)
60 struct resource_track rtrack
;
62 init_resource_track(&rtrack
);
65 mtrace_print("Pass 2");
69 printf("Pass 2: Checking directory structure\n");
70 inode_count
= allocate_memory((fs
->super
->s_inodes_count
+ 1) *
71 sizeof(unsigned short),
72 "buffer for inode count");
74 buf
= allocate_memory(fs
->blocksize
, "directory scan buffer");
76 for (i
=0; i
< dir_block_count
; i
++)
77 check_dir_block(fs
, &dir_blocks
[i
], buf
);
87 print_resource_track(&rtrack
);
92 * Make sure the first entry in the directory is '.', and that the
93 * directory entry is sane.
95 static int check_dot(ext2_filsys fs
,
96 struct ext2_dir_entry
*dirent
,
99 struct ext2_dir_entry
*nextdir
;
103 char name
[BLOCK_SIZE
];
105 if (!dirent
->inode
) {
106 printf("Missing '.' in directory inode %ld.\n", ino
);
107 if (dirent
->rec_len
< 12)
108 fatal_error("Cannot fix, insufficient space to add '.'");
112 dirent
->name_len
= 1;
113 dirent
->name
[0] = '.';
117 ext2fs_unmark_valid(fs
);
121 if ((dirent
->name_len
!= 1) ||
122 strncmp(dirent
->name
, ".", dirent
->name_len
)) {
123 strncpy(name
, dirent
->name
, dirent
->name_len
);
124 name
[dirent
->name_len
] = '\0';
125 printf("Missing '.' in directory inode %ld.\n", ino
);
126 printf("Cannot fix, first entry in directory contains '%s'\n",
130 if (dirent
->inode
!= ino
) {
131 printf("Bad inode number for '.' in directory inode %ld.\n",
138 ext2fs_unmark_valid(fs
);
140 if (dirent
->rec_len
> 12) {
141 new_len
= dirent
->rec_len
- 12;
145 ask("Directory entry for '.' is big. Split", 1)) {
146 nextdir
= (struct ext2_dir_entry
*)
147 ((char *) dirent
+ 12);
148 dirent
->rec_len
= 12;
149 nextdir
->rec_len
= new_len
;
151 nextdir
->name_len
= 0;
160 * Make sure the second entry in the directory is '..', and that the
161 * directory entry is sane. We do not check the inode number of '..'
162 * here; this gets done in pass 3.
164 static int check_dotdot(ext2_filsys fs
,
165 struct ext2_dir_entry
*dirent
,
166 struct dir_info
*dir
)
168 char name
[BLOCK_SIZE
];
171 if (!dirent
->inode
) {
172 printf("Missing '..' in directory inode %d.\n", ino
);
173 if (dirent
->rec_len
< 12)
174 fatal_error("Cannot fix, insufficient space to add '..'");
178 * Note: we don't have the parent inode just
179 * yet, so we will fill it in with the root
180 * inode. This will get fixed in pass 3.
182 dirent
->inode
= EXT2_ROOT_INO
;
183 dirent
->name_len
= 2;
184 dirent
->name
[0] = '.';
185 dirent
->name
[1] = '.';
188 ext2fs_unmark_valid(fs
);
191 if ((dirent
->name_len
!= 2) ||
192 strncmp(dirent
->name
, "..", dirent
->name_len
)) {
193 strncpy(name
, dirent
->name
, dirent
->name_len
);
194 name
[dirent
->name_len
] = '\0';
195 printf("Missing '..' in directory inode %d.\n", ino
);
196 printf("Cannot fix, first entry in directory contains %s\n",
200 dir
->dotdot
= dirent
->inode
;
205 * Check to make sure a directory entry doesn't contain any illegal
208 static int check_name(ext2_filsys fs
,
209 struct ext2_dir_entry
*dirent
,
219 for ( i
= 0; i
< dirent
->name_len
; i
++) {
220 if (dirent
->name
[i
] == '/' || dirent
->name
[i
] == '\0') {
222 retval
= ext2fs_get_pathname(fs
, dir_ino
,
225 com_err(program_name
, retval
, "while getting pathname in check_name");
228 printf ("Bad file name '%s' (contains '/' or "
229 " null) in directory '%s'",
233 fixup
= ask("Replace '/' or null by '.'", 1);
236 dirent
->name
[i
] = '.';
239 ext2fs_unmark_valid(fs
);
245 static int check_dir_block(ext2_filsys fs
,
246 struct dir_block_struct
*db
,
249 struct dir_info
*subdir
, *dir
;
250 struct ext2_dir_entry
*dirent
;
251 char name
[BLOCK_SIZE
];
253 int dir_modified
= 0;
257 blk_t block_nr
= db
->blk
;
259 static char unknown
[] = "???";
262 * Make sure the inode is still in use (could have been
263 * deleted in the duplicate/bad blocks pass.
265 if (!(ext2fs_test_inode_bitmap(fs
, inode_used_map
, ino
)))
274 printf("In process_dir_block block %d, #%d, inode %d\n", block_nr
,
278 retval
= io_channel_read_blk(fs
->io
, block_nr
, 1, buf
);
280 com_err(program_name
, retval
,
281 "while reading directory block %d", block_nr
);
286 dirent
= (struct ext2_dir_entry
*) (buf
+ offset
);
287 if (((offset
+ dirent
->rec_len
) > fs
->blocksize
) ||
288 (dirent
->rec_len
< 8) ||
289 ((dirent
->name_len
+8) > dirent
->rec_len
)) {
290 printf("Directory inode %ld, block %d, offset %d: directory corrupted\n",
291 ino
, db
->blockcnt
, offset
);
293 if (ask("Salvage", 1)) {
294 dirent
->rec_len
= fs
->blocksize
- offset
;
295 dirent
->name_len
= 0;
299 ext2fs_unmark_valid(fs
);
303 strncpy(name
, dirent
->name
, dirent
->name_len
);
304 name
[dirent
->name_len
] = '\0';
305 if (dot_state
== 1) {
306 if (check_dot(fs
, dirent
, ino
))
308 } else if (dot_state
== 2) {
309 dir
= get_dir_info(ino
);
311 printf("Internal error: couldn't find dir_info for %ld\n",
315 if (check_dotdot(fs
, dirent
, dir
))
317 } else if (dirent
->inode
== ino
) {
318 retval
= ext2fs_get_pathname(fs
, ino
, 0, &path1
);
321 printf("Entry '%s' in %s (%ld) is a link to '.' ",
323 if (path1
!= unknown
)
326 if (ask("Clear", 1)) {
335 printf("Entry '%s', name_len %d, rec_len %d, inode %d... ",
336 name
, dirent
->name_len
, dirent
->rec_len
, dirent
->inode
);
338 if (check_name(fs
, dirent
, ino
, name
))
342 * Make sure the inode listed is a legal one.
344 if (((dirent
->inode
!= EXT2_ROOT_INO
) &&
345 (dirent
->inode
< EXT2_FIRST_INO
)) ||
346 (dirent
->inode
> fs
->super
->s_inodes_count
)) {
347 retval
= ext2fs_get_pathname(fs
, ino
, 0, &path1
);
350 printf("Entry '%s' in %s (%ld) has bad inode #: %ld.\n",
351 name
, path1
, ino
, dirent
->inode
);
352 if (path1
!= unknown
)
355 if (ask("Clear", 1)) {
360 ext2fs_unmark_valid(fs
);
364 * If the inode is unusued, offer to clear it.
366 if (!(ext2fs_test_inode_bitmap(fs
, inode_used_map
,
368 retval
= ext2fs_get_pathname(fs
, ino
, 0, &path1
);
371 printf("Entry '%s' in %s (%ld) has deleted/unused inode %ld.\n",
372 name
, path1
, ino
, dirent
->inode
);
373 if (path1
!= unknown
)
375 if (ask("Clear", 1)) {
380 ext2fs_unmark_valid(fs
);
384 * If the inode was marked as having bad fields in
385 * pass1, process it and offer to fix/clear it.
386 * (We wait until now so that we can display the
387 * pathname to the user.)
390 ext2fs_test_inode_bitmap(fs
, inode_bad_map
,
392 if (process_bad_inode(fs
, ino
, dirent
->inode
)) {
400 * If this is a directory, then mark its parent in its
401 * dir_info structure. If the parent field is already
402 * filled in, then this directory has more than one
403 * hard link. We assume the first link is correct,
404 * and ask the user if he/she wants to clear this one.
406 if ((dot_state
> 2) &&
407 (ext2fs_test_inode_bitmap(fs
, inode_dir_map
,
409 subdir
= get_dir_info(dirent
->inode
);
411 printf("INTERNAL ERROR: missing dir %ld\n",
415 if (subdir
->parent
) {
416 retval
= ext2fs_get_pathname(fs
, ino
,
420 retval
= ext2fs_get_pathname(fs
,
426 printf("Entry '%s' in %s (%ld) is a link to directory %s (%ld).\n",
427 name
, path1
, ino
, path2
,
429 if (path1
!= unknown
)
431 if (path2
!= unknown
)
433 if (ask("Clear", 1)) {
438 ext2fs_unmark_valid(fs
);
440 subdir
->parent
= ino
;
443 if (inode_count
[dirent
->inode
]++ > 0)
447 offset
+= dirent
->rec_len
;
448 } while (offset
< fs
->blocksize
);
452 if (offset
!= fs
->blocksize
) {
453 printf("Final rec_len is %d, should be %d\n",
455 dirent
->rec_len
- fs
->blocksize
+ offset
);
458 retval
= io_channel_write_blk(fs
->io
, block_nr
,
461 com_err(program_name
, retval
,
462 "while writing directory block %d", block_nr
);
464 ext2fs_mark_changed(fs
);
470 * This function is called to deallocate a block, and is an interator
471 * functioned called by deallocate inode via ext2fs_iterate_block().
473 static int deallocate_inode_block(ext2_filsys fs
,
480 ext2fs_unmark_block_bitmap(fs
, block_found_map
, *block_nr
);
481 ext2fs_unmark_block_bitmap(fs
, fs
->block_map
, *block_nr
);
486 * This fuction deallocates an inode
488 static void deallocate_inode(ext2_filsys fs
, ino_t ino
,
492 struct ext2_inode inode
;
494 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
496 com_err("deallocate_inode", retval
, "while reading inode %d",
500 inode
.i_links_count
= 0;
501 inode
.i_dtime
= time(0);
502 retval
= ext2fs_write_inode(fs
, ino
, &inode
);
504 com_err("deallocate_inode", retval
, "while writing inode %d",
509 * Fix up the bitmaps...
512 ext2fs_unmark_inode_bitmap(fs
, inode_used_map
, ino
);
513 ext2fs_unmark_inode_bitmap(fs
, inode_dir_map
, ino
);
515 ext2fs_unmark_inode_bitmap(fs
, inode_bad_map
, ino
);
516 ext2fs_unmark_inode_bitmap(fs
, fs
->inode_map
, ino
);
517 ext2fs_mark_ib_dirty(fs
);
519 if (!inode_has_valid_blocks(&inode
))
522 ext2fs_mark_bb_dirty(fs
);
523 retval
= ext2fs_block_iterate(fs
, ino
, 0, block_buf
,
524 deallocate_inode_block
, 0);
526 com_err("deallocate_inode", retval
,
527 "while calling ext2fs_block_iterate for inode %d",
532 * These two subroutines are used by process_bad_inode; it is used to
533 * make sure that certain reserved fields are really zero. If not,
534 * prompt the user if he/she wants us to zeroize them.
536 static void check_for_zero_long(ext2_filsys fs
, ino_t ino
, char *pathname
,
537 const char *name
, unsigned long *val
,
543 printf("%s for inode %ld (%s) is %ld, should be zero.\n",
544 name
, ino
, pathname
, *val
);
546 sprintf(prompt
, "Clear %s", name
);
547 if (ask(prompt
, 1)) {
551 ext2fs_unmark_valid(fs
);
555 static void check_for_zero_char(ext2_filsys fs
, ino_t ino
, char *pathname
,
556 const char *name
, unsigned char *val
,
562 printf("%s for inode %ld (%s) is %d, should be zero.\n",
563 name
, ino
, pathname
, *val
);
565 sprintf(prompt
, "Clear %s", name
);
566 if (ask(prompt
, 1)) {
570 ext2fs_unmark_valid(fs
);
576 static int process_bad_inode(ext2_filsys fs
, ino_t dir
, ino_t ino
)
578 struct ext2_inode inode
;
580 int inode_modified
= 0;
583 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
585 com_err("process_bad_inode", retval
, "while reading inode %d",
589 retval
= ext2fs_get_pathname(fs
, dir
, ino
, &pathname
);
591 com_err("process_bad_inode", retval
,
592 "while getting pathname for inode %d",
596 if (!S_ISDIR(inode
.i_mode
) && !S_ISREG(inode
.i_mode
) &&
597 !S_ISCHR(inode
.i_mode
) && !S_ISBLK(inode
.i_mode
) &&
598 !S_ISLNK(inode
.i_mode
) && !S_ISFIFO(inode
.i_mode
) &&
599 !(S_ISSOCK(inode
.i_mode
))) {
600 printf("Inode %ld (%s) has a bad mode (0%o).\n",
601 ino
, pathname
, inode
.i_mode
);
603 if (ask("Clear", 1)) {
604 deallocate_inode(fs
, ino
, 0);
607 ext2fs_unmark_valid(fs
);
609 check_for_zero_long(fs
, ino
, pathname
, "i_faddr", &inode
.i_faddr
,
611 check_for_zero_char(fs
, ino
, pathname
, "i_frag", &inode
.i_frag
,
613 check_for_zero_char(fs
, ino
, pathname
, "i_fsize", &inode
.i_fsize
,
615 check_for_zero_long(fs
, ino
, pathname
, "i_file_acl", &inode
.i_file_acl
,
617 check_for_zero_long(fs
, ino
, pathname
, "i_dir_acl", &inode
.i_dir_acl
,
620 if (inode_modified
) {
621 retval
= ext2fs_write_inode(fs
, ino
, &inode
);
623 com_err("process_bad_inode", retval
,
624 "while writing inode %d",