]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/pass1b.c
ADD TAG: E2FSPROGS-1_06
[thirdparty/e2fsprogs.git] / e2fsck / pass1b.c
CommitLineData
3839e657
TT
1/*
2 * pass1b.c --- Pass #1b of e2fsck
3 *
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
6 * than one inode.
7 *
8 * Pass1B scans the data blocks of all the inodes again, generating a
9 * complete list of duplicate blocks and which inodes have claimed
10 * them.
11 *
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.
15 *
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.
20 *
21 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
22 * redistributed under the terms of the GNU Public License.
23 *
24 */
25
26#include <time.h>
50e1e10f
TT
27#ifdef HAVE_ERRNO_H
28#include <errno.h>
29#endif
3839e657
TT
30
31#include <et/com_err.h>
32#include "e2fsck.h"
33
34/*
35 * This is structure is allocated for each time that a block is
36 * claimed by more than one file. So if a particular block is claimed
37 * by 3 files, then three copies of this structure will be allocated,
38 * one for each conflict.
39 *
40 * The linked list structure is as follows:
41 *
42 * dup_blk --> block #34 --> block #35 --> block #47
43 * inode #12 inode #14 inode #17
44 * num_bad = 3 num_bad = 2 num_bad = 2
45 * | | |
46 * V V V
47 * block #34 block #35 block #47
48 * inode #14 inode #15 inode #23
49 * |
50 * V
51 * block #34
52 * inode #15
53 *
54 * The num_bad field indicates how many inodes are sharing a
55 * particular block, and is only stored in the first element of the
56 * linked list for a particular block. As the block conflicts are
57 * resolved, num_bad is decremented; when it reaches 1, then we no
58 * longer need to worry about that block.
59 */
60struct dup_block {
61 blk_t block; /* Block number */
62 ino_t ino; /* Inode number */
63 int num_bad;
64 /* Pointer to next dup record with different block */
65 struct dup_block *next_block;
66 /* Pointer to next dup record with different inode */
67 struct dup_block *next_inode;
68};
69
70/*
71 * This structure stores information about a particular inode which
72 * is sharing blocks with other inodes. This information is collected
73 * to display to the user, so that the user knows what files he or she
74 * is dealing with, when trying to decide how to resolve the conflict
75 * of multiply-claimed blocks.
76 */
77struct dup_inode {
78 ino_t ino;
79 time_t mtime;
80 char *pathname;
81 int num_dupblocks;
82 int flags;
83 struct dup_inode *next;
84};
85
86#define DUP_INODE_DONT_FREE_PATHNAME 0x1
87
88static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
89 int blockcnt, void *private);
90static void delete_file(ext2_filsys fs, struct dup_inode *dp,
91 char *block_buf);
92static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf);
93static void pass1b(ext2_filsys fs, char *block_buf);
94static void pass1c(ext2_filsys fs, char *block_buf);
95static void pass1d(ext2_filsys fs, char *block_buf);
96
97static struct dup_block *dup_blk = 0;
98static struct dup_inode *dup_ino = 0;
99static int dup_inode_count = 0;
100
f3db3566 101static ext2fs_inode_bitmap inode_dup_map;
3839e657
TT
102
103/*
104 * Main procedure for handling duplicate blocks
105 */
106void pass1_dupblocks(ext2_filsys fs, char *block_buf)
107{
108 errcode_t retval;
109 struct dup_block *p, *q, *next_p, *next_q;
110 struct dup_inode *r, *next_r;
111
f3db3566
TT
112 retval = ext2fs_allocate_inode_bitmap(fs,
113 "multiply claimed inode map", &inode_dup_map);
3839e657
TT
114 if (retval) {
115 com_err("ext2fs_allocate_inode_bitmap", retval,
116 "while allocating inode_dup_map");
117 fatal_error(0);
118 }
119
120 pass1b(fs, block_buf);
121 pass1c(fs, block_buf);
122 pass1d(fs, block_buf);
123
124 /*
125 * Time to free all of the accumulated data structures that we
126 * don't need anymore.
127 */
f3db3566
TT
128 ext2fs_free_inode_bitmap(inode_dup_map); inode_dup_map = 0;
129 ext2fs_free_block_bitmap(block_dup_map); block_dup_map = 0;
3839e657
TT
130 for (p = dup_blk; p; p = next_p) {
131 next_p = p->next_block;
132 for (q = p; q; q = next_q) {
133 next_q = q->next_inode;
134 free(q);
135 }
136 }
137 for (r = dup_ino; r; r = next_r) {
138 next_r = r->next;
139 if (r->pathname && !(r->flags & DUP_INODE_DONT_FREE_PATHNAME))
140 free(r->pathname);
141 free(r);
142 }
143}
144
145/*
146 * Scan the inodes looking for inodes that contain duplicate blocks.
147 */
148struct process_block_struct {
149 ino_t ino;
150 int dup_blocks;
151};
152
153void pass1b(ext2_filsys fs, char *block_buf)
154{
155 ino_t ino;
156 struct ext2_inode inode;
157 ext2_inode_scan scan;
158 errcode_t retval;
159 struct process_block_struct pb;
160 struct dup_inode *dp;
161
162 printf("Duplicate blocks found... invoking duplicate block passes.\n");
163 printf("Pass 1B: Rescan for duplicate/bad blocks\n");
164 retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
165 if (retval) {
166 com_err(program_name, retval, "while opening inode scan");
167 fatal_error(0);
168 }
169 retval = ext2fs_get_next_inode(scan, &ino, &inode);
170 if (retval) {
171 com_err(program_name, retval, "while starting inode scan");
172 fatal_error(0);
173 }
174 stashed_inode = &inode;
175 while (ino) {
176 stashed_ino = ino;
177 if ((ino != EXT2_BAD_INO) &&
f3db3566 178 (!ext2fs_test_inode_bitmap(inode_used_map, ino) ||
3839e657
TT
179 !inode_has_valid_blocks(&inode)))
180 goto next;
181
182 pb.ino = ino;
183 pb.dup_blocks = 0;
184 retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
185 process_pass1b_block, &pb);
186 if (pb.dup_blocks) {
187 if (ino != EXT2_BAD_INO)
188 printf("\n");
189 dp = allocate_memory(sizeof(struct dup_inode),
190 "duplicate inode record");
191 dp->ino = ino;
192 dp->mtime = inode.i_mtime;
193 dp->num_dupblocks = pb.dup_blocks;
194 dp->pathname = 0;
195 dp->flags = 0;
196 dp->next = dup_ino;
197 dup_ino = dp;
198 if (ino != EXT2_BAD_INO)
199 dup_inode_count++;
200 }
201 if (retval)
202 com_err(program_name, retval,
203 "while calling ext2fs_block_iterate in pass1b");
204
205 next:
206 retval = ext2fs_get_next_inode(scan, &ino, &inode);
207 if (retval) {
208 com_err(program_name, retval,
209 "while doing inode scan");
210 fatal_error(0);
211 }
212 }
213 ext2fs_close_inode_scan(scan);
214 fs->get_blocks = 0;
215 fs->check_directory = 0;
216}
217
218int process_pass1b_block(ext2_filsys fs,
219 blk_t *block_nr,
220 int blockcnt,
221 void *private)
222{
223 struct process_block_struct *p;
224 struct dup_block *dp, *q, *r;
225 int i;
226
227 if (!*block_nr)
228 return 0;
229 p = (struct process_block_struct *) private;
230
f3db3566 231 if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) {
3839e657
TT
232 /* OK, this is a duplicate block */
233 if (p->ino != EXT2_BAD_INO) {
234 if (!p->dup_blocks)
f3db3566 235 printf("Duplicate/bad block(s) in inode %lu:",
3839e657 236 p->ino);
50e1e10f 237 printf(" %u", *block_nr);
3839e657
TT
238 }
239 p->dup_blocks++;
f3db3566
TT
240 ext2fs_mark_block_bitmap(block_dup_map, *block_nr);
241 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
3839e657
TT
242 dp = allocate_memory(sizeof(struct dup_block),
243 "duplicate block record");
244 dp->block = *block_nr;
245 dp->ino = p->ino;
246 dp->num_bad = 0;
247 q = dup_blk;
248 while (q) {
249 if (q->block == *block_nr)
250 break;
251 q = q->next_block;
252 }
253 if (q) {
254 dp->next_inode = q->next_inode;
255 q->next_inode = dp;
256 } else {
257 dp->next_block = dup_blk;
258 dup_blk = dp;
259 }
260 }
261 /*
262 * Set the num_bad field
263 */
264 for (q = dup_blk; q; q = q->next_block) {
265 i = 0;
266 for (r = q; r; r = r->next_inode)
267 i++;
268 q->num_bad = i;
269 }
270 return 0;
271}
272
273/*
274 * Used by pass1c to name the "special" inodes. They are declared as
275 * writeable strings to prevent const problems.
276 */
277#define num_special_inodes 7
278char special_inode_name[num_special_inodes][40] =
279{
280 "<The NULL inode>", /* 0 */
281 "<The bad blocks inode>", /* 1 */
282 "/", /* 2 */
283 "<The ACL index inode>", /* 3 */
284 "<The ACL data inode>", /* 4 */
285 "<The boot loader inode>", /* 5 */
286 "<The undelete directory inode>" /* 6 */
287};
288
289/*
290 * Pass 1c: Scan directories for inodes with duplicate blocks. This
291 * is used so that we can print pathnames when prompting the user for
292 * what to do.
293 */
294struct process_dir_struct {
295 ext2_filsys fs;
296 ino_t dir_ino;
297 int count;
298};
299
300void pass1c(ext2_filsys fs, char *block_buf)
301{
302 int i;
303 struct dup_inode *p;
304 errcode_t retval;
305 char buf[80];
306 int inodes_left = dup_inode_count;
307 int offset, entry;
308 struct ext2_dir_entry *dirent;
309
310 printf("Pass 1C: Scan directories for inodes with dup blocks.\n");
311
312 /*
313 * First check to see if any of the inodes with dup blocks is
314 * the bad block inode or the root inode; handle them as
315 * special cases.
316 */
317 for (p = dup_ino; p; p = p->next) {
318 if (p->ino < num_special_inodes) {
319 p->pathname = special_inode_name[p->ino];
320 p->flags |= DUP_INODE_DONT_FREE_PATHNAME;
321 inodes_left--;
322 }
323 }
324
325 /*
326 * Search through all directories to translate inodes to names
327 * (by searching for the containing directory for that inode.)
328 */
329 for (i=0; inodes_left && i < dir_block_count; i++) {
50e1e10f
TT
330 retval = ext2fs_read_dir_block(fs, dir_blocks[i].blk,
331 block_buf);
3839e657
TT
332 entry = offset = 0;
333 while (offset < fs->blocksize) {
334 entry++;
335 dirent = (struct ext2_dir_entry *)
336 (block_buf + offset);
337 if (!dirent->inode ||
338 ((dir_blocks[i].blockcnt == 0) && (entry <= 2)))
339 goto next;
340
f3db3566 341 if (!ext2fs_test_inode_bitmap(inode_dup_map,
3839e657
TT
342 dirent->inode))
343 goto next;
344
345 for (p = dup_ino; p; p = p->next) {
346 if (p->ino == dirent->inode)
347 break;
348 }
349
350 if (!p || p->pathname)
351 goto next;
352
353 (void) ext2fs_get_pathname(fs, dir_blocks[i].ino,
354 p->ino, &p->pathname);
355 inodes_left--;
356
357 next:
358 if (dirent->rec_len < 8)
359 break;
360 offset += dirent->rec_len;
361 }
362 }
363
364
365 /*
366 * If we can't get a name, then put in a generic one.
367 */
368 for (p = dup_ino; p; p = p->next) {
369 if (!p->pathname) {
f3db3566 370 sprintf(buf, "<Unknown inode #%lu>", p->ino);
3839e657
TT
371 p->pathname = malloc(strlen(buf)+1);
372 if (!p->pathname) {
373 fprintf(stderr, "pass1c: couldn't malloc "
374 "generic pathname\n");
375 fatal_error(0);
376 }
377 strcpy(p->pathname, buf);
378 }
379 }
380}
381
382static void pass1d(ext2_filsys fs, char *block_buf)
383{
384 struct dup_inode *p, *s;
385 struct dup_block *q, *r;
386 ino_t *shared;
387 int shared_len;
388 int i;
389 errcode_t retval;
390 char *time_str;
391 int file_ok;
392
393 printf("Pass 1D: Reconciling duplicate blocks\n");
394 read_bitmaps(fs);
395
396 printf("(There are %d inodes containing duplicate/bad blocks.)\n\n",
397 dup_inode_count);
398 shared = allocate_memory(sizeof(ino_t) * dup_inode_count,
399 "Shared inode list");
400 for (p = dup_ino; p; p = p->next) {
401 shared_len = 0;
402 file_ok = 1;
403 if (p->ino == EXT2_BAD_INO)
404 continue;
405
406 /*
407 * Search through the duplicate records to see which
408 * inodes share blocks with this one
409 */
410 for (q = dup_blk; q; q = q->next_block) {
411 /*
412 * See if this block is used by this inode.
413 * If it isn't, continue.
414 */
415 for (r = q; r; r = r->next_inode)
416 if (r->ino == p->ino)
417 break;
418 if (!r)
419 continue;
420 if (q->num_bad > 1)
421 file_ok = 0;
422 /*
423 * Add all inodes used by this block to the
424 * shared[] --- which is a unique list, so
425 * if an inode is already in shared[], don't
426 * add it again.
427 */
428 for (r = q; r; r = r->next_inode) {
429 if (r->ino == p->ino)
430 continue;
431 for (i = 0; i < shared_len; i++)
432 if (shared[i] == r->ino)
433 break;
434 if (i == shared_len) {
435 shared[shared_len++] = r->ino;
436 }
437 }
438 }
439 time_str = ctime(&p->mtime);
440 time_str[24] = 0;
f3db3566 441 printf("File %s (inode #%lu, mod time %s) \n",
3839e657
TT
442 p->pathname, p->ino, time_str);
443 printf(" has %d duplicate blocks, shared with %d file%s:\n",
444 p->num_dupblocks, shared_len,
445 (shared_len>1) ? "s" : "");
446 for (i = 0; i < shared_len; i++) {
447 for (s = dup_ino; s; s = s->next)
448 if (s->ino == shared[i])
449 break;
450 if (!s)
451 continue;
452 time_str = ctime(&s->mtime);
453 time_str[24] = 0;
f3db3566 454 printf("\t%s (inode #%lu, mod time %s)\n",
3839e657
TT
455 s->pathname, s->ino, time_str);
456 }
457 if (file_ok) {
458 printf("Duplicated blocks already reassigned or cloned.\n\n");
459 continue;
460 }
461
462 if (ask("Clone duplicate/bad blocks", 1)) {
463 retval = clone_file(fs, p, block_buf);
464 if (retval)
465 printf("Couldn't clone file: %s\n",
466 error_message(retval));
467 else {
468 printf("\n");
469 continue;
470 }
471 }
472 if (ask("Delete file", 1))
473 delete_file(fs, p, block_buf);
474 else
475 ext2fs_unmark_valid(fs);
476 printf("\n");
477 }
50e1e10f 478 free(shared);
3839e657
TT
479}
480
481static int delete_file_block(ext2_filsys fs,
482 blk_t *block_nr,
483 int blockcnt,
484 void *private)
485{
486 struct dup_block *p;
487
488 if (!*block_nr)
489 return 0;
490
f3db3566 491 if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) {
3839e657
TT
492 for (p = dup_blk; p; p = p->next_block)
493 if (p->block == *block_nr)
494 break;
495 if (p) {
496 p->num_bad--;
497 if (p->num_bad == 1)
f3db3566 498 ext2fs_unmark_block_bitmap(block_dup_map,
3839e657
TT
499 *block_nr);
500 } else
501 com_err("delete_file_block", 0,
502 "internal error; can't find dup_blk for %d\n",
503 *block_nr);
504 } else {
f3db3566
TT
505 ext2fs_unmark_block_bitmap(block_found_map, *block_nr);
506 ext2fs_unmark_block_bitmap(fs->block_map, *block_nr);
3839e657
TT
507 }
508
509 return 0;
510}
511
512static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
513{
514 errcode_t retval;
515 struct process_block_struct pb;
516 struct ext2_inode inode;
517
518 pb.ino = dp->ino;
519 pb.dup_blocks = dp->num_dupblocks;
520
521 retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
522 delete_file_block, &pb);
523 if (retval)
524 com_err("delete_file", retval,
525 "while calling ext2fs_block_iterate for inode %d",
526 dp->ino);
f3db3566
TT
527 ext2fs_unmark_inode_bitmap(inode_used_map, dp->ino);
528 ext2fs_unmark_inode_bitmap(inode_dir_map, dp->ino);
3839e657 529 if (inode_bad_map)
f3db3566
TT
530 ext2fs_unmark_inode_bitmap(inode_bad_map, dp->ino);
531 ext2fs_unmark_inode_bitmap(fs->inode_map, dp->ino);
3839e657
TT
532 ext2fs_mark_ib_dirty(fs);
533 ext2fs_mark_bb_dirty(fs);
f3db3566 534 e2fsck_read_inode(fs, dp->ino, &inode, "delete_file");
3839e657
TT
535 inode.i_links_count = 0;
536 inode.i_dtime = time(0);
f3db3566 537 e2fsck_write_inode(fs, dp->ino, &inode, "delete_file");
3839e657
TT
538}
539
540struct clone_struct {
541 errcode_t errcode;
542 char *buf;
543};
544
545static int clone_file_block(ext2_filsys fs,
546 blk_t *block_nr,
547 int blockcnt,
548 void *private)
549{
550 struct dup_block *p;
551 blk_t new_block;
552 errcode_t retval;
553 struct clone_struct *cs = (struct clone_struct *) private;
554
555 if (!*block_nr)
556 return 0;
557
f3db3566 558 if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) {
3839e657
TT
559 for (p = dup_blk; p; p = p->next_block)
560 if (p->block == *block_nr)
561 break;
562 if (p) {
563 retval = ext2fs_new_block(fs, 0, block_found_map,
564 &new_block);
565 if (retval) {
566 cs->errcode = retval;
567 return BLOCK_ABORT;
568 }
569 retval = io_channel_read_blk(fs->io, *block_nr, 1,
570 cs->buf);
571 if (retval) {
572 cs->errcode = retval;
573 return BLOCK_ABORT;
574 }
575 retval = io_channel_write_blk(fs->io, new_block, 1,
576 cs->buf);
577 if (retval) {
578 cs->errcode = retval;
579 return BLOCK_ABORT;
580 }
581 p->num_bad--;
582 if (p->num_bad == 1)
f3db3566 583 ext2fs_unmark_block_bitmap(block_dup_map,
3839e657
TT
584 *block_nr);
585 *block_nr = new_block;
f3db3566 586 ext2fs_mark_block_bitmap(block_found_map,
3839e657 587 new_block);
f3db3566 588 ext2fs_mark_block_bitmap(fs->block_map, new_block);
3839e657
TT
589 return BLOCK_CHANGED;
590 } else
591 com_err("clone_file_block", 0,
592 "internal error; can't find dup_blk for %d\n",
593 *block_nr);
594 }
595 return 0;
596}
597
598static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
599{
600 errcode_t retval;
601 struct clone_struct cs;
602
603 cs.errcode = 0;
604 cs.buf = malloc(fs->blocksize);
605 if (!cs.buf)
606 return ENOMEM;
607
608 retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
609 clone_file_block, &cs);
610 ext2fs_mark_bb_dirty(fs);
611 free(cs.buf);
612 if (retval) {
613 com_err("clone_file", retval,
614 "while calling ext2fs_block_iterate for inode %d",
615 dp->ino);
616 return retval;
617 }
618 if (cs.errcode) {
619 com_err("clone_file", retval,
620 "returned from clone_file_block");
621 return retval;
622 }
623 return 0;
624}
625
626
627
628
629