blob: 3af03f433c63e88375fd64f724afd1dd8532bb2c [file] [log] [blame]
Mike Frysinger51a43b42005-09-24 07:11:16 +00001/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002 * e2fsck
3 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 * This file may be
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006 * redistributed under the terms of the GNU Public License.
7 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008 *
9 * Dictionary Abstract Data Type
10 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
11 * Free Software License:
12 * All rights are reserved by the author, with the following exceptions:
13 * Permission is granted to freely reproduce and distribute this software,
14 * possibly in exchange for a fee, provided that this copyright notice appears
15 * intact. Permission is also granted to adapt this software to produce
16 * derivative works, as long as the modified versions carry this copyright
17 * notice and additional notices stating that the work has been modified.
18 * This source code may be translated into executable form and incorporated
19 * into proprietary software; there is no requirement for such software to
20 * contain a copyright notice related to this source.
21 *
22 * linux/fs/recovery and linux/fs/revoke
23 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
24 *
25 * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
26 *
27 * This file is part of the Linux kernel and is made available under
28 * the terms of the GNU General Public License, version 2, or at your
29 * option, any later version, incorporated herein by reference.
30 *
31 * Journal recovery routines for the generic filesystem journaling code;
32 * part of the ext2fs journaling system.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000033 */
34
35#ifndef _GNU_SOURCE
36#define _GNU_SOURCE 1 /* get strnlen() */
37#endif
38#include <sys/types.h>
39#include <inttypes.h>
40#include <stdio.h>
41#include <string.h>
42#include <unistd.h>
43#include <stdlib.h>
44#include <time.h>
45#include <fcntl.h>
46#include <ctype.h>
47#include <setjmp.h>
48#include <errno.h>
49#include <getopt.h>
50#include <limits.h>
51#include <stddef.h>
52#include <assert.h>
53#include <signal.h>
54#include <sys/time.h>
55#include <sys/stat.h>
56#include <sys/resource.h>
57#include <sys/param.h>
58#include <sys/mount.h>
59#include <sys/ioctl.h>
60#include <malloc.h>
61#include <termios.h>
62#include <mntent.h>
63#include <dirent.h>
64
65#include "e2fsbb.h"
66
67#include "ext2fs/ext2_fs.h"
68#include "ext2fs/ext2fs.h"
69#include "blkid/blkid.h"
70#include "ext2fs/ext2_ext_attr.h"
71#include "uuid/uuid.h"
72
73#ifdef __GNUC__
74#define _INLINE_ __inline__
75#define EXT2FS_ATTR(x) __attribute__(x)
76#else
77#define _INLINE_
78#define EXT2FS_ATTR(x)
79#endif
80
81/*
82 * Exit codes used by fsck-type programs
83 */
84#define FSCK_OK 0 /* No errors */
85#define FSCK_NONDESTRUCT 1 /* File system errors corrected */
86#define FSCK_REBOOT 2 /* System should be rebooted */
87#define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */
88#define FSCK_ERROR 8 /* Operational error */
89#define FSCK_USAGE 16 /* Usage or syntax error */
90#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
91#define FSCK_LIBRARY 128 /* Shared library error */
92
93/*
94 * The last ext2fs revision level that this version of e2fsck is able to
95 * support
96 */
97#define E2FSCK_CURRENT_REV 1
98
99/*
100 * The directory information structure; stores directory information
101 * collected in earlier passes, to avoid disk i/o in fetching the
102 * directory information.
103 */
104struct dir_info {
105 ext2_ino_t ino; /* Inode number */
106 ext2_ino_t dotdot; /* Parent according to '..' */
107 ext2_ino_t parent; /* Parent according to treewalk */
108};
109
110
111/*
112 * The indexed directory information structure; stores information for
113 * directories which contain a hash tree index.
114 */
115struct dx_dir_info {
116 ext2_ino_t ino; /* Inode number */
117 int numblocks; /* number of blocks */
118 int hashversion;
119 short depth; /* depth of tree */
120 struct dx_dirblock_info *dx_block; /* Array of size numblocks */
121};
122
123#define DX_DIRBLOCK_ROOT 1
124#define DX_DIRBLOCK_LEAF 2
125#define DX_DIRBLOCK_NODE 3
126#define DX_DIRBLOCK_CORRUPT 4
127#define DX_DIRBLOCK_CLEARED 8
128
129struct dx_dirblock_info {
130 int type;
131 blk_t phys;
132 int flags;
133 blk_t parent;
134 ext2_dirhash_t min_hash;
135 ext2_dirhash_t max_hash;
136 ext2_dirhash_t node_min_hash;
137 ext2_dirhash_t node_max_hash;
138};
139
140#define DX_FLAG_REFERENCED 1
141#define DX_FLAG_DUP_REF 2
142#define DX_FLAG_FIRST 4
143#define DX_FLAG_LAST 8
144
145#ifdef RESOURCE_TRACK
146/*
147 * This structure is used for keeping track of how much resources have
148 * been used for a particular pass of e2fsck.
149 */
150struct resource_track {
151 struct timeval time_start;
152 struct timeval user_start;
153 struct timeval system_start;
154 void *brk_start;
155};
156#endif
157
158/*
159 * E2fsck options
160 */
161#define E2F_OPT_READONLY 0x0001
162#define E2F_OPT_PREEN 0x0002
163#define E2F_OPT_YES 0x0004
164#define E2F_OPT_NO 0x0008
165#define E2F_OPT_TIME 0x0010
166#define E2F_OPT_TIME2 0x0020
167#define E2F_OPT_CHECKBLOCKS 0x0040
168#define E2F_OPT_DEBUG 0x0080
169#define E2F_OPT_FORCE 0x0100
170#define E2F_OPT_WRITECHECK 0x0200
171#define E2F_OPT_COMPRESS_DIRS 0x0400
172
173/*
174 * E2fsck flags
175 */
176#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
177#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
178#define E2F_FLAG_SIGNAL_MASK 0x0003
179#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
180
181#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
182
183#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
184#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */
185#define E2F_FLAG_JOURNAL_INODE 0x0080 /* Create a new ext3 journal inode */
186#define E2F_FLAG_SB_SPECIFIED 0x0100 /* The superblock was explicitly
187 * specified by the user */
188#define E2F_FLAG_RESTARTED 0x0200 /* E2fsck has been restarted */
189#define E2F_FLAG_RESIZE_INODE 0x0400 /* Request to recreate resize inode */
190
191/*
192 * Defines for indicating the e2fsck pass number
193 */
194#define E2F_PASS_1 1
195#define E2F_PASS_2 2
196#define E2F_PASS_3 3
197#define E2F_PASS_4 4
198#define E2F_PASS_5 5
199#define E2F_PASS_1B 6
200
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000201
202/*
203 * This is the global e2fsck structure.
204 */
205typedef struct e2fsck_struct *e2fsck_t;
206
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000207/*
208 * Define the extended attribute refcount structure
209 */
210typedef struct ea_refcount *ext2_refcount_t;
211
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000212struct e2fsck_struct {
213 ext2_filsys fs;
214 const char *program_name;
215 char *filesystem_name;
216 char *device_name;
217 char *io_options;
218 int flags; /* E2fsck internal flags */
219 int options;
220 blk_t use_superblock; /* sb requested by user */
221 blk_t superblock; /* sb used to open fs */
222 int blocksize; /* blocksize */
223 blk_t num_blocks; /* Total number of blocks */
224 int mount_flags;
225 blkid_cache blkid; /* blkid cache */
226
227 jmp_buf abort_loc;
228
229 unsigned long abort_code;
230
231 int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
232 unsigned long max);
233
234 ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
235 ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
236 ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
237 ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
238 ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
239 ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
240
241 ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
242 ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
243 ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
244
245 /*
246 * Inode count arrays
247 */
248 ext2_icount_t inode_count;
249 ext2_icount_t inode_link_info;
250
251 ext2_refcount_t refcount;
252 ext2_refcount_t refcount_extra;
253
254 /*
255 * Array of flags indicating whether an inode bitmap, block
256 * bitmap, or inode table is invalid
257 */
258 int *invalid_inode_bitmap_flag;
259 int *invalid_block_bitmap_flag;
260 int *invalid_inode_table_flag;
261 int invalid_bitmaps; /* There are invalid bitmaps/itable */
262
263 /*
264 * Block buffer
265 */
266 char *block_buf;
267
268 /*
269 * For pass1_check_directory and pass1_get_blocks
270 */
271 ext2_ino_t stashed_ino;
272 struct ext2_inode *stashed_inode;
273
274 /*
275 * Location of the lost and found directory
276 */
277 ext2_ino_t lost_and_found;
278 int bad_lost_and_found;
279
280 /*
281 * Directory information
282 */
283 int dir_info_count;
284 int dir_info_size;
285 struct dir_info *dir_info;
286
287 /*
288 * Indexed directory information
289 */
290 int dx_dir_info_count;
291 int dx_dir_info_size;
292 struct dx_dir_info *dx_dir_info;
293
294 /*
295 * Directories to hash
296 */
297 ext2_u32_list dirs_to_hash;
298
299 /*
300 * Tuning parameters
301 */
302 int process_inode_size;
303 int inode_buffer_blocks;
304
305 /*
306 * ext3 journal support
307 */
308 io_channel journal_io;
309 char *journal_name;
310
311#ifdef RESOURCE_TRACK
312 /*
313 * For timing purposes
314 */
315 struct resource_track global_rtrack;
316#endif
317
318 /*
319 * How we display the progress update (for unix)
320 */
321 int progress_fd;
322 int progress_pos;
323 int progress_last_percent;
324 unsigned int progress_last_time;
325 int interactive; /* Are we connected directly to a tty? */
326 char start_meta[2], stop_meta[2];
327
328 /* File counts */
329 int fs_directory_count;
330 int fs_regular_count;
331 int fs_blockdev_count;
332 int fs_chardev_count;
333 int fs_links_count;
334 int fs_symlinks_count;
335 int fs_fast_symlinks_count;
336 int fs_fifo_count;
337 int fs_total_count;
338 int fs_badblocks_count;
339 int fs_sockets_count;
340 int fs_ind_count;
341 int fs_dind_count;
342 int fs_tind_count;
343 int fs_fragmented;
344 int large_files;
345 int fs_ext_attr_inodes;
346 int fs_ext_attr_blocks;
347
348 int ext_attr_ver;
349
350 /*
351 * For the use of callers of the e2fsck functions; not used by
352 * e2fsck functions themselves.
353 */
354 void *priv_data;
355};
356
357/* Used by the region allocation code */
358typedef __u32 region_addr_t;
359typedef struct region_struct *region_t;
360
361/*
362 * Procedure declarations
363 */
364
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000365static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000366
367/* pass1.c */
368static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000369
370/* pass2.c */
371static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
372 ext2_ino_t ino, char *buf);
373
374/* pass3.c */
375static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
376static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
377 int num, int gauranteed_size);
378static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
379static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
380 int adj);
381
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000382/* rehash.c */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000383static void e2fsck_rehash_directories(e2fsck_t ctx);
384
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000385/* util.c */
386static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
387 const char *description);
388static int ask(e2fsck_t ctx, const char * string, int def);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000389static void e2fsck_read_bitmaps(e2fsck_t ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000390static void preenhalt(e2fsck_t ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000391#ifdef RESOURCE_TRACK
392static void print_resource_track(const char *desc,
393 struct resource_track *track);
394static void init_resource_track(struct resource_track *track);
395#endif
396static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
397 struct ext2_inode * inode, const char * proc);
398static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
399 struct ext2_inode * inode, const char * proc);
400#ifdef MTRACE
401static void mtrace_print(char *mesg);
402#endif
403static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
404 const char *name, io_manager manager);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000405
406/* unix.c */
407static void e2fsck_clear_progbar(e2fsck_t ctx);
408static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
409 float percent, unsigned int dpynum);
410/*
411 * problem.h --- e2fsck problem error codes
412 */
413
414typedef __u32 problem_t;
415
416struct problem_context {
417 errcode_t errcode;
418 ext2_ino_t ino, ino2, dir;
419 struct ext2_inode *inode;
420 struct ext2_dir_entry *dirent;
421 blk_t blk, blk2;
422 e2_blkcnt_t blkcount;
423 int group;
424 __u64 num;
425 const char *str;
426};
427
428/*
429 * We define a set of "latch groups"; these are problems which are
430 * handled as a set. The user answers once for a particular latch
431 * group.
432 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +0000433#define PR_LATCH_MASK 0x0ff0 /* Latch mask */
434#define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */
435#define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */
436#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */
437#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */
438#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */
439#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */
440#define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
441#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +0000442#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
443
444#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
445
446/*
447 * Latch group descriptor flags
448 */
449#define PRL_YES 0x0001 /* Answer yes */
450#define PRL_NO 0x0002 /* Answer no */
451#define PRL_LATCHED 0x0004 /* The latch group is latched */
452#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */
453
454#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */
455
456/*
457 * Pre-Pass 1 errors
458 */
459
460/* Block bitmap not in group */
461#define PR_0_BB_NOT_GROUP 0x000001
462
463/* Inode bitmap not in group */
464#define PR_0_IB_NOT_GROUP 0x000002
465
466/* Inode table not in group */
467#define PR_0_ITABLE_NOT_GROUP 0x000003
468
469/* Superblock corrupt */
470#define PR_0_SB_CORRUPT 0x000004
471
472/* Filesystem size is wrong */
473#define PR_0_FS_SIZE_WRONG 0x000005
474
475/* Fragments not supported */
476#define PR_0_NO_FRAGMENTS 0x000006
477
478/* Bad blocks_per_group */
479#define PR_0_BLOCKS_PER_GROUP 0x000007
480
481/* Bad first_data_block */
482#define PR_0_FIRST_DATA_BLOCK 0x000008
483
484/* Adding UUID to filesystem */
485#define PR_0_ADD_UUID 0x000009
486
487/* Relocate hint */
488#define PR_0_RELOCATE_HINT 0x00000A
489
490/* Miscellaneous superblock corruption */
491#define PR_0_MISC_CORRUPT_SUPER 0x00000B
492
493/* Error determing physical device size of filesystem */
494#define PR_0_GETSIZE_ERROR 0x00000C
495
496/* Inode count in the superblock incorrect */
497#define PR_0_INODE_COUNT_WRONG 0x00000D
498
499/* The Hurd does not support the filetype feature */
500#define PR_0_HURD_CLEAR_FILETYPE 0x00000E
501
502/* Journal inode is invalid */
503#define PR_0_JOURNAL_BAD_INODE 0x00000F
504
505/* The external journal has multiple filesystems (which we can't handle yet) */
506#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010
507
508/* Can't find external journal */
509#define PR_0_CANT_FIND_JOURNAL 0x000011
510
511/* External journal has bad superblock */
512#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012
513
514/* Superblock has a bad journal UUID */
515#define PR_0_JOURNAL_BAD_UUID 0x000013
516
517/* Journal has an unknown superblock type */
518#define PR_0_JOURNAL_UNSUPP_SUPER 0x000014
519
520/* Journal superblock is corrupt */
521#define PR_0_JOURNAL_BAD_SUPER 0x000015
522
523/* Journal superblock is corrupt */
524#define PR_0_JOURNAL_HAS_JOURNAL 0x000016
525
526/* Superblock has recovery flag set but no journal */
527#define PR_0_JOURNAL_RECOVER_SET 0x000017
528
529/* Journal has data, but recovery flag is clear */
530#define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018
531
532/* Ask if we should clear the journal */
533#define PR_0_JOURNAL_RESET_JOURNAL 0x000019
534
535/* Filesystem revision is 0, but feature flags are set */
536#define PR_0_FS_REV_LEVEL 0x00001A
537
538/* Clearing orphan inode */
539#define PR_0_ORPHAN_CLEAR_INODE 0x000020
540
541/* Illegal block found in orphaned inode */
542#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021
543
544/* Already cleared block found in orphaned inode */
545#define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK 0x000022
546
547/* Illegal orphan inode in superblock */
548#define PR_0_ORPHAN_ILLEGAL_HEAD_INODE 0x000023
549
550/* Illegal inode in orphaned inode list */
551#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024
552
553/* Journal has unsupported read-only feature - abort */
554#define PR_0_JOURNAL_UNSUPP_ROCOMPAT 0x000025
555
556/* Journal has unsupported incompatible feature - abort */
557#define PR_0_JOURNAL_UNSUPP_INCOMPAT 0x000026
558
559/* Journal has unsupported version number */
560#define PR_0_JOURNAL_UNSUPP_VERSION 0x000027
561
562/* Moving journal to hidden file */
563#define PR_0_MOVE_JOURNAL 0x000028
564
565/* Error moving journal */
566#define PR_0_ERR_MOVE_JOURNAL 0x000029
567
568/* Clearing V2 journal superblock */
569#define PR_0_CLEAR_V2_JOURNAL 0x00002A
570
571/* Run journal anyway */
572#define PR_0_JOURNAL_RUN 0x00002B
573
574/* Run journal anyway by default */
575#define PR_0_JOURNAL_RUN_DEFAULT 0x00002C
576
577/* Backup journal inode blocks */
578#define PR_0_BACKUP_JNL 0x00002D
579
580/* Reserved blocks w/o resize_inode */
581#define PR_0_NONZERO_RESERVED_GDT_BLOCKS 0x00002E
582
583/* Resize_inode not enabled, but resize inode is non-zero */
584#define PR_0_CLEAR_RESIZE_INODE 0x00002F
585
586/* Resize inode invalid */
587#define PR_0_RESIZE_INODE_INVALID 0x000030
588
589/*
590 * Pass 1 errors
591 */
592
593/* Pass 1: Checking inodes, blocks, and sizes */
594#define PR_1_PASS_HEADER 0x010000
595
596/* Root directory is not an inode */
597#define PR_1_ROOT_NO_DIR 0x010001
598
599/* Root directory has dtime set */
600#define PR_1_ROOT_DTIME 0x010002
601
602/* Reserved inode has bad mode */
603#define PR_1_RESERVED_BAD_MODE 0x010003
604
605/* Deleted inode has zero dtime */
606#define PR_1_ZERO_DTIME 0x010004
607
608/* Inode in use, but dtime set */
609#define PR_1_SET_DTIME 0x010005
610
611/* Zero-length directory */
612#define PR_1_ZERO_LENGTH_DIR 0x010006
613
614/* Block bitmap conflicts with some other fs block */
615#define PR_1_BB_CONFLICT 0x010007
616
617/* Inode bitmap conflicts with some other fs block */
618#define PR_1_IB_CONFLICT 0x010008
619
620/* Inode table conflicts with some other fs block */
621#define PR_1_ITABLE_CONFLICT 0x010009
622
623/* Block bitmap is on a bad block */
624#define PR_1_BB_BAD_BLOCK 0x01000A
625
626/* Inode bitmap is on a bad block */
627#define PR_1_IB_BAD_BLOCK 0x01000B
628
629/* Inode has incorrect i_size */
630#define PR_1_BAD_I_SIZE 0x01000C
631
632/* Inode has incorrect i_blocks */
633#define PR_1_BAD_I_BLOCKS 0x01000D
634
635/* Illegal block number in inode */
636#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E
637
638/* Block number overlaps fs metadata */
639#define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F
640
641/* Inode has illegal blocks (latch question) */
642#define PR_1_INODE_BLOCK_LATCH 0x010010
643
644/* Too many bad blocks in inode */
645#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011
646
647/* Illegal block number in bad block inode */
648#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012
649
650/* Bad block inode has illegal blocks (latch question) */
651#define PR_1_INODE_BBLOCK_LATCH 0x010013
652
653/* Duplicate or bad blocks in use! */
654#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014
655
656/* Bad block used as bad block indirect block */
657#define PR_1_BBINODE_BAD_METABLOCK 0x010015
658
659/* Inconsistency can't be fixed prompt */
660#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016
661
662/* Bad primary block */
663#define PR_1_BAD_PRIMARY_BLOCK 0x010017
664
665/* Bad primary block prompt */
666#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018
667
668/* Bad primary superblock */
669#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x010019
670
671/* Bad primary block group descriptors */
672#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A
673
674/* Bad superblock in group */
675#define PR_1_BAD_SUPERBLOCK 0x01001B
676
677/* Bad block group descriptors in group */
678#define PR_1_BAD_GROUP_DESCRIPTORS 0x01001C
679
680/* Block claimed for no reason */
681#define PR_1_PROGERR_CLAIMED_BLOCK 0x01001D
682
683/* Error allocating blocks for relocating metadata */
684#define PR_1_RELOC_BLOCK_ALLOCATE 0x01001E
685
686/* Error allocating block buffer during relocation process */
687#define PR_1_RELOC_MEMORY_ALLOCATE 0x01001F
688
689/* Relocating metadata group information from X to Y */
690#define PR_1_RELOC_FROM_TO 0x010020
691
692/* Relocating metatdata group information to X */
693#define PR_1_RELOC_TO 0x010021
694
695/* Block read error during relocation process */
696#define PR_1_RELOC_READ_ERR 0x010022
697
698/* Block write error during relocation process */
699#define PR_1_RELOC_WRITE_ERR 0x010023
700
701/* Error allocating inode bitmap */
702#define PR_1_ALLOCATE_IBITMAP_ERROR 0x010024
703
704/* Error allocating block bitmap */
705#define PR_1_ALLOCATE_BBITMAP_ERROR 0x010025
706
707/* Error allocating icount structure */
708#define PR_1_ALLOCATE_ICOUNT 0x010026
709
710/* Error allocating dbcount */
711#define PR_1_ALLOCATE_DBCOUNT 0x010027
712
713/* Error while scanning inodes */
714#define PR_1_ISCAN_ERROR 0x010028
715
716/* Error while iterating over blocks */
717#define PR_1_BLOCK_ITERATE 0x010029
718
719/* Error while storing inode count information */
720#define PR_1_ICOUNT_STORE 0x01002A
721
722/* Error while storing directory block information */
723#define PR_1_ADD_DBLOCK 0x01002B
724
725/* Error while reading inode (for clearing) */
726#define PR_1_READ_INODE 0x01002C
727
728/* Suppress messages prompt */
729#define PR_1_SUPPRESS_MESSAGES 0x01002D
730
731/* Imagic flag set on an inode when filesystem doesn't support it */
732#define PR_1_SET_IMAGIC 0x01002F
733
734/* Immutable flag set on a device or socket inode */
735#define PR_1_SET_IMMUTABLE 0x010030
736
737/* Compression flag set on a non-compressed filesystem */
738#define PR_1_COMPR_SET 0x010031
739
740/* Non-zero size on on device, fifo or socket inode */
741#define PR_1_SET_NONZSIZE 0x010032
742
743/* Filesystem revision is 0, but feature flags are set */
744#define PR_1_FS_REV_LEVEL 0x010033
745
746/* Journal inode not in use, needs clearing */
747#define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034
748
749/* Journal inode has wrong mode */
750#define PR_1_JOURNAL_BAD_MODE 0x010035
751
752/* Inode that was part of orphan linked list */
753#define PR_1_LOW_DTIME 0x010036
754
755/* Latch question which asks how to deal with low dtime inodes */
756#define PR_1_ORPHAN_LIST_REFUGEES 0x010037
757
758/* Error allocating refcount structure */
759#define PR_1_ALLOCATE_REFCOUNT 0x010038
760
761/* Error reading Extended Attribute block */
762#define PR_1_READ_EA_BLOCK 0x010039
763
764/* Invalid Extended Attribute block */
765#define PR_1_BAD_EA_BLOCK 0x01003A
766
767/* Error reading Extended Attribute block while fixing refcount -- abort */
768#define PR_1_EXTATTR_READ_ABORT 0x01003B
769
770/* Extended attribute reference count incorrect */
771#define PR_1_EXTATTR_REFCOUNT 0x01003C
772
773/* Error writing Extended Attribute block while fixing refcount */
774#define PR_1_EXTATTR_WRITE 0x01003D
775
776/* Multiple EA blocks not supported */
777#define PR_1_EA_MULTI_BLOCK 0x01003E
778
779/* Error allocating EA region allocation structure */
780#define PR_1_EA_ALLOC_REGION 0x01003F
781
782/* Error EA allocation collision */
783#define PR_1_EA_ALLOC_COLLISION 0x010040
784
785/* Bad extended attribute name */
786#define PR_1_EA_BAD_NAME 0x010041
787
788/* Bad extended attribute value */
789#define PR_1_EA_BAD_VALUE 0x010042
790
791/* Inode too big (latch question) */
792#define PR_1_INODE_TOOBIG 0x010043
793
794/* Directory too big */
795#define PR_1_TOOBIG_DIR 0x010044
796
797/* Regular file too big */
798#define PR_1_TOOBIG_REG 0x010045
799
800/* Symlink too big */
801#define PR_1_TOOBIG_SYMLINK 0x010046
802
803/* INDEX_FL flag set on a non-HTREE filesystem */
804#define PR_1_HTREE_SET 0x010047
805
806/* INDEX_FL flag set on a non-directory */
807#define PR_1_HTREE_NODIR 0x010048
808
809/* Invalid root node in HTREE directory */
810#define PR_1_HTREE_BADROOT 0x010049
811
812/* Unsupported hash version in HTREE directory */
813#define PR_1_HTREE_HASHV 0x01004A
814
815/* Incompatible flag in HTREE root node */
816#define PR_1_HTREE_INCOMPAT 0x01004B
817
818/* HTREE too deep */
819#define PR_1_HTREE_DEPTH 0x01004C
820
821/* Bad block has indirect block that conflicts with filesystem block */
822#define PR_1_BB_FS_BLOCK 0x01004D
823
824/* Resize inode failed */
825#define PR_1_RESIZE_INODE_CREATE 0x01004E
826
827/* inode->i_size is too long */
828#define PR_1_EXTRA_ISIZE 0x01004F
829
830/* attribute name is too long */
831#define PR_1_ATTR_NAME_LEN 0x010050
832
833/* wrong EA value offset */
834#define PR_1_ATTR_VALUE_OFFSET 0x010051
835
836/* wrong EA blocknumber */
837#define PR_1_ATTR_VALUE_BLOCK 0x010052
838
839/* wrong EA value size */
840#define PR_1_ATTR_VALUE_SIZE 0x010053
841
842/* wrong EA hash value */
843#define PR_1_ATTR_HASH 0x010054
844
845/*
846 * Pass 1b errors
847 */
848
849/* Pass 1B: Rescan for duplicate/bad blocks */
850#define PR_1B_PASS_HEADER 0x011000
851
852/* Duplicate/bad block(s) header */
853#define PR_1B_DUP_BLOCK_HEADER 0x011001
854
855/* Duplicate/bad block(s) in inode */
856#define PR_1B_DUP_BLOCK 0x011002
857
858/* Duplicate/bad block(s) end */
859#define PR_1B_DUP_BLOCK_END 0x011003
860
861/* Error while scanning inodes */
862#define PR_1B_ISCAN_ERROR 0x011004
863
864/* Error allocating inode bitmap */
865#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005
866
867/* Error while iterating over blocks */
868#define PR_1B_BLOCK_ITERATE 0x0110006
869
870/* Error adjusting EA refcount */
871#define PR_1B_ADJ_EA_REFCOUNT 0x0110007
872
873
874/* Pass 1C: Scan directories for inodes with dup blocks. */
875#define PR_1C_PASS_HEADER 0x012000
876
877
878/* Pass 1D: Reconciling duplicate blocks */
879#define PR_1D_PASS_HEADER 0x013000
880
881/* File has duplicate blocks */
882#define PR_1D_DUP_FILE 0x013001
883
884/* List of files sharing duplicate blocks */
885#define PR_1D_DUP_FILE_LIST 0x013002
886
887/* File sharing blocks with filesystem metadata */
888#define PR_1D_SHARE_METADATA 0x013003
889
890/* Report of how many duplicate/bad inodes */
891#define PR_1D_NUM_DUP_INODES 0x013004
892
893/* Duplicated blocks already reassigned or cloned. */
894#define PR_1D_DUP_BLOCKS_DEALT 0x013005
895
896/* Clone duplicate/bad blocks? */
897#define PR_1D_CLONE_QUESTION 0x013006
898
899/* Delete file? */
900#define PR_1D_DELETE_QUESTION 0x013007
901
902/* Couldn't clone file (error) */
903#define PR_1D_CLONE_ERROR 0x013008
904
905/*
906 * Pass 2 errors
907 */
908
909/* Pass 2: Checking directory structure */
910#define PR_2_PASS_HEADER 0x020000
911
912/* Bad inode number for '.' */
913#define PR_2_BAD_INODE_DOT 0x020001
914
915/* Directory entry has bad inode number */
916#define PR_2_BAD_INO 0x020002
917
918/* Directory entry has deleted or unused inode */
919#define PR_2_UNUSED_INODE 0x020003
920
921/* Directry entry is link to '.' */
922#define PR_2_LINK_DOT 0x020004
923
924/* Directory entry points to inode now located in a bad block */
925#define PR_2_BB_INODE 0x020005
926
927/* Directory entry contains a link to a directory */
928#define PR_2_LINK_DIR 0x020006
929
930/* Directory entry contains a link to the root directry */
931#define PR_2_LINK_ROOT 0x020007
932
933/* Directory entry has illegal characters in its name */
934#define PR_2_BAD_NAME 0x020008
935
936/* Missing '.' in directory inode */
937#define PR_2_MISSING_DOT 0x020009
938
939/* Missing '..' in directory inode */
940#define PR_2_MISSING_DOT_DOT 0x02000A
941
942/* First entry in directory inode doesn't contain '.' */
943#define PR_2_1ST_NOT_DOT 0x02000B
944
945/* Second entry in directory inode doesn't contain '..' */
946#define PR_2_2ND_NOT_DOT_DOT 0x02000C
947
948/* i_faddr should be zero */
949#define PR_2_FADDR_ZERO 0x02000D
950
951/* i_file_acl should be zero */
952#define PR_2_FILE_ACL_ZERO 0x02000E
953
954/* i_dir_acl should be zero */
955#define PR_2_DIR_ACL_ZERO 0x02000F
956
957/* i_frag should be zero */
958#define PR_2_FRAG_ZERO 0x020010
959
960/* i_fsize should be zero */
961#define PR_2_FSIZE_ZERO 0x020011
962
963/* inode has bad mode */
964#define PR_2_BAD_MODE 0x020012
965
966/* directory corrupted */
967#define PR_2_DIR_CORRUPTED 0x020013
968
969/* filename too long */
970#define PR_2_FILENAME_LONG 0x020014
971
972/* Directory inode has a missing block (hole) */
973#define PR_2_DIRECTORY_HOLE 0x020015
974
975/* '.' is not NULL terminated */
976#define PR_2_DOT_NULL_TERM 0x020016
977
978/* '..' is not NULL terminated */
979#define PR_2_DOT_DOT_NULL_TERM 0x020017
980
981/* Illegal character device in inode */
982#define PR_2_BAD_CHAR_DEV 0x020018
983
984/* Illegal block device in inode */
985#define PR_2_BAD_BLOCK_DEV 0x020019
986
987/* Duplicate '.' entry */
988#define PR_2_DUP_DOT 0x02001A
989
990/* Duplicate '..' entry */
991#define PR_2_DUP_DOT_DOT 0x02001B
992
993/* Internal error: couldn't find dir_info */
994#define PR_2_NO_DIRINFO 0x02001C
995
996/* Final rec_len is wrong */
997#define PR_2_FINAL_RECLEN 0x02001D
998
999/* Error allocating icount structure */
1000#define PR_2_ALLOCATE_ICOUNT 0x02001E
1001
1002/* Error iterating over directory blocks */
1003#define PR_2_DBLIST_ITERATE 0x02001F
1004
1005/* Error reading directory block */
1006#define PR_2_READ_DIRBLOCK 0x020020
1007
1008/* Error writing directory block */
1009#define PR_2_WRITE_DIRBLOCK 0x020021
1010
1011/* Error allocating new directory block */
1012#define PR_2_ALLOC_DIRBOCK 0x020022
1013
1014/* Error deallocating inode */
1015#define PR_2_DEALLOC_INODE 0x020023
1016
1017/* Directory entry for '.' is big. Split? */
1018#define PR_2_SPLIT_DOT 0x020024
1019
1020/* Illegal FIFO */
1021#define PR_2_BAD_FIFO 0x020025
1022
1023/* Illegal socket */
1024#define PR_2_BAD_SOCKET 0x020026
1025
1026/* Directory filetype not set */
1027#define PR_2_SET_FILETYPE 0x020027
1028
1029/* Directory filetype incorrect */
1030#define PR_2_BAD_FILETYPE 0x020028
1031
1032/* Directory filetype set when it shouldn't be */
1033#define PR_2_CLEAR_FILETYPE 0x020029
1034
1035/* Directory filename can't be zero-length */
1036#define PR_2_NULL_NAME 0x020030
1037
1038/* Invalid symlink */
1039#define PR_2_INVALID_SYMLINK 0x020031
1040
1041/* i_file_acl (extended attribute) is bad */
1042#define PR_2_FILE_ACL_BAD 0x020032
1043
1044/* Filesystem contains large files, but has no such flag in sb */
1045#define PR_2_FEATURE_LARGE_FILES 0x020033
1046
1047/* Node in HTREE directory not referenced */
1048#define PR_2_HTREE_NOTREF 0x020034
1049
1050/* Node in HTREE directory referenced twice */
1051#define PR_2_HTREE_DUPREF 0x020035
1052
1053/* Node in HTREE directory has bad min hash */
1054#define PR_2_HTREE_MIN_HASH 0x020036
1055
1056/* Node in HTREE directory has bad max hash */
1057#define PR_2_HTREE_MAX_HASH 0x020037
1058
1059/* Clear invalid HTREE directory */
1060#define PR_2_HTREE_CLEAR 0x020038
1061
1062/* Clear the htree flag forcibly */
1063/* #define PR_2_HTREE_FCLR 0x020039 */
1064
1065/* Bad block in htree interior node */
1066#define PR_2_HTREE_BADBLK 0x02003A
1067
1068/* Error adjusting EA refcount */
1069#define PR_2_ADJ_EA_REFCOUNT 0x02003B
1070
1071/* Invalid HTREE root node */
1072#define PR_2_HTREE_BAD_ROOT 0x02003C
1073
1074/* Invalid HTREE limit */
1075#define PR_2_HTREE_BAD_LIMIT 0x02003D
1076
1077/* Invalid HTREE count */
1078#define PR_2_HTREE_BAD_COUNT 0x02003E
1079
1080/* HTREE interior node has out-of-order hashes in table */
1081#define PR_2_HTREE_HASH_ORDER 0x02003F
1082
1083/* Node in HTREE directory has bad depth */
1084#define PR_2_HTREE_BAD_DEPTH 0x020040
1085
1086/* Duplicate directory entry found */
1087#define PR_2_DUPLICATE_DIRENT 0x020041
1088
1089/* Non-unique filename found */
1090#define PR_2_NON_UNIQUE_FILE 0x020042
1091
1092/* Duplicate directory entry found */
1093#define PR_2_REPORT_DUP_DIRENT 0x020043
1094
1095/*
1096 * Pass 3 errors
1097 */
1098
1099/* Pass 3: Checking directory connectivity */
1100#define PR_3_PASS_HEADER 0x030000
1101
1102/* Root inode not allocated */
1103#define PR_3_NO_ROOT_INODE 0x030001
1104
1105/* No room in lost+found */
1106#define PR_3_EXPAND_LF_DIR 0x030002
1107
1108/* Unconnected directory inode */
1109#define PR_3_UNCONNECTED_DIR 0x030003
1110
1111/* /lost+found not found */
1112#define PR_3_NO_LF_DIR 0x030004
1113
1114/* .. entry is incorrect */
1115#define PR_3_BAD_DOT_DOT 0x030005
1116
1117/* Bad or non-existent /lost+found. Cannot reconnect */
1118#define PR_3_NO_LPF 0x030006
1119
1120/* Could not expand /lost+found */
1121#define PR_3_CANT_EXPAND_LPF 0x030007
1122
1123/* Could not reconnect inode */
1124#define PR_3_CANT_RECONNECT 0x030008
1125
1126/* Error while trying to find /lost+found */
1127#define PR_3_ERR_FIND_LPF 0x030009
1128
1129/* Error in ext2fs_new_block while creating /lost+found */
1130#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A
1131
1132/* Error in ext2fs_new_inode while creating /lost+found */
1133#define PR_3_ERR_LPF_NEW_INODE 0x03000B
1134
1135/* Error in ext2fs_new_dir_block while creating /lost+found */
1136#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C
1137
1138/* Error while writing directory block for /lost+found */
1139#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D
1140
1141/* Error while adjusting inode count */
1142#define PR_3_ADJUST_INODE 0x03000E
1143
1144/* Couldn't fix parent directory -- error */
1145#define PR_3_FIX_PARENT_ERR 0x03000F
1146
1147/* Couldn't fix parent directory -- couldn't find it */
1148#define PR_3_FIX_PARENT_NOFIND 0x030010
1149
1150/* Error allocating inode bitmap */
1151#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011
1152
1153/* Error creating root directory */
1154#define PR_3_CREATE_ROOT_ERROR 0x030012
1155
1156/* Error creating lost and found directory */
1157#define PR_3_CREATE_LPF_ERROR 0x030013
1158
1159/* Root inode is not directory; aborting */
1160#define PR_3_ROOT_NOT_DIR_ABORT 0x030014
1161
1162/* Cannot proceed without a root inode. */
1163#define PR_3_NO_ROOT_INODE_ABORT 0x030015
1164
1165/* Internal error: couldn't find dir_info */
1166#define PR_3_NO_DIRINFO 0x030016
1167
1168/* Lost+found is not a directory */
1169#define PR_3_LPF_NOTDIR 0x030017
1170
1171/*
1172 * Pass 3a --- rehashing diretories
1173 */
1174/* Pass 3a: Reindexing directories */
1175#define PR_3A_PASS_HEADER 0x031000
1176
1177/* Error iterating over directories */
1178#define PR_3A_OPTIMIZE_ITER 0x031001
1179
1180/* Error rehash directory */
1181#define PR_3A_OPTIMIZE_DIR_ERR 0x031002
1182
1183/* Rehashing dir header */
1184#define PR_3A_OPTIMIZE_DIR_HEADER 0x031003
1185
1186/* Rehashing directory %d */
1187#define PR_3A_OPTIMIZE_DIR 0x031004
1188
1189/* Rehashing dir end */
1190#define PR_3A_OPTIMIZE_DIR_END 0x031005
1191
1192/*
1193 * Pass 4 errors
1194 */
1195
1196/* Pass 4: Checking reference counts */
1197#define PR_4_PASS_HEADER 0x040000
1198
1199/* Unattached zero-length inode */
1200#define PR_4_ZERO_LEN_INODE 0x040001
1201
1202/* Unattached inode */
1203#define PR_4_UNATTACHED_INODE 0x040002
1204
1205/* Inode ref count wrong */
1206#define PR_4_BAD_REF_COUNT 0x040003
1207
1208/* Inconsistent inode count information cached */
1209#define PR_4_INCONSISTENT_COUNT 0x040004
1210
1211/*
1212 * Pass 5 errors
1213 */
1214
1215/* Pass 5: Checking group summary information */
1216#define PR_5_PASS_HEADER 0x050000
1217
1218/* Padding at end of inode bitmap is not set. */
1219#define PR_5_INODE_BMAP_PADDING 0x050001
1220
1221/* Padding at end of block bitmap is not set. */
1222#define PR_5_BLOCK_BMAP_PADDING 0x050002
1223
1224/* Block bitmap differences header */
1225#define PR_5_BLOCK_BITMAP_HEADER 0x050003
1226
1227/* Block not used, but marked in bitmap */
1228#define PR_5_BLOCK_UNUSED 0x050004
1229
1230/* Block used, but not marked used in bitmap */
1231#define PR_5_BLOCK_USED 0x050005
1232
1233/* Block bitmap differences end */
1234#define PR_5_BLOCK_BITMAP_END 0x050006
1235
1236/* Inode bitmap differences header */
1237#define PR_5_INODE_BITMAP_HEADER 0x050007
1238
1239/* Inode not used, but marked in bitmap */
1240#define PR_5_INODE_UNUSED 0x050008
1241
1242/* Inode used, but not marked used in bitmap */
1243#define PR_5_INODE_USED 0x050009
1244
1245/* Inode bitmap differences end */
1246#define PR_5_INODE_BITMAP_END 0x05000A
1247
1248/* Free inodes count for group wrong */
1249#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B
1250
1251/* Directories count for group wrong */
1252#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C
1253
1254/* Free inodes count wrong */
1255#define PR_5_FREE_INODE_COUNT 0x05000D
1256
1257/* Free blocks count for group wrong */
1258#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E
1259
1260/* Free blocks count wrong */
1261#define PR_5_FREE_BLOCK_COUNT 0x05000F
1262
1263/* Programming error: bitmap endpoints don't match */
1264#define PR_5_BMAP_ENDPOINTS 0x050010
1265
1266/* Internal error: fudging end of bitmap */
1267#define PR_5_FUDGE_BITMAP_ERROR 0x050011
1268
1269/* Error copying in replacement inode bitmap */
1270#define PR_5_COPY_IBITMAP_ERROR 0x050012
1271
1272/* Error copying in replacement block bitmap */
1273#define PR_5_COPY_BBITMAP_ERROR 0x050013
1274
1275/* Block range not used, but marked in bitmap */
1276#define PR_5_BLOCK_RANGE_UNUSED 0x050014
1277
1278/* Block range used, but not marked used in bitmap */
1279#define PR_5_BLOCK_RANGE_USED 0x050015
1280
1281/* Inode range not used, but marked in bitmap */
1282#define PR_5_INODE_RANGE_UNUSED 0x050016
1283
1284/* Inode rangeused, but not marked used in bitmap */
1285#define PR_5_INODE_RANGE_USED 0x050017
1286
1287/*
1288 * Function declarations
1289 */
1290static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
1291static int end_problem_latch(e2fsck_t ctx, int mask);
1292static int set_latch_flags(int mask, int setflags, int clearflags);
1293static void clear_problem_context(struct problem_context *ctx);
1294
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001295/*
1296 * Dictionary Abstract Data Type
1297 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
1298 *
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001299 * dict.h v 1.22.2.6 2000/11/13 01:36:44 kaz
1300 * kazlib_1_20
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001301 */
1302
1303#ifndef DICT_H
1304#define DICT_H
1305
1306/*
1307 * Blurb for inclusion into C++ translation units
1308 */
1309
1310typedef unsigned long dictcount_t;
1311#define DICTCOUNT_T_MAX ULONG_MAX
1312
1313/*
1314 * The dictionary is implemented as a red-black tree
1315 */
1316
1317typedef enum { dnode_red, dnode_black } dnode_color_t;
1318
1319typedef struct dnode_t {
1320 struct dnode_t *dict_left;
1321 struct dnode_t *dict_right;
1322 struct dnode_t *dict_parent;
1323 dnode_color_t dict_color;
1324 const void *dict_key;
1325 void *dict_data;
1326} dnode_t;
1327
1328typedef int (*dict_comp_t)(const void *, const void *);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001329typedef void (*dnode_free_t)(dnode_t *);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001330
1331typedef struct dict_t {
1332 dnode_t dict_nilnode;
1333 dictcount_t dict_nodecount;
1334 dictcount_t dict_maxcount;
1335 dict_comp_t dict_compare;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001336 dnode_free_t dict_freenode;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001337 int dict_dupes;
1338} dict_t;
1339
1340typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
1341
1342typedef struct dict_load_t {
1343 dict_t *dict_dictptr;
1344 dnode_t dict_nilnode;
1345} dict_load_t;
1346
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001347#define dict_count(D) ((D)->dict_nodecount)
1348#define dnode_get(N) ((N)->dict_data)
1349#define dnode_getkey(N) ((N)->dict_key)
1350
1351#endif
1352
1353/*
1354 * Compatibility header file for e2fsck which should be included
1355 * instead of linux/jfs.h
1356 *
1357 * Copyright (C) 2000 Stephen C. Tweedie
1358 */
1359
1360/*
1361 * Pull in the definition of the e2fsck context structure
1362 */
1363
1364
1365struct buffer_head {
1366 char b_data[8192];
1367 e2fsck_t b_ctx;
1368 io_channel b_io;
1369 int b_size;
1370 blk_t b_blocknr;
1371 int b_dirty;
1372 int b_uptodate;
1373 int b_err;
1374};
1375
1376struct inode {
1377 e2fsck_t i_ctx;
1378 ext2_ino_t i_ino;
1379 struct ext2_inode i_ext2;
1380};
1381
1382struct kdev_s {
1383 e2fsck_t k_ctx;
1384 int k_dev;
1385};
1386
1387#define K_DEV_FS 1
1388#define K_DEV_JOURNAL 2
1389
1390typedef struct kdev_s *kdev_t;
1391
1392#define lock_buffer(bh) do {} while(0)
1393#define unlock_buffer(bh) do {} while(0)
1394#define buffer_req(bh) 1
1395#define do_readahead(journal, start) do {} while(0)
1396
1397static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
1398
1399typedef struct {
1400 int object_length;
1401} kmem_cache_t;
1402
1403#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001404
1405/*
1406 * We use the standard libext2fs portability tricks for inline
1407 * functions.
1408 */
1409
1410static _INLINE_ kmem_cache_t * do_cache_create(int len)
1411{
1412 kmem_cache_t *new_cache;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001413
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001414 new_cache = malloc(sizeof(*new_cache));
1415 if (new_cache)
1416 new_cache->object_length = len;
1417 return new_cache;
1418}
1419
1420static _INLINE_ void do_cache_destroy(kmem_cache_t *cache)
1421{
1422 free(cache);
1423}
1424
1425/*
1426 * Now pull in the real linux/jfs.h definitions.
1427 */
1428#include "ext2fs/kernel-jbd.h"
1429
1430/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001431 * badblocks.c --- replace/append bad blocks to the bad block inode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001432 */
1433
1434static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
1435 void *priv_data);
1436
1437
1438static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
1439{
1440 printf(_("Bad block %u out of range; ignored.\n"), blk);
1441 return;
1442}
1443
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001444static void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001445 int replace_bad_blocks)
1446{
1447 ext2_filsys fs = ctx->fs;
1448 errcode_t retval;
1449 badblocks_list bb_list = 0;
1450 FILE *f;
1451 char buf[1024];
1452
1453 e2fsck_read_bitmaps(ctx);
1454
1455 /*
1456 * Make sure the bad block inode is sane. If there are any
1457 * illegal blocks, clear them.
1458 */
1459 retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
1460 check_bb_inode_blocks, 0);
1461 if (retval) {
1462 com_err("ext2fs_block_iterate", retval,
1463 _("while sanity checking the bad blocks inode"));
1464 goto fatal;
1465 }
1466
1467 /*
1468 * If we're appending to the bad blocks inode, read in the
1469 * current bad blocks.
1470 */
1471 if (!replace_bad_blocks) {
1472 retval = ext2fs_read_bb_inode(fs, &bb_list);
1473 if (retval) {
1474 com_err("ext2fs_read_bb_inode", retval,
1475 _("while reading the bad blocks inode"));
1476 goto fatal;
1477 }
1478 }
1479
1480 /*
1481 * Now read in the bad blocks from the file; if
1482 * bad_blocks_file is null, then try to run the badblocks
1483 * command.
1484 */
1485 if (bad_blocks_file) {
1486 f = fopen(bad_blocks_file, "r");
1487 if (!f) {
1488 com_err("read_bad_blocks_file", errno,
1489 _("while trying to open %s"), bad_blocks_file);
1490 goto fatal;
1491 }
1492 } else {
1493 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
1494 (ctx->options & E2F_OPT_PREEN) ? "" : "-s ",
1495 (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "",
1496 fs->device_name, fs->super->s_blocks_count);
1497 f = popen(buf, "r");
1498 if (!f) {
1499 com_err("read_bad_blocks_file", errno,
1500 _("while trying popen '%s'"), buf);
1501 goto fatal;
1502 }
1503 }
1504 retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
1505 if (bad_blocks_file)
1506 fclose(f);
1507 else
1508 pclose(f);
1509 if (retval) {
1510 com_err("ext2fs_read_bb_FILE", retval,
1511 _("while reading in list of bad blocks from file"));
1512 goto fatal;
1513 }
1514
1515 /*
1516 * Finally, update the bad blocks from the bad_block_map
1517 */
1518 retval = ext2fs_update_bb_inode(fs, bb_list);
1519 if (retval) {
1520 com_err("ext2fs_update_bb_inode", retval,
1521 _("while updating bad block inode"));
1522 goto fatal;
1523 }
1524
1525 ext2fs_badblocks_list_free(bb_list);
1526 return;
1527
1528fatal:
1529 ctx->flags |= E2F_FLAG_ABORT;
1530 return;
1531
1532}
1533
1534static int check_bb_inode_blocks(ext2_filsys fs,
1535 blk_t *block_nr,
1536 int blockcnt EXT2FS_ATTR((unused)),
1537 void *priv_data EXT2FS_ATTR((unused)))
1538{
1539 if (!*block_nr)
1540 return 0;
1541
1542 /*
1543 * If the block number is outrageous, clear it and ignore it.
1544 */
1545 if (*block_nr >= fs->super->s_blocks_count ||
1546 *block_nr < fs->super->s_first_data_block) {
1547 printf(_("Warning illegal block %u found in bad block inode. Cleared.\n"), *block_nr);
1548 *block_nr = 0;
1549 return BLOCK_CHANGED;
1550 }
1551
1552 return 0;
1553}
1554
1555/*
1556 * Dictionary Abstract Data Type
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001557 */
1558
1559
1560/*
1561 * These macros provide short convenient names for structure members,
1562 * which are embellished with dict_ prefixes so that they are
1563 * properly confined to the documented namespace. It's legal for a
1564 * program which uses dict to define, for instance, a macro called ``parent''.
1565 * Such a macro would interfere with the dnode_t struct definition.
1566 * In general, highly portable and reusable C modules which expose their
1567 * structures need to confine structure member names to well-defined spaces.
1568 * The resulting identifiers aren't necessarily convenient to use, nor
1569 * readable, in the implementation, however!
1570 */
1571
1572#define left dict_left
1573#define right dict_right
1574#define parent dict_parent
1575#define color dict_color
1576#define key dict_key
1577#define data dict_data
1578
1579#define nilnode dict_nilnode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001580#define maxcount dict_maxcount
1581#define compare dict_compare
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001582#define dupes dict_dupes
1583
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001584#define dict_root(D) ((D)->nilnode.left)
1585#define dict_nil(D) (&(D)->nilnode)
1586#define DICT_DEPTH_MAX 64
1587
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001588static void dnode_free(dnode_t *node);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001589
1590/*
1591 * Perform a ``left rotation'' adjustment on the tree. The given node P and
1592 * its right child C are rearranged so that the P instead becomes the left
1593 * child of C. The left subtree of C is inherited as the new right subtree
1594 * for P. The ordering of the keys within the tree is thus preserved.
1595 */
1596
1597static void rotate_left(dnode_t *upper)
1598{
1599 dnode_t *lower, *lowleft, *upparent;
1600
1601 lower = upper->right;
1602 upper->right = lowleft = lower->left;
1603 lowleft->parent = upper;
1604
1605 lower->parent = upparent = upper->parent;
1606
1607 /* don't need to check for root node here because root->parent is
1608 the sentinel nil node, and root->parent->left points back to root */
1609
1610 if (upper == upparent->left) {
1611 upparent->left = lower;
1612 } else {
1613 assert (upper == upparent->right);
1614 upparent->right = lower;
1615 }
1616
1617 lower->left = upper;
1618 upper->parent = lower;
1619}
1620
1621/*
1622 * This operation is the ``mirror'' image of rotate_left. It is
1623 * the same procedure, but with left and right interchanged.
1624 */
1625
1626static void rotate_right(dnode_t *upper)
1627{
1628 dnode_t *lower, *lowright, *upparent;
1629
1630 lower = upper->left;
1631 upper->left = lowright = lower->right;
1632 lowright->parent = upper;
1633
1634 lower->parent = upparent = upper->parent;
1635
1636 if (upper == upparent->right) {
1637 upparent->right = lower;
1638 } else {
1639 assert (upper == upparent->left);
1640 upparent->left = lower;
1641 }
1642
1643 lower->right = upper;
1644 upper->parent = lower;
1645}
1646
1647/*
1648 * Do a postorder traversal of the tree rooted at the specified
1649 * node and free everything under it. Used by dict_free().
1650 */
1651
1652static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
1653{
1654 if (node == nil)
1655 return;
1656 free_nodes(dict, node->left, nil);
1657 free_nodes(dict, node->right, nil);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001658 dict->dict_freenode(node);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001659}
1660
1661/*
1662 * Verify that the tree contains the given node. This is done by
1663 * traversing all of the nodes and comparing their pointers to the
1664 * given pointer. Returns 1 if the node is found, otherwise
1665 * returns zero. It is intended for debugging purposes.
1666 */
1667
1668static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
1669{
1670 if (root != nil) {
1671 return root == node
1672 || verify_dict_has_node(nil, root->left, node)
1673 || verify_dict_has_node(nil, root->right, node);
1674 }
1675 return 0;
1676}
1677
1678
1679/*
1680 * Select a different set of node allocator routines.
1681 */
1682
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001683static void dict_set_allocator(dict_t *dict, dnode_free_t fr)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001684{
1685 assert (dict_count(dict) == 0);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001686 dict->dict_freenode = fr;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001687}
1688
1689/*
1690 * Free all the nodes in the dictionary by using the dictionary's
1691 * installed free routine. The dictionary is emptied.
1692 */
1693
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001694static void dict_free_nodes(dict_t *dict)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001695{
1696 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
1697 free_nodes(dict, root, nil);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001698 dict->dict_nodecount = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001699 dict->nilnode.left = &dict->nilnode;
1700 dict->nilnode.right = &dict->nilnode;
1701}
1702
1703/*
1704 * Initialize a user-supplied dictionary object.
1705 */
1706
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001707static dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001708{
1709 dict->compare = comp;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001710 dict->dict_freenode = dnode_free;
1711 dict->dict_nodecount = 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001712 dict->maxcount = maxcount;
1713 dict->nilnode.left = &dict->nilnode;
1714 dict->nilnode.right = &dict->nilnode;
1715 dict->nilnode.parent = &dict->nilnode;
1716 dict->nilnode.color = dnode_black;
1717 dict->dupes = 0;
1718 return dict;
1719}
1720
1721/*
1722 * Locate a node in the dictionary having the given key.
1723 * If the node is not found, a null a pointer is returned (rather than
1724 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
1725 * located node is returned.
1726 */
1727
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001728static dnode_t *dict_lookup(dict_t *dict, const void *key)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001729{
1730 dnode_t *root = dict_root(dict);
1731 dnode_t *nil = dict_nil(dict);
1732 dnode_t *saved;
1733 int result;
1734
1735 /* simple binary search adapted for trees that contain duplicate keys */
1736
1737 while (root != nil) {
1738 result = dict->compare(key, root->key);
1739 if (result < 0)
1740 root = root->left;
1741 else if (result > 0)
1742 root = root->right;
1743 else {
1744 if (!dict->dupes) { /* no duplicates, return match */
1745 return root;
1746 } else { /* could be dupes, find leftmost one */
1747 do {
1748 saved = root;
1749 root = root->left;
1750 while (root != nil && dict->compare(key, root->key))
1751 root = root->right;
1752 } while (root != nil);
1753 return saved;
1754 }
1755 }
1756 }
1757
1758 return NULL;
1759}
1760
1761/*
1762 * Insert a node into the dictionary. The node should have been
1763 * initialized with a data field. All other fields are ignored.
1764 * The behavior is undefined if the user attempts to insert into
1765 * a dictionary that is already full (for which the dict_isfull()
1766 * function returns true).
1767 */
1768
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001769static void dict_insert(dict_t *dict, dnode_t *node, const void *key)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001770{
1771 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
1772 dnode_t *parent = nil, *uncle, *grandpa;
1773 int result = -1;
1774
1775 node->key = key;
1776
1777 /* basic binary tree insert */
1778
1779 while (where != nil) {
1780 parent = where;
1781 result = dict->compare(key, where->key);
1782 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
1783 assert (dict->dupes || result != 0);
1784 if (result < 0)
1785 where = where->left;
1786 else
1787 where = where->right;
1788 }
1789
1790 assert (where == nil);
1791
1792 if (result < 0)
1793 parent->left = node;
1794 else
1795 parent->right = node;
1796
1797 node->parent = parent;
1798 node->left = nil;
1799 node->right = nil;
1800
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001801 dict->dict_nodecount++;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001802
1803 /* red black adjustments */
1804
1805 node->color = dnode_red;
1806
1807 while (parent->color == dnode_red) {
1808 grandpa = parent->parent;
1809 if (parent == grandpa->left) {
1810 uncle = grandpa->right;
1811 if (uncle->color == dnode_red) { /* red parent, red uncle */
1812 parent->color = dnode_black;
1813 uncle->color = dnode_black;
1814 grandpa->color = dnode_red;
1815 node = grandpa;
1816 parent = grandpa->parent;
1817 } else { /* red parent, black uncle */
1818 if (node == parent->right) {
1819 rotate_left(parent);
1820 parent = node;
1821 assert (grandpa == parent->parent);
1822 /* rotation between parent and child preserves grandpa */
1823 }
1824 parent->color = dnode_black;
1825 grandpa->color = dnode_red;
1826 rotate_right(grandpa);
1827 break;
1828 }
1829 } else { /* symmetric cases: parent == parent->parent->right */
1830 uncle = grandpa->left;
1831 if (uncle->color == dnode_red) {
1832 parent->color = dnode_black;
1833 uncle->color = dnode_black;
1834 grandpa->color = dnode_red;
1835 node = grandpa;
1836 parent = grandpa->parent;
1837 } else {
1838 if (node == parent->left) {
1839 rotate_right(parent);
1840 parent = node;
1841 assert (grandpa == parent->parent);
1842 }
1843 parent->color = dnode_black;
1844 grandpa->color = dnode_red;
1845 rotate_left(grandpa);
1846 break;
1847 }
1848 }
1849 }
1850
1851 dict_root(dict)->color = dnode_black;
1852
1853}
1854
1855/*
1856 * Allocate a node using the dictionary's allocator routine, give it
1857 * the data item.
1858 */
1859
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001860static dnode_t *dnode_init(dnode_t *dnode, void *data)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001861{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001862 dnode->data = data;
1863 dnode->parent = NULL;
1864 dnode->left = NULL;
1865 dnode->right = NULL;
1866 return dnode;
1867}
1868
1869static int dict_alloc_insert(dict_t *dict, const void *key, void *data)
1870{
1871 dnode_t *node = malloc(sizeof(dnode_t));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001872
1873 if (node) {
1874 dnode_init(node, data);
1875 dict_insert(dict, node, key);
1876 return 1;
1877 }
1878 return 0;
1879}
1880
1881/*
1882 * Return the node with the lowest (leftmost) key. If the dictionary is empty
1883 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
1884 */
1885
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001886static dnode_t *dict_first(dict_t *dict)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001887{
1888 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
1889
1890 if (root != nil)
1891 while ((left = root->left) != nil)
1892 root = left;
1893
1894 return (root == nil) ? NULL : root;
1895}
1896
1897/*
1898 * Return the given node's successor node---the node which has the
1899 * next key in the the left to right ordering. If the node has
1900 * no successor, a null pointer is returned rather than a pointer to
1901 * the nil node.
1902 */
1903
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001904static dnode_t *dict_next(dict_t *dict, dnode_t *curr)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001905{
1906 dnode_t *nil = dict_nil(dict), *parent, *left;
1907
1908 if (curr->right != nil) {
1909 curr = curr->right;
1910 while ((left = curr->left) != nil)
1911 curr = left;
1912 return curr;
1913 }
1914
1915 parent = curr->parent;
1916
1917 while (parent != nil && curr == parent->right) {
1918 curr = parent;
1919 parent = curr->parent;
1920 }
1921
1922 return (parent == nil) ? NULL : parent;
1923}
1924
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001925
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001926static void dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001927{
1928 free(node);
1929}
1930
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001931
1932#undef left
1933#undef right
1934#undef parent
1935#undef color
1936#undef key
1937#undef data
1938
1939#undef nilnode
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001940#undef maxcount
1941#undef compare
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001942#undef dupes
1943
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001944
1945/*
1946 * dirinfo.c --- maintains the directory information table for e2fsck.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001947 */
1948
1949/*
1950 * This subroutine is called during pass1 to create a directory info
1951 * entry. During pass1, the passed-in parent is 0; it will get filled
1952 * in during pass2.
1953 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00001954static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00001955{
1956 struct dir_info *dir;
1957 int i, j;
1958 ext2_ino_t num_dirs;
1959 errcode_t retval;
1960 unsigned long old_size;
1961
1962#if 0
1963 printf("add_dir_info for inode %lu...\n", ino);
1964#endif
1965 if (!ctx->dir_info) {
1966 ctx->dir_info_count = 0;
1967 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
1968 if (retval)
1969 num_dirs = 1024; /* Guess */
1970 ctx->dir_info_size = num_dirs + 10;
1971 ctx->dir_info = (struct dir_info *)
1972 e2fsck_allocate_memory(ctx, ctx->dir_info_size
1973 * sizeof (struct dir_info),
1974 "directory map");
1975 }
1976
1977 if (ctx->dir_info_count >= ctx->dir_info_size) {
1978 old_size = ctx->dir_info_size * sizeof(struct dir_info);
1979 ctx->dir_info_size += 10;
1980 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
1981 sizeof(struct dir_info),
1982 &ctx->dir_info);
1983 if (retval) {
1984 ctx->dir_info_size -= 10;
1985 return;
1986 }
1987 }
1988
1989 /*
1990 * Normally, add_dir_info is called with each inode in
1991 * sequential order; but once in a while (like when pass 3
1992 * needs to recreate the root directory or lost+found
1993 * directory) it is called out of order. In those cases, we
1994 * need to move the dir_info entries down to make room, since
1995 * the dir_info array needs to be sorted by inode number for
1996 * get_dir_info()'s sake.
1997 */
1998 if (ctx->dir_info_count &&
1999 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
2000 for (i = ctx->dir_info_count-1; i > 0; i--)
2001 if (ctx->dir_info[i-1].ino < ino)
2002 break;
2003 dir = &ctx->dir_info[i];
2004 if (dir->ino != ino)
2005 for (j = ctx->dir_info_count++; j > i; j--)
2006 ctx->dir_info[j] = ctx->dir_info[j-1];
2007 } else
2008 dir = &ctx->dir_info[ctx->dir_info_count++];
2009
2010 dir->ino = ino;
2011 dir->dotdot = parent;
2012 dir->parent = parent;
2013}
2014
2015/*
2016 * get_dir_info() --- given an inode number, try to find the directory
2017 * information entry for it.
2018 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002019static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002020{
2021 int low, high, mid;
2022
2023 low = 0;
2024 high = ctx->dir_info_count-1;
2025 if (!ctx->dir_info)
2026 return 0;
2027 if (ino == ctx->dir_info[low].ino)
2028 return &ctx->dir_info[low];
2029 if (ino == ctx->dir_info[high].ino)
2030 return &ctx->dir_info[high];
2031
2032 while (low < high) {
2033 mid = (low+high)/2;
2034 if (mid == low || mid == high)
2035 break;
2036 if (ino == ctx->dir_info[mid].ino)
2037 return &ctx->dir_info[mid];
2038 if (ino < ctx->dir_info[mid].ino)
2039 high = mid;
2040 else
2041 low = mid;
2042 }
2043 return 0;
2044}
2045
2046/*
2047 * Free the dir_info structure when it isn't needed any more.
2048 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002049static void e2fsck_free_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002050{
2051 if (ctx->dir_info) {
2052 ext2fs_free_mem(&ctx->dir_info);
2053 ctx->dir_info = 0;
2054 }
2055 ctx->dir_info_size = 0;
2056 ctx->dir_info_count = 0;
2057}
2058
2059/*
2060 * Return the count of number of directories in the dir_info structure
2061 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002062static inline int e2fsck_get_num_dirinfo(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002063{
2064 return ctx->dir_info_count;
2065}
2066
2067/*
2068 * A simple interator function
2069 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002070static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002071{
2072 if (*control >= ctx->dir_info_count)
2073 return 0;
2074
2075 return(ctx->dir_info + (*control)++);
2076}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002077
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002078/*
2079 * dirinfo.c --- maintains the directory information table for e2fsck.
2080 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002081 */
2082
2083#ifdef ENABLE_HTREE
2084
2085/*
2086 * This subroutine is called during pass1 to create a directory info
2087 * entry. During pass1, the passed-in parent is 0; it will get filled
2088 * in during pass2.
2089 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002090static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002091{
2092 struct dx_dir_info *dir;
2093 int i, j;
2094 errcode_t retval;
2095 unsigned long old_size;
2096
2097#if 0
2098 printf("add_dx_dir_info for inode %lu...\n", ino);
2099#endif
2100 if (!ctx->dx_dir_info) {
2101 ctx->dx_dir_info_count = 0;
2102 ctx->dx_dir_info_size = 100; /* Guess */
2103 ctx->dx_dir_info = (struct dx_dir_info *)
2104 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
2105 * sizeof (struct dx_dir_info),
2106 "directory map");
2107 }
2108
2109 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
2110 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
2111 ctx->dx_dir_info_size += 10;
2112 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
2113 sizeof(struct dx_dir_info),
2114 &ctx->dx_dir_info);
2115 if (retval) {
2116 ctx->dx_dir_info_size -= 10;
2117 return;
2118 }
2119 }
2120
2121 /*
2122 * Normally, add_dx_dir_info is called with each inode in
2123 * sequential order; but once in a while (like when pass 3
2124 * needs to recreate the root directory or lost+found
2125 * directory) it is called out of order. In those cases, we
2126 * need to move the dx_dir_info entries down to make room, since
2127 * the dx_dir_info array needs to be sorted by inode number for
2128 * get_dx_dir_info()'s sake.
2129 */
2130 if (ctx->dx_dir_info_count &&
2131 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
2132 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
2133 if (ctx->dx_dir_info[i-1].ino < ino)
2134 break;
2135 dir = &ctx->dx_dir_info[i];
2136 if (dir->ino != ino)
2137 for (j = ctx->dx_dir_info_count++; j > i; j--)
2138 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
2139 } else
2140 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
2141
2142 dir->ino = ino;
2143 dir->numblocks = num_blocks;
2144 dir->hashversion = 0;
2145 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
2146 * sizeof (struct dx_dirblock_info),
2147 "dx_block info array");
2148
2149}
2150
2151/*
2152 * get_dx_dir_info() --- given an inode number, try to find the directory
2153 * information entry for it.
2154 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002155static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002156{
2157 int low, high, mid;
2158
2159 low = 0;
2160 high = ctx->dx_dir_info_count-1;
2161 if (!ctx->dx_dir_info)
2162 return 0;
2163 if (ino == ctx->dx_dir_info[low].ino)
2164 return &ctx->dx_dir_info[low];
2165 if (ino == ctx->dx_dir_info[high].ino)
2166 return &ctx->dx_dir_info[high];
2167
2168 while (low < high) {
2169 mid = (low+high)/2;
2170 if (mid == low || mid == high)
2171 break;
2172 if (ino == ctx->dx_dir_info[mid].ino)
2173 return &ctx->dx_dir_info[mid];
2174 if (ino < ctx->dx_dir_info[mid].ino)
2175 high = mid;
2176 else
2177 low = mid;
2178 }
2179 return 0;
2180}
2181
2182/*
2183 * Free the dx_dir_info structure when it isn't needed any more.
2184 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002185static void e2fsck_free_dx_dir_info(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002186{
2187 int i;
2188 struct dx_dir_info *dir;
2189
2190 if (ctx->dx_dir_info) {
2191 dir = ctx->dx_dir_info;
2192 for (i=0; i < ctx->dx_dir_info_count; i++) {
2193 if (dir->dx_block) {
2194 ext2fs_free_mem(&dir->dx_block);
2195 dir->dx_block = 0;
2196 }
2197 }
2198 ext2fs_free_mem(&ctx->dx_dir_info);
2199 ctx->dx_dir_info = 0;
2200 }
2201 ctx->dx_dir_info_size = 0;
2202 ctx->dx_dir_info_count = 0;
2203}
2204
2205/*
2206 * A simple interator function
2207 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002208static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002209{
2210 if (*control >= ctx->dx_dir_info_count)
2211 return 0;
2212
2213 return(ctx->dx_dir_info + (*control)++);
2214}
2215
2216#endif /* ENABLE_HTREE */
2217/*
2218 * e2fsck.c - a consistency checker for the new extended file system.
2219 *
Mike Frysinger51a43b42005-09-24 07:11:16 +00002220 */
2221
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002222/*
2223 * This function allocates an e2fsck context
2224 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002225static errcode_t e2fsck_allocate_context(e2fsck_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002226{
2227 e2fsck_t context;
2228 errcode_t retval;
2229
2230 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
2231 if (retval)
2232 return retval;
2233
2234 memset(context, 0, sizeof(struct e2fsck_struct));
2235
2236 context->process_inode_size = 256;
2237 context->ext_attr_ver = 2;
2238
2239 *ret = context;
2240 return 0;
2241}
2242
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002243struct ea_refcount_el {
2244 blk_t ea_blk;
2245 int ea_count;
2246};
2247
2248struct ea_refcount {
2249 blk_t count;
2250 blk_t size;
2251 blk_t cursor;
2252 struct ea_refcount_el *list;
2253};
2254
2255static void ea_refcount_free(ext2_refcount_t refcount)
2256{
2257 if (!refcount)
2258 return;
2259
2260 if (refcount->list)
2261 ext2fs_free_mem(&refcount->list);
2262 ext2fs_free_mem(&refcount);
2263}
2264
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002265/*
2266 * This function resets an e2fsck context; it is called when e2fsck
2267 * needs to be restarted.
2268 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002269static errcode_t e2fsck_reset_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002270{
2271 ctx->flags = 0;
2272 ctx->lost_and_found = 0;
2273 ctx->bad_lost_and_found = 0;
2274 if (ctx->inode_used_map) {
2275 ext2fs_free_inode_bitmap(ctx->inode_used_map);
2276 ctx->inode_used_map = 0;
2277 }
2278 if (ctx->inode_dir_map) {
2279 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
2280 ctx->inode_dir_map = 0;
2281 }
2282 if (ctx->inode_reg_map) {
2283 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
2284 ctx->inode_reg_map = 0;
2285 }
2286 if (ctx->block_found_map) {
2287 ext2fs_free_block_bitmap(ctx->block_found_map);
2288 ctx->block_found_map = 0;
2289 }
2290 if (ctx->inode_link_info) {
2291 ext2fs_free_icount(ctx->inode_link_info);
2292 ctx->inode_link_info = 0;
2293 }
2294 if (ctx->journal_io) {
2295 if (ctx->fs && ctx->fs->io != ctx->journal_io)
2296 io_channel_close(ctx->journal_io);
2297 ctx->journal_io = 0;
2298 }
2299 if (ctx->fs && ctx->fs->dblist) {
2300 ext2fs_free_dblist(ctx->fs->dblist);
2301 ctx->fs->dblist = 0;
2302 }
2303 e2fsck_free_dir_info(ctx);
2304#ifdef ENABLE_HTREE
2305 e2fsck_free_dx_dir_info(ctx);
Mike Frysinger51a43b42005-09-24 07:11:16 +00002306#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002307 if (ctx->refcount) {
2308 ea_refcount_free(ctx->refcount);
2309 ctx->refcount = 0;
2310 }
2311 if (ctx->refcount_extra) {
2312 ea_refcount_free(ctx->refcount_extra);
2313 ctx->refcount_extra = 0;
2314 }
2315 if (ctx->block_dup_map) {
2316 ext2fs_free_block_bitmap(ctx->block_dup_map);
2317 ctx->block_dup_map = 0;
2318 }
2319 if (ctx->block_ea_map) {
2320 ext2fs_free_block_bitmap(ctx->block_ea_map);
2321 ctx->block_ea_map = 0;
2322 }
2323 if (ctx->inode_bb_map) {
2324 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
2325 ctx->inode_bb_map = 0;
2326 }
2327 if (ctx->inode_bad_map) {
2328 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2329 ctx->inode_bad_map = 0;
2330 }
2331 if (ctx->inode_imagic_map) {
2332 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
2333 ctx->inode_imagic_map = 0;
2334 }
2335 if (ctx->dirs_to_hash) {
2336 ext2fs_u32_list_free(ctx->dirs_to_hash);
2337 ctx->dirs_to_hash = 0;
2338 }
2339
2340 /*
2341 * Clear the array of invalid meta-data flags
2342 */
2343 if (ctx->invalid_inode_bitmap_flag) {
2344 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
2345 ctx->invalid_inode_bitmap_flag = 0;
2346 }
2347 if (ctx->invalid_block_bitmap_flag) {
2348 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
2349 ctx->invalid_block_bitmap_flag = 0;
2350 }
2351 if (ctx->invalid_inode_table_flag) {
2352 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
2353 ctx->invalid_inode_table_flag = 0;
2354 }
2355
2356 /* Clear statistic counters */
2357 ctx->fs_directory_count = 0;
2358 ctx->fs_regular_count = 0;
2359 ctx->fs_blockdev_count = 0;
2360 ctx->fs_chardev_count = 0;
2361 ctx->fs_links_count = 0;
2362 ctx->fs_symlinks_count = 0;
2363 ctx->fs_fast_symlinks_count = 0;
2364 ctx->fs_fifo_count = 0;
2365 ctx->fs_total_count = 0;
2366 ctx->fs_badblocks_count = 0;
2367 ctx->fs_sockets_count = 0;
2368 ctx->fs_ind_count = 0;
2369 ctx->fs_dind_count = 0;
2370 ctx->fs_tind_count = 0;
2371 ctx->fs_fragmented = 0;
2372 ctx->large_files = 0;
2373
2374 /* Reset the superblock to the user's requested value */
2375 ctx->superblock = ctx->use_superblock;
2376
2377 return 0;
2378}
2379
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002380static void e2fsck_free_context(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002381{
2382 if (!ctx)
2383 return;
2384
2385 e2fsck_reset_context(ctx);
2386 if (ctx->blkid)
2387 blkid_put_cache(ctx->blkid);
2388
2389 ext2fs_free_mem(&ctx);
2390}
2391
2392/*
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002393 * ea_refcount.c
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002394 */
2395
2396/*
2397 * The strategy we use for keeping track of EA refcounts is as
2398 * follows. We keep a sorted array of first EA blocks and its
2399 * reference counts. Once the refcount has dropped to zero, it is
2400 * removed from the array to save memory space. Once the EA block is
2401 * checked, its bit is set in the block_ea_map bitmap.
2402 */
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002403
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002404
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002405static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002406{
2407 ext2_refcount_t refcount;
2408 errcode_t retval;
2409 size_t bytes;
2410
2411 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
2412 if (retval)
2413 return retval;
2414 memset(refcount, 0, sizeof(struct ea_refcount));
2415
2416 if (!size)
2417 size = 500;
2418 refcount->size = size;
2419 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
2420#ifdef DEBUG
2421 printf("Refcount allocated %d entries, %d bytes.\n",
2422 refcount->size, bytes);
2423#endif
2424 retval = ext2fs_get_mem(bytes, &refcount->list);
2425 if (retval)
2426 goto errout;
2427 memset(refcount->list, 0, bytes);
2428
2429 refcount->count = 0;
2430 refcount->cursor = 0;
2431
2432 *ret = refcount;
2433 return 0;
2434
2435errout:
2436 ea_refcount_free(refcount);
2437 return(retval);
2438}
2439
2440/*
2441 * collapse_refcount() --- go through the refcount array, and get rid
2442 * of any count == zero entries
2443 */
2444static void refcount_collapse(ext2_refcount_t refcount)
2445{
2446 unsigned int i, j;
2447 struct ea_refcount_el *list;
2448
2449 list = refcount->list;
2450 for (i = 0, j = 0; i < refcount->count; i++) {
2451 if (list[i].ea_count) {
2452 if (i != j)
2453 list[j] = list[i];
2454 j++;
2455 }
2456 }
2457#if defined(DEBUG) || defined(TEST_PROGRAM)
2458 printf("Refcount_collapse: size was %d, now %d\n",
2459 refcount->count, j);
2460#endif
2461 refcount->count = j;
2462}
2463
2464
2465/*
2466 * insert_refcount_el() --- Insert a new entry into the sorted list at a
2467 * specified position.
2468 */
2469static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
2470 blk_t blk, int pos)
2471{
2472 struct ea_refcount_el *el;
2473 errcode_t retval;
2474 blk_t new_size = 0;
2475 int num;
2476
2477 if (refcount->count >= refcount->size) {
2478 new_size = refcount->size + 100;
2479#ifdef DEBUG
2480 printf("Reallocating refcount %d entries...\n", new_size);
2481#endif
2482 retval = ext2fs_resize_mem((size_t) refcount->size *
2483 sizeof(struct ea_refcount_el),
2484 (size_t) new_size *
2485 sizeof(struct ea_refcount_el),
2486 &refcount->list);
2487 if (retval)
2488 return 0;
2489 refcount->size = new_size;
2490 }
2491 num = (int) refcount->count - pos;
2492 if (num < 0)
2493 return 0; /* should never happen */
2494 if (num) {
2495 memmove(&refcount->list[pos+1], &refcount->list[pos],
2496 sizeof(struct ea_refcount_el) * num);
2497 }
2498 refcount->count++;
2499 el = &refcount->list[pos];
2500 el->ea_count = 0;
2501 el->ea_blk = blk;
2502 return el;
2503}
2504
2505
2506/*
2507 * get_refcount_el() --- given an block number, try to find refcount
2508 * information in the sorted list. If the create flag is set,
2509 * and we can't find an entry, create one in the sorted list.
2510 */
2511static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
2512 blk_t blk, int create)
2513{
2514 float range;
2515 int low, high, mid;
2516 blk_t lowval, highval;
2517
2518 if (!refcount || !refcount->list)
2519 return 0;
2520retry:
2521 low = 0;
2522 high = (int) refcount->count-1;
2523 if (create && ((refcount->count == 0) ||
2524 (blk > refcount->list[high].ea_blk))) {
2525 if (refcount->count >= refcount->size)
2526 refcount_collapse(refcount);
2527
2528 return insert_refcount_el(refcount, blk,
2529 (unsigned) refcount->count);
2530 }
2531 if (refcount->count == 0)
2532 return 0;
2533
2534 if (refcount->cursor >= refcount->count)
2535 refcount->cursor = 0;
2536 if (blk == refcount->list[refcount->cursor].ea_blk)
2537 return &refcount->list[refcount->cursor++];
2538#ifdef DEBUG
2539 printf("Non-cursor get_refcount_el: %u\n", blk);
2540#endif
2541 while (low <= high) {
2542#if 0
2543 mid = (low+high)/2;
Mike Frysinger51a43b42005-09-24 07:11:16 +00002544#else
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002545 if (low == high)
2546 mid = low;
2547 else {
2548 /* Interpolate for efficiency */
2549 lowval = refcount->list[low].ea_blk;
2550 highval = refcount->list[high].ea_blk;
2551
2552 if (blk < lowval)
2553 range = 0;
2554 else if (blk > highval)
2555 range = 1;
2556 else
2557 range = ((float) (blk - lowval)) /
2558 (highval - lowval);
2559 mid = low + ((int) (range * (high-low)));
2560 }
Mike Frysinger51a43b42005-09-24 07:11:16 +00002561#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002562 if (blk == refcount->list[mid].ea_blk) {
2563 refcount->cursor = mid+1;
2564 return &refcount->list[mid];
2565 }
2566 if (blk < refcount->list[mid].ea_blk)
2567 high = mid-1;
2568 else
2569 low = mid+1;
2570 }
2571 /*
2572 * If we need to create a new entry, it should be right at
2573 * low (where high will be left at low-1).
2574 */
2575 if (create) {
2576 if (refcount->count >= refcount->size) {
2577 refcount_collapse(refcount);
2578 if (refcount->count < refcount->size)
2579 goto retry;
2580 }
2581 return insert_refcount_el(refcount, blk, low);
2582 }
2583 return 0;
2584}
2585
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002586static errcode_t
2587ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002588{
2589 struct ea_refcount_el *el;
2590
2591 el = get_refcount_el(refcount, blk, 1);
2592 if (!el)
2593 return EXT2_ET_NO_MEMORY;
2594 el->ea_count++;
2595
2596 if (ret)
2597 *ret = el->ea_count;
2598 return 0;
2599}
2600
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002601static errcode_t
2602ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002603{
2604 struct ea_refcount_el *el;
2605
2606 el = get_refcount_el(refcount, blk, 0);
2607 if (!el || el->ea_count == 0)
2608 return EXT2_ET_INVALID_ARGUMENT;
2609
2610 el->ea_count--;
2611
2612 if (ret)
2613 *ret = el->ea_count;
2614 return 0;
2615}
2616
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002617static errcode_t
2618ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002619{
2620 struct ea_refcount_el *el;
2621
2622 /*
2623 * Get the refcount element
2624 */
2625 el = get_refcount_el(refcount, blk, count ? 1 : 0);
2626 if (!el)
2627 return count ? EXT2_ET_NO_MEMORY : 0;
2628 el->ea_count = count;
2629 return 0;
2630}
2631
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002632static inline void ea_refcount_intr_begin(ext2_refcount_t refcount)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002633{
2634 refcount->cursor = 0;
2635}
2636
2637
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002638static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002639{
2640 struct ea_refcount_el *list;
2641
2642 while (1) {
2643 if (refcount->cursor >= refcount->count)
2644 return 0;
2645 list = refcount->list;
2646 if (list[refcount->cursor].ea_count) {
2647 if (ret)
2648 *ret = list[refcount->cursor].ea_count;
2649 return list[refcount->cursor++].ea_blk;
2650 }
2651 refcount->cursor++;
2652 }
2653}
2654
2655
2656/*
2657 * ehandler.c --- handle bad block errors which come up during the
2658 * course of an e2fsck session.
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002659 */
2660
2661
2662static const char *operation;
2663
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002664static errcode_t
2665e2fsck_handle_read_error(io_channel channel, unsigned long block, int count,
2666 void *data, size_t size EXT2FS_ATTR((unused)),
2667 int actual EXT2FS_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002668{
2669 int i;
2670 char *p;
2671 ext2_filsys fs = (ext2_filsys) channel->app_data;
2672 e2fsck_t ctx;
2673
2674 ctx = (e2fsck_t) fs->priv_data;
2675
2676 /*
2677 * If more than one block was read, try reading each block
2678 * separately. We could use the actual bytes read to figure
2679 * out where to start, but we don't bother.
2680 */
2681 if (count > 1) {
2682 p = (char *) data;
2683 for (i=0; i < count; i++, p += channel->block_size, block++) {
2684 error = io_channel_read_blk(channel, block,
2685 1, p);
2686 if (error)
2687 return error;
2688 }
2689 return 0;
2690 }
2691 if (operation)
2692 printf(_("Error reading block %lu (%s) while %s. "), block,
2693 error_message(error), operation);
2694 else
2695 printf(_("Error reading block %lu (%s). "), block,
2696 error_message(error));
2697 preenhalt(ctx);
2698 if (ask(ctx, _("Ignore error"), 1)) {
2699 if (ask(ctx, _("Force rewrite"), 1))
2700 io_channel_write_blk(channel, block, 1, data);
2701 return 0;
2702 }
2703
2704 return error;
2705}
2706
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002707static errcode_t
2708e2fsck_handle_write_error(io_channel channel, unsigned long block, int count,
2709 const void *data, size_t size EXT2FS_ATTR((unused)),
2710 int actual EXT2FS_ATTR((unused)), errcode_t error)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002711{
2712 int i;
2713 const char *p;
2714 ext2_filsys fs = (ext2_filsys) channel->app_data;
2715 e2fsck_t ctx;
2716
2717 ctx = (e2fsck_t) fs->priv_data;
2718
2719 /*
2720 * If more than one block was written, try writing each block
2721 * separately. We could use the actual bytes read to figure
2722 * out where to start, but we don't bother.
2723 */
2724 if (count > 1) {
2725 p = (const char *) data;
2726 for (i=0; i < count; i++, p += channel->block_size, block++) {
2727 error = io_channel_write_blk(channel, block,
2728 1, p);
2729 if (error)
2730 return error;
2731 }
2732 return 0;
2733 }
2734
2735 if (operation)
2736 printf(_("Error writing block %lu (%s) while %s. "), block,
2737 error_message(error), operation);
2738 else
2739 printf(_("Error writing block %lu (%s). "), block,
2740 error_message(error));
2741 preenhalt(ctx);
2742 if (ask(ctx, _("Ignore error"), 1))
2743 return 0;
2744
2745 return error;
2746}
2747
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002748static inline const char *ehandler_operation(const char *op)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002749{
2750 const char *ret = operation;
2751
2752 operation = op;
2753 return ret;
2754}
2755
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002756static void ehandler_init(io_channel channel)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002757{
2758 channel->read_error = e2fsck_handle_read_error;
2759 channel->write_error = e2fsck_handle_write_error;
2760}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002761
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002762/*
2763 * journal.c --- code for handling the "ext3" journal
2764 *
2765 * Copyright (C) 2000 Andreas Dilger
2766 * Copyright (C) 2000 Theodore Ts'o
2767 *
2768 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
2769 * Copyright (C) 1999 Red Hat Software
2770 *
2771 * This file may be redistributed under the terms of the
2772 * GNU General Public License version 2 or at your discretion
2773 * any later version.
2774 */
2775
2776#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
2777
2778
2779#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
2780static int bh_count = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +00002781#endif
2782
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002783/*
2784 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
2785 * This creates a larger static binary, and a smaller binary using
2786 * shared libraries. It's also probably slightly less CPU-efficient,
2787 * which is why it's not on by default. But, it's a good way of
2788 * testing the functions in inode_io.c and fileio.c.
2789 */
2790#undef USE_INODE_IO
2791
2792/* Kernel compatibility functions for handling the journal. These allow us
2793 * to use the recovery.c file virtually unchanged from the kernel, so we
2794 * don't have to do much to keep kernel and user recovery in sync.
2795 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002796static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002797{
2798#ifdef USE_INODE_IO
2799 *phys = block;
2800 return 0;
2801#else
2802 struct inode *inode = journal->j_inode;
2803 errcode_t retval;
2804 blk_t pblk;
2805
2806 if (!inode) {
2807 *phys = block;
2808 return 0;
2809 }
2810
2811 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
2812 &inode->i_ext2, NULL, 0, block, &pblk);
2813 *phys = pblk;
2814 return (retval);
2815#endif
2816}
2817
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002818static struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002819{
2820 struct buffer_head *bh;
2821
2822 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
2823 if (!bh)
2824 return NULL;
2825
2826 jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
2827 (unsigned long) blocknr, blocksize, ++bh_count);
2828
2829 bh->b_ctx = kdev->k_ctx;
2830 if (kdev->k_dev == K_DEV_FS)
2831 bh->b_io = kdev->k_ctx->fs->io;
2832 else
2833 bh->b_io = kdev->k_ctx->journal_io;
2834 bh->b_size = blocksize;
2835 bh->b_blocknr = blocknr;
2836
2837 return bh;
2838}
2839
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002840static void sync_blockdev(kdev_t kdev)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002841{
2842 io_channel io;
2843
2844 if (kdev->k_dev == K_DEV_FS)
2845 io = kdev->k_ctx->fs->io;
2846 else
2847 io = kdev->k_ctx->journal_io;
2848
2849 io_channel_flush(io);
2850}
2851
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002852static void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002853{
2854 int retval;
2855 struct buffer_head *bh;
2856
2857 for (; nr > 0; --nr) {
2858 bh = *bhp++;
2859 if (rw == READ && !bh->b_uptodate) {
2860 jfs_debug(3, "reading block %lu/%p\n",
2861 (unsigned long) bh->b_blocknr, (void *) bh);
2862 retval = io_channel_read_blk(bh->b_io,
2863 bh->b_blocknr,
2864 1, bh->b_data);
2865 if (retval) {
2866 com_err(bh->b_ctx->device_name, retval,
2867 "while reading block %lu\n",
2868 (unsigned long) bh->b_blocknr);
2869 bh->b_err = retval;
2870 continue;
2871 }
2872 bh->b_uptodate = 1;
2873 } else if (rw == WRITE && bh->b_dirty) {
2874 jfs_debug(3, "writing block %lu/%p\n",
2875 (unsigned long) bh->b_blocknr, (void *) bh);
2876 retval = io_channel_write_blk(bh->b_io,
2877 bh->b_blocknr,
2878 1, bh->b_data);
2879 if (retval) {
2880 com_err(bh->b_ctx->device_name, retval,
2881 "while writing block %lu\n",
2882 (unsigned long) bh->b_blocknr);
2883 bh->b_err = retval;
2884 continue;
2885 }
2886 bh->b_dirty = 0;
2887 bh->b_uptodate = 1;
2888 } else {
2889 jfs_debug(3, "no-op %s for block %lu\n",
2890 rw == READ ? "read" : "write",
2891 (unsigned long) bh->b_blocknr);
2892 }
2893 }
2894}
2895
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002896static inline void mark_buffer_dirty(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002897{
2898 bh->b_dirty = 1;
2899}
2900
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002901static inline void mark_buffer_clean(struct buffer_head * bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002902{
2903 bh->b_dirty = 0;
2904}
2905
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002906static void brelse(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002907{
2908 if (bh->b_dirty)
2909 ll_rw_block(WRITE, 1, &bh);
2910 jfs_debug(3, "freeing block %lu/%p (total %d)\n",
2911 (unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
2912 ext2fs_free_mem(&bh);
2913}
2914
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002915static inline int buffer_uptodate(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002916{
2917 return bh->b_uptodate;
2918}
2919
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002920static inline void mark_buffer_uptodate(struct buffer_head *bh, int val)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002921{
2922 bh->b_uptodate = val;
2923}
2924
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00002925static void wait_on_buffer(struct buffer_head *bh)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00002926{
2927 if (!bh->b_uptodate)
2928 ll_rw_block(READ, 1, &bh);
2929}
2930
2931
2932static void e2fsck_clear_recover(e2fsck_t ctx, int error)
2933{
2934 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
2935
2936 /* if we had an error doing journal recovery, we need a full fsck */
2937 if (error)
2938 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
2939 ext2fs_mark_super_dirty(ctx->fs);
2940}
2941
2942static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
2943{
2944 struct ext2_super_block *sb = ctx->fs->super;
2945 struct ext2_super_block jsuper;
2946 struct problem_context pctx;
2947 struct buffer_head *bh;
2948 struct inode *j_inode = NULL;
2949 struct kdev_s *dev_fs = NULL, *dev_journal;
2950 const char *journal_name = 0;
2951 journal_t *journal = NULL;
2952 errcode_t retval = 0;
2953 io_manager io_ptr = 0;
2954 unsigned long start = 0;
2955 blk_t blk;
2956 int ext_journal = 0;
2957 int tried_backup_jnl = 0;
2958 int i;
2959
2960 clear_problem_context(&pctx);
2961
2962 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
2963 if (!journal) {
2964 return EXT2_ET_NO_MEMORY;
2965 }
2966
2967 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
2968 if (!dev_fs) {
2969 retval = EXT2_ET_NO_MEMORY;
2970 goto errout;
2971 }
2972 dev_journal = dev_fs+1;
2973
2974 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
2975 dev_fs->k_dev = K_DEV_FS;
2976 dev_journal->k_dev = K_DEV_JOURNAL;
2977
2978 journal->j_dev = dev_journal;
2979 journal->j_fs_dev = dev_fs;
2980 journal->j_inode = NULL;
2981 journal->j_blocksize = ctx->fs->blocksize;
2982
2983 if (uuid_is_null(sb->s_journal_uuid)) {
2984 if (!sb->s_journal_inum)
2985 return EXT2_ET_BAD_INODE_NUM;
2986 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
2987 "journal inode");
2988 if (!j_inode) {
2989 retval = EXT2_ET_NO_MEMORY;
2990 goto errout;
2991 }
2992
2993 j_inode->i_ctx = ctx;
2994 j_inode->i_ino = sb->s_journal_inum;
2995
2996 if ((retval = ext2fs_read_inode(ctx->fs,
2997 sb->s_journal_inum,
2998 &j_inode->i_ext2))) {
2999 try_backup_journal:
3000 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
3001 tried_backup_jnl)
3002 goto errout;
3003 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
3004 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
3005 EXT2_N_BLOCKS*4);
3006 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
3007 j_inode->i_ext2.i_links_count = 1;
3008 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
3009 tried_backup_jnl++;
3010 }
3011 if (!j_inode->i_ext2.i_links_count ||
3012 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
3013 retval = EXT2_ET_NO_JOURNAL;
3014 goto try_backup_journal;
3015 }
3016 if (j_inode->i_ext2.i_size / journal->j_blocksize <
3017 JFS_MIN_JOURNAL_BLOCKS) {
3018 retval = EXT2_ET_JOURNAL_TOO_SMALL;
3019 goto try_backup_journal;
3020 }
3021 for (i=0; i < EXT2_N_BLOCKS; i++) {
3022 blk = j_inode->i_ext2.i_block[i];
3023 if (!blk) {
3024 if (i < EXT2_NDIR_BLOCKS) {
3025 retval = EXT2_ET_JOURNAL_TOO_SMALL;
3026 goto try_backup_journal;
3027 }
3028 continue;
3029 }
3030 if (blk < sb->s_first_data_block ||
3031 blk >= sb->s_blocks_count) {
3032 retval = EXT2_ET_BAD_BLOCK_NUM;
3033 goto try_backup_journal;
3034 }
3035 }
3036 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
3037
3038#ifdef USE_INODE_IO
3039 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
3040 &j_inode->i_ext2,
3041 &journal_name);
3042 if (retval)
3043 goto errout;
3044
3045 io_ptr = inode_io_manager;
3046#else
3047 journal->j_inode = j_inode;
3048 ctx->journal_io = ctx->fs->io;
3049 if ((retval = journal_bmap(journal, 0, &start)) != 0)
3050 goto errout;
3051#endif
3052 } else {
3053 ext_journal = 1;
3054 if (!ctx->journal_name) {
3055 char uuid[37];
3056
3057 uuid_unparse(sb->s_journal_uuid, uuid);
3058 ctx->journal_name = blkid_get_devname(ctx->blkid,
3059 "UUID", uuid);
3060 if (!ctx->journal_name)
3061 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
3062 }
3063 journal_name = ctx->journal_name;
3064
3065 if (!journal_name) {
3066 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
3067 return EXT2_ET_LOAD_EXT_JOURNAL;
3068 }
3069
3070 jfs_debug(1, "Using journal file %s\n", journal_name);
3071 io_ptr = unix_io_manager;
3072 }
3073
3074#if 0
3075 test_io_backing_manager = io_ptr;
3076 io_ptr = test_io_manager;
3077#endif
3078#ifndef USE_INODE_IO
3079 if (ext_journal)
3080#endif
3081 retval = io_ptr->open(journal_name, IO_FLAG_RW,
3082 &ctx->journal_io);
3083 if (retval)
3084 goto errout;
3085
3086 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
3087
3088 if (ext_journal) {
3089 if (ctx->fs->blocksize == 1024)
3090 start = 1;
3091 bh = getblk(dev_journal, start, ctx->fs->blocksize);
3092 if (!bh) {
3093 retval = EXT2_ET_NO_MEMORY;
3094 goto errout;
3095 }
3096 ll_rw_block(READ, 1, &bh);
3097 if ((retval = bh->b_err) != 0)
3098 goto errout;
3099 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
3100 sizeof(jsuper));
3101 brelse(bh);
3102#ifdef EXT2FS_ENABLE_SWAPFS
3103 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
3104 ext2fs_swap_super(&jsuper);
3105#endif
3106 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
3107 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
3108 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
3109 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3110 goto errout;
3111 }
3112 /* Make sure the journal UUID is correct */
3113 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
3114 sizeof(jsuper.s_uuid))) {
3115 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
3116 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3117 goto errout;
3118 }
3119
3120 journal->j_maxlen = jsuper.s_blocks_count;
3121 start++;
3122 }
3123
3124 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
3125 retval = EXT2_ET_NO_MEMORY;
3126 goto errout;
3127 }
3128
3129 journal->j_sb_buffer = bh;
3130 journal->j_superblock = (journal_superblock_t *)bh->b_data;
3131
3132#ifdef USE_INODE_IO
3133 if (j_inode)
3134 ext2fs_free_mem(&j_inode);
3135#endif
3136
3137 *ret_journal = journal;
3138 return 0;
3139
3140errout:
3141 if (dev_fs)
3142 ext2fs_free_mem(&dev_fs);
3143 if (j_inode)
3144 ext2fs_free_mem(&j_inode);
3145 if (journal)
3146 ext2fs_free_mem(&journal);
3147 return retval;
3148
3149}
3150
3151static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
3152 struct problem_context *pctx)
3153{
3154 struct ext2_super_block *sb = ctx->fs->super;
3155 int recover = ctx->fs->super->s_feature_incompat &
3156 EXT3_FEATURE_INCOMPAT_RECOVER;
3157 int has_journal = ctx->fs->super->s_feature_compat &
3158 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3159
3160 if (has_journal || sb->s_journal_inum) {
3161 /* The journal inode is bogus, remove and force full fsck */
3162 pctx->ino = sb->s_journal_inum;
3163 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
3164 if (has_journal && sb->s_journal_inum)
3165 printf("*** ext3 journal has been deleted - "
3166 "filesystem is now ext2 only ***\n\n");
3167 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3168 sb->s_journal_inum = 0;
3169 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
3170 e2fsck_clear_recover(ctx, 1);
3171 return 0;
3172 }
3173 return EXT2_ET_BAD_INODE_NUM;
3174 } else if (recover) {
3175 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
3176 e2fsck_clear_recover(ctx, 1);
3177 return 0;
3178 }
3179 return EXT2_ET_UNSUPP_FEATURE;
3180 }
3181 return 0;
3182}
3183
3184#define V1_SB_SIZE 0x0024
3185static void clear_v2_journal_fields(journal_t *journal)
3186{
3187 e2fsck_t ctx = journal->j_dev->k_ctx;
3188 struct problem_context pctx;
3189
3190 clear_problem_context(&pctx);
3191
3192 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
3193 return;
3194
3195 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
3196 ctx->fs->blocksize-V1_SB_SIZE);
3197 mark_buffer_dirty(journal->j_sb_buffer);
3198}
3199
3200
3201static errcode_t e2fsck_journal_load(journal_t *journal)
3202{
3203 e2fsck_t ctx = journal->j_dev->k_ctx;
3204 journal_superblock_t *jsb;
3205 struct buffer_head *jbh = journal->j_sb_buffer;
3206 struct problem_context pctx;
3207
3208 clear_problem_context(&pctx);
3209
3210 ll_rw_block(READ, 1, &jbh);
3211 if (jbh->b_err) {
3212 com_err(ctx->device_name, jbh->b_err,
3213 _("reading journal superblock\n"));
3214 return jbh->b_err;
3215 }
3216
3217 jsb = journal->j_superblock;
3218 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
3219 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
3220 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3221
3222 switch (ntohl(jsb->s_header.h_blocktype)) {
3223 case JFS_SUPERBLOCK_V1:
3224 journal->j_format_version = 1;
3225 if (jsb->s_feature_compat ||
3226 jsb->s_feature_incompat ||
3227 jsb->s_feature_ro_compat ||
3228 jsb->s_nr_users)
3229 clear_v2_journal_fields(journal);
3230 break;
3231
3232 case JFS_SUPERBLOCK_V2:
3233 journal->j_format_version = 2;
3234 if (ntohl(jsb->s_nr_users) > 1 &&
3235 uuid_is_null(ctx->fs->super->s_journal_uuid))
3236 clear_v2_journal_fields(journal);
3237 if (ntohl(jsb->s_nr_users) > 1) {
3238 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
3239 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3240 }
3241 break;
3242
3243 /*
3244 * These should never appear in a journal super block, so if
3245 * they do, the journal is badly corrupted.
3246 */
3247 case JFS_DESCRIPTOR_BLOCK:
3248 case JFS_COMMIT_BLOCK:
3249 case JFS_REVOKE_BLOCK:
3250 return EXT2_ET_CORRUPT_SUPERBLOCK;
3251
3252 /* If we don't understand the superblock major type, but there
3253 * is a magic number, then it is likely to be a new format we
3254 * just don't understand, so leave it alone. */
3255 default:
3256 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3257 }
3258
3259 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
3260 return EXT2_ET_UNSUPP_FEATURE;
3261
3262 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
3263 return EXT2_ET_RO_UNSUPP_FEATURE;
3264
3265 /* We have now checked whether we know enough about the journal
3266 * format to be able to proceed safely, so any other checks that
3267 * fail we should attempt to recover from. */
3268 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
3269 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3270 _("%s: no valid journal superblock found\n"),
3271 ctx->device_name);
3272 return EXT2_ET_CORRUPT_SUPERBLOCK;
3273 }
3274
3275 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
3276 journal->j_maxlen = ntohl(jsb->s_maxlen);
3277 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
3278 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3279 _("%s: journal too short\n"),
3280 ctx->device_name);
3281 return EXT2_ET_CORRUPT_SUPERBLOCK;
3282 }
3283
3284 journal->j_tail_sequence = ntohl(jsb->s_sequence);
3285 journal->j_transaction_sequence = journal->j_tail_sequence;
3286 journal->j_tail = ntohl(jsb->s_start);
3287 journal->j_first = ntohl(jsb->s_first);
3288 journal->j_last = ntohl(jsb->s_maxlen);
3289
3290 return 0;
3291}
3292
3293static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
3294 journal_t *journal)
3295{
3296 char *p;
3297 union {
3298 uuid_t uuid;
3299 __u32 val[4];
3300 } u;
3301 __u32 new_seq = 0;
3302 int i;
3303
3304 /* Leave a valid existing V1 superblock signature alone.
3305 * Anything unrecognisable we overwrite with a new V2
3306 * signature. */
3307
3308 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
3309 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
3310 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
3311 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
3312 }
3313
3314 /* Zero out everything else beyond the superblock header */
3315
3316 p = ((char *) jsb) + sizeof(journal_header_t);
3317 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
3318
3319 jsb->s_blocksize = htonl(ctx->fs->blocksize);
3320 jsb->s_maxlen = htonl(journal->j_maxlen);
3321 jsb->s_first = htonl(1);
3322
3323 /* Initialize the journal sequence number so that there is "no"
3324 * chance we will find old "valid" transactions in the journal.
3325 * This avoids the need to zero the whole journal (slow to do,
3326 * and risky when we are just recovering the filesystem).
3327 */
3328 uuid_generate(u.uuid);
3329 for (i = 0; i < 4; i ++)
3330 new_seq ^= u.val[i];
3331 jsb->s_sequence = htonl(new_seq);
3332
3333 mark_buffer_dirty(journal->j_sb_buffer);
3334 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
3335}
3336
3337static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
3338 journal_t *journal,
3339 struct problem_context *pctx)
3340{
3341 struct ext2_super_block *sb = ctx->fs->super;
3342 int recover = ctx->fs->super->s_feature_incompat &
3343 EXT3_FEATURE_INCOMPAT_RECOVER;
3344
3345 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
3346 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
3347 e2fsck_journal_reset_super(ctx, journal->j_superblock,
3348 journal);
3349 journal->j_transaction_sequence = 1;
3350 e2fsck_clear_recover(ctx, recover);
3351 return 0;
3352 }
3353 return EXT2_ET_CORRUPT_SUPERBLOCK;
3354 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
3355 return EXT2_ET_CORRUPT_SUPERBLOCK;
3356
3357 return 0;
3358}
3359
3360static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
3361 int reset, int drop)
3362{
3363 journal_superblock_t *jsb;
3364
3365 if (drop)
3366 mark_buffer_clean(journal->j_sb_buffer);
3367 else if (!(ctx->options & E2F_OPT_READONLY)) {
3368 jsb = journal->j_superblock;
3369 jsb->s_sequence = htonl(journal->j_transaction_sequence);
3370 if (reset)
3371 jsb->s_start = 0; /* this marks the journal as empty */
3372 mark_buffer_dirty(journal->j_sb_buffer);
3373 }
3374 brelse(journal->j_sb_buffer);
3375
3376 if (ctx->journal_io) {
3377 if (ctx->fs && ctx->fs->io != ctx->journal_io)
3378 io_channel_close(ctx->journal_io);
3379 ctx->journal_io = 0;
3380 }
3381
3382#ifndef USE_INODE_IO
3383 if (journal->j_inode)
3384 ext2fs_free_mem(&journal->j_inode);
3385#endif
3386 if (journal->j_fs_dev)
3387 ext2fs_free_mem(&journal->j_fs_dev);
3388 ext2fs_free_mem(&journal);
3389}
3390
3391/*
3392 * This function makes sure that the superblock fields regarding the
3393 * journal are consistent.
3394 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003395static int e2fsck_check_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003396{
3397 struct ext2_super_block *sb = ctx->fs->super;
3398 journal_t *journal;
3399 int recover = ctx->fs->super->s_feature_incompat &
3400 EXT3_FEATURE_INCOMPAT_RECOVER;
3401 struct problem_context pctx;
3402 problem_t problem;
3403 int reset = 0, force_fsck = 0;
3404 int retval;
3405
3406 /* If we don't have any journal features, don't do anything more */
3407 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
3408 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
3409 uuid_is_null(sb->s_journal_uuid))
3410 return 0;
3411
3412 clear_problem_context(&pctx);
3413 pctx.num = sb->s_journal_inum;
3414
3415 retval = e2fsck_get_journal(ctx, &journal);
3416 if (retval) {
3417 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
3418 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
3419 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
3420 (retval == EXT2_ET_NO_JOURNAL))
3421 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3422 return retval;
3423 }
3424
3425 retval = e2fsck_journal_load(journal);
3426 if (retval) {
3427 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
3428 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
3429 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
3430 &pctx))) ||
3431 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
3432 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
3433 &pctx))) ||
3434 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
3435 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
3436 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
3437 &pctx);
3438 e2fsck_journal_release(ctx, journal, 0, 1);
3439 return retval;
3440 }
3441
3442 /*
3443 * We want to make the flags consistent here. We will not leave with
3444 * needs_recovery set but has_journal clear. We can't get in a loop
3445 * with -y, -n, or -p, only if a user isn't making up their mind.
3446 */
3447no_has_journal:
3448 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
3449 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
3450 pctx.str = "inode";
3451 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
3452 if (recover &&
3453 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
3454 goto no_has_journal;
3455 /*
3456 * Need a full fsck if we are releasing a
3457 * journal stored on a reserved inode.
3458 */
3459 force_fsck = recover ||
3460 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
3461 /* Clear all of the journal fields */
3462 sb->s_journal_inum = 0;
3463 sb->s_journal_dev = 0;
3464 memset(sb->s_journal_uuid, 0,
3465 sizeof(sb->s_journal_uuid));
3466 e2fsck_clear_recover(ctx, force_fsck);
3467 } else if (!(ctx->options & E2F_OPT_READONLY)) {
3468 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3469 ext2fs_mark_super_dirty(ctx->fs);
3470 }
3471 }
3472
3473 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
3474 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
3475 journal->j_superblock->s_start != 0) {
3476 /* Print status information */
3477 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
3478 if (ctx->superblock)
3479 problem = PR_0_JOURNAL_RUN_DEFAULT;
3480 else
3481 problem = PR_0_JOURNAL_RUN;
3482 if (fix_problem(ctx, problem, &pctx)) {
3483 ctx->options |= E2F_OPT_FORCE;
3484 sb->s_feature_incompat |=
3485 EXT3_FEATURE_INCOMPAT_RECOVER;
3486 ext2fs_mark_super_dirty(ctx->fs);
3487 } else if (fix_problem(ctx,
3488 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
3489 reset = 1;
3490 sb->s_state &= ~EXT2_VALID_FS;
3491 ext2fs_mark_super_dirty(ctx->fs);
3492 }
3493 /*
3494 * If the user answers no to the above question, we
3495 * ignore the fact that journal apparently has data;
3496 * accidentally replaying over valid data would be far
3497 * worse than skipping a questionable recovery.
3498 *
3499 * XXX should we abort with a fatal error here? What
3500 * will the ext3 kernel code do if a filesystem with
3501 * !NEEDS_RECOVERY but with a non-zero
3502 * journal->j_superblock->s_start is mounted?
3503 */
3504 }
3505
3506 e2fsck_journal_release(ctx, journal, reset, 0);
3507 return retval;
3508}
3509
3510static errcode_t recover_ext3_journal(e2fsck_t ctx)
3511{
3512 journal_t *journal;
3513 int retval;
3514
3515 journal_init_revoke_caches();
3516 retval = e2fsck_get_journal(ctx, &journal);
3517 if (retval)
3518 return retval;
3519
3520 retval = e2fsck_journal_load(journal);
3521 if (retval)
3522 goto errout;
3523
3524 retval = journal_init_revoke(journal, 1024);
3525 if (retval)
3526 goto errout;
3527
3528 retval = -journal_recover(journal);
3529 if (retval)
3530 goto errout;
3531
3532 if (journal->j_superblock->s_errno) {
3533 ctx->fs->super->s_state |= EXT2_ERROR_FS;
3534 ext2fs_mark_super_dirty(ctx->fs);
3535 journal->j_superblock->s_errno = 0;
3536 mark_buffer_dirty(journal->j_sb_buffer);
3537 }
3538
3539errout:
3540 journal_destroy_revoke(journal);
3541 journal_destroy_revoke_caches();
3542 e2fsck_journal_release(ctx, journal, 1, 0);
3543 return retval;
3544}
3545
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003546static int e2fsck_run_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003547{
3548 io_manager io_ptr = ctx->fs->io->manager;
3549 int blocksize = ctx->fs->blocksize;
3550 errcode_t retval, recover_retval;
3551
3552 printf(_("%s: recovering journal\n"), ctx->device_name);
3553 if (ctx->options & E2F_OPT_READONLY) {
3554 printf(_("%s: won't do journal recovery while read-only\n"),
3555 ctx->device_name);
3556 return EXT2_ET_FILE_RO;
3557 }
3558
3559 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
3560 ext2fs_flush(ctx->fs); /* Force out any modifications */
3561
3562 recover_retval = recover_ext3_journal(ctx);
3563
3564 /*
3565 * Reload the filesystem context to get up-to-date data from disk
3566 * because journal recovery will change the filesystem under us.
3567 */
3568 ext2fs_close(ctx->fs);
3569 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
3570 ctx->superblock, blocksize, io_ptr,
3571 &ctx->fs);
3572
3573 if (retval) {
3574 com_err(ctx->program_name, retval,
3575 _("while trying to re-open %s"),
3576 ctx->device_name);
3577 fatal_error(ctx, 0);
3578 }
3579 ctx->fs->priv_data = ctx;
3580
3581 /* Set the superblock flags */
3582 e2fsck_clear_recover(ctx, recover_retval);
3583 return recover_retval;
3584}
3585
3586/*
3587 * This function will move the journal inode from a visible file in
3588 * the filesystem directory hierarchy to the reserved inode if necessary.
3589 */
3590static const char * const journal_names[] = {
3591 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
3592
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003593static void e2fsck_move_ext3_journal(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003594{
3595 struct ext2_super_block *sb = ctx->fs->super;
3596 struct problem_context pctx;
3597 struct ext2_inode inode;
3598 ext2_filsys fs = ctx->fs;
3599 ext2_ino_t ino;
3600 errcode_t retval;
3601 const char * const * cpp;
3602 int group, mount_flags;
3603
3604 clear_problem_context(&pctx);
3605
3606 /*
3607 * If the filesystem is opened read-only, or there is no
3608 * journal, then do nothing.
3609 */
3610 if ((ctx->options & E2F_OPT_READONLY) ||
3611 (sb->s_journal_inum == 0) ||
3612 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
3613 return;
3614
3615 /*
3616 * Read in the journal inode
3617 */
3618 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
3619 return;
3620
3621 /*
3622 * If it's necessary to backup the journal inode, do so.
3623 */
3624 if ((sb->s_jnl_backup_type == 0) ||
3625 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
3626 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
3627 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
3628 memcpy(sb->s_jnl_blocks, inode.i_block,
3629 EXT2_N_BLOCKS*4);
3630 sb->s_jnl_blocks[16] = inode.i_size;
3631 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
3632 ext2fs_mark_super_dirty(fs);
3633 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3634 }
3635 }
3636
3637 /*
3638 * If the journal is already the hidden inode, then do nothing
3639 */
3640 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
3641 return;
3642
3643 /*
3644 * The journal inode had better have only one link and not be readable.
3645 */
3646 if (inode.i_links_count != 1)
3647 return;
3648
3649 /*
3650 * If the filesystem is mounted, or we can't tell whether
3651 * or not it's mounted, do nothing.
3652 */
3653 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
3654 if (retval || (mount_flags & EXT2_MF_MOUNTED))
3655 return;
3656
3657 /*
3658 * If we can't find the name of the journal inode, then do
3659 * nothing.
3660 */
3661 for (cpp = journal_names; *cpp; cpp++) {
3662 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
3663 strlen(*cpp), 0, &ino);
3664 if ((retval == 0) && (ino == sb->s_journal_inum))
3665 break;
3666 }
3667 if (*cpp == 0)
3668 return;
3669
3670 /* We need the inode bitmap to be loaded */
3671 retval = ext2fs_read_bitmaps(fs);
3672 if (retval)
3673 return;
3674
3675 pctx.str = *cpp;
3676 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
3677 return;
3678
3679 /*
3680 * OK, we've done all the checks, let's actually move the
3681 * journal inode. Errors at this point mean we need to force
3682 * an ext2 filesystem check.
3683 */
3684 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
3685 goto err_out;
3686 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
3687 goto err_out;
3688 sb->s_journal_inum = EXT2_JOURNAL_INO;
3689 ext2fs_mark_super_dirty(fs);
3690 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3691 inode.i_links_count = 0;
3692 inode.i_dtime = time(0);
3693 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
3694 goto err_out;
3695
3696 group = ext2fs_group_of_ino(fs, ino);
3697 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
3698 ext2fs_mark_ib_dirty(fs);
3699 fs->group_desc[group].bg_free_inodes_count++;
3700 fs->super->s_free_inodes_count++;
3701 return;
3702
3703err_out:
3704 pctx.errcode = retval;
3705 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
3706 fs->super->s_state &= ~EXT2_VALID_FS;
3707 ext2fs_mark_super_dirty(fs);
3708 return;
3709}
3710
3711/*
3712 * message.c --- print e2fsck messages (with compression)
3713 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003714 * print_e2fsck_message() prints a message to the user, using
3715 * compression techniques and expansions of abbreviations.
3716 *
3717 * The following % expansions are supported:
3718 *
3719 * %b <blk> block number
3720 * %B <blkcount> integer
3721 * %c <blk2> block number
3722 * %Di <dirent>->ino inode number
3723 * %Dn <dirent>->name string
3724 * %Dr <dirent>->rec_len
3725 * %Dl <dirent>->name_len
3726 * %Dt <dirent>->filetype
3727 * %d <dir> inode number
3728 * %g <group> integer
3729 * %i <ino> inode number
3730 * %Is <inode> -> i_size
3731 * %IS <inode> -> i_extra_isize
3732 * %Ib <inode> -> i_blocks
3733 * %Il <inode> -> i_links_count
3734 * %Im <inode> -> i_mode
3735 * %IM <inode> -> i_mtime
3736 * %IF <inode> -> i_faddr
3737 * %If <inode> -> i_file_acl
3738 * %Id <inode> -> i_dir_acl
3739 * %Iu <inode> -> i_uid
3740 * %Ig <inode> -> i_gid
3741 * %j <ino2> inode number
3742 * %m <com_err error message>
3743 * %N <num>
3744 * %p ext2fs_get_pathname of directory <ino>
3745 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
3746 * the containing directory. (If dirent is NULL
3747 * then return the pathname of directory <ino2>)
3748 * %q ext2fs_get_pathname of directory <dir>
3749 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
3750 * the containing directory.
3751 * %s <str> miscellaneous string
3752 * %S backup superblock
3753 * %X <num> hexadecimal format
3754 *
3755 * The following '@' expansions are supported:
3756 *
3757 * @a extended attribute
3758 * @A error allocating
3759 * @b block
3760 * @B bitmap
3761 * @c compress
3762 * @C conflicts with some other fs block
3763 * @D deleted
3764 * @d directory
3765 * @e entry
3766 * @E Entry '%Dn' in %p (%i)
3767 * @f filesystem
3768 * @F for @i %i (%Q) is
3769 * @g group
3770 * @h HTREE directory inode
3771 * @i inode
3772 * @I illegal
3773 * @j journal
3774 * @l lost+found
3775 * @L is a link
3776 * @o orphaned
3777 * @p problem in
3778 * @r root inode
3779 * @s should be
3780 * @S superblock
3781 * @u unattached
3782 * @v device
3783 * @z zero-length
3784 */
3785
3786
3787/*
3788 * This structure defines the abbreviations used by the text strings
3789 * below. The first character in the string is the index letter. An
3790 * abbreviation of the form '@<i>' is expanded by looking up the index
3791 * letter <i> in the table below.
3792 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003793static const char * const abbrevs[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003794 N_("aextended attribute"),
3795 N_("Aerror allocating"),
3796 N_("bblock"),
3797 N_("Bbitmap"),
3798 N_("ccompress"),
3799 N_("Cconflicts with some other fs @b"),
3800 N_("iinode"),
3801 N_("Iillegal"),
3802 N_("jjournal"),
3803 N_("Ddeleted"),
3804 N_("ddirectory"),
3805 N_("eentry"),
3806 N_("E@e '%Dn' in %p (%i)"),
3807 N_("ffilesystem"),
3808 N_("Ffor @i %i (%Q) is"),
3809 N_("ggroup"),
3810 N_("hHTREE @d @i"),
3811 N_("llost+found"),
3812 N_("Lis a link"),
3813 N_("oorphaned"),
3814 N_("pproblem in"),
3815 N_("rroot @i"),
3816 N_("sshould be"),
3817 N_("Ssuper@b"),
3818 N_("uunattached"),
3819 N_("vdevice"),
3820 N_("zzero-length"),
3821 "@@",
3822 0
3823 };
3824
3825/*
3826 * Give more user friendly names to the "special" inodes.
3827 */
3828#define num_special_inodes 11
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003829static const char * const special_inode_name[] =
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003830{
3831 N_("<The NULL inode>"), /* 0 */
3832 N_("<The bad blocks inode>"), /* 1 */
3833 "/", /* 2 */
3834 N_("<The ACL index inode>"), /* 3 */
3835 N_("<The ACL data inode>"), /* 4 */
3836 N_("<The boot loader inode>"), /* 5 */
3837 N_("<The undelete directory inode>"), /* 6 */
3838 N_("<The group descriptor inode>"), /* 7 */
3839 N_("<The journal inode>"), /* 8 */
3840 N_("<Reserved inode 9>"), /* 9 */
3841 N_("<Reserved inode 10>"), /* 10 */
3842};
3843
3844/*
3845 * This function does "safe" printing. It will convert non-printable
3846 * ASCII characters using '^' and M- notation.
3847 */
3848static void safe_print(const char *cp, int len)
3849{
3850 unsigned char ch;
3851
3852 if (len < 0)
3853 len = strlen(cp);
3854
3855 while (len--) {
3856 ch = *cp++;
3857 if (ch > 128) {
3858 fputs("M-", stdout);
3859 ch -= 128;
3860 }
3861 if ((ch < 32) || (ch == 0x7f)) {
3862 fputc('^', stdout);
3863 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
3864 }
3865 fputc(ch, stdout);
3866 }
3867}
3868
3869
3870/*
3871 * This function prints a pathname, using the ext2fs_get_pathname
3872 * function
3873 */
3874static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
3875{
3876 errcode_t retval;
3877 char *path;
3878
3879 if (!dir && (ino < num_special_inodes)) {
3880 fputs(_(special_inode_name[ino]), stdout);
3881 return;
3882 }
3883
3884 retval = ext2fs_get_pathname(fs, dir, ino, &path);
3885 if (retval)
3886 fputs("???", stdout);
3887 else {
3888 safe_print(path, -1);
3889 ext2fs_free_mem(&path);
3890 }
3891}
3892
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003893static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
3894 struct problem_context *pctx, int first);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003895/*
3896 * This function handles the '@' expansion. We allow recursive
3897 * expansion; an @ expression can contain further '@' and '%'
3898 * expressions.
3899 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003900static void expand_at_expression(e2fsck_t ctx, char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003901 struct problem_context *pctx,
3902 int *first)
3903{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003904 const char * const *cpp;
3905 const char *str;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003906
3907 /* Search for the abbreviation */
3908 for (cpp = abbrevs; *cpp; cpp++) {
3909 if (ch == *cpp[0])
3910 break;
3911 }
3912 if (*cpp) {
3913 str = _(*cpp) + 1;
3914 if (*first && islower(*str)) {
3915 *first = 0;
3916 fputc(toupper(*str++), stdout);
3917 }
3918 print_e2fsck_message(ctx, str, pctx, *first);
3919 } else
3920 printf("@%c", ch);
3921}
3922
3923/*
3924 * This function expands '%IX' expressions
3925 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00003926static void expand_inode_expression(char ch,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00003927 struct problem_context *ctx)
3928{
3929 struct ext2_inode *inode;
3930 struct ext2_inode_large *large_inode;
3931 char * time_str;
3932 time_t t;
3933 int do_gmt = -1;
3934
3935 if (!ctx || !ctx->inode)
3936 goto no_inode;
3937
3938 inode = ctx->inode;
3939 large_inode = (struct ext2_inode_large *) inode;
3940
3941 switch (ch) {
3942 case 's':
3943 if (LINUX_S_ISDIR(inode->i_mode))
3944 printf("%u", inode->i_size);
3945 else {
3946#ifdef EXT2_NO_64_TYPE
3947 if (inode->i_size_high)
3948 printf("0x%x%08x", inode->i_size_high,
3949 inode->i_size);
3950 else
3951 printf("%u", inode->i_size);
3952#else
3953 printf("%llu", (inode->i_size |
3954 ((__u64) inode->i_size_high << 32)));
3955#endif
3956 }
3957 break;
3958 case 'S':
3959 printf("%u", large_inode->i_extra_isize);
3960 break;
3961 case 'b':
3962 printf("%u", inode->i_blocks);
3963 break;
3964 case 'l':
3965 printf("%d", inode->i_links_count);
3966 break;
3967 case 'm':
3968 printf("0%o", inode->i_mode);
3969 break;
3970 case 'M':
3971 /* The diet libc doesn't respect the TZ environemnt variable */
3972 if (do_gmt == -1) {
3973 time_str = getenv("TZ");
3974 if (!time_str)
3975 time_str = "";
3976 do_gmt = !strcmp(time_str, "GMT");
3977 }
3978 t = inode->i_mtime;
3979 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
3980 printf("%.24s", time_str);
3981 break;
3982 case 'F':
3983 printf("%u", inode->i_faddr);
3984 break;
3985 case 'f':
3986 printf("%u", inode->i_file_acl);
3987 break;
3988 case 'd':
3989 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
3990 inode->i_dir_acl : 0));
3991 break;
3992 case 'u':
3993 printf("%d", (inode->i_uid |
3994 (inode->osd2.linux2.l_i_uid_high << 16)));
3995 break;
3996 case 'g':
3997 printf("%d", (inode->i_gid |
3998 (inode->osd2.linux2.l_i_gid_high << 16)));
3999 break;
4000 default:
4001 no_inode:
4002 printf("%%I%c", ch);
4003 break;
4004 }
4005}
4006
4007/*
4008 * This function expands '%dX' expressions
4009 */
4010static _INLINE_ void expand_dirent_expression(char ch,
4011 struct problem_context *ctx)
4012{
4013 struct ext2_dir_entry *dirent;
4014 int len;
4015
4016 if (!ctx || !ctx->dirent)
4017 goto no_dirent;
4018
4019 dirent = ctx->dirent;
4020
4021 switch (ch) {
4022 case 'i':
4023 printf("%u", dirent->inode);
4024 break;
4025 case 'n':
4026 len = dirent->name_len & 0xFF;
4027 if (len > EXT2_NAME_LEN)
4028 len = EXT2_NAME_LEN;
4029 if (len > dirent->rec_len)
4030 len = dirent->rec_len;
4031 safe_print(dirent->name, len);
4032 break;
4033 case 'r':
4034 printf("%u", dirent->rec_len);
4035 break;
4036 case 'l':
4037 printf("%u", dirent->name_len & 0xFF);
4038 break;
4039 case 't':
4040 printf("%u", dirent->name_len >> 8);
4041 break;
4042 default:
4043 no_dirent:
4044 printf("%%D%c", ch);
4045 break;
4046 }
4047}
4048
4049static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
4050 struct problem_context *ctx)
4051{
4052 if (!ctx)
4053 goto no_context;
4054
4055 switch (ch) {
4056 case '%':
4057 fputc('%', stdout);
4058 break;
4059 case 'b':
4060 printf("%u", ctx->blk);
4061 break;
4062 case 'B':
4063#ifdef EXT2_NO_64_TYPE
4064 printf("%d", ctx->blkcount);
4065#else
4066 printf("%lld", ctx->blkcount);
4067#endif
4068 break;
4069 case 'c':
4070 printf("%u", ctx->blk2);
4071 break;
4072 case 'd':
4073 printf("%u", ctx->dir);
4074 break;
4075 case 'g':
4076 printf("%d", ctx->group);
4077 break;
4078 case 'i':
4079 printf("%u", ctx->ino);
4080 break;
4081 case 'j':
4082 printf("%u", ctx->ino2);
4083 break;
4084 case 'm':
4085 printf("%s", error_message(ctx->errcode));
4086 break;
4087 case 'N':
4088#ifdef EXT2_NO_64_TYPE
4089 printf("%u", ctx->num);
4090#else
4091 printf("%llu", ctx->num);
4092#endif
4093 break;
4094 case 'p':
4095 print_pathname(fs, ctx->ino, 0);
4096 break;
4097 case 'P':
4098 print_pathname(fs, ctx->ino2,
4099 ctx->dirent ? ctx->dirent->inode : 0);
4100 break;
4101 case 'q':
4102 print_pathname(fs, ctx->dir, 0);
4103 break;
4104 case 'Q':
4105 print_pathname(fs, ctx->dir, ctx->ino);
4106 break;
4107 case 'S':
4108 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
4109 break;
4110 case 's':
4111 printf("%s", ctx->str ? ctx->str : "NULL");
4112 break;
4113 case 'X':
4114#ifdef EXT2_NO_64_TYPE
4115 printf("0x%x", ctx->num);
4116#else
4117 printf("0x%llx", ctx->num);
4118#endif
4119 break;
4120 default:
4121 no_context:
4122 printf("%%%c", ch);
4123 break;
4124 }
4125}
4126
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004127
4128static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004129 struct problem_context *pctx, int first)
4130{
4131 ext2_filsys fs = ctx->fs;
4132 const char * cp;
4133 int i;
4134
4135 e2fsck_clear_progbar(ctx);
4136 for (cp = msg; *cp; cp++) {
4137 if (cp[0] == '@') {
4138 cp++;
4139 expand_at_expression(ctx, *cp, pctx, &first);
4140 } else if (cp[0] == '%' && cp[1] == 'I') {
4141 cp += 2;
4142 expand_inode_expression(*cp, pctx);
4143 } else if (cp[0] == '%' && cp[1] == 'D') {
4144 cp += 2;
4145 expand_dirent_expression(*cp, pctx);
4146 } else if ((cp[0] == '%')) {
4147 cp++;
4148 expand_percent_expression(fs, *cp, pctx);
4149 } else {
4150 for (i=0; cp[i]; i++)
4151 if ((cp[i] == '@') || cp[i] == '%')
4152 break;
4153 printf("%.*s", i, cp);
4154 cp += i-1;
4155 }
4156 first = 0;
4157 }
4158}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004159
4160
4161/*
4162 * region.c --- code which manages allocations within a region.
4163 */
4164
4165struct region_el {
4166 region_addr_t start;
4167 region_addr_t end;
4168 struct region_el *next;
4169};
4170
4171struct region_struct {
4172 region_addr_t min;
4173 region_addr_t max;
4174 struct region_el *allocated;
4175};
4176
4177static region_t region_create(region_addr_t min, region_addr_t max)
4178{
4179 region_t region;
4180
4181 region = malloc(sizeof(struct region_struct));
4182 if (!region)
4183 return NULL;
4184 memset(region, 0, sizeof(struct region_struct));
4185 region->min = min;
4186 region->max = max;
4187 return region;
4188}
4189
4190static void region_free(region_t region)
4191{
4192 struct region_el *r, *next;
4193
4194 for (r = region->allocated; r; r = next) {
4195 next = r->next;
4196 free(r);
4197 }
4198 memset(region, 0, sizeof(struct region_struct));
4199 free(region);
4200}
4201
4202static int region_allocate(region_t region, region_addr_t start, int n)
4203{
4204 struct region_el *r, *new_region, *prev, *next;
4205 region_addr_t end;
4206
4207 end = start+n;
4208 if ((start < region->min) || (end > region->max))
4209 return -1;
4210 if (n == 0)
4211 return 1;
4212
4213 /*
4214 * Search through the linked list. If we find that it
4215 * conflicts witih something that's already allocated, return
4216 * 1; if we can find an existing region which we can grow, do
4217 * so. Otherwise, stop when we find the appropriate place
4218 * insert a new region element into the linked list.
4219 */
4220 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
4221 if (((start >= r->start) && (start < r->end)) ||
4222 ((end > r->start) && (end <= r->end)) ||
4223 ((start <= r->start) && (end >= r->end)))
4224 return 1;
4225 if (end == r->start) {
4226 r->start = start;
4227 return 0;
4228 }
4229 if (start == r->end) {
4230 if ((next = r->next)) {
4231 if (end > next->start)
4232 return 1;
4233 if (end == next->start) {
4234 r->end = next->end;
4235 r->next = next->next;
4236 free(next);
4237 return 0;
4238 }
4239 }
4240 r->end = end;
4241 return 0;
4242 }
4243 if (start < r->start)
4244 break;
4245 }
4246 /*
4247 * Insert a new region element structure into the linked list
4248 */
4249 new_region = malloc(sizeof(struct region_el));
4250 if (!new_region)
4251 return -1;
4252 new_region->start = start;
4253 new_region->end = start + n;
4254 new_region->next = r;
4255 if (prev)
4256 prev->next = new_region;
4257 else
4258 region->allocated = new_region;
4259 return 0;
4260}
4261
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004262/*
4263 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
4264 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004265 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
4266 * and applies the following tests to each inode:
4267 *
4268 * - The mode field of the inode must be legal.
4269 * - The size and block count fields of the inode are correct.
4270 * - A data block must not be used by another inode
4271 *
4272 * Pass 1 also gathers the collects the following information:
4273 *
4274 * - A bitmap of which inodes are in use. (inode_used_map)
4275 * - A bitmap of which inodes are directories. (inode_dir_map)
4276 * - A bitmap of which inodes are regular files. (inode_reg_map)
4277 * - A bitmap of which inodes have bad fields. (inode_bad_map)
4278 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
4279 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
4280 * - A bitmap of which blocks are in use. (block_found_map)
4281 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
4282 * - The data blocks of the directory inodes. (dir_map)
4283 *
4284 * Pass 1 is designed to stash away enough information so that the
4285 * other passes should not need to read in the inode information
4286 * during the normal course of a filesystem check. (Althogh if an
4287 * inconsistency is detected, other passes may need to read in an
4288 * inode to fix it.)
4289 *
4290 * Note that pass 1B will be invoked if there are any duplicate blocks
4291 * found.
4292 */
4293
4294
4295static int process_block(ext2_filsys fs, blk_t *blocknr,
4296 e2_blkcnt_t blockcnt, blk_t ref_blk,
4297 int ref_offset, void *priv_data);
4298static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
4299 e2_blkcnt_t blockcnt, blk_t ref_blk,
4300 int ref_offset, void *priv_data);
4301static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4302 char *block_buf);
4303static void mark_table_blocks(e2fsck_t ctx);
4304static void alloc_bb_map(e2fsck_t ctx);
4305static void alloc_imagic_map(e2fsck_t ctx);
4306static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
4307static void handle_fs_bad_blocks(e2fsck_t ctx);
4308static void process_inodes(e2fsck_t ctx, char *block_buf);
4309static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
4310static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
4311 dgrp_t group, void * priv_data);
4312static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
4313 char *block_buf, int adjust_sign);
4314/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
4315
4316static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
4317 struct ext2_inode * inode, int bufsize,
4318 const char *proc);
4319
4320struct process_block_struct_1 {
4321 ext2_ino_t ino;
4322 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
4323 fragmented:1, compressed:1, bbcheck:1;
4324 blk_t num_blocks;
4325 blk_t max_blocks;
4326 e2_blkcnt_t last_block;
4327 int num_illegal_blocks;
4328 blk_t previous_block;
4329 struct ext2_inode *inode;
4330 struct problem_context *pctx;
4331 ext2fs_block_bitmap fs_meta_blocks;
4332 e2fsck_t ctx;
4333};
4334
4335struct process_inode_block {
4336 ext2_ino_t ino;
4337 struct ext2_inode inode;
4338};
4339
4340struct scan_callback_struct {
4341 e2fsck_t ctx;
4342 char *block_buf;
4343};
4344
4345/*
4346 * For the inodes to process list.
4347 */
4348static struct process_inode_block *inodes_to_process;
4349static int process_inode_count;
4350
4351static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
4352 EXT2_MIN_BLOCK_LOG_SIZE + 1];
4353
4354/*
4355 * Free all memory allocated by pass1 in preparation for restarting
4356 * things.
4357 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004358static void unwind_pass1(void)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004359{
4360 ext2fs_free_mem(&inodes_to_process);
4361 inodes_to_process = 0;
4362}
4363
4364/*
4365 * Check to make sure a device inode is real. Returns 1 if the device
4366 * checks out, 0 if not.
4367 *
4368 * Note: this routine is now also used to check FIFO's and Sockets,
4369 * since they have the same requirement; the i_block fields should be
4370 * zero.
4371 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004372static int
4373e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004374{
4375 int i;
4376
4377 /*
4378 * If i_blocks is non-zero, or the index flag is set, then
4379 * this is a bogus device/fifo/socket
4380 */
4381 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
4382 (inode->i_flags & EXT2_INDEX_FL))
4383 return 0;
4384
4385 /*
4386 * We should be able to do the test below all the time, but
4387 * because the kernel doesn't forcibly clear the device
4388 * inode's additional i_block fields, there are some rare
4389 * occasions when a legitimate device inode will have non-zero
4390 * additional i_block fields. So for now, we only complain
4391 * when the immutable flag is set, which should never happen
4392 * for devices. (And that's when the problem is caused, since
4393 * you can't set or clear immutable flags for devices.) Once
4394 * the kernel has been fixed we can change this...
4395 */
4396 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
4397 for (i=4; i < EXT2_N_BLOCKS; i++)
4398 if (inode->i_block[i])
4399 return 0;
4400 }
4401 return 1;
4402}
4403
4404/*
4405 * Check to make sure a symlink inode is real. Returns 1 if the symlink
4406 * checks out, 0 if not.
4407 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004408static int
4409e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, char *buf)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004410{
4411 unsigned int len;
4412 int i;
4413 blk_t blocks;
4414
4415 if ((inode->i_size_high || inode->i_size == 0) ||
4416 (inode->i_flags & EXT2_INDEX_FL))
4417 return 0;
4418
4419 blocks = ext2fs_inode_data_blocks(fs, inode);
4420 if (blocks) {
4421 if ((inode->i_size >= fs->blocksize) ||
4422 (blocks != fs->blocksize >> 9) ||
4423 (inode->i_block[0] < fs->super->s_first_data_block) ||
4424 (inode->i_block[0] >= fs->super->s_blocks_count))
4425 return 0;
4426
4427 for (i = 1; i < EXT2_N_BLOCKS; i++)
4428 if (inode->i_block[i])
4429 return 0;
4430
4431 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
4432 return 0;
4433
4434 len = strnlen(buf, fs->blocksize);
4435 if (len == fs->blocksize)
4436 return 0;
4437 } else {
4438 if (inode->i_size >= sizeof(inode->i_block))
4439 return 0;
4440
4441 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
4442 if (len == sizeof(inode->i_block))
4443 return 0;
4444 }
4445 if (len != inode->i_size)
4446 return 0;
4447 return 1;
4448}
4449
4450/*
4451 * If the immutable (or append-only) flag is set on the inode, offer
4452 * to clear it.
4453 */
4454#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
4455static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
4456{
4457 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
4458 return;
4459
4460 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
4461 return;
4462
4463 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
4464 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4465}
4466
4467/*
4468 * If device, fifo or socket, check size is zero -- if not offer to
4469 * clear it
4470 */
4471static void check_size(e2fsck_t ctx, struct problem_context *pctx)
4472{
4473 struct ext2_inode *inode = pctx->inode;
4474
4475 if ((inode->i_size == 0) && (inode->i_size_high == 0))
4476 return;
4477
4478 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
4479 return;
4480
4481 inode->i_size = 0;
4482 inode->i_size_high = 0;
4483 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4484}
4485
4486static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
4487{
4488 struct ext2_super_block *sb = ctx->fs->super;
4489 struct ext2_inode_large *inode;
4490 struct ext2_ext_attr_entry *entry;
4491 char *start, *end;
4492 int storage_size, remain, offs;
4493 int problem = 0;
4494
4495 inode = (struct ext2_inode_large *) pctx->inode;
4496 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
4497 inode->i_extra_isize;
4498 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4499 inode->i_extra_isize + sizeof(__u32);
4500 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
4501 entry = (struct ext2_ext_attr_entry *) start;
4502
4503 /* scan all entry's headers first */
4504
4505 /* take finish entry 0UL into account */
4506 remain = storage_size - sizeof(__u32);
4507 offs = end - start;
4508
4509 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
4510
4511 /* header eats this space */
4512 remain -= sizeof(struct ext2_ext_attr_entry);
4513
4514 /* is attribute name valid? */
4515 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
4516 pctx->num = entry->e_name_len;
4517 problem = PR_1_ATTR_NAME_LEN;
4518 goto fix;
4519 }
4520
4521 /* attribute len eats this space */
4522 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
4523
4524 /* check value size */
4525 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
4526 pctx->num = entry->e_value_size;
4527 problem = PR_1_ATTR_VALUE_SIZE;
4528 goto fix;
4529 }
4530
4531 /* check value placement */
4532 if (entry->e_value_offs +
4533 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
4534 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
4535 pctx->num = entry->e_value_offs;
4536 problem = PR_1_ATTR_VALUE_OFFSET;
4537 goto fix;
4538 }
4539
4540 /* e_value_block must be 0 in inode's ea */
4541 if (entry->e_value_block != 0) {
4542 pctx->num = entry->e_value_block;
4543 problem = PR_1_ATTR_VALUE_BLOCK;
4544 goto fix;
4545 }
4546
4547 /* e_hash must be 0 in inode's ea */
4548 if (entry->e_hash != 0) {
4549 pctx->num = entry->e_hash;
4550 problem = PR_1_ATTR_HASH;
4551 goto fix;
4552 }
4553
4554 remain -= entry->e_value_size;
4555 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
4556
4557 entry = EXT2_EXT_ATTR_NEXT(entry);
4558 }
4559fix:
4560 /*
4561 * it seems like a corruption. it's very unlikely we could repair
4562 * EA(s) in automatic fashion -bzzz
4563 */
4564#if 0
4565 problem = PR_1_ATTR_HASH;
4566#endif
4567 if (problem == 0 || !fix_problem(ctx, problem, pctx))
4568 return;
4569
4570 /* simple remove all possible EA(s) */
4571 *((__u32 *)start) = 0UL;
4572 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
4573 EXT2_INODE_SIZE(sb), "pass1");
4574}
4575
4576static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
4577{
4578 struct ext2_super_block *sb = ctx->fs->super;
4579 struct ext2_inode_large *inode;
4580 __u32 *eamagic;
4581 int min, max;
4582
4583 inode = (struct ext2_inode_large *) pctx->inode;
4584 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
4585 /* this isn't large inode. so, nothing to check */
4586 return;
4587 }
4588
4589#if 0
4590 printf("inode #%u, i_extra_size %d\n", pctx->ino,
4591 inode->i_extra_isize);
4592#endif
4593 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
4594 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
4595 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
4596 /*
4597 * For now we will allow i_extra_isize to be 0, but really
4598 * implementations should never allow i_extra_isize to be 0
4599 */
4600 if (inode->i_extra_isize &&
4601 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
4602 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
4603 return;
4604 inode->i_extra_isize = min;
4605 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
4606 EXT2_INODE_SIZE(sb), "pass1");
4607 return;
4608 }
4609
4610 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4611 inode->i_extra_isize);
4612 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
4613 /* it seems inode has an extended attribute(s) in body */
4614 check_ea_in_inode(ctx, pctx);
4615 }
4616}
4617
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00004618static void e2fsck_pass1(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00004619{
4620 int i;
4621 __u64 max_sizes;
4622 ext2_filsys fs = ctx->fs;
4623 ext2_ino_t ino;
4624 struct ext2_inode *inode;
4625 ext2_inode_scan scan;
4626 char *block_buf;
4627#ifdef RESOURCE_TRACK
4628 struct resource_track rtrack;
4629#endif
4630 unsigned char frag, fsize;
4631 struct problem_context pctx;
4632 struct scan_callback_struct scan_struct;
4633 struct ext2_super_block *sb = ctx->fs->super;
4634 int imagic_fs;
4635 int busted_fs_time = 0;
4636 int inode_size;
4637
4638#ifdef RESOURCE_TRACK
4639 init_resource_track(&rtrack);
4640#endif
4641 clear_problem_context(&pctx);
4642
4643 if (!(ctx->options & E2F_OPT_PREEN))
4644 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
4645
4646 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4647 !(ctx->options & E2F_OPT_NO)) {
4648 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
4649 ctx->dirs_to_hash = 0;
4650 }
4651
4652#ifdef MTRACE
4653 mtrace_print("Pass 1");
4654#endif
4655
4656#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
4657
4658 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
4659 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
4660 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
4661 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
4662 max_sizes = (max_sizes * (1UL << i)) - 1;
4663 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
4664 }
4665#undef EXT2_BPP
4666
4667 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
4668
4669 /*
4670 * Allocate bitmaps structures
4671 */
4672 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
4673 &ctx->inode_used_map);
4674 if (pctx.errcode) {
4675 pctx.num = 1;
4676 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4677 ctx->flags |= E2F_FLAG_ABORT;
4678 return;
4679 }
4680 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4681 _("directory inode map"), &ctx->inode_dir_map);
4682 if (pctx.errcode) {
4683 pctx.num = 2;
4684 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4685 ctx->flags |= E2F_FLAG_ABORT;
4686 return;
4687 }
4688 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4689 _("regular file inode map"), &ctx->inode_reg_map);
4690 if (pctx.errcode) {
4691 pctx.num = 6;
4692 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4693 ctx->flags |= E2F_FLAG_ABORT;
4694 return;
4695 }
4696 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
4697 &ctx->block_found_map);
4698 if (pctx.errcode) {
4699 pctx.num = 1;
4700 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4701 ctx->flags |= E2F_FLAG_ABORT;
4702 return;
4703 }
4704 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
4705 &ctx->inode_link_info);
4706 if (pctx.errcode) {
4707 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
4708 ctx->flags |= E2F_FLAG_ABORT;
4709 return;
4710 }
4711 inode_size = EXT2_INODE_SIZE(fs->super);
4712 inode = (struct ext2_inode *)
4713 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
4714
4715 inodes_to_process = (struct process_inode_block *)
4716 e2fsck_allocate_memory(ctx,
4717 (ctx->process_inode_size *
4718 sizeof(struct process_inode_block)),
4719 "array of inodes to process");
4720 process_inode_count = 0;
4721
4722 pctx.errcode = ext2fs_init_dblist(fs, 0);
4723 if (pctx.errcode) {
4724 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
4725 ctx->flags |= E2F_FLAG_ABORT;
4726 return;
4727 }
4728
4729 /*
4730 * If the last orphan field is set, clear it, since the pass1
4731 * processing will automatically find and clear the orphans.
4732 * In the future, we may want to try using the last_orphan
4733 * linked list ourselves, but for now, we clear it so that the
4734 * ext3 mount code won't get confused.
4735 */
4736 if (!(ctx->options & E2F_OPT_READONLY)) {
4737 if (fs->super->s_last_orphan) {
4738 fs->super->s_last_orphan = 0;
4739 ext2fs_mark_super_dirty(fs);
4740 }
4741 }
4742
4743 mark_table_blocks(ctx);
4744 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
4745 "block interate buffer");
4746 e2fsck_use_inode_shortcuts(ctx, 1);
4747 ehandler_operation(_("doing inode scan"));
4748 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4749 &scan);
4750 if (pctx.errcode) {
4751 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4752 ctx->flags |= E2F_FLAG_ABORT;
4753 return;
4754 }
4755 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
4756 ctx->stashed_inode = inode;
4757 scan_struct.ctx = ctx;
4758 scan_struct.block_buf = block_buf;
4759 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
4760 if (ctx->progress)
4761 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
4762 return;
4763 if (fs->super->s_wtime < fs->super->s_inodes_count)
4764 busted_fs_time = 1;
4765
4766 while (1) {
4767 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
4768 inode, inode_size);
4769 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4770 return;
4771 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
4772 if (!ctx->inode_bb_map)
4773 alloc_bb_map(ctx);
4774 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
4775 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4776 continue;
4777 }
4778 if (pctx.errcode) {
4779 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4780 ctx->flags |= E2F_FLAG_ABORT;
4781 return;
4782 }
4783 if (!ino)
4784 break;
4785 pctx.ino = ino;
4786 pctx.inode = inode;
4787 ctx->stashed_ino = ino;
4788 if (inode->i_links_count) {
4789 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
4790 ino, inode->i_links_count);
4791 if (pctx.errcode) {
4792 pctx.num = inode->i_links_count;
4793 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
4794 ctx->flags |= E2F_FLAG_ABORT;
4795 return;
4796 }
4797 }
4798 if (ino == EXT2_BAD_INO) {
4799 struct process_block_struct_1 pb;
4800
4801 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
4802 &pb.fs_meta_blocks);
4803 if (pctx.errcode) {
4804 pctx.num = 4;
4805 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4806 ctx->flags |= E2F_FLAG_ABORT;
4807 return;
4808 }
4809 pb.ino = EXT2_BAD_INO;
4810 pb.num_blocks = pb.last_block = 0;
4811 pb.num_illegal_blocks = 0;
4812 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
4813 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
4814 pb.inode = inode;
4815 pb.pctx = &pctx;
4816 pb.ctx = ctx;
4817 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
4818 block_buf, process_bad_block, &pb);
4819 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
4820 if (pctx.errcode) {
4821 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
4822 ctx->flags |= E2F_FLAG_ABORT;
4823 return;
4824 }
4825 if (pb.bbcheck)
4826 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
4827 ctx->flags |= E2F_FLAG_ABORT;
4828 return;
4829 }
4830 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4831 clear_problem_context(&pctx);
4832 continue;
4833 } else if (ino == EXT2_ROOT_INO) {
4834 /*
4835 * Make sure the root inode is a directory; if
4836 * not, offer to clear it. It will be
4837 * regnerated in pass #3.
4838 */
4839 if (!LINUX_S_ISDIR(inode->i_mode)) {
4840 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
4841 inode->i_dtime = time(0);
4842 inode->i_links_count = 0;
4843 ext2fs_icount_store(ctx->inode_link_info,
4844 ino, 0);
4845 e2fsck_write_inode(ctx, ino, inode,
4846 "pass1");
4847 }
4848
4849 }
4850 /*
4851 * If dtime is set, offer to clear it. mke2fs
4852 * version 0.2b created filesystems with the
4853 * dtime field set for the root and lost+found
4854 * directories. We won't worry about
4855 * /lost+found, since that can be regenerated
4856 * easily. But we will fix the root directory
4857 * as a special case.
4858 */
4859 if (inode->i_dtime && inode->i_links_count) {
4860 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
4861 inode->i_dtime = 0;
4862 e2fsck_write_inode(ctx, ino, inode,
4863 "pass1");
4864 }
4865 }
4866 } else if (ino == EXT2_JOURNAL_INO) {
4867 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4868 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
4869 if (!LINUX_S_ISREG(inode->i_mode) &&
4870 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
4871 &pctx)) {
4872 inode->i_mode = LINUX_S_IFREG;
4873 e2fsck_write_inode(ctx, ino, inode,
4874 "pass1");
4875 }
4876 check_blocks(ctx, &pctx, block_buf);
4877 continue;
4878 }
4879 if ((inode->i_links_count || inode->i_blocks ||
4880 inode->i_blocks || inode->i_block[0]) &&
4881 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
4882 &pctx)) {
4883 memset(inode, 0, inode_size);
4884 ext2fs_icount_store(ctx->inode_link_info,
4885 ino, 0);
4886 e2fsck_write_inode_full(ctx, ino, inode,
4887 inode_size, "pass1");
4888 }
4889 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
4890 int problem = 0;
4891
4892 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4893 if (ino == EXT2_BOOT_LOADER_INO) {
4894 if (LINUX_S_ISDIR(inode->i_mode))
4895 problem = PR_1_RESERVED_BAD_MODE;
4896 } else if (ino == EXT2_RESIZE_INO) {
4897 if (inode->i_mode &&
4898 !LINUX_S_ISREG(inode->i_mode))
4899 problem = PR_1_RESERVED_BAD_MODE;
4900 } else {
4901 if (inode->i_mode != 0)
4902 problem = PR_1_RESERVED_BAD_MODE;
4903 }
4904 if (problem) {
4905 if (fix_problem(ctx, problem, &pctx)) {
4906 inode->i_mode = 0;
4907 e2fsck_write_inode(ctx, ino, inode,
4908 "pass1");
4909 }
4910 }
4911 check_blocks(ctx, &pctx, block_buf);
4912 continue;
4913 }
4914 /*
4915 * Check for inodes who might have been part of the
4916 * orphaned list linked list. They should have gotten
4917 * dealt with by now, unless the list had somehow been
4918 * corrupted.
4919 *
4920 * FIXME: In the future, inodes which are still in use
4921 * (and which are therefore) pending truncation should
4922 * be handled specially. Right now we just clear the
4923 * dtime field, and the normal e2fsck handling of
4924 * inodes where i_size and the inode blocks are
4925 * inconsistent is to fix i_size, instead of releasing
4926 * the extra blocks. This won't catch the inodes that
4927 * was at the end of the orphan list, but it's better
4928 * than nothing. The right answer is that there
4929 * shouldn't be any bugs in the orphan list handling. :-)
4930 */
4931 if (inode->i_dtime && !busted_fs_time &&
4932 inode->i_dtime < ctx->fs->super->s_inodes_count) {
4933 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
4934 inode->i_dtime = inode->i_links_count ?
4935 0 : time(0);
4936 e2fsck_write_inode(ctx, ino, inode,
4937 "pass1");
4938 }
4939 }
4940
4941 /*
4942 * This code assumes that deleted inodes have
4943 * i_links_count set to 0.
4944 */
4945 if (!inode->i_links_count) {
4946 if (!inode->i_dtime && inode->i_mode) {
4947 if (fix_problem(ctx,
4948 PR_1_ZERO_DTIME, &pctx)) {
4949 inode->i_dtime = time(0);
4950 e2fsck_write_inode(ctx, ino, inode,
4951 "pass1");
4952 }
4953 }
4954 continue;
4955 }
4956 /*
4957 * n.b. 0.3c ext2fs code didn't clear i_links_count for
4958 * deleted files. Oops.
4959 *
4960 * Since all new ext2 implementations get this right,
4961 * we now assume that the case of non-zero
4962 * i_links_count and non-zero dtime means that we
4963 * should keep the file, not delete it.
4964 *
4965 */
4966 if (inode->i_dtime) {
4967 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
4968 inode->i_dtime = 0;
4969 e2fsck_write_inode(ctx, ino, inode, "pass1");
4970 }
4971 }
4972
4973 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4974 switch (fs->super->s_creator_os) {
4975 case EXT2_OS_LINUX:
4976 frag = inode->osd2.linux2.l_i_frag;
4977 fsize = inode->osd2.linux2.l_i_fsize;
4978 break;
4979 case EXT2_OS_HURD:
4980 frag = inode->osd2.hurd2.h_i_frag;
4981 fsize = inode->osd2.hurd2.h_i_fsize;
4982 break;
4983 case EXT2_OS_MASIX:
4984 frag = inode->osd2.masix2.m_i_frag;
4985 fsize = inode->osd2.masix2.m_i_fsize;
4986 break;
4987 default:
4988 frag = fsize = 0;
4989 }
4990
4991 if (inode->i_faddr || frag || fsize ||
4992 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
4993 mark_inode_bad(ctx, ino);
4994 if (inode->i_flags & EXT2_IMAGIC_FL) {
4995 if (imagic_fs) {
4996 if (!ctx->inode_imagic_map)
4997 alloc_imagic_map(ctx);
4998 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
4999 ino);
5000 } else {
5001 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
5002 inode->i_flags &= ~EXT2_IMAGIC_FL;
5003 e2fsck_write_inode(ctx, ino,
5004 inode, "pass1");
5005 }
5006 }
5007 }
5008
5009 check_inode_extra_space(ctx, &pctx);
5010
5011 if (LINUX_S_ISDIR(inode->i_mode)) {
5012 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
5013 e2fsck_add_dir_info(ctx, ino, 0);
5014 ctx->fs_directory_count++;
5015 } else if (LINUX_S_ISREG (inode->i_mode)) {
5016 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
5017 ctx->fs_regular_count++;
5018 } else if (LINUX_S_ISCHR (inode->i_mode) &&
5019 e2fsck_pass1_check_device_inode(fs, inode)) {
5020 check_immutable(ctx, &pctx);
5021 check_size(ctx, &pctx);
5022 ctx->fs_chardev_count++;
5023 } else if (LINUX_S_ISBLK (inode->i_mode) &&
5024 e2fsck_pass1_check_device_inode(fs, inode)) {
5025 check_immutable(ctx, &pctx);
5026 check_size(ctx, &pctx);
5027 ctx->fs_blockdev_count++;
5028 } else if (LINUX_S_ISLNK (inode->i_mode) &&
5029 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
5030 check_immutable(ctx, &pctx);
5031 ctx->fs_symlinks_count++;
5032 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
5033 ctx->fs_fast_symlinks_count++;
5034 check_blocks(ctx, &pctx, block_buf);
5035 continue;
5036 }
5037 }
5038 else if (LINUX_S_ISFIFO (inode->i_mode) &&
5039 e2fsck_pass1_check_device_inode(fs, inode)) {
5040 check_immutable(ctx, &pctx);
5041 check_size(ctx, &pctx);
5042 ctx->fs_fifo_count++;
5043 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
5044 e2fsck_pass1_check_device_inode(fs, inode)) {
5045 check_immutable(ctx, &pctx);
5046 check_size(ctx, &pctx);
5047 ctx->fs_sockets_count++;
5048 } else
5049 mark_inode_bad(ctx, ino);
5050 if (inode->i_block[EXT2_IND_BLOCK])
5051 ctx->fs_ind_count++;
5052 if (inode->i_block[EXT2_DIND_BLOCK])
5053 ctx->fs_dind_count++;
5054 if (inode->i_block[EXT2_TIND_BLOCK])
5055 ctx->fs_tind_count++;
5056 if (inode->i_block[EXT2_IND_BLOCK] ||
5057 inode->i_block[EXT2_DIND_BLOCK] ||
5058 inode->i_block[EXT2_TIND_BLOCK] ||
5059 inode->i_file_acl) {
5060 inodes_to_process[process_inode_count].ino = ino;
5061 inodes_to_process[process_inode_count].inode = *inode;
5062 process_inode_count++;
5063 } else
5064 check_blocks(ctx, &pctx, block_buf);
5065
5066 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5067 return;
5068
5069 if (process_inode_count >= ctx->process_inode_size) {
5070 process_inodes(ctx, block_buf);
5071
5072 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5073 return;
5074 }
5075 }
5076 process_inodes(ctx, block_buf);
5077 ext2fs_close_inode_scan(scan);
5078 ehandler_operation(0);
5079
5080 /*
5081 * If any extended attribute blocks' reference counts need to
5082 * be adjusted, either up (ctx->refcount_extra), or down
5083 * (ctx->refcount), then fix them.
5084 */
5085 if (ctx->refcount) {
5086 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
5087 ea_refcount_free(ctx->refcount);
5088 ctx->refcount = 0;
5089 }
5090 if (ctx->refcount_extra) {
5091 adjust_extattr_refcount(ctx, ctx->refcount_extra,
5092 block_buf, +1);
5093 ea_refcount_free(ctx->refcount_extra);
5094 ctx->refcount_extra = 0;
5095 }
5096
5097 if (ctx->invalid_bitmaps)
5098 handle_fs_bad_blocks(ctx);
5099
5100 /* We don't need the block_ea_map any more */
5101 if (ctx->block_ea_map) {
5102 ext2fs_free_block_bitmap(ctx->block_ea_map);
5103 ctx->block_ea_map = 0;
5104 }
5105
5106 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
5107 ext2fs_block_bitmap save_bmap;
5108
5109 save_bmap = fs->block_map;
5110 fs->block_map = ctx->block_found_map;
5111 clear_problem_context(&pctx);
5112 pctx.errcode = ext2fs_create_resize_inode(fs);
5113 if (pctx.errcode) {
5114 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
5115 /* Should never get here */
5116 ctx->flags |= E2F_FLAG_ABORT;
5117 return;
5118 }
5119 fs->block_map = save_bmap;
5120 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
5121 }
5122
5123 if (ctx->flags & E2F_FLAG_RESTART) {
5124 /*
5125 * Only the master copy of the superblock and block
5126 * group descriptors are going to be written during a
5127 * restart, so set the superblock to be used to be the
5128 * master superblock.
5129 */
5130 ctx->use_superblock = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00005131 unwind_pass1();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00005132 goto endit;
5133 }
5134
5135 if (ctx->block_dup_map) {
5136 if (ctx->options & E2F_OPT_PREEN) {
5137 clear_problem_context(&pctx);
5138 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
5139 }
5140 e2fsck_pass1_dupblocks(ctx, block_buf);
5141 }
5142 ext2fs_free_mem(&inodes_to_process);
5143endit:
5144 e2fsck_use_inode_shortcuts(ctx, 0);
5145
5146 ext2fs_free_mem(&block_buf);
5147 ext2fs_free_mem(&inode);
5148
5149#ifdef RESOURCE_TRACK
5150 if (ctx->options & E2F_OPT_TIME2) {
5151 e2fsck_clear_progbar(ctx);
5152 print_resource_track(_("Pass 1"), &rtrack);
5153 }
5154#endif
5155}
5156
5157/*
5158 * When the inode_scan routines call this callback at the end of the
5159 * glock group, call process_inodes.
5160 */
5161static errcode_t scan_callback(ext2_filsys fs,
5162 ext2_inode_scan scan EXT2FS_ATTR((unused)),
5163 dgrp_t group, void * priv_data)
5164{
5165 struct scan_callback_struct *scan_struct;
5166 e2fsck_t ctx;
5167
5168 scan_struct = (struct scan_callback_struct *) priv_data;
5169 ctx = scan_struct->ctx;
5170
5171 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
5172
5173 if (ctx->progress)
5174 if ((ctx->progress)(ctx, 1, group+1,
5175 ctx->fs->group_desc_count))
5176 return EXT2_ET_CANCEL_REQUESTED;
5177
5178 return 0;
5179}
5180
5181/*
5182 * Process the inodes in the "inodes to process" list.
5183 */
5184static void process_inodes(e2fsck_t ctx, char *block_buf)
5185{
5186 int i;
5187 struct ext2_inode *old_stashed_inode;
5188 ext2_ino_t old_stashed_ino;
5189 const char *old_operation;
5190 char buf[80];
5191 struct problem_context pctx;
5192
5193#if 0
5194 printf("begin process_inodes: ");
5195#endif
5196 if (process_inode_count == 0)
5197 return;
5198 old_operation = ehandler_operation(0);
5199 old_stashed_inode = ctx->stashed_inode;
5200 old_stashed_ino = ctx->stashed_ino;
5201 qsort(inodes_to_process, process_inode_count,
5202 sizeof(struct process_inode_block), process_inode_cmp);
5203 clear_problem_context(&pctx);
5204 for (i=0; i < process_inode_count; i++) {
5205 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
5206 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
5207
5208#if 0
5209 printf("%u ", pctx.ino);
5210#endif
5211 sprintf(buf, _("reading indirect blocks of inode %u"),
5212 pctx.ino);
5213 ehandler_operation(buf);
5214 check_blocks(ctx, &pctx, block_buf);
5215 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5216 break;
5217 }
5218 ctx->stashed_inode = old_stashed_inode;
5219 ctx->stashed_ino = old_stashed_ino;
5220 process_inode_count = 0;
5221#if 0
5222 printf("end process inodes\n");
5223#endif
5224 ehandler_operation(old_operation);
5225}
5226
5227static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
5228{
5229 const struct process_inode_block *ib_a =
5230 (const struct process_inode_block *) a;
5231 const struct process_inode_block *ib_b =
5232 (const struct process_inode_block *) b;
5233 int ret;
5234
5235 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
5236 ib_b->inode.i_block[EXT2_IND_BLOCK]);
5237 if (ret == 0)
5238 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
5239 return ret;
5240}
5241
5242/*
5243 * Mark an inode as being bad in some what
5244 */
5245static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
5246{
5247 struct problem_context pctx;
5248
5249 if (!ctx->inode_bad_map) {
5250 clear_problem_context(&pctx);
5251
5252 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5253 _("bad inode map"), &ctx->inode_bad_map);
5254 if (pctx.errcode) {
5255 pctx.num = 3;
5256 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5257 /* Should never get here */
5258 ctx->flags |= E2F_FLAG_ABORT;
5259 return;
5260 }
5261 }
5262 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
5263}
5264
5265
5266/*
5267 * This procedure will allocate the inode "bb" (badblock) map table
5268 */
5269static void alloc_bb_map(e2fsck_t ctx)
5270{
5271 struct problem_context pctx;
5272
5273 clear_problem_context(&pctx);
5274 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5275 _("inode in bad block map"),
5276 &ctx->inode_bb_map);
5277 if (pctx.errcode) {
5278 pctx.num = 4;
5279 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5280 /* Should never get here */
5281 ctx->flags |= E2F_FLAG_ABORT;
5282 return;
5283 }
5284}
5285
5286/*
5287 * This procedure will allocate the inode imagic table
5288 */
5289static void alloc_imagic_map(e2fsck_t ctx)
5290{
5291 struct problem_context pctx;
5292
5293 clear_problem_context(&pctx);
5294 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5295 _("imagic inode map"),
5296 &ctx->inode_imagic_map);
5297 if (pctx.errcode) {
5298 pctx.num = 5;
5299 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5300 /* Should never get here */
5301 ctx->flags |= E2F_FLAG_ABORT;
5302 return;
5303 }
5304}
5305
5306/*
5307 * Marks a block as in use, setting the dup_map if it's been set
5308 * already. Called by process_block and process_bad_block.
5309 *
5310 * WARNING: Assumes checks have already been done to make sure block
5311 * is valid. This is true in both process_block and process_bad_block.
5312 */
5313static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
5314{
5315 struct problem_context pctx;
5316
5317 clear_problem_context(&pctx);
5318
5319 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
5320 if (!ctx->block_dup_map) {
5321 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
5322 _("multiply claimed block map"),
5323 &ctx->block_dup_map);
5324 if (pctx.errcode) {
5325 pctx.num = 3;
5326 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
5327 &pctx);
5328 /* Should never get here */
5329 ctx->flags |= E2F_FLAG_ABORT;
5330 return;
5331 }
5332 }
5333 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
5334 } else {
5335 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
5336 }
5337}
5338
5339/*
5340 * Adjust the extended attribute block's reference counts at the end
5341 * of pass 1, either by subtracting out references for EA blocks that
5342 * are still referenced in ctx->refcount, or by adding references for
5343 * EA blocks that had extra references as accounted for in
5344 * ctx->refcount_extra.
5345 */
5346static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
5347 char *block_buf, int adjust_sign)
5348{
5349 struct ext2_ext_attr_header *header;
5350 struct problem_context pctx;
5351 ext2_filsys fs = ctx->fs;
5352 blk_t blk;
5353 __u32 should_be;
5354 int count;
5355
5356 clear_problem_context(&pctx);
5357
5358 ea_refcount_intr_begin(refcount);
5359 while (1) {
5360 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
5361 break;
5362 pctx.blk = blk;
5363 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5364 if (pctx.errcode) {
5365 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
5366 return;
5367 }
5368 header = (struct ext2_ext_attr_header *) block_buf;
5369 pctx.blkcount = header->h_refcount;
5370 should_be = header->h_refcount + adjust_sign * count;
5371 pctx.num = should_be;
5372 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
5373 header->h_refcount = should_be;
5374 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
5375 block_buf);
5376 if (pctx.errcode) {
5377 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
5378 continue;
5379 }
5380 }
5381 }
5382}
5383
5384/*
5385 * Handle processing the extended attribute blocks
5386 */
5387static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
5388 char *block_buf)
5389{
5390 ext2_filsys fs = ctx->fs;
5391 ext2_ino_t ino = pctx->ino;
5392 struct ext2_inode *inode = pctx->inode;
5393 blk_t blk;
5394 char * end;
5395 struct ext2_ext_attr_header *header;
5396 struct ext2_ext_attr_entry *entry;
5397 int count;
5398 region_t region;
5399
5400 blk = inode->i_file_acl;
5401 if (blk == 0)
5402 return 0;
5403
5404 /*
5405 * If the Extended attribute flag isn't set, then a non-zero
5406 * file acl means that the inode is corrupted.
5407 *
5408 * Or if the extended attribute block is an invalid block,
5409 * then the inode is also corrupted.
5410 */
5411 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
5412 (blk < fs->super->s_first_data_block) ||
5413 (blk >= fs->super->s_blocks_count)) {
5414 mark_inode_bad(ctx, ino);
5415 return 0;
5416 }
5417
5418 /* If ea bitmap hasn't been allocated, create it */
5419 if (!ctx->block_ea_map) {
5420 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
5421 _("ext attr block map"),
5422 &ctx->block_ea_map);
5423 if (pctx->errcode) {
5424 pctx->num = 2;
5425 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
5426 ctx->flags |= E2F_FLAG_ABORT;
5427 return 0;
5428 }
5429 }
5430
5431 /* Create the EA refcount structure if necessary */
5432 if (!ctx->refcount) {
5433 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
5434 if (pctx->errcode) {
5435 pctx->num = 1;
5436 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5437 ctx->flags |= E2F_FLAG_ABORT;
5438 return 0;
5439 }
5440 }
5441
5442#if 0
5443 /* Debugging text */
5444 printf("Inode %u has EA block %u\n", ino, blk);
5445#endif
5446
5447 /* Have we seen this EA block before? */
5448 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
5449 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
5450 return 1;
5451 /* Ooops, this EA was referenced more than it stated */
5452 if (!ctx->refcount_extra) {
5453 pctx->errcode = ea_refcount_create(0,
5454 &ctx->refcount_extra);
5455 if (pctx->errcode) {
5456 pctx->num = 2;
5457 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5458 ctx->flags |= E2F_FLAG_ABORT;
5459 return 0;
5460 }
5461 }
5462 ea_refcount_increment(ctx->refcount_extra, blk, 0);
5463 return 1;
5464 }
5465
5466 /*
5467 * OK, we haven't seen this EA block yet. So we need to
5468 * validate it
5469 */
5470 pctx->blk = blk;
5471 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5472 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
5473 goto clear_extattr;
5474 header = (struct ext2_ext_attr_header *) block_buf;
5475 pctx->blk = inode->i_file_acl;
5476 if (((ctx->ext_attr_ver == 1) &&
5477 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
5478 ((ctx->ext_attr_ver == 2) &&
5479 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
5480 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
5481 goto clear_extattr;
5482 }
5483
5484 if (header->h_blocks != 1) {
5485 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
5486 goto clear_extattr;
5487 }
5488
5489 region = region_create(0, fs->blocksize);
5490 if (!region) {
5491 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
5492 ctx->flags |= E2F_FLAG_ABORT;
5493 return 0;
5494 }
5495 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
5496 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5497 goto clear_extattr;
5498 }
5499
5500 entry = (struct ext2_ext_attr_entry *)(header+1);
5501 end = block_buf + fs->blocksize;
5502 while ((char *)entry < end && *(__u32 *)entry) {
5503 if (region_allocate(region, (char *)entry - (char *)header,
5504 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
5505 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5506 goto clear_extattr;
5507 }
5508 if ((ctx->ext_attr_ver == 1 &&
5509 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
5510 (ctx->ext_attr_ver == 2 &&
5511 entry->e_name_index == 0)) {
5512 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
5513 goto clear_extattr;
5514 }
5515 if (entry->e_value_block != 0) {
5516 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
5517 goto clear_extattr;
5518 }
5519 if (entry->e_value_size &&
5520 region_allocate(region, entry->e_value_offs,
5521 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
5522 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5523 goto clear_extattr;
5524 }
5525 entry = EXT2_EXT_ATTR_NEXT(entry);
5526 }
5527 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
5528 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5529 goto clear_extattr;
5530 }
5531 region_free(region);
5532
5533 count = header->h_refcount - 1;
5534 if (count)
5535 ea_refcount_store(ctx->refcount, blk, count);
5536 mark_block_used(ctx, blk);
5537 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
5538
5539 return 1;
5540
5541clear_extattr:
5542 inode->i_file_acl = 0;
5543 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
5544 return 0;
5545}
5546
5547/* Returns 1 if bad htree, 0 if OK */
5548static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
5549 ext2_ino_t ino EXT2FS_ATTR((unused)),
5550 struct ext2_inode *inode,
5551 char *block_buf)
5552{
5553 struct ext2_dx_root_info *root;
5554 ext2_filsys fs = ctx->fs;
5555 errcode_t retval;
5556 blk_t blk;
5557
5558 if ((!LINUX_S_ISDIR(inode->i_mode) &&
5559 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
5560 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
5561 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
5562 return 1;
5563
5564 blk = inode->i_block[0];
5565 if (((blk == 0) ||
5566 (blk < fs->super->s_first_data_block) ||
5567 (blk >= fs->super->s_blocks_count)) &&
5568 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5569 return 1;
5570
5571 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
5572 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5573 return 1;
5574
5575 /* XXX should check that beginning matches a directory */
5576 root = (struct ext2_dx_root_info *) (block_buf + 24);
5577
5578 if ((root->reserved_zero || root->info_length < 8) &&
5579 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5580 return 1;
5581
5582 pctx->num = root->hash_version;
5583 if ((root->hash_version != EXT2_HASH_LEGACY) &&
5584 (root->hash_version != EXT2_HASH_HALF_MD4) &&
5585 (root->hash_version != EXT2_HASH_TEA) &&
5586 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
5587 return 1;
5588
5589 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
5590 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
5591 return 1;
5592
5593 pctx->num = root->indirect_levels;
5594 if ((root->indirect_levels > 1) &&
5595 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
5596 return 1;
5597
5598 return 0;
5599}
5600
5601/*
5602 * This subroutine is called on each inode to account for all of the
5603 * blocks used by that inode.
5604 */
5605static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
5606 char *block_buf)
5607{
5608 ext2_filsys fs = ctx->fs;
5609 struct process_block_struct_1 pb;
5610 ext2_ino_t ino = pctx->ino;
5611 struct ext2_inode *inode = pctx->inode;
5612 int bad_size = 0;
5613 int dirty_inode = 0;
5614 __u64 size;
5615
5616 pb.ino = ino;
5617 pb.num_blocks = 0;
5618 pb.last_block = -1;
5619 pb.num_illegal_blocks = 0;
5620 pb.suppress = 0; pb.clear = 0;
5621 pb.fragmented = 0;
5622 pb.compressed = 0;
5623 pb.previous_block = 0;
5624 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
5625 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
5626 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
5627 pb.inode = inode;
5628 pb.pctx = pctx;
5629 pb.ctx = ctx;
5630 pctx->ino = ino;
5631 pctx->errcode = 0;
5632
5633 if (inode->i_flags & EXT2_COMPRBLK_FL) {
5634 if (fs->super->s_feature_incompat &
5635 EXT2_FEATURE_INCOMPAT_COMPRESSION)
5636 pb.compressed = 1;
5637 else {
5638 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
5639 inode->i_flags &= ~EXT2_COMPRBLK_FL;
5640 dirty_inode++;
5641 }
5642 }
5643 }
5644
5645 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
5646 pb.num_blocks++;
5647
5648 if (ext2fs_inode_has_valid_blocks(inode))
5649 pctx->errcode = ext2fs_block_iterate2(fs, ino,
5650 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
5651 block_buf, process_block, &pb);
5652 end_problem_latch(ctx, PR_LATCH_BLOCK);
5653 end_problem_latch(ctx, PR_LATCH_TOOBIG);
5654 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5655 goto out;
5656 if (pctx->errcode)
5657 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
5658
5659 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
5660 ctx->fs_fragmented++;
5661
5662 if (pb.clear) {
5663 inode->i_links_count = 0;
5664 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5665 inode->i_dtime = time(0);
5666 dirty_inode++;
5667 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5668 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5669 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5670 /*
5671 * The inode was probably partially accounted for
5672 * before processing was aborted, so we need to
5673 * restart the pass 1 scan.
5674 */
5675 ctx->flags |= E2F_FLAG_RESTART;
5676 goto out;
5677 }
5678
5679 if (inode->i_flags & EXT2_INDEX_FL) {
5680 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
5681 inode->i_flags &= ~EXT2_INDEX_FL;
5682 dirty_inode++;
5683 } else {
5684#ifdef ENABLE_HTREE
5685 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
5686#endif
5687 }
5688 }
5689 if (ctx->dirs_to_hash && pb.is_dir &&
5690 !(inode->i_flags & EXT2_INDEX_FL) &&
5691 ((inode->i_size / fs->blocksize) >= 3))
5692 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
5693
5694 if (!pb.num_blocks && pb.is_dir) {
5695 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
5696 inode->i_links_count = 0;
5697 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5698 inode->i_dtime = time(0);
5699 dirty_inode++;
5700 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5701 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5702 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5703 ctx->fs_directory_count--;
5704 goto out;
5705 }
5706 }
5707
5708 pb.num_blocks *= (fs->blocksize / 512);
5709#if 0
5710 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
5711 ino, inode->i_size, pb.last_block, inode->i_blocks,
5712 pb.num_blocks);
5713#endif
5714 if (pb.is_dir) {
5715 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
5716 if (nblock > (pb.last_block + 1))
5717 bad_size = 1;
5718 else if (nblock < (pb.last_block + 1)) {
5719 if (((pb.last_block + 1) - nblock) >
5720 fs->super->s_prealloc_dir_blocks)
5721 bad_size = 2;
5722 }
5723 } else {
5724 size = EXT2_I_SIZE(inode);
5725 if ((pb.last_block >= 0) &&
5726 (size < (__u64) pb.last_block * fs->blocksize))
5727 bad_size = 3;
5728 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
5729 bad_size = 4;
5730 }
5731 /* i_size for symlinks is checked elsewhere */
5732 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
5733 pctx->num = (pb.last_block+1) * fs->blocksize;
5734 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
5735 inode->i_size = pctx->num;
5736 if (!LINUX_S_ISDIR(inode->i_mode))
5737 inode->i_size_high = pctx->num >> 32;
5738 dirty_inode++;
5739 }
5740 pctx->num = 0;
5741 }
5742 if (LINUX_S_ISREG(inode->i_mode) &&
5743 (inode->i_size_high || inode->i_size & 0x80000000UL))
5744 ctx->large_files++;
5745 if (pb.num_blocks != inode->i_blocks) {
5746 pctx->num = pb.num_blocks;
5747 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
5748 inode->i_blocks = pb.num_blocks;
5749 dirty_inode++;
5750 }
5751 pctx->num = 0;
5752 }
5753out:
5754 if (dirty_inode)
5755 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
5756}
5757
5758#if 0
5759/*
5760 * Helper function called by process block when an illegal block is
5761 * found. It returns a description about why the block is illegal
5762 */
5763static char *describe_illegal_block(ext2_filsys fs, blk_t block)
5764{
5765 blk_t super;
5766 int i;
5767 static char problem[80];
5768
5769 super = fs->super->s_first_data_block;
5770 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
5771 if (block < super) {
5772 sprintf(problem, "< FIRSTBLOCK (%u)", super);
5773 return(problem);
5774 } else if (block >= fs->super->s_blocks_count) {
5775 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
5776 return(problem);
5777 }
5778 for (i = 0; i < fs->group_desc_count; i++) {
5779 if (block == super) {
5780 sprintf(problem, "is the superblock in group %d", i);
5781 break;
5782 }
5783 if (block > super &&
5784 block <= (super + fs->desc_blocks)) {
5785 sprintf(problem, "is in the group descriptors "
5786 "of group %d", i);
5787 break;
5788 }
5789 if (block == fs->group_desc[i].bg_block_bitmap) {
5790 sprintf(problem, "is the block bitmap of group %d", i);
5791 break;
5792 }
5793 if (block == fs->group_desc[i].bg_inode_bitmap) {
5794 sprintf(problem, "is the inode bitmap of group %d", i);
5795 break;
5796 }
5797 if (block >= fs->group_desc[i].bg_inode_table &&
5798 (block < fs->group_desc[i].bg_inode_table
5799 + fs->inode_blocks_per_group)) {
5800 sprintf(problem, "is in the inode table of group %d",
5801 i);
5802 break;
5803 }
5804 super += fs->super->s_blocks_per_group;
5805 }
5806 return(problem);
5807}
5808#endif
5809
5810/*
5811 * This is a helper function for check_blocks().
5812 */
5813static int process_block(ext2_filsys fs,
5814 blk_t *block_nr,
5815 e2_blkcnt_t blockcnt,
5816 blk_t ref_block EXT2FS_ATTR((unused)),
5817 int ref_offset EXT2FS_ATTR((unused)),
5818 void *priv_data)
5819{
5820 struct process_block_struct_1 *p;
5821 struct problem_context *pctx;
5822 blk_t blk = *block_nr;
5823 int ret_code = 0;
5824 int problem = 0;
5825 e2fsck_t ctx;
5826
5827 p = (struct process_block_struct_1 *) priv_data;
5828 pctx = p->pctx;
5829 ctx = p->ctx;
5830
5831 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
5832 /* todo: Check that the comprblk_fl is high, that the
5833 blkaddr pattern looks right (all non-holes up to
5834 first EXT2FS_COMPRESSED_BLKADDR, then all
5835 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
5836 that the feature_incompat bit is high, and that the
5837 inode is a regular file. If we're doing a "full
5838 check" (a concept introduced to e2fsck by e2compr,
5839 meaning that we look at data blocks as well as
5840 metadata) then call some library routine that
5841 checks the compressed data. I'll have to think
5842 about this, because one particularly important
5843 problem to be able to fix is to recalculate the
5844 cluster size if necessary. I think that perhaps
5845 we'd better do most/all e2compr-specific checks
5846 separately, after the non-e2compr checks. If not
5847 doing a full check, it may be useful to test that
5848 the personality is linux; e.g. if it isn't then
5849 perhaps this really is just an illegal block. */
5850 return 0;
5851 }
5852
5853 if (blk == 0) {
5854 if (p->is_dir == 0) {
5855 /*
5856 * Should never happen, since only directories
5857 * get called with BLOCK_FLAG_HOLE
5858 */
5859#if DEBUG_E2FSCK
5860 printf("process_block() called with blk == 0, "
5861 "blockcnt=%d, inode %lu???\n",
5862 blockcnt, p->ino);
5863#endif
5864 return 0;
5865 }
5866 if (blockcnt < 0)
5867 return 0;
5868 if (blockcnt * fs->blocksize < p->inode->i_size) {
5869#if 0
5870 printf("Missing block (#%d) in directory inode %lu!\n",
5871 blockcnt, p->ino);
5872#endif
5873 goto mark_dir;
5874 }
5875 return 0;
5876 }
5877
5878#if 0
5879 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
5880 blockcnt);
5881#endif
5882
5883 /*
5884 * Simplistic fragmentation check. We merely require that the
5885 * file be contiguous. (Which can never be true for really
5886 * big files that are greater than a block group.)
5887 */
5888 if (!HOLE_BLKADDR(p->previous_block)) {
5889 if (p->previous_block+1 != blk)
5890 p->fragmented = 1;
5891 }
5892 p->previous_block = blk;
5893
5894 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
5895 problem = PR_1_TOOBIG_DIR;
5896 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
5897 problem = PR_1_TOOBIG_REG;
5898 if (!p->is_dir && !p->is_reg && blockcnt > 0)
5899 problem = PR_1_TOOBIG_SYMLINK;
5900
5901 if (blk < fs->super->s_first_data_block ||
5902 blk >= fs->super->s_blocks_count)
5903 problem = PR_1_ILLEGAL_BLOCK_NUM;
5904
5905 if (problem) {
5906 p->num_illegal_blocks++;
5907 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
5908 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
5909 p->clear = 1;
5910 return BLOCK_ABORT;
5911 }
5912 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
5913 p->suppress = 1;
5914 set_latch_flags(PR_LATCH_BLOCK,
5915 PRL_SUPPRESS, 0);
5916 }
5917 }
5918 pctx->blk = blk;
5919 pctx->blkcount = blockcnt;
5920 if (fix_problem(ctx, problem, pctx)) {
5921 blk = *block_nr = 0;
5922 ret_code = BLOCK_CHANGED;
5923 goto mark_dir;
5924 } else
5925 return 0;
5926 }
5927
5928 if (p->ino == EXT2_RESIZE_INO) {
5929 /*
5930 * The resize inode has already be sanity checked
5931 * during pass #0 (the superblock checks). All we
5932 * have to do is mark the double indirect block as
5933 * being in use; all of the other blocks are handled
5934 * by mark_table_blocks()).
5935 */
5936 if (blockcnt == BLOCK_COUNT_DIND)
5937 mark_block_used(ctx, blk);
5938 } else
5939 mark_block_used(ctx, blk);
5940 p->num_blocks++;
5941 if (blockcnt >= 0)
5942 p->last_block = blockcnt;
5943mark_dir:
5944 if (p->is_dir && (blockcnt >= 0)) {
5945 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
5946 blk, blockcnt);
5947 if (pctx->errcode) {
5948 pctx->blk = blk;
5949 pctx->num = blockcnt;
5950 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
5951 /* Should never get here */
5952 ctx->flags |= E2F_FLAG_ABORT;
5953 return BLOCK_ABORT;
5954 }
5955 }
5956 return ret_code;
5957}
5958
5959static int process_bad_block(ext2_filsys fs,
5960 blk_t *block_nr,
5961 e2_blkcnt_t blockcnt,
5962 blk_t ref_block EXT2FS_ATTR((unused)),
5963 int ref_offset EXT2FS_ATTR((unused)),
5964 void *priv_data)
5965{
5966 struct process_block_struct_1 *p;
5967 blk_t blk = *block_nr;
5968 blk_t first_block;
5969 dgrp_t i;
5970 struct problem_context *pctx;
5971 e2fsck_t ctx;
5972
5973 /*
5974 * Note: This function processes blocks for the bad blocks
5975 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
5976 */
5977
5978 if (!blk)
5979 return 0;
5980
5981 p = (struct process_block_struct_1 *) priv_data;
5982 ctx = p->ctx;
5983 pctx = p->pctx;
5984
5985 pctx->ino = EXT2_BAD_INO;
5986 pctx->blk = blk;
5987 pctx->blkcount = blockcnt;
5988
5989 if ((blk < fs->super->s_first_data_block) ||
5990 (blk >= fs->super->s_blocks_count)) {
5991 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
5992 *block_nr = 0;
5993 return BLOCK_CHANGED;
5994 } else
5995 return 0;
5996 }
5997
5998 if (blockcnt < 0) {
5999 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
6000 p->bbcheck = 1;
6001 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
6002 *block_nr = 0;
6003 return BLOCK_CHANGED;
6004 }
6005 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
6006 blk)) {
6007 p->bbcheck = 1;
6008 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
6009 pctx)) {
6010 *block_nr = 0;
6011 return BLOCK_CHANGED;
6012 }
6013 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6014 return BLOCK_ABORT;
6015 } else
6016 mark_block_used(ctx, blk);
6017 return 0;
6018 }
6019#if 0
6020 printf ("DEBUG: Marking %u as bad.\n", blk);
6021#endif
6022 ctx->fs_badblocks_count++;
6023 /*
6024 * If the block is not used, then mark it as used and return.
6025 * If it is already marked as found, this must mean that
6026 * there's an overlap between the filesystem table blocks
6027 * (bitmaps and inode table) and the bad block list.
6028 */
6029 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
6030 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6031 return 0;
6032 }
6033 /*
6034 * Try to find the where the filesystem block was used...
6035 */
6036 first_block = fs->super->s_first_data_block;
6037
6038 for (i = 0; i < fs->group_desc_count; i++ ) {
6039 pctx->group = i;
6040 pctx->blk = blk;
6041 if (!ext2fs_bg_has_super(fs, i))
6042 goto skip_super;
6043 if (blk == first_block) {
6044 if (i == 0) {
6045 if (fix_problem(ctx,
6046 PR_1_BAD_PRIMARY_SUPERBLOCK,
6047 pctx)) {
6048 *block_nr = 0;
6049 return BLOCK_CHANGED;
6050 }
6051 return 0;
6052 }
6053 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
6054 return 0;
6055 }
6056 if ((blk > first_block) &&
6057 (blk <= first_block + fs->desc_blocks)) {
6058 if (i == 0) {
6059 pctx->blk = *block_nr;
6060 if (fix_problem(ctx,
6061 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
6062 *block_nr = 0;
6063 return BLOCK_CHANGED;
6064 }
6065 return 0;
6066 }
6067 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
6068 return 0;
6069 }
6070 skip_super:
6071 if (blk == fs->group_desc[i].bg_block_bitmap) {
6072 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
6073 ctx->invalid_block_bitmap_flag[i]++;
6074 ctx->invalid_bitmaps++;
6075 }
6076 return 0;
6077 }
6078 if (blk == fs->group_desc[i].bg_inode_bitmap) {
6079 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
6080 ctx->invalid_inode_bitmap_flag[i]++;
6081 ctx->invalid_bitmaps++;
6082 }
6083 return 0;
6084 }
6085 if ((blk >= fs->group_desc[i].bg_inode_table) &&
6086 (blk < (fs->group_desc[i].bg_inode_table +
6087 fs->inode_blocks_per_group))) {
6088 /*
6089 * If there are bad blocks in the inode table,
6090 * the inode scan code will try to do
6091 * something reasonable automatically.
6092 */
6093 return 0;
6094 }
6095 first_block += fs->super->s_blocks_per_group;
6096 }
6097 /*
6098 * If we've gotten to this point, then the only
6099 * possibility is that the bad block inode meta data
6100 * is using a bad block.
6101 */
6102 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
6103 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
6104 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
6105 p->bbcheck = 1;
6106 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
6107 *block_nr = 0;
6108 return BLOCK_CHANGED;
6109 }
6110 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6111 return BLOCK_ABORT;
6112 return 0;
6113 }
6114
6115 pctx->group = -1;
6116
6117 /* Warn user that the block wasn't claimed */
6118 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
6119
6120 return 0;
6121}
6122
6123static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
6124 const char *name, int num, blk_t *new_block)
6125{
6126 ext2_filsys fs = ctx->fs;
6127 blk_t old_block = *new_block;
6128 int i;
6129 char *buf;
6130 struct problem_context pctx;
6131
6132 clear_problem_context(&pctx);
6133
6134 pctx.group = group;
6135 pctx.blk = old_block;
6136 pctx.str = name;
6137
6138 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
6139 first_block + fs->super->s_blocks_per_group,
6140 num, ctx->block_found_map, new_block);
6141 if (pctx.errcode) {
6142 pctx.num = num;
6143 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
6144 ext2fs_unmark_valid(fs);
6145 return;
6146 }
6147 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
6148 if (pctx.errcode) {
6149 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
6150 ext2fs_unmark_valid(fs);
6151 return;
6152 }
6153 ext2fs_mark_super_dirty(fs);
6154 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
6155 pctx.blk2 = *new_block;
6156 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
6157 PR_1_RELOC_TO), &pctx);
6158 pctx.blk2 = 0;
6159 for (i = 0; i < num; i++) {
6160 pctx.blk = i;
6161 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
6162 if (old_block) {
6163 pctx.errcode = io_channel_read_blk(fs->io,
6164 old_block + i, 1, buf);
6165 if (pctx.errcode)
6166 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
6167 } else
6168 memset(buf, 0, fs->blocksize);
6169
6170 pctx.blk = (*new_block) + i;
6171 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
6172 1, buf);
6173 if (pctx.errcode)
6174 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
6175 }
6176 ext2fs_free_mem(&buf);
6177}
6178
6179/*
6180 * This routine gets called at the end of pass 1 if bad blocks are
6181 * detected in the superblock, group descriptors, inode_bitmaps, or
6182 * block bitmaps. At this point, all of the blocks have been mapped
6183 * out, so we can try to allocate new block(s) to replace the bad
6184 * blocks.
6185 */
6186static void handle_fs_bad_blocks(e2fsck_t ctx)
6187{
6188 ext2_filsys fs = ctx->fs;
6189 dgrp_t i;
6190 int first_block = fs->super->s_first_data_block;
6191
6192 for (i = 0; i < fs->group_desc_count; i++) {
6193 if (ctx->invalid_block_bitmap_flag[i]) {
6194 new_table_block(ctx, first_block, i, _("block bitmap"),
6195 1, &fs->group_desc[i].bg_block_bitmap);
6196 }
6197 if (ctx->invalid_inode_bitmap_flag[i]) {
6198 new_table_block(ctx, first_block, i, _("inode bitmap"),
6199 1, &fs->group_desc[i].bg_inode_bitmap);
6200 }
6201 if (ctx->invalid_inode_table_flag[i]) {
6202 new_table_block(ctx, first_block, i, _("inode table"),
6203 fs->inode_blocks_per_group,
6204 &fs->group_desc[i].bg_inode_table);
6205 ctx->flags |= E2F_FLAG_RESTART;
6206 }
6207 first_block += fs->super->s_blocks_per_group;
6208 }
6209 ctx->invalid_bitmaps = 0;
6210}
6211
6212/*
6213 * This routine marks all blocks which are used by the superblock,
6214 * group descriptors, inode bitmaps, and block bitmaps.
6215 */
6216static void mark_table_blocks(e2fsck_t ctx)
6217{
6218 ext2_filsys fs = ctx->fs;
6219 blk_t block, b;
6220 dgrp_t i;
6221 int j;
6222 struct problem_context pctx;
6223
6224 clear_problem_context(&pctx);
6225
6226 block = fs->super->s_first_data_block;
6227 for (i = 0; i < fs->group_desc_count; i++) {
6228 pctx.group = i;
6229
6230 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
6231
6232 /*
6233 * Mark the blocks used for the inode table
6234 */
6235 if (fs->group_desc[i].bg_inode_table) {
6236 for (j = 0, b = fs->group_desc[i].bg_inode_table;
6237 j < fs->inode_blocks_per_group;
6238 j++, b++) {
6239 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6240 b)) {
6241 pctx.blk = b;
6242 if (fix_problem(ctx,
6243 PR_1_ITABLE_CONFLICT, &pctx)) {
6244 ctx->invalid_inode_table_flag[i]++;
6245 ctx->invalid_bitmaps++;
6246 }
6247 } else {
6248 ext2fs_mark_block_bitmap(ctx->block_found_map,
6249 b);
6250 }
6251 }
6252 }
6253
6254 /*
6255 * Mark block used for the block bitmap
6256 */
6257 if (fs->group_desc[i].bg_block_bitmap) {
6258 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6259 fs->group_desc[i].bg_block_bitmap)) {
6260 pctx.blk = fs->group_desc[i].bg_block_bitmap;
6261 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
6262 ctx->invalid_block_bitmap_flag[i]++;
6263 ctx->invalid_bitmaps++;
6264 }
6265 } else {
6266 ext2fs_mark_block_bitmap(ctx->block_found_map,
6267 fs->group_desc[i].bg_block_bitmap);
6268 }
6269
6270 }
6271 /*
6272 * Mark block used for the inode bitmap
6273 */
6274 if (fs->group_desc[i].bg_inode_bitmap) {
6275 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6276 fs->group_desc[i].bg_inode_bitmap)) {
6277 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
6278 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
6279 ctx->invalid_inode_bitmap_flag[i]++;
6280 ctx->invalid_bitmaps++;
6281 }
6282 } else {
6283 ext2fs_mark_block_bitmap(ctx->block_found_map,
6284 fs->group_desc[i].bg_inode_bitmap);
6285 }
6286 }
6287 block += fs->super->s_blocks_per_group;
6288 }
6289}
6290
6291/*
6292 * Thes subroutines short circuits ext2fs_get_blocks and
6293 * ext2fs_check_directory; we use them since we already have the inode
6294 * structure, so there's no point in letting the ext2fs library read
6295 * the inode again.
6296 */
6297static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
6298 blk_t *blocks)
6299{
6300 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6301 int i;
6302
6303 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6304 return EXT2_ET_CALLBACK_NOTHANDLED;
6305
6306 for (i=0; i < EXT2_N_BLOCKS; i++)
6307 blocks[i] = ctx->stashed_inode->i_block[i];
6308 return 0;
6309}
6310
6311static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
6312 struct ext2_inode *inode)
6313{
6314 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6315
6316 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6317 return EXT2_ET_CALLBACK_NOTHANDLED;
6318 *inode = *ctx->stashed_inode;
6319 return 0;
6320}
6321
6322static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
6323 struct ext2_inode *inode)
6324{
6325 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6326
6327 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
6328 *ctx->stashed_inode = *inode;
6329 return EXT2_ET_CALLBACK_NOTHANDLED;
6330}
6331
6332static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
6333{
6334 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6335
6336 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6337 return EXT2_ET_CALLBACK_NOTHANDLED;
6338
6339 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
6340 return EXT2_ET_NO_DIRECTORY;
6341 return 0;
6342}
6343
6344void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
6345{
6346 ext2_filsys fs = ctx->fs;
6347
6348 if (bool) {
6349 fs->get_blocks = pass1_get_blocks;
6350 fs->check_directory = pass1_check_directory;
6351 fs->read_inode = pass1_read_inode;
6352 fs->write_inode = pass1_write_inode;
6353 ctx->stashed_ino = 0;
6354 } else {
6355 fs->get_blocks = 0;
6356 fs->check_directory = 0;
6357 fs->read_inode = 0;
6358 fs->write_inode = 0;
6359 }
6360}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006361
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006362/*
6363 * pass1b.c --- Pass #1b of e2fsck
6364 *
6365 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
6366 * only invoked if pass 1 discovered blocks which are in use by more
6367 * than one inode.
6368 *
6369 * Pass1B scans the data blocks of all the inodes again, generating a
6370 * complete list of duplicate blocks and which inodes have claimed
6371 * them.
6372 *
6373 * Pass1C does a tree-traversal of the filesystem, to determine the
6374 * parent directories of these inodes. This step is necessary so that
6375 * e2fsck can print out the pathnames of affected inodes.
6376 *
6377 * Pass1D is a reconciliation pass. For each inode with duplicate
6378 * blocks, the user is prompted if s/he would like to clone the file
6379 * (so that the file gets a fresh copy of the duplicated blocks) or
6380 * simply to delete the file.
6381 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006382 */
6383
6384
6385/* Needed for architectures where sizeof(int) != sizeof(void *) */
6386#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
6387#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
6388
6389/* Define an extension to the ext2 library's block count information */
6390#define BLOCK_COUNT_EXTATTR (-5)
6391
6392struct block_el {
6393 blk_t block;
6394 struct block_el *next;
6395};
6396
6397struct inode_el {
6398 ext2_ino_t inode;
6399 struct inode_el *next;
6400};
6401
6402struct dup_block {
6403 int num_bad;
6404 struct inode_el *inode_list;
6405};
6406
6407/*
6408 * This structure stores information about a particular inode which
6409 * is sharing blocks with other inodes. This information is collected
6410 * to display to the user, so that the user knows what files he or she
6411 * is dealing with, when trying to decide how to resolve the conflict
6412 * of multiply-claimed blocks.
6413 */
6414struct dup_inode {
6415 ext2_ino_t dir;
6416 int num_dupblocks;
6417 struct ext2_inode inode;
6418 struct block_el *block_list;
6419};
6420
6421static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
6422 e2_blkcnt_t blockcnt, blk_t ref_blk,
6423 int ref_offset, void *priv_data);
6424static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6425 struct dup_inode *dp, char *block_buf);
6426static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6427 struct dup_inode *dp, char* block_buf);
6428static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
6429
6430static void pass1b(e2fsck_t ctx, char *block_buf);
6431static void pass1c(e2fsck_t ctx, char *block_buf);
6432static void pass1d(e2fsck_t ctx, char *block_buf);
6433
6434static int dup_inode_count = 0;
6435
6436static dict_t blk_dict, ino_dict;
6437
6438static ext2fs_inode_bitmap inode_dup_map;
6439
6440static int dict_int_cmp(const void *a, const void *b)
6441{
6442 intptr_t ia, ib;
6443
6444 ia = (intptr_t)a;
6445 ib = (intptr_t)b;
6446
6447 return (ia-ib);
6448}
6449
6450/*
6451 * Add a duplicate block record
6452 */
6453static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
6454 struct ext2_inode *inode)
6455{
6456 dnode_t *n;
6457 struct dup_block *db;
6458 struct dup_inode *di;
6459 struct block_el *blk_el;
6460 struct inode_el *ino_el;
6461
6462 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
6463 if (n)
6464 db = (struct dup_block *) dnode_get(n);
6465 else {
6466 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
6467 sizeof(struct dup_block), "duplicate block header");
6468 db->num_bad = 0;
6469 db->inode_list = 0;
6470 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
6471 }
6472 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
6473 sizeof(struct inode_el), "inode element");
6474 ino_el->inode = ino;
6475 ino_el->next = db->inode_list;
6476 db->inode_list = ino_el;
6477 db->num_bad++;
6478
6479 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
6480 if (n)
6481 di = (struct dup_inode *) dnode_get(n);
6482 else {
6483 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
6484 sizeof(struct dup_inode), "duplicate inode header");
6485 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
6486 di->num_dupblocks = 0;
6487 di->block_list = 0;
6488 di->inode = *inode;
6489 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
6490 }
6491 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
6492 sizeof(struct block_el), "block element");
6493 blk_el->block = blk;
6494 blk_el->next = di->block_list;
6495 di->block_list = blk_el;
6496 di->num_dupblocks++;
6497}
6498
6499/*
6500 * Free a duplicate inode record
6501 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006502static void inode_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006503{
6504 struct dup_inode *di;
6505 struct block_el *p, *next;
6506
6507 di = (struct dup_inode *) dnode_get(node);
6508 for (p = di->block_list; p; p = next) {
6509 next = p->next;
6510 free(p);
6511 }
6512 free(node);
6513}
6514
6515/*
6516 * Free a duplicate block record
6517 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006518static void block_dnode_free(dnode_t *node)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006519{
6520 struct dup_block *db;
6521 struct inode_el *p, *next;
6522
6523 db = (struct dup_block *) dnode_get(node);
6524 for (p = db->inode_list; p; p = next) {
6525 next = p->next;
6526 free(p);
6527 }
6528 free(node);
6529}
6530
6531
6532/*
6533 * Main procedure for handling duplicate blocks
6534 */
6535void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
6536{
6537 ext2_filsys fs = ctx->fs;
6538 struct problem_context pctx;
6539
6540 clear_problem_context(&pctx);
6541
6542 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
6543 _("multiply claimed inode map"), &inode_dup_map);
6544 if (pctx.errcode) {
6545 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
6546 ctx->flags |= E2F_FLAG_ABORT;
6547 return;
6548 }
6549
6550 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
6551 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00006552 dict_set_allocator(&ino_dict, inode_dnode_free);
6553 dict_set_allocator(&blk_dict, block_dnode_free);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00006554
6555 pass1b(ctx, block_buf);
6556 pass1c(ctx, block_buf);
6557 pass1d(ctx, block_buf);
6558
6559 /*
6560 * Time to free all of the accumulated data structures that we
6561 * don't need anymore.
6562 */
6563 dict_free_nodes(&ino_dict);
6564 dict_free_nodes(&blk_dict);
6565}
6566
6567/*
6568 * Scan the inodes looking for inodes that contain duplicate blocks.
6569 */
6570struct process_block_struct_1b {
6571 e2fsck_t ctx;
6572 ext2_ino_t ino;
6573 int dup_blocks;
6574 struct ext2_inode *inode;
6575 struct problem_context *pctx;
6576};
6577
6578static void pass1b(e2fsck_t ctx, char *block_buf)
6579{
6580 ext2_filsys fs = ctx->fs;
6581 ext2_ino_t ino;
6582 struct ext2_inode inode;
6583 ext2_inode_scan scan;
6584 struct process_block_struct_1b pb;
6585 struct problem_context pctx;
6586
6587 clear_problem_context(&pctx);
6588
6589 if (!(ctx->options & E2F_OPT_PREEN))
6590 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
6591 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
6592 &scan);
6593 if (pctx.errcode) {
6594 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6595 ctx->flags |= E2F_FLAG_ABORT;
6596 return;
6597 }
6598 ctx->stashed_inode = &inode;
6599 pb.ctx = ctx;
6600 pb.pctx = &pctx;
6601 pctx.str = "pass1b";
6602 while (1) {
6603 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
6604 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
6605 continue;
6606 if (pctx.errcode) {
6607 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6608 ctx->flags |= E2F_FLAG_ABORT;
6609 return;
6610 }
6611 if (!ino)
6612 break;
6613 pctx.ino = ctx->stashed_ino = ino;
6614 if ((ino != EXT2_BAD_INO) &&
6615 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
6616 continue;
6617
6618 pb.ino = ino;
6619 pb.dup_blocks = 0;
6620 pb.inode = &inode;
6621
6622 if (ext2fs_inode_has_valid_blocks(&inode) ||
6623 (ino == EXT2_BAD_INO))
6624 pctx.errcode = ext2fs_block_iterate2(fs, ino,
6625 0, block_buf, process_pass1b_block, &pb);
6626 if (inode.i_file_acl)
6627 process_pass1b_block(fs, &inode.i_file_acl,
6628 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6629 if (pb.dup_blocks) {
6630 end_problem_latch(ctx, PR_LATCH_DBLOCK);
6631 if (ino >= EXT2_FIRST_INODE(fs->super) ||
6632 ino == EXT2_ROOT_INO)
6633 dup_inode_count++;
6634 }
6635 if (pctx.errcode)
6636 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6637 }
6638 ext2fs_close_inode_scan(scan);
6639 e2fsck_use_inode_shortcuts(ctx, 0);
6640}
6641
6642static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
6643 blk_t *block_nr,
6644 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
6645 blk_t ref_blk EXT2FS_ATTR((unused)),
6646 int ref_offset EXT2FS_ATTR((unused)),
6647 void *priv_data)
6648{
6649 struct process_block_struct_1b *p;
6650 e2fsck_t ctx;
6651
6652 if (HOLE_BLKADDR(*block_nr))
6653 return 0;
6654 p = (struct process_block_struct_1b *) priv_data;
6655 ctx = p->ctx;
6656
6657 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
6658 return 0;
6659
6660 /* OK, this is a duplicate block */
6661 if (p->ino != EXT2_BAD_INO) {
6662 p->pctx->blk = *block_nr;
6663 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
6664 }
6665 p->dup_blocks++;
6666 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
6667
6668 add_dupe(ctx, p->ino, *block_nr, p->inode);
6669
6670 return 0;
6671}
6672
6673/*
6674 * Pass 1c: Scan directories for inodes with duplicate blocks. This
6675 * is used so that we can print pathnames when prompting the user for
6676 * what to do.
6677 */
6678struct search_dir_struct {
6679 int count;
6680 ext2_ino_t first_inode;
6681 ext2_ino_t max_inode;
6682};
6683
6684static int search_dirent_proc(ext2_ino_t dir, int entry,
6685 struct ext2_dir_entry *dirent,
6686 int offset EXT2FS_ATTR((unused)),
6687 int blocksize EXT2FS_ATTR((unused)),
6688 char *buf EXT2FS_ATTR((unused)),
6689 void *priv_data)
6690{
6691 struct search_dir_struct *sd;
6692 struct dup_inode *p;
6693 dnode_t *n;
6694
6695 sd = (struct search_dir_struct *) priv_data;
6696
6697 if (dirent->inode > sd->max_inode)
6698 /* Should abort this inode, but not everything */
6699 return 0;
6700
6701 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
6702 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
6703 return 0;
6704
6705 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
6706 if (!n)
6707 return 0;
6708 p = (struct dup_inode *) dnode_get(n);
6709 p->dir = dir;
6710 sd->count--;
6711
6712 return(sd->count ? 0 : DIRENT_ABORT);
6713}
6714
6715
6716static void pass1c(e2fsck_t ctx, char *block_buf)
6717{
6718 ext2_filsys fs = ctx->fs;
6719 struct search_dir_struct sd;
6720 struct problem_context pctx;
6721
6722 clear_problem_context(&pctx);
6723
6724 if (!(ctx->options & E2F_OPT_PREEN))
6725 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
6726
6727 /*
6728 * Search through all directories to translate inodes to names
6729 * (by searching for the containing directory for that inode.)
6730 */
6731 sd.count = dup_inode_count;
6732 sd.first_inode = EXT2_FIRST_INODE(fs->super);
6733 sd.max_inode = fs->super->s_inodes_count;
6734 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
6735 search_dirent_proc, &sd);
6736}
6737
6738static void pass1d(e2fsck_t ctx, char *block_buf)
6739{
6740 ext2_filsys fs = ctx->fs;
6741 struct dup_inode *p, *t;
6742 struct dup_block *q;
6743 ext2_ino_t *shared, ino;
6744 int shared_len;
6745 int i;
6746 int file_ok;
6747 int meta_data = 0;
6748 struct problem_context pctx;
6749 dnode_t *n, *m;
6750 struct block_el *s;
6751 struct inode_el *r;
6752
6753 clear_problem_context(&pctx);
6754
6755 if (!(ctx->options & E2F_OPT_PREEN))
6756 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
6757 e2fsck_read_bitmaps(ctx);
6758
6759 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
6760 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
6761 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
6762 sizeof(ext2_ino_t) * dict_count(&ino_dict),
6763 "Shared inode list");
6764 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
6765 p = (struct dup_inode *) dnode_get(n);
6766 shared_len = 0;
6767 file_ok = 1;
6768 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
6769 if (ino == EXT2_BAD_INO)
6770 continue;
6771
6772 /*
6773 * Find all of the inodes which share blocks with this
6774 * one. First we find all of the duplicate blocks
6775 * belonging to this inode, and then search each block
6776 * get the list of inodes, and merge them together.
6777 */
6778 for (s = p->block_list; s; s = s->next) {
6779 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
6780 if (!m)
6781 continue; /* Should never happen... */
6782 q = (struct dup_block *) dnode_get(m);
6783 if (q->num_bad > 1)
6784 file_ok = 0;
6785 if (check_if_fs_block(ctx, s->block)) {
6786 file_ok = 0;
6787 meta_data = 1;
6788 }
6789
6790 /*
6791 * Add all inodes used by this block to the
6792 * shared[] --- which is a unique list, so
6793 * if an inode is already in shared[], don't
6794 * add it again.
6795 */
6796 for (r = q->inode_list; r; r = r->next) {
6797 if (r->inode == ino)
6798 continue;
6799 for (i = 0; i < shared_len; i++)
6800 if (shared[i] == r->inode)
6801 break;
6802 if (i == shared_len) {
6803 shared[shared_len++] = r->inode;
6804 }
6805 }
6806 }
6807
6808 /*
6809 * Report the inode that we are working on
6810 */
6811 pctx.inode = &p->inode;
6812 pctx.ino = ino;
6813 pctx.dir = p->dir;
6814 pctx.blkcount = p->num_dupblocks;
6815 pctx.num = meta_data ? shared_len+1 : shared_len;
6816 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
6817 pctx.blkcount = 0;
6818 pctx.num = 0;
6819
6820 if (meta_data)
6821 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
6822
6823 for (i = 0; i < shared_len; i++) {
6824 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
6825 if (!m)
6826 continue; /* should never happen */
6827 t = (struct dup_inode *) dnode_get(m);
6828 /*
6829 * Report the inode that we are sharing with
6830 */
6831 pctx.inode = &t->inode;
6832 pctx.ino = shared[i];
6833 pctx.dir = t->dir;
6834 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
6835 }
6836 if (file_ok) {
6837 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
6838 continue;
6839 }
6840 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
6841 pctx.errcode = clone_file(ctx, ino, p, block_buf);
6842 if (pctx.errcode)
6843 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
6844 else
6845 continue;
6846 }
6847 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
6848 delete_file(ctx, ino, p, block_buf);
6849 else
6850 ext2fs_unmark_valid(fs);
6851 }
6852 ext2fs_free_mem(&shared);
6853}
6854
6855/*
6856 * Drop the refcount on the dup_block structure, and clear the entry
6857 * in the block_dup_map if appropriate.
6858 */
6859static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
6860{
6861 p->num_bad--;
6862 if (p->num_bad <= 0 ||
6863 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
6864 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
6865}
6866
6867static int delete_file_block(ext2_filsys fs,
6868 blk_t *block_nr,
6869 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
6870 blk_t ref_block EXT2FS_ATTR((unused)),
6871 int ref_offset EXT2FS_ATTR((unused)),
6872 void *priv_data)
6873{
6874 struct process_block_struct_1b *pb;
6875 struct dup_block *p;
6876 dnode_t *n;
6877 e2fsck_t ctx;
6878
6879 pb = (struct process_block_struct_1b *) priv_data;
6880 ctx = pb->ctx;
6881
6882 if (HOLE_BLKADDR(*block_nr))
6883 return 0;
6884
6885 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6886 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6887 if (n) {
6888 p = (struct dup_block *) dnode_get(n);
6889 decrement_badcount(ctx, *block_nr, p);
6890 } else
6891 com_err("delete_file_block", 0,
6892 _("internal error; can't find dup_blk for %d\n"),
6893 *block_nr);
6894 } else {
6895 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
6896 ext2fs_block_alloc_stats(fs, *block_nr, -1);
6897 }
6898
6899 return 0;
6900}
6901
6902static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6903 struct dup_inode *dp, char* block_buf)
6904{
6905 ext2_filsys fs = ctx->fs;
6906 struct process_block_struct_1b pb;
6907 struct ext2_inode inode;
6908 struct problem_context pctx;
6909 unsigned int count;
6910
6911 clear_problem_context(&pctx);
6912 pctx.ino = pb.ino = ino;
6913 pb.dup_blocks = dp->num_dupblocks;
6914 pb.ctx = ctx;
6915 pctx.str = "delete_file";
6916
6917 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6918 if (ext2fs_inode_has_valid_blocks(&inode))
6919 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
6920 delete_file_block, &pb);
6921 if (pctx.errcode)
6922 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6923 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
6924 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
6925 if (ctx->inode_bad_map)
6926 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
6927 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
6928
6929 /* Inode may have changed by block_iterate, so reread it */
6930 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
6931 inode.i_links_count = 0;
6932 inode.i_dtime = time(0);
6933 if (inode.i_file_acl &&
6934 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
6935 count = 1;
6936 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
6937 block_buf, -1, &count);
6938 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
6939 pctx.errcode = 0;
6940 count = 1;
6941 }
6942 if (pctx.errcode) {
6943 pctx.blk = inode.i_file_acl;
6944 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
6945 }
6946 /*
6947 * If the count is zero, then arrange to have the
6948 * block deleted. If the block is in the block_dup_map,
6949 * also call delete_file_block since it will take care
6950 * of keeping the accounting straight.
6951 */
6952 if ((count == 0) ||
6953 ext2fs_test_block_bitmap(ctx->block_dup_map,
6954 inode.i_file_acl))
6955 delete_file_block(fs, &inode.i_file_acl,
6956 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6957 }
6958 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
6959}
6960
6961struct clone_struct {
6962 errcode_t errcode;
6963 ext2_ino_t dir;
6964 char *buf;
6965 e2fsck_t ctx;
6966};
6967
6968static int clone_file_block(ext2_filsys fs,
6969 blk_t *block_nr,
6970 e2_blkcnt_t blockcnt,
6971 blk_t ref_block EXT2FS_ATTR((unused)),
6972 int ref_offset EXT2FS_ATTR((unused)),
6973 void *priv_data)
6974{
6975 struct dup_block *p;
6976 blk_t new_block;
6977 errcode_t retval;
6978 struct clone_struct *cs = (struct clone_struct *) priv_data;
6979 dnode_t *n;
6980 e2fsck_t ctx;
6981
6982 ctx = cs->ctx;
6983
6984 if (HOLE_BLKADDR(*block_nr))
6985 return 0;
6986
6987 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
6988 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
6989 if (n) {
6990 p = (struct dup_block *) dnode_get(n);
6991 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
6992 &new_block);
6993 if (retval) {
6994 cs->errcode = retval;
6995 return BLOCK_ABORT;
6996 }
6997 if (cs->dir && (blockcnt >= 0)) {
6998 retval = ext2fs_set_dir_block(fs->dblist,
6999 cs->dir, new_block, blockcnt);
7000 if (retval) {
7001 cs->errcode = retval;
7002 return BLOCK_ABORT;
7003 }
7004 }
7005#if 0
7006 printf("Cloning block %u to %u\n", *block_nr,
7007 new_block);
7008#endif
7009 retval = io_channel_read_blk(fs->io, *block_nr, 1,
7010 cs->buf);
7011 if (retval) {
7012 cs->errcode = retval;
7013 return BLOCK_ABORT;
7014 }
7015 retval = io_channel_write_blk(fs->io, new_block, 1,
7016 cs->buf);
7017 if (retval) {
7018 cs->errcode = retval;
7019 return BLOCK_ABORT;
7020 }
7021 decrement_badcount(ctx, *block_nr, p);
7022 *block_nr = new_block;
7023 ext2fs_mark_block_bitmap(ctx->block_found_map,
7024 new_block);
7025 ext2fs_mark_block_bitmap(fs->block_map, new_block);
7026 return BLOCK_CHANGED;
7027 } else
7028 com_err("clone_file_block", 0,
7029 _("internal error; can't find dup_blk for %d\n"),
7030 *block_nr);
7031 }
7032 return 0;
7033}
7034
7035static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
7036 struct dup_inode *dp, char* block_buf)
7037{
7038 ext2_filsys fs = ctx->fs;
7039 errcode_t retval;
7040 struct clone_struct cs;
7041 struct problem_context pctx;
7042 blk_t blk;
7043 dnode_t *n;
7044 struct inode_el *ino_el;
7045 struct dup_block *db;
7046 struct dup_inode *di;
7047
7048 clear_problem_context(&pctx);
7049 cs.errcode = 0;
7050 cs.dir = 0;
7051 cs.ctx = ctx;
7052 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
7053 if (retval)
7054 return retval;
7055
7056 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
7057 cs.dir = ino;
7058
7059 pctx.ino = ino;
7060 pctx.str = "clone_file";
7061 if (ext2fs_inode_has_valid_blocks(&dp->inode))
7062 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
7063 clone_file_block, &cs);
7064 ext2fs_mark_bb_dirty(fs);
7065 if (pctx.errcode) {
7066 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
7067 retval = pctx.errcode;
7068 goto errout;
7069 }
7070 if (cs.errcode) {
7071 com_err("clone_file", cs.errcode,
7072 _("returned from clone_file_block"));
7073 retval = cs.errcode;
7074 goto errout;
7075 }
7076 /* The inode may have changed on disk, so we have to re-read it */
7077 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
7078 blk = dp->inode.i_file_acl;
7079 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
7080 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
7081 BLOCK_CHANGED)) {
7082 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
7083 /*
7084 * If we cloned the EA block, find all other inodes
7085 * which refered to that EA block, and modify
7086 * them to point to the new EA block.
7087 */
7088 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
7089 db = (struct dup_block *) dnode_get(n);
7090 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
7091 if (ino_el->inode == ino)
7092 continue;
7093 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
7094 di = (struct dup_inode *) dnode_get(n);
7095 if (di->inode.i_file_acl == blk) {
7096 di->inode.i_file_acl = dp->inode.i_file_acl;
7097 e2fsck_write_inode(ctx, ino_el->inode,
7098 &di->inode, "clone file EA");
7099 decrement_badcount(ctx, blk, db);
7100 }
7101 }
7102 }
7103 retval = 0;
7104errout:
7105 ext2fs_free_mem(&cs.buf);
7106 return retval;
7107}
7108
7109/*
7110 * This routine returns 1 if a block overlaps with one of the superblocks,
7111 * group descriptors, inode bitmaps, or block bitmaps.
7112 */
7113static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
7114{
7115 ext2_filsys fs = ctx->fs;
7116 blk_t block;
7117 dgrp_t i;
7118
7119 block = fs->super->s_first_data_block;
7120 for (i = 0; i < fs->group_desc_count; i++) {
7121
7122 /* Check superblocks/block group descriptros */
7123 if (ext2fs_bg_has_super(fs, i)) {
7124 if (test_block >= block &&
7125 (test_block <= block + fs->desc_blocks))
7126 return 1;
7127 }
7128
7129 /* Check the inode table */
7130 if ((fs->group_desc[i].bg_inode_table) &&
7131 (test_block >= fs->group_desc[i].bg_inode_table) &&
7132 (test_block < (fs->group_desc[i].bg_inode_table +
7133 fs->inode_blocks_per_group)))
7134 return 1;
7135
7136 /* Check the bitmap blocks */
7137 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
7138 (test_block == fs->group_desc[i].bg_inode_bitmap))
7139 return 1;
7140
7141 block += fs->super->s_blocks_per_group;
7142 }
7143 return 0;
7144}
7145/*
7146 * pass2.c --- check directory structure
7147 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007148 * Pass 2 of e2fsck iterates through all active directory inodes, and
7149 * applies to following tests to each directory entry in the directory
7150 * blocks in the inodes:
7151 *
7152 * - The length of the directory entry (rec_len) should be at
7153 * least 8 bytes, and no more than the remaining space
7154 * left in the directory block.
7155 * - The length of the name in the directory entry (name_len)
7156 * should be less than (rec_len - 8).
7157 * - The inode number in the directory entry should be within
7158 * legal bounds.
7159 * - The inode number should refer to a in-use inode.
7160 * - The first entry should be '.', and its inode should be
7161 * the inode of the directory.
7162 * - The second entry should be '..'.
7163 *
7164 * To minimize disk seek time, the directory blocks are processed in
7165 * sorted order of block numbers.
7166 *
7167 * Pass 2 also collects the following information:
7168 * - The inode numbers of the subdirectories for each directory.
7169 *
7170 * Pass 2 relies on the following information from previous passes:
7171 * - The directory information collected in pass 1.
7172 * - The inode_used_map bitmap
7173 * - The inode_bad_map bitmap
7174 * - The inode_dir_map bitmap
7175 *
7176 * Pass 2 frees the following data structures
7177 * - The inode_bad_map bitmap
7178 * - The inode_reg_map bitmap
7179 */
7180
7181/* #define DX_DEBUG */
7182
7183/*
7184 * Keeps track of how many times an inode is referenced.
7185 */
7186static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
7187static int check_dir_block(ext2_filsys fs,
7188 struct ext2_db_entry *dir_blocks_info,
7189 void *priv_data);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007190static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *dir_blocks_info,
7191 struct problem_context *pctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007192static int update_dir_block(ext2_filsys fs,
7193 blk_t *block_nr,
7194 e2_blkcnt_t blockcnt,
7195 blk_t ref_block,
7196 int ref_offset,
7197 void *priv_data);
7198static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
7199static int htree_depth(struct dx_dir_info *dx_dir,
7200 struct dx_dirblock_info *dx_db);
7201static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
7202
7203struct check_dir_struct {
7204 char *buf;
7205 struct problem_context pctx;
7206 int count, max;
7207 e2fsck_t ctx;
7208};
7209
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007210static void e2fsck_pass2(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007211{
7212 struct ext2_super_block *sb = ctx->fs->super;
7213 struct problem_context pctx;
7214 ext2_filsys fs = ctx->fs;
7215 char *buf;
7216#ifdef RESOURCE_TRACK
7217 struct resource_track rtrack;
7218#endif
7219 struct dir_info *dir;
7220 struct check_dir_struct cd;
7221 struct dx_dir_info *dx_dir;
7222 struct dx_dirblock_info *dx_db, *dx_parent;
7223 int b;
7224 int i, depth;
7225 problem_t code;
7226 int bad_dir;
7227
7228#ifdef RESOURCE_TRACK
7229 init_resource_track(&rtrack);
7230#endif
7231
7232 clear_problem_context(&cd.pctx);
7233
7234#ifdef MTRACE
7235 mtrace_print("Pass 2");
7236#endif
7237
7238 if (!(ctx->options & E2F_OPT_PREEN))
7239 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
7240
7241 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
7242 0, ctx->inode_link_info,
7243 &ctx->inode_count);
7244 if (cd.pctx.errcode) {
7245 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
7246 ctx->flags |= E2F_FLAG_ABORT;
7247 return;
7248 }
7249 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
7250 "directory scan buffer");
7251
7252 /*
7253 * Set up the parent pointer for the root directory, if
7254 * present. (If the root directory is not present, we will
7255 * create it in pass 3.)
7256 */
7257 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
7258 if (dir)
7259 dir->parent = EXT2_ROOT_INO;
7260
7261 cd.buf = buf;
7262 cd.ctx = ctx;
7263 cd.count = 1;
7264 cd.max = ext2fs_dblist_count(fs->dblist);
7265
7266 if (ctx->progress)
7267 (void) (ctx->progress)(ctx, 2, 0, cd.max);
7268
7269 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
7270 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
7271
7272 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
7273 &cd);
7274 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7275 return;
7276 if (cd.pctx.errcode) {
7277 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
7278 ctx->flags |= E2F_FLAG_ABORT;
7279 return;
7280 }
7281
7282#ifdef ENABLE_HTREE
7283 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
7284 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7285 return;
7286 if (dx_dir->numblocks == 0)
7287 continue;
7288 clear_problem_context(&pctx);
7289 bad_dir = 0;
7290 pctx.dir = dx_dir->ino;
7291 dx_db = dx_dir->dx_block;
7292 if (dx_db->flags & DX_FLAG_REFERENCED)
7293 dx_db->flags |= DX_FLAG_DUP_REF;
7294 else
7295 dx_db->flags |= DX_FLAG_REFERENCED;
7296 /*
7297 * Find all of the first and last leaf blocks, and
7298 * update their parent's min and max hash values
7299 */
7300 for (b=0, dx_db = dx_dir->dx_block;
7301 b < dx_dir->numblocks;
7302 b++, dx_db++) {
7303 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
7304 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
7305 continue;
7306 dx_parent = &dx_dir->dx_block[dx_db->parent];
7307 /*
7308 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
7309 */
7310 if (dx_db->flags & DX_FLAG_FIRST)
7311 dx_parent->min_hash = dx_db->min_hash;
7312 /*
7313 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
7314 */
7315 if (dx_db->flags & DX_FLAG_LAST)
7316 dx_parent->max_hash = dx_db->max_hash;
7317 }
7318
7319 for (b=0, dx_db = dx_dir->dx_block;
7320 b < dx_dir->numblocks;
7321 b++, dx_db++) {
7322 pctx.blkcount = b;
7323 pctx.group = dx_db->parent;
7324 code = 0;
7325 if (!(dx_db->flags & DX_FLAG_FIRST) &&
7326 (dx_db->min_hash < dx_db->node_min_hash)) {
7327 pctx.blk = dx_db->min_hash;
7328 pctx.blk2 = dx_db->node_min_hash;
7329 code = PR_2_HTREE_MIN_HASH;
7330 fix_problem(ctx, code, &pctx);
7331 bad_dir++;
7332 }
7333 if (dx_db->type == DX_DIRBLOCK_LEAF) {
7334 depth = htree_depth(dx_dir, dx_db);
7335 if (depth != dx_dir->depth) {
7336 code = PR_2_HTREE_BAD_DEPTH;
7337 fix_problem(ctx, code, &pctx);
7338 bad_dir++;
7339 }
7340 }
7341 /*
7342 * This test doesn't apply for the root block
7343 * at block #0
7344 */
7345 if (b &&
7346 (dx_db->max_hash > dx_db->node_max_hash)) {
7347 pctx.blk = dx_db->max_hash;
7348 pctx.blk2 = dx_db->node_max_hash;
7349 code = PR_2_HTREE_MAX_HASH;
7350 fix_problem(ctx, code, &pctx);
7351 bad_dir++;
7352 }
7353 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
7354 code = PR_2_HTREE_NOTREF;
7355 fix_problem(ctx, code, &pctx);
7356 bad_dir++;
7357 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
7358 code = PR_2_HTREE_DUPREF;
7359 fix_problem(ctx, code, &pctx);
7360 bad_dir++;
7361 }
7362 if (code == 0)
7363 continue;
7364 }
7365 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
7366 clear_htree(ctx, dx_dir->ino);
7367 dx_dir->numblocks = 0;
7368 }
7369 }
7370#endif
7371 ext2fs_free_mem(&buf);
7372 ext2fs_free_dblist(fs->dblist);
7373
7374 if (ctx->inode_bad_map) {
7375 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
7376 ctx->inode_bad_map = 0;
7377 }
7378 if (ctx->inode_reg_map) {
7379 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
7380 ctx->inode_reg_map = 0;
7381 }
7382
7383 clear_problem_context(&pctx);
7384 if (ctx->large_files) {
7385 if (!(sb->s_feature_ro_compat &
7386 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
7387 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
7388 sb->s_feature_ro_compat |=
7389 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7390 ext2fs_mark_super_dirty(fs);
7391 }
7392 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
7393 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
7394 ext2fs_update_dynamic_rev(fs);
7395 ext2fs_mark_super_dirty(fs);
7396 }
7397 } else if (!ctx->large_files &&
7398 (sb->s_feature_ro_compat &
7399 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
7400 if (fs->flags & EXT2_FLAG_RW) {
7401 sb->s_feature_ro_compat &=
7402 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7403 ext2fs_mark_super_dirty(fs);
7404 }
7405 }
7406
7407#ifdef RESOURCE_TRACK
7408 if (ctx->options & E2F_OPT_TIME2) {
7409 e2fsck_clear_progbar(ctx);
7410 print_resource_track(_("Pass 2"), &rtrack);
7411 }
7412#endif
7413}
7414
7415#define MAX_DEPTH 32000
7416static int htree_depth(struct dx_dir_info *dx_dir,
7417 struct dx_dirblock_info *dx_db)
7418{
7419 int depth = 0;
7420
7421 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
7422 dx_db = &dx_dir->dx_block[dx_db->parent];
7423 depth++;
7424 }
7425 return depth;
7426}
7427
7428static int dict_de_cmp(const void *a, const void *b)
7429{
7430 const struct ext2_dir_entry *de_a, *de_b;
7431 int a_len, b_len;
7432
7433 de_a = (const struct ext2_dir_entry *) a;
7434 a_len = de_a->name_len & 0xFF;
7435 de_b = (const struct ext2_dir_entry *) b;
7436 b_len = de_b->name_len & 0xFF;
7437
7438 if (a_len != b_len)
7439 return (a_len - b_len);
7440
7441 return strncmp(de_a->name, de_b->name, a_len);
7442}
7443
7444/*
7445 * This is special sort function that makes sure that directory blocks
7446 * with a dirblock of zero are sorted to the beginning of the list.
7447 * This guarantees that the root node of the htree directories are
7448 * processed first, so we know what hash version to use.
7449 */
7450static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
7451{
7452 const struct ext2_db_entry *db_a =
7453 (const struct ext2_db_entry *) a;
7454 const struct ext2_db_entry *db_b =
7455 (const struct ext2_db_entry *) b;
7456
7457 if (db_a->blockcnt && !db_b->blockcnt)
7458 return 1;
7459
7460 if (!db_a->blockcnt && db_b->blockcnt)
7461 return -1;
7462
7463 if (db_a->blk != db_b->blk)
7464 return (int) (db_a->blk - db_b->blk);
7465
7466 if (db_a->ino != db_b->ino)
7467 return (int) (db_a->ino - db_b->ino);
7468
7469 return (int) (db_a->blockcnt - db_b->blockcnt);
7470}
7471
7472
7473/*
7474 * Make sure the first entry in the directory is '.', and that the
7475 * directory entry is sane.
7476 */
7477static int check_dot(e2fsck_t ctx,
7478 struct ext2_dir_entry *dirent,
7479 ext2_ino_t ino, struct problem_context *pctx)
7480{
7481 struct ext2_dir_entry *nextdir;
7482 int status = 0;
7483 int created = 0;
7484 int new_len;
7485 int problem = 0;
7486
7487 if (!dirent->inode)
7488 problem = PR_2_MISSING_DOT;
7489 else if (((dirent->name_len & 0xFF) != 1) ||
7490 (dirent->name[0] != '.'))
7491 problem = PR_2_1ST_NOT_DOT;
7492 else if (dirent->name[1] != '\0')
7493 problem = PR_2_DOT_NULL_TERM;
7494
7495 if (problem) {
7496 if (fix_problem(ctx, problem, pctx)) {
7497 if (dirent->rec_len < 12)
7498 dirent->rec_len = 12;
7499 dirent->inode = ino;
7500 dirent->name_len = 1;
7501 dirent->name[0] = '.';
7502 dirent->name[1] = '\0';
7503 status = 1;
7504 created = 1;
7505 }
7506 }
7507 if (dirent->inode != ino) {
7508 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
7509 dirent->inode = ino;
7510 status = 1;
7511 }
7512 }
7513 if (dirent->rec_len > 12) {
7514 new_len = dirent->rec_len - 12;
7515 if (new_len > 12) {
7516 if (created ||
7517 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
7518 nextdir = (struct ext2_dir_entry *)
7519 ((char *) dirent + 12);
7520 dirent->rec_len = 12;
7521 nextdir->rec_len = new_len;
7522 nextdir->inode = 0;
7523 nextdir->name_len = 0;
7524 status = 1;
7525 }
7526 }
7527 }
7528 return status;
7529}
7530
7531/*
7532 * Make sure the second entry in the directory is '..', and that the
7533 * directory entry is sane. We do not check the inode number of '..'
7534 * here; this gets done in pass 3.
7535 */
7536static int check_dotdot(e2fsck_t ctx,
7537 struct ext2_dir_entry *dirent,
7538 struct dir_info *dir, struct problem_context *pctx)
7539{
7540 int problem = 0;
7541
7542 if (!dirent->inode)
7543 problem = PR_2_MISSING_DOT_DOT;
7544 else if (((dirent->name_len & 0xFF) != 2) ||
7545 (dirent->name[0] != '.') ||
7546 (dirent->name[1] != '.'))
7547 problem = PR_2_2ND_NOT_DOT_DOT;
7548 else if (dirent->name[2] != '\0')
7549 problem = PR_2_DOT_DOT_NULL_TERM;
7550
7551 if (problem) {
7552 if (fix_problem(ctx, problem, pctx)) {
7553 if (dirent->rec_len < 12)
7554 dirent->rec_len = 12;
7555 /*
7556 * Note: we don't have the parent inode just
7557 * yet, so we will fill it in with the root
7558 * inode. This will get fixed in pass 3.
7559 */
7560 dirent->inode = EXT2_ROOT_INO;
7561 dirent->name_len = 2;
7562 dirent->name[0] = '.';
7563 dirent->name[1] = '.';
7564 dirent->name[2] = '\0';
7565 return 1;
7566 }
7567 return 0;
7568 }
7569 dir->dotdot = dirent->inode;
7570 return 0;
7571}
7572
7573/*
7574 * Check to make sure a directory entry doesn't contain any illegal
7575 * characters.
7576 */
7577static int check_name(e2fsck_t ctx,
7578 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007579 struct problem_context *pctx)
7580{
7581 int i;
7582 int fixup = -1;
7583 int ret = 0;
7584
7585 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
7586 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
7587 if (fixup < 0) {
7588 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
7589 }
7590 if (fixup) {
7591 dirent->name[i] = '.';
7592 ret = 1;
7593 }
7594 }
7595 }
7596 return ret;
7597}
7598
7599/*
7600 * Check the directory filetype (if present)
7601 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007602
7603/*
7604 * Given a mode, return the ext2 file type
7605 */
7606static int ext2_file_type(unsigned int mode)
7607{
7608 if (LINUX_S_ISREG(mode))
7609 return EXT2_FT_REG_FILE;
7610
7611 if (LINUX_S_ISDIR(mode))
7612 return EXT2_FT_DIR;
7613
7614 if (LINUX_S_ISCHR(mode))
7615 return EXT2_FT_CHRDEV;
7616
7617 if (LINUX_S_ISBLK(mode))
7618 return EXT2_FT_BLKDEV;
7619
7620 if (LINUX_S_ISLNK(mode))
7621 return EXT2_FT_SYMLINK;
7622
7623 if (LINUX_S_ISFIFO(mode))
7624 return EXT2_FT_FIFO;
7625
7626 if (LINUX_S_ISSOCK(mode))
7627 return EXT2_FT_SOCK;
7628
7629 return 0;
7630}
7631
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007632static _INLINE_ int check_filetype(e2fsck_t ctx,
7633 struct ext2_dir_entry *dirent,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007634 struct problem_context *pctx)
7635{
7636 int filetype = dirent->name_len >> 8;
7637 int should_be = EXT2_FT_UNKNOWN;
7638 struct ext2_inode inode;
7639
7640 if (!(ctx->fs->super->s_feature_incompat &
7641 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
7642 if (filetype == 0 ||
7643 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
7644 return 0;
7645 dirent->name_len = dirent->name_len & 0xFF;
7646 return 1;
7647 }
7648
7649 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
7650 should_be = EXT2_FT_DIR;
7651 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
7652 dirent->inode)) {
7653 should_be = EXT2_FT_REG_FILE;
7654 } else if (ctx->inode_bad_map &&
7655 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
7656 dirent->inode))
7657 should_be = 0;
7658 else {
7659 e2fsck_read_inode(ctx, dirent->inode, &inode,
7660 "check_filetype");
7661 should_be = ext2_file_type(inode.i_mode);
7662 }
7663 if (filetype == should_be)
7664 return 0;
7665 pctx->num = should_be;
7666
7667 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
7668 pctx) == 0)
7669 return 0;
7670
7671 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
7672 return 1;
7673}
7674
7675#ifdef ENABLE_HTREE
7676static void parse_int_node(ext2_filsys fs,
7677 struct ext2_db_entry *db,
7678 struct check_dir_struct *cd,
7679 struct dx_dir_info *dx_dir,
7680 char *block_buf)
7681{
7682 struct ext2_dx_root_info *root;
7683 struct ext2_dx_entry *ent;
7684 struct ext2_dx_countlimit *limit;
7685 struct dx_dirblock_info *dx_db;
7686 int i, expect_limit, count;
7687 blk_t blk;
7688 ext2_dirhash_t min_hash = 0xffffffff;
7689 ext2_dirhash_t max_hash = 0;
7690 ext2_dirhash_t hash = 0, prev_hash;
7691
7692 if (db->blockcnt == 0) {
7693 root = (struct ext2_dx_root_info *) (block_buf + 24);
7694
7695#ifdef DX_DEBUG
7696 printf("Root node dump:\n");
7697 printf("\t Reserved zero: %d\n", root->reserved_zero);
7698 printf("\t Hash Version: %d\n", root->hash_version);
7699 printf("\t Info length: %d\n", root->info_length);
7700 printf("\t Indirect levels: %d\n", root->indirect_levels);
7701 printf("\t Flags: %d\n", root->unused_flags);
7702#endif
7703
7704 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
7705 } else {
7706 ent = (struct ext2_dx_entry *) (block_buf+8);
7707 }
7708 limit = (struct ext2_dx_countlimit *) ent;
7709
7710#ifdef DX_DEBUG
7711 printf("Number of entries (count): %d\n",
7712 ext2fs_le16_to_cpu(limit->count));
7713 printf("Number of entries (limit): %d\n",
7714 ext2fs_le16_to_cpu(limit->limit));
7715#endif
7716
7717 count = ext2fs_le16_to_cpu(limit->count);
7718 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
7719 sizeof(struct ext2_dx_entry);
7720 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
7721 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
7722 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
7723 goto clear_and_exit;
7724 }
7725 if (count > expect_limit) {
7726 cd->pctx.num = count;
7727 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
7728 goto clear_and_exit;
7729 count = expect_limit;
7730 }
7731
7732 for (i=0; i < count; i++) {
7733 prev_hash = hash;
7734 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
7735#ifdef DX_DEBUG
7736 printf("Entry #%d: Hash 0x%08x, block %d\n", i,
7737 hash, ext2fs_le32_to_cpu(ent[i].block));
7738#endif
7739 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
7740 /* Check to make sure the block is valid */
7741 if (blk > (blk_t) dx_dir->numblocks) {
7742 cd->pctx.blk = blk;
7743 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
7744 &cd->pctx))
7745 goto clear_and_exit;
7746 }
7747 if (hash < prev_hash &&
7748 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
7749 goto clear_and_exit;
7750 dx_db = &dx_dir->dx_block[blk];
7751 if (dx_db->flags & DX_FLAG_REFERENCED) {
7752 dx_db->flags |= DX_FLAG_DUP_REF;
7753 } else {
7754 dx_db->flags |= DX_FLAG_REFERENCED;
7755 dx_db->parent = db->blockcnt;
7756 }
7757 if (hash < min_hash)
7758 min_hash = hash;
7759 if (hash > max_hash)
7760 max_hash = hash;
7761 dx_db->node_min_hash = hash;
7762 if ((i+1) < count)
7763 dx_db->node_max_hash =
7764 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
7765 else {
7766 dx_db->node_max_hash = 0xfffffffe;
7767 dx_db->flags |= DX_FLAG_LAST;
7768 }
7769 if (i == 0)
7770 dx_db->flags |= DX_FLAG_FIRST;
7771 }
7772#ifdef DX_DEBUG
7773 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
7774 db->blockcnt, min_hash, max_hash);
7775#endif
7776 dx_db = &dx_dir->dx_block[db->blockcnt];
7777 dx_db->min_hash = min_hash;
7778 dx_db->max_hash = max_hash;
7779 return;
7780
7781clear_and_exit:
7782 clear_htree(cd->ctx, cd->pctx.ino);
7783 dx_dir->numblocks = 0;
7784}
7785#endif /* ENABLE_HTREE */
7786
7787/*
7788 * Given a busted directory, try to salvage it somehow.
7789 *
7790 */
7791static void salvage_directory(ext2_filsys fs,
7792 struct ext2_dir_entry *dirent,
7793 struct ext2_dir_entry *prev,
7794 unsigned int *offset)
7795{
7796 char *cp = (char *) dirent;
7797 int left = fs->blocksize - *offset - dirent->rec_len;
7798 int name_len = dirent->name_len & 0xFF;
7799
7800 /*
7801 * Special case of directory entry of size 8: copy what's left
7802 * of the directory block up to cover up the invalid hole.
7803 */
7804 if ((left >= 12) && (dirent->rec_len == 8)) {
7805 memmove(cp, cp+8, left);
7806 memset(cp + left, 0, 8);
7807 return;
7808 }
7809 /*
7810 * If the directory entry overruns the end of the directory
7811 * block, and the name is small enough to fit, then adjust the
7812 * record length.
7813 */
7814 if ((left < 0) &&
7815 (name_len + 8 <= dirent->rec_len + left) &&
7816 dirent->inode <= fs->super->s_inodes_count &&
7817 strnlen(dirent->name, name_len) == name_len) {
7818 dirent->rec_len += left;
7819 return;
7820 }
7821 /*
7822 * If the directory entry is a multiple of four, so it is
7823 * valid, let the previous directory entry absorb the invalid
7824 * one.
7825 */
7826 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
7827 prev->rec_len += dirent->rec_len;
7828 *offset += dirent->rec_len;
7829 return;
7830 }
7831 /*
7832 * Default salvage method --- kill all of the directory
7833 * entries for the rest of the block. We will either try to
7834 * absorb it into the previous directory entry, or create a
7835 * new empty directory entry the rest of the directory block.
7836 */
7837 if (prev) {
7838 prev->rec_len += fs->blocksize - *offset;
7839 *offset = fs->blocksize;
7840 } else {
7841 dirent->rec_len = fs->blocksize - *offset;
7842 dirent->name_len = 0;
7843 dirent->inode = 0;
7844 }
7845}
7846
7847static int check_dir_block(ext2_filsys fs,
7848 struct ext2_db_entry *db,
7849 void *priv_data)
7850{
7851 struct dir_info *subdir, *dir;
7852 struct dx_dir_info *dx_dir;
7853#ifdef ENABLE_HTREE
7854 struct dx_dirblock_info *dx_db = 0;
7855#endif /* ENABLE_HTREE */
7856 struct ext2_dir_entry *dirent, *prev;
7857 ext2_dirhash_t hash;
7858 unsigned int offset = 0;
7859 int dir_modified = 0;
7860 int dot_state;
7861 blk_t block_nr = db->blk;
7862 ext2_ino_t ino = db->ino;
7863 __u16 links;
7864 struct check_dir_struct *cd;
7865 char *buf;
7866 e2fsck_t ctx;
7867 int problem;
7868 struct ext2_dx_root_info *root;
7869 struct ext2_dx_countlimit *limit;
7870 static dict_t de_dict;
7871 struct problem_context pctx;
7872 int dups_found = 0;
7873
7874 cd = (struct check_dir_struct *) priv_data;
7875 buf = cd->buf;
7876 ctx = cd->ctx;
7877
7878 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7879 return DIRENT_ABORT;
7880
7881 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
7882 return DIRENT_ABORT;
7883
7884 /*
7885 * Make sure the inode is still in use (could have been
7886 * deleted in the duplicate/bad blocks pass.
7887 */
7888 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
7889 return 0;
7890
7891 cd->pctx.ino = ino;
7892 cd->pctx.blk = block_nr;
7893 cd->pctx.blkcount = db->blockcnt;
7894 cd->pctx.ino2 = 0;
7895 cd->pctx.dirent = 0;
7896 cd->pctx.num = 0;
7897
7898 if (db->blk == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00007899 if (allocate_dir_block(ctx, db, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00007900 return 0;
7901 block_nr = db->blk;
7902 }
7903
7904 if (db->blockcnt)
7905 dot_state = 2;
7906 else
7907 dot_state = 0;
7908
7909 if (ctx->dirs_to_hash &&
7910 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
7911 dups_found++;
7912
7913#if 0
7914 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
7915 db->blockcnt, ino);
7916#endif
7917
7918 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
7919 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
7920 cd->pctx.errcode = 0; /* We'll handle this ourselves */
7921 if (cd->pctx.errcode) {
7922 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
7923 ctx->flags |= E2F_FLAG_ABORT;
7924 return DIRENT_ABORT;
7925 }
7926 memset(buf, 0, fs->blocksize);
7927 }
7928#ifdef ENABLE_HTREE
7929 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
7930 if (dx_dir && dx_dir->numblocks) {
7931 if (db->blockcnt >= dx_dir->numblocks) {
7932 printf("XXX should never happen!!!\n");
7933 abort();
7934 }
7935 dx_db = &dx_dir->dx_block[db->blockcnt];
7936 dx_db->type = DX_DIRBLOCK_LEAF;
7937 dx_db->phys = block_nr;
7938 dx_db->min_hash = ~0;
7939 dx_db->max_hash = 0;
7940
7941 dirent = (struct ext2_dir_entry *) buf;
7942 limit = (struct ext2_dx_countlimit *) (buf+8);
7943 if (db->blockcnt == 0) {
7944 root = (struct ext2_dx_root_info *) (buf + 24);
7945 dx_db->type = DX_DIRBLOCK_ROOT;
7946 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
7947 if ((root->reserved_zero ||
7948 root->info_length < 8 ||
7949 root->indirect_levels > 1) &&
7950 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
7951 clear_htree(ctx, ino);
7952 dx_dir->numblocks = 0;
7953 dx_db = 0;
7954 }
7955 dx_dir->hashversion = root->hash_version;
7956 dx_dir->depth = root->indirect_levels + 1;
7957 } else if ((dirent->inode == 0) &&
7958 (dirent->rec_len == fs->blocksize) &&
7959 (dirent->name_len == 0) &&
7960 (ext2fs_le16_to_cpu(limit->limit) ==
7961 ((fs->blocksize-8) /
7962 sizeof(struct ext2_dx_entry))))
7963 dx_db->type = DX_DIRBLOCK_NODE;
7964 }
7965#endif /* ENABLE_HTREE */
7966
7967 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
7968 prev = 0;
7969 do {
7970 problem = 0;
7971 dirent = (struct ext2_dir_entry *) (buf + offset);
7972 cd->pctx.dirent = dirent;
7973 cd->pctx.num = offset;
7974 if (((offset + dirent->rec_len) > fs->blocksize) ||
7975 (dirent->rec_len < 12) ||
7976 ((dirent->rec_len % 4) != 0) ||
7977 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
7978 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
7979 salvage_directory(fs, dirent, prev, &offset);
7980 dir_modified++;
7981 continue;
7982 } else
7983 goto abort_free_dict;
7984 }
7985 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
7986 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
7987 dirent->name_len = EXT2_NAME_LEN;
7988 dir_modified++;
7989 }
7990 }
7991
7992 if (dot_state == 0) {
7993 if (check_dot(ctx, dirent, ino, &cd->pctx))
7994 dir_modified++;
7995 } else if (dot_state == 1) {
7996 dir = e2fsck_get_dir_info(ctx, ino);
7997 if (!dir) {
7998 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
7999 goto abort_free_dict;
8000 }
8001 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
8002 dir_modified++;
8003 } else if (dirent->inode == ino) {
8004 problem = PR_2_LINK_DOT;
8005 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
8006 dirent->inode = 0;
8007 dir_modified++;
8008 goto next;
8009 }
8010 }
8011 if (!dirent->inode)
8012 goto next;
8013
8014 /*
8015 * Make sure the inode listed is a legal one.
8016 */
8017 if (((dirent->inode != EXT2_ROOT_INO) &&
8018 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
8019 (dirent->inode > fs->super->s_inodes_count)) {
8020 problem = PR_2_BAD_INO;
8021 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
8022 dirent->inode))) {
8023 /*
8024 * If the inode is unused, offer to clear it.
8025 */
8026 problem = PR_2_UNUSED_INODE;
8027 } else if (ctx->inode_bb_map &&
8028 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
8029 dirent->inode))) {
8030 /*
8031 * If the inode is in a bad block, offer to
8032 * clear it.
8033 */
8034 problem = PR_2_BB_INODE;
8035 } else if ((dot_state > 1) &&
8036 ((dirent->name_len & 0xFF) == 1) &&
8037 (dirent->name[0] == '.')) {
8038 /*
8039 * If there's a '.' entry in anything other
8040 * than the first directory entry, it's a
8041 * duplicate entry that should be removed.
8042 */
8043 problem = PR_2_DUP_DOT;
8044 } else if ((dot_state > 1) &&
8045 ((dirent->name_len & 0xFF) == 2) &&
8046 (dirent->name[0] == '.') &&
8047 (dirent->name[1] == '.')) {
8048 /*
8049 * If there's a '..' entry in anything other
8050 * than the second directory entry, it's a
8051 * duplicate entry that should be removed.
8052 */
8053 problem = PR_2_DUP_DOT_DOT;
8054 } else if ((dot_state > 1) &&
8055 (dirent->inode == EXT2_ROOT_INO)) {
8056 /*
8057 * Don't allow links to the root directory.
8058 * We check this specially to make sure we
8059 * catch this error case even if the root
8060 * directory hasn't been created yet.
8061 */
8062 problem = PR_2_LINK_ROOT;
8063 } else if ((dot_state > 1) &&
8064 (dirent->name_len & 0xFF) == 0) {
8065 /*
8066 * Don't allow zero-length directory names.
8067 */
8068 problem = PR_2_NULL_NAME;
8069 }
8070
8071 if (problem) {
8072 if (fix_problem(ctx, problem, &cd->pctx)) {
8073 dirent->inode = 0;
8074 dir_modified++;
8075 goto next;
8076 } else {
8077 ext2fs_unmark_valid(fs);
8078 if (problem == PR_2_BAD_INO)
8079 goto next;
8080 }
8081 }
8082
8083 /*
8084 * If the inode was marked as having bad fields in
8085 * pass1, process it and offer to fix/clear it.
8086 * (We wait until now so that we can display the
8087 * pathname to the user.)
8088 */
8089 if (ctx->inode_bad_map &&
8090 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
8091 dirent->inode)) {
8092 if (e2fsck_process_bad_inode(ctx, ino,
8093 dirent->inode,
8094 buf + fs->blocksize)) {
8095 dirent->inode = 0;
8096 dir_modified++;
8097 goto next;
8098 }
8099 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8100 return DIRENT_ABORT;
8101 }
8102
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008103 if (check_name(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008104 dir_modified++;
8105
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008106 if (check_filetype(ctx, dirent, &cd->pctx))
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008107 dir_modified++;
8108
8109#ifdef ENABLE_HTREE
8110 if (dx_db) {
8111 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
8112 (dirent->name_len & 0xFF),
8113 fs->super->s_hash_seed, &hash, 0);
8114 if (hash < dx_db->min_hash)
8115 dx_db->min_hash = hash;
8116 if (hash > dx_db->max_hash)
8117 dx_db->max_hash = hash;
8118 }
8119#endif
8120
8121 /*
8122 * If this is a directory, then mark its parent in its
8123 * dir_info structure. If the parent field is already
8124 * filled in, then this directory has more than one
8125 * hard link. We assume the first link is correct,
8126 * and ask the user if he/she wants to clear this one.
8127 */
8128 if ((dot_state > 1) &&
8129 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8130 dirent->inode))) {
8131 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
8132 if (!subdir) {
8133 cd->pctx.ino = dirent->inode;
8134 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
8135 goto abort_free_dict;
8136 }
8137 if (subdir->parent) {
8138 cd->pctx.ino2 = subdir->parent;
8139 if (fix_problem(ctx, PR_2_LINK_DIR,
8140 &cd->pctx)) {
8141 dirent->inode = 0;
8142 dir_modified++;
8143 goto next;
8144 }
8145 cd->pctx.ino2 = 0;
8146 } else
8147 subdir->parent = ino;
8148 }
8149
8150 if (dups_found) {
8151 ;
8152 } else if (dict_lookup(&de_dict, dirent)) {
8153 clear_problem_context(&pctx);
8154 pctx.ino = ino;
8155 pctx.dirent = dirent;
8156 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
8157 if (!ctx->dirs_to_hash)
8158 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
8159 if (ctx->dirs_to_hash)
8160 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8161 dups_found++;
8162 } else
8163 dict_alloc_insert(&de_dict, dirent, dirent);
8164
8165 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
8166 &links);
8167 if (links > 1)
8168 ctx->fs_links_count++;
8169 ctx->fs_total_count++;
8170 next:
8171 prev = dirent;
8172 offset += dirent->rec_len;
8173 dot_state++;
8174 } while (offset < fs->blocksize);
8175#if 0
8176 printf("\n");
8177#endif
8178#ifdef ENABLE_HTREE
8179 if (dx_db) {
8180#ifdef DX_DEBUG
8181 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
8182 db->blockcnt, dx_db->type,
8183 dx_db->min_hash, dx_db->max_hash);
8184#endif
8185 cd->pctx.dir = cd->pctx.ino;
8186 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
8187 (dx_db->type == DX_DIRBLOCK_NODE))
8188 parse_int_node(fs, db, cd, dx_dir, buf);
8189 }
8190#endif /* ENABLE_HTREE */
8191 if (offset != fs->blocksize) {
8192 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
8193 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
8194 dirent->rec_len = cd->pctx.num;
8195 dir_modified++;
8196 }
8197 }
8198 if (dir_modified) {
8199 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
8200 if (cd->pctx.errcode) {
8201 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
8202 &cd->pctx))
8203 goto abort_free_dict;
8204 }
8205 ext2fs_mark_changed(fs);
8206 }
8207 dict_free_nodes(&de_dict);
8208 return 0;
8209abort_free_dict:
8210 dict_free_nodes(&de_dict);
8211 ctx->flags |= E2F_FLAG_ABORT;
8212 return DIRENT_ABORT;
8213}
8214
8215/*
8216 * This function is called to deallocate a block, and is an interator
8217 * functioned called by deallocate inode via ext2fs_iterate_block().
8218 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008219static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008220 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
8221 blk_t ref_block EXT2FS_ATTR((unused)),
8222 int ref_offset EXT2FS_ATTR((unused)),
8223 void *priv_data)
8224{
8225 e2fsck_t ctx = (e2fsck_t) priv_data;
8226
8227 if (HOLE_BLKADDR(*block_nr))
8228 return 0;
8229 if ((*block_nr < fs->super->s_first_data_block) ||
8230 (*block_nr >= fs->super->s_blocks_count))
8231 return 0;
8232 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
8233 ext2fs_block_alloc_stats(fs, *block_nr, -1);
8234 return 0;
8235}
8236
8237/*
8238 * This fuction deallocates an inode
8239 */
8240static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
8241{
8242 ext2_filsys fs = ctx->fs;
8243 struct ext2_inode inode;
8244 struct problem_context pctx;
8245 __u32 count;
8246
8247 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
8248 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
8249 inode.i_links_count = 0;
8250 inode.i_dtime = time(0);
8251 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
8252 clear_problem_context(&pctx);
8253 pctx.ino = ino;
8254
8255 /*
8256 * Fix up the bitmaps...
8257 */
8258 e2fsck_read_bitmaps(ctx);
8259 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
8260 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
8261 if (ctx->inode_bad_map)
8262 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8263 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
8264
8265 if (inode.i_file_acl &&
8266 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
8267 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
8268 block_buf, -1, &count);
8269 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
8270 pctx.errcode = 0;
8271 count = 1;
8272 }
8273 if (pctx.errcode) {
8274 pctx.blk = inode.i_file_acl;
8275 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
8276 ctx->flags |= E2F_FLAG_ABORT;
8277 return;
8278 }
8279 if (count == 0) {
8280 ext2fs_unmark_block_bitmap(ctx->block_found_map,
8281 inode.i_file_acl);
8282 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
8283 }
8284 inode.i_file_acl = 0;
8285 }
8286
8287 if (!ext2fs_inode_has_valid_blocks(&inode))
8288 return;
8289
8290 if (LINUX_S_ISREG(inode.i_mode) &&
8291 (inode.i_size_high || inode.i_size & 0x80000000UL))
8292 ctx->large_files--;
8293
8294 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
8295 deallocate_inode_block, ctx);
8296 if (pctx.errcode) {
8297 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
8298 ctx->flags |= E2F_FLAG_ABORT;
8299 return;
8300 }
8301}
8302
8303/*
8304 * This fuction clears the htree flag on an inode
8305 */
8306static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
8307{
8308 struct ext2_inode inode;
8309
8310 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
8311 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
8312 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
8313 if (ctx->dirs_to_hash)
8314 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8315}
8316
8317
8318static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
8319 ext2_ino_t ino, char *buf)
8320{
8321 ext2_filsys fs = ctx->fs;
8322 struct ext2_inode inode;
8323 int inode_modified = 0;
8324 int not_fixed = 0;
8325 unsigned char *frag, *fsize;
8326 struct problem_context pctx;
8327 int problem = 0;
8328
8329 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
8330
8331 clear_problem_context(&pctx);
8332 pctx.ino = ino;
8333 pctx.dir = dir;
8334 pctx.inode = &inode;
8335
8336 if (inode.i_file_acl &&
8337 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
8338 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
8339 inode.i_file_acl = 0;
8340#ifdef EXT2FS_ENABLE_SWAPFS
8341 /*
8342 * This is a special kludge to deal with long symlinks
8343 * on big endian systems. i_blocks had already been
8344 * decremented earlier in pass 1, but since i_file_acl
8345 * hadn't yet been cleared, ext2fs_read_inode()
8346 * assumed that the file was short symlink and would
8347 * not have byte swapped i_block[0]. Hence, we have
8348 * to byte-swap it here.
8349 */
8350 if (LINUX_S_ISLNK(inode.i_mode) &&
8351 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
8352 (inode.i_blocks == fs->blocksize >> 9))
8353 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
8354#endif
8355 inode_modified++;
8356 } else
8357 not_fixed++;
8358
8359 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
8360 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
8361 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
8362 !(LINUX_S_ISSOCK(inode.i_mode)))
8363 problem = PR_2_BAD_MODE;
8364 else if (LINUX_S_ISCHR(inode.i_mode)
8365 && !e2fsck_pass1_check_device_inode(fs, &inode))
8366 problem = PR_2_BAD_CHAR_DEV;
8367 else if (LINUX_S_ISBLK(inode.i_mode)
8368 && !e2fsck_pass1_check_device_inode(fs, &inode))
8369 problem = PR_2_BAD_BLOCK_DEV;
8370 else if (LINUX_S_ISFIFO(inode.i_mode)
8371 && !e2fsck_pass1_check_device_inode(fs, &inode))
8372 problem = PR_2_BAD_FIFO;
8373 else if (LINUX_S_ISSOCK(inode.i_mode)
8374 && !e2fsck_pass1_check_device_inode(fs, &inode))
8375 problem = PR_2_BAD_SOCKET;
8376 else if (LINUX_S_ISLNK(inode.i_mode)
8377 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
8378 problem = PR_2_INVALID_SYMLINK;
8379 }
8380
8381 if (problem) {
8382 if (fix_problem(ctx, problem, &pctx)) {
8383 deallocate_inode(ctx, ino, 0);
8384 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8385 return 0;
8386 return 1;
8387 } else
8388 not_fixed++;
8389 problem = 0;
8390 }
8391
8392 if (inode.i_faddr) {
8393 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
8394 inode.i_faddr = 0;
8395 inode_modified++;
8396 } else
8397 not_fixed++;
8398 }
8399
8400 switch (fs->super->s_creator_os) {
8401 case EXT2_OS_LINUX:
8402 frag = &inode.osd2.linux2.l_i_frag;
8403 fsize = &inode.osd2.linux2.l_i_fsize;
8404 break;
8405 case EXT2_OS_HURD:
8406 frag = &inode.osd2.hurd2.h_i_frag;
8407 fsize = &inode.osd2.hurd2.h_i_fsize;
8408 break;
8409 case EXT2_OS_MASIX:
8410 frag = &inode.osd2.masix2.m_i_frag;
8411 fsize = &inode.osd2.masix2.m_i_fsize;
8412 break;
8413 default:
8414 frag = fsize = 0;
8415 }
8416 if (frag && *frag) {
8417 pctx.num = *frag;
8418 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
8419 *frag = 0;
8420 inode_modified++;
8421 } else
8422 not_fixed++;
8423 pctx.num = 0;
8424 }
8425 if (fsize && *fsize) {
8426 pctx.num = *fsize;
8427 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
8428 *fsize = 0;
8429 inode_modified++;
8430 } else
8431 not_fixed++;
8432 pctx.num = 0;
8433 }
8434
8435 if (inode.i_file_acl &&
8436 ((inode.i_file_acl < fs->super->s_first_data_block) ||
8437 (inode.i_file_acl >= fs->super->s_blocks_count))) {
8438 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
8439 inode.i_file_acl = 0;
8440 inode_modified++;
8441 } else
8442 not_fixed++;
8443 }
8444 if (inode.i_dir_acl &&
8445 LINUX_S_ISDIR(inode.i_mode)) {
8446 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
8447 inode.i_dir_acl = 0;
8448 inode_modified++;
8449 } else
8450 not_fixed++;
8451 }
8452
8453 if (inode_modified)
8454 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
8455 if (!not_fixed)
8456 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8457 return 0;
8458}
8459
8460
8461/*
8462 * allocate_dir_block --- this function allocates a new directory
8463 * block for a particular inode; this is done if a directory has
8464 * a "hole" in it, or if a directory has a illegal block number
8465 * that was zeroed out and now needs to be replaced.
8466 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008467static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008468 struct problem_context *pctx)
8469{
8470 ext2_filsys fs = ctx->fs;
8471 blk_t blk;
8472 char *block;
8473 struct ext2_inode inode;
8474
8475 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
8476 return 1;
8477
8478 /*
8479 * Read the inode and block bitmaps in; we'll be messing with
8480 * them.
8481 */
8482 e2fsck_read_bitmaps(ctx);
8483
8484 /*
8485 * First, find a free block
8486 */
8487 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8488 if (pctx->errcode) {
8489 pctx->str = "ext2fs_new_block";
8490 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8491 return 1;
8492 }
8493 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8494 ext2fs_mark_block_bitmap(fs->block_map, blk);
8495 ext2fs_mark_bb_dirty(fs);
8496
8497 /*
8498 * Now let's create the actual data block for the inode
8499 */
8500 if (db->blockcnt)
8501 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
8502 else
8503 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
8504 EXT2_ROOT_INO, &block);
8505
8506 if (pctx->errcode) {
8507 pctx->str = "ext2fs_new_dir_block";
8508 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8509 return 1;
8510 }
8511
8512 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
8513 ext2fs_free_mem(&block);
8514 if (pctx->errcode) {
8515 pctx->str = "ext2fs_write_dir_block";
8516 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8517 return 1;
8518 }
8519
8520 /*
8521 * Update the inode block count
8522 */
8523 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
8524 inode.i_blocks += fs->blocksize / 512;
8525 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
8526 inode.i_size = (db->blockcnt+1) * fs->blocksize;
8527 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
8528
8529 /*
8530 * Finally, update the block pointers for the inode
8531 */
8532 db->blk = blk;
8533 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
8534 0, update_dir_block, db);
8535 if (pctx->errcode) {
8536 pctx->str = "ext2fs_block_iterate";
8537 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8538 return 1;
8539 }
8540
8541 return 0;
8542}
8543
8544/*
8545 * This is a helper function for allocate_dir_block().
8546 */
8547static int update_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
8548 blk_t *block_nr,
8549 e2_blkcnt_t blockcnt,
8550 blk_t ref_block EXT2FS_ATTR((unused)),
8551 int ref_offset EXT2FS_ATTR((unused)),
8552 void *priv_data)
8553{
8554 struct ext2_db_entry *db;
8555
8556 db = (struct ext2_db_entry *) priv_data;
8557 if (db->blockcnt == (int) blockcnt) {
8558 *block_nr = db->blk;
8559 return BLOCK_CHANGED;
8560 }
8561 return 0;
8562}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008563
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008564/*
8565 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
8566 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008567 * Pass #3 assures that all directories are connected to the
8568 * filesystem tree, using the following algorithm:
8569 *
8570 * First, the root directory is checked to make sure it exists; if
8571 * not, e2fsck will offer to create a new one. It is then marked as
8572 * "done".
8573 *
8574 * Then, pass3 interates over all directory inodes; for each directory
8575 * it attempts to trace up the filesystem tree, using dirinfo.parent
8576 * until it reaches a directory which has been marked "done". If it
8577 * can not do so, then the directory must be disconnected, and e2fsck
8578 * will offer to reconnect it to /lost+found. While it is chasing
8579 * parent pointers up the filesystem tree, if pass3 sees a directory
8580 * twice, then it has detected a filesystem loop, and it will again
8581 * offer to reconnect the directory to /lost+found in to break the
8582 * filesystem loop.
8583 *
8584 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
8585 * reconnect inodes to /lost+found; this subroutine is also used by
8586 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
8587 * is responsible for creating /lost+found if it does not exist.
8588 *
8589 * Pass 3 frees the following data structures:
8590 * - The dirinfo directory information cache.
8591 */
8592
8593static void check_root(e2fsck_t ctx);
8594static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8595 struct problem_context *pctx);
8596static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
8597
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008598static ext2fs_inode_bitmap inode_loop_detect;
8599static ext2fs_inode_bitmap inode_done_map;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008600
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00008601static void e2fsck_pass3(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00008602{
8603 ext2_filsys fs = ctx->fs;
8604 int i;
8605#ifdef RESOURCE_TRACK
8606 struct resource_track rtrack;
8607#endif
8608 struct problem_context pctx;
8609 struct dir_info *dir;
8610 unsigned long maxdirs, count;
8611
8612#ifdef RESOURCE_TRACK
8613 init_resource_track(&rtrack);
8614#endif
8615
8616 clear_problem_context(&pctx);
8617
8618#ifdef MTRACE
8619 mtrace_print("Pass 3");
8620#endif
8621
8622 if (!(ctx->options & E2F_OPT_PREEN))
8623 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
8624
8625 /*
8626 * Allocate some bitmaps to do loop detection.
8627 */
8628 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
8629 &inode_done_map);
8630 if (pctx.errcode) {
8631 pctx.num = 2;
8632 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
8633 ctx->flags |= E2F_FLAG_ABORT;
8634 goto abort_exit;
8635 }
8636#ifdef RESOURCE_TRACK
8637 if (ctx->options & E2F_OPT_TIME) {
8638 e2fsck_clear_progbar(ctx);
8639 print_resource_track(_("Peak memory"), &ctx->global_rtrack);
8640 }
8641#endif
8642
8643 check_root(ctx);
8644 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8645 goto abort_exit;
8646
8647 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
8648
8649 maxdirs = e2fsck_get_num_dirinfo(ctx);
8650 count = 1;
8651
8652 if (ctx->progress)
8653 if ((ctx->progress)(ctx, 3, 0, maxdirs))
8654 goto abort_exit;
8655
8656 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
8657 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8658 goto abort_exit;
8659 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
8660 goto abort_exit;
8661 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
8662 if (check_directory(ctx, dir, &pctx))
8663 goto abort_exit;
8664 }
8665
8666 /*
8667 * Force the creation of /lost+found if not present
8668 */
8669 if ((ctx->flags & E2F_OPT_READONLY) == 0)
8670 e2fsck_get_lost_and_found(ctx, 1);
8671
8672 /*
8673 * If there are any directories that need to be indexed or
8674 * optimized, do it here.
8675 */
8676 e2fsck_rehash_directories(ctx);
8677
8678abort_exit:
8679 e2fsck_free_dir_info(ctx);
8680 if (inode_loop_detect) {
8681 ext2fs_free_inode_bitmap(inode_loop_detect);
8682 inode_loop_detect = 0;
8683 }
8684 if (inode_done_map) {
8685 ext2fs_free_inode_bitmap(inode_done_map);
8686 inode_done_map = 0;
8687 }
8688
8689#ifdef RESOURCE_TRACK
8690 if (ctx->options & E2F_OPT_TIME2) {
8691 e2fsck_clear_progbar(ctx);
8692 print_resource_track(_("Pass 3"), &rtrack);
8693 }
8694#endif
8695}
8696
8697/*
8698 * This makes sure the root inode is present; if not, we ask if the
8699 * user wants us to create it. Not creating it is a fatal error.
8700 */
8701static void check_root(e2fsck_t ctx)
8702{
8703 ext2_filsys fs = ctx->fs;
8704 blk_t blk;
8705 struct ext2_inode inode;
8706 char * block;
8707 struct problem_context pctx;
8708
8709 clear_problem_context(&pctx);
8710
8711 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
8712 /*
8713 * If the root inode is not a directory, die here. The
8714 * user must have answered 'no' in pass1 when we
8715 * offered to clear it.
8716 */
8717 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8718 EXT2_ROOT_INO))) {
8719 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
8720 ctx->flags |= E2F_FLAG_ABORT;
8721 }
8722 return;
8723 }
8724
8725 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
8726 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
8727 ctx->flags |= E2F_FLAG_ABORT;
8728 return;
8729 }
8730
8731 e2fsck_read_bitmaps(ctx);
8732
8733 /*
8734 * First, find a free block
8735 */
8736 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8737 if (pctx.errcode) {
8738 pctx.str = "ext2fs_new_block";
8739 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8740 ctx->flags |= E2F_FLAG_ABORT;
8741 return;
8742 }
8743 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8744 ext2fs_mark_block_bitmap(fs->block_map, blk);
8745 ext2fs_mark_bb_dirty(fs);
8746
8747 /*
8748 * Now let's create the actual data block for the inode
8749 */
8750 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
8751 &block);
8752 if (pctx.errcode) {
8753 pctx.str = "ext2fs_new_dir_block";
8754 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8755 ctx->flags |= E2F_FLAG_ABORT;
8756 return;
8757 }
8758
8759 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
8760 if (pctx.errcode) {
8761 pctx.str = "ext2fs_write_dir_block";
8762 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8763 ctx->flags |= E2F_FLAG_ABORT;
8764 return;
8765 }
8766 ext2fs_free_mem(&block);
8767
8768 /*
8769 * Set up the inode structure
8770 */
8771 memset(&inode, 0, sizeof(inode));
8772 inode.i_mode = 040755;
8773 inode.i_size = fs->blocksize;
8774 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8775 inode.i_links_count = 2;
8776 inode.i_blocks = fs->blocksize / 512;
8777 inode.i_block[0] = blk;
8778
8779 /*
8780 * Write out the inode.
8781 */
8782 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
8783 if (pctx.errcode) {
8784 pctx.str = "ext2fs_write_inode";
8785 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8786 ctx->flags |= E2F_FLAG_ABORT;
8787 return;
8788 }
8789
8790 /*
8791 * Miscellaneous bookkeeping...
8792 */
8793 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
8794 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
8795 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
8796
8797 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
8798 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
8799 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
8800 ext2fs_mark_ib_dirty(fs);
8801}
8802
8803/*
8804 * This subroutine is responsible for making sure that a particular
8805 * directory is connected to the root; if it isn't we trace it up as
8806 * far as we can go, and then offer to connect the resulting parent to
8807 * the lost+found. We have to do loop detection; if we ever discover
8808 * a loop, we treat that as a disconnected directory and offer to
8809 * reparent it to lost+found.
8810 *
8811 * However, loop detection is expensive, because for very large
8812 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
8813 * is non-trivial. Loops in filesystems are also a rare error case,
8814 * and we shouldn't optimize for error cases. So we try two passes of
8815 * the algorithm. The first time, we ignore loop detection and merely
8816 * increment a counter; if the counter exceeds some extreme threshold,
8817 * then we try again with the loop detection bitmap enabled.
8818 */
8819static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8820 struct problem_context *pctx)
8821{
8822 ext2_filsys fs = ctx->fs;
8823 struct dir_info *p = dir;
8824 int loop_pass = 0, parent_count = 0;
8825
8826 if (!p)
8827 return 0;
8828
8829 while (1) {
8830 /*
8831 * Mark this inode as being "done"; by the time we
8832 * return from this function, the inode we either be
8833 * verified as being connected to the directory tree,
8834 * or we will have offered to reconnect this to
8835 * lost+found.
8836 *
8837 * If it was marked done already, then we've reached a
8838 * parent we've already checked.
8839 */
8840 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
8841 break;
8842
8843 /*
8844 * If this directory doesn't have a parent, or we've
8845 * seen the parent once already, then offer to
8846 * reparent it to lost+found
8847 */
8848 if (!p->parent ||
8849 (loop_pass &&
8850 (ext2fs_test_inode_bitmap(inode_loop_detect,
8851 p->parent)))) {
8852 pctx->ino = p->ino;
8853 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
8854 if (e2fsck_reconnect_file(ctx, pctx->ino))
8855 ext2fs_unmark_valid(fs);
8856 else {
8857 p = e2fsck_get_dir_info(ctx, pctx->ino);
8858 p->parent = ctx->lost_and_found;
8859 fix_dotdot(ctx, p, ctx->lost_and_found);
8860 }
8861 }
8862 break;
8863 }
8864 p = e2fsck_get_dir_info(ctx, p->parent);
8865 if (!p) {
8866 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
8867 return 0;
8868 }
8869 if (loop_pass) {
8870 ext2fs_mark_inode_bitmap(inode_loop_detect,
8871 p->ino);
8872 } else if (parent_count++ > 2048) {
8873 /*
8874 * If we've run into a path depth that's
8875 * greater than 2048, try again with the inode
8876 * loop bitmap turned on and start from the
8877 * top.
8878 */
8879 loop_pass = 1;
8880 if (inode_loop_detect)
8881 ext2fs_clear_inode_bitmap(inode_loop_detect);
8882 else {
8883 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
8884 if (pctx->errcode) {
8885 pctx->num = 1;
8886 fix_problem(ctx,
8887 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
8888 ctx->flags |= E2F_FLAG_ABORT;
8889 return -1;
8890 }
8891 }
8892 p = dir;
8893 }
8894 }
8895
8896 /*
8897 * Make sure that .. and the parent directory are the same;
8898 * offer to fix it if not.
8899 */
8900 if (dir->parent != dir->dotdot) {
8901 pctx->ino = dir->ino;
8902 pctx->ino2 = dir->dotdot;
8903 pctx->dir = dir->parent;
8904 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
8905 fix_dotdot(ctx, dir, dir->parent);
8906 }
8907 return 0;
8908}
8909
8910/*
8911 * This routine gets the lost_and_found inode, making it a directory
8912 * if necessary
8913 */
8914ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
8915{
8916 ext2_filsys fs = ctx->fs;
8917 ext2_ino_t ino;
8918 blk_t blk;
8919 errcode_t retval;
8920 struct ext2_inode inode;
8921 char * block;
8922 static const char name[] = "lost+found";
8923 struct problem_context pctx;
8924 struct dir_info *dirinfo;
8925
8926 if (ctx->lost_and_found)
8927 return ctx->lost_and_found;
8928
8929 clear_problem_context(&pctx);
8930
8931 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
8932 sizeof(name)-1, 0, &ino);
8933 if (retval && !fix)
8934 return 0;
8935 if (!retval) {
8936 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
8937 ctx->lost_and_found = ino;
8938 return ino;
8939 }
8940
8941 /* Lost+found isn't a directory! */
8942 if (!fix)
8943 return 0;
8944 pctx.ino = ino;
8945 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
8946 return 0;
8947
8948 /* OK, unlink the old /lost+found file. */
8949 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
8950 if (pctx.errcode) {
8951 pctx.str = "ext2fs_unlink";
8952 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
8953 return 0;
8954 }
8955 dirinfo = e2fsck_get_dir_info(ctx, ino);
8956 if (dirinfo)
8957 dirinfo->parent = 0;
8958 e2fsck_adjust_inode_count(ctx, ino, -1);
8959 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
8960 pctx.errcode = retval;
8961 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
8962 }
8963 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
8964 return 0;
8965
8966 /*
8967 * Read the inode and block bitmaps in; we'll be messing with
8968 * them.
8969 */
8970 e2fsck_read_bitmaps(ctx);
8971
8972 /*
8973 * First, find a free block
8974 */
8975 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8976 if (retval) {
8977 pctx.errcode = retval;
8978 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
8979 return 0;
8980 }
8981 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8982 ext2fs_block_alloc_stats(fs, blk, +1);
8983
8984 /*
8985 * Next find a free inode.
8986 */
8987 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
8988 ctx->inode_used_map, &ino);
8989 if (retval) {
8990 pctx.errcode = retval;
8991 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
8992 return 0;
8993 }
8994 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
8995 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
8996 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
8997
8998 /*
8999 * Now let's create the actual data block for the inode
9000 */
9001 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
9002 if (retval) {
9003 pctx.errcode = retval;
9004 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
9005 return 0;
9006 }
9007
9008 retval = ext2fs_write_dir_block(fs, blk, block);
9009 ext2fs_free_mem(&block);
9010 if (retval) {
9011 pctx.errcode = retval;
9012 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
9013 return 0;
9014 }
9015
9016 /*
9017 * Set up the inode structure
9018 */
9019 memset(&inode, 0, sizeof(inode));
9020 inode.i_mode = 040700;
9021 inode.i_size = fs->blocksize;
9022 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
9023 inode.i_links_count = 2;
9024 inode.i_blocks = fs->blocksize / 512;
9025 inode.i_block[0] = blk;
9026
9027 /*
9028 * Next, write out the inode.
9029 */
9030 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
9031 if (pctx.errcode) {
9032 pctx.str = "ext2fs_write_inode";
9033 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9034 return 0;
9035 }
9036 /*
9037 * Finally, create the directory link
9038 */
9039 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
9040 if (pctx.errcode) {
9041 pctx.str = "ext2fs_link";
9042 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9043 return 0;
9044 }
9045
9046 /*
9047 * Miscellaneous bookkeeping that needs to be kept straight.
9048 */
9049 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
9050 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
9051 ext2fs_icount_store(ctx->inode_count, ino, 2);
9052 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
9053 ctx->lost_and_found = ino;
9054#if 0
9055 printf("/lost+found created; inode #%lu\n", ino);
9056#endif
9057 return ino;
9058}
9059
9060/*
9061 * This routine will connect a file to lost+found
9062 */
9063int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
9064{
9065 ext2_filsys fs = ctx->fs;
9066 errcode_t retval;
9067 char name[80];
9068 struct problem_context pctx;
9069 struct ext2_inode inode;
9070 int file_type = 0;
9071
9072 clear_problem_context(&pctx);
9073 pctx.ino = ino;
9074
9075 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
9076 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
9077 ctx->bad_lost_and_found++;
9078 }
9079 if (ctx->bad_lost_and_found) {
9080 fix_problem(ctx, PR_3_NO_LPF, &pctx);
9081 return 1;
9082 }
9083
9084 sprintf(name, "#%u", ino);
9085 if (ext2fs_read_inode(fs, ino, &inode) == 0)
9086 file_type = ext2_file_type(inode.i_mode);
9087 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
9088 if (retval == EXT2_ET_DIR_NO_SPACE) {
9089 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
9090 return 1;
9091 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
9092 1, 0);
9093 if (retval) {
9094 pctx.errcode = retval;
9095 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
9096 return 1;
9097 }
9098 retval = ext2fs_link(fs, ctx->lost_and_found, name,
9099 ino, file_type);
9100 }
9101 if (retval) {
9102 pctx.errcode = retval;
9103 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
9104 return 1;
9105 }
9106 e2fsck_adjust_inode_count(ctx, ino, 1);
9107
9108 return 0;
9109}
9110
9111/*
9112 * Utility routine to adjust the inode counts on an inode.
9113 */
9114errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
9115{
9116 ext2_filsys fs = ctx->fs;
9117 errcode_t retval;
9118 struct ext2_inode inode;
9119
9120 if (!ino)
9121 return 0;
9122
9123 retval = ext2fs_read_inode(fs, ino, &inode);
9124 if (retval)
9125 return retval;
9126
9127#if 0
9128 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
9129 inode.i_links_count);
9130#endif
9131
9132 if (adj == 1) {
9133 ext2fs_icount_increment(ctx->inode_count, ino, 0);
9134 if (inode.i_links_count == (__u16) ~0)
9135 return 0;
9136 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
9137 inode.i_links_count++;
9138 } else if (adj == -1) {
9139 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
9140 if (inode.i_links_count == 0)
9141 return 0;
9142 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
9143 inode.i_links_count--;
9144 }
9145
9146 retval = ext2fs_write_inode(fs, ino, &inode);
9147 if (retval)
9148 return retval;
9149
9150 return 0;
9151}
9152
9153/*
9154 * Fix parent --- this routine fixes up the parent of a directory.
9155 */
9156struct fix_dotdot_struct {
9157 ext2_filsys fs;
9158 ext2_ino_t parent;
9159 int done;
9160 e2fsck_t ctx;
9161};
9162
9163static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
9164 int offset EXT2FS_ATTR((unused)),
9165 int blocksize EXT2FS_ATTR((unused)),
9166 char *buf EXT2FS_ATTR((unused)),
9167 void *priv_data)
9168{
9169 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
9170 errcode_t retval;
9171 struct problem_context pctx;
9172
9173 if ((dirent->name_len & 0xFF) != 2)
9174 return 0;
9175 if (strncmp(dirent->name, "..", 2))
9176 return 0;
9177
9178 clear_problem_context(&pctx);
9179
9180 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
9181 if (retval) {
9182 pctx.errcode = retval;
9183 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9184 }
9185 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
9186 if (retval) {
9187 pctx.errcode = retval;
9188 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9189 }
9190 dirent->inode = fp->parent;
9191
9192 fp->done++;
9193 return DIRENT_ABORT | DIRENT_CHANGED;
9194}
9195
9196static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
9197{
9198 ext2_filsys fs = ctx->fs;
9199 errcode_t retval;
9200 struct fix_dotdot_struct fp;
9201 struct problem_context pctx;
9202
9203 fp.fs = fs;
9204 fp.parent = parent;
9205 fp.done = 0;
9206 fp.ctx = ctx;
9207
9208#if 0
9209 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
9210#endif
9211
9212 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
9213 0, fix_dotdot_proc, &fp);
9214 if (retval || !fp.done) {
9215 clear_problem_context(&pctx);
9216 pctx.ino = dir->ino;
9217 pctx.errcode = retval;
9218 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
9219 PR_3_FIX_PARENT_NOFIND, &pctx);
9220 ext2fs_unmark_valid(fs);
9221 }
9222 dir->dotdot = parent;
9223
9224 return;
9225}
9226
9227/*
9228 * These routines are responsible for expanding a /lost+found if it is
9229 * too small.
9230 */
9231
9232struct expand_dir_struct {
9233 int num;
9234 int guaranteed_size;
9235 int newblocks;
9236 int last_block;
9237 errcode_t err;
9238 e2fsck_t ctx;
9239};
9240
9241static int expand_dir_proc(ext2_filsys fs,
9242 blk_t *blocknr,
9243 e2_blkcnt_t blockcnt,
9244 blk_t ref_block EXT2FS_ATTR((unused)),
9245 int ref_offset EXT2FS_ATTR((unused)),
9246 void *priv_data)
9247{
9248 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
9249 blk_t new_blk;
9250 static blk_t last_blk = 0;
9251 char *block;
9252 errcode_t retval;
9253 e2fsck_t ctx;
9254
9255 ctx = es->ctx;
9256
9257 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
9258 return BLOCK_ABORT;
9259
9260 if (blockcnt > 0)
9261 es->last_block = blockcnt;
9262 if (*blocknr) {
9263 last_blk = *blocknr;
9264 return 0;
9265 }
9266 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
9267 &new_blk);
9268 if (retval) {
9269 es->err = retval;
9270 return BLOCK_ABORT;
9271 }
9272 if (blockcnt > 0) {
9273 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
9274 if (retval) {
9275 es->err = retval;
9276 return BLOCK_ABORT;
9277 }
9278 es->num--;
9279 retval = ext2fs_write_dir_block(fs, new_blk, block);
9280 } else {
9281 retval = ext2fs_get_mem(fs->blocksize, &block);
9282 if (retval) {
9283 es->err = retval;
9284 return BLOCK_ABORT;
9285 }
9286 memset(block, 0, fs->blocksize);
9287 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
9288 }
9289 if (retval) {
9290 es->err = retval;
9291 return BLOCK_ABORT;
9292 }
9293 ext2fs_free_mem(&block);
9294 *blocknr = new_blk;
9295 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
9296 ext2fs_block_alloc_stats(fs, new_blk, +1);
9297 es->newblocks++;
9298
9299 if (es->num == 0)
9300 return (BLOCK_CHANGED | BLOCK_ABORT);
9301 else
9302 return BLOCK_CHANGED;
9303}
9304
9305errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
9306 int num, int guaranteed_size)
9307{
9308 ext2_filsys fs = ctx->fs;
9309 errcode_t retval;
9310 struct expand_dir_struct es;
9311 struct ext2_inode inode;
9312
9313 if (!(fs->flags & EXT2_FLAG_RW))
9314 return EXT2_ET_RO_FILSYS;
9315
9316 /*
9317 * Read the inode and block bitmaps in; we'll be messing with
9318 * them.
9319 */
9320 e2fsck_read_bitmaps(ctx);
9321
9322 retval = ext2fs_check_directory(fs, dir);
9323 if (retval)
9324 return retval;
9325
9326 es.num = num;
9327 es.guaranteed_size = guaranteed_size;
9328 es.last_block = 0;
9329 es.err = 0;
9330 es.newblocks = 0;
9331 es.ctx = ctx;
9332
9333 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
9334 0, expand_dir_proc, &es);
9335
9336 if (es.err)
9337 return es.err;
9338
9339 /*
9340 * Update the size and block count fields in the inode.
9341 */
9342 retval = ext2fs_read_inode(fs, dir, &inode);
9343 if (retval)
9344 return retval;
9345
9346 inode.i_size = (es.last_block + 1) * fs->blocksize;
9347 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
9348
9349 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
9350
9351 return 0;
9352}
9353
9354/*
9355 * pass4.c -- pass #4 of e2fsck: Check reference counts
9356 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009357 * Pass 4 frees the following data structures:
9358 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
9359 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
9360 */
9361
9362/*
9363 * This routine is called when an inode is not connected to the
9364 * directory tree.
9365 *
9366 * This subroutine returns 1 then the caller shouldn't bother with the
9367 * rest of the pass 4 tests.
9368 */
9369static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
9370{
9371 ext2_filsys fs = ctx->fs;
9372 struct ext2_inode inode;
9373 struct problem_context pctx;
9374
9375 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
9376 clear_problem_context(&pctx);
9377 pctx.ino = i;
9378 pctx.inode = &inode;
9379
9380 /*
9381 * Offer to delete any zero-length files that does not have
9382 * blocks. If there is an EA block, it might have useful
9383 * information, so we won't prompt to delete it, but let it be
9384 * reconnected to lost+found.
9385 */
9386 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
9387 LINUX_S_ISDIR(inode.i_mode))) {
9388 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
9389 ext2fs_icount_store(ctx->inode_link_info, i, 0);
9390 inode.i_links_count = 0;
9391 inode.i_dtime = time(0);
9392 e2fsck_write_inode(ctx, i, &inode,
9393 "disconnect_inode");
9394 /*
9395 * Fix up the bitmaps...
9396 */
9397 e2fsck_read_bitmaps(ctx);
9398 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
9399 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
9400 ext2fs_inode_alloc_stats2(fs, i, -1,
9401 LINUX_S_ISDIR(inode.i_mode));
9402 return 0;
9403 }
9404 }
9405
9406 /*
9407 * Prompt to reconnect.
9408 */
9409 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
9410 if (e2fsck_reconnect_file(ctx, i))
9411 ext2fs_unmark_valid(fs);
9412 } else {
9413 /*
9414 * If we don't attach the inode, then skip the
9415 * i_links_test since there's no point in trying to
9416 * force i_links_count to zero.
9417 */
9418 ext2fs_unmark_valid(fs);
9419 return 1;
9420 }
9421 return 0;
9422}
9423
9424
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009425static void e2fsck_pass4(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009426{
9427 ext2_filsys fs = ctx->fs;
9428 ext2_ino_t i;
9429 struct ext2_inode inode;
9430#ifdef RESOURCE_TRACK
9431 struct resource_track rtrack;
9432#endif
9433 struct problem_context pctx;
9434 __u16 link_count, link_counted;
9435 char *buf = 0;
9436 int group, maxgroup;
9437
9438#ifdef RESOURCE_TRACK
9439 init_resource_track(&rtrack);
9440#endif
9441
9442#ifdef MTRACE
9443 mtrace_print("Pass 4");
9444#endif
9445
9446 clear_problem_context(&pctx);
9447
9448 if (!(ctx->options & E2F_OPT_PREEN))
9449 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
9450
9451 group = 0;
9452 maxgroup = fs->group_desc_count;
9453 if (ctx->progress)
9454 if ((ctx->progress)(ctx, 4, 0, maxgroup))
9455 return;
9456
9457 for (i=1; i <= fs->super->s_inodes_count; i++) {
9458 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9459 return;
9460 if ((i % fs->super->s_inodes_per_group) == 0) {
9461 group++;
9462 if (ctx->progress)
9463 if ((ctx->progress)(ctx, 4, group, maxgroup))
9464 return;
9465 }
9466 if (i == EXT2_BAD_INO ||
9467 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
9468 continue;
9469 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
9470 (ctx->inode_imagic_map &&
9471 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
9472 (ctx->inode_bb_map &&
9473 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
9474 continue;
9475 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
9476 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
9477 if (link_counted == 0) {
9478 if (!buf)
9479 buf = e2fsck_allocate_memory(ctx,
9480 fs->blocksize, "bad_inode buffer");
9481 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
9482 continue;
9483 if (disconnect_inode(ctx, i))
9484 continue;
9485 ext2fs_icount_fetch(ctx->inode_link_info, i,
9486 &link_count);
9487 ext2fs_icount_fetch(ctx->inode_count, i,
9488 &link_counted);
9489 }
9490 if (link_counted != link_count) {
9491 e2fsck_read_inode(ctx, i, &inode, "pass4");
9492 pctx.ino = i;
9493 pctx.inode = &inode;
9494 if (link_count != inode.i_links_count) {
9495 pctx.num = link_count;
9496 fix_problem(ctx,
9497 PR_4_INCONSISTENT_COUNT, &pctx);
9498 }
9499 pctx.num = link_counted;
9500 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
9501 inode.i_links_count = link_counted;
9502 e2fsck_write_inode(ctx, i, &inode, "pass4");
9503 }
9504 }
9505 }
9506 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
9507 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
9508 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
9509 ctx->inode_bb_map = 0;
9510 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
9511 ctx->inode_imagic_map = 0;
9512 if (buf)
9513 ext2fs_free_mem(&buf);
9514#ifdef RESOURCE_TRACK
9515 if (ctx->options & E2F_OPT_TIME2) {
9516 e2fsck_clear_progbar(ctx);
9517 print_resource_track(_("Pass 4"), &rtrack);
9518 }
9519#endif
9520}
9521
9522/*
9523 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009524 */
9525
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +00009526#define NO_BLK ((blk_t) -1)
9527
9528static void print_bitmap_problem(e2fsck_t ctx, int problem,
9529 struct problem_context *pctx)
9530{
9531 switch (problem) {
9532 case PR_5_BLOCK_UNUSED:
9533 if (pctx->blk == pctx->blk2)
9534 pctx->blk2 = 0;
9535 else
9536 problem = PR_5_BLOCK_RANGE_UNUSED;
9537 break;
9538 case PR_5_BLOCK_USED:
9539 if (pctx->blk == pctx->blk2)
9540 pctx->blk2 = 0;
9541 else
9542 problem = PR_5_BLOCK_RANGE_USED;
9543 break;
9544 case PR_5_INODE_UNUSED:
9545 if (pctx->ino == pctx->ino2)
9546 pctx->ino2 = 0;
9547 else
9548 problem = PR_5_INODE_RANGE_UNUSED;
9549 break;
9550 case PR_5_INODE_USED:
9551 if (pctx->ino == pctx->ino2)
9552 pctx->ino2 = 0;
9553 else
9554 problem = PR_5_INODE_RANGE_USED;
9555 break;
9556 }
9557 fix_problem(ctx, problem, pctx);
9558 pctx->blk = pctx->blk2 = NO_BLK;
9559 pctx->ino = pctx->ino2 = 0;
9560}
9561
9562static void check_block_bitmaps(e2fsck_t ctx)
9563{
9564 ext2_filsys fs = ctx->fs;
9565 blk_t i;
9566 int *free_array;
9567 int group = 0;
9568 unsigned int blocks = 0;
9569 unsigned int free_blocks = 0;
9570 int group_free = 0;
9571 int actual, bitmap;
9572 struct problem_context pctx;
9573 int problem, save_problem, fixit, had_problem;
9574 errcode_t retval;
9575
9576 clear_problem_context(&pctx);
9577 free_array = (int *) e2fsck_allocate_memory(ctx,
9578 fs->group_desc_count * sizeof(int), "free block count array");
9579
9580 if ((fs->super->s_first_data_block <
9581 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
9582 (fs->super->s_blocks_count-1 >
9583 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
9584 pctx.num = 1;
9585 pctx.blk = fs->super->s_first_data_block;
9586 pctx.blk2 = fs->super->s_blocks_count -1;
9587 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
9588 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
9589 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9590
9591 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9592 return;
9593 }
9594
9595 if ((fs->super->s_first_data_block <
9596 ext2fs_get_block_bitmap_start(fs->block_map)) ||
9597 (fs->super->s_blocks_count-1 >
9598 ext2fs_get_block_bitmap_end(fs->block_map))) {
9599 pctx.num = 2;
9600 pctx.blk = fs->super->s_first_data_block;
9601 pctx.blk2 = fs->super->s_blocks_count -1;
9602 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
9603 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
9604 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9605
9606 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9607 return;
9608 }
9609
9610redo_counts:
9611 had_problem = 0;
9612 save_problem = 0;
9613 pctx.blk = pctx.blk2 = NO_BLK;
9614 for (i = fs->super->s_first_data_block;
9615 i < fs->super->s_blocks_count;
9616 i++) {
9617 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
9618 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
9619
9620 if (actual == bitmap)
9621 goto do_counts;
9622
9623 if (!actual && bitmap) {
9624 /*
9625 * Block not used, but marked in use in the bitmap.
9626 */
9627 problem = PR_5_BLOCK_UNUSED;
9628 } else {
9629 /*
9630 * Block used, but not marked in use in the bitmap.
9631 */
9632 problem = PR_5_BLOCK_USED;
9633 }
9634 if (pctx.blk == NO_BLK) {
9635 pctx.blk = pctx.blk2 = i;
9636 save_problem = problem;
9637 } else {
9638 if ((problem == save_problem) &&
9639 (pctx.blk2 == i-1))
9640 pctx.blk2++;
9641 else {
9642 print_bitmap_problem(ctx, save_problem, &pctx);
9643 pctx.blk = pctx.blk2 = i;
9644 save_problem = problem;
9645 }
9646 }
9647 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9648 had_problem++;
9649
9650 do_counts:
9651 if (!bitmap) {
9652 group_free++;
9653 free_blocks++;
9654 }
9655 blocks ++;
9656 if ((blocks == fs->super->s_blocks_per_group) ||
9657 (i == fs->super->s_blocks_count-1)) {
9658 free_array[group] = group_free;
9659 group ++;
9660 blocks = 0;
9661 group_free = 0;
9662 if (ctx->progress)
9663 if ((ctx->progress)(ctx, 5, group,
9664 fs->group_desc_count*2))
9665 return;
9666 }
9667 }
9668 if (pctx.blk != NO_BLK)
9669 print_bitmap_problem(ctx, save_problem, &pctx);
9670 if (had_problem)
9671 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
9672 else
9673 fixit = -1;
9674 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9675
9676 if (fixit == 1) {
9677 ext2fs_free_block_bitmap(fs->block_map);
9678 retval = ext2fs_copy_bitmap(ctx->block_found_map,
9679 &fs->block_map);
9680 if (retval) {
9681 clear_problem_context(&pctx);
9682 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
9683 ctx->flags |= E2F_FLAG_ABORT;
9684 return;
9685 }
9686 ext2fs_set_bitmap_padding(fs->block_map);
9687 ext2fs_mark_bb_dirty(fs);
9688
9689 /* Redo the counts */
9690 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
9691 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9692 goto redo_counts;
9693 } else if (fixit == 0)
9694 ext2fs_unmark_valid(fs);
9695
9696 for (i = 0; i < fs->group_desc_count; i++) {
9697 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
9698 pctx.group = i;
9699 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
9700 pctx.blk2 = free_array[i];
9701
9702 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
9703 &pctx)) {
9704 fs->group_desc[i].bg_free_blocks_count =
9705 free_array[i];
9706 ext2fs_mark_super_dirty(fs);
9707 } else
9708 ext2fs_unmark_valid(fs);
9709 }
9710 }
9711 if (free_blocks != fs->super->s_free_blocks_count) {
9712 pctx.group = 0;
9713 pctx.blk = fs->super->s_free_blocks_count;
9714 pctx.blk2 = free_blocks;
9715
9716 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
9717 fs->super->s_free_blocks_count = free_blocks;
9718 ext2fs_mark_super_dirty(fs);
9719 } else
9720 ext2fs_unmark_valid(fs);
9721 }
9722 ext2fs_free_mem(&free_array);
9723}
9724
9725static void check_inode_bitmaps(e2fsck_t ctx)
9726{
9727 ext2_filsys fs = ctx->fs;
9728 ext2_ino_t i;
9729 unsigned int free_inodes = 0;
9730 int group_free = 0;
9731 int dirs_count = 0;
9732 int group = 0;
9733 unsigned int inodes = 0;
9734 int *free_array;
9735 int *dir_array;
9736 int actual, bitmap;
9737 errcode_t retval;
9738 struct problem_context pctx;
9739 int problem, save_problem, fixit, had_problem;
9740
9741 clear_problem_context(&pctx);
9742 free_array = (int *) e2fsck_allocate_memory(ctx,
9743 fs->group_desc_count * sizeof(int), "free inode count array");
9744
9745 dir_array = (int *) e2fsck_allocate_memory(ctx,
9746 fs->group_desc_count * sizeof(int), "directory count array");
9747
9748 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
9749 (fs->super->s_inodes_count >
9750 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
9751 pctx.num = 3;
9752 pctx.blk = 1;
9753 pctx.blk2 = fs->super->s_inodes_count;
9754 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
9755 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
9756 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9757
9758 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9759 return;
9760 }
9761 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
9762 (fs->super->s_inodes_count >
9763 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
9764 pctx.num = 4;
9765 pctx.blk = 1;
9766 pctx.blk2 = fs->super->s_inodes_count;
9767 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
9768 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
9769 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9770
9771 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9772 return;
9773 }
9774
9775redo_counts:
9776 had_problem = 0;
9777 save_problem = 0;
9778 pctx.ino = pctx.ino2 = 0;
9779 for (i = 1; i <= fs->super->s_inodes_count; i++) {
9780 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
9781 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
9782
9783 if (actual == bitmap)
9784 goto do_counts;
9785
9786 if (!actual && bitmap) {
9787 /*
9788 * Inode wasn't used, but marked in bitmap
9789 */
9790 problem = PR_5_INODE_UNUSED;
9791 } else /* if (actual && !bitmap) */ {
9792 /*
9793 * Inode used, but not in bitmap
9794 */
9795 problem = PR_5_INODE_USED;
9796 }
9797 if (pctx.ino == 0) {
9798 pctx.ino = pctx.ino2 = i;
9799 save_problem = problem;
9800 } else {
9801 if ((problem == save_problem) &&
9802 (pctx.ino2 == i-1))
9803 pctx.ino2++;
9804 else {
9805 print_bitmap_problem(ctx, save_problem, &pctx);
9806 pctx.ino = pctx.ino2 = i;
9807 save_problem = problem;
9808 }
9809 }
9810 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9811 had_problem++;
9812
9813do_counts:
9814 if (!bitmap) {
9815 group_free++;
9816 free_inodes++;
9817 } else {
9818 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
9819 dirs_count++;
9820 }
9821 inodes++;
9822 if ((inodes == fs->super->s_inodes_per_group) ||
9823 (i == fs->super->s_inodes_count)) {
9824 free_array[group] = group_free;
9825 dir_array[group] = dirs_count;
9826 group ++;
9827 inodes = 0;
9828 group_free = 0;
9829 dirs_count = 0;
9830 if (ctx->progress)
9831 if ((ctx->progress)(ctx, 5,
9832 group + fs->group_desc_count,
9833 fs->group_desc_count*2))
9834 return;
9835 }
9836 }
9837 if (pctx.ino)
9838 print_bitmap_problem(ctx, save_problem, &pctx);
9839
9840 if (had_problem)
9841 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
9842 else
9843 fixit = -1;
9844 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9845
9846 if (fixit == 1) {
9847 ext2fs_free_inode_bitmap(fs->inode_map);
9848 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
9849 &fs->inode_map);
9850 if (retval) {
9851 clear_problem_context(&pctx);
9852 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
9853 ctx->flags |= E2F_FLAG_ABORT;
9854 return;
9855 }
9856 ext2fs_set_bitmap_padding(fs->inode_map);
9857 ext2fs_mark_ib_dirty(fs);
9858
9859 /* redo counts */
9860 inodes = 0; free_inodes = 0; group_free = 0;
9861 dirs_count = 0; group = 0;
9862 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9863 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
9864 goto redo_counts;
9865 } else if (fixit == 0)
9866 ext2fs_unmark_valid(fs);
9867
9868 for (i = 0; i < fs->group_desc_count; i++) {
9869 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
9870 pctx.group = i;
9871 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
9872 pctx.ino2 = free_array[i];
9873 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
9874 &pctx)) {
9875 fs->group_desc[i].bg_free_inodes_count =
9876 free_array[i];
9877 ext2fs_mark_super_dirty(fs);
9878 } else
9879 ext2fs_unmark_valid(fs);
9880 }
9881 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
9882 pctx.group = i;
9883 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
9884 pctx.ino2 = dir_array[i];
9885
9886 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
9887 &pctx)) {
9888 fs->group_desc[i].bg_used_dirs_count =
9889 dir_array[i];
9890 ext2fs_mark_super_dirty(fs);
9891 } else
9892 ext2fs_unmark_valid(fs);
9893 }
9894 }
9895 if (free_inodes != fs->super->s_free_inodes_count) {
9896 pctx.group = -1;
9897 pctx.ino = fs->super->s_free_inodes_count;
9898 pctx.ino2 = free_inodes;
9899
9900 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
9901 fs->super->s_free_inodes_count = free_inodes;
9902 ext2fs_mark_super_dirty(fs);
9903 } else
9904 ext2fs_unmark_valid(fs);
9905 }
9906 ext2fs_free_mem(&free_array);
9907 ext2fs_free_mem(&dir_array);
9908}
9909
9910static void check_inode_end(e2fsck_t ctx)
9911{
9912 ext2_filsys fs = ctx->fs;
9913 ext2_ino_t end, save_inodes_count, i;
9914 struct problem_context pctx;
9915
9916 clear_problem_context(&pctx);
9917
9918 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
9919 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
9920 &save_inodes_count);
9921 if (pctx.errcode) {
9922 pctx.num = 1;
9923 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9924 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9925 return;
9926 }
9927 if (save_inodes_count == end)
9928 return;
9929
9930 for (i = save_inodes_count + 1; i <= end; i++) {
9931 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
9932 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
9933 for (i = save_inodes_count + 1; i <= end; i++)
9934 ext2fs_mark_inode_bitmap(fs->inode_map,
9935 i);
9936 ext2fs_mark_ib_dirty(fs);
9937 } else
9938 ext2fs_unmark_valid(fs);
9939 break;
9940 }
9941 }
9942
9943 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
9944 save_inodes_count, 0);
9945 if (pctx.errcode) {
9946 pctx.num = 2;
9947 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9948 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9949 return;
9950 }
9951}
9952
9953static void check_block_end(e2fsck_t ctx)
9954{
9955 ext2_filsys fs = ctx->fs;
9956 blk_t end, save_blocks_count, i;
9957 struct problem_context pctx;
9958
9959 clear_problem_context(&pctx);
9960
9961 end = fs->block_map->start +
9962 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
9963 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
9964 &save_blocks_count);
9965 if (pctx.errcode) {
9966 pctx.num = 3;
9967 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9968 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9969 return;
9970 }
9971 if (save_blocks_count == end)
9972 return;
9973
9974 for (i = save_blocks_count + 1; i <= end; i++) {
9975 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
9976 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
9977 for (i = save_blocks_count + 1; i <= end; i++)
9978 ext2fs_mark_block_bitmap(fs->block_map,
9979 i);
9980 ext2fs_mark_bb_dirty(fs);
9981 } else
9982 ext2fs_unmark_valid(fs);
9983 break;
9984 }
9985 }
9986
9987 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
9988 save_blocks_count, 0);
9989 if (pctx.errcode) {
9990 pctx.num = 4;
9991 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
9992 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9993 return;
9994 }
9995}
9996
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +00009997static void e2fsck_pass5(e2fsck_t ctx)
9998{
9999#ifdef RESOURCE_TRACK
10000 struct resource_track rtrack;
10001#endif
10002 struct problem_context pctx;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010003
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010004#ifdef MTRACE
10005 mtrace_print("Pass 5");
10006#endif
10007
10008#ifdef RESOURCE_TRACK
10009 init_resource_track(&rtrack);
10010#endif
10011
10012 clear_problem_context(&pctx);
10013
10014 if (!(ctx->options & E2F_OPT_PREEN))
10015 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
10016
10017 if (ctx->progress)
10018 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
10019 return;
10020
10021 e2fsck_read_bitmaps(ctx);
10022
10023 check_block_bitmaps(ctx);
10024 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10025 return;
10026 check_inode_bitmaps(ctx);
10027 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10028 return;
10029 check_inode_end(ctx);
10030 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10031 return;
10032 check_block_end(ctx);
10033 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
10034 return;
10035
10036 ext2fs_free_inode_bitmap(ctx->inode_used_map);
10037 ctx->inode_used_map = 0;
10038 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
10039 ctx->inode_dir_map = 0;
10040 ext2fs_free_block_bitmap(ctx->block_found_map);
10041 ctx->block_found_map = 0;
10042
10043#ifdef RESOURCE_TRACK
10044 if (ctx->options & E2F_OPT_TIME2) {
10045 e2fsck_clear_progbar(ctx);
10046 print_resource_track(_("Pass 5"), &rtrack);
10047 }
10048#endif
10049}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010050
10051/*
10052 * problem.c --- report filesystem problems to the user
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010053 */
10054
10055#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
10056#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
10057#define PR_NO_DEFAULT 0x000004 /* Default to no */
10058#define PR_MSG_ONLY 0x000008 /* Print message only */
10059
10060/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
10061
10062#define PR_FATAL 0x001000 /* Fatal error */
10063#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
10064 /* ask another */
10065#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
10066#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
10067#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
10068#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
10069#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
10070
10071
10072#define PROMPT_NONE 0
10073#define PROMPT_FIX 1
10074#define PROMPT_CLEAR 2
10075#define PROMPT_RELOCATE 3
10076#define PROMPT_ALLOCATE 4
10077#define PROMPT_EXPAND 5
10078#define PROMPT_CONNECT 6
10079#define PROMPT_CREATE 7
10080#define PROMPT_SALVAGE 8
10081#define PROMPT_TRUNCATE 9
10082#define PROMPT_CLEAR_INODE 10
10083#define PROMPT_ABORT 11
10084#define PROMPT_SPLIT 12
10085#define PROMPT_CONTINUE 13
10086#define PROMPT_CLONE 14
10087#define PROMPT_DELETE 15
10088#define PROMPT_SUPPRESS 16
10089#define PROMPT_UNLINK 17
10090#define PROMPT_CLEAR_HTREE 18
10091#define PROMPT_RECREATE 19
10092#define PROMPT_NULL 20
10093
10094struct e2fsck_problem {
10095 problem_t e2p_code;
10096 const char * e2p_description;
10097 char prompt;
10098 int flags;
10099 problem_t second_code;
10100};
10101
10102struct latch_descr {
10103 int latch_code;
10104 problem_t question;
10105 problem_t end_message;
10106 int flags;
10107};
10108
10109/*
10110 * These are the prompts which are used to ask the user if they want
10111 * to fix a problem.
10112 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010113static const char * const prompt[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010114 N_("(no prompt)"), /* 0 */
10115 N_("Fix"), /* 1 */
10116 N_("Clear"), /* 2 */
10117 N_("Relocate"), /* 3 */
10118 N_("Allocate"), /* 4 */
10119 N_("Expand"), /* 5 */
10120 N_("Connect to /lost+found"), /* 6 */
10121 N_("Create"), /* 7 */
10122 N_("Salvage"), /* 8 */
10123 N_("Truncate"), /* 9 */
10124 N_("Clear inode"), /* 10 */
10125 N_("Abort"), /* 11 */
10126 N_("Split"), /* 12 */
10127 N_("Continue"), /* 13 */
10128 N_("Clone duplicate/bad blocks"), /* 14 */
10129 N_("Delete file"), /* 15 */
10130 N_("Suppress messages"),/* 16 */
10131 N_("Unlink"), /* 17 */
10132 N_("Clear HTree index"),/* 18 */
10133 N_("Recreate"), /* 19 */
10134 "", /* 20 */
10135};
10136
10137/*
10138 * These messages are printed when we are preen mode and we will be
10139 * automatically fixing the problem.
10140 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000010141static const char * const preen_msg[] = {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000010142 N_("(NONE)"), /* 0 */
10143 N_("FIXED"), /* 1 */
10144 N_("CLEARED"), /* 2 */
10145 N_("RELOCATED"), /* 3 */
10146 N_("ALLOCATED"), /* 4 */
10147 N_("EXPANDED"), /* 5 */
10148 N_("RECONNECTED"), /* 6 */
10149 N_("CREATED"), /* 7 */
10150 N_("SALVAGED"), /* 8 */
10151 N_("TRUNCATED"), /* 9 */
10152 N_("INODE CLEARED"), /* 10 */
10153 N_("ABORTED"), /* 11 */
10154 N_("SPLIT"), /* 12 */
10155 N_("CONTINUING"), /* 13 */
10156 N_("DUPLICATE/BAD BLOCKS CLONED"), /* 14 */
10157 N_("FILE DELETED"), /* 15 */
10158 N_("SUPPRESSED"), /* 16 */
10159 N_("UNLINKED"), /* 17 */
10160 N_("HTREE INDEX CLEARED"),/* 18 */
10161 N_("WILL RECREATE"), /* 19 */
10162 "", /* 20 */
10163};
10164
10165static const struct e2fsck_problem problem_table[] = {
10166
10167 /* Pre-Pass 1 errors */
10168
10169 /* Block bitmap not in group */
10170 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
10171 PROMPT_RELOCATE, PR_LATCH_RELOC },
10172
10173 /* Inode bitmap not in group */
10174 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
10175 PROMPT_RELOCATE, PR_LATCH_RELOC },
10176
10177 /* Inode table not in group */
10178 { PR_0_ITABLE_NOT_GROUP,
10179 N_("@i table for @g %g is not in @g. (@b %b)\n"
10180 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
10181 PROMPT_RELOCATE, PR_LATCH_RELOC },
10182
10183 /* Superblock corrupt */
10184 { PR_0_SB_CORRUPT,
10185 N_("\nThe @S could not be read or does not describe a correct ext2\n"
10186 "@f. If the @v is valid and it really contains an ext2\n"
10187 "@f (and not swap or ufs or something else), then the @S\n"
10188 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
10189 " e2fsck -b %S <@v>\n\n"),
10190 PROMPT_NONE, PR_FATAL },
10191
10192 /* Filesystem size is wrong */
10193 { PR_0_FS_SIZE_WRONG,
10194 N_("The @f size (according to the @S) is %b @bs\n"
10195 "The physical size of the @v is %c @bs\n"
10196 "Either the @S or the partition table is likely to be corrupt!\n"),
10197 PROMPT_ABORT, 0 },
10198
10199 /* Fragments not supported */
10200 { PR_0_NO_FRAGMENTS,
10201 N_("@S @b_size = %b, fragsize = %c.\n"
10202 "This version of e2fsck does not support fragment sizes different\n"
10203 "from the @b size.\n"),
10204 PROMPT_NONE, PR_FATAL },
10205
10206 /* Bad blocks_per_group */
10207 { PR_0_BLOCKS_PER_GROUP,
10208 N_("@S @bs_per_group = %b, should have been %c\n"),
10209 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10210
10211 /* Bad first_data_block */
10212 { PR_0_FIRST_DATA_BLOCK,
10213 N_("@S first_data_@b = %b, should have been %c\n"),
10214 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10215
10216 /* Adding UUID to filesystem */
10217 { PR_0_ADD_UUID,
10218 N_("@f did not have a UUID; generating one.\n\n"),
10219 PROMPT_NONE, 0 },
10220
10221 /* Relocate hint */
10222 { PR_0_RELOCATE_HINT,
10223 N_("Note: if there is several inode or block bitmap blocks\n"
10224 "which require relocation, or one part of the inode table\n"
10225 "which must be moved, you may wish to try running e2fsck\n"
10226 "with the '-b %S' option first. The problem may lie only\n"
10227 "with the primary block group descriptor, and the backup\n"
10228 "block group descriptor may be OK.\n\n"),
10229 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
10230
10231 /* Miscellaneous superblock corruption */
10232 { PR_0_MISC_CORRUPT_SUPER,
10233 N_("Corruption found in @S. (%s = %N).\n"),
10234 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10235
10236 /* Error determing physical device size of filesystem */
10237 { PR_0_GETSIZE_ERROR,
10238 N_("Error determining size of the physical @v: %m\n"),
10239 PROMPT_NONE, PR_FATAL },
10240
10241 /* Inode count in superblock is incorrect */
10242 { PR_0_INODE_COUNT_WRONG,
10243 N_("@i count in @S is %i, should be %j.\n"),
10244 PROMPT_FIX, 0 },
10245
10246 { PR_0_HURD_CLEAR_FILETYPE,
10247 N_("The Hurd does not support the filetype feature.\n"),
10248 PROMPT_CLEAR, 0 },
10249
10250 /* Journal inode is invalid */
10251 { PR_0_JOURNAL_BAD_INODE,
10252 N_("@S has a bad ext3 @j (@i %i).\n"),
10253 PROMPT_CLEAR, PR_PREEN_OK },
10254
10255 /* The external journal has (unsupported) multiple filesystems */
10256 { PR_0_JOURNAL_UNSUPP_MULTIFS,
10257 N_("External @j has multiple @f users (unsupported).\n"),
10258 PROMPT_NONE, PR_FATAL },
10259
10260 /* Can't find external journal */
10261 { PR_0_CANT_FIND_JOURNAL,
10262 N_("Can't find external @j\n"),
10263 PROMPT_NONE, PR_FATAL },
10264
10265 /* External journal has bad superblock */
10266 { PR_0_EXT_JOURNAL_BAD_SUPER,
10267 N_("External @j has bad @S\n"),
10268 PROMPT_NONE, PR_FATAL },
10269
10270 /* Superblock has a bad journal UUID */
10271 { PR_0_JOURNAL_BAD_UUID,
10272 N_("External @j does not support this @f\n"),
10273 PROMPT_NONE, PR_FATAL },
10274
10275 /* Journal has an unknown superblock type */
10276 { PR_0_JOURNAL_UNSUPP_SUPER,
10277 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
10278 "It is likely that your copy of e2fsck is old and/or doesn't "
10279 "support this @j format.\n"
10280 "It is also possible the @j @S is corrupt.\n"),
10281 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
10282
10283 /* Journal superblock is corrupt */
10284 { PR_0_JOURNAL_BAD_SUPER,
10285 N_("Ext3 @j @S is corrupt.\n"),
10286 PROMPT_FIX, PR_PREEN_OK },
10287
10288 /* Superblock flag should be cleared */
10289 { PR_0_JOURNAL_HAS_JOURNAL,
10290 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
10291 PROMPT_CLEAR, PR_PREEN_OK },
10292
10293 /* Superblock flag is incorrect */
10294 { PR_0_JOURNAL_RECOVER_SET,
10295 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
10296 PROMPT_CLEAR, PR_PREEN_OK },
10297
10298 /* Journal has data, but recovery flag is clear */
10299 { PR_0_JOURNAL_RECOVERY_CLEAR,
10300 N_("ext3 recovery flag clear, but @j has data.\n"),
10301 PROMPT_NONE, 0 },
10302
10303 /* Ask if we should clear the journal */
10304 { PR_0_JOURNAL_RESET_JOURNAL,
10305 N_("Clear @j"),
10306 PROMPT_NULL, PR_PREEN_NOMSG },
10307
10308 /* Ask if we should run the journal anyway */
10309 { PR_0_JOURNAL_RUN,
10310 N_("Run @j anyway"),
10311 PROMPT_NULL, 0 },
10312
10313 /* Run the journal by default */
10314 { PR_0_JOURNAL_RUN_DEFAULT,
10315 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
10316 PROMPT_NONE, 0 },
10317
10318 /* Clearing orphan inode */
10319 { PR_0_ORPHAN_CLEAR_INODE,
10320 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
10321 PROMPT_NONE, 0 },
10322
10323 /* Illegal block found in orphaned inode */
10324 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
10325 N_("@I @b #%B (%b) found in @o @i %i.\n"),
10326 PROMPT_NONE, 0 },
10327
10328 /* Already cleared block found in orphaned inode */
10329 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
10330 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
10331 PROMPT_NONE, 0 },
10332
10333 /* Illegal orphan inode in superblock */
10334 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
10335 N_("@I @o @i %i in @S.\n"),
10336 PROMPT_NONE, 0 },
10337
10338 /* Illegal inode in orphaned inode list */
10339 { PR_0_ORPHAN_ILLEGAL_INODE,
10340 N_("@I @i %i in @o @i list.\n"),
10341 PROMPT_NONE, 0 },
10342
10343 /* Filesystem revision is 0, but feature flags are set */
10344 { PR_0_FS_REV_LEVEL,
10345 "@f has feature flag(s) set, but is a revision 0 @f. ",
10346 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10347
10348 /* Journal superblock has an unknown read-only feature flag set */
10349 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
10350 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
10351 PROMPT_ABORT, 0 },
10352
10353 /* Journal superblock has an unknown incompatible feature flag set */
10354 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
10355 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
10356 PROMPT_ABORT, 0 },
10357
10358 /* Journal has unsupported version number */
10359 { PR_0_JOURNAL_UNSUPP_VERSION,
10360 N_("@j version not supported by this e2fsck.\n"),
10361 PROMPT_ABORT, 0 },
10362
10363 /* Moving journal to hidden file */
10364 { PR_0_MOVE_JOURNAL,
10365 N_("Moving @j from /%s to hidden inode.\n\n"),
10366 PROMPT_NONE, 0 },
10367
10368 /* Error moving journal to hidden file */
10369 { PR_0_ERR_MOVE_JOURNAL,
10370 N_("Error moving @j: %m\n\n"),
10371 PROMPT_NONE, 0 },
10372
10373 /* Clearing V2 journal superblock */
10374 { PR_0_CLEAR_V2_JOURNAL,
10375 N_("Found invalid V2 @j @S fields (from V1 journal).\n"
10376 "Clearing fields beyond the V1 @j @S...\n\n"),
10377 PROMPT_NONE, 0 },
10378
10379 /* Backup journal inode blocks */
10380 { PR_0_BACKUP_JNL,
10381 N_("Backing up @j @i @b information.\n\n"),
10382 PROMPT_NONE, 0 },
10383
10384 /* Reserved blocks w/o resize_inode */
10385 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
10386 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
10387 "is %N; @s zero. "),
10388 PROMPT_FIX, 0 },
10389
10390 /* Resize_inode not enabled, but resize inode is non-zero */
10391 { PR_0_CLEAR_RESIZE_INODE,
10392 N_("Resize_@i not enabled, but the resize inode is non-zero. "),
10393 PROMPT_CLEAR, 0 },
10394
10395 /* Resize inode invalid */
10396 { PR_0_RESIZE_INODE_INVALID,
10397 N_("Resize @i not valid. "),
10398 PROMPT_RECREATE, 0 },
10399
10400 /* Pass 1 errors */
10401
10402 /* Pass 1: Checking inodes, blocks, and sizes */
10403 { PR_1_PASS_HEADER,
10404 N_("Pass 1: Checking @is, @bs, and sizes\n"),
10405 PROMPT_NONE, 0 },
10406
10407 /* Root directory is not an inode */
10408 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
10409 PROMPT_CLEAR, 0 },
10410
10411 /* Root directory has dtime set */
10412 { PR_1_ROOT_DTIME,
10413 N_("@r has dtime set (probably due to old mke2fs). "),
10414 PROMPT_FIX, PR_PREEN_OK },
10415
10416 /* Reserved inode has bad mode */
10417 { PR_1_RESERVED_BAD_MODE,
10418 N_("Reserved @i %i %Q has bad mode. "),
10419 PROMPT_CLEAR, PR_PREEN_OK },
10420
10421 /* Deleted inode has zero dtime */
10422 { PR_1_ZERO_DTIME,
10423 N_("@D @i %i has zero dtime. "),
10424 PROMPT_FIX, PR_PREEN_OK },
10425
10426 /* Inode in use, but dtime set */
10427 { PR_1_SET_DTIME,
10428 N_("@i %i is in use, but has dtime set. "),
10429 PROMPT_FIX, PR_PREEN_OK },
10430
10431 /* Zero-length directory */
10432 { PR_1_ZERO_LENGTH_DIR,
10433 N_("@i %i is a @z @d. "),
10434 PROMPT_CLEAR, PR_PREEN_OK },
10435
10436 /* Block bitmap conflicts with some other fs block */
10437 { PR_1_BB_CONFLICT,
10438 N_("@g %g's @b @B at %b @C.\n"),
10439 PROMPT_RELOCATE, 0 },
10440
10441 /* Inode bitmap conflicts with some other fs block */
10442 { PR_1_IB_CONFLICT,
10443 N_("@g %g's @i @B at %b @C.\n"),
10444 PROMPT_RELOCATE, 0 },
10445
10446 /* Inode table conflicts with some other fs block */
10447 { PR_1_ITABLE_CONFLICT,
10448 N_("@g %g's @i table at %b @C.\n"),
10449 PROMPT_RELOCATE, 0 },
10450
10451 /* Block bitmap is on a bad block */
10452 { PR_1_BB_BAD_BLOCK,
10453 N_("@g %g's @b @B (%b) is bad. "),
10454 PROMPT_RELOCATE, 0 },
10455
10456 /* Inode bitmap is on a bad block */
10457 { PR_1_IB_BAD_BLOCK,
10458 N_("@g %g's @i @B (%b) is bad. "),
10459 PROMPT_RELOCATE, 0 },
10460
10461 /* Inode has incorrect i_size */
10462 { PR_1_BAD_I_SIZE,
10463 N_("@i %i, i_size is %Is, @s %N. "),
10464 PROMPT_FIX, PR_PREEN_OK },
10465
10466 /* Inode has incorrect i_blocks */
10467 { PR_1_BAD_I_BLOCKS,
10468 N_("@i %i, i_@bs is %Ib, @s %N. "),
10469 PROMPT_FIX, PR_PREEN_OK },
10470
10471 /* Illegal blocknumber in inode */
10472 { PR_1_ILLEGAL_BLOCK_NUM,
10473 N_("@I @b #%B (%b) in @i %i. "),
10474 PROMPT_CLEAR, PR_LATCH_BLOCK },
10475
10476 /* Block number overlaps fs metadata */
10477 { PR_1_BLOCK_OVERLAPS_METADATA,
10478 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
10479 PROMPT_CLEAR, PR_LATCH_BLOCK },
10480
10481 /* Inode has illegal blocks (latch question) */
10482 { PR_1_INODE_BLOCK_LATCH,
10483 N_("@i %i has illegal @b(s). "),
10484 PROMPT_CLEAR, 0 },
10485
10486 /* Too many bad blocks in inode */
10487 { PR_1_TOO_MANY_BAD_BLOCKS,
10488 N_("Too many illegal @bs in @i %i.\n"),
10489 PROMPT_CLEAR_INODE, PR_NO_OK },
10490
10491 /* Illegal block number in bad block inode */
10492 { PR_1_BB_ILLEGAL_BLOCK_NUM,
10493 N_("@I @b #%B (%b) in bad @b @i. "),
10494 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10495
10496 /* Bad block inode has illegal blocks (latch question) */
10497 { PR_1_INODE_BBLOCK_LATCH,
10498 N_("Bad @b @i has illegal @b(s). "),
10499 PROMPT_CLEAR, 0 },
10500
10501 /* Duplicate or bad blocks in use! */
10502 { PR_1_DUP_BLOCKS_PREENSTOP,
10503 N_("Duplicate or bad @b in use!\n"),
10504 PROMPT_NONE, 0 },
10505
10506 /* Bad block used as bad block indirect block */
10507 { PR_1_BBINODE_BAD_METABLOCK,
10508 N_("Bad @b %b used as bad @b @i indirect @b. "),
10509 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10510
10511 /* Inconsistency can't be fixed prompt */
10512 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
10513 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
10514 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
10515 "in the @f.\n"),
10516 PROMPT_CONTINUE, PR_PREEN_NOMSG },
10517
10518 /* Bad primary block */
10519 { PR_1_BAD_PRIMARY_BLOCK,
10520 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
10521 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
10522
10523 /* Bad primary block prompt */
10524 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
10525 N_("You can clear the this @b (and hope for the best) from the\n"
10526 "bad @b list and hope that @b is really OK, but there are no\n"
10527 "guarantees.\n\n"),
10528 PROMPT_CLEAR, PR_PREEN_NOMSG },
10529
10530 /* Bad primary superblock */
10531 { PR_1_BAD_PRIMARY_SUPERBLOCK,
10532 N_("The primary @S (%b) is on the bad @b list.\n"),
10533 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10534
10535 /* Bad primary block group descriptors */
10536 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
10537 N_("Block %b in the primary @g descriptors "
10538 "is on the bad @b list\n"),
10539 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10540
10541 /* Bad superblock in group */
10542 { PR_1_BAD_SUPERBLOCK,
10543 N_("Warning: Group %g's @S (%b) is bad.\n"),
10544 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10545
10546 /* Bad block group descriptors in group */
10547 { PR_1_BAD_GROUP_DESCRIPTORS,
10548 N_("Warning: Group %g's copy of the @g descriptors has a bad "
10549 "@b (%b).\n"),
10550 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10551
10552 /* Block claimed for no reason */
10553 { PR_1_PROGERR_CLAIMED_BLOCK,
10554 N_("Programming error? @b #%b claimed for no reason in "
10555 "process_bad_@b.\n"),
10556 PROMPT_NONE, PR_PREEN_OK },
10557
10558 /* Error allocating blocks for relocating metadata */
10559 { PR_1_RELOC_BLOCK_ALLOCATE,
10560 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
10561 PROMPT_NONE, PR_PREEN_OK },
10562
10563 /* Error allocating block buffer during relocation process */
10564 { PR_1_RELOC_MEMORY_ALLOCATE,
10565 N_("@A @b buffer for relocating %s\n"),
10566 PROMPT_NONE, PR_PREEN_OK },
10567
10568 /* Relocating metadata group information from X to Y */
10569 { PR_1_RELOC_FROM_TO,
10570 N_("Relocating @g %g's %s from %b to %c...\n"),
10571 PROMPT_NONE, PR_PREEN_OK },
10572
10573 /* Relocating metatdata group information to X */
10574 { PR_1_RELOC_TO,
10575 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
10576 PROMPT_NONE, PR_PREEN_OK },
10577
10578 /* Block read error during relocation process */
10579 { PR_1_RELOC_READ_ERR,
10580 N_("Warning: could not read @b %b of %s: %m\n"),
10581 PROMPT_NONE, PR_PREEN_OK },
10582
10583 /* Block write error during relocation process */
10584 { PR_1_RELOC_WRITE_ERR,
10585 N_("Warning: could not write @b %b for %s: %m\n"),
10586 PROMPT_NONE, PR_PREEN_OK },
10587
10588 /* Error allocating inode bitmap */
10589 { PR_1_ALLOCATE_IBITMAP_ERROR,
10590 "@A @i @B (%N): %m\n",
10591 PROMPT_NONE, PR_FATAL },
10592
10593 /* Error allocating block bitmap */
10594 { PR_1_ALLOCATE_BBITMAP_ERROR,
10595 "@A @b @B (%N): %m\n",
10596 PROMPT_NONE, PR_FATAL },
10597
10598 /* Error allocating icount structure */
10599 { PR_1_ALLOCATE_ICOUNT,
10600 N_("@A icount link information: %m\n"),
10601 PROMPT_NONE, PR_FATAL },
10602
10603 /* Error allocating dbcount */
10604 { PR_1_ALLOCATE_DBCOUNT,
10605 N_("@A @d @b array: %m\n"),
10606 PROMPT_NONE, PR_FATAL },
10607
10608 /* Error while scanning inodes */
10609 { PR_1_ISCAN_ERROR,
10610 N_("Error while scanning @is (%i): %m\n"),
10611 PROMPT_NONE, PR_FATAL },
10612
10613 /* Error while iterating over blocks */
10614 { PR_1_BLOCK_ITERATE,
10615 N_("Error while iterating over @bs in @i %i: %m\n"),
10616 PROMPT_NONE, PR_FATAL },
10617
10618 /* Error while storing inode count information */
10619 { PR_1_ICOUNT_STORE,
10620 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
10621 PROMPT_NONE, PR_FATAL },
10622
10623 /* Error while storing directory block information */
10624 { PR_1_ADD_DBLOCK,
10625 N_("Error storing @d @b information "
10626 "(@i=%i, @b=%b, num=%N): %m\n"),
10627 PROMPT_NONE, PR_FATAL },
10628
10629 /* Error while reading inode (for clearing) */
10630 { PR_1_READ_INODE,
10631 N_("Error reading @i %i: %m\n"),
10632 PROMPT_NONE, PR_FATAL },
10633
10634 /* Suppress messages prompt */
10635 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
10636
10637 /* Imagic flag set on an inode when filesystem doesn't support it */
10638 { PR_1_SET_IMAGIC,
10639 N_("@i %i has imagic flag set. "),
10640 PROMPT_CLEAR, 0 },
10641
10642 /* Immutable flag set on a device or socket inode */
10643 { PR_1_SET_IMMUTABLE,
10644 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
10645 "or append-only flag set. "),
10646 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
10647
10648 /* Compression flag set on an inode when filesystem doesn't support it */
10649 { PR_1_COMPR_SET,
10650 N_("@i %i has @cion flag set on @f without @cion support. "),
10651 PROMPT_CLEAR, 0 },
10652
10653 /* Non-zero size for device, fifo or socket inode */
10654 { PR_1_SET_NONZSIZE,
10655 "Special (@v/socket/fifo) @i %i has non-zero size. ",
10656 PROMPT_FIX, PR_PREEN_OK },
10657
10658 /* Filesystem revision is 0, but feature flags are set */
10659 { PR_1_FS_REV_LEVEL,
10660 "@f has feature flag(s) set, but is a revision 0 @f. ",
10661 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10662
10663 /* Journal inode is not in use, but contains data */
10664 { PR_1_JOURNAL_INODE_NOT_CLEAR,
10665 "@j @i is not in use, but contains data. ",
10666 PROMPT_CLEAR, PR_PREEN_OK },
10667
10668 /* Journal has bad mode */
10669 { PR_1_JOURNAL_BAD_MODE,
10670 N_("@j is not regular file. "),
10671 PROMPT_FIX, PR_PREEN_OK },
10672
10673 /* Deal with inodes that were part of orphan linked list */
10674 { PR_1_LOW_DTIME,
10675 N_("@i %i was part of the orphaned @i list. "),
10676 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
10677
10678 /* Deal with inodes that were part of corrupted orphan linked
10679 list (latch question) */
10680 { PR_1_ORPHAN_LIST_REFUGEES,
10681 N_("@is that were part of a corrupted orphan linked list found. "),
10682 PROMPT_FIX, 0 },
10683
10684 /* Error allocating refcount structure */
10685 { PR_1_ALLOCATE_REFCOUNT,
10686 "@A refcount structure (%N): %m\n",
10687 PROMPT_NONE, PR_FATAL },
10688
10689 /* Error reading extended attribute block */
10690 { PR_1_READ_EA_BLOCK,
10691 N_("Error reading @a @b %b for @i %i. "),
10692 PROMPT_CLEAR, 0 },
10693
10694 /* Invalid extended attribute block */
10695 { PR_1_BAD_EA_BLOCK,
10696 N_("@i %i has a bad @a @b %b. "),
10697 PROMPT_CLEAR, 0 },
10698
10699 /* Error reading Extended Attribute block while fixing refcount */
10700 { PR_1_EXTATTR_READ_ABORT,
10701 N_("Error reading @a @b %b (%m). "),
10702 PROMPT_ABORT, 0 },
10703
10704 /* Extended attribute reference count incorrect */
10705 { PR_1_EXTATTR_REFCOUNT,
10706 N_("@a @b %b has reference count %B, should be %N. "),
10707 PROMPT_FIX, 0 },
10708
10709 /* Error writing Extended Attribute block while fixing refcount */
10710 { PR_1_EXTATTR_WRITE,
10711 N_("Error writing @a @b %b (%m). "),
10712 PROMPT_ABORT, 0 },
10713
10714 /* Multiple EA blocks not supported */
10715 { PR_1_EA_MULTI_BLOCK,
10716 N_("@a @b %b has h_blocks > 1. "),
10717 PROMPT_CLEAR, 0},
10718
10719 /* Error allocating EA region allocation structure */
10720 { PR_1_EA_ALLOC_REGION,
10721 N_("Error allocating @a @b %b. "),
10722 PROMPT_ABORT, 0},
10723
10724 /* Error EA allocation collision */
10725 { PR_1_EA_ALLOC_COLLISION,
10726 N_("@a @b %b is corrupt (allocation collision). "),
10727 PROMPT_CLEAR, 0},
10728
10729 /* Bad extended attribute name */
10730 { PR_1_EA_BAD_NAME,
10731 N_("@a @b %b is corrupt (invalid name). "),
10732 PROMPT_CLEAR, 0},
10733
10734 /* Bad extended attribute value */
10735 { PR_1_EA_BAD_VALUE,
10736 N_("@a @b %b is corrupt (invalid value). "),
10737 PROMPT_CLEAR, 0},
10738
10739 /* Inode too big (latch question) */
10740 { PR_1_INODE_TOOBIG,
10741 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
10742
10743 /* Directory too big */
10744 { PR_1_TOOBIG_DIR,
10745 N_("@b #%B (%b) causes @d to be too big. "),
10746 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10747
10748 /* Regular file too big */
10749 { PR_1_TOOBIG_REG,
10750 N_("@b #%B (%b) causes file to be too big. "),
10751 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10752
10753 /* Symlink too big */
10754 { PR_1_TOOBIG_SYMLINK,
10755 N_("@b #%B (%b) causes symlink to be too big. "),
10756 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10757
10758 /* INDEX_FL flag set on a non-HTREE filesystem */
10759 { PR_1_HTREE_SET,
10760 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
10761 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10762
10763 /* INDEX_FL flag set on a non-directory */
10764 { PR_1_HTREE_NODIR,
10765 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
10766 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10767
10768 /* Invalid root node in HTREE directory */
10769 { PR_1_HTREE_BADROOT,
10770 N_("@h %i has an invalid root node.\n"),
10771 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10772
10773 /* Unsupported hash version in HTREE directory */
10774 { PR_1_HTREE_HASHV,
10775 N_("@h %i has an unsupported hash version (%N)\n"),
10776 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10777
10778 /* Incompatible flag in HTREE root node */
10779 { PR_1_HTREE_INCOMPAT,
10780 N_("@h %i uses an incompatible htree root node flag.\n"),
10781 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10782
10783 /* HTREE too deep */
10784 { PR_1_HTREE_DEPTH,
10785 N_("@h %i has a tree depth (%N) which is too big\n"),
10786 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10787
10788 /* Bad block has indirect block that conflicts with filesystem block */
10789 { PR_1_BB_FS_BLOCK,
10790 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
10791 "@f metadata. "),
10792 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10793
10794 /* Resize inode failed */
10795 { PR_1_RESIZE_INODE_CREATE,
10796 N_("Resize @i (re)creation failed: %m."),
10797 PROMPT_ABORT, 0 },
10798
10799 /* invalid inode->i_extra_isize */
10800 { PR_1_EXTRA_ISIZE,
10801 N_("@i %i has a extra size (%IS) which is invalid\n"),
10802 PROMPT_FIX, PR_PREEN_OK },
10803
10804 /* invalid ea entry->e_name_len */
10805 { PR_1_ATTR_NAME_LEN,
10806 N_("@a in @i %i has a namelen (%N) which is invalid\n"),
10807 PROMPT_CLEAR, PR_PREEN_OK },
10808
10809 /* invalid ea entry->e_value_size */
10810 { PR_1_ATTR_VALUE_SIZE,
10811 N_("@a in @i %i has a value size (%N) which is invalid\n"),
10812 PROMPT_CLEAR, PR_PREEN_OK },
10813
10814 /* invalid ea entry->e_value_offs */
10815 { PR_1_ATTR_VALUE_OFFSET,
10816 N_("@a in @i %i has a value offset (%N) which is invalid\n"),
10817 PROMPT_CLEAR, PR_PREEN_OK },
10818
10819 /* invalid ea entry->e_value_block */
10820 { PR_1_ATTR_VALUE_BLOCK,
10821 N_("@a in @i %i has a value block (%N) which is invalid (must be 0)\n"),
10822 PROMPT_CLEAR, PR_PREEN_OK },
10823
10824 /* invalid ea entry->e_hash */
10825 { PR_1_ATTR_HASH,
10826 N_("@a in @i %i has a hash (%N) which is invalid (must be 0)\n"),
10827 PROMPT_CLEAR, PR_PREEN_OK },
10828
10829 /* Pass 1b errors */
10830
10831 /* Pass 1B: Rescan for duplicate/bad blocks */
10832 { PR_1B_PASS_HEADER,
10833 N_("Duplicate @bs found... invoking duplicate @b passes.\n"
10834 "Pass 1B: Rescan for duplicate/bad @bs\n"),
10835 PROMPT_NONE, 0 },
10836
10837 /* Duplicate/bad block(s) header */
10838 { PR_1B_DUP_BLOCK_HEADER,
10839 N_("Duplicate/bad @b(s) in @i %i:"),
10840 PROMPT_NONE, 0 },
10841
10842 /* Duplicate/bad block(s) in inode */
10843 { PR_1B_DUP_BLOCK,
10844 " %b",
10845 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
10846
10847 /* Duplicate/bad block(s) end */
10848 { PR_1B_DUP_BLOCK_END,
10849 "\n",
10850 PROMPT_NONE, PR_PREEN_NOHDR },
10851
10852 /* Error while scanning inodes */
10853 { PR_1B_ISCAN_ERROR,
10854 N_("Error while scanning inodes (%i): %m\n"),
10855 PROMPT_NONE, PR_FATAL },
10856
10857 /* Error allocating inode bitmap */
10858 { PR_1B_ALLOCATE_IBITMAP_ERROR,
10859 N_("@A @i @B (inode_dup_map): %m\n"),
10860 PROMPT_NONE, PR_FATAL },
10861
10862 /* Error while iterating over blocks */
10863 { PR_1B_BLOCK_ITERATE,
10864 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
10865 PROMPT_NONE, 0 },
10866
10867 /* Error adjusting EA refcount */
10868 { PR_1B_ADJ_EA_REFCOUNT,
10869 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
10870 PROMPT_NONE, 0 },
10871
10872
10873 /* Pass 1C: Scan directories for inodes with dup blocks. */
10874 { PR_1C_PASS_HEADER,
10875 N_("Pass 1C: Scan directories for @is with dup @bs.\n"),
10876 PROMPT_NONE, 0 },
10877
10878
10879 /* Pass 1D: Reconciling duplicate blocks */
10880 { PR_1D_PASS_HEADER,
10881 N_("Pass 1D: Reconciling duplicate @bs\n"),
10882 PROMPT_NONE, 0 },
10883
10884 /* File has duplicate blocks */
10885 { PR_1D_DUP_FILE,
10886 N_("File %Q (@i #%i, mod time %IM) \n"
10887 " has %B duplicate @b(s), shared with %N file(s):\n"),
10888 PROMPT_NONE, 0 },
10889
10890 /* List of files sharing duplicate blocks */
10891 { PR_1D_DUP_FILE_LIST,
10892 N_("\t%Q (@i #%i, mod time %IM)\n"),
10893 PROMPT_NONE, 0 },
10894
10895 /* File sharing blocks with filesystem metadata */
10896 { PR_1D_SHARE_METADATA,
10897 N_("\t<@f metadata>\n"),
10898 PROMPT_NONE, 0 },
10899
10900 /* Report of how many duplicate/bad inodes */
10901 { PR_1D_NUM_DUP_INODES,
10902 N_("(There are %N @is containing duplicate/bad @bs.)\n\n"),
10903 PROMPT_NONE, 0 },
10904
10905 /* Duplicated blocks already reassigned or cloned. */
10906 { PR_1D_DUP_BLOCKS_DEALT,
10907 N_("Duplicated @bs already reassigned or cloned.\n\n"),
10908 PROMPT_NONE, 0 },
10909
10910 /* Clone duplicate/bad blocks? */
10911 { PR_1D_CLONE_QUESTION,
10912 "", PROMPT_CLONE, PR_NO_OK },
10913
10914 /* Delete file? */
10915 { PR_1D_DELETE_QUESTION,
10916 "", PROMPT_DELETE, 0 },
10917
10918 /* Couldn't clone file (error) */
10919 { PR_1D_CLONE_ERROR,
10920 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
10921
10922 /* Pass 2 errors */
10923
10924 /* Pass 2: Checking directory structure */
10925 { PR_2_PASS_HEADER,
10926 N_("Pass 2: Checking @d structure\n"),
10927 PROMPT_NONE, 0 },
10928
10929 /* Bad inode number for '.' */
10930 { PR_2_BAD_INODE_DOT,
10931 N_("Bad @i number for '.' in @d @i %i.\n"),
10932 PROMPT_FIX, 0 },
10933
10934 /* Directory entry has bad inode number */
10935 { PR_2_BAD_INO,
10936 N_("@E has bad @i #: %Di.\n"),
10937 PROMPT_CLEAR, 0 },
10938
10939 /* Directory entry has deleted or unused inode */
10940 { PR_2_UNUSED_INODE,
10941 N_("@E has @D/unused @i %Di. "),
10942 PROMPT_CLEAR, PR_PREEN_OK },
10943
10944 /* Directry entry is link to '.' */
10945 { PR_2_LINK_DOT,
10946 N_("@E @L to '.' "),
10947 PROMPT_CLEAR, 0 },
10948
10949 /* Directory entry points to inode now located in a bad block */
10950 { PR_2_BB_INODE,
10951 N_("@E points to @i (%Di) located in a bad @b.\n"),
10952 PROMPT_CLEAR, 0 },
10953
10954 /* Directory entry contains a link to a directory */
10955 { PR_2_LINK_DIR,
10956 N_("@E @L to @d %P (%Di).\n"),
10957 PROMPT_CLEAR, 0 },
10958
10959 /* Directory entry contains a link to the root directry */
10960 { PR_2_LINK_ROOT,
10961 N_("@E @L to the @r.\n"),
10962 PROMPT_CLEAR, 0 },
10963
10964 /* Directory entry has illegal characters in its name */
10965 { PR_2_BAD_NAME,
10966 N_("@E has illegal characters in its name.\n"),
10967 PROMPT_FIX, 0 },
10968
10969 /* Missing '.' in directory inode */
10970 { PR_2_MISSING_DOT,
10971 N_("Missing '.' in @d @i %i.\n"),
10972 PROMPT_FIX, 0 },
10973
10974 /* Missing '..' in directory inode */
10975 { PR_2_MISSING_DOT_DOT,
10976 N_("Missing '..' in @d @i %i.\n"),
10977 PROMPT_FIX, 0 },
10978
10979 /* First entry in directory inode doesn't contain '.' */
10980 { PR_2_1ST_NOT_DOT,
10981 N_("First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n"),
10982 PROMPT_FIX, 0 },
10983
10984 /* Second entry in directory inode doesn't contain '..' */
10985 { PR_2_2ND_NOT_DOT_DOT,
10986 N_("Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n"),
10987 PROMPT_FIX, 0 },
10988
10989 /* i_faddr should be zero */
10990 { PR_2_FADDR_ZERO,
10991 N_("i_faddr @F %IF, @s zero.\n"),
10992 PROMPT_CLEAR, 0 },
10993
10994 /* i_file_acl should be zero */
10995 { PR_2_FILE_ACL_ZERO,
10996 N_("i_file_acl @F %If, @s zero.\n"),
10997 PROMPT_CLEAR, 0 },
10998
10999 /* i_dir_acl should be zero */
11000 { PR_2_DIR_ACL_ZERO,
11001 N_("i_dir_acl @F %Id, @s zero.\n"),
11002 PROMPT_CLEAR, 0 },
11003
11004 /* i_frag should be zero */
11005 { PR_2_FRAG_ZERO,
11006 N_("i_frag @F %N, @s zero.\n"),
11007 PROMPT_CLEAR, 0 },
11008
11009 /* i_fsize should be zero */
11010 { PR_2_FSIZE_ZERO,
11011 N_("i_fsize @F %N, @s zero.\n"),
11012 PROMPT_CLEAR, 0 },
11013
11014 /* inode has bad mode */
11015 { PR_2_BAD_MODE,
11016 N_("@i %i (%Q) has a bad mode (%Im).\n"),
11017 PROMPT_CLEAR, 0 },
11018
11019 /* directory corrupted */
11020 { PR_2_DIR_CORRUPTED,
11021 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
11022 PROMPT_SALVAGE, 0 },
11023
11024 /* filename too long */
11025 { PR_2_FILENAME_LONG,
11026 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
11027 PROMPT_TRUNCATE, 0 },
11028
11029 /* Directory inode has a missing block (hole) */
11030 { PR_2_DIRECTORY_HOLE,
11031 N_("@d @i %i has an unallocated @b #%B. "),
11032 PROMPT_ALLOCATE, 0 },
11033
11034 /* '.' is not NULL terminated */
11035 { PR_2_DOT_NULL_TERM,
11036 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
11037 PROMPT_FIX, 0 },
11038
11039 /* '..' is not NULL terminated */
11040 { PR_2_DOT_DOT_NULL_TERM,
11041 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
11042 PROMPT_FIX, 0 },
11043
11044 /* Illegal character device inode */
11045 { PR_2_BAD_CHAR_DEV,
11046 N_("@i %i (%Q) is an @I character @v.\n"),
11047 PROMPT_CLEAR, 0 },
11048
11049 /* Illegal block device inode */
11050 { PR_2_BAD_BLOCK_DEV,
11051 N_("@i %i (%Q) is an @I @b @v.\n"),
11052 PROMPT_CLEAR, 0 },
11053
11054 /* Duplicate '.' entry */
11055 { PR_2_DUP_DOT,
11056 N_("@E is duplicate '.' @e.\n"),
11057 PROMPT_FIX, 0 },
11058
11059 /* Duplicate '..' entry */
11060 { PR_2_DUP_DOT_DOT,
11061 N_("@E is duplicate '..' @e.\n"),
11062 PROMPT_FIX, 0 },
11063
11064 /* Internal error: couldn't find dir_info */
11065 { PR_2_NO_DIRINFO,
11066 N_("Internal error: couldn't find dir_info for %i.\n"),
11067 PROMPT_NONE, PR_FATAL },
11068
11069 /* Final rec_len is wrong */
11070 { PR_2_FINAL_RECLEN,
11071 N_("@E has rec_len of %Dr, should be %N.\n"),
11072 PROMPT_FIX, 0 },
11073
11074 /* Error allocating icount structure */
11075 { PR_2_ALLOCATE_ICOUNT,
11076 N_("@A icount structure: %m\n"),
11077 PROMPT_NONE, PR_FATAL },
11078
11079 /* Error iterating over directory blocks */
11080 { PR_2_DBLIST_ITERATE,
11081 N_("Error iterating over @d @bs: %m\n"),
11082 PROMPT_NONE, PR_FATAL },
11083
11084 /* Error reading directory block */
11085 { PR_2_READ_DIRBLOCK,
11086 N_("Error reading @d @b %b (@i %i): %m\n"),
11087 PROMPT_CONTINUE, 0 },
11088
11089 /* Error writing directory block */
11090 { PR_2_WRITE_DIRBLOCK,
11091 N_("Error writing @d @b %b (@i %i): %m\n"),
11092 PROMPT_CONTINUE, 0 },
11093
11094 /* Error allocating new directory block */
11095 { PR_2_ALLOC_DIRBOCK,
11096 N_("@A new @d @b for @i %i (%s): %m\n"),
11097 PROMPT_NONE, 0 },
11098
11099 /* Error deallocating inode */
11100 { PR_2_DEALLOC_INODE,
11101 N_("Error deallocating @i %i: %m\n"),
11102 PROMPT_NONE, PR_FATAL },
11103
11104 /* Directory entry for '.' is big. Split? */
11105 { PR_2_SPLIT_DOT,
11106 N_("@d @e for '.' is big. "),
11107 PROMPT_SPLIT, PR_NO_OK },
11108
11109 /* Illegal FIFO inode */
11110 { PR_2_BAD_FIFO,
11111 N_("@i %i (%Q) is an @I FIFO.\n"),
11112 PROMPT_CLEAR, 0 },
11113
11114 /* Illegal socket inode */
11115 { PR_2_BAD_SOCKET,
11116 N_("@i %i (%Q) is an @I socket.\n"),
11117 PROMPT_CLEAR, 0 },
11118
11119 /* Directory filetype not set */
11120 { PR_2_SET_FILETYPE,
11121 N_("Setting filetype for @E to %N.\n"),
11122 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
11123
11124 /* Directory filetype incorrect */
11125 { PR_2_BAD_FILETYPE,
11126 N_("@E has an incorrect filetype (was %Dt, should be %N).\n"),
11127 PROMPT_FIX, 0 },
11128
11129 /* Directory filetype set on filesystem */
11130 { PR_2_CLEAR_FILETYPE,
11131 N_("@E has filetype set.\n"),
11132 PROMPT_CLEAR, PR_PREEN_OK },
11133
11134 /* Directory filename is null */
11135 { PR_2_NULL_NAME,
11136 N_("@E has a zero-length name.\n"),
11137 PROMPT_CLEAR, 0 },
11138
11139 /* Invalid symlink */
11140 { PR_2_INVALID_SYMLINK,
11141 N_("Symlink %Q (@i #%i) is invalid.\n"),
11142 PROMPT_CLEAR, 0 },
11143
11144 /* i_file_acl (extended attribute block) is bad */
11145 { PR_2_FILE_ACL_BAD,
11146 N_("@a @b @F invalid (%If).\n"),
11147 PROMPT_CLEAR, 0 },
11148
11149 /* Filesystem contains large files, but has no such flag in sb */
11150 { PR_2_FEATURE_LARGE_FILES,
11151 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
11152 PROMPT_FIX, 0 },
11153
11154 /* Node in HTREE directory not referenced */
11155 { PR_2_HTREE_NOTREF,
11156 N_("@p @h %d: node (%B) not referenced\n"),
11157 PROMPT_NONE, 0 },
11158
11159 /* Node in HTREE directory referenced twice */
11160 { PR_2_HTREE_DUPREF,
11161 N_("@p @h %d: node (%B) referenced twice\n"),
11162 PROMPT_NONE, 0 },
11163
11164 /* Node in HTREE directory has bad min hash */
11165 { PR_2_HTREE_MIN_HASH,
11166 N_("@p @h %d: node (%B) has bad min hash\n"),
11167 PROMPT_NONE, 0 },
11168
11169 /* Node in HTREE directory has bad max hash */
11170 { PR_2_HTREE_MAX_HASH,
11171 N_("@p @h %d: node (%B) has bad max hash\n"),
11172 PROMPT_NONE, 0 },
11173
11174 /* Clear invalid HTREE directory */
11175 { PR_2_HTREE_CLEAR,
11176 N_("Invalid @h %d (%q). "), PROMPT_CLEAR, 0 },
11177
11178 /* Bad block in htree interior node */
11179 { PR_2_HTREE_BADBLK,
11180 N_("@p @h %d (%q): bad @b number %b.\n"),
11181 PROMPT_CLEAR_HTREE, 0 },
11182
11183 /* Error adjusting EA refcount */
11184 { PR_2_ADJ_EA_REFCOUNT,
11185 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
11186 PROMPT_NONE, PR_FATAL },
11187
11188 /* Invalid HTREE root node */
11189 { PR_2_HTREE_BAD_ROOT,
11190 N_("@p @h %d: root node is invalid\n"),
11191 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11192
11193 /* Invalid HTREE limit */
11194 { PR_2_HTREE_BAD_LIMIT,
11195 N_("@p @h %d: node (%B) has bad limit (%N)\n"),
11196 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11197
11198 /* Invalid HTREE count */
11199 { PR_2_HTREE_BAD_COUNT,
11200 N_("@p @h %d: node (%B) has bad count (%N)\n"),
11201 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11202
11203 /* HTREE interior node has out-of-order hashes in table */
11204 { PR_2_HTREE_HASH_ORDER,
11205 N_("@p @h %d: node (%B) has an unordered hash table\n"),
11206 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11207
11208 /* Node in HTREE directory has bad depth */
11209 { PR_2_HTREE_BAD_DEPTH,
11210 N_("@p @h %d: node (%B) has bad depth\n"),
11211 PROMPT_NONE, 0 },
11212
11213 /* Duplicate directory entry found */
11214 { PR_2_DUPLICATE_DIRENT,
11215 N_("Duplicate @E found. "),
11216 PROMPT_CLEAR, 0 },
11217
11218 /* Non-unique filename found */
11219 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
11220 N_("@E has a non-unique filename.\nRename to %s"),
11221 PROMPT_NULL, 0 },
11222
11223 /* Duplicate directory entry found */
11224 { PR_2_REPORT_DUP_DIRENT,
11225 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
11226 PROMPT_NONE, 0 },
11227
11228 /* Pass 3 errors */
11229
11230 /* Pass 3: Checking directory connectivity */
11231 { PR_3_PASS_HEADER,
11232 N_("Pass 3: Checking @d connectivity\n"),
11233 PROMPT_NONE, 0 },
11234
11235 /* Root inode not allocated */
11236 { PR_3_NO_ROOT_INODE,
11237 N_("@r not allocated. "),
11238 PROMPT_ALLOCATE, 0 },
11239
11240 /* No room in lost+found */
11241 { PR_3_EXPAND_LF_DIR,
11242 N_("No room in @l @d. "),
11243 PROMPT_EXPAND, 0 },
11244
11245 /* Unconnected directory inode */
11246 { PR_3_UNCONNECTED_DIR,
11247 N_("Unconnected @d @i %i (%p)\n"),
11248 PROMPT_CONNECT, 0 },
11249
11250 /* /lost+found not found */
11251 { PR_3_NO_LF_DIR,
11252 N_("/@l not found. "),
11253 PROMPT_CREATE, PR_PREEN_OK },
11254
11255 /* .. entry is incorrect */
11256 { PR_3_BAD_DOT_DOT,
11257 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
11258 PROMPT_FIX, 0 },
11259
11260 /* Bad or non-existent /lost+found. Cannot reconnect */
11261 { PR_3_NO_LPF,
11262 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
11263 PROMPT_NONE, 0 },
11264
11265 /* Could not expand /lost+found */
11266 { PR_3_CANT_EXPAND_LPF,
11267 N_("Could not expand /@l: %m\n"),
11268 PROMPT_NONE, 0 },
11269
11270 /* Could not reconnect inode */
11271 { PR_3_CANT_RECONNECT,
11272 N_("Could not reconnect %i: %m\n"),
11273 PROMPT_NONE, 0 },
11274
11275 /* Error while trying to find /lost+found */
11276 { PR_3_ERR_FIND_LPF,
11277 N_("Error while trying to find /@l: %m\n"),
11278 PROMPT_NONE, 0 },
11279
11280 /* Error in ext2fs_new_block while creating /lost+found */
11281 { PR_3_ERR_LPF_NEW_BLOCK,
11282 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
11283 PROMPT_NONE, 0 },
11284
11285 /* Error in ext2fs_new_inode while creating /lost+found */
11286 { PR_3_ERR_LPF_NEW_INODE,
11287 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
11288 PROMPT_NONE, 0 },
11289
11290 /* Error in ext2fs_new_dir_block while creating /lost+found */
11291 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
11292 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
11293 PROMPT_NONE, 0 },
11294
11295 /* Error while writing directory block for /lost+found */
11296 { PR_3_ERR_LPF_WRITE_BLOCK,
11297 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
11298 PROMPT_NONE, 0 },
11299
11300 /* Error while adjusting inode count */
11301 { PR_3_ADJUST_INODE,
11302 N_("Error while adjusting @i count on @i %i\n"),
11303 PROMPT_NONE, 0 },
11304
11305 /* Couldn't fix parent directory -- error */
11306 { PR_3_FIX_PARENT_ERR,
11307 N_("Couldn't fix parent of @i %i: %m\n\n"),
11308 PROMPT_NONE, 0 },
11309
11310 /* Couldn't fix parent directory -- couldn't find it */
11311 { PR_3_FIX_PARENT_NOFIND,
11312 N_("Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n"),
11313 PROMPT_NONE, 0 },
11314
11315 /* Error allocating inode bitmap */
11316 { PR_3_ALLOCATE_IBITMAP_ERROR,
11317 N_("@A @i @B (%N): %m\n"),
11318 PROMPT_NONE, PR_FATAL },
11319
11320 /* Error creating root directory */
11321 { PR_3_CREATE_ROOT_ERROR,
11322 N_("Error creating root @d (%s): %m\n"),
11323 PROMPT_NONE, PR_FATAL },
11324
11325 /* Error creating lost and found directory */
11326 { PR_3_CREATE_LPF_ERROR,
11327 N_("Error creating /@l @d (%s): %m\n"),
11328 PROMPT_NONE, PR_FATAL },
11329
11330 /* Root inode is not directory; aborting */
11331 { PR_3_ROOT_NOT_DIR_ABORT,
11332 N_("@r is not a @d; aborting.\n"),
11333 PROMPT_NONE, PR_FATAL },
11334
11335 /* Cannot proceed without a root inode. */
11336 { PR_3_NO_ROOT_INODE_ABORT,
11337 N_("Cannot proceed without a @r.\n"),
11338 PROMPT_NONE, PR_FATAL },
11339
11340 /* Internal error: couldn't find dir_info */
11341 { PR_3_NO_DIRINFO,
11342 N_("Internal error: couldn't find dir_info for %i.\n"),
11343 PROMPT_NONE, PR_FATAL },
11344
11345 /* Lost+found not a directory */
11346 { PR_3_LPF_NOTDIR,
11347 N_("/@l is not a @d (ino=%i)\n"),
11348 PROMPT_UNLINK, 0 },
11349
11350 /* Pass 3A Directory Optimization */
11351
11352 /* Pass 3A: Optimizing directories */
11353 { PR_3A_PASS_HEADER,
11354 N_("Pass 3A: Optimizing directories\n"),
11355 PROMPT_NONE, PR_PREEN_NOMSG },
11356
11357 /* Error iterating over directories */
11358 { PR_3A_OPTIMIZE_ITER,
11359 N_("Failed to create dirs_to_hash iterator: %m"),
11360 PROMPT_NONE, 0 },
11361
11362 /* Error rehash directory */
11363 { PR_3A_OPTIMIZE_DIR_ERR,
11364 N_("Failed to optimize directory %q (%d): %m"),
11365 PROMPT_NONE, 0 },
11366
11367 /* Rehashing dir header */
11368 { PR_3A_OPTIMIZE_DIR_HEADER,
11369 N_("Optimizing directories: "),
11370 PROMPT_NONE, PR_MSG_ONLY },
11371
11372 /* Rehashing directory %d */
11373 { PR_3A_OPTIMIZE_DIR,
11374 " %d",
11375 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
11376
11377 /* Rehashing dir end */
11378 { PR_3A_OPTIMIZE_DIR_END,
11379 "\n",
11380 PROMPT_NONE, PR_PREEN_NOHDR },
11381
11382 /* Pass 4 errors */
11383
11384 /* Pass 4: Checking reference counts */
11385 { PR_4_PASS_HEADER,
11386 N_("Pass 4: Checking reference counts\n"),
11387 PROMPT_NONE, 0 },
11388
11389 /* Unattached zero-length inode */
11390 { PR_4_ZERO_LEN_INODE,
11391 "@u @z @i %i. ",
11392 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
11393
11394 /* Unattached inode */
11395 { PR_4_UNATTACHED_INODE,
11396 "@u @i %i\n",
11397 PROMPT_CONNECT, 0 },
11398
11399 /* Inode ref count wrong */
11400 { PR_4_BAD_REF_COUNT,
11401 N_("@i %i ref count is %Il, @s %N. "),
11402 PROMPT_FIX, PR_PREEN_OK },
11403
11404 { PR_4_INCONSISTENT_COUNT,
11405 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
11406 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
11407 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
11408 "They should be the same!\n"),
11409 PROMPT_NONE, 0 },
11410
11411 /* Pass 5 errors */
11412
11413 /* Pass 5: Checking group summary information */
11414 { PR_5_PASS_HEADER,
11415 N_("Pass 5: Checking @g summary information\n"),
11416 PROMPT_NONE, 0 },
11417
11418 /* Padding at end of inode bitmap is not set. */
11419 { PR_5_INODE_BMAP_PADDING,
11420 N_("Padding at end of @i @B is not set. "),
11421 PROMPT_FIX, PR_PREEN_OK },
11422
11423 /* Padding at end of block bitmap is not set. */
11424 { PR_5_BLOCK_BMAP_PADDING,
11425 N_("Padding at end of @b @B is not set. "),
11426 PROMPT_FIX, PR_PREEN_OK },
11427
11428 /* Block bitmap differences header */
11429 { PR_5_BLOCK_BITMAP_HEADER,
11430 N_("@b @B differences: "),
11431 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
11432
11433 /* Block not used, but marked in bitmap */
11434 { PR_5_BLOCK_UNUSED,
11435 " -%b",
11436 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11437
11438 /* Block used, but not marked used in bitmap */
11439 { PR_5_BLOCK_USED,
11440 " +%b",
11441 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11442
11443 /* Block bitmap differences end */
11444 { PR_5_BLOCK_BITMAP_END,
11445 "\n",
11446 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11447
11448 /* Inode bitmap differences header */
11449 { PR_5_INODE_BITMAP_HEADER,
11450 N_("@i @B differences: "),
11451 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
11452
11453 /* Inode not used, but marked in bitmap */
11454 { PR_5_INODE_UNUSED,
11455 " -%i",
11456 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11457
11458 /* Inode used, but not marked used in bitmap */
11459 { PR_5_INODE_USED,
11460 " +%i",
11461 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11462
11463 /* Inode bitmap differences end */
11464 { PR_5_INODE_BITMAP_END,
11465 "\n",
11466 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11467
11468 /* Free inodes count for group wrong */
11469 { PR_5_FREE_INODE_COUNT_GROUP,
11470 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
11471 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11472
11473 /* Directories count for group wrong */
11474 { PR_5_FREE_DIR_COUNT_GROUP,
11475 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
11476 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11477
11478 /* Free inodes count wrong */
11479 { PR_5_FREE_INODE_COUNT,
11480 N_("Free @is count wrong (%i, counted=%j).\n"),
11481 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11482
11483 /* Free blocks count for group wrong */
11484 { PR_5_FREE_BLOCK_COUNT_GROUP,
11485 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
11486 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11487
11488 /* Free blocks count wrong */
11489 { PR_5_FREE_BLOCK_COUNT,
11490 N_("Free @bs count wrong (%b, counted=%c).\n"),
11491 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11492
11493 /* Programming error: bitmap endpoints don't match */
11494 { PR_5_BMAP_ENDPOINTS,
11495 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
11496 "match calculated @B endpoints (%i, %j)\n"),
11497 PROMPT_NONE, PR_FATAL },
11498
11499 /* Internal error: fudging end of bitmap */
11500 { PR_5_FUDGE_BITMAP_ERROR,
11501 N_("Internal error: fudging end of bitmap (%N)\n"),
11502 PROMPT_NONE, PR_FATAL },
11503
11504 /* Error copying in replacement inode bitmap */
11505 { PR_5_COPY_IBITMAP_ERROR,
11506 "Error copying in replacement @i @B: %m\n",
11507 PROMPT_NONE, PR_FATAL },
11508
11509 /* Error copying in replacement block bitmap */
11510 { PR_5_COPY_BBITMAP_ERROR,
11511 "Error copying in replacement @b @B: %m\n",
11512 PROMPT_NONE, PR_FATAL },
11513
11514 /* Block range not used, but marked in bitmap */
11515 { PR_5_BLOCK_RANGE_UNUSED,
11516 " -(%b--%c)",
11517 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11518
11519 /* Block range used, but not marked used in bitmap */
11520 { PR_5_BLOCK_RANGE_USED,
11521 " +(%b--%c)",
11522 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11523
11524 /* Inode range not used, but marked in bitmap */
11525 { PR_5_INODE_RANGE_UNUSED,
11526 " -(%i--%j)",
11527 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11528
11529 /* Inode range used, but not marked used in bitmap */
11530 { PR_5_INODE_RANGE_USED,
11531 " +(%i--%j)",
11532 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11533
11534 { 0 }
11535};
11536
11537/*
11538 * This is the latch flags register. It allows several problems to be
11539 * "latched" together. This means that the user has to answer but one
11540 * question for the set of problems, and all of the associated
11541 * problems will be either fixed or not fixed.
11542 */
11543static struct latch_descr pr_latch_info[] = {
11544 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
11545 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
11546 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
11547 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
11548 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
11549 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
11550 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
11551 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
11552 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
11553 { -1, 0, 0 },
11554};
11555
11556static const struct e2fsck_problem *find_problem(problem_t code)
11557{
11558 int i;
11559
11560 for (i=0; problem_table[i].e2p_code; i++) {
11561 if (problem_table[i].e2p_code == code)
11562 return &problem_table[i];
11563 }
11564 return 0;
11565}
11566
11567static struct latch_descr *find_latch(int code)
11568{
11569 int i;
11570
11571 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
11572 if (pr_latch_info[i].latch_code == code)
11573 return &pr_latch_info[i];
11574 }
11575 return 0;
11576}
11577
11578int end_problem_latch(e2fsck_t ctx, int mask)
11579{
11580 struct latch_descr *ldesc;
11581 struct problem_context pctx;
11582 int answer = -1;
11583
11584 ldesc = find_latch(mask);
11585 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
11586 clear_problem_context(&pctx);
11587 answer = fix_problem(ctx, ldesc->end_message, &pctx);
11588 }
11589 ldesc->flags &= ~(PRL_VARIABLE);
11590 return answer;
11591}
11592
11593int set_latch_flags(int mask, int setflags, int clearflags)
11594{
11595 struct latch_descr *ldesc;
11596
11597 ldesc = find_latch(mask);
11598 if (!ldesc)
11599 return -1;
11600 ldesc->flags |= setflags;
11601 ldesc->flags &= ~clearflags;
11602 return 0;
11603}
11604
11605void clear_problem_context(struct problem_context *ctx)
11606{
11607 memset(ctx, 0, sizeof(struct problem_context));
11608 ctx->blkcount = -1;
11609 ctx->group = -1;
11610}
11611
11612int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
11613{
11614 ext2_filsys fs = ctx->fs;
11615 const struct e2fsck_problem *ptr;
11616 struct latch_descr *ldesc = 0;
11617 const char *message;
11618 int def_yn, answer, ans;
11619 int print_answer = 0;
11620 int suppress = 0;
11621
11622 ptr = find_problem(code);
11623 if (!ptr) {
11624 printf(_("Unhandled error code (0x%x)!\n"), code);
11625 return 0;
11626 }
11627 def_yn = 1;
11628 if ((ptr->flags & PR_NO_DEFAULT) ||
11629 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
11630 (ctx->options & E2F_OPT_NO))
11631 def_yn= 0;
11632
11633 /*
11634 * Do special latch processing. This is where we ask the
11635 * latch question, if it exists
11636 */
11637 if (ptr->flags & PR_LATCH_MASK) {
11638 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
11639 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
11640 ans = fix_problem(ctx, ldesc->question, pctx);
11641 if (ans == 1)
11642 ldesc->flags |= PRL_YES;
11643 if (ans == 0)
11644 ldesc->flags |= PRL_NO;
11645 ldesc->flags |= PRL_LATCHED;
11646 }
11647 if (ldesc->flags & PRL_SUPPRESS)
11648 suppress++;
11649 }
11650 if ((ptr->flags & PR_PREEN_NOMSG) &&
11651 (ctx->options & E2F_OPT_PREEN))
11652 suppress++;
11653 if ((ptr->flags & PR_NO_NOMSG) &&
11654 (ctx->options & E2F_OPT_NO))
11655 suppress++;
11656 if (!suppress) {
11657 message = ptr->e2p_description;
11658 if ((ctx->options & E2F_OPT_PREEN) &&
11659 !(ptr->flags & PR_PREEN_NOHDR)) {
11660 printf("%s: ", ctx->device_name ?
11661 ctx->device_name : ctx->filesystem_name);
11662 }
11663 if (*message)
11664 print_e2fsck_message(ctx, _(message), pctx, 1);
11665 }
11666 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
11667 preenhalt(ctx);
11668
11669 if (ptr->flags & PR_FATAL)
11670 fatal_error(ctx, 0);
11671
11672 if (ptr->prompt == PROMPT_NONE) {
11673 if (ptr->flags & PR_NOCOLLATE)
11674 answer = -1;
11675 else
11676 answer = def_yn;
11677 } else {
11678 if (ctx->options & E2F_OPT_PREEN) {
11679 answer = def_yn;
11680 if (!(ptr->flags & PR_PREEN_NOMSG))
11681 print_answer = 1;
11682 } else if ((ptr->flags & PR_LATCH_MASK) &&
11683 (ldesc->flags & (PRL_YES | PRL_NO))) {
11684 if (!suppress)
11685 print_answer = 1;
11686 if (ldesc->flags & PRL_YES)
11687 answer = 1;
11688 else
11689 answer = 0;
11690 } else
11691 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
11692 if (!answer && !(ptr->flags & PR_NO_OK))
11693 ext2fs_unmark_valid(fs);
11694
11695 if (print_answer)
11696 printf("%s.\n", answer ?
11697 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
11698
11699 }
11700
11701 if ((ptr->prompt == PROMPT_ABORT) && answer)
11702 fatal_error(ctx, 0);
11703
11704 if (ptr->flags & PR_AFTER_CODE)
11705 answer = fix_problem(ctx, ptr->second_code, pctx);
11706
11707 return answer;
11708}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011709
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011710/*
11711 * linux/fs/recovery.c
11712 *
11713 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011714 */
11715
11716/*
11717 * Maintain information about the progress of the recovery job, so that
11718 * the different passes can carry information between them.
11719 */
11720struct recovery_info
11721{
11722 tid_t start_transaction;
11723 tid_t end_transaction;
11724
11725 int nr_replays;
11726 int nr_revokes;
11727 int nr_revoke_hits;
11728};
11729
11730enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
11731static int do_one_pass(journal_t *journal,
11732 struct recovery_info *info, enum passtype pass);
11733static int scan_revoke_records(journal_t *, struct buffer_head *,
11734 tid_t, struct recovery_info *);
11735
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011736/*
11737 * Read a block from the journal
11738 */
11739
11740static int jread(struct buffer_head **bhp, journal_t *journal,
11741 unsigned int offset)
11742{
11743 int err;
11744 unsigned long blocknr;
11745 struct buffer_head *bh;
11746
11747 *bhp = NULL;
11748
11749 J_ASSERT (offset < journal->j_maxlen);
11750
11751 err = journal_bmap(journal, offset, &blocknr);
11752
11753 if (err) {
11754 printk (KERN_ERR "JBD: bad block at offset %u\n",
11755 offset);
11756 return err;
11757 }
11758
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000011759 bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000011760 if (!bh)
11761 return -ENOMEM;
11762
11763 if (!buffer_uptodate(bh)) {
11764 /* If this is a brand new buffer, start readahead.
11765 Otherwise, we assume we are already reading it. */
11766 if (!buffer_req(bh))
11767 do_readahead(journal, offset);
11768 wait_on_buffer(bh);
11769 }
11770
11771 if (!buffer_uptodate(bh)) {
11772 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
11773 offset);
11774 brelse(bh);
11775 return -EIO;
11776 }
11777
11778 *bhp = bh;
11779 return 0;
11780}
11781
11782
11783/*
11784 * Count the number of in-use tags in a journal descriptor block.
11785 */
11786
11787static int count_tags(struct buffer_head *bh, int size)
11788{
11789 char * tagp;
11790 journal_block_tag_t * tag;
11791 int nr = 0;
11792
11793 tagp = &bh->b_data[sizeof(journal_header_t)];
11794
11795 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
11796 tag = (journal_block_tag_t *) tagp;
11797
11798 nr++;
11799 tagp += sizeof(journal_block_tag_t);
11800 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
11801 tagp += 16;
11802
11803 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
11804 break;
11805 }
11806
11807 return nr;
11808}
11809
11810
11811/* Make sure we wrap around the log correctly! */
11812#define wrap(journal, var) \
11813do { \
11814 if (var >= (journal)->j_last) \
11815 var -= ((journal)->j_last - (journal)->j_first); \
11816} while (0)
11817
11818/**
11819 * int journal_recover(journal_t *journal) - recovers a on-disk journal
11820 * @journal: the journal to recover
11821 *
11822 * The primary function for recovering the log contents when mounting a
11823 * journaled device.
11824 *
11825 * Recovery is done in three passes. In the first pass, we look for the
11826 * end of the log. In the second, we assemble the list of revoke
11827 * blocks. In the third and final pass, we replay any un-revoked blocks
11828 * in the log.
11829 */
11830int journal_recover(journal_t *journal)
11831{
11832 int err;
11833 journal_superblock_t * sb;
11834
11835 struct recovery_info info;
11836
11837 memset(&info, 0, sizeof(info));
11838 sb = journal->j_superblock;
11839
11840 /*
11841 * The journal superblock's s_start field (the current log head)
11842 * is always zero if, and only if, the journal was cleanly
11843 * unmounted.
11844 */
11845
11846 if (!sb->s_start) {
11847 jbd_debug(1, "No recovery required, last transaction %d\n",
11848 ntohl(sb->s_sequence));
11849 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
11850 return 0;
11851 }
11852
11853 err = do_one_pass(journal, &info, PASS_SCAN);
11854 if (!err)
11855 err = do_one_pass(journal, &info, PASS_REVOKE);
11856 if (!err)
11857 err = do_one_pass(journal, &info, PASS_REPLAY);
11858
11859 jbd_debug(0, "JBD: recovery, exit status %d, "
11860 "recovered transactions %u to %u\n",
11861 err, info.start_transaction, info.end_transaction);
11862 jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
11863 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
11864
11865 /* Restart the log at the next transaction ID, thus invalidating
11866 * any existing commit records in the log. */
11867 journal->j_transaction_sequence = ++info.end_transaction;
11868
11869 journal_clear_revoke(journal);
11870 sync_blockdev(journal->j_fs_dev);
11871 return err;
11872}
11873
11874static int do_one_pass(journal_t *journal,
11875 struct recovery_info *info, enum passtype pass)
11876{
11877 unsigned int first_commit_ID, next_commit_ID;
11878 unsigned long next_log_block;
11879 int err, success = 0;
11880 journal_superblock_t * sb;
11881 journal_header_t * tmp;
11882 struct buffer_head * bh;
11883 unsigned int sequence;
11884 int blocktype;
11885
11886 /* Precompute the maximum metadata descriptors in a descriptor block */
11887 int MAX_BLOCKS_PER_DESC;
11888 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
11889 / sizeof(journal_block_tag_t));
11890
11891 /*
11892 * First thing is to establish what we expect to find in the log
11893 * (in terms of transaction IDs), and where (in terms of log
11894 * block offsets): query the superblock.
11895 */
11896
11897 sb = journal->j_superblock;
11898 next_commit_ID = ntohl(sb->s_sequence);
11899 next_log_block = ntohl(sb->s_start);
11900
11901 first_commit_ID = next_commit_ID;
11902 if (pass == PASS_SCAN)
11903 info->start_transaction = first_commit_ID;
11904
11905 jbd_debug(1, "Starting recovery pass %d\n", pass);
11906
11907 /*
11908 * Now we walk through the log, transaction by transaction,
11909 * making sure that each transaction has a commit block in the
11910 * expected place. Each complete transaction gets replayed back
11911 * into the main filesystem.
11912 */
11913
11914 while (1) {
11915 int flags;
11916 char * tagp;
11917 journal_block_tag_t * tag;
11918 struct buffer_head * obh;
11919 struct buffer_head * nbh;
11920
11921 /* If we already know where to stop the log traversal,
11922 * check right now that we haven't gone past the end of
11923 * the log. */
11924
11925 if (pass != PASS_SCAN)
11926 if (tid_geq(next_commit_ID, info->end_transaction))
11927 break;
11928
11929 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
11930 next_commit_ID, next_log_block, journal->j_last);
11931
11932 /* Skip over each chunk of the transaction looking
11933 * either the next descriptor block or the final commit
11934 * record. */
11935
11936 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
11937 err = jread(&bh, journal, next_log_block);
11938 if (err)
11939 goto failed;
11940
11941 next_log_block++;
11942 wrap(journal, next_log_block);
11943
11944 /* What kind of buffer is it?
11945 *
11946 * If it is a descriptor block, check that it has the
11947 * expected sequence number. Otherwise, we're all done
11948 * here. */
11949
11950 tmp = (journal_header_t *)bh->b_data;
11951
11952 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
11953 brelse(bh);
11954 break;
11955 }
11956
11957 blocktype = ntohl(tmp->h_blocktype);
11958 sequence = ntohl(tmp->h_sequence);
11959 jbd_debug(3, "Found magic %d, sequence %d\n",
11960 blocktype, sequence);
11961
11962 if (sequence != next_commit_ID) {
11963 brelse(bh);
11964 break;
11965 }
11966
11967 /* OK, we have a valid descriptor block which matches
11968 * all of the sequence number checks. What are we going
11969 * to do with it? That depends on the pass... */
11970
11971 switch(blocktype) {
11972 case JFS_DESCRIPTOR_BLOCK:
11973 /* If it is a valid descriptor block, replay it
11974 * in pass REPLAY; otherwise, just skip over the
11975 * blocks it describes. */
11976 if (pass != PASS_REPLAY) {
11977 next_log_block +=
11978 count_tags(bh, journal->j_blocksize);
11979 wrap(journal, next_log_block);
11980 brelse(bh);
11981 continue;
11982 }
11983
11984 /* A descriptor block: we can now write all of
11985 * the data blocks. Yay, useful work is finally
11986 * getting done here! */
11987
11988 tagp = &bh->b_data[sizeof(journal_header_t)];
11989 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
11990 <= journal->j_blocksize) {
11991 unsigned long io_block;
11992
11993 tag = (journal_block_tag_t *) tagp;
11994 flags = ntohl(tag->t_flags);
11995
11996 io_block = next_log_block++;
11997 wrap(journal, next_log_block);
11998 err = jread(&obh, journal, io_block);
11999 if (err) {
12000 /* Recover what we can, but
12001 * report failure at the end. */
12002 success = err;
12003 printk (KERN_ERR
12004 "JBD: IO error %d recovering "
12005 "block %ld in log\n",
12006 err, io_block);
12007 } else {
12008 unsigned long blocknr;
12009
12010 J_ASSERT(obh != NULL);
12011 blocknr = ntohl(tag->t_blocknr);
12012
12013 /* If the block has been
12014 * revoked, then we're all done
12015 * here. */
12016 if (journal_test_revoke
12017 (journal, blocknr,
12018 next_commit_ID)) {
12019 brelse(obh);
12020 ++info->nr_revoke_hits;
12021 goto skip_write;
12022 }
12023
12024 /* Find a buffer for the new
12025 * data being restored */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012026 nbh = getblk(journal->j_fs_dev,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012027 blocknr,
12028 journal->j_blocksize);
12029 if (nbh == NULL) {
12030 printk(KERN_ERR
12031 "JBD: Out of memory "
12032 "during recovery.\n");
12033 err = -ENOMEM;
12034 brelse(bh);
12035 brelse(obh);
12036 goto failed;
12037 }
12038
12039 lock_buffer(nbh);
12040 memcpy(nbh->b_data, obh->b_data,
12041 journal->j_blocksize);
12042 if (flags & JFS_FLAG_ESCAPE) {
12043 *((unsigned int *)bh->b_data) =
12044 htonl(JFS_MAGIC_NUMBER);
12045 }
12046
12047 BUFFER_TRACE(nbh, "marking dirty");
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012048 mark_buffer_uptodate(nbh, 1);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012049 mark_buffer_dirty(nbh);
12050 BUFFER_TRACE(nbh, "marking uptodate");
12051 ++info->nr_replays;
12052 /* ll_rw_block(WRITE, 1, &nbh); */
12053 unlock_buffer(nbh);
12054 brelse(obh);
12055 brelse(nbh);
12056 }
12057
12058 skip_write:
12059 tagp += sizeof(journal_block_tag_t);
12060 if (!(flags & JFS_FLAG_SAME_UUID))
12061 tagp += 16;
12062
12063 if (flags & JFS_FLAG_LAST_TAG)
12064 break;
12065 }
12066
12067 brelse(bh);
12068 continue;
12069
12070 case JFS_COMMIT_BLOCK:
12071 /* Found an expected commit block: not much to
12072 * do other than move on to the next sequence
12073 * number. */
12074 brelse(bh);
12075 next_commit_ID++;
12076 continue;
12077
12078 case JFS_REVOKE_BLOCK:
12079 /* If we aren't in the REVOKE pass, then we can
12080 * just skip over this block. */
12081 if (pass != PASS_REVOKE) {
12082 brelse(bh);
12083 continue;
12084 }
12085
12086 err = scan_revoke_records(journal, bh,
12087 next_commit_ID, info);
12088 brelse(bh);
12089 if (err)
12090 goto failed;
12091 continue;
12092
12093 default:
12094 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
12095 blocktype);
12096 goto done;
12097 }
12098 }
12099
12100 done:
12101 /*
12102 * We broke out of the log scan loop: either we came to the
12103 * known end of the log or we found an unexpected block in the
12104 * log. If the latter happened, then we know that the "current"
12105 * transaction marks the end of the valid log.
12106 */
12107
12108 if (pass == PASS_SCAN)
12109 info->end_transaction = next_commit_ID;
12110 else {
12111 /* It's really bad news if different passes end up at
12112 * different places (but possible due to IO errors). */
12113 if (info->end_transaction != next_commit_ID) {
12114 printk (KERN_ERR "JBD: recovery pass %d ended at "
12115 "transaction %u, expected %u\n",
12116 pass, next_commit_ID, info->end_transaction);
12117 if (!success)
12118 success = -EIO;
12119 }
12120 }
12121
12122 return success;
12123
12124 failed:
12125 return err;
12126}
12127
12128
12129/* Scan a revoke record, marking all blocks mentioned as revoked. */
12130
12131static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
12132 tid_t sequence, struct recovery_info *info)
12133{
12134 journal_revoke_header_t *header;
12135 int offset, max;
12136
12137 header = (journal_revoke_header_t *) bh->b_data;
12138 offset = sizeof(journal_revoke_header_t);
12139 max = ntohl(header->r_count);
12140
12141 while (offset < max) {
12142 unsigned long blocknr;
12143 int err;
12144
12145 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
12146 offset += 4;
12147 err = journal_set_revoke(journal, blocknr, sequence);
12148 if (err)
12149 return err;
12150 ++info->nr_revokes;
12151 }
12152 return 0;
12153}
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012154
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012155
12156/*
12157 * rehash.c --- rebuild hash tree directories
12158 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012159 * This algorithm is designed for simplicity of implementation and to
12160 * pack the directory as much as possible. It however requires twice
12161 * as much memory as the size of the directory. The maximum size
12162 * directory supported using a 4k blocksize is roughly a gigabyte, and
12163 * so there may very well be problems with machines that don't have
12164 * virtual memory, and obscenely large directories.
12165 *
12166 * An alternate algorithm which is much more disk intensive could be
12167 * written, and probably will need to be written in the future. The
12168 * design goals of such an algorithm are: (a) use (roughly) constant
12169 * amounts of memory, no matter how large the directory, (b) the
12170 * directory must be safe at all times, even if e2fsck is interrupted
12171 * in the middle, (c) we must use minimal amounts of extra disk
12172 * blocks. This pretty much requires an incremental approach, where
12173 * we are reading from one part of the directory, and inserting into
12174 * the front half. So the algorithm will have to keep track of a
12175 * moving block boundary between the new tree and the old tree, and
12176 * files will need to be moved from the old directory and inserted
12177 * into the new tree. If the new directory requires space which isn't
12178 * yet available, blocks from the beginning part of the old directory
12179 * may need to be moved to the end of the directory to make room for
12180 * the new tree:
12181 *
12182 * --------------------------------------------------------
12183 * | new tree | | old tree |
12184 * --------------------------------------------------------
12185 * ^ ptr ^ptr
12186 * tail new head old
12187 *
12188 * This is going to be a pain in the tuckus to implement, and will
12189 * require a lot more disk accesses. So I'm going to skip it for now;
12190 * it's only really going to be an issue for really, really big
12191 * filesystems (when we reach the level of tens of millions of files
12192 * in a single directory). It will probably be easier to simply
12193 * require that e2fsck use VM first.
12194 */
12195
12196struct fill_dir_struct {
12197 char *buf;
12198 struct ext2_inode *inode;
12199 int err;
12200 e2fsck_t ctx;
12201 struct hash_entry *harray;
12202 int max_array, num_array;
12203 int dir_size;
12204 int compress;
12205 ino_t parent;
12206};
12207
12208struct hash_entry {
12209 ext2_dirhash_t hash;
12210 ext2_dirhash_t minor_hash;
12211 struct ext2_dir_entry *dir;
12212};
12213
12214struct out_dir {
12215 int num;
12216 int max;
12217 char *buf;
12218 ext2_dirhash_t *hashes;
12219};
12220
12221static int fill_dir_block(ext2_filsys fs,
12222 blk_t *block_nr,
12223 e2_blkcnt_t blockcnt,
12224 blk_t ref_block EXT2FS_ATTR((unused)),
12225 int ref_offset EXT2FS_ATTR((unused)),
12226 void *priv_data)
12227{
12228 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
12229 struct hash_entry *new_array, *ent;
12230 struct ext2_dir_entry *dirent;
12231 char *dir;
12232 unsigned int offset, dir_offset;
12233
12234 if (blockcnt < 0)
12235 return 0;
12236
12237 offset = blockcnt * fs->blocksize;
12238 if (offset + fs->blocksize > fd->inode->i_size) {
12239 fd->err = EXT2_ET_DIR_CORRUPTED;
12240 return BLOCK_ABORT;
12241 }
12242 dir = (fd->buf+offset);
12243 if (HOLE_BLKADDR(*block_nr)) {
12244 memset(dir, 0, fs->blocksize);
12245 dirent = (struct ext2_dir_entry *) dir;
12246 dirent->rec_len = fs->blocksize;
12247 } else {
12248 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
12249 if (fd->err)
12250 return BLOCK_ABORT;
12251 }
12252 /* While the directory block is "hot", index it. */
12253 dir_offset = 0;
12254 while (dir_offset < fs->blocksize) {
12255 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
12256 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
12257 (dirent->rec_len < 8) ||
12258 ((dirent->rec_len % 4) != 0) ||
12259 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
12260 fd->err = EXT2_ET_DIR_CORRUPTED;
12261 return BLOCK_ABORT;
12262 }
12263 dir_offset += dirent->rec_len;
12264 if (dirent->inode == 0)
12265 continue;
12266 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
12267 (dirent->name[0] == '.'))
12268 continue;
12269 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
12270 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
12271 fd->parent = dirent->inode;
12272 continue;
12273 }
12274 if (fd->num_array >= fd->max_array) {
12275 new_array = realloc(fd->harray,
12276 sizeof(struct hash_entry) * (fd->max_array+500));
12277 if (!new_array) {
12278 fd->err = ENOMEM;
12279 return BLOCK_ABORT;
12280 }
12281 fd->harray = new_array;
12282 fd->max_array += 500;
12283 }
12284 ent = fd->harray + fd->num_array++;
12285 ent->dir = dirent;
12286 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
12287 if (fd->compress)
12288 ent->hash = ent->minor_hash = 0;
12289 else {
12290 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
12291 dirent->name,
12292 dirent->name_len & 0xFF,
12293 fs->super->s_hash_seed,
12294 &ent->hash, &ent->minor_hash);
12295 if (fd->err)
12296 return BLOCK_ABORT;
12297 }
12298 }
12299
12300 return 0;
12301}
12302
12303/* Used for sorting the hash entry */
12304static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
12305{
12306 const struct hash_entry *he_a = (const struct hash_entry *) a;
12307 const struct hash_entry *he_b = (const struct hash_entry *) b;
12308 int ret;
12309 int min_len;
12310
12311 min_len = he_a->dir->name_len;
12312 if (min_len > he_b->dir->name_len)
12313 min_len = he_b->dir->name_len;
12314
12315 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
12316 if (ret == 0) {
12317 if (he_a->dir->name_len > he_b->dir->name_len)
12318 ret = 1;
12319 else if (he_a->dir->name_len < he_b->dir->name_len)
12320 ret = -1;
12321 else
12322 ret = he_b->dir->inode - he_a->dir->inode;
12323 }
12324 return ret;
12325}
12326
12327/* Used for sorting the hash entry */
12328static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
12329{
12330 const struct hash_entry *he_a = (const struct hash_entry *) a;
12331 const struct hash_entry *he_b = (const struct hash_entry *) b;
12332 int ret;
12333
12334 if (he_a->hash > he_b->hash)
12335 ret = 1;
12336 else if (he_a->hash < he_b->hash)
12337 ret = -1;
12338 else {
12339 if (he_a->minor_hash > he_b->minor_hash)
12340 ret = 1;
12341 else if (he_a->minor_hash < he_b->minor_hash)
12342 ret = -1;
12343 else
12344 ret = name_cmp(a, b);
12345 }
12346 return ret;
12347}
12348
12349static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
12350 int blocks)
12351{
12352 void *new_mem;
12353
12354 if (outdir->max) {
12355 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
12356 if (!new_mem)
12357 return ENOMEM;
12358 outdir->buf = new_mem;
12359 new_mem = realloc(outdir->hashes,
12360 blocks * sizeof(ext2_dirhash_t));
12361 if (!new_mem)
12362 return ENOMEM;
12363 outdir->hashes = new_mem;
12364 } else {
12365 outdir->buf = malloc(blocks * fs->blocksize);
12366 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
12367 outdir->num = 0;
12368 }
12369 outdir->max = blocks;
12370 return 0;
12371}
12372
12373static void free_out_dir(struct out_dir *outdir)
12374{
12375 if (outdir->buf)
12376 free(outdir->buf);
12377 if (outdir->hashes)
12378 free(outdir->hashes);
12379 outdir->max = 0;
12380 outdir->num =0;
12381}
12382
12383static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
12384 char ** ret)
12385{
12386 errcode_t retval;
12387
12388 if (outdir->num >= outdir->max) {
12389 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
12390 if (retval)
12391 return retval;
12392 }
12393 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
12394 memset(*ret, 0, fs->blocksize);
12395 return 0;
12396}
12397
12398/*
12399 * This function is used to make a unique filename. We do this by
12400 * appending ~0, and then incrementing the number. However, we cannot
12401 * expand the length of the filename beyond the padding available in
12402 * the directory entry.
12403 */
12404static void mutate_name(char *str, __u16 *len)
12405{
12406 int i;
12407 __u16 l = *len & 0xFF, h = *len & 0xff00;
12408
12409 /*
12410 * First check to see if it looks the name has been mutated
12411 * already
12412 */
12413 for (i = l-1; i > 0; i--) {
12414 if (!isdigit(str[i]))
12415 break;
12416 }
12417 if ((i == l-1) || (str[i] != '~')) {
12418 if (((l-1) & 3) < 2)
12419 l += 2;
12420 else
12421 l = (l+3) & ~3;
12422 str[l-2] = '~';
12423 str[l-1] = '0';
12424 *len = l | h;
12425 return;
12426 }
12427 for (i = l-1; i >= 0; i--) {
12428 if (isdigit(str[i])) {
12429 if (str[i] == '9')
12430 str[i] = '0';
12431 else {
12432 str[i]++;
12433 return;
12434 }
12435 continue;
12436 }
12437 if (i == 1) {
12438 if (str[0] == 'z')
12439 str[0] = 'A';
12440 else if (str[0] == 'Z') {
12441 str[0] = '~';
12442 str[1] = '0';
12443 } else
12444 str[0]++;
12445 } else if (i > 0) {
12446 str[i] = '1';
12447 str[i-1] = '~';
12448 } else {
12449 if (str[0] == '~')
12450 str[0] = 'a';
12451 else
12452 str[0]++;
12453 }
12454 break;
12455 }
12456}
12457
12458static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
12459 ext2_ino_t ino,
12460 struct fill_dir_struct *fd)
12461{
12462 struct problem_context pctx;
12463 struct hash_entry *ent, *prev;
12464 int i, j;
12465 int fixed = 0;
12466 char new_name[256];
12467 __u16 new_len;
12468
12469 clear_problem_context(&pctx);
12470 pctx.ino = ino;
12471
12472 for (i=1; i < fd->num_array; i++) {
12473 ent = fd->harray + i;
12474 prev = ent - 1;
12475 if (!ent->dir->inode ||
12476 ((ent->dir->name_len & 0xFF) !=
12477 (prev->dir->name_len & 0xFF)) ||
12478 (strncmp(ent->dir->name, prev->dir->name,
12479 ent->dir->name_len & 0xFF)))
12480 continue;
12481 pctx.dirent = ent->dir;
12482 if ((ent->dir->inode == prev->dir->inode) &&
12483 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
12484 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
12485 ent->dir->inode = 0;
12486 fixed++;
12487 continue;
12488 }
12489 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
12490 new_len = ent->dir->name_len;
12491 mutate_name(new_name, &new_len);
12492 for (j=0; j < fd->num_array; j++) {
12493 if ((i==j) ||
12494 ((ent->dir->name_len & 0xFF) !=
12495 (fd->harray[j].dir->name_len & 0xFF)) ||
12496 (strncmp(new_name, fd->harray[j].dir->name,
12497 new_len & 0xFF)))
12498 continue;
12499 mutate_name(new_name, &new_len);
12500
12501 j = -1;
12502 }
12503 new_name[new_len & 0xFF] = 0;
12504 pctx.str = new_name;
12505 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
12506 memcpy(ent->dir->name, new_name, new_len & 0xFF);
12507 ent->dir->name_len = new_len;
12508 ext2fs_dirhash(fs->super->s_def_hash_version,
12509 ent->dir->name,
12510 ent->dir->name_len & 0xFF,
12511 fs->super->s_hash_seed,
12512 &ent->hash, &ent->minor_hash);
12513 fixed++;
12514 }
12515 }
12516 return fixed;
12517}
12518
12519
12520static errcode_t copy_dir_entries(ext2_filsys fs,
12521 struct fill_dir_struct *fd,
12522 struct out_dir *outdir)
12523{
12524 errcode_t retval;
12525 char *block_start;
12526 struct hash_entry *ent;
12527 struct ext2_dir_entry *dirent;
12528 int i, rec_len, left;
12529 ext2_dirhash_t prev_hash;
12530 int offset;
12531
12532 outdir->max = 0;
12533 retval = alloc_size_dir(fs, outdir,
12534 (fd->dir_size / fs->blocksize) + 2);
12535 if (retval)
12536 return retval;
12537 outdir->num = fd->compress ? 0 : 1;
12538 offset = 0;
12539 outdir->hashes[0] = 0;
12540 prev_hash = 1;
12541 if ((retval = get_next_block(fs, outdir, &block_start)))
12542 return retval;
12543 dirent = (struct ext2_dir_entry *) block_start;
12544 left = fs->blocksize;
12545 for (i=0; i < fd->num_array; i++) {
12546 ent = fd->harray + i;
12547 if (ent->dir->inode == 0)
12548 continue;
12549 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
12550 if (rec_len > left) {
12551 if (left)
12552 dirent->rec_len += left;
12553 if ((retval = get_next_block(fs, outdir,
12554 &block_start)))
12555 return retval;
12556 offset = 0;
12557 }
12558 left = fs->blocksize - offset;
12559 dirent = (struct ext2_dir_entry *) (block_start + offset);
12560 if (offset == 0) {
12561 if (ent->hash == prev_hash)
12562 outdir->hashes[outdir->num-1] = ent->hash | 1;
12563 else
12564 outdir->hashes[outdir->num-1] = ent->hash;
12565 }
12566 dirent->inode = ent->dir->inode;
12567 dirent->name_len = ent->dir->name_len;
12568 dirent->rec_len = rec_len;
12569 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
12570 offset += rec_len;
12571 left -= rec_len;
12572 if (left < 12) {
12573 dirent->rec_len += left;
12574 offset += left;
12575 left = 0;
12576 }
12577 prev_hash = ent->hash;
12578 }
12579 if (left)
12580 dirent->rec_len += left;
12581
12582 return 0;
12583}
12584
12585
12586static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
12587 ext2_ino_t ino, ext2_ino_t parent)
12588{
12589 struct ext2_dir_entry *dir;
12590 struct ext2_dx_root_info *root;
12591 struct ext2_dx_countlimit *limits;
12592 int filetype = 0;
12593
12594 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
12595 filetype = EXT2_FT_DIR << 8;
12596
12597 memset(buf, 0, fs->blocksize);
12598 dir = (struct ext2_dir_entry *) buf;
12599 dir->inode = ino;
12600 dir->name[0] = '.';
12601 dir->name_len = 1 | filetype;
12602 dir->rec_len = 12;
12603 dir = (struct ext2_dir_entry *) (buf + 12);
12604 dir->inode = parent;
12605 dir->name[0] = '.';
12606 dir->name[1] = '.';
12607 dir->name_len = 2 | filetype;
12608 dir->rec_len = fs->blocksize - 12;
12609
12610 root = (struct ext2_dx_root_info *) (buf+24);
12611 root->reserved_zero = 0;
12612 root->hash_version = fs->super->s_def_hash_version;
12613 root->info_length = 8;
12614 root->indirect_levels = 0;
12615 root->unused_flags = 0;
12616
12617 limits = (struct ext2_dx_countlimit *) (buf+32);
12618 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
12619 limits->count = 0;
12620
12621 return root;
12622}
12623
12624
12625static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
12626{
12627 struct ext2_dir_entry *dir;
12628 struct ext2_dx_countlimit *limits;
12629
12630 memset(buf, 0, fs->blocksize);
12631 dir = (struct ext2_dir_entry *) buf;
12632 dir->inode = 0;
12633 dir->rec_len = fs->blocksize;
12634
12635 limits = (struct ext2_dx_countlimit *) (buf+8);
12636 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
12637 limits->count = 0;
12638
12639 return (struct ext2_dx_entry *) limits;
12640}
12641
12642/*
12643 * This function takes the leaf nodes which have been written in
12644 * outdir, and populates the root node and any necessary interior nodes.
12645 */
12646static errcode_t calculate_tree(ext2_filsys fs,
12647 struct out_dir *outdir,
12648 ext2_ino_t ino,
12649 ext2_ino_t parent)
12650{
12651 struct ext2_dx_root_info *root_info;
12652 struct ext2_dx_entry *root, *dx_ent = 0;
12653 struct ext2_dx_countlimit *root_limit, *limit;
12654 errcode_t retval;
12655 char * block_start;
12656 int i, c1, c2, nblks;
12657 int limit_offset, root_offset;
12658
12659 root_info = set_root_node(fs, outdir->buf, ino, parent);
12660 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
12661 root_info->info_length;
12662 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12663 c1 = root_limit->limit;
12664 nblks = outdir->num;
12665
12666 /* Write out the pointer blocks */
12667 if (nblks-1 <= c1) {
12668 /* Just write out the root block, and we're done */
12669 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
12670 for (i=1; i < nblks; i++) {
12671 root->block = ext2fs_cpu_to_le32(i);
12672 if (i != 1)
12673 root->hash =
12674 ext2fs_cpu_to_le32(outdir->hashes[i]);
12675 root++;
12676 c1--;
12677 }
12678 } else {
12679 c2 = 0;
12680 limit = 0;
12681 root_info->indirect_levels = 1;
12682 for (i=1; i < nblks; i++) {
12683 if (c1 == 0)
12684 return ENOSPC;
12685 if (c2 == 0) {
12686 if (limit)
12687 limit->limit = limit->count =
12688 ext2fs_cpu_to_le16(limit->limit);
12689 root = (struct ext2_dx_entry *)
12690 (outdir->buf + root_offset);
12691 root->block = ext2fs_cpu_to_le32(outdir->num);
12692 if (i != 1)
12693 root->hash =
12694 ext2fs_cpu_to_le32(outdir->hashes[i]);
12695 if ((retval = get_next_block(fs, outdir,
12696 &block_start)))
12697 return retval;
12698 dx_ent = set_int_node(fs, block_start);
12699 limit = (struct ext2_dx_countlimit *) dx_ent;
12700 c2 = limit->limit;
12701 root_offset += sizeof(struct ext2_dx_entry);
12702 c1--;
12703 }
12704 dx_ent->block = ext2fs_cpu_to_le32(i);
12705 if (c2 != limit->limit)
12706 dx_ent->hash =
12707 ext2fs_cpu_to_le32(outdir->hashes[i]);
12708 dx_ent++;
12709 c2--;
12710 }
12711 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
12712 limit->limit = ext2fs_cpu_to_le16(limit->limit);
12713 }
12714 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
12715 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
12716 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
12717
12718 return 0;
12719}
12720
12721struct write_dir_struct {
12722 struct out_dir *outdir;
12723 errcode_t err;
12724 e2fsck_t ctx;
12725 int cleared;
12726};
12727
12728/*
12729 * Helper function which writes out a directory block.
12730 */
12731static int write_dir_block(ext2_filsys fs,
12732 blk_t *block_nr,
12733 e2_blkcnt_t blockcnt,
12734 blk_t ref_block EXT2FS_ATTR((unused)),
12735 int ref_offset EXT2FS_ATTR((unused)),
12736 void *priv_data)
12737{
12738 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
12739 blk_t blk;
12740 char *dir;
12741
12742 if (*block_nr == 0)
12743 return 0;
12744 if (blockcnt >= wd->outdir->num) {
12745 e2fsck_read_bitmaps(wd->ctx);
12746 blk = *block_nr;
12747 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
12748 ext2fs_block_alloc_stats(fs, blk, -1);
12749 *block_nr = 0;
12750 wd->cleared++;
12751 return BLOCK_CHANGED;
12752 }
12753 if (blockcnt < 0)
12754 return 0;
12755
12756 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
12757 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
12758 if (wd->err)
12759 return BLOCK_ABORT;
12760 return 0;
12761}
12762
12763static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
12764 struct out_dir *outdir,
12765 ext2_ino_t ino, int compress)
12766{
12767 struct write_dir_struct wd;
12768 errcode_t retval;
12769 struct ext2_inode inode;
12770
12771 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
12772 if (retval)
12773 return retval;
12774
12775 wd.outdir = outdir;
12776 wd.err = 0;
12777 wd.ctx = ctx;
12778 wd.cleared = 0;
12779
12780 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12781 write_dir_block, &wd);
12782 if (retval)
12783 return retval;
12784 if (wd.err)
12785 return wd.err;
12786
12787 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12788 if (compress)
12789 inode.i_flags &= ~EXT2_INDEX_FL;
12790 else
12791 inode.i_flags |= EXT2_INDEX_FL;
12792 inode.i_size = outdir->num * fs->blocksize;
12793 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
12794 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
12795
12796 return 0;
12797}
12798
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012799static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012800{
12801 ext2_filsys fs = ctx->fs;
12802 errcode_t retval;
12803 struct ext2_inode inode;
12804 char *dir_buf = 0;
12805 struct fill_dir_struct fd;
12806 struct out_dir outdir;
12807
12808 outdir.max = outdir.num = 0;
12809 outdir.buf = 0;
12810 outdir.hashes = 0;
12811 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
12812
12813 retval = ENOMEM;
12814 fd.harray = 0;
12815 dir_buf = malloc(inode.i_size);
12816 if (!dir_buf)
12817 goto errout;
12818
12819 fd.max_array = inode.i_size / 32;
12820 fd.num_array = 0;
12821 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
12822 if (!fd.harray)
12823 goto errout;
12824
12825 fd.ctx = ctx;
12826 fd.buf = dir_buf;
12827 fd.inode = &inode;
12828 fd.err = 0;
12829 fd.dir_size = 0;
12830 fd.compress = 0;
12831 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
12832 (inode.i_size / fs->blocksize) < 2)
12833 fd.compress = 1;
12834 fd.parent = 0;
12835
12836 /* Read in the entire directory into memory */
12837 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
12838 fill_dir_block, &fd);
12839 if (fd.err) {
12840 retval = fd.err;
12841 goto errout;
12842 }
12843
12844#if 0
12845 printf("%d entries (%d bytes) found in inode %d\n",
12846 fd.num_array, fd.dir_size, ino);
12847#endif
12848
12849 /* Sort the list */
12850resort:
12851 if (fd.compress)
12852 qsort(fd.harray+2, fd.num_array-2,
12853 sizeof(struct hash_entry), name_cmp);
12854 else
12855 qsort(fd.harray, fd.num_array,
12856 sizeof(struct hash_entry), hash_cmp);
12857
12858 /*
12859 * Look for duplicates
12860 */
12861 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
12862 goto resort;
12863
12864 if (ctx->options & E2F_OPT_NO) {
12865 retval = 0;
12866 goto errout;
12867 }
12868
12869 /*
12870 * Copy the directory entries. In a htree directory these
12871 * will become the leaf nodes.
12872 */
12873 retval = copy_dir_entries(fs, &fd, &outdir);
12874 if (retval)
12875 goto errout;
12876
12877 free(dir_buf); dir_buf = 0;
12878
12879 if (!fd.compress) {
12880 /* Calculate the interior nodes */
12881 retval = calculate_tree(fs, &outdir, ino, fd.parent);
12882 if (retval)
12883 goto errout;
12884 }
12885
12886 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
12887 if (retval)
12888 goto errout;
12889
12890errout:
12891 if (dir_buf)
12892 free(dir_buf);
12893 if (fd.harray)
12894 free(fd.harray);
12895
12896 free_out_dir(&outdir);
12897 return retval;
12898}
12899
12900void e2fsck_rehash_directories(e2fsck_t ctx)
12901{
12902 struct problem_context pctx;
12903#ifdef RESOURCE_TRACK
12904 struct resource_track rtrack;
12905#endif
12906 struct dir_info *dir;
12907 ext2_u32_iterate iter;
12908 ext2_ino_t ino;
12909 errcode_t retval;
12910 int i, cur, max, all_dirs, dir_index, first = 1;
12911
12912#ifdef RESOURCE_TRACK
12913 init_resource_track(&rtrack);
12914#endif
12915
12916 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
12917
12918 if (!ctx->dirs_to_hash && !all_dirs)
12919 return;
12920
12921 e2fsck_get_lost_and_found(ctx, 0);
12922
12923 clear_problem_context(&pctx);
12924
12925 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
12926 cur = 0;
12927 if (all_dirs) {
12928 i = 0;
12929 max = e2fsck_get_num_dirinfo(ctx);
12930 } else {
12931 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
12932 &iter);
12933 if (retval) {
12934 pctx.errcode = retval;
12935 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
12936 return;
12937 }
12938 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
12939 }
12940 while (1) {
12941 if (all_dirs) {
12942 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
12943 break;
12944 ino = dir->ino;
12945 } else {
12946 if (!ext2fs_u32_list_iterate(iter, &ino))
12947 break;
12948 }
12949 if (ino == ctx->lost_and_found)
12950 continue;
12951 pctx.dir = ino;
12952 if (first) {
12953 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
12954 first = 0;
12955 }
12956#if 0
12957 fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
12958#endif
12959 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
12960 if (pctx.errcode) {
12961 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12962 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
12963 }
12964 if (ctx->progress && !ctx->progress_fd)
12965 e2fsck_simple_progress(ctx, "Rebuilding directory",
12966 100.0 * (float) (++cur) / (float) max, ino);
12967 }
12968 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
12969 if (!all_dirs)
12970 ext2fs_u32_list_iterate_end(iter);
12971
12972 if (ctx->dirs_to_hash)
12973 ext2fs_u32_list_free(ctx->dirs_to_hash);
12974 ctx->dirs_to_hash = 0;
12975
12976#ifdef RESOURCE_TRACK
12977 if (ctx->options & E2F_OPT_TIME2) {
12978 e2fsck_clear_progbar(ctx);
12979 print_resource_track("Pass 3A", &rtrack);
12980 }
12981#endif
12982}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000012983
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012984/*
12985 * linux/fs/revoke.c
12986 *
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000012987 * Journal revoke routines for the generic filesystem journaling code;
12988 * part of the ext2fs journaling system.
12989 *
12990 * Revoke is the mechanism used to prevent old log records for deleted
12991 * metadata from being replayed on top of newer data using the same
12992 * blocks. The revoke mechanism is used in two separate places:
12993 *
12994 * + Commit: during commit we write the entire list of the current
12995 * transaction's revoked blocks to the journal
12996 *
12997 * + Recovery: during recovery we record the transaction ID of all
12998 * revoked blocks. If there are multiple revoke records in the log
12999 * for a single block, only the last one counts, and if there is a log
13000 * entry for a block beyond the last revoke, then that log entry still
13001 * gets replayed.
13002 *
13003 * We can get interactions between revokes and new log data within a
13004 * single transaction:
13005 *
13006 * Block is revoked and then journaled:
13007 * The desired end result is the journaling of the new block, so we
13008 * cancel the revoke before the transaction commits.
13009 *
13010 * Block is journaled and then revoked:
13011 * The revoke must take precedence over the write of the block, so we
13012 * need either to cancel the journal entry or to write the revoke
13013 * later in the log than the log block. In this case, we choose the
13014 * latter: journaling a block cancels any revoke record for that block
13015 * in the current transaction, so any revoke for that block in the
13016 * transaction must have happened after the block was journaled and so
13017 * the revoke must take precedence.
13018 *
13019 * Block is revoked and then written as data:
13020 * The data write is allowed to succeed, but the revoke is _not_
13021 * cancelled. We still need to prevent old log records from
13022 * overwriting the new data. We don't even need to clear the revoke
13023 * bit here.
13024 *
13025 * Revoke information on buffers is a tri-state value:
13026 *
13027 * RevokeValid clear: no cached revoke status, need to look it up
13028 * RevokeValid set, Revoked clear:
13029 * buffer has not been revoked, and cancel_revoke
13030 * need do nothing.
13031 * RevokeValid set, Revoked set:
13032 * buffer has been revoked.
13033 */
13034
13035static kmem_cache_t *revoke_record_cache;
13036static kmem_cache_t *revoke_table_cache;
13037
13038/* Each revoke record represents one single revoked block. During
13039 journal replay, this involves recording the transaction ID of the
13040 last transaction to revoke this block. */
13041
13042struct jbd_revoke_record_s
13043{
13044 struct list_head hash;
13045 tid_t sequence; /* Used for recovery only */
13046 unsigned long blocknr;
13047};
13048
13049
13050/* The revoke table is just a simple hash table of revoke records. */
13051struct jbd_revoke_table_s
13052{
13053 /* It is conceivable that we might want a larger hash table
13054 * for recovery. Must be a power of two. */
13055 int hash_size;
13056 int hash_shift;
13057 struct list_head *hash_table;
13058};
13059
13060
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013061/* Utility functions to maintain the revoke table */
13062
13063/* Borrowed from buffer.c: this is a tried and tested block hash function */
13064static inline int hash(journal_t *journal, unsigned long block)
13065{
13066 struct jbd_revoke_table_s *table = journal->j_revoke;
13067 int hash_shift = table->hash_shift;
13068
13069 return ((block << (hash_shift - 6)) ^
13070 (block >> 13) ^
13071 (block << (hash_shift - 12))) & (table->hash_size - 1);
13072}
13073
13074static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
13075 tid_t seq)
13076{
13077 struct list_head *hash_list;
13078 struct jbd_revoke_record_s *record;
13079
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013080 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
13081 if (!record)
13082 goto oom;
13083
13084 record->sequence = seq;
13085 record->blocknr = blocknr;
13086 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13087 list_add(&record->hash, hash_list);
13088 return 0;
13089
13090oom:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013091 return -ENOMEM;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013092}
13093
13094/* Find a revoke record in the journal's hash table. */
13095
13096static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
13097 unsigned long blocknr)
13098{
13099 struct list_head *hash_list;
13100 struct jbd_revoke_record_s *record;
13101
13102 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13103
13104 record = (struct jbd_revoke_record_s *) hash_list->next;
13105 while (&(record->hash) != hash_list) {
13106 if (record->blocknr == blocknr)
13107 return record;
13108 record = (struct jbd_revoke_record_s *) record->hash.next;
13109 }
13110 return NULL;
13111}
13112
13113int journal_init_revoke_caches(void)
13114{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013115 revoke_record_cache = do_cache_create(sizeof(struct jbd_revoke_record_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013116 if (revoke_record_cache == 0)
13117 return -ENOMEM;
13118
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013119 revoke_table_cache = do_cache_create(sizeof(struct jbd_revoke_table_s));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013120 if (revoke_table_cache == 0) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013121 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013122 revoke_record_cache = NULL;
13123 return -ENOMEM;
13124 }
13125 return 0;
13126}
13127
13128void journal_destroy_revoke_caches(void)
13129{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013130 do_cache_destroy(revoke_record_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013131 revoke_record_cache = 0;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013132 do_cache_destroy(revoke_table_cache);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013133 revoke_table_cache = 0;
13134}
13135
13136/* Initialise the revoke table for a given journal to a given size. */
13137
13138int journal_init_revoke(journal_t *journal, int hash_size)
13139{
13140 int shift, tmp;
13141
13142 J_ASSERT (journal->j_revoke == NULL);
13143
13144 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
13145 if (!journal->j_revoke)
13146 return -ENOMEM;
13147
13148 /* Check that the hash_size is a power of two */
13149 J_ASSERT ((hash_size & (hash_size-1)) == 0);
13150
13151 journal->j_revoke->hash_size = hash_size;
13152
13153 shift = 0;
13154 tmp = hash_size;
13155 while((tmp >>= 1UL) != 0UL)
13156 shift++;
13157 journal->j_revoke->hash_shift = shift;
13158
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013159 journal->j_revoke->hash_table = malloc(hash_size * sizeof(struct list_head));
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013160 if (!journal->j_revoke->hash_table) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013161 free(journal->j_revoke);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013162 journal->j_revoke = NULL;
13163 return -ENOMEM;
13164 }
13165
13166 for (tmp = 0; tmp < hash_size; tmp++)
13167 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
13168
13169 return 0;
13170}
13171
13172/* Destoy a journal's revoke table. The table must already be empty! */
13173
13174void journal_destroy_revoke(journal_t *journal)
13175{
13176 struct jbd_revoke_table_s *table;
13177 struct list_head *hash_list;
13178 int i;
13179
13180 table = journal->j_revoke;
13181 if (!table)
13182 return;
13183
13184 for (i=0; i<table->hash_size; i++) {
13185 hash_list = &table->hash_table[i];
13186 J_ASSERT (list_empty(hash_list));
13187 }
13188
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013189 free(table->hash_table);
13190 free(table);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013191 journal->j_revoke = NULL;
13192}
13193
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013194/*
13195 * Revoke support for recovery.
13196 *
13197 * Recovery needs to be able to:
13198 *
13199 * record all revoke records, including the tid of the latest instance
13200 * of each revoke in the journal
13201 *
13202 * check whether a given block in a given transaction should be replayed
13203 * (ie. has not been revoked by a revoke record in that or a subsequent
13204 * transaction)
13205 *
13206 * empty the revoke table after recovery.
13207 */
13208
13209/*
13210 * First, setting revoke records. We create a new revoke record for
13211 * every block ever revoked in the log as we scan it for recovery, and
13212 * we update the existing records if we find multiple revokes for a
13213 * single block.
13214 */
13215
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013216int journal_set_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013217 tid_t sequence)
13218{
13219 struct jbd_revoke_record_s *record;
13220
13221 record = find_revoke_record(journal, blocknr);
13222 if (record) {
13223 /* If we have multiple occurences, only record the
13224 * latest sequence number in the hashed record */
13225 if (tid_gt(sequence, record->sequence))
13226 record->sequence = sequence;
13227 return 0;
13228 }
13229 return insert_revoke_hash(journal, blocknr, sequence);
13230}
13231
13232/*
13233 * Test revoke records. For a given block referenced in the log, has
13234 * that block been revoked? A revoke record with a given transaction
13235 * sequence number revokes all blocks in that transaction and earlier
13236 * ones, but later transactions still need replayed.
13237 */
13238
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013239int journal_test_revoke(journal_t *journal, unsigned long blocknr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013240 tid_t sequence)
13241{
13242 struct jbd_revoke_record_s *record;
13243
13244 record = find_revoke_record(journal, blocknr);
13245 if (!record)
13246 return 0;
13247 if (tid_gt(sequence, record->sequence))
13248 return 0;
13249 return 1;
13250}
13251
13252/*
13253 * Finally, once recovery is over, we need to clear the revoke table so
13254 * that it can be reused by the running filesystem.
13255 */
13256
13257void journal_clear_revoke(journal_t *journal)
13258{
13259 int i;
13260 struct list_head *hash_list;
13261 struct jbd_revoke_record_s *record;
13262 struct jbd_revoke_table_s *revoke_var;
13263
13264 revoke_var = journal->j_revoke;
13265
13266 for (i = 0; i < revoke_var->hash_size; i++) {
13267 hash_list = &revoke_var->hash_table[i];
13268 while (!list_empty(hash_list)) {
13269 record = (struct jbd_revoke_record_s*) hash_list->next;
13270 list_del(&record->hash);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013271 free(record);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013272 }
13273 }
13274}
13275
13276/*
13277 * e2fsck.c - superblock checks
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013278 */
13279
13280#define MIN_CHECK 1
13281#define MAX_CHECK 2
13282
13283static void check_super_value(e2fsck_t ctx, const char *descr,
13284 unsigned long value, int flags,
13285 unsigned long min_val, unsigned long max_val)
13286{
13287 struct problem_context pctx;
13288
13289 if (((flags & MIN_CHECK) && (value < min_val)) ||
13290 ((flags & MAX_CHECK) && (value > max_val))) {
13291 clear_problem_context(&pctx);
13292 pctx.num = value;
13293 pctx.str = descr;
13294 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13295 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13296 }
13297}
13298
13299/*
13300 * This routine may get stubbed out in special compilations of the
13301 * e2fsck code..
13302 */
13303#ifndef EXT2_SPECIAL_DEVICE_SIZE
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013304static errcode_t e2fsck_get_device_size(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013305{
13306 return (ext2fs_get_device_size(ctx->filesystem_name,
13307 EXT2_BLOCK_SIZE(ctx->fs->super),
13308 &ctx->num_blocks));
13309}
13310#endif
13311
13312/*
13313 * helper function to release an inode
13314 */
13315struct process_block_struct {
13316 e2fsck_t ctx;
13317 char *buf;
13318 struct problem_context *pctx;
13319 int truncating;
13320 int truncate_offset;
13321 e2_blkcnt_t truncate_block;
13322 int truncated_blocks;
13323 int abort;
13324 errcode_t errcode;
13325};
13326
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013327static int release_inode_block(ext2_filsys fs, blk_t *block_nr,
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013328 e2_blkcnt_t blockcnt,
13329 blk_t ref_blk EXT2FS_ATTR((unused)),
13330 int ref_offset EXT2FS_ATTR((unused)),
13331 void *priv_data)
13332{
13333 struct process_block_struct *pb;
13334 e2fsck_t ctx;
13335 struct problem_context *pctx;
13336 blk_t blk = *block_nr;
13337 int retval = 0;
13338
13339 pb = (struct process_block_struct *) priv_data;
13340 ctx = pb->ctx;
13341 pctx = pb->pctx;
13342
13343 pctx->blk = blk;
13344 pctx->blkcount = blockcnt;
13345
13346 if (HOLE_BLKADDR(blk))
13347 return 0;
13348
13349 if ((blk < fs->super->s_first_data_block) ||
13350 (blk >= fs->super->s_blocks_count)) {
13351 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
13352 return_abort:
13353 pb->abort = 1;
13354 return BLOCK_ABORT;
13355 }
13356
13357 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
13358 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
13359 goto return_abort;
13360 }
13361
13362 /*
13363 * If we are deleting an orphan, then we leave the fields alone.
13364 * If we are truncating an orphan, then update the inode fields
13365 * and clean up any partial block data.
13366 */
13367 if (pb->truncating) {
13368 /*
13369 * We only remove indirect blocks if they are
13370 * completely empty.
13371 */
13372 if (blockcnt < 0) {
13373 int i, limit;
13374 blk_t *bp;
13375
13376 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13377 pb->buf);
13378 if (pb->errcode)
13379 goto return_abort;
13380
13381 limit = fs->blocksize >> 2;
13382 for (i = 0, bp = (blk_t *) pb->buf;
13383 i < limit; i++, bp++)
13384 if (*bp)
13385 return 0;
13386 }
13387 /*
13388 * We don't remove direct blocks until we've reached
13389 * the truncation block.
13390 */
13391 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
13392 return 0;
13393 /*
13394 * If part of the last block needs truncating, we do
13395 * it here.
13396 */
13397 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
13398 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
13399 pb->buf);
13400 if (pb->errcode)
13401 goto return_abort;
13402 memset(pb->buf + pb->truncate_offset, 0,
13403 fs->blocksize - pb->truncate_offset);
13404 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
13405 pb->buf);
13406 if (pb->errcode)
13407 goto return_abort;
13408 }
13409 pb->truncated_blocks++;
13410 *block_nr = 0;
13411 retval |= BLOCK_CHANGED;
13412 }
13413
13414 ext2fs_block_alloc_stats(fs, blk, -1);
13415 return retval;
13416}
13417
13418/*
13419 * This function releases an inode. Returns 1 if an inconsistency was
13420 * found. If the inode has a link count, then it is being truncated and
13421 * not deleted.
13422 */
13423static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
13424 struct ext2_inode *inode, char *block_buf,
13425 struct problem_context *pctx)
13426{
13427 struct process_block_struct pb;
13428 ext2_filsys fs = ctx->fs;
13429 errcode_t retval;
13430 __u32 count;
13431
13432 if (!ext2fs_inode_has_valid_blocks(inode))
13433 return 0;
13434
13435 pb.buf = block_buf + 3 * ctx->fs->blocksize;
13436 pb.ctx = ctx;
13437 pb.abort = 0;
13438 pb.errcode = 0;
13439 pb.pctx = pctx;
13440 if (inode->i_links_count) {
13441 pb.truncating = 1;
13442 pb.truncate_block = (e2_blkcnt_t)
13443 ((((long long)inode->i_size_high << 32) +
13444 inode->i_size + fs->blocksize - 1) /
13445 fs->blocksize);
13446 pb.truncate_offset = inode->i_size % fs->blocksize;
13447 } else {
13448 pb.truncating = 0;
13449 pb.truncate_block = 0;
13450 pb.truncate_offset = 0;
13451 }
13452 pb.truncated_blocks = 0;
13453 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
13454 block_buf, release_inode_block, &pb);
13455 if (retval) {
13456 com_err("release_inode_blocks", retval,
13457 _("while calling ext2fs_block_iterate for inode %d"),
13458 ino);
13459 return 1;
13460 }
13461 if (pb.abort)
13462 return 1;
13463
13464 /* Refresh the inode since ext2fs_block_iterate may have changed it */
13465 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
13466
13467 if (pb.truncated_blocks)
13468 inode->i_blocks -= pb.truncated_blocks *
13469 (fs->blocksize / 512);
13470
13471 if (inode->i_file_acl) {
13472 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
13473 block_buf, -1, &count);
13474 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
13475 retval = 0;
13476 count = 1;
13477 }
13478 if (retval) {
13479 com_err("release_inode_blocks", retval,
13480 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
13481 ino);
13482 return 1;
13483 }
13484 if (count == 0)
13485 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
13486 inode->i_file_acl = 0;
13487 }
13488 return 0;
13489}
13490
13491/*
13492 * This function releases all of the orphan inodes. It returns 1 if
13493 * it hit some error, and 0 on success.
13494 */
13495static int release_orphan_inodes(e2fsck_t ctx)
13496{
13497 ext2_filsys fs = ctx->fs;
13498 ext2_ino_t ino, next_ino;
13499 struct ext2_inode inode;
13500 struct problem_context pctx;
13501 char *block_buf;
13502
13503 if ((ino = fs->super->s_last_orphan) == 0)
13504 return 0;
13505
13506 /*
13507 * Win or lose, we won't be using the head of the orphan inode
13508 * list again.
13509 */
13510 fs->super->s_last_orphan = 0;
13511 ext2fs_mark_super_dirty(fs);
13512
13513 /*
13514 * If the filesystem contains errors, don't run the orphan
13515 * list, since the orphan list can't be trusted; and we're
13516 * going to be running a full e2fsck run anyway...
13517 */
13518 if (fs->super->s_state & EXT2_ERROR_FS)
13519 return 0;
13520
13521 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
13522 (ino > fs->super->s_inodes_count)) {
13523 clear_problem_context(&pctx);
13524 pctx.ino = ino;
13525 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
13526 return 1;
13527 }
13528
13529 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
13530 "block iterate buffer");
13531 e2fsck_read_bitmaps(ctx);
13532
13533 while (ino) {
13534 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
13535 clear_problem_context(&pctx);
13536 pctx.ino = ino;
13537 pctx.inode = &inode;
13538 pctx.str = inode.i_links_count ? _("Truncating") :
13539 _("Clearing");
13540
13541 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
13542
13543 next_ino = inode.i_dtime;
13544 if (next_ino &&
13545 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
13546 (next_ino > fs->super->s_inodes_count))) {
13547 pctx.ino = next_ino;
13548 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
13549 goto return_abort;
13550 }
13551
13552 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
13553 goto return_abort;
13554
13555 if (!inode.i_links_count) {
13556 ext2fs_inode_alloc_stats2(fs, ino, -1,
13557 LINUX_S_ISDIR(inode.i_mode));
13558 inode.i_dtime = time(0);
13559 } else {
13560 inode.i_dtime = 0;
13561 }
13562 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
13563 ino = next_ino;
13564 }
13565 ext2fs_free_mem(&block_buf);
13566 return 0;
13567return_abort:
13568 ext2fs_free_mem(&block_buf);
13569 return 1;
13570}
13571
13572/*
13573 * Check the resize inode to make sure it is sane. We check both for
13574 * the case where on-line resizing is not enabled (in which case the
13575 * resize inode should be cleared) as well as the case where on-line
13576 * resizing is enabled.
13577 */
13578static void check_resize_inode(e2fsck_t ctx)
13579{
13580 ext2_filsys fs = ctx->fs;
13581 struct ext2_inode inode;
13582 struct problem_context pctx;
13583 int i, j, gdt_off, ind_off;
13584 blk_t blk, pblk, expect;
13585 __u32 *dind_buf = 0, *ind_buf;
13586 errcode_t retval;
13587
13588 clear_problem_context(&pctx);
13589
13590 /*
13591 * If the resize inode feature isn't set, then
13592 * s_reserved_gdt_blocks must be zero.
13593 */
13594 if (!(fs->super->s_feature_compat &
13595 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13596 if (fs->super->s_reserved_gdt_blocks) {
13597 pctx.num = fs->super->s_reserved_gdt_blocks;
13598 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
13599 &pctx)) {
13600 fs->super->s_reserved_gdt_blocks = 0;
13601 ext2fs_mark_super_dirty(fs);
13602 }
13603 }
13604 }
13605
13606 /* Read the resizde inode */
13607 pctx.ino = EXT2_RESIZE_INO;
13608 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
13609 if (retval) {
13610 if (fs->super->s_feature_compat &
13611 EXT2_FEATURE_COMPAT_RESIZE_INODE)
13612 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13613 return;
13614 }
13615
13616 /*
13617 * If the resize inode feature isn't set, check to make sure
13618 * the resize inode is cleared; then we're done.
13619 */
13620 if (!(fs->super->s_feature_compat &
13621 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
13622 for (i=0; i < EXT2_N_BLOCKS; i++) {
13623 if (inode.i_block[i])
13624 break;
13625 }
13626 if ((i < EXT2_N_BLOCKS) &&
13627 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
13628 memset(&inode, 0, sizeof(inode));
13629 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13630 "clear_resize");
13631 }
13632 return;
13633 }
13634
13635 /*
13636 * The resize inode feature is enabled; check to make sure the
13637 * only block in use is the double indirect block
13638 */
13639 blk = inode.i_block[EXT2_DIND_BLOCK];
13640 for (i=0; i < EXT2_N_BLOCKS; i++) {
13641 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
13642 break;
13643 }
13644 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
13645 !(inode.i_mode & LINUX_S_IFREG) ||
13646 (blk < fs->super->s_first_data_block ||
13647 blk >= fs->super->s_blocks_count)) {
13648 resize_inode_invalid:
13649 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
13650 memset(&inode, 0, sizeof(inode));
13651 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
13652 "clear_resize");
13653 ctx->flags |= E2F_FLAG_RESIZE_INODE;
13654 }
13655 if (!(ctx->options & E2F_OPT_READONLY)) {
13656 fs->super->s_state &= ~EXT2_VALID_FS;
13657 ext2fs_mark_super_dirty(fs);
13658 }
13659 goto cleanup;
13660 }
13661 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
13662 "resize dind buffer");
13663 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
13664
13665 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
13666 if (retval)
13667 goto resize_inode_invalid;
13668
13669 gdt_off = fs->desc_blocks;
13670 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
13671 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
13672 i++, gdt_off++, pblk++) {
13673 gdt_off %= fs->blocksize/4;
13674 if (dind_buf[gdt_off] != pblk)
13675 goto resize_inode_invalid;
13676 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
13677 if (retval)
13678 goto resize_inode_invalid;
13679 ind_off = 0;
13680 for (j = 1; j < fs->group_desc_count; j++) {
13681 if (!ext2fs_bg_has_super(fs, j))
13682 continue;
13683 expect = pblk + (j * fs->super->s_blocks_per_group);
13684 if (ind_buf[ind_off] != expect)
13685 goto resize_inode_invalid;
13686 ind_off++;
13687 }
13688 }
13689
13690cleanup:
13691 if (dind_buf)
13692 ext2fs_free_mem(&dind_buf);
13693
13694 }
13695
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013696static void check_super_block(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013697{
13698 ext2_filsys fs = ctx->fs;
13699 blk_t first_block, last_block;
13700 struct ext2_super_block *sb = fs->super;
13701 struct ext2_group_desc *gd;
13702 blk_t blocks_per_group = fs->super->s_blocks_per_group;
13703 blk_t bpg_max;
13704 int inodes_per_block;
13705 int ipg_max;
13706 int inode_size;
13707 dgrp_t i;
13708 blk_t should_be;
13709 struct problem_context pctx;
13710 __u32 free_blocks = 0, free_inodes = 0;
13711
13712 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
13713 ipg_max = inodes_per_block * (blocks_per_group - 4);
13714 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
13715 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
13716 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
13717 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
13718 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
13719
13720 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13721 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
13722 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
13723 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
13724 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
13725 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
13726
13727 clear_problem_context(&pctx);
13728
13729 /*
13730 * Verify the super block constants...
13731 */
13732 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
13733 MIN_CHECK, 1, 0);
13734 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
13735 MIN_CHECK, 1, 0);
13736 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
13737 MAX_CHECK, 0, sb->s_blocks_count);
13738 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
13739 MIN_CHECK | MAX_CHECK, 0,
13740 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
13741 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
13742 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
13743 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
13744 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
13745 bpg_max);
13746 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
13747 MIN_CHECK | MAX_CHECK, 8, bpg_max);
13748 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
13749 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
13750 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
13751 MAX_CHECK, 0, sb->s_blocks_count / 2);
13752 check_super_value(ctx, "reserved_gdt_blocks",
13753 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
13754 fs->blocksize/4);
13755 inode_size = EXT2_INODE_SIZE(sb);
13756 check_super_value(ctx, "inode_size",
13757 inode_size, MIN_CHECK | MAX_CHECK,
13758 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
13759 if (inode_size & (inode_size - 1)) {
13760 pctx.num = inode_size;
13761 pctx.str = "inode_size";
13762 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13763 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13764 return;
13765 }
13766
13767 if (!ctx->num_blocks) {
13768 pctx.errcode = e2fsck_get_device_size(ctx);
13769 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
13770 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
13771 ctx->flags |= E2F_FLAG_ABORT;
13772 return;
13773 }
13774 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
13775 (ctx->num_blocks < sb->s_blocks_count)) {
13776 pctx.blk = sb->s_blocks_count;
13777 pctx.blk2 = ctx->num_blocks;
13778 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
13779 ctx->flags |= E2F_FLAG_ABORT;
13780 return;
13781 }
13782 }
13783 }
13784
13785 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
13786 pctx.blk = EXT2_BLOCK_SIZE(sb);
13787 pctx.blk2 = EXT2_FRAG_SIZE(sb);
13788 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
13789 ctx->flags |= E2F_FLAG_ABORT;
13790 return;
13791 }
13792
13793 should_be = sb->s_frags_per_group >>
13794 (sb->s_log_block_size - sb->s_log_frag_size);
13795 if (sb->s_blocks_per_group != should_be) {
13796 pctx.blk = sb->s_blocks_per_group;
13797 pctx.blk2 = should_be;
13798 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
13799 ctx->flags |= E2F_FLAG_ABORT;
13800 return;
13801 }
13802
13803 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
13804 if (sb->s_first_data_block != should_be) {
13805 pctx.blk = sb->s_first_data_block;
13806 pctx.blk2 = should_be;
13807 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
13808 ctx->flags |= E2F_FLAG_ABORT;
13809 return;
13810 }
13811
13812 should_be = sb->s_inodes_per_group * fs->group_desc_count;
13813 if (sb->s_inodes_count != should_be) {
13814 pctx.ino = sb->s_inodes_count;
13815 pctx.ino2 = should_be;
13816 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
13817 sb->s_inodes_count = should_be;
13818 ext2fs_mark_super_dirty(fs);
13819 }
13820 }
13821
13822 /*
13823 * Verify the group descriptors....
13824 */
13825 first_block = sb->s_first_data_block;
13826 last_block = first_block + blocks_per_group;
13827
13828 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
13829 pctx.group = i;
13830
13831 if (i == fs->group_desc_count - 1)
13832 last_block = sb->s_blocks_count;
13833 if ((gd->bg_block_bitmap < first_block) ||
13834 (gd->bg_block_bitmap >= last_block)) {
13835 pctx.blk = gd->bg_block_bitmap;
13836 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
13837 gd->bg_block_bitmap = 0;
13838 }
13839 if (gd->bg_block_bitmap == 0) {
13840 ctx->invalid_block_bitmap_flag[i]++;
13841 ctx->invalid_bitmaps++;
13842 }
13843 if ((gd->bg_inode_bitmap < first_block) ||
13844 (gd->bg_inode_bitmap >= last_block)) {
13845 pctx.blk = gd->bg_inode_bitmap;
13846 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
13847 gd->bg_inode_bitmap = 0;
13848 }
13849 if (gd->bg_inode_bitmap == 0) {
13850 ctx->invalid_inode_bitmap_flag[i]++;
13851 ctx->invalid_bitmaps++;
13852 }
13853 if ((gd->bg_inode_table < first_block) ||
13854 ((gd->bg_inode_table +
13855 fs->inode_blocks_per_group - 1) >= last_block)) {
13856 pctx.blk = gd->bg_inode_table;
13857 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
13858 gd->bg_inode_table = 0;
13859 }
13860 if (gd->bg_inode_table == 0) {
13861 ctx->invalid_inode_table_flag[i]++;
13862 ctx->invalid_bitmaps++;
13863 }
13864 free_blocks += gd->bg_free_blocks_count;
13865 free_inodes += gd->bg_free_inodes_count;
13866 first_block += sb->s_blocks_per_group;
13867 last_block += sb->s_blocks_per_group;
13868
13869 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
13870 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
13871 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
13872 ext2fs_unmark_valid(fs);
13873
13874 }
13875
13876 /*
13877 * Update the global counts from the block group counts. This
13878 * is needed for an experimental patch which eliminates
13879 * locking the entire filesystem when allocating blocks or
13880 * inodes; if the filesystem is not unmounted cleanly, the
13881 * global counts may not be accurate.
13882 */
13883 if ((free_blocks != sb->s_free_blocks_count) ||
13884 (free_inodes != sb->s_free_inodes_count)) {
13885 if (ctx->options & E2F_OPT_READONLY)
13886 ext2fs_unmark_valid(fs);
13887 else {
13888 sb->s_free_blocks_count = free_blocks;
13889 sb->s_free_inodes_count = free_inodes;
13890 ext2fs_mark_super_dirty(fs);
13891 }
13892 }
13893
13894 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
13895 (sb->s_free_inodes_count > sb->s_inodes_count))
13896 ext2fs_unmark_valid(fs);
13897
13898
13899 /*
13900 * If we have invalid bitmaps, set the error state of the
13901 * filesystem.
13902 */
13903 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
13904 sb->s_state &= ~EXT2_VALID_FS;
13905 ext2fs_mark_super_dirty(fs);
13906 }
13907
13908 clear_problem_context(&pctx);
13909
13910#ifndef EXT2_SKIP_UUID
13911 /*
13912 * If the UUID field isn't assigned, assign it.
13913 */
13914 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
13915 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
13916 uuid_generate(sb->s_uuid);
13917 ext2fs_mark_super_dirty(fs);
13918 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
13919 }
13920 }
13921#endif
13922
13923 /*
13924 * For the Hurd, check to see if the filetype option is set,
13925 * since it doesn't support it.
13926 */
13927 if (!(ctx->options & E2F_OPT_READONLY) &&
13928 fs->super->s_creator_os == EXT2_OS_HURD &&
13929 (fs->super->s_feature_incompat &
13930 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
13931 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
13932 fs->super->s_feature_incompat &=
13933 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
13934 ext2fs_mark_super_dirty(fs);
13935
13936 }
13937 }
13938
13939 /*
13940 * If we have any of the compatibility flags set, we need to have a
13941 * revision 1 filesystem. Most kernels will not check the flags on
13942 * a rev 0 filesystem and we may have corruption issues because of
13943 * the incompatible changes to the filesystem.
13944 */
13945 if (!(ctx->options & E2F_OPT_READONLY) &&
13946 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
13947 (fs->super->s_feature_compat ||
13948 fs->super->s_feature_ro_compat ||
13949 fs->super->s_feature_incompat) &&
13950 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
13951 ext2fs_update_dynamic_rev(fs);
13952 ext2fs_mark_super_dirty(fs);
13953 }
13954
13955 check_resize_inode(ctx);
13956
13957 /*
13958 * Clean up any orphan inodes, if present.
13959 */
13960 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
13961 fs->super->s_state &= ~EXT2_VALID_FS;
13962 ext2fs_mark_super_dirty(fs);
13963 }
13964
13965 /*
13966 * Move the ext3 journal file, if necessary.
13967 */
13968 e2fsck_move_ext3_journal(ctx);
13969 return;
13970}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000013971
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013972/*
13973 * swapfs.c --- byte-swap an ext2 filesystem
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000013974 */
13975
13976#ifdef ENABLE_SWAPFS
13977
13978struct swap_block_struct {
13979 ext2_ino_t ino;
13980 int isdir;
13981 errcode_t errcode;
13982 char *dir_buf;
13983 struct ext2_inode *inode;
13984};
13985
13986/*
13987 * This is a helper function for block_iterate. We mark all of the
13988 * indirect and direct blocks as changed, so that block_iterate will
13989 * write them out.
13990 */
13991static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
13992 void *priv_data)
13993{
13994 errcode_t retval;
13995
13996 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
13997
13998 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
13999 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
14000 if (retval) {
14001 sb->errcode = retval;
14002 return BLOCK_ABORT;
14003 }
14004 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
14005 if (retval) {
14006 sb->errcode = retval;
14007 return BLOCK_ABORT;
14008 }
14009 }
14010 if (blockcnt >= 0) {
14011 if (blockcnt < EXT2_NDIR_BLOCKS)
14012 return 0;
14013 return BLOCK_CHANGED;
14014 }
14015 if (blockcnt == BLOCK_COUNT_IND) {
14016 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
14017 return 0;
14018 return BLOCK_CHANGED;
14019 }
14020 if (blockcnt == BLOCK_COUNT_DIND) {
14021 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
14022 return 0;
14023 return BLOCK_CHANGED;
14024 }
14025 if (blockcnt == BLOCK_COUNT_TIND) {
14026 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
14027 return 0;
14028 return BLOCK_CHANGED;
14029 }
14030 return BLOCK_CHANGED;
14031}
14032
14033/*
14034 * This function is responsible for byte-swapping all of the indirect,
14035 * block pointers. It is also responsible for byte-swapping directories.
14036 */
14037static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
14038 struct ext2_inode *inode)
14039{
14040 errcode_t retval;
14041 struct swap_block_struct sb;
14042
14043 sb.ino = ino;
14044 sb.inode = inode;
14045 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
14046 sb.errcode = 0;
14047 sb.isdir = 0;
14048 if (LINUX_S_ISDIR(inode->i_mode))
14049 sb.isdir = 1;
14050
14051 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
14052 swap_block, &sb);
14053 if (retval) {
14054 com_err("swap_inode_blocks", retval,
14055 _("while calling ext2fs_block_iterate"));
14056 ctx->flags |= E2F_FLAG_ABORT;
14057 return;
14058 }
14059 if (sb.errcode) {
14060 com_err("swap_inode_blocks", sb.errcode,
14061 _("while calling iterator function"));
14062 ctx->flags |= E2F_FLAG_ABORT;
14063 return;
14064 }
14065}
14066
14067static void swap_inodes(e2fsck_t ctx)
14068{
14069 ext2_filsys fs = ctx->fs;
14070 dgrp_t group;
14071 unsigned int i;
14072 ext2_ino_t ino = 1;
14073 char *buf, *block_buf;
14074 errcode_t retval;
14075 struct ext2_inode * inode;
14076
14077 e2fsck_use_inode_shortcuts(ctx, 1);
14078
14079 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
14080 &buf);
14081 if (retval) {
14082 com_err("swap_inodes", retval,
14083 _("while allocating inode buffer"));
14084 ctx->flags |= E2F_FLAG_ABORT;
14085 return;
14086 }
14087 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
14088 "block interate buffer");
14089 for (group = 0; group < fs->group_desc_count; group++) {
14090 retval = io_channel_read_blk(fs->io,
14091 fs->group_desc[group].bg_inode_table,
14092 fs->inode_blocks_per_group, buf);
14093 if (retval) {
14094 com_err("swap_inodes", retval,
14095 _("while reading inode table (group %d)"),
14096 group);
14097 ctx->flags |= E2F_FLAG_ABORT;
14098 return;
14099 }
14100 inode = (struct ext2_inode *) buf;
14101 for (i=0; i < fs->super->s_inodes_per_group;
14102 i++, ino++, inode++) {
14103 ctx->stashed_ino = ino;
14104 ctx->stashed_inode = inode;
14105
14106 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
14107 ext2fs_swap_inode(fs, inode, inode, 0);
14108
14109 /*
14110 * Skip deleted files.
14111 */
14112 if (inode->i_links_count == 0)
14113 continue;
14114
14115 if (LINUX_S_ISDIR(inode->i_mode) ||
14116 ((inode->i_block[EXT2_IND_BLOCK] ||
14117 inode->i_block[EXT2_DIND_BLOCK] ||
14118 inode->i_block[EXT2_TIND_BLOCK]) &&
14119 ext2fs_inode_has_valid_blocks(inode)))
14120 swap_inode_blocks(ctx, ino, block_buf, inode);
14121
14122 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14123 return;
14124
14125 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14126 ext2fs_swap_inode(fs, inode, inode, 1);
14127 }
14128 retval = io_channel_write_blk(fs->io,
14129 fs->group_desc[group].bg_inode_table,
14130 fs->inode_blocks_per_group, buf);
14131 if (retval) {
14132 com_err("swap_inodes", retval,
14133 _("while writing inode table (group %d)"),
14134 group);
14135 ctx->flags |= E2F_FLAG_ABORT;
14136 return;
14137 }
14138 }
14139 ext2fs_free_mem(&buf);
14140 ext2fs_free_mem(&block_buf);
14141 e2fsck_use_inode_shortcuts(ctx, 0);
14142 ext2fs_flush_icache(fs);
14143}
14144
14145#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
14146/*
14147 * On the PowerPC, the big-endian variant of the ext2 filesystem
14148 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
14149 * of each word. Thus a bitmap with only bit 0 set would be, as
14150 * a string of bytes, 00 00 00 01 00 ...
14151 * To cope with this, we byte-reverse each word of a bitmap if
14152 * we have a big-endian filesystem, that is, if we are *not*
14153 * byte-swapping other word-sized numbers.
14154 */
14155#define EXT2_BIG_ENDIAN_BITMAPS
14156#endif
14157
14158#ifdef EXT2_BIG_ENDIAN_BITMAPS
14159static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
14160{
14161 __u32 *p = (__u32 *) bmap->bitmap;
14162 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
14163
14164 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
14165 *p = ext2fs_swab32(*p);
14166}
14167#endif
14168
14169
14170#ifdef ENABLE_SWAPFS
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014171static void swap_filesys(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014172{
14173 ext2_filsys fs = ctx->fs;
14174#ifdef RESOURCE_TRACK
14175 struct resource_track rtrack;
14176
14177 init_resource_track(&rtrack);
14178#endif
14179
14180 if (!(ctx->options & E2F_OPT_PREEN))
14181 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
14182
14183#ifdef MTRACE
14184 mtrace_print("Byte swap");
14185#endif
14186
14187 if (fs->super->s_mnt_count) {
14188 fprintf(stderr, _("%s: the filesystem must be freshly "
14189 "checked using fsck\n"
14190 "and not mounted before trying to "
14191 "byte-swap it.\n"), ctx->device_name);
14192 ctx->flags |= E2F_FLAG_ABORT;
14193 return;
14194 }
14195 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
14196 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
14197 EXT2_FLAG_SWAP_BYTES_WRITE);
14198 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
14199 } else {
14200 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
14201 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
14202 }
14203 swap_inodes(ctx);
14204 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14205 return;
14206 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14207 fs->flags |= EXT2_FLAG_SWAP_BYTES;
14208 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
14209 EXT2_FLAG_SWAP_BYTES_WRITE);
14210
14211#ifdef EXT2_BIG_ENDIAN_BITMAPS
14212 e2fsck_read_bitmaps(ctx);
14213 ext2fs_swap_bitmap(fs->inode_map);
14214 ext2fs_swap_bitmap(fs->block_map);
14215 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
14216#endif
14217 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
14218 ext2fs_flush(fs);
14219 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
14220
14221#ifdef RESOURCE_TRACK
14222 if (ctx->options & E2F_OPT_TIME2)
14223 print_resource_track(_("Byte swap"), &rtrack);
14224#endif
14225}
14226#endif /* ENABLE_SWAPFS */
14227
14228#endif
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014229
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014230/*
14231 * util.c --- miscellaneous utilities
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014232 */
14233
14234#ifdef HAVE_CONIO_H
14235#undef HAVE_TERMIOS_H
14236#include <conio.h>
14237#define read_a_char() getch()
14238#else
14239#ifdef HAVE_TERMIOS_H
14240#include <termios.h>
14241#endif
14242#endif
14243
14244#if 0
14245void fatal_error(e2fsck_t ctx, const char *msg)
14246{
14247 if (msg)
14248 fprintf (stderr, "e2fsck: %s\n", msg);
14249 if (ctx->fs && ctx->fs->io) {
14250 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
14251 io_channel_flush(ctx->fs->io);
14252 else
14253 fprintf(stderr, "e2fsck: io manager magic bad!\n");
14254 }
14255 ctx->flags |= E2F_FLAG_ABORT;
14256 if (ctx->flags & E2F_FLAG_SETJMP_OK)
14257 longjmp(ctx->abort_loc, 1);
14258 exit(FSCK_ERROR);
14259}
14260#endif
14261
14262void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
14263 const char *description)
14264{
14265 void *ret;
14266 char buf[256];
14267
14268#ifdef DEBUG_ALLOCATE_MEMORY
14269 printf("Allocating %d bytes for %s...\n", size, description);
14270#endif
14271 ret = malloc(size);
14272 if (!ret) {
14273 sprintf(buf, "Can't allocate %s\n", description);
14274 fatal_error(ctx, buf);
14275 }
14276 memset(ret, 0, size);
14277 return ret;
14278}
14279
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014280static char *string_copy(const char *str, int len)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014281{
14282 char *ret;
14283
14284 if (!str)
14285 return NULL;
14286 if (!len)
14287 len = strlen(str);
14288 ret = malloc(len+1);
14289 if (ret) {
14290 strncpy(ret, str, len);
14291 ret[len] = 0;
14292 }
14293 return ret;
14294}
14295
14296#ifndef HAVE_CONIO_H
14297static int read_a_char(void)
14298{
14299 char c;
14300 int r;
14301 int fail = 0;
14302
14303 while(1) {
14304 if (e2fsck_global_ctx &&
14305 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
14306 return 3;
14307 }
14308 r = read(0, &c, 1);
14309 if (r == 1)
14310 return c;
14311 if (fail++ > 100)
14312 break;
14313 }
14314 return EOF;
14315}
14316#endif
14317
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014318static int ask_yn(const char * string, int def)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014319{
14320 int c;
14321 const char *defstr;
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014322 static const char short_yes[] = "yY";
14323 static const char short_no[] = "nN";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014324
14325#ifdef HAVE_TERMIOS_H
14326 struct termios termios, tmp;
14327
14328 tcgetattr (0, &termios);
14329 tmp = termios;
14330 tmp.c_lflag &= ~(ICANON | ECHO);
14331 tmp.c_cc[VMIN] = 1;
14332 tmp.c_cc[VTIME] = 0;
14333 tcsetattr (0, TCSANOW, &tmp);
14334#endif
14335
14336 if (def == 1)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014337 defstr = "<y>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014338 else if (def == 0)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014339 defstr = "<n>";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014340 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014341 defstr = " (y/n)";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014342 printf("%s%s? ", string, defstr);
14343 while (1) {
14344 fflush (stdout);
14345 if ((c = read_a_char()) == EOF)
14346 break;
14347 if (c == 3) {
14348#ifdef HAVE_TERMIOS_H
14349 tcsetattr (0, TCSANOW, &termios);
14350#endif
14351 if (e2fsck_global_ctx &&
14352 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
14353 puts("\n");
14354 longjmp(e2fsck_global_ctx->abort_loc, 1);
14355 }
14356 puts(_("cancelled!\n"));
14357 return 0;
14358 }
14359 if (strchr(short_yes, (char) c)) {
14360 def = 1;
14361 break;
14362 }
14363 else if (strchr(short_no, (char) c)) {
14364 def = 0;
14365 break;
14366 }
14367 else if ((c == ' ' || c == '\n') && (def != -1))
14368 break;
14369 }
14370 if (def)
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014371 puts("yes\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014372 else
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014373 puts ("no\n");
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014374#ifdef HAVE_TERMIOS_H
14375 tcsetattr (0, TCSANOW, &termios);
14376#endif
14377 return def;
14378}
14379
14380int ask (e2fsck_t ctx, const char * string, int def)
14381{
14382 if (ctx->options & E2F_OPT_NO) {
14383 printf (_("%s? no\n\n"), string);
14384 return 0;
14385 }
14386 if (ctx->options & E2F_OPT_YES) {
14387 printf (_("%s? yes\n\n"), string);
14388 return 1;
14389 }
14390 if (ctx->options & E2F_OPT_PREEN) {
14391 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
14392 return def;
14393 }
14394 return ask_yn(string, def);
14395}
14396
14397void e2fsck_read_bitmaps(e2fsck_t ctx)
14398{
14399 ext2_filsys fs = ctx->fs;
14400 errcode_t retval;
14401
14402 if (ctx->invalid_bitmaps) {
14403 com_err(ctx->program_name, 0,
14404 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
14405 ctx->device_name);
14406 fatal_error(ctx, 0);
14407 }
14408
14409 ehandler_operation(_("reading inode and block bitmaps"));
14410 retval = ext2fs_read_bitmaps(fs);
14411 ehandler_operation(0);
14412 if (retval) {
14413 com_err(ctx->program_name, retval,
14414 _("while retrying to read bitmaps for %s"),
14415 ctx->device_name);
14416 fatal_error(ctx, 0);
14417 }
14418}
14419
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014420static void e2fsck_write_bitmaps(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014421{
14422 ext2_filsys fs = ctx->fs;
14423 errcode_t retval;
14424
14425 if (ext2fs_test_bb_dirty(fs)) {
14426 ehandler_operation(_("writing block bitmaps"));
14427 retval = ext2fs_write_block_bitmap(fs);
14428 ehandler_operation(0);
14429 if (retval) {
14430 com_err(ctx->program_name, retval,
14431 _("while retrying to write block bitmaps for %s"),
14432 ctx->device_name);
14433 fatal_error(ctx, 0);
14434 }
14435 }
14436
14437 if (ext2fs_test_ib_dirty(fs)) {
14438 ehandler_operation(_("writing inode bitmaps"));
14439 retval = ext2fs_write_inode_bitmap(fs);
14440 ehandler_operation(0);
14441 if (retval) {
14442 com_err(ctx->program_name, retval,
14443 _("while retrying to write inode bitmaps for %s"),
14444 ctx->device_name);
14445 fatal_error(ctx, 0);
14446 }
14447 }
14448}
14449
14450void preenhalt(e2fsck_t ctx)
14451{
14452 ext2_filsys fs = ctx->fs;
14453
14454 if (!(ctx->options & E2F_OPT_PREEN))
14455 return;
14456 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
14457 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
14458 ctx->device_name);
14459 if (fs != NULL) {
14460 fs->super->s_state |= EXT2_ERROR_FS;
14461 ext2fs_mark_super_dirty(fs);
14462 ext2fs_close(fs);
14463 }
14464 exit(FSCK_UNCORRECTED);
14465}
14466
14467#ifdef RESOURCE_TRACK
14468void init_resource_track(struct resource_track *track)
14469{
14470#ifdef HAVE_GETRUSAGE
14471 struct rusage r;
14472#endif
14473
14474 track->brk_start = sbrk(0);
14475 gettimeofday(&track->time_start, 0);
14476#ifdef HAVE_GETRUSAGE
14477#ifdef sun
14478 memset(&r, 0, sizeof(struct rusage));
14479#endif
14480 getrusage(RUSAGE_SELF, &r);
14481 track->user_start = r.ru_utime;
14482 track->system_start = r.ru_stime;
14483#else
14484 track->user_start.tv_sec = track->user_start.tv_usec = 0;
14485 track->system_start.tv_sec = track->system_start.tv_usec = 0;
14486#endif
14487}
14488
14489static _INLINE_ float timeval_subtract(struct timeval *tv1,
14490 struct timeval *tv2)
14491{
14492 return ((tv1->tv_sec - tv2->tv_sec) +
14493 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
14494}
14495
14496void print_resource_track(const char *desc, struct resource_track *track)
14497{
14498#ifdef HAVE_GETRUSAGE
14499 struct rusage r;
14500#endif
14501#ifdef HAVE_MALLINFO
14502 struct mallinfo malloc_info;
14503#endif
14504 struct timeval time_end;
14505
14506 gettimeofday(&time_end, 0);
14507
14508 if (desc)
14509 printf("%s: ", desc);
14510
14511#ifdef HAVE_MALLINFO
14512#define kbytes(x) (((x) + 1023) / 1024)
14513
14514 malloc_info = mallinfo();
14515 printf(_("Memory used: %dk/%dk (%dk/%dk), "),
14516 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
14517 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
14518#else
14519 printf(_("Memory used: %d, "),
14520 (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
14521#endif
14522#ifdef HAVE_GETRUSAGE
14523 getrusage(RUSAGE_SELF, &r);
14524
14525 printf(_("time: %5.2f/%5.2f/%5.2f\n"),
14526 timeval_subtract(&time_end, &track->time_start),
14527 timeval_subtract(&r.ru_utime, &track->user_start),
14528 timeval_subtract(&r.ru_stime, &track->system_start));
14529#else
14530 printf(_("elapsed time: %6.3f\n"),
14531 timeval_subtract(&time_end, &track->time_start));
14532#endif
14533}
14534#endif /* RESOURCE_TRACK */
14535
14536void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
14537 struct ext2_inode * inode, const char *proc)
14538{
14539 int retval;
14540
14541 retval = ext2fs_read_inode(ctx->fs, ino, inode);
14542 if (retval) {
14543 com_err("ext2fs_read_inode", retval,
14544 _("while reading inode %ld in %s"), ino, proc);
14545 fatal_error(ctx, 0);
14546 }
14547}
14548
14549extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
14550 struct ext2_inode * inode, int bufsize,
14551 const char *proc)
14552{
14553 int retval;
14554
14555 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
14556 if (retval) {
14557 com_err("ext2fs_write_inode", retval,
14558 _("while writing inode %ld in %s"), ino, proc);
14559 fatal_error(ctx, 0);
14560 }
14561}
14562
14563extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
14564 struct ext2_inode * inode, const char *proc)
14565{
14566 int retval;
14567
14568 retval = ext2fs_write_inode(ctx->fs, ino, inode);
14569 if (retval) {
14570 com_err("ext2fs_write_inode", retval,
14571 _("while writing inode %ld in %s"), ino, proc);
14572 fatal_error(ctx, 0);
14573 }
14574}
14575
14576#ifdef MTRACE
14577void mtrace_print(char *mesg)
14578{
14579 FILE *malloc_get_mallstream();
14580 FILE *f = malloc_get_mallstream();
14581
14582 if (f)
14583 fprintf(f, "============= %s\n", mesg);
14584}
14585#endif
14586
14587blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
14588 io_manager manager)
14589{
14590 struct ext2_super_block *sb;
14591 io_channel io = NULL;
14592 void *buf = NULL;
14593 int blocksize;
14594 blk_t superblock, ret_sb = 8193;
14595
14596 if (fs && fs->super) {
14597 ret_sb = (fs->super->s_blocks_per_group +
14598 fs->super->s_first_data_block);
14599 if (ctx) {
14600 ctx->superblock = ret_sb;
14601 ctx->blocksize = fs->blocksize;
14602 }
14603 return ret_sb;
14604 }
14605
14606 if (ctx) {
14607 if (ctx->blocksize) {
14608 ret_sb = ctx->blocksize * 8;
14609 if (ctx->blocksize == 1024)
14610 ret_sb++;
14611 ctx->superblock = ret_sb;
14612 return ret_sb;
14613 }
14614 ctx->superblock = ret_sb;
14615 ctx->blocksize = 1024;
14616 }
14617
14618 if (!name || !manager)
14619 goto cleanup;
14620
14621 if (manager->open(name, 0, &io) != 0)
14622 goto cleanup;
14623
14624 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
14625 goto cleanup;
14626 sb = (struct ext2_super_block *) buf;
14627
14628 for (blocksize = EXT2_MIN_BLOCK_SIZE;
14629 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
14630 superblock = blocksize*8;
14631 if (blocksize == 1024)
14632 superblock++;
14633 io_channel_set_blksize(io, blocksize);
14634 if (io_channel_read_blk(io, superblock,
14635 -SUPERBLOCK_SIZE, buf))
14636 continue;
14637#ifdef EXT2FS_ENABLE_SWAPFS
14638 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
14639 ext2fs_swap_super(sb);
14640#endif
14641 if (sb->s_magic == EXT2_SUPER_MAGIC) {
14642 ret_sb = superblock;
14643 if (ctx) {
14644 ctx->superblock = superblock;
14645 ctx->blocksize = blocksize;
14646 }
14647 break;
14648 }
14649 }
14650
14651cleanup:
14652 if (io)
14653 io_channel_close(io);
14654 if (buf)
14655 ext2fs_free_mem(&buf);
14656 return (ret_sb);
14657}
14658
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014659
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014660/*
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014661 * This function runs through the e2fsck passes and calls them all,
14662 * returning restart, abort, or cancel as necessary...
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014663 */
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014664typedef void (*pass_t)(e2fsck_t ctx);
14665
14666static const pass_t e2fsck_passes[] = {
14667 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
14668 e2fsck_pass5, 0 };
14669
14670#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
14671
14672static int e2fsck_run(e2fsck_t ctx)
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014673{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014674 int i;
14675 pass_t e2fsck_pass;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014676
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014677 if (setjmp(ctx->abort_loc)) {
14678 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
14679 return (ctx->flags & E2F_FLAG_RUN_RETURN);
14680 }
14681 ctx->flags |= E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014682
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014683 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
14684 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14685 break;
14686 e2fsck_pass(ctx);
14687 if (ctx->progress)
14688 (void) (ctx->progress)(ctx, 0, 0, 0);
14689 }
14690 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014691
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014692 if (ctx->flags & E2F_FLAG_RUN_RETURN)
14693 return (ctx->flags & E2F_FLAG_RUN_RETURN);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014694 return 0;
14695}
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014696
14697
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014698/*
14699 * unix.c - The unix-specific code for e2fsck
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014700 */
14701
14702
Mike Frysinger51a43b42005-09-24 07:11:16 +000014703/* Command line options */
14704static int swapfs;
14705#ifdef ENABLE_SWAPFS
14706static int normalize_swapfs;
14707#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014708static int cflag; /* check disk */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014709static int show_version_only;
14710static int verbose;
14711
14712static int replace_bad_blocks;
14713static int keep_bad_blocks;
14714static char *bad_blocks_file;
14715
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014716#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
Mike Frysinger51a43b42005-09-24 07:11:16 +000014717int journal_enable_debug = -1;
14718#endif
14719
14720#if 0
14721static void usage(e2fsck_t ctx)
14722{
14723 fprintf(stderr,
14724 _("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n"
14725 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
14726 "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal]\n"
14727 "\t\t[-E extended-options] device\n"),
14728 ctx->program_name);
14729
14730 fprintf(stderr, _("\nEmergency help:\n"
14731 " -p Automatic repair (no questions)\n"
14732 " -n Make no changes to the filesystem\n"
14733 " -y Assume \"yes\" to all questions\n"
14734 " -c Check for bad blocks and add them to the badblock list\n"
14735 " -f Force checking even if filesystem is marked clean\n"));
14736 fprintf(stderr, _(""
14737 " -v Be verbose\n"
14738 " -b superblock Use alternative superblock\n"
14739 " -B blocksize Force blocksize when looking for superblock\n"
14740 " -j external-journal Set location of the external journal\n"
14741 " -l bad_blocks_file Add to badblocks list\n"
14742 " -L bad_blocks_file Set badblocks list\n"
14743 ));
14744
14745 exit(FSCK_USAGE);
14746}
14747#endif
14748
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014749#define P_E2(singular, plural, n) n, ((n) == 1 ? singular : plural)
14750
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014751static void show_stats(e2fsck_t ctx)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014752{
14753 ext2_filsys fs = ctx->fs;
14754 int inodes, inodes_used, blocks, blocks_used;
14755 int dir_links;
14756 int num_files, num_links;
14757 int frag_percent;
14758
14759 dir_links = 2 * ctx->fs_directory_count - 1;
14760 num_files = ctx->fs_total_count - dir_links;
14761 num_links = ctx->fs_links_count - dir_links;
14762 inodes = fs->super->s_inodes_count;
14763 inodes_used = (fs->super->s_inodes_count -
14764 fs->super->s_free_inodes_count);
14765 blocks = fs->super->s_blocks_count;
14766 blocks_used = (fs->super->s_blocks_count -
14767 fs->super->s_free_blocks_count);
14768
14769 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
14770 frag_percent = (frag_percent + 5) / 10;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014771
Mike Frysinger51a43b42005-09-24 07:11:16 +000014772 if (!verbose) {
14773 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
14774 ctx->device_name, inodes_used, inodes,
14775 frag_percent / 10, frag_percent % 10,
14776 blocks_used, blocks);
14777 return;
14778 }
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014779 printf ("\n%8d inode%s used (%d%%)\n", P_E2("", "s", inodes_used),
14780 100 * inodes_used / inodes);
14781 printf ("%8d non-contiguous inode%s (%0d.%d%%)\n",
14782 P_E2("", "s", ctx->fs_fragmented),
14783 frag_percent / 10, frag_percent % 10);
Mike Frysinger51a43b42005-09-24 07:11:16 +000014784 printf (_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
14785 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014786 printf ("%8d block%s used (%d%%)\n", P_E2("", "s", blocks_used),
14787 (int) ((long long) 100 * blocks_used / blocks));
14788 printf ("%8d bad block%s\n", P_E2("", "s", ctx->fs_badblocks_count));
14789 printf ("%8d large file%s\n", P_E2("", "s", ctx->large_files));
14790 printf ("\n%8d regular file%s\n", P_E2("", "s", ctx->fs_regular_count));
14791 printf ("%8d director%s\n", P_E2("y", "ies", ctx->fs_directory_count));
14792 printf ("%8d character device file%s\n", P_E2("", "s", ctx->fs_chardev_count));
14793 printf ("%8d block device file%s\n", P_E2("", "s", ctx->fs_blockdev_count));
14794 printf ("%8d fifo%s\n", P_E2("", "s", ctx->fs_fifo_count));
14795 printf ("%8d link%s\n", P_E2("", "s", ctx->fs_links_count - dir_links));
14796 printf ("%8d symbolic link%s", P_E2("", "s", ctx->fs_symlinks_count));
14797 printf (" (%d fast symbolic link%s)\n", P_E2("", "s", ctx->fs_fast_symlinks_count));
14798 printf ("%8d socket%s--------\n\n", P_E2("", "s", ctx->fs_sockets_count));
14799 printf ("%8d file%s\n", P_E2("", "s", ctx->fs_total_count - dir_links));
Mike Frysinger51a43b42005-09-24 07:11:16 +000014800}
14801
14802static void check_mount(e2fsck_t ctx)
14803{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014804 errcode_t retval;
14805 int cont;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014806
14807 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
14808 &ctx->mount_flags);
14809 if (retval) {
14810 com_err("ext2fs_check_if_mount", retval,
14811 _("while determining whether %s is mounted."),
14812 ctx->filesystem_name);
14813 return;
14814 }
14815
14816 /*
14817 * If the filesystem isn't mounted, or it's the root filesystem
14818 * and it's mounted read-only, then everything's fine.
14819 */
14820 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) ||
14821 ((ctx->mount_flags & EXT2_MF_ISROOT) &&
14822 (ctx->mount_flags & EXT2_MF_READONLY)))
14823 return;
14824
14825 if (ctx->options & E2F_OPT_READONLY) {
14826 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name);
14827 return;
14828 }
14829
14830 printf(_("%s is mounted. "), ctx->filesystem_name);
14831 if (!ctx->interactive)
14832 fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
14833 printf(_("\n\n\007\007\007\007WARNING!!! "
14834 "Running e2fsck on a mounted filesystem may cause\n"
14835 "SEVERE filesystem damage.\007\007\007\n\n"));
14836 cont = ask_yn(_("Do you really want to continue"), -1);
14837 if (!cont) {
14838 printf (_("check aborted.\n"));
14839 exit (0);
14840 }
14841 return;
14842}
14843
14844static int is_on_batt(void)
14845{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014846 FILE *f;
14847 DIR *d;
14848 char tmp[80], tmp2[80], fname[80];
14849 unsigned int acflag;
14850 struct dirent* de;
Mike Frysinger51a43b42005-09-24 07:11:16 +000014851
14852 f = fopen("/proc/apm", "r");
14853 if (f) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014854 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014855 acflag = 1;
14856 fclose(f);
14857 return (acflag != 1);
14858 }
14859 d = opendir("/proc/acpi/ac_adapter");
14860 if (d) {
14861 while ((de=readdir(d)) != NULL) {
14862 if (!strncmp(".", de->d_name, 1))
14863 continue;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014864 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
Mike Frysinger51a43b42005-09-24 07:11:16 +000014865 de->d_name);
14866 f = fopen(fname, "r");
14867 if (!f)
14868 continue;
14869 if (fscanf(f, "%s %s", tmp2, tmp) != 2)
14870 tmp[0] = 0;
14871 fclose(f);
14872 if (strncmp(tmp, "off-line", 8) == 0) {
14873 closedir(d);
14874 return 1;
14875 }
14876 }
14877 closedir(d);
14878 }
14879 return 0;
14880}
14881
14882/*
14883 * This routine checks to see if a filesystem can be skipped; if so,
14884 * it will exit with E2FSCK_OK. Under some conditions it will print a
14885 * message explaining why a check is being forced.
14886 */
14887static void check_if_skip(e2fsck_t ctx)
14888{
14889 ext2_filsys fs = ctx->fs;
14890 const char *reason = NULL;
14891 unsigned int reason_arg = 0;
14892 long next_check;
14893 int batt = is_on_batt();
14894 time_t now = time(0);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014895
Mike Frysinger51a43b42005-09-24 07:11:16 +000014896 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
14897 cflag || swapfs)
14898 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014899
Mike Frysinger51a43b42005-09-24 07:11:16 +000014900 if ((fs->super->s_state & EXT2_ERROR_FS) ||
14901 !ext2fs_test_valid(fs))
14902 reason = _(" contains a file system with errors");
14903 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
14904 reason = _(" was not cleanly unmounted");
14905 else if ((fs->super->s_max_mnt_count > 0) &&
14906 (fs->super->s_mnt_count >=
14907 (unsigned) fs->super->s_max_mnt_count)) {
14908 reason = _(" has been mounted %u times without being checked");
14909 reason_arg = fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014910 if (batt && (fs->super->s_mnt_count <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014911 (unsigned) fs->super->s_max_mnt_count*2))
14912 reason = 0;
14913 } else if (fs->super->s_checkinterval &&
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014914 ((now - fs->super->s_lastcheck) >=
Mike Frysinger51a43b42005-09-24 07:11:16 +000014915 fs->super->s_checkinterval)) {
14916 reason = _(" has gone %u days without being checked");
14917 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014918 if (batt && ((now - fs->super->s_lastcheck) <
Mike Frysinger51a43b42005-09-24 07:11:16 +000014919 fs->super->s_checkinterval*2))
14920 reason = 0;
14921 }
14922 if (reason) {
14923 fputs(ctx->device_name, stdout);
14924 printf(reason, reason_arg);
14925 fputs(_(", check forced.\n"), stdout);
14926 return;
14927 }
14928 printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name,
14929 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
14930 fs->super->s_inodes_count,
14931 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
14932 fs->super->s_blocks_count);
14933 next_check = 100000;
14934 if (fs->super->s_max_mnt_count > 0) {
14935 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014936 if (next_check <= 0)
Mike Frysinger51a43b42005-09-24 07:11:16 +000014937 next_check = 1;
14938 }
14939 if (fs->super->s_checkinterval &&
14940 ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
14941 next_check = 1;
14942 if (next_check <= 5) {
14943 if (next_check == 1)
14944 fputs(_(" (check after next mount)"), stdout);
14945 else
14946 printf(_(" (check in %ld mounts)"), next_check);
14947 }
14948 fputc('\n', stdout);
14949 ext2fs_close(fs);
14950 ctx->fs = NULL;
14951 e2fsck_free_context(ctx);
14952 exit(FSCK_OK);
14953}
14954
14955/*
14956 * For completion notice
14957 */
14958struct percent_tbl {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014959 int max_pass;
14960 int table[32];
Mike Frysinger51a43b42005-09-24 07:11:16 +000014961};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014962static const struct percent_tbl e2fsck_tbl = {
Mike Frysinger51a43b42005-09-24 07:11:16 +000014963 5, { 0, 70, 90, 92, 95, 100 }
14964};
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014965
Mike Frysinger51a43b42005-09-24 07:11:16 +000014966static char bar[128], spaces[128];
14967
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000014968static float calc_percent(const struct percent_tbl *tbl, int pass, int curr,
Mike Frysinger51a43b42005-09-24 07:11:16 +000014969 int max)
14970{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014971 float percent;
14972
Mike Frysinger51a43b42005-09-24 07:11:16 +000014973 if (pass <= 0)
14974 return 0.0;
14975 if (pass > tbl->max_pass || max == 0)
14976 return 100.0;
14977 percent = ((float) curr) / ((float) max);
14978 return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
14979 + tbl->table[pass-1]);
14980}
14981
14982extern void e2fsck_clear_progbar(e2fsck_t ctx)
14983{
14984 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
14985 return;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014986
Mike Frysinger51a43b42005-09-24 07:11:16 +000014987 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
14988 ctx->stop_meta);
14989 fflush(stdout);
14990 ctx->flags &= ~E2F_FLAG_PROG_BAR;
14991}
14992
14993int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
14994 unsigned int dpynum)
14995{
14996 static const char spinner[] = "\\|/-";
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000014997 int i;
14998 unsigned int tick;
14999 struct timeval tv;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015000 int dpywidth;
15001 int fixed_percent;
15002
15003 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
15004 return 0;
15005
15006 /*
15007 * Calculate the new progress position. If the
15008 * percentage hasn't changed, then we skip out right
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015009 * away.
Mike Frysinger51a43b42005-09-24 07:11:16 +000015010 */
15011 fixed_percent = (int) ((10 * percent) + 0.5);
15012 if (ctx->progress_last_percent == fixed_percent)
15013 return 0;
15014 ctx->progress_last_percent = fixed_percent;
15015
15016 /*
15017 * If we've already updated the spinner once within
15018 * the last 1/8th of a second, no point doing it
15019 * again.
15020 */
15021 gettimeofday(&tv, NULL);
15022 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
15023 if ((tick == ctx->progress_last_time) &&
15024 (fixed_percent != 0) && (fixed_percent != 1000))
15025 return 0;
15026 ctx->progress_last_time = tick;
15027
15028 /*
15029 * Advance the spinner, and note that the progress bar
15030 * will be on the screen
15031 */
15032 ctx->progress_pos = (ctx->progress_pos+1) & 3;
15033 ctx->flags |= E2F_FLAG_PROG_BAR;
15034
15035 dpywidth = 66 - strlen(label);
15036 dpywidth = 8 * (dpywidth / 8);
15037 if (dpynum)
15038 dpywidth -= 8;
15039
15040 i = ((percent * dpywidth) + 50) / 100;
15041 printf("%s%s: |%s%s", ctx->start_meta, label,
15042 bar + (sizeof(bar) - (i+1)),
15043 spaces + (sizeof(spaces) - (dpywidth - i + 1)));
15044 if (fixed_percent == 1000)
15045 fputc('|', stdout);
15046 else
15047 fputc(spinner[ctx->progress_pos & 3], stdout);
15048 printf(" %4.1f%% ", percent);
15049 if (dpynum)
15050 printf("%u\r", dpynum);
15051 else
15052 fputs(" \r", stdout);
15053 fputs(ctx->stop_meta, stdout);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015054
Mike Frysinger51a43b42005-09-24 07:11:16 +000015055 if (fixed_percent == 1000)
15056 e2fsck_clear_progbar(ctx);
15057 fflush(stdout);
15058
15059 return 0;
15060}
15061
15062static int e2fsck_update_progress(e2fsck_t ctx, int pass,
15063 unsigned long cur, unsigned long max)
15064{
15065 char buf[80];
15066 float percent;
15067
15068 if (pass == 0)
15069 return 0;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015070
Mike Frysinger51a43b42005-09-24 07:11:16 +000015071 if (ctx->progress_fd) {
15072 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
15073 write(ctx->progress_fd, buf, strlen(buf));
15074 } else {
15075 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
15076 e2fsck_simple_progress(ctx, ctx->device_name,
15077 percent, 0);
15078 }
15079 return 0;
15080}
15081
15082#define PATH_SET "PATH=/sbin"
15083
15084static void reserve_stdio_fds(void)
15085{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015086 int fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015087
15088 while (1) {
15089 fd = open("/dev/null", O_RDWR);
15090 if (fd > 2)
15091 break;
15092 if (fd < 0) {
15093 fprintf(stderr, _("ERROR: Couldn't open "
15094 "/dev/null (%s)\n"),
15095 strerror(errno));
15096 break;
15097 }
15098 }
15099 close(fd);
15100}
15101
Mike Frysinger51a43b42005-09-24 07:11:16 +000015102static void signal_progress_on(int sig EXT2FS_ATTR((unused)))
15103{
15104 e2fsck_t ctx = e2fsck_global_ctx;
15105
15106 if (!ctx)
15107 return;
15108
15109 ctx->progress = e2fsck_update_progress;
15110 ctx->progress_fd = 0;
15111}
15112
15113static void signal_progress_off(int sig EXT2FS_ATTR((unused)))
15114{
15115 e2fsck_t ctx = e2fsck_global_ctx;
15116
15117 if (!ctx)
15118 return;
15119
15120 e2fsck_clear_progbar(ctx);
15121 ctx->progress = 0;
15122}
15123
15124static void signal_cancel(int sig EXT2FS_ATTR((unused)))
15125{
15126 e2fsck_t ctx = e2fsck_global_ctx;
15127
15128 if (!ctx)
15129 exit(FSCK_CANCELED);
15130
15131 ctx->flags |= E2F_FLAG_CANCEL;
15132}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015133
15134static void parse_extended_opts(e2fsck_t ctx, const char *opts)
15135{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015136 char *buf, *token, *next, *p, *arg;
15137 int ea_ver;
15138 int extended_usage = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015139
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015140 buf = string_copy(opts, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015141 for (token = buf; token && *token; token = next) {
15142 p = strchr(token, ',');
15143 next = 0;
15144 if (p) {
15145 *p = 0;
15146 next = p+1;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015147 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015148 arg = strchr(token, '=');
15149 if (arg) {
15150 *arg = 0;
15151 arg++;
15152 }
15153 if (strcmp(token, "ea_ver") == 0) {
15154 if (!arg) {
15155 extended_usage++;
15156 continue;
15157 }
15158 ea_ver = strtoul(arg, &p, 0);
15159 if (*p ||
15160 ((ea_ver != 1) && (ea_ver != 2))) {
15161 fprintf(stderr,
15162 _("Invalid EA version.\n"));
15163 extended_usage++;
15164 continue;
15165 }
15166 ctx->ext_attr_ver = ea_ver;
15167 } else
15168 extended_usage++;
15169 }
15170 if (extended_usage) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015171 bb_error_msg_and_die(
15172 "Extended options are separated by commas, "
Mike Frysinger51a43b42005-09-24 07:11:16 +000015173 "and may take an argument which\n"
15174 "is set off by an equals ('=') sign. "
15175 "Valid raid options are:\n"
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015176 "\tea_ver=<ea_version (1 or 2)\n\n");
Mike Frysinger51a43b42005-09-24 07:11:16 +000015177 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015178}
Mike Frysinger51a43b42005-09-24 07:11:16 +000015179
15180
15181static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
15182{
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015183 int flush = 0;
15184 int c, fd;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015185#ifdef MTRACE
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015186 extern void *mallwatch;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015187#endif
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015188 e2fsck_t ctx;
15189 errcode_t retval;
15190 struct sigaction sa;
15191 char *extended_opts = 0;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015192
15193 retval = e2fsck_allocate_context(&ctx);
15194 if (retval)
15195 return retval;
15196
15197 *ret_ctx = ctx;
15198
15199 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
15200 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
15201 if (isatty(0) && isatty(1)) {
15202 ctx->interactive = 1;
15203 } else {
15204 ctx->start_meta[0] = '\001';
15205 ctx->stop_meta[0] = '\002';
15206 }
15207 memset(bar, '=', sizeof(bar)-1);
15208 memset(spaces, ' ', sizeof(spaces)-1);
15209 blkid_get_cache(&ctx->blkid, NULL);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015210
Mike Frysinger51a43b42005-09-24 07:11:16 +000015211 if (argc && *argv)
15212 ctx->program_name = *argv;
15213 else
15214 ctx->program_name = "e2fsck";
15215 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
15216 switch (c) {
15217 case 'C':
15218 ctx->progress = e2fsck_update_progress;
15219 ctx->progress_fd = atoi(optarg);
15220 if (!ctx->progress_fd)
15221 break;
15222 /* Validate the file descriptor to avoid disasters */
15223 fd = dup(ctx->progress_fd);
15224 if (fd < 0) {
15225 fprintf(stderr,
15226 _("Error validating file descriptor %d: %s\n"),
15227 ctx->progress_fd,
15228 error_message(errno));
15229 fatal_error(ctx,
15230 _("Invalid completion information file descriptor"));
15231 } else
15232 close(fd);
15233 break;
15234 case 'D':
15235 ctx->options |= E2F_OPT_COMPRESS_DIRS;
15236 break;
15237 case 'E':
15238 extended_opts = optarg;
15239 break;
15240 case 'p':
15241 case 'a':
15242 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
15243 conflict_opt:
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015244 fatal_error(ctx,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015245 _("Only one the options -p/-a, -n or -y may be specified."));
15246 }
15247 ctx->options |= E2F_OPT_PREEN;
15248 break;
15249 case 'n':
15250 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
15251 goto conflict_opt;
15252 ctx->options |= E2F_OPT_NO;
15253 break;
15254 case 'y':
15255 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO))
15256 goto conflict_opt;
15257 ctx->options |= E2F_OPT_YES;
15258 break;
15259 case 't':
15260#ifdef RESOURCE_TRACK
15261 if (ctx->options & E2F_OPT_TIME)
15262 ctx->options |= E2F_OPT_TIME2;
15263 else
15264 ctx->options |= E2F_OPT_TIME;
15265#else
15266 fprintf(stderr, _("The -t option is not "
15267 "supported on this version of e2fsck.\n"));
15268#endif
15269 break;
15270 case 'c':
15271 if (cflag++)
15272 ctx->options |= E2F_OPT_WRITECHECK;
15273 ctx->options |= E2F_OPT_CHECKBLOCKS;
15274 break;
15275 case 'r':
15276 /* What we do by default, anyway! */
15277 break;
15278 case 'b':
15279 ctx->use_superblock = atoi(optarg);
15280 ctx->flags |= E2F_FLAG_SB_SPECIFIED;
15281 break;
15282 case 'B':
15283 ctx->blocksize = atoi(optarg);
15284 break;
15285 case 'I':
15286 ctx->inode_buffer_blocks = atoi(optarg);
15287 break;
15288 case 'j':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015289 ctx->journal_name = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015290 break;
15291 case 'P':
15292 ctx->process_inode_size = atoi(optarg);
15293 break;
15294 case 'L':
15295 replace_bad_blocks++;
15296 case 'l':
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015297 bad_blocks_file = string_copy(optarg, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015298 break;
15299 case 'd':
15300 ctx->options |= E2F_OPT_DEBUG;
15301 break;
15302 case 'f':
15303 ctx->options |= E2F_OPT_FORCE;
15304 break;
15305 case 'F':
15306 flush = 1;
15307 break;
15308 case 'v':
15309 verbose = 1;
15310 break;
15311 case 'V':
15312 show_version_only = 1;
15313 break;
15314#ifdef MTRACE
15315 case 'M':
15316 mallwatch = (void *) strtol(optarg, NULL, 0);
15317 break;
15318#endif
15319 case 'N':
15320 ctx->device_name = optarg;
15321 break;
15322#ifdef ENABLE_SWAPFS
15323 case 's':
15324 normalize_swapfs = 1;
15325 case 'S':
15326 swapfs = 1;
15327 break;
15328#else
15329 case 's':
15330 case 'S':
15331 fprintf(stderr, _("Byte-swapping filesystems "
15332 "not compiled in this version "
15333 "of e2fsck\n"));
15334 exit(1);
15335#endif
15336 case 'k':
15337 keep_bad_blocks++;
15338 break;
15339 default:
15340 usage();
15341 }
15342 if (show_version_only)
15343 return 0;
15344 if (optind != argc - 1)
15345 usage();
15346 if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
15347 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
15348 ctx->options |= E2F_OPT_READONLY;
15349 ctx->io_options = strchr(argv[optind], '?');
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015350 if (ctx->io_options)
Mike Frysinger51a43b42005-09-24 07:11:16 +000015351 *ctx->io_options++ = 0;
15352 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
15353 if (!ctx->filesystem_name) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015354 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
Mike Frysinger51a43b42005-09-24 07:11:16 +000015355 argv[optind]);
15356 fatal_error(ctx, 0);
15357 }
15358 if (extended_opts)
15359 parse_extended_opts(ctx, extended_opts);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015360
Mike Frysinger51a43b42005-09-24 07:11:16 +000015361 if (flush) {
15362 fd = open(ctx->filesystem_name, O_RDONLY, 0);
15363 if (fd < 0) {
15364 com_err("open", errno,
15365 _("while opening %s for flushing"),
15366 ctx->filesystem_name);
15367 fatal_error(ctx, 0);
15368 }
15369 if ((retval = ext2fs_sync_device(fd, 1))) {
15370 com_err("ext2fs_sync_device", retval,
15371 _("while trying to flush %s"),
15372 ctx->filesystem_name);
15373 fatal_error(ctx, 0);
15374 }
15375 close(fd);
15376 }
15377#ifdef ENABLE_SWAPFS
15378 if (swapfs) {
15379 if (cflag || bad_blocks_file) {
15380 fprintf(stderr, _("Incompatible options not "
15381 "allowed when byte-swapping.\n"));
15382 exit(FSCK_USAGE);
15383 }
15384 }
15385#endif
15386 if (cflag && bad_blocks_file) {
15387 fprintf(stderr, _("The -c and the -l/-L options may "
15388 "not be both used at the same time.\n"));
15389 exit(FSCK_USAGE);
15390 }
Mike Frysinger51a43b42005-09-24 07:11:16 +000015391 /*
15392 * Set up signal action
15393 */
15394 memset(&sa, 0, sizeof(struct sigaction));
15395 sa.sa_handler = signal_cancel;
15396 sigaction(SIGINT, &sa, 0);
15397 sigaction(SIGTERM, &sa, 0);
15398#ifdef SA_RESTART
15399 sa.sa_flags = SA_RESTART;
15400#endif
15401 e2fsck_global_ctx = ctx;
15402 sa.sa_handler = signal_progress_on;
15403 sigaction(SIGUSR1, &sa, 0);
15404 sa.sa_handler = signal_progress_off;
15405 sigaction(SIGUSR2, &sa, 0);
Mike Frysinger51a43b42005-09-24 07:11:16 +000015406
15407 /* Update our PATH to include /sbin if we need to run badblocks */
15408 if (cflag) {
15409 char *oldpath = getenv("PATH");
15410 if (oldpath) {
15411 char *newpath;
15412
15413 newpath = (char *) malloc(sizeof (PATH_SET) + 1 +
15414 strlen (oldpath));
15415 if (!newpath)
15416 fatal_error(ctx, "Couldn't malloc() newpath");
15417 strcpy (newpath, PATH_SET);
15418 strcat (newpath, ":");
15419 strcat (newpath, oldpath);
15420 putenv (newpath);
15421 } else
15422 putenv (PATH_SET);
15423 }
15424#ifdef __CONFIG_JBD_DEBUG__E2FS
15425 if (getenv("E2FSCK_JBD_DEBUG"))
15426 journal_enable_debug = atoi(getenv("E2FSCK_JBD_DEBUG"));
15427#endif
15428 return 0;
15429}
15430
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015431static const char my_ver_string[] = E2FSPROGS_VERSION;
15432static const char my_ver_date[] = E2FSPROGS_DATE;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015433
Mike Frysinger51a43b42005-09-24 07:11:16 +000015434int e2fsck_main (int argc, char *argv[])
15435{
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015436 errcode_t retval;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015437 int exit_value = FSCK_OK;
15438 ext2_filsys fs = 0;
15439 io_manager io_ptr;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015440 struct ext2_super_block *sb;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015441 const char *lib_ver_date;
15442 int my_ver, lib_ver;
15443 e2fsck_t ctx;
Mike Frysinger51a43b42005-09-24 07:11:16 +000015444 struct problem_context pctx;
15445 int flags, run_result;
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015446
Mike Frysinger51a43b42005-09-24 07:11:16 +000015447 clear_problem_context(&pctx);
15448#ifdef MTRACE
15449 mtrace();
15450#endif
15451#ifdef MCHECK
15452 mcheck(0);
15453#endif
15454#ifdef ENABLE_NLS
15455 setlocale(LC_MESSAGES, "");
15456 setlocale(LC_CTYPE, "");
15457 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
15458 textdomain(NLS_CAT_NAME);
15459#endif
15460 my_ver = ext2fs_parse_version_string(my_ver_string);
15461 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
15462 if (my_ver > lib_ver) {
15463 fprintf( stderr, _("Error: ext2fs library version "
15464 "out of date!\n"));
15465 show_version_only++;
15466 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015467
Mike Frysinger51a43b42005-09-24 07:11:16 +000015468 retval = PRS(argc, argv, &ctx);
15469 if (retval) {
15470 com_err("e2fsck", retval,
15471 _("while trying to initialize program"));
15472 exit(FSCK_ERROR);
15473 }
15474 reserve_stdio_fds();
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015475
Mike Frysinger51a43b42005-09-24 07:11:16 +000015476#ifdef RESOURCE_TRACK
15477 init_resource_track(&ctx->global_rtrack);
15478#endif
15479
15480 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
15481 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
15482 my_ver_date);
15483
15484 if (show_version_only) {
15485 fprintf(stderr, _("\tUsing %s, %s\n"),
15486 error_message(EXT2_ET_BASE), lib_ver_date);
15487 exit(FSCK_OK);
15488 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015489
Mike Frysinger51a43b42005-09-24 07:11:16 +000015490 check_mount(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015491
Mike Frysinger51a43b42005-09-24 07:11:16 +000015492 if (!(ctx->options & E2F_OPT_PREEN) &&
15493 !(ctx->options & E2F_OPT_NO) &&
15494 !(ctx->options & E2F_OPT_YES)) {
15495 if (!ctx->interactive)
15496 fatal_error(ctx,
15497 _("need terminal for interactive repairs"));
15498 }
15499 ctx->superblock = ctx->use_superblock;
15500restart:
15501#ifdef CONFIG_TESTIO_DEBUG
15502 io_ptr = test_io_manager;
15503 test_io_backing_manager = unix_io_manager;
15504#else
15505 io_ptr = unix_io_manager;
15506#endif
15507 flags = 0;
15508 if ((ctx->options & E2F_OPT_READONLY) == 0)
15509 flags |= EXT2_FLAG_RW;
15510
15511 if (ctx->superblock && ctx->blocksize) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015512 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015513 flags, ctx->superblock, ctx->blocksize,
15514 io_ptr, &fs);
15515 } else if (ctx->superblock) {
15516 int blocksize;
15517 for (blocksize = EXT2_MIN_BLOCK_SIZE;
15518 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015519 retval = ext2fs_open2(ctx->filesystem_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015520 ctx->io_options, flags,
15521 ctx->superblock, blocksize,
15522 io_ptr, &fs);
15523 if (!retval)
15524 break;
15525 }
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015526 } else
15527 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015528 flags, 0, 0, io_ptr, &fs);
15529 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
15530 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
15531 ((retval == EXT2_ET_BAD_MAGIC) ||
15532 ((retval == 0) && ext2fs_check_desc(fs)))) {
15533 if (!fs || (fs->group_desc_count > 1)) {
15534 printf(_("%s trying backup blocks...\n"),
15535 retval ? _("Couldn't find ext2 superblock,") :
15536 _("Group descriptors look bad..."));
15537 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
15538 if (fs)
15539 ext2fs_close(fs);
15540 goto restart;
15541 }
15542 }
15543 if (retval) {
15544 com_err(ctx->program_name, retval, _("while trying to open %s"),
15545 ctx->filesystem_name);
15546 if (retval == EXT2_ET_REV_TOO_HIGH) {
15547 printf(_("The filesystem revision is apparently "
15548 "too high for this version of e2fsck.\n"
15549 "(Or the filesystem superblock "
15550 "is corrupt)\n\n"));
15551 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15552 } else if (retval == EXT2_ET_SHORT_READ)
15553 printf(_("Could this be a zero-length partition?\n"));
15554 else if ((retval == EPERM) || (retval == EACCES))
15555 printf(_("You must have %s access to the "
15556 "filesystem or be root\n"),
15557 (ctx->options & E2F_OPT_READONLY) ?
15558 "r/o" : "r/w");
15559 else if (retval == ENXIO)
15560 printf(_("Possibly non-existent or swap device?\n"));
15561#ifdef EROFS
15562 else if (retval == EROFS)
15563 printf(_("Disk write-protected; use the -n option "
15564 "to do a read-only\n"
15565 "check of the device.\n"));
15566#endif
15567 else
15568 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
15569 fatal_error(ctx, 0);
15570 }
15571 ctx->fs = fs;
15572 fs->priv_data = ctx;
15573 sb = fs->super;
15574 if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
15575 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
15576 _("while trying to open %s"),
15577 ctx->filesystem_name);
15578 get_newer:
15579 fatal_error(ctx, _("Get a newer version of e2fsck!"));
15580 }
15581
15582 /*
15583 * Set the device name, which is used whenever we print error
15584 * or informational messages to the user.
15585 */
15586 if (ctx->device_name == 0 &&
15587 (sb->s_volume_name[0] != 0)) {
"Vladimir N. Oleynik"69d728b2005-09-28 15:16:22 +000015588 ctx->device_name = string_copy(sb->s_volume_name,
Mike Frysinger51a43b42005-09-24 07:11:16 +000015589 sizeof(sb->s_volume_name));
15590 }
15591 if (ctx->device_name == 0)
15592 ctx->device_name = ctx->filesystem_name;
15593
15594 /*
15595 * Make sure the ext3 superblock fields are consistent.
15596 */
15597 retval = e2fsck_check_ext3_journal(ctx);
15598 if (retval) {
15599 com_err(ctx->program_name, retval,
15600 _("while checking ext3 journal for %s"),
15601 ctx->device_name);
15602 fatal_error(ctx, 0);
15603 }
15604
15605 /*
15606 * Check to see if we need to do ext3-style recovery. If so,
15607 * do it, and then restart the fsck.
15608 */
15609 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
15610 if (ctx->options & E2F_OPT_READONLY) {
15611 printf(_("Warning: skipping journal recovery "
15612 "because doing a read-only filesystem "
15613 "check.\n"));
15614 io_channel_flush(ctx->fs->io);
15615 } else {
15616 if (ctx->flags & E2F_FLAG_RESTARTED) {
15617 /*
15618 * Whoops, we attempted to run the
15619 * journal twice. This should never
15620 * happen, unless the hardware or
15621 * device driver is being bogus.
15622 */
15623 com_err(ctx->program_name, 0,
15624 _("unable to set superblock flags on %s\n"), ctx->device_name);
15625 fatal_error(ctx, 0);
15626 }
15627 retval = e2fsck_run_ext3_journal(ctx);
15628 if (retval) {
15629 com_err(ctx->program_name, retval,
15630 _("while recovering ext3 journal of %s"),
15631 ctx->device_name);
15632 fatal_error(ctx, 0);
15633 }
15634 ext2fs_close(ctx->fs);
15635 ctx->fs = 0;
15636 ctx->flags |= E2F_FLAG_RESTARTED;
15637 goto restart;
15638 }
15639 }
15640
15641 /*
15642 * Check for compatibility with the feature sets. We need to
15643 * be more stringent than ext2fs_open().
15644 */
15645 if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
15646 (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
15647 com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
15648 "(%s)", ctx->device_name);
15649 goto get_newer;
15650 }
15651 if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
15652 com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
15653 "(%s)", ctx->device_name);
15654 goto get_newer;
15655 }
15656#ifdef ENABLE_COMPRESSION
15657 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
15658 com_err(ctx->program_name, 0,
15659 _("Warning: compression support is experimental.\n"));
15660#endif
15661#ifndef ENABLE_HTREE
15662 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
15663 com_err(ctx->program_name, 0,
15664 _("E2fsck not compiled with HTREE support,\n\t"
15665 "but filesystem %s has HTREE directories.\n"),
15666 ctx->device_name);
15667 goto get_newer;
15668 }
15669#endif
15670
15671 /*
15672 * If the user specified a specific superblock, presumably the
15673 * master superblock has been trashed. So we mark the
15674 * superblock as dirty, so it can be written out.
15675 */
15676 if (ctx->superblock &&
15677 !(ctx->options & E2F_OPT_READONLY))
15678 ext2fs_mark_super_dirty(fs);
15679
15680 /*
15681 * We only update the master superblock because (a) paranoia;
15682 * we don't want to corrupt the backup superblocks, and (b) we
15683 * don't need to update the mount count and last checked
15684 * fields in the backup superblock (the kernel doesn't
15685 * update the backup superblocks anyway).
15686 */
15687 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
15688
15689 ehandler_init(fs->io);
15690
15691 if (ctx->superblock)
15692 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
15693 ext2fs_mark_valid(fs);
15694 check_super_block(ctx);
15695 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15696 fatal_error(ctx, 0);
15697 check_if_skip(ctx);
15698 if (bad_blocks_file)
15699 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
15700 else if (cflag)
15701 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */
15702 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15703 fatal_error(ctx, 0);
15704#ifdef ENABLE_SWAPFS
15705 if (normalize_swapfs) {
15706 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
15707 ext2fs_native_flag()) {
15708 fprintf(stderr, _("%s: Filesystem byte order "
15709 "already normalized.\n"), ctx->device_name);
15710 fatal_error(ctx, 0);
15711 }
15712 }
15713 if (swapfs) {
15714 swap_filesys(ctx);
15715 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
15716 fatal_error(ctx, 0);
15717 }
15718#endif
15719
15720 /*
15721 * Mark the system as valid, 'til proven otherwise
15722 */
15723 ext2fs_mark_valid(fs);
15724
15725 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
15726 if (retval) {
15727 com_err(ctx->program_name, retval,
15728 _("while reading bad blocks inode"));
15729 preenhalt(ctx);
15730 printf(_("This doesn't bode well,"
15731 " but we'll try to go on...\n"));
15732 }
15733
15734 run_result = e2fsck_run(ctx);
15735 e2fsck_clear_progbar(ctx);
15736 if (run_result == E2F_FLAG_RESTART) {
15737 printf(_("Restarting e2fsck from the beginning...\n"));
15738 retval = e2fsck_reset_context(ctx);
15739 if (retval) {
15740 com_err(ctx->program_name, retval,
15741 _("while resetting context"));
15742 fatal_error(ctx, 0);
15743 }
15744 ext2fs_close(fs);
15745 goto restart;
15746 }
15747 if (run_result & E2F_FLAG_CANCEL) {
15748 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
15749 ctx->device_name : ctx->filesystem_name);
15750 exit_value |= FSCK_CANCELED;
15751 }
15752 if (run_result & E2F_FLAG_ABORT)
15753 fatal_error(ctx, _("aborted"));
15754
15755#ifdef MTRACE
15756 mtrace_print("Cleanup");
15757#endif
15758 if (ext2fs_test_changed(fs)) {
15759 exit_value |= FSCK_NONDESTRUCT;
15760 if (!(ctx->options & E2F_OPT_PREEN))
15761 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
15762 ctx->device_name);
15763 if (ctx->mount_flags & EXT2_MF_ISROOT) {
15764 printf(_("%s: ***** REBOOT LINUX *****\n"),
15765 ctx->device_name);
15766 exit_value |= FSCK_REBOOT;
15767 }
15768 }
15769 if (!ext2fs_test_valid(fs)) {
15770 printf(_("\n%s: ********** WARNING: Filesystem still has "
15771 "errors **********\n\n"), ctx->device_name);
15772 exit_value |= FSCK_UNCORRECTED;
15773 exit_value &= ~FSCK_NONDESTRUCT;
15774 }
15775 if (exit_value & FSCK_CANCELED)
15776 exit_value &= ~FSCK_NONDESTRUCT;
15777 else {
15778 show_stats(ctx);
15779 if (!(ctx->options & E2F_OPT_READONLY)) {
15780 if (ext2fs_test_valid(fs)) {
15781 if (!(sb->s_state & EXT2_VALID_FS))
15782 exit_value |= FSCK_NONDESTRUCT;
15783 sb->s_state = EXT2_VALID_FS;
15784 } else
15785 sb->s_state &= ~EXT2_VALID_FS;
15786 sb->s_mnt_count = 0;
15787 sb->s_lastcheck = time(NULL);
15788 ext2fs_mark_super_dirty(fs);
15789 }
15790 }
15791
15792 e2fsck_write_bitmaps(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015793
Mike Frysinger51a43b42005-09-24 07:11:16 +000015794 ext2fs_close(fs);
15795 ctx->fs = NULL;
15796 free(ctx->filesystem_name);
15797 free(ctx->journal_name);
15798 e2fsck_free_context(ctx);
"Vladimir N. Oleynik"3978e552005-09-27 11:43:29 +000015799
Mike Frysinger51a43b42005-09-24 07:11:16 +000015800#ifdef RESOURCE_TRACK
15801 if (ctx->options & E2F_OPT_TIME)
15802 print_resource_track(NULL, &ctx->global_rtrack);
15803#endif
15804
15805 return exit_value;
15806}