2 * pass1b.c --- Pass #1b of e2fsck
4 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
5 * only invoked if pass 1 discovered blocks which are in use by more
8 * Pass1B scans the data blocks of all the inodes again, generating a
9 * complete list of duplicate blocks and which inodes have claimed
12 * Pass1C does a tree-traversal of the filesystem, to determine the
13 * parent directories of these inodes. This step is necessary so that
14 * e2fsck can print out the pathnames of affected inodes.
16 * Pass1D is a reconciliation pass. For each inode with duplicate
17 * blocks, the user is prompted if s/he would like to clone the file
18 * (so that the file gets a fresh copy of the duplicated blocks) or
19 * simply to delete the file.
21 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
22 * redistributed under the terms of the GNU Public License.
28 #include <et/com_err.h>
32 * This is structure is allocated for each time that a block is
33 * claimed by more than one file. So if a particular block is claimed
34 * by 3 files, then three copies of this structure will be allocated,
35 * one for each conflict.
37 * The linked list structure is as follows:
39 * dup_blk --> block #34 --> block #35 --> block #47
40 * inode #12 inode #14 inode #17
41 * num_bad = 3 num_bad = 2 num_bad = 2
44 * block #34 block #35 block #47
45 * inode #14 inode #15 inode #23
51 * The num_bad field indicates how many inodes are sharing a
52 * particular block, and is only stored in the first element of the
53 * linked list for a particular block. As the block conflicts are
54 * resolved, num_bad is decremented; when it reaches 1, then we no
55 * longer need to worry about that block.
58 blk_t block; /* Block number */
59 ino_t ino; /* Inode number */
61 /* Pointer to next dup record with different block */
62 struct dup_block *next_block;
63 /* Pointer to next dup record with different inode */
64 struct dup_block *next_inode;
68 * This structure stores information about a particular inode which
69 * is sharing blocks with other inodes. This information is collected
70 * to display to the user, so that the user knows what files he or she
71 * is dealing with, when trying to decide how to resolve the conflict
72 * of multiply-claimed blocks.
80 struct dup_inode *next;
83 #define DUP_INODE_DONT_FREE_PATHNAME 0x1
85 static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
86 int blockcnt, void *private);
87 static void delete_file(ext2_filsys fs, struct dup_inode *dp,
89 static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf);
90 static void pass1b(ext2_filsys fs, char *block_buf);
91 static void pass1c(ext2_filsys fs, char *block_buf);
92 static void pass1d(ext2_filsys fs, char *block_buf);
94 static struct dup_block *dup_blk = 0;
95 static struct dup_inode *dup_ino = 0;
96 static int dup_inode_count = 0;
99 * For pass1_check_directory and pass1_get_blocks
101 extern ino_t stashed_ino;
102 extern struct ext2_inode *stashed_inode;
104 static char *inode_dup_map;
107 * Main procedure for handling duplicate blocks
109 void pass1_dupblocks(ext2_filsys fs, char *block_buf)
112 struct dup_block *p, *q, *next_p, *next_q;
113 struct dup_inode *r, *next_r;
115 retval = ext2fs_allocate_inode_bitmap(fs, &inode_dup_map);
117 com_err("ext2fs_allocate_inode_bitmap", retval,
118 "while allocating inode_dup_map");
122 pass1b(fs, block_buf);
123 pass1c(fs, block_buf);
124 pass1d(fs, block_buf);
127 * Time to free all of the accumulated data structures that we
128 * don't need anymore.
130 free(inode_dup_map); inode_dup_map = 0;
131 free(block_dup_map); block_dup_map = 0;
132 for (p = dup_blk; p; p = next_p) {
133 next_p = p->next_block;
134 for (q = p; q; q = next_q) {
135 next_q = q->next_inode;
139 for (r = dup_ino; r; r = next_r) {
141 if (r->pathname && !(r->flags & DUP_INODE_DONT_FREE_PATHNAME))
148 * Scan the inodes looking for inodes that contain duplicate blocks.
150 struct process_block_struct {
155 void pass1b(ext2_filsys fs, char *block_buf)
158 struct ext2_inode inode;
159 ext2_inode_scan scan;
161 struct process_block_struct pb;
162 struct dup_inode *dp;
164 printf("Duplicate blocks found... invoking duplicate block passes.\n");
165 printf("Pass 1B: Rescan for duplicate/bad blocks\n");
166 retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
168 com_err(program_name, retval, "while opening inode scan");
171 retval = ext2fs_get_next_inode(scan, &ino, &inode);
173 com_err(program_name, retval, "while starting inode scan");
176 stashed_inode = &inode;
179 if ((ino != EXT2_BAD_INO) &&
180 (!ext2fs_test_inode_bitmap(fs, inode_used_map, ino) ||
181 !inode_has_valid_blocks(&inode)))
186 retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
187 process_pass1b_block, &pb);
189 if (ino != EXT2_BAD_INO)
191 dp = allocate_memory(sizeof(struct dup_inode),
192 "duplicate inode record");
194 dp->mtime = inode.i_mtime;
195 dp->num_dupblocks = pb.dup_blocks;
200 if (ino != EXT2_BAD_INO)
204 com_err(program_name, retval,
205 "while calling ext2fs_block_iterate in pass1b");
208 retval = ext2fs_get_next_inode(scan, &ino, &inode);
210 com_err(program_name, retval,
211 "while doing inode scan");
215 ext2fs_close_inode_scan(scan);
217 fs->check_directory = 0;
220 int process_pass1b_block(ext2_filsys fs,
225 struct process_block_struct *p;
226 struct dup_block *dp, *q, *r;
231 p = (struct process_block_struct *) private;
233 if (ext2fs_test_block_bitmap(fs, block_dup_map, *block_nr)) {
234 /* OK, this is a duplicate block */
235 if (p->ino != EXT2_BAD_INO) {
237 printf("Duplicate/bad block(s) in inode %ld:",
239 printf(" %ld", *block_nr);
242 ext2fs_mark_block_bitmap(fs, block_dup_map, *block_nr);
243 ext2fs_mark_inode_bitmap(fs, inode_dup_map, p->ino);
244 dp = allocate_memory(sizeof(struct dup_block),
245 "duplicate block record");
246 dp->block = *block_nr;
251 if (q->block == *block_nr)
256 dp->next_inode = q->next_inode;
259 dp->next_block = dup_blk;
264 * Set the num_bad field
266 for (q = dup_blk; q; q = q->next_block) {
268 for (r = q; r; r = r->next_inode)
276 * Used by pass1c to name the "special" inodes. They are declared as
277 * writeable strings to prevent const problems.
279 #define num_special_inodes 7
280 char special_inode_name[num_special_inodes][40] =
282 "<The NULL inode>", /* 0 */
283 "<The bad blocks inode>", /* 1 */
285 "<The ACL index inode>", /* 3 */
286 "<The ACL data inode>", /* 4 */
287 "<The boot loader inode>", /* 5 */
288 "<The undelete directory inode>" /* 6 */
292 * Pass 1c: Scan directories for inodes with duplicate blocks. This
293 * is used so that we can print pathnames when prompting the user for
296 struct process_dir_struct {
302 void pass1c(ext2_filsys fs, char *block_buf)
308 int inodes_left = dup_inode_count;
310 struct ext2_dir_entry *dirent;
312 printf("Pass 1C: Scan directories for inodes with dup blocks.\n");
315 * First check to see if any of the inodes with dup blocks is
316 * the bad block inode or the root inode; handle them as
319 for (p = dup_ino; p; p = p->next) {
320 if (p->ino < num_special_inodes) {
321 p->pathname = special_inode_name[p->ino];
322 p->flags |= DUP_INODE_DONT_FREE_PATHNAME;
328 * Search through all directories to translate inodes to names
329 * (by searching for the containing directory for that inode.)
331 for (i=0; inodes_left && i < dir_block_count; i++) {
332 retval = io_channel_read_blk(fs->io, dir_blocks[i].blk,
335 while (offset < fs->blocksize) {
337 dirent = (struct ext2_dir_entry *)
338 (block_buf + offset);
339 if (!dirent->inode ||
340 ((dir_blocks[i].blockcnt == 0) && (entry <= 2)))
343 if (!ext2fs_test_inode_bitmap(fs, inode_dup_map,
347 for (p = dup_ino; p; p = p->next) {
348 if (p->ino == dirent->inode)
352 if (!p || p->pathname)
355 (void) ext2fs_get_pathname(fs, dir_blocks[i].ino,
356 p->ino, &p->pathname);
360 if (dirent->rec_len < 8)
362 offset += dirent->rec_len;
368 * If we can't get a name, then put in a generic one.
370 for (p = dup_ino; p; p = p->next) {
372 sprintf(buf, "<Unknown inode #%ld>", p->ino);
373 p->pathname = malloc(strlen(buf)+1);
375 fprintf(stderr, "pass1c: couldn't malloc "
376 "generic pathname\n");
379 strcpy(p->pathname, buf);
384 static void pass1d(ext2_filsys fs, char *block_buf)
386 struct dup_inode *p, *s;
387 struct dup_block *q, *r;
395 printf("Pass 1D: Reconciling duplicate blocks\n");
398 printf("(There are %d inodes containing duplicate/bad blocks.)\n\n",
400 shared = allocate_memory(sizeof(ino_t) * dup_inode_count,
401 "Shared inode list");
402 for (p = dup_ino; p; p = p->next) {
405 if (p->ino == EXT2_BAD_INO)
409 * Search through the duplicate records to see which
410 * inodes share blocks with this one
412 for (q = dup_blk; q; q = q->next_block) {
414 * See if this block is used by this inode.
415 * If it isn't, continue.
417 for (r = q; r; r = r->next_inode)
418 if (r->ino == p->ino)
425 * Add all inodes used by this block to the
426 * shared[] --- which is a unique list, so
427 * if an inode is already in shared[], don't
430 for (r = q; r; r = r->next_inode) {
431 if (r->ino == p->ino)
433 for (i = 0; i < shared_len; i++)
434 if (shared[i] == r->ino)
436 if (i == shared_len) {
437 shared[shared_len++] = r->ino;
441 time_str = ctime(&p->mtime);
443 printf("File %s (inode #%ld, mod time %s) \n",
444 p->pathname, p->ino, time_str);
445 printf(" has %d duplicate blocks, shared with %d file%s:\n",
446 p->num_dupblocks, shared_len,
447 (shared_len>1) ? "s" : "");
448 for (i = 0; i < shared_len; i++) {
449 for (s = dup_ino; s; s = s->next)
450 if (s->ino == shared[i])
454 time_str = ctime(&s->mtime);
456 printf("\t%s (inode #%ld, mod time %s)\n",
457 s->pathname, s->ino, time_str);
460 printf("Duplicated blocks already reassigned or cloned.\n\n");
464 if (ask("Clone duplicate/bad blocks", 1)) {
465 retval = clone_file(fs, p, block_buf);
467 printf("Couldn't clone file: %s\n",
468 error_message(retval));
474 if (ask("Delete file", 1))
475 delete_file(fs, p, block_buf);
477 ext2fs_unmark_valid(fs);
482 static int delete_file_block(ext2_filsys fs,
492 if (ext2fs_test_block_bitmap(fs, block_dup_map, *block_nr)) {
493 for (p = dup_blk; p; p = p->next_block)
494 if (p->block == *block_nr)
499 ext2fs_unmark_block_bitmap(fs, block_dup_map,
502 com_err("delete_file_block", 0,
503 "internal error; can't find dup_blk for %d\n",
506 ext2fs_unmark_block_bitmap(fs, block_found_map, *block_nr);
507 ext2fs_unmark_block_bitmap(fs, fs->block_map, *block_nr);
513 static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
516 struct process_block_struct pb;
517 struct ext2_inode inode;
520 pb.dup_blocks = dp->num_dupblocks;
522 retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
523 delete_file_block, &pb);
525 com_err("delete_file", retval,
526 "while calling ext2fs_block_iterate for inode %d",
528 ext2fs_unmark_inode_bitmap(fs, inode_used_map, dp->ino);
529 ext2fs_unmark_inode_bitmap(fs, inode_dir_map, dp->ino);
531 ext2fs_unmark_inode_bitmap(fs, inode_bad_map, dp->ino);
532 ext2fs_unmark_inode_bitmap(fs, fs->inode_map, dp->ino);
533 ext2fs_mark_ib_dirty(fs);
534 ext2fs_mark_bb_dirty(fs);
535 retval = ext2fs_read_inode(fs, dp->ino, &inode);
537 com_err("delete_file", retval, "while reading inode %d",
541 inode.i_links_count = 0;
542 inode.i_dtime = time(0);
543 retval = ext2fs_write_inode(fs, dp->ino, &inode);
545 com_err("delete_file", retval, "while writing inode %d",
551 struct clone_struct {
556 static int clone_file_block(ext2_filsys fs,
564 struct clone_struct *cs = (struct clone_struct *) private;
569 if (ext2fs_test_block_bitmap(fs, block_dup_map, *block_nr)) {
570 for (p = dup_blk; p; p = p->next_block)
571 if (p->block == *block_nr)
574 retval = ext2fs_new_block(fs, 0, block_found_map,
577 cs->errcode = retval;
580 retval = io_channel_read_blk(fs->io, *block_nr, 1,
583 cs->errcode = retval;
586 retval = io_channel_write_blk(fs->io, new_block, 1,
589 cs->errcode = retval;
594 ext2fs_unmark_block_bitmap(fs, block_dup_map,
596 *block_nr = new_block;
597 ext2fs_mark_block_bitmap(fs, block_found_map,
599 ext2fs_mark_block_bitmap(fs, fs->block_map, new_block);
600 return BLOCK_CHANGED;
602 com_err("clone_file_block", 0,
603 "internal error; can't find dup_blk for %d\n",
609 static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
612 struct clone_struct cs;
615 cs.buf = malloc(fs->blocksize);
619 retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
620 clone_file_block, &cs);
621 ext2fs_mark_bb_dirty(fs);
624 com_err("clone_file", retval,
625 "while calling ext2fs_block_iterate for inode %d",
630 com_err("clone_file", retval,
631 "returned from clone_file_block");