Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / e2fsck / pass1.c
1 /*
2  * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
3  * 
4  * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
5  * redistributed under the terms of the GNU Public License.
6  * 
7  * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
8  * and applies the following tests to each inode:
9  *
10  *      - The mode field of the inode must be legal.
11  *      - The size and block count fields of the inode are correct.
12  *      - A data block must not be used by another inode
13  *
14  * Pass 1 also gathers the collects the following information:
15  *
16  *      - A bitmap of which inodes are in use.          (inode_used_map)
17  *      - A bitmap of which inodes are directories.     (inode_dir_map)
18  *      - A bitmap of which inodes have bad fields.     (inode_bad_map)
19  *      - A bitmap of which blocks are in use.          (block_found_map)
20  *      - A bitmap of which blocks are in use by two inodes     (block_dup_map)
21  *      - The data blocks of the directory inodes.      (dir_map)
22  *
23  * Pass 1 is designed to stash away enough information so that the
24  * other passes should not need to read in the inode information
25  * during the normal course of a filesystem check.  (Althogh if an
26  * inconsistency is detected, other passes may need to read in an
27  * inode to fix it.)
28  *
29  * Note that pass 1B will be invoked if there are any duplicate blocks
30  * found.
31  */
32
33 #include <time.h>
34
35 #include <et/com_err.h>
36 #include "e2fsck.h"
37
38 /* Files counts */
39 int fs_directory_count = 0;
40 int fs_regular_count = 0;
41 int fs_blockdev_count = 0;
42 int fs_chardev_count = 0;
43 int fs_links_count = 0;
44 int fs_symlinks_count = 0;
45 int fs_fast_symlinks_count = 0;
46 int fs_fifo_count = 0;
47 int fs_total_count = 0;
48 int fs_badblocks_count = 0;
49 int fs_sockets_count = 0;
50
51 char * inode_used_map = 0;      /* Inodes which are in use */
52 char * inode_bad_map = 0;       /* Inodes which are bad in some way */
53 char * inode_dir_map = 0;       /* Inodes which are directories */
54
55 char * block_found_map = 0;
56 char * block_dup_map = 0;
57 static char * bad_fs_block_map = 0;
58
59 static int fix_link_count = -1;
60
61 unsigned short * inode_link_info = NULL;
62
63 static int process_block(ext2_filsys fs, blk_t  *blocknr,
64                          int    blockcnt, void  *private);
65 static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
66                              int blockcnt, void *private);
67 static int process_fs_bad_block(ext2_filsys fs, blk_t *block_nr,
68                                 int blockcnt, void *private);
69 static void check_blocks(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
70                          char *block_buf);
71 static void mark_table_blocks(ext2_filsys fs);
72 static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino);
73 static errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks);
74 static void alloc_bad_map(ext2_filsys fs);
75 static void handle_fs_bad_blocks(ext2_filsys fs, char *block_buf);
76 static void process_inodes(ext2_filsys fs, char *block_buf);
77 static int process_inode_cmp(const void *a, const void *b);
78 static int dir_block_cmp(const void *a, const void *b);
79
80 struct process_block_struct {
81         ino_t   ino;
82         int     is_dir;
83         int     num_blocks;
84         int     last_block;
85         int     fix;
86 };
87
88 struct process_inode_block {
89         ino_t   ino;
90         struct ext2_inode inode;
91 };
92
93 /*
94  * For pass1_check_directory and pass1_get_blocks
95  */
96 ino_t stashed_ino;
97 struct ext2_inode *stashed_inode;
98
99 /*
100  * For the inodes to process list.
101  */
102 static struct process_inode_block *inodes_to_process;
103 static int process_inode_count;
104 int process_inode_size = 128;
105
106 /*
107  * For the directory blocks list.
108  */
109 struct dir_block_struct *dir_blocks = 0;
110 int     dir_block_count = 0;
111 int     dir_block_size = 0;
112
113 void pass1(ext2_filsys fs)
114 {
115         ino_t   ino;
116         struct ext2_inode inode;
117         ext2_inode_scan scan;
118         char            *block_buf;
119         errcode_t       retval;
120         struct resource_track   rtrack;
121         
122         init_resource_track(&rtrack);
123         
124         if (!preen)
125                 printf("Pass 1: Checking inodes, blocks, and sizes\n");
126
127 #ifdef MTRACE
128         mtrace_print("Pass 1");
129 #endif
130
131         /*
132          * Allocate bitmaps structures
133          */
134         retval = ext2fs_allocate_inode_bitmap(fs, &inode_used_map);
135         if (retval) {
136                 com_err("ext2fs_allocate_inode_bitmap", retval,
137                         "while allocating inode_used_map");
138                 fatal_error(0);
139         }
140         retval = ext2fs_allocate_inode_bitmap(fs, &inode_dir_map);
141         if (retval) {
142                 com_err("ext2fs_allocate_inode_bitmap", retval,
143                         "while allocating inode_dir_map");
144                 fatal_error(0);
145         }
146         retval = ext2fs_allocate_block_bitmap(fs, &block_found_map);
147         if (retval) {
148                 com_err("ext2fs_allocate_block_bitmap", retval,
149                         "while allocating block_found_map");
150                 fatal_error(0);
151         }
152         inode_link_info = allocate_memory((fs->super->s_inodes_count + 1) *
153                                           sizeof(unsigned short),
154                                           "inode link count array");
155         inodes_to_process = allocate_memory(process_inode_size *
156                                             sizeof(struct process_inode_block),
157                                             "array of inodes to process");
158         process_inode_count = 0;
159
160         dir_block_size = get_num_dirs(fs) * 4;
161         dir_block_count = 0;
162         dir_blocks = allocate_memory(sizeof(struct dir_block_struct) *
163                                      dir_block_size,
164                                      "directory block information");
165
166         mark_table_blocks(fs);
167         block_buf = allocate_memory(fs->blocksize * 3, "block interate buffer");
168         fs->get_blocks = pass1_get_blocks;
169         fs->check_directory = pass1_check_directory;
170         ehandler_operation("doing inode scan");
171         retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
172         if (retval) {
173                 com_err(program_name, retval, "while opening inode scan");
174                 fatal_error(0);
175         }
176         retval = ext2fs_get_next_inode(scan, &ino, &inode);
177         if (retval) {
178                 com_err(program_name, retval, "while starting inode scan");
179                 fatal_error(0);
180         }
181         stashed_inode = &inode;
182         while (ino) {
183                 stashed_ino = ino;
184                 inode_link_info[ino] = inode.i_links_count;
185                 if (ino == EXT2_BAD_INO) {
186                         struct process_block_struct pb;
187                         
188                         pb.ino = EXT2_BAD_INO;
189                         pb.num_blocks = pb.last_block = 0;
190                         pb.is_dir = 0;
191                         pb.fix = -1;
192                         retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
193                                                       process_bad_block, &pb);
194                         if (retval)
195                                 com_err(program_name, retval, "while calling e2fsc_block_interate in pass 1");
196
197                         ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
198                         goto next;
199                 }
200                 if (ino == EXT2_ROOT_INO) {
201                         /*
202                          * Make sure the root inode is a directory; if
203                          * not, offer to clear it.  It will be
204                          * regnerated in pass #3.
205                          */
206                         if (!S_ISDIR(inode.i_mode)) {
207                                 printf("Root inode is not a directory.  ");
208                                 preenhalt();
209                                 if (ask("Clear", 1)) {
210                                         inode.i_dtime = time(0);
211                                         inode.i_links_count = 0;
212                                         ext2fs_write_inode(fs, ino, &inode);
213                                 } else 
214                                         ext2fs_unmark_valid(fs);
215                         }
216                         /*
217                          * If dtime is set, offer to clear it.  mke2fs
218                          * version 0.2b created filesystems with the
219                          * dtime field set for the root and lost+found
220                          * directories.  We won't worry about
221                          * /lost+found, since that can be regenerated
222                          * easily.  But we will fix the root directory
223                          * as a special case.
224                          */
225                         if (inode.i_dtime && inode.i_links_count) {
226                                 if (ask("Root inode has dtime set "
227                                         "(probably due to old mke2fs).  Fix",
228                                         1)) {
229                                         inode.i_dtime = 0;
230                                         ext2fs_write_inode(fs, ino, &inode);
231                                         printf("Note: /lost+found will "
232                                                "probably be deleted as well, "
233                                                "due to the mke2fs bug.\n"
234                                                "Be sure to run mklost+found "
235                                                "to recreate it after e2fsck "
236                                                "finishes.\n\n");
237                                 } else
238                                         ext2fs_unmark_valid(fs);
239                         }
240                 }
241                 if ((ino != EXT2_ROOT_INO) && (ino < EXT2_FIRST_INO)) {
242                         ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
243                         check_blocks(fs, ino, &inode, block_buf);
244                         goto next;
245                 }
246                 /*
247                  * This code assumes that deleted inodes have
248                  * i_links_count set to 0.  
249                  */
250                 if (!inode.i_links_count) {
251                         if (!inode.i_dtime && inode.i_mode) {
252                                 printf("Deleted inode %ld has zero dtime.\n",
253                                        ino);
254                                 if (ask("Set dtime", 1)) {
255                                         inode.i_dtime = time(0);
256                                         ext2fs_write_inode(fs, ino, &inode);
257                                 } else
258                                         ext2fs_unmark_valid(fs);
259                         }
260                         goto next;
261                 }
262                 /*
263                  * 0.3c ext2fs code didn't clear i_links_count for
264                  * deleted files.  Oops.
265                  * 
266                  * In the future, when the new ext2fs behavior is the
267                  * norm, we may want to handle the case of a non-zero
268                  * i_links_count and non-zero dtime by clearing dtime
269                  * and assuming the inode is in use, instead of
270                  * assuming the inode is not in use.
271                  */
272                 if (inode.i_dtime) {
273                         if (fix_link_count == -1) {
274                                 printf("\nDeleted inode detected with non-zero link count.\n");
275                                 printf("This is probably due to old ext2fs kernel code.  \n");
276                                 fix_link_count = ask("Fix inode(s)", 1);
277                         }
278                         printf("Inode %ld is deleted w/ non-zero link_count.  %s\n",
279                                ino, clear_msg[fix_link_count]);
280                         if (fix_link_count) {
281                                 inode.i_links_count = 0;
282                                 ext2fs_write_inode(fs, ino, &inode);
283                         } else
284                                 ext2fs_unmark_valid(fs);
285                         goto next;
286                 }
287                 
288                 ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
289                 if (inode.i_faddr || inode.i_frag || inode.i_fsize ||
290                     inode.i_file_acl || inode.i_dir_acl) {
291                         if (!inode_bad_map)
292                                 alloc_bad_map(fs);
293                         ext2fs_mark_inode_bitmap(fs, inode_bad_map, ino);
294                 }
295                 
296                 if (S_ISDIR(inode.i_mode)) {
297                         ext2fs_mark_inode_bitmap(fs, inode_dir_map, ino);
298                         add_dir_info(fs, ino, 0, &inode);
299                         fs_directory_count++;
300                 } else if (S_ISREG (inode.i_mode))
301                         fs_regular_count++;
302                 else if (S_ISCHR (inode.i_mode))
303                         fs_chardev_count++;
304                 else if (S_ISBLK (inode.i_mode))
305                         fs_blockdev_count++;
306                 else if (S_ISLNK (inode.i_mode)) {
307                         fs_symlinks_count++;
308                         if (!inode.i_blocks)
309                                 fs_fast_symlinks_count++;
310                 }
311                 else if (S_ISFIFO (inode.i_mode))
312                         fs_fifo_count++;
313                 else if (S_ISSOCK (inode.i_mode))
314                         fs_sockets_count++;
315                 else {
316                         if (!inode_bad_map)
317                                 alloc_bad_map(fs);
318                         ext2fs_mark_inode_bitmap(fs, inode_bad_map, ino);
319                 }
320                 if (inode.i_block[EXT2_IND_BLOCK] ||
321                     inode.i_block[EXT2_DIND_BLOCK] ||
322                     inode.i_block[EXT2_TIND_BLOCK]) {
323                         inodes_to_process[process_inode_count].ino = ino;
324                         inodes_to_process[process_inode_count].inode = inode;
325                         process_inode_count++;
326                 } else 
327                         check_blocks(fs, ino, &inode, block_buf);
328                 inode_link_info[ino] = inode.i_links_count;
329
330                 if (process_inode_count >= process_inode_size)
331                         process_inodes(fs, block_buf);
332         next:
333                 retval = ext2fs_get_next_inode(scan, &ino, &inode);
334                 if (retval) {
335                         com_err(program_name, retval,
336                                 "while doing inode scan");
337                         fatal_error(0);
338                 }
339         }
340         process_inodes(fs, block_buf);
341         ext2fs_close_inode_scan(scan);
342         ehandler_operation(0);
343
344         qsort(dir_blocks, dir_block_count, sizeof(struct dir_block_struct),
345               dir_block_cmp);
346
347         if (block_dup_map) {
348                 if (preen) {
349                         printf("Duplicate or bad blocks in use!\n");
350                         preenhalt();
351                 }
352                 pass1_dupblocks(fs, block_buf);
353         }
354         fs->get_blocks = 0;
355         fs->check_directory = 0;
356         free(inodes_to_process);
357         if (bad_fs_block_map) {
358                 handle_fs_bad_blocks(fs, block_buf);
359                 free(bad_fs_block_map);
360         }
361         free(block_buf);
362
363         if (tflag > 1) {
364                 printf("Pass 1: ");
365                 print_resource_track(&rtrack);
366         }
367 }
368
369 /*
370  * Process the inodes in the "inodes to process" list.
371  */
372 static void process_inodes(ext2_filsys fs, char *block_buf)
373 {
374         int                     i;
375         struct ext2_inode       *old_stashed_inode;
376         ino_t                   ino;
377         const char              *old_operation;
378         char                    buf[80];
379
380 #if 0
381         printf("process_inodes: ");
382 #endif
383         old_operation = ehandler_operation(0);
384         old_stashed_inode = stashed_inode;
385         qsort(inodes_to_process, process_inode_count,
386                       sizeof(struct process_inode_block), process_inode_cmp);
387         for (i=0; i < process_inode_count; i++) {
388                 stashed_inode = &inodes_to_process[i].inode;
389                 ino = inodes_to_process[i].ino;
390                 stashed_ino = ino;
391 #if 0
392                 printf("%d ", ino);
393 #endif
394                 sprintf(buf, "reading indirect blocks of inode %ld", ino);
395                 ehandler_operation(buf);
396                 check_blocks(fs, ino, stashed_inode, block_buf);
397                 
398         }
399         stashed_inode = old_stashed_inode;
400         process_inode_count = 0;
401 #if 0
402         printf("\n");
403 #endif
404         ehandler_operation(old_operation);
405 }
406
407 static int process_inode_cmp(const void *a, const void *b)
408 {
409         const struct process_inode_block *ib_a =
410                 (const struct process_inode_block *) a;
411         const struct process_inode_block *ib_b =
412                 (const struct process_inode_block *) b;
413
414         return (ib_a->inode.i_block[EXT2_IND_BLOCK] -
415                 ib_b->inode.i_block[EXT2_IND_BLOCK]);
416 }
417
418 static int dir_block_cmp(const void *a, const void *b)
419 {
420         const struct dir_block_struct *db_a =
421                 (const struct dir_block_struct *) a;
422         const struct dir_block_struct *db_b =
423                 (const struct dir_block_struct *) b;
424
425         return (db_a->blk - db_b->blk);
426 }
427
428 /*
429  * This procedure will allocate the inode bad map table
430  */
431 static void alloc_bad_map(ext2_filsys fs)
432 {
433         errcode_t       retval;
434         
435         retval = ext2fs_allocate_inode_bitmap(fs, &inode_bad_map);
436         if (retval) {
437                 com_err("ext2fs_allocate_inode_bitmap", retval,
438                         "while allocating inode_bad_map");
439                 fatal_error(0);
440         }
441 }
442
443 /*
444  * Marks a block as in use, setting the dup_map if it's been set
445  * already.  Called by process_block and process_bad_block.
446  */
447 static void mark_block_used(ext2_filsys fs, blk_t block)
448 {
449         errcode_t       retval;
450         
451         if (ext2fs_test_block_bitmap(fs, block_found_map, block)) {
452                 if (!block_dup_map) {
453                         retval = ext2fs_allocate_block_bitmap(fs,
454                                                               &block_dup_map);
455                         if (retval) {
456                                 com_err("ext2fs_allocate_block_bitmap", retval,
457                                         "while allocating block_dup_map");
458                                 fatal_error(0);
459                         }
460                 }
461                 ext2fs_mark_block_bitmap(fs, block_dup_map, block);
462         } else {
463                 ext2fs_mark_block_bitmap(fs, block_found_map, block);
464         }
465 }
466
467 /*
468  * This subroutine is called on each inode to account for all of the
469  * blocks used by that inode.
470  */
471 static void check_blocks(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
472                          char *block_buf)
473 {
474         struct process_block_struct pb;
475         errcode_t       retval;
476         
477         if (!inode_has_valid_blocks(inode))
478                 return;
479         
480         pb.ino = ino;
481         pb.num_blocks = pb.last_block = 0;
482         pb.is_dir = S_ISDIR(inode->i_mode);
483         pb.fix = -1;
484         retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
485                                       process_block, &pb);
486         if (retval)
487                 com_err(program_name, retval,
488                         "while calling ext2fs_block_iterate in check_blocks");
489
490         pb.num_blocks *= (fs->blocksize / 512);
491 #if 0
492         printf("inode %d, i_size = %d, last_block = %d, i_blocks=%d, num_blocks = %d\n",
493                ino, inode->i_size, pb.last_block, inode->i_blocks,
494                pb.num_blocks);
495 #endif
496         if (!pb.num_blocks && pb.is_dir) {
497                 printf("Inode %ld is a zero length directory.  ", ino);
498                 if (ask("Clear", 1)) {
499                         inode->i_links_count = 0;
500                         inode->i_dtime = time(0);
501                         ext2fs_write_inode(fs, ino, inode);
502                         ext2fs_unmark_inode_bitmap(fs, inode_dir_map, ino);
503                         ext2fs_unmark_inode_bitmap(fs, inode_used_map, ino);
504                         fs_directory_count--;
505                 } else
506                         ext2fs_unmark_valid(fs);
507         }
508         if (inode->i_size < pb.last_block * fs->blocksize) {
509                 printf ("Inode %ld, incorrect size, %ld (counted = %d). ",
510                         ino, inode->i_size,
511                         (pb.last_block+1) * fs->blocksize);
512                 if (ask ("Set size to counted", 1)) {
513                         inode->i_size = (pb.last_block+1) * fs->blocksize;
514                         ext2fs_write_inode(fs, ino, inode);
515                 } else
516                         ext2fs_unmark_valid(fs);
517         }
518         if (pb.num_blocks != inode->i_blocks) {
519                 printf ("Inode %ld, i_blocks wrong %ld (counted=%d) .",
520                         ino, inode->i_blocks, pb.num_blocks);
521                 if (ask ("Set i_blocks to counted", 1)) {
522                         inode->i_blocks = pb.num_blocks;
523                         ext2fs_write_inode(fs, ino, inode);
524                 } else
525                                 ext2fs_unmark_valid(fs);
526         }
527 }       
528
529 /*
530  * This is a helper function for check_blocks().
531  */
532 int process_block(ext2_filsys fs,
533                   blk_t *block_nr,
534                   int blockcnt,
535                   void *private)
536 {
537         struct process_block_struct *p;
538         int     group;
539         int     illegal_block = 0;
540         char    problem[80];
541         blk_t   firstblock;
542         blk_t   blk = *block_nr;
543
544         if (!blk)
545                 return 0;
546         p = (struct process_block_struct *) private;
547
548 #if 0
549         printf("Process_block, inode %d, block %d, #%d\n", p->ino, blk,
550                blockcnt);
551 #endif  
552         
553         p->num_blocks++;
554         if (blockcnt > 0)
555                 p->last_block = blockcnt;
556
557         firstblock = fs->super->s_first_data_block;
558         group = (blk - firstblock) / fs->super->s_blocks_per_group;
559         if (blk < firstblock) {
560                 sprintf(problem, "< FIRSTBLOCK (%ld)", firstblock);
561                 illegal_block++;
562         } else if (blk >= fs->super->s_blocks_count) {
563                 sprintf(problem, "> BLOCKS (%ld)", fs->super->s_blocks_count);
564                 illegal_block++;
565         } else if (blk == fs->group_desc[group].bg_block_bitmap) {
566                 sprintf(problem, "is the block bitmap of group %d", group);
567                 illegal_block++;
568         } else if (blk == fs->group_desc[group].bg_inode_bitmap) {
569                 sprintf(problem, "is the inode bitmap of group %d", group);
570                 illegal_block++;
571         } else if (blk >= fs->group_desc[group].bg_inode_table &&
572                    blk < fs->group_desc[group].bg_inode_table + fs->inode_blocks_per_group) {
573                 sprintf(problem, "is in the inode table of group %d", group);
574                 illegal_block++;
575         }
576         if (illegal_block) {
577                 if (preen) {
578                         printf("Block %ld of inode %ld %s\n", blk, p->ino,
579                                problem);
580                         preenhalt();
581                 }
582                 if (p->fix == -1) {
583                         printf("Remove illegal block(s) in inode %ld", p->ino);
584                         p->fix = ask("", 1);
585                 }
586                 printf("Block #%d (%ld) %s.  %s\n", blockcnt, blk, problem,
587                        clear_msg[p->fix]);
588                 if (p->fix) {
589                         *block_nr = 0;
590                         return BLOCK_CHANGED;
591                 } else {
592                         ext2fs_unmark_valid(fs);
593                         return 0;
594                 }
595         }
596
597         mark_block_used(fs, blk);
598         
599         if (p->is_dir && (blockcnt >= 0)) {
600                 if (dir_block_count >= dir_block_size) {
601                         dir_block_size += 100;
602                         dir_blocks = realloc(dir_blocks,
603                                              dir_block_size *
604                                              sizeof(struct dir_block_struct));
605                 }
606
607                 dir_blocks[dir_block_count].blk = blk;
608                 dir_blocks[dir_block_count].ino = p->ino;
609                 dir_blocks[dir_block_count].blockcnt = blockcnt;
610                 dir_block_count++;
611         }
612         
613 #if 0
614         printf("process block, inode %d, block #%d is %d\n",
615                p->ino, blockcnt, blk);
616 #endif
617         
618         return 0;
619 }
620
621 int process_bad_block(ext2_filsys fs,
622                       blk_t *block_nr,
623                       int blockcnt,
624                       void *private)
625 {
626         struct process_block_struct *p;
627         errcode_t       retval;
628         blk_t           blk = *block_nr;
629         
630         if (!blk)
631                 return 0;
632         p = (struct process_block_struct *) private;
633
634         if ((blk < fs->super->s_first_data_block) ||
635             (blk >= fs->super->s_blocks_count)) {
636                 if (preen) {
637                         printf("Illegal block %ld in bad block inode\n", blk);
638                         preenhalt();
639                 }
640                 if (p->fix == -1)
641                         p->fix = ask("Remove illegal block(s) in bad block inode", 1);
642                 printf("Illegal block %ld in bad block inode.  %s\n", blk,
643                        clear_msg[p->fix]);
644                 if (p->fix) {
645                         *block_nr = 0;
646                         return BLOCK_CHANGED;
647                 } else {
648                         ext2fs_unmark_valid(fs);
649                         return 0;
650                 }
651         }
652
653         if (blockcnt < 0) {
654                 mark_block_used(fs, blk);
655                 return 0;
656         }
657 #if 0 
658         printf ("DEBUG: Marking %d as bad.\n", blk);
659 #endif
660         fs_badblocks_count++;
661         /*
662          * If the block is not used, then mark it as used and return.
663          * If it is already marked as found, this must mean that
664          * there's an overlap between the filesystem table blocks
665          * (bitmaps and inode table) and the bad block list.
666          */
667         if (!ext2fs_test_block_bitmap(fs, block_found_map, blk)) {
668                 ext2fs_mark_block_bitmap(fs, block_found_map, blk);
669                 return 0;
670         }
671         if (!bad_fs_block_map) {
672                 retval = ext2fs_allocate_inode_bitmap(fs, &bad_fs_block_map);
673                 if (retval) {
674                         com_err("ext2fs_allocate_block_bitmap", retval,
675                                 "while allocating bad_fs_block_map");
676                 fatal_error(0);
677                 }
678         }
679         ext2fs_mark_block_bitmap(fs, bad_fs_block_map, blk);
680         return 0;
681 }
682
683 /*
684  * This routine gets called at the end of pass 1 if bad blocks are
685  * detected in the superblock, group descriptors, inode_bitmaps, or
686  * block bitmaps.  At this point, all of the blocks have been mapped
687  * out, so we can try to allocate new block(s) to replace the bad
688  * blocks.
689  */
690 static void handle_fs_bad_blocks(ext2_filsys fs, char *block_buf)
691 {
692         errcode_t       retval;
693         
694         printf("Warning: Bad block(s) found in filesystem-reserved blocks.\n");
695         
696         retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, block_buf,
697                                       process_fs_bad_block, 0);
698 }
699
700 static void new_table_block(ext2_filsys fs, blk_t first_block,
701                             const char *name, int num, blk_t *new_block)
702 {
703         errcode_t       retval;
704         blk_t           old_block = *new_block;
705         int             i;
706         char            *buf;
707         
708         retval = ext2fs_get_free_blocks(fs, first_block,
709                         first_block + fs->super->s_blocks_per_group,
710                                         num, block_found_map, new_block);
711         if (retval) {
712                 printf("Could not allocate %d block(s) for %s: %s\n",
713                        num, name, error_message(retval));
714                 ext2fs_unmark_valid(fs);
715                 return;
716         }
717         buf = malloc(fs->blocksize);
718         if (!buf) {
719                 printf("Could not allocate block buffer for relocating %s\n",
720                        name);
721                 ext2fs_unmark_valid(fs);
722                 return;
723         }
724         ext2fs_mark_super_dirty(fs);
725         for (i = 0; i < num; i++) {
726                 ext2fs_mark_block_bitmap(fs, block_found_map, (*new_block)+i);
727                 retval = io_channel_read_blk(fs->io, old_block + i,
728                                              1, buf);
729                 if (retval)
730                         printf("Warning: could not read block %ld of %s: %s\n",
731                                old_block + i, name, error_message(retval));
732                 retval = io_channel_write_blk(fs->io, (*new_block) + i,
733                                               1, buf);
734                 if (retval)
735                         printf("Warning: could not write block %ld for %s: %s\n",
736                                (*new_block) + i, name, error_message(retval));
737                 /*
738                  * If this particular block is not marked as bad, then
739                  * clear its bit in the block_found map.  Otherwise,
740                  * leave it set, since it is included in the bad
741                  * blocks inode.
742                  */
743                 if (!ext2fs_test_block_bitmap(fs, bad_fs_block_map,
744                                               old_block + i))
745                         ext2fs_unmark_block_bitmap(fs, block_found_map,
746                                                    old_block + i);
747                 /*
748                  * Clear the bitmap since this block has now been moved.
749                  */
750                 ext2fs_unmark_block_bitmap(fs, bad_fs_block_map,
751                                            old_block + i);
752         }
753         free(buf);
754 }
755
756 /*
757  * Helper function for handle_fs_bad_blocks()
758  */
759 static int process_fs_bad_block(ext2_filsys fs, blk_t *block_nr,
760                              int blockcnt, void *private)
761 {
762         int     i;
763         blk_t   block = *block_nr;
764         int     first_block = fs->super->s_first_data_block;
765
766         /*
767          * If this block isn't one that is marked as a bad block in
768          * the filesystem tables, return
769          */
770         if (!ext2fs_test_block_bitmap(fs, bad_fs_block_map, block))
771                 return 0;
772
773         for (i = 0; i < fs->group_desc_count; i++) {
774                 if (block == first_block)
775                         printf("Bad block %ld in group %d's superblock.\n",
776                                block, i);
777                 if (block == fs->group_desc[i].bg_block_bitmap) {
778                         printf("Bad block %ld in group %d's block bitmap.  ",
779                                block, i);
780                         if (ask("Relocate", 1)) {
781                                 new_table_block(fs, first_block,
782                                                 "block bitmap", 1, 
783                                         &fs->group_desc[i].bg_block_bitmap);
784                         } else
785                                 ext2fs_unmark_valid(fs);
786                 }
787                 if (block == fs->group_desc[i].bg_inode_bitmap) {
788                         printf("Bad block %ld in group %d's inode bitmap.  ",
789                                block, i);
790                         if (ask("Relocate", 1)) {
791                                 new_table_block(fs, first_block,
792                                                 "inode bitmap", 1, 
793                                         &fs->group_desc[i].bg_inode_bitmap);
794                         } else
795                                 ext2fs_unmark_valid(fs);
796                 }
797                 if ((block >= fs->group_desc[i].bg_inode_table) &&
798                     (block < (fs->group_desc[i].bg_inode_table +
799                               fs->inode_blocks_per_group))) {
800                         printf("WARNING: Severe data loss possible!!!!\n");
801                         printf("Bad block %ld in group %d's inode table.  ",
802                                block, i);
803                         if (ask("Relocate", 1)) {
804                                 new_table_block(fs, first_block,
805                                                 "inode table",
806                                                 fs->inode_blocks_per_group, 
807                                         &fs->group_desc[i].bg_inode_table);
808                         } else
809                                 ext2fs_unmark_valid(fs);
810                 }
811                 if ((block > first_block) &&
812                     (block <= first_block + fs->desc_blocks))
813                         printf("Bad block %ld in group %d's copy of the descriptors.\n",
814                                block, i);
815                 first_block += fs->super->s_blocks_per_group;
816         }
817         return 0;
818 }
819
820 /*
821  * This routine marks all blocks which are used by the superblock,
822  * group descriptors, inode bitmaps, and block bitmaps.
823  */
824 static void mark_table_blocks(ext2_filsys fs)
825 {
826         blk_t   block;
827         int     i,j;
828         
829         block = fs->super->s_first_data_block;
830         for (i = 0; i < fs->group_desc_count; i++) {
831                 /*
832                  * Mark block used for the block bitmap 
833                  */
834                 ext2fs_mark_block_bitmap(fs, block_found_map,
835                                          fs->group_desc[i].bg_block_bitmap);
836                 /*
837                  * Mark block used for the inode bitmap 
838                  */
839                 ext2fs_mark_block_bitmap(fs, block_found_map,
840                                          fs->group_desc[i].bg_inode_bitmap);
841                 /*
842                  * Mark the blocks used for the inode table
843                  */
844                 for (j = 0; j < fs->inode_blocks_per_group; j++)
845                         ext2fs_mark_block_bitmap(fs, block_found_map,
846                                                  fs->group_desc[i].bg_inode_table + j);
847                 /*
848                  * Mark this group's copy of the superblock
849                  */
850                 ext2fs_mark_block_bitmap(fs, block_found_map, block);
851                 
852                 /*
853                  * Mark this group's copy of the descriptors
854                  */
855                 for (j = 0; j < fs->desc_blocks; j++)
856                         ext2fs_mark_block_bitmap(fs, block_found_map,
857                                                  block + j + 1);
858                 block += fs->super->s_blocks_per_group;
859         }
860 }
861         
862 /*
863  * This subroutines short circuits ext2fs_get_blocks and
864  * ext2fs_check_directory; we use them since we already have the inode
865  * structure, so there's no point in letting the ext2fs library read
866  * the inode again.
867  */
868 static errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
869 {
870         int     i;
871         
872         if (ino == stashed_ino) {
873                 for (i=0; i < EXT2_N_BLOCKS; i++)
874                         blocks[i] = stashed_inode->i_block[i];
875                 return 0;
876         }
877         printf("INTERNAL ERROR: pass1_get_blocks: unexpected inode #%ld\n",
878                ino);
879         printf("\t(was expecting %ld)\n", stashed_ino);
880         exit(FSCK_ERROR);
881 }
882
883 static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
884 {
885         if (ino == stashed_ino) {
886                 if (!S_ISDIR(stashed_inode->i_mode))
887                         return ENOTDIR;
888                 return 0;
889         }
890         printf("INTERNAL ERROR: pass1_check_directory: unexpected inode #%ld\n",
891                ino);
892         printf("\t(was expecting %ld)\n", stashed_ino);
893         exit(FSCK_ERROR);
894 }