aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author"Vladimir N. Oleynik" <dzo@simtreas.ru>2005-09-27 11:43:29 +0000
committer"Vladimir N. Oleynik" <dzo@simtreas.ru>2005-09-27 11:43:29 +0000
commit3978e5576e1675c2fac631fcba07a976405b5e4b (patch)
treea7020db24bbcaebdce5a3a325967e21feacf7a89
parent16ce8aa4123388c4a6237301e656c8f4e24a7e52 (diff)
downloadbusybox-w32-3978e5576e1675c2fac631fcba07a976405b5e4b.tar.gz
busybox-w32-3978e5576e1675c2fac631fcba07a976405b5e4b.tar.bz2
busybox-w32-3978e5576e1675c2fac631fcba07a976405b5e4b.zip
move e2fsck/* to e2fsck.c, one e2fsck_main and jornal exported, small automatic size reduction
-rw-r--r--e2fsprogs/Makefile.in30
-rw-r--r--e2fsprogs/e2fsck.c15558
-rw-r--r--e2fsprogs/e2fsck/badblocks.c135
-rw-r--r--e2fsprogs/e2fsck/dict.c1529
-rw-r--r--e2fsprogs/e2fsck/dict.h144
-rw-r--r--e2fsprogs/e2fsck/dirinfo.c137
-rw-r--r--e2fsprogs/e2fsck/dx_dirinfo.c150
-rw-r--r--e2fsprogs/e2fsck/e2fsck.c202
-rw-r--r--e2fsprogs/e2fsck/e2fsck.h446
-rw-r--r--e2fsprogs/e2fsck/ea_refcount.c479
-rw-r--r--e2fsprogs/e2fsck/ehandler.c124
-rw-r--r--e2fsprogs/e2fsck/jfs_user.h120
-rw-r--r--e2fsprogs/e2fsck/journal.c960
-rw-r--r--e2fsprogs/e2fsck/message.c466
-rw-r--r--e2fsprogs/e2fsck/pass1.c2122
-rw-r--r--e2fsprogs/e2fsck/pass1b.c805
-rw-r--r--e2fsprogs/e2fsck/pass2.c1414
-rw-r--r--e2fsprogs/e2fsck/pass3.c804
-rw-r--r--e2fsprogs/e2fsck/pass4.c178
-rw-r--r--e2fsprogs/e2fsck/pass5.c547
-rw-r--r--e2fsprogs/e2fsck/problem.c1655
-rw-r--r--e2fsprogs/e2fsck/problem.h897
-rw-r--r--e2fsprogs/e2fsck/problemP.h42
-rw-r--r--e2fsprogs/e2fsck/recovery.c586
-rw-r--r--e2fsprogs/e2fsck/region.c204
-rw-r--r--e2fsprogs/e2fsck/rehash.c840
-rw-r--r--e2fsprogs/e2fsck/revoke.c640
-rw-r--r--e2fsprogs/e2fsck/super.c713
-rw-r--r--e2fsprogs/e2fsck/swapfs.c268
-rw-r--r--e2fsprogs/e2fsck/util.c503
30 files changed, 15465 insertions, 17233 deletions
diff --git a/e2fsprogs/Makefile.in b/e2fsprogs/Makefile.in
index e1459e05f..f7dbba30f 100644
--- a/e2fsprogs/Makefile.in
+++ b/e2fsprogs/Makefile.in
@@ -11,37 +11,33 @@ E2FSPROGS_DIR:=$(top_builddir)/e2fsprogs
11E2FSPROGS_CFLAGS := -I$(E2FSPROGS_DIR) -include $(E2FSPROGS_DIR)/e2fsbb.h 11E2FSPROGS_CFLAGS := -I$(E2FSPROGS_DIR) -include $(E2FSPROGS_DIR)/e2fsbb.h
12 12
13BLKID_SRC := cache.c dev.c devname.c devno.c blkid_getsize.c \ 13BLKID_SRC := cache.c dev.c devname.c devno.c blkid_getsize.c \
14 probe.c read.c resolve.c save.c tag.c resolve.c 14 probe.c read.c resolve.c save.c tag.c resolve.c
15BLKID_SRCS := $(patsubst %,blkid/%, $(BLKID_SRC)) 15BLKID_SRCS := $(patsubst %,blkid/%, $(BLKID_SRC))
16BLKID_OBJS := $(patsubst %.c,%.o, $(BLKID_SRCS)) 16BLKID_OBJS := $(patsubst %.c,%.o, $(BLKID_SRCS))
17 17
18E2FSCK_SRC := badblocks.c dict.c dirinfo.c dx_dirinfo.c e2fsck.c \ 18E2FSCK_SRCS := e2fsck.c
19 ea_refcount.c ehandler.c journal.c message.c pass1.c pass1b.c \
20 pass2.c pass3.c pass4.c pass5.c problem.c recovery.c region.c \
21 rehash.c revoke.c super.c swapfs.c util.c
22E2FSCK_SRCS := $(patsubst %,e2fsck/%, $(E2FSCK_SRC))
23E2FSCK_OBJS := $(patsubst %.c,%.o, $(E2FSCK_SRCS)) 19E2FSCK_OBJS := $(patsubst %.c,%.o, $(E2FSCK_SRCS))
24 20
25E2P_SRC := fgetsetflags.c fgetsetversion.c pf.c iod.c mntopts.c \ 21E2P_SRC := fgetsetflags.c fgetsetversion.c pf.c iod.c mntopts.c \
26 feature.c ls.c uuid.c pe.c ostype.c ps.c hashstr.c \ 22 feature.c ls.c uuid.c pe.c ostype.c ps.c hashstr.c \
27 parse_num.c 23 parse_num.c
28E2P_SRCS := $(patsubst %,e2p/%, $(E2P_SRC)) 24E2P_SRCS := $(patsubst %,e2p/%, $(E2P_SRC))
29E2P_OBJS := $(patsubst %.c,%.o, $(E2P_SRCS)) 25E2P_OBJS := $(patsubst %.c,%.o, $(E2P_SRCS))
30 26
31EXT2FS_SRC := gen_bitmap.c bitops.c ismounted.c mkjournal.c unix_io.c \ 27EXT2FS_SRC := gen_bitmap.c bitops.c ismounted.c mkjournal.c unix_io.c \
32 rw_bitmaps.c initialize.c bitmaps.c block.c \ 28 rw_bitmaps.c initialize.c bitmaps.c block.c \
33 ind_block.c inode.c freefs.c alloc_stats.c closefs.c \ 29 ind_block.c inode.c freefs.c alloc_stats.c closefs.c \
34 openfs.c io_manager.c finddev.c read_bb.c alloc.c badblocks.c \ 30 openfs.c io_manager.c finddev.c read_bb.c alloc.c badblocks.c \
35 getsize.c getsectsize.c alloc_tables.c read_bb_file.c mkdir.c \ 31 getsize.c getsectsize.c alloc_tables.c read_bb_file.c mkdir.c \
36 bb_inode.c newdir.c alloc_sb.c lookup.c dirblock.c expanddir.c \ 32 bb_inode.c newdir.c alloc_sb.c lookup.c dirblock.c expanddir.c \
37 dir_iterate.c link.c res_gdt.c icount.c get_pathname.c dblist.c \ 33 dir_iterate.c link.c res_gdt.c icount.c get_pathname.c dblist.c \
38 dirhash.c version.c flushb.c unlink.c check_desc.c valid_blk.c \ 34 dirhash.c version.c flushb.c unlink.c check_desc.c valid_blk.c \
39 ext_attr.c bmap.c dblist_dir.c ext2fs_inline.c 35 ext_attr.c bmap.c dblist_dir.c ext2fs_inline.c
40EXT2FS_SRCS := $(patsubst %,ext2fs/%, $(EXT2FS_SRC)) 36EXT2FS_SRCS := $(patsubst %,ext2fs/%, $(EXT2FS_SRC))
41EXT2FS_OBJS := $(patsubst %.c,%.o, $(EXT2FS_SRCS)) 37EXT2FS_OBJS := $(patsubst %.c,%.o, $(EXT2FS_SRCS))
42 38
43UUID_SRC := compare.c gen_uuid.c pack.c parse.c unpack.c unparse.c \ 39UUID_SRC := compare.c gen_uuid.c pack.c parse.c unpack.c unparse.c \
44 uuid_time.c 40 uuid_time.c
45UUID_SRCS := $(patsubst %,uuid/%, $(UUID_SRC)) 41UUID_SRCS := $(patsubst %,uuid/%, $(UUID_SRC))
46UUID_OBJS := $(patsubst %.c,%.o, $(UUID_SRCS)) 42UUID_OBJS := $(patsubst %.c,%.o, $(UUID_SRCS))
47 43
diff --git a/e2fsprogs/e2fsck.c b/e2fsprogs/e2fsck.c
index db93ea0ce..74bc9f7b8 100644
--- a/e2fsprogs/e2fsck.c
+++ b/e2fsprogs/e2fsck.c
@@ -1,59 +1,15413 @@
1/* 1/*
2 * unix.c - The unix-specific code for e2fsck 2 * e2fsck
3 * 3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. 4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
5 * 6 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */ 7 */
11 8
9#ifndef _GNU_SOURCE
10#define _GNU_SOURCE 1 /* get strnlen() */
11#endif
12#include <sys/types.h>
13#include <inttypes.h>
12#include <stdio.h> 14#include <stdio.h>
13#include <stdlib.h>
14#include <string.h> 15#include <string.h>
16#include <unistd.h>
17#include <stdlib.h>
18#include <time.h>
15#include <fcntl.h> 19#include <fcntl.h>
16#include <ctype.h> 20#include <ctype.h>
17#include <time.h> 21#include <setjmp.h>
18#ifdef HAVE_SIGNAL_H 22#include <errno.h>
23#include <getopt.h>
24#include <limits.h>
25#include <stddef.h>
26#include <assert.h>
19#include <signal.h> 27#include <signal.h>
28#include <sys/time.h>
29#include <sys/stat.h>
30#include <sys/resource.h>
31#include <sys/param.h>
32#include <sys/mount.h>
33#include <sys/ioctl.h>
34#include <malloc.h>
35#include <termios.h>
36#include <mntent.h>
37#include <dirent.h>
38
39#include "e2fsbb.h"
40
41#include "ext2fs/ext2_fs.h"
42#include "ext2fs/ext2fs.h"
43#include "blkid/blkid.h"
44#include "ext2fs/ext2_ext_attr.h"
45#include "uuid/uuid.h"
46
47#ifdef __GNUC__
48#define _INLINE_ __inline__
49#define EXT2FS_ATTR(x) __attribute__(x)
50#else
51#define _INLINE_
52#define EXT2FS_ATTR(x)
20#endif 53#endif
21#ifdef HAVE_GETOPT_H 54
22#include <getopt.h> 55/*
56 * Exit codes used by fsck-type programs
57 */
58#define FSCK_OK 0 /* No errors */
59#define FSCK_NONDESTRUCT 1 /* File system errors corrected */
60#define FSCK_REBOOT 2 /* System should be rebooted */
61#define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */
62#define FSCK_ERROR 8 /* Operational error */
63#define FSCK_USAGE 16 /* Usage or syntax error */
64#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
65#define FSCK_LIBRARY 128 /* Shared library error */
66
67/*
68 * The last ext2fs revision level that this version of e2fsck is able to
69 * support
70 */
71#define E2FSCK_CURRENT_REV 1
72
73/*
74 * The directory information structure; stores directory information
75 * collected in earlier passes, to avoid disk i/o in fetching the
76 * directory information.
77 */
78struct dir_info {
79 ext2_ino_t ino; /* Inode number */
80 ext2_ino_t dotdot; /* Parent according to '..' */
81 ext2_ino_t parent; /* Parent according to treewalk */
82};
83
84
85/*
86 * The indexed directory information structure; stores information for
87 * directories which contain a hash tree index.
88 */
89struct dx_dir_info {
90 ext2_ino_t ino; /* Inode number */
91 int numblocks; /* number of blocks */
92 int hashversion;
93 short depth; /* depth of tree */
94 struct dx_dirblock_info *dx_block; /* Array of size numblocks */
95};
96
97#define DX_DIRBLOCK_ROOT 1
98#define DX_DIRBLOCK_LEAF 2
99#define DX_DIRBLOCK_NODE 3
100#define DX_DIRBLOCK_CORRUPT 4
101#define DX_DIRBLOCK_CLEARED 8
102
103struct dx_dirblock_info {
104 int type;
105 blk_t phys;
106 int flags;
107 blk_t parent;
108 ext2_dirhash_t min_hash;
109 ext2_dirhash_t max_hash;
110 ext2_dirhash_t node_min_hash;
111 ext2_dirhash_t node_max_hash;
112};
113
114#define DX_FLAG_REFERENCED 1
115#define DX_FLAG_DUP_REF 2
116#define DX_FLAG_FIRST 4
117#define DX_FLAG_LAST 8
118
119#ifdef RESOURCE_TRACK
120/*
121 * This structure is used for keeping track of how much resources have
122 * been used for a particular pass of e2fsck.
123 */
124struct resource_track {
125 struct timeval time_start;
126 struct timeval user_start;
127 struct timeval system_start;
128 void *brk_start;
129};
130#endif
131
132/*
133 * E2fsck options
134 */
135#define E2F_OPT_READONLY 0x0001
136#define E2F_OPT_PREEN 0x0002
137#define E2F_OPT_YES 0x0004
138#define E2F_OPT_NO 0x0008
139#define E2F_OPT_TIME 0x0010
140#define E2F_OPT_TIME2 0x0020
141#define E2F_OPT_CHECKBLOCKS 0x0040
142#define E2F_OPT_DEBUG 0x0080
143#define E2F_OPT_FORCE 0x0100
144#define E2F_OPT_WRITECHECK 0x0200
145#define E2F_OPT_COMPRESS_DIRS 0x0400
146
147/*
148 * E2fsck flags
149 */
150#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
151#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
152#define E2F_FLAG_SIGNAL_MASK 0x0003
153#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
154
155#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
156
157#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
158#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */
159#define E2F_FLAG_JOURNAL_INODE 0x0080 /* Create a new ext3 journal inode */
160#define E2F_FLAG_SB_SPECIFIED 0x0100 /* The superblock was explicitly
161 * specified by the user */
162#define E2F_FLAG_RESTARTED 0x0200 /* E2fsck has been restarted */
163#define E2F_FLAG_RESIZE_INODE 0x0400 /* Request to recreate resize inode */
164
165/*
166 * Defines for indicating the e2fsck pass number
167 */
168#define E2F_PASS_1 1
169#define E2F_PASS_2 2
170#define E2F_PASS_3 3
171#define E2F_PASS_4 4
172#define E2F_PASS_5 5
173#define E2F_PASS_1B 6
174
175/*
176 * Define the extended attribute refcount structure
177 */
178typedef struct ea_refcount *ext2_refcount_t;
179
180/*
181 * This is the global e2fsck structure.
182 */
183typedef struct e2fsck_struct *e2fsck_t;
184
185struct e2fsck_struct {
186 ext2_filsys fs;
187 const char *program_name;
188 char *filesystem_name;
189 char *device_name;
190 char *io_options;
191 int flags; /* E2fsck internal flags */
192 int options;
193 blk_t use_superblock; /* sb requested by user */
194 blk_t superblock; /* sb used to open fs */
195 int blocksize; /* blocksize */
196 blk_t num_blocks; /* Total number of blocks */
197 int mount_flags;
198 blkid_cache blkid; /* blkid cache */
199
200 jmp_buf abort_loc;
201
202 unsigned long abort_code;
203
204 int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
205 unsigned long max);
206
207 ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
208 ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
209 ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
210 ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
211 ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
212 ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
213
214 ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
215 ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
216 ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
217
218 /*
219 * Inode count arrays
220 */
221 ext2_icount_t inode_count;
222 ext2_icount_t inode_link_info;
223
224 ext2_refcount_t refcount;
225 ext2_refcount_t refcount_extra;
226
227 /*
228 * Array of flags indicating whether an inode bitmap, block
229 * bitmap, or inode table is invalid
230 */
231 int *invalid_inode_bitmap_flag;
232 int *invalid_block_bitmap_flag;
233 int *invalid_inode_table_flag;
234 int invalid_bitmaps; /* There are invalid bitmaps/itable */
235
236 /*
237 * Block buffer
238 */
239 char *block_buf;
240
241 /*
242 * For pass1_check_directory and pass1_get_blocks
243 */
244 ext2_ino_t stashed_ino;
245 struct ext2_inode *stashed_inode;
246
247 /*
248 * Location of the lost and found directory
249 */
250 ext2_ino_t lost_and_found;
251 int bad_lost_and_found;
252
253 /*
254 * Directory information
255 */
256 int dir_info_count;
257 int dir_info_size;
258 struct dir_info *dir_info;
259
260 /*
261 * Indexed directory information
262 */
263 int dx_dir_info_count;
264 int dx_dir_info_size;
265 struct dx_dir_info *dx_dir_info;
266
267 /*
268 * Directories to hash
269 */
270 ext2_u32_list dirs_to_hash;
271
272 /*
273 * Tuning parameters
274 */
275 int process_inode_size;
276 int inode_buffer_blocks;
277
278 /*
279 * ext3 journal support
280 */
281 io_channel journal_io;
282 char *journal_name;
283
284#ifdef RESOURCE_TRACK
285 /*
286 * For timing purposes
287 */
288 struct resource_track global_rtrack;
289#endif
290
291 /*
292 * How we display the progress update (for unix)
293 */
294 int progress_fd;
295 int progress_pos;
296 int progress_last_percent;
297 unsigned int progress_last_time;
298 int interactive; /* Are we connected directly to a tty? */
299 char start_meta[2], stop_meta[2];
300
301 /* File counts */
302 int fs_directory_count;
303 int fs_regular_count;
304 int fs_blockdev_count;
305 int fs_chardev_count;
306 int fs_links_count;
307 int fs_symlinks_count;
308 int fs_fast_symlinks_count;
309 int fs_fifo_count;
310 int fs_total_count;
311 int fs_badblocks_count;
312 int fs_sockets_count;
313 int fs_ind_count;
314 int fs_dind_count;
315 int fs_tind_count;
316 int fs_fragmented;
317 int large_files;
318 int fs_ext_attr_inodes;
319 int fs_ext_attr_blocks;
320
321 int ext_attr_ver;
322
323 /*
324 * For the use of callers of the e2fsck functions; not used by
325 * e2fsck functions themselves.
326 */
327 void *priv_data;
328};
329
330/* Used by the region allocation code */
331typedef __u32 region_addr_t;
332typedef struct region_struct *region_t;
333
334/*
335 * Procedure declarations
336 */
337
338static void e2fsck_pass1(e2fsck_t ctx);
339static void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
340static void e2fsck_pass2(e2fsck_t ctx);
341static void e2fsck_pass3(e2fsck_t ctx);
342static void e2fsck_pass4(e2fsck_t ctx);
343static void e2fsck_pass5(e2fsck_t ctx);
344
345/* e2fsck.c */
346static errcode_t e2fsck_allocate_context(e2fsck_t *ret);
347static errcode_t e2fsck_reset_context(e2fsck_t ctx);
348static void e2fsck_free_context(e2fsck_t ctx);
349static int e2fsck_run(e2fsck_t ctx);
350
351
352/* badblock.c */
353static void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
354 int replace_bad_blocks);
355
356/* dirinfo.c */
357static void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
358static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino);
359static void e2fsck_free_dir_info(e2fsck_t ctx);
360static int e2fsck_get_num_dirinfo(e2fsck_t ctx);
361static struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control);
362
363/* dx_dirinfo.c */
364static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks);
365static struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino);
366static void e2fsck_free_dx_dir_info(e2fsck_t ctx);
367static struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control);
368
369/* ea_refcount.c */
370static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret);
371static void ea_refcount_free(ext2_refcount_t refcount);
372static errcode_t ea_refcount_increment(ext2_refcount_t refcount,
373 blk_t blk, int *ret);
374static errcode_t ea_refcount_decrement(ext2_refcount_t refcount,
375 blk_t blk, int *ret);
376static errcode_t ea_refcount_store(ext2_refcount_t refcount,
377 blk_t blk, int count);
378static void ea_refcount_intr_begin(ext2_refcount_t refcount);
379static blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret);
380
381/* ehandler.c */
382static const char *ehandler_operation(const char *op);
383static void ehandler_init(io_channel channel);
384
385/* journal.c */
386static int e2fsck_check_ext3_journal(e2fsck_t ctx);
387static int e2fsck_run_ext3_journal(e2fsck_t ctx);
388static void e2fsck_move_ext3_journal(e2fsck_t ctx);
389
390/* pass1.c */
391static void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
392static int e2fsck_pass1_check_device_inode(ext2_filsys fs,
393 struct ext2_inode *inode);
394static int e2fsck_pass1_check_symlink(ext2_filsys fs,
395 struct ext2_inode *inode, char *buf);
396
397/* pass2.c */
398static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
399 ext2_ino_t ino, char *buf);
400
401/* pass3.c */
402static int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
403static errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
404 int num, int gauranteed_size);
405static ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
406static errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
407 int adj);
408
409
410/* region.c */
411static region_t region_create(region_addr_t min, region_addr_t max);
412static void region_free(region_t region);
413static int region_allocate(region_t region, region_addr_t start, int n);
414
415/* rehash.c */
416static errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
417static void e2fsck_rehash_directories(e2fsck_t ctx);
418
419/* super.c */
420static void check_super_block(e2fsck_t ctx);
421static errcode_t e2fsck_get_device_size(e2fsck_t ctx);
422
423#ifdef ENABLE_SWAPFS
424/* swapfs.c */
425static void swap_filesys(e2fsck_t ctx);
426#endif
427
428/* util.c */
429static void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
430 const char *description);
431static int ask(e2fsck_t ctx, const char * string, int def);
432static int ask_yn(const char * string, int def);
433static void e2fsck_read_bitmaps(e2fsck_t ctx);
434static void e2fsck_write_bitmaps(e2fsck_t ctx);
435static void preenhalt(e2fsck_t ctx);
436static char *string_copy(e2fsck_t ctx, const char *str, int len);
437#ifdef RESOURCE_TRACK
438static void print_resource_track(const char *desc,
439 struct resource_track *track);
440static void init_resource_track(struct resource_track *track);
441#endif
442static void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
443 struct ext2_inode * inode, const char * proc);
444static void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
445 struct ext2_inode * inode, const char * proc);
446#ifdef MTRACE
447static void mtrace_print(char *mesg);
448#endif
449static blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
450 const char *name, io_manager manager);
451static int ext2_file_type(unsigned int mode);
452
453/* unix.c */
454static void e2fsck_clear_progbar(e2fsck_t ctx);
455static int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
456 float percent, unsigned int dpynum);
457/*
458 * problem.h --- e2fsck problem error codes
459 */
460
461typedef __u32 problem_t;
462
463struct problem_context {
464 errcode_t errcode;
465 ext2_ino_t ino, ino2, dir;
466 struct ext2_inode *inode;
467 struct ext2_dir_entry *dirent;
468 blk_t blk, blk2;
469 e2_blkcnt_t blkcount;
470 int group;
471 __u64 num;
472 const char *str;
473};
474
475/*
476 * We define a set of "latch groups"; these are problems which are
477 * handled as a set. The user answers once for a particular latch
478 * group.
479 */
480#define PR_LATCH_MASK 0x0ff0 /* Latch mask */
481#define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */
482#define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */
483#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */
484#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */
485#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */
486#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */
487#define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
488#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
489#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
490
491#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
492
493/*
494 * Latch group descriptor flags
495 */
496#define PRL_YES 0x0001 /* Answer yes */
497#define PRL_NO 0x0002 /* Answer no */
498#define PRL_LATCHED 0x0004 /* The latch group is latched */
499#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */
500
501#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */
502
503/*
504 * Pre-Pass 1 errors
505 */
506
507/* Block bitmap not in group */
508#define PR_0_BB_NOT_GROUP 0x000001
509
510/* Inode bitmap not in group */
511#define PR_0_IB_NOT_GROUP 0x000002
512
513/* Inode table not in group */
514#define PR_0_ITABLE_NOT_GROUP 0x000003
515
516/* Superblock corrupt */
517#define PR_0_SB_CORRUPT 0x000004
518
519/* Filesystem size is wrong */
520#define PR_0_FS_SIZE_WRONG 0x000005
521
522/* Fragments not supported */
523#define PR_0_NO_FRAGMENTS 0x000006
524
525/* Bad blocks_per_group */
526#define PR_0_BLOCKS_PER_GROUP 0x000007
527
528/* Bad first_data_block */
529#define PR_0_FIRST_DATA_BLOCK 0x000008
530
531/* Adding UUID to filesystem */
532#define PR_0_ADD_UUID 0x000009
533
534/* Relocate hint */
535#define PR_0_RELOCATE_HINT 0x00000A
536
537/* Miscellaneous superblock corruption */
538#define PR_0_MISC_CORRUPT_SUPER 0x00000B
539
540/* Error determing physical device size of filesystem */
541#define PR_0_GETSIZE_ERROR 0x00000C
542
543/* Inode count in the superblock incorrect */
544#define PR_0_INODE_COUNT_WRONG 0x00000D
545
546/* The Hurd does not support the filetype feature */
547#define PR_0_HURD_CLEAR_FILETYPE 0x00000E
548
549/* Journal inode is invalid */
550#define PR_0_JOURNAL_BAD_INODE 0x00000F
551
552/* The external journal has multiple filesystems (which we can't handle yet) */
553#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010
554
555/* Can't find external journal */
556#define PR_0_CANT_FIND_JOURNAL 0x000011
557
558/* External journal has bad superblock */
559#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012
560
561/* Superblock has a bad journal UUID */
562#define PR_0_JOURNAL_BAD_UUID 0x000013
563
564/* Journal has an unknown superblock type */
565#define PR_0_JOURNAL_UNSUPP_SUPER 0x000014
566
567/* Journal superblock is corrupt */
568#define PR_0_JOURNAL_BAD_SUPER 0x000015
569
570/* Journal superblock is corrupt */
571#define PR_0_JOURNAL_HAS_JOURNAL 0x000016
572
573/* Superblock has recovery flag set but no journal */
574#define PR_0_JOURNAL_RECOVER_SET 0x000017
575
576/* Journal has data, but recovery flag is clear */
577#define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018
578
579/* Ask if we should clear the journal */
580#define PR_0_JOURNAL_RESET_JOURNAL 0x000019
581
582/* Filesystem revision is 0, but feature flags are set */
583#define PR_0_FS_REV_LEVEL 0x00001A
584
585/* Clearing orphan inode */
586#define PR_0_ORPHAN_CLEAR_INODE 0x000020
587
588/* Illegal block found in orphaned inode */
589#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021
590
591/* Already cleared block found in orphaned inode */
592#define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK 0x000022
593
594/* Illegal orphan inode in superblock */
595#define PR_0_ORPHAN_ILLEGAL_HEAD_INODE 0x000023
596
597/* Illegal inode in orphaned inode list */
598#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024
599
600/* Journal has unsupported read-only feature - abort */
601#define PR_0_JOURNAL_UNSUPP_ROCOMPAT 0x000025
602
603/* Journal has unsupported incompatible feature - abort */
604#define PR_0_JOURNAL_UNSUPP_INCOMPAT 0x000026
605
606/* Journal has unsupported version number */
607#define PR_0_JOURNAL_UNSUPP_VERSION 0x000027
608
609/* Moving journal to hidden file */
610#define PR_0_MOVE_JOURNAL 0x000028
611
612/* Error moving journal */
613#define PR_0_ERR_MOVE_JOURNAL 0x000029
614
615/* Clearing V2 journal superblock */
616#define PR_0_CLEAR_V2_JOURNAL 0x00002A
617
618/* Run journal anyway */
619#define PR_0_JOURNAL_RUN 0x00002B
620
621/* Run journal anyway by default */
622#define PR_0_JOURNAL_RUN_DEFAULT 0x00002C
623
624/* Backup journal inode blocks */
625#define PR_0_BACKUP_JNL 0x00002D
626
627/* Reserved blocks w/o resize_inode */
628#define PR_0_NONZERO_RESERVED_GDT_BLOCKS 0x00002E
629
630/* Resize_inode not enabled, but resize inode is non-zero */
631#define PR_0_CLEAR_RESIZE_INODE 0x00002F
632
633/* Resize inode invalid */
634#define PR_0_RESIZE_INODE_INVALID 0x000030
635
636/*
637 * Pass 1 errors
638 */
639
640/* Pass 1: Checking inodes, blocks, and sizes */
641#define PR_1_PASS_HEADER 0x010000
642
643/* Root directory is not an inode */
644#define PR_1_ROOT_NO_DIR 0x010001
645
646/* Root directory has dtime set */
647#define PR_1_ROOT_DTIME 0x010002
648
649/* Reserved inode has bad mode */
650#define PR_1_RESERVED_BAD_MODE 0x010003
651
652/* Deleted inode has zero dtime */
653#define PR_1_ZERO_DTIME 0x010004
654
655/* Inode in use, but dtime set */
656#define PR_1_SET_DTIME 0x010005
657
658/* Zero-length directory */
659#define PR_1_ZERO_LENGTH_DIR 0x010006
660
661/* Block bitmap conflicts with some other fs block */
662#define PR_1_BB_CONFLICT 0x010007
663
664/* Inode bitmap conflicts with some other fs block */
665#define PR_1_IB_CONFLICT 0x010008
666
667/* Inode table conflicts with some other fs block */
668#define PR_1_ITABLE_CONFLICT 0x010009
669
670/* Block bitmap is on a bad block */
671#define PR_1_BB_BAD_BLOCK 0x01000A
672
673/* Inode bitmap is on a bad block */
674#define PR_1_IB_BAD_BLOCK 0x01000B
675
676/* Inode has incorrect i_size */
677#define PR_1_BAD_I_SIZE 0x01000C
678
679/* Inode has incorrect i_blocks */
680#define PR_1_BAD_I_BLOCKS 0x01000D
681
682/* Illegal block number in inode */
683#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E
684
685/* Block number overlaps fs metadata */
686#define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F
687
688/* Inode has illegal blocks (latch question) */
689#define PR_1_INODE_BLOCK_LATCH 0x010010
690
691/* Too many bad blocks in inode */
692#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011
693
694/* Illegal block number in bad block inode */
695#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012
696
697/* Bad block inode has illegal blocks (latch question) */
698#define PR_1_INODE_BBLOCK_LATCH 0x010013
699
700/* Duplicate or bad blocks in use! */
701#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014
702
703/* Bad block used as bad block indirect block */
704#define PR_1_BBINODE_BAD_METABLOCK 0x010015
705
706/* Inconsistency can't be fixed prompt */
707#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016
708
709/* Bad primary block */
710#define PR_1_BAD_PRIMARY_BLOCK 0x010017
711
712/* Bad primary block prompt */
713#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018
714
715/* Bad primary superblock */
716#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x010019
717
718/* Bad primary block group descriptors */
719#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A
720
721/* Bad superblock in group */
722#define PR_1_BAD_SUPERBLOCK 0x01001B
723
724/* Bad block group descriptors in group */
725#define PR_1_BAD_GROUP_DESCRIPTORS 0x01001C
726
727/* Block claimed for no reason */
728#define PR_1_PROGERR_CLAIMED_BLOCK 0x01001D
729
730/* Error allocating blocks for relocating metadata */
731#define PR_1_RELOC_BLOCK_ALLOCATE 0x01001E
732
733/* Error allocating block buffer during relocation process */
734#define PR_1_RELOC_MEMORY_ALLOCATE 0x01001F
735
736/* Relocating metadata group information from X to Y */
737#define PR_1_RELOC_FROM_TO 0x010020
738
739/* Relocating metatdata group information to X */
740#define PR_1_RELOC_TO 0x010021
741
742/* Block read error during relocation process */
743#define PR_1_RELOC_READ_ERR 0x010022
744
745/* Block write error during relocation process */
746#define PR_1_RELOC_WRITE_ERR 0x010023
747
748/* Error allocating inode bitmap */
749#define PR_1_ALLOCATE_IBITMAP_ERROR 0x010024
750
751/* Error allocating block bitmap */
752#define PR_1_ALLOCATE_BBITMAP_ERROR 0x010025
753
754/* Error allocating icount structure */
755#define PR_1_ALLOCATE_ICOUNT 0x010026
756
757/* Error allocating dbcount */
758#define PR_1_ALLOCATE_DBCOUNT 0x010027
759
760/* Error while scanning inodes */
761#define PR_1_ISCAN_ERROR 0x010028
762
763/* Error while iterating over blocks */
764#define PR_1_BLOCK_ITERATE 0x010029
765
766/* Error while storing inode count information */
767#define PR_1_ICOUNT_STORE 0x01002A
768
769/* Error while storing directory block information */
770#define PR_1_ADD_DBLOCK 0x01002B
771
772/* Error while reading inode (for clearing) */
773#define PR_1_READ_INODE 0x01002C
774
775/* Suppress messages prompt */
776#define PR_1_SUPPRESS_MESSAGES 0x01002D
777
778/* Imagic flag set on an inode when filesystem doesn't support it */
779#define PR_1_SET_IMAGIC 0x01002F
780
781/* Immutable flag set on a device or socket inode */
782#define PR_1_SET_IMMUTABLE 0x010030
783
784/* Compression flag set on a non-compressed filesystem */
785#define PR_1_COMPR_SET 0x010031
786
787/* Non-zero size on on device, fifo or socket inode */
788#define PR_1_SET_NONZSIZE 0x010032
789
790/* Filesystem revision is 0, but feature flags are set */
791#define PR_1_FS_REV_LEVEL 0x010033
792
793/* Journal inode not in use, needs clearing */
794#define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034
795
796/* Journal inode has wrong mode */
797#define PR_1_JOURNAL_BAD_MODE 0x010035
798
799/* Inode that was part of orphan linked list */
800#define PR_1_LOW_DTIME 0x010036
801
802/* Latch question which asks how to deal with low dtime inodes */
803#define PR_1_ORPHAN_LIST_REFUGEES 0x010037
804
805/* Error allocating refcount structure */
806#define PR_1_ALLOCATE_REFCOUNT 0x010038
807
808/* Error reading Extended Attribute block */
809#define PR_1_READ_EA_BLOCK 0x010039
810
811/* Invalid Extended Attribute block */
812#define PR_1_BAD_EA_BLOCK 0x01003A
813
814/* Error reading Extended Attribute block while fixing refcount -- abort */
815#define PR_1_EXTATTR_READ_ABORT 0x01003B
816
817/* Extended attribute reference count incorrect */
818#define PR_1_EXTATTR_REFCOUNT 0x01003C
819
820/* Error writing Extended Attribute block while fixing refcount */
821#define PR_1_EXTATTR_WRITE 0x01003D
822
823/* Multiple EA blocks not supported */
824#define PR_1_EA_MULTI_BLOCK 0x01003E
825
826/* Error allocating EA region allocation structure */
827#define PR_1_EA_ALLOC_REGION 0x01003F
828
829/* Error EA allocation collision */
830#define PR_1_EA_ALLOC_COLLISION 0x010040
831
832/* Bad extended attribute name */
833#define PR_1_EA_BAD_NAME 0x010041
834
835/* Bad extended attribute value */
836#define PR_1_EA_BAD_VALUE 0x010042
837
838/* Inode too big (latch question) */
839#define PR_1_INODE_TOOBIG 0x010043
840
841/* Directory too big */
842#define PR_1_TOOBIG_DIR 0x010044
843
844/* Regular file too big */
845#define PR_1_TOOBIG_REG 0x010045
846
847/* Symlink too big */
848#define PR_1_TOOBIG_SYMLINK 0x010046
849
850/* INDEX_FL flag set on a non-HTREE filesystem */
851#define PR_1_HTREE_SET 0x010047
852
853/* INDEX_FL flag set on a non-directory */
854#define PR_1_HTREE_NODIR 0x010048
855
856/* Invalid root node in HTREE directory */
857#define PR_1_HTREE_BADROOT 0x010049
858
859/* Unsupported hash version in HTREE directory */
860#define PR_1_HTREE_HASHV 0x01004A
861
862/* Incompatible flag in HTREE root node */
863#define PR_1_HTREE_INCOMPAT 0x01004B
864
865/* HTREE too deep */
866#define PR_1_HTREE_DEPTH 0x01004C
867
868/* Bad block has indirect block that conflicts with filesystem block */
869#define PR_1_BB_FS_BLOCK 0x01004D
870
871/* Resize inode failed */
872#define PR_1_RESIZE_INODE_CREATE 0x01004E
873
874/* inode->i_size is too long */
875#define PR_1_EXTRA_ISIZE 0x01004F
876
877/* attribute name is too long */
878#define PR_1_ATTR_NAME_LEN 0x010050
879
880/* wrong EA value offset */
881#define PR_1_ATTR_VALUE_OFFSET 0x010051
882
883/* wrong EA blocknumber */
884#define PR_1_ATTR_VALUE_BLOCK 0x010052
885
886/* wrong EA value size */
887#define PR_1_ATTR_VALUE_SIZE 0x010053
888
889/* wrong EA hash value */
890#define PR_1_ATTR_HASH 0x010054
891
892/*
893 * Pass 1b errors
894 */
895
896/* Pass 1B: Rescan for duplicate/bad blocks */
897#define PR_1B_PASS_HEADER 0x011000
898
899/* Duplicate/bad block(s) header */
900#define PR_1B_DUP_BLOCK_HEADER 0x011001
901
902/* Duplicate/bad block(s) in inode */
903#define PR_1B_DUP_BLOCK 0x011002
904
905/* Duplicate/bad block(s) end */
906#define PR_1B_DUP_BLOCK_END 0x011003
907
908/* Error while scanning inodes */
909#define PR_1B_ISCAN_ERROR 0x011004
910
911/* Error allocating inode bitmap */
912#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005
913
914/* Error while iterating over blocks */
915#define PR_1B_BLOCK_ITERATE 0x0110006
916
917/* Error adjusting EA refcount */
918#define PR_1B_ADJ_EA_REFCOUNT 0x0110007
919
920
921/* Pass 1C: Scan directories for inodes with dup blocks. */
922#define PR_1C_PASS_HEADER 0x012000
923
924
925/* Pass 1D: Reconciling duplicate blocks */
926#define PR_1D_PASS_HEADER 0x013000
927
928/* File has duplicate blocks */
929#define PR_1D_DUP_FILE 0x013001
930
931/* List of files sharing duplicate blocks */
932#define PR_1D_DUP_FILE_LIST 0x013002
933
934/* File sharing blocks with filesystem metadata */
935#define PR_1D_SHARE_METADATA 0x013003
936
937/* Report of how many duplicate/bad inodes */
938#define PR_1D_NUM_DUP_INODES 0x013004
939
940/* Duplicated blocks already reassigned or cloned. */
941#define PR_1D_DUP_BLOCKS_DEALT 0x013005
942
943/* Clone duplicate/bad blocks? */
944#define PR_1D_CLONE_QUESTION 0x013006
945
946/* Delete file? */
947#define PR_1D_DELETE_QUESTION 0x013007
948
949/* Couldn't clone file (error) */
950#define PR_1D_CLONE_ERROR 0x013008
951
952/*
953 * Pass 2 errors
954 */
955
956/* Pass 2: Checking directory structure */
957#define PR_2_PASS_HEADER 0x020000
958
959/* Bad inode number for '.' */
960#define PR_2_BAD_INODE_DOT 0x020001
961
962/* Directory entry has bad inode number */
963#define PR_2_BAD_INO 0x020002
964
965/* Directory entry has deleted or unused inode */
966#define PR_2_UNUSED_INODE 0x020003
967
968/* Directry entry is link to '.' */
969#define PR_2_LINK_DOT 0x020004
970
971/* Directory entry points to inode now located in a bad block */
972#define PR_2_BB_INODE 0x020005
973
974/* Directory entry contains a link to a directory */
975#define PR_2_LINK_DIR 0x020006
976
977/* Directory entry contains a link to the root directry */
978#define PR_2_LINK_ROOT 0x020007
979
980/* Directory entry has illegal characters in its name */
981#define PR_2_BAD_NAME 0x020008
982
983/* Missing '.' in directory inode */
984#define PR_2_MISSING_DOT 0x020009
985
986/* Missing '..' in directory inode */
987#define PR_2_MISSING_DOT_DOT 0x02000A
988
989/* First entry in directory inode doesn't contain '.' */
990#define PR_2_1ST_NOT_DOT 0x02000B
991
992/* Second entry in directory inode doesn't contain '..' */
993#define PR_2_2ND_NOT_DOT_DOT 0x02000C
994
995/* i_faddr should be zero */
996#define PR_2_FADDR_ZERO 0x02000D
997
998/* i_file_acl should be zero */
999#define PR_2_FILE_ACL_ZERO 0x02000E
1000
1001/* i_dir_acl should be zero */
1002#define PR_2_DIR_ACL_ZERO 0x02000F
1003
1004/* i_frag should be zero */
1005#define PR_2_FRAG_ZERO 0x020010
1006
1007/* i_fsize should be zero */
1008#define PR_2_FSIZE_ZERO 0x020011
1009
1010/* inode has bad mode */
1011#define PR_2_BAD_MODE 0x020012
1012
1013/* directory corrupted */
1014#define PR_2_DIR_CORRUPTED 0x020013
1015
1016/* filename too long */
1017#define PR_2_FILENAME_LONG 0x020014
1018
1019/* Directory inode has a missing block (hole) */
1020#define PR_2_DIRECTORY_HOLE 0x020015
1021
1022/* '.' is not NULL terminated */
1023#define PR_2_DOT_NULL_TERM 0x020016
1024
1025/* '..' is not NULL terminated */
1026#define PR_2_DOT_DOT_NULL_TERM 0x020017
1027
1028/* Illegal character device in inode */
1029#define PR_2_BAD_CHAR_DEV 0x020018
1030
1031/* Illegal block device in inode */
1032#define PR_2_BAD_BLOCK_DEV 0x020019
1033
1034/* Duplicate '.' entry */
1035#define PR_2_DUP_DOT 0x02001A
1036
1037/* Duplicate '..' entry */
1038#define PR_2_DUP_DOT_DOT 0x02001B
1039
1040/* Internal error: couldn't find dir_info */
1041#define PR_2_NO_DIRINFO 0x02001C
1042
1043/* Final rec_len is wrong */
1044#define PR_2_FINAL_RECLEN 0x02001D
1045
1046/* Error allocating icount structure */
1047#define PR_2_ALLOCATE_ICOUNT 0x02001E
1048
1049/* Error iterating over directory blocks */
1050#define PR_2_DBLIST_ITERATE 0x02001F
1051
1052/* Error reading directory block */
1053#define PR_2_READ_DIRBLOCK 0x020020
1054
1055/* Error writing directory block */
1056#define PR_2_WRITE_DIRBLOCK 0x020021
1057
1058/* Error allocating new directory block */
1059#define PR_2_ALLOC_DIRBOCK 0x020022
1060
1061/* Error deallocating inode */
1062#define PR_2_DEALLOC_INODE 0x020023
1063
1064/* Directory entry for '.' is big. Split? */
1065#define PR_2_SPLIT_DOT 0x020024
1066
1067/* Illegal FIFO */
1068#define PR_2_BAD_FIFO 0x020025
1069
1070/* Illegal socket */
1071#define PR_2_BAD_SOCKET 0x020026
1072
1073/* Directory filetype not set */
1074#define PR_2_SET_FILETYPE 0x020027
1075
1076/* Directory filetype incorrect */
1077#define PR_2_BAD_FILETYPE 0x020028
1078
1079/* Directory filetype set when it shouldn't be */
1080#define PR_2_CLEAR_FILETYPE 0x020029
1081
1082/* Directory filename can't be zero-length */
1083#define PR_2_NULL_NAME 0x020030
1084
1085/* Invalid symlink */
1086#define PR_2_INVALID_SYMLINK 0x020031
1087
1088/* i_file_acl (extended attribute) is bad */
1089#define PR_2_FILE_ACL_BAD 0x020032
1090
1091/* Filesystem contains large files, but has no such flag in sb */
1092#define PR_2_FEATURE_LARGE_FILES 0x020033
1093
1094/* Node in HTREE directory not referenced */
1095#define PR_2_HTREE_NOTREF 0x020034
1096
1097/* Node in HTREE directory referenced twice */
1098#define PR_2_HTREE_DUPREF 0x020035
1099
1100/* Node in HTREE directory has bad min hash */
1101#define PR_2_HTREE_MIN_HASH 0x020036
1102
1103/* Node in HTREE directory has bad max hash */
1104#define PR_2_HTREE_MAX_HASH 0x020037
1105
1106/* Clear invalid HTREE directory */
1107#define PR_2_HTREE_CLEAR 0x020038
1108
1109/* Clear the htree flag forcibly */
1110/* #define PR_2_HTREE_FCLR 0x020039 */
1111
1112/* Bad block in htree interior node */
1113#define PR_2_HTREE_BADBLK 0x02003A
1114
1115/* Error adjusting EA refcount */
1116#define PR_2_ADJ_EA_REFCOUNT 0x02003B
1117
1118/* Invalid HTREE root node */
1119#define PR_2_HTREE_BAD_ROOT 0x02003C
1120
1121/* Invalid HTREE limit */
1122#define PR_2_HTREE_BAD_LIMIT 0x02003D
1123
1124/* Invalid HTREE count */
1125#define PR_2_HTREE_BAD_COUNT 0x02003E
1126
1127/* HTREE interior node has out-of-order hashes in table */
1128#define PR_2_HTREE_HASH_ORDER 0x02003F
1129
1130/* Node in HTREE directory has bad depth */
1131#define PR_2_HTREE_BAD_DEPTH 0x020040
1132
1133/* Duplicate directory entry found */
1134#define PR_2_DUPLICATE_DIRENT 0x020041
1135
1136/* Non-unique filename found */
1137#define PR_2_NON_UNIQUE_FILE 0x020042
1138
1139/* Duplicate directory entry found */
1140#define PR_2_REPORT_DUP_DIRENT 0x020043
1141
1142/*
1143 * Pass 3 errors
1144 */
1145
1146/* Pass 3: Checking directory connectivity */
1147#define PR_3_PASS_HEADER 0x030000
1148
1149/* Root inode not allocated */
1150#define PR_3_NO_ROOT_INODE 0x030001
1151
1152/* No room in lost+found */
1153#define PR_3_EXPAND_LF_DIR 0x030002
1154
1155/* Unconnected directory inode */
1156#define PR_3_UNCONNECTED_DIR 0x030003
1157
1158/* /lost+found not found */
1159#define PR_3_NO_LF_DIR 0x030004
1160
1161/* .. entry is incorrect */
1162#define PR_3_BAD_DOT_DOT 0x030005
1163
1164/* Bad or non-existent /lost+found. Cannot reconnect */
1165#define PR_3_NO_LPF 0x030006
1166
1167/* Could not expand /lost+found */
1168#define PR_3_CANT_EXPAND_LPF 0x030007
1169
1170/* Could not reconnect inode */
1171#define PR_3_CANT_RECONNECT 0x030008
1172
1173/* Error while trying to find /lost+found */
1174#define PR_3_ERR_FIND_LPF 0x030009
1175
1176/* Error in ext2fs_new_block while creating /lost+found */
1177#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A
1178
1179/* Error in ext2fs_new_inode while creating /lost+found */
1180#define PR_3_ERR_LPF_NEW_INODE 0x03000B
1181
1182/* Error in ext2fs_new_dir_block while creating /lost+found */
1183#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C
1184
1185/* Error while writing directory block for /lost+found */
1186#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D
1187
1188/* Error while adjusting inode count */
1189#define PR_3_ADJUST_INODE 0x03000E
1190
1191/* Couldn't fix parent directory -- error */
1192#define PR_3_FIX_PARENT_ERR 0x03000F
1193
1194/* Couldn't fix parent directory -- couldn't find it */
1195#define PR_3_FIX_PARENT_NOFIND 0x030010
1196
1197/* Error allocating inode bitmap */
1198#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011
1199
1200/* Error creating root directory */
1201#define PR_3_CREATE_ROOT_ERROR 0x030012
1202
1203/* Error creating lost and found directory */
1204#define PR_3_CREATE_LPF_ERROR 0x030013
1205
1206/* Root inode is not directory; aborting */
1207#define PR_3_ROOT_NOT_DIR_ABORT 0x030014
1208
1209/* Cannot proceed without a root inode. */
1210#define PR_3_NO_ROOT_INODE_ABORT 0x030015
1211
1212/* Internal error: couldn't find dir_info */
1213#define PR_3_NO_DIRINFO 0x030016
1214
1215/* Lost+found is not a directory */
1216#define PR_3_LPF_NOTDIR 0x030017
1217
1218/*
1219 * Pass 3a --- rehashing diretories
1220 */
1221/* Pass 3a: Reindexing directories */
1222#define PR_3A_PASS_HEADER 0x031000
1223
1224/* Error iterating over directories */
1225#define PR_3A_OPTIMIZE_ITER 0x031001
1226
1227/* Error rehash directory */
1228#define PR_3A_OPTIMIZE_DIR_ERR 0x031002
1229
1230/* Rehashing dir header */
1231#define PR_3A_OPTIMIZE_DIR_HEADER 0x031003
1232
1233/* Rehashing directory %d */
1234#define PR_3A_OPTIMIZE_DIR 0x031004
1235
1236/* Rehashing dir end */
1237#define PR_3A_OPTIMIZE_DIR_END 0x031005
1238
1239/*
1240 * Pass 4 errors
1241 */
1242
1243/* Pass 4: Checking reference counts */
1244#define PR_4_PASS_HEADER 0x040000
1245
1246/* Unattached zero-length inode */
1247#define PR_4_ZERO_LEN_INODE 0x040001
1248
1249/* Unattached inode */
1250#define PR_4_UNATTACHED_INODE 0x040002
1251
1252/* Inode ref count wrong */
1253#define PR_4_BAD_REF_COUNT 0x040003
1254
1255/* Inconsistent inode count information cached */
1256#define PR_4_INCONSISTENT_COUNT 0x040004
1257
1258/*
1259 * Pass 5 errors
1260 */
1261
1262/* Pass 5: Checking group summary information */
1263#define PR_5_PASS_HEADER 0x050000
1264
1265/* Padding at end of inode bitmap is not set. */
1266#define PR_5_INODE_BMAP_PADDING 0x050001
1267
1268/* Padding at end of block bitmap is not set. */
1269#define PR_5_BLOCK_BMAP_PADDING 0x050002
1270
1271/* Block bitmap differences header */
1272#define PR_5_BLOCK_BITMAP_HEADER 0x050003
1273
1274/* Block not used, but marked in bitmap */
1275#define PR_5_BLOCK_UNUSED 0x050004
1276
1277/* Block used, but not marked used in bitmap */
1278#define PR_5_BLOCK_USED 0x050005
1279
1280/* Block bitmap differences end */
1281#define PR_5_BLOCK_BITMAP_END 0x050006
1282
1283/* Inode bitmap differences header */
1284#define PR_5_INODE_BITMAP_HEADER 0x050007
1285
1286/* Inode not used, but marked in bitmap */
1287#define PR_5_INODE_UNUSED 0x050008
1288
1289/* Inode used, but not marked used in bitmap */
1290#define PR_5_INODE_USED 0x050009
1291
1292/* Inode bitmap differences end */
1293#define PR_5_INODE_BITMAP_END 0x05000A
1294
1295/* Free inodes count for group wrong */
1296#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B
1297
1298/* Directories count for group wrong */
1299#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C
1300
1301/* Free inodes count wrong */
1302#define PR_5_FREE_INODE_COUNT 0x05000D
1303
1304/* Free blocks count for group wrong */
1305#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E
1306
1307/* Free blocks count wrong */
1308#define PR_5_FREE_BLOCK_COUNT 0x05000F
1309
1310/* Programming error: bitmap endpoints don't match */
1311#define PR_5_BMAP_ENDPOINTS 0x050010
1312
1313/* Internal error: fudging end of bitmap */
1314#define PR_5_FUDGE_BITMAP_ERROR 0x050011
1315
1316/* Error copying in replacement inode bitmap */
1317#define PR_5_COPY_IBITMAP_ERROR 0x050012
1318
1319/* Error copying in replacement block bitmap */
1320#define PR_5_COPY_BBITMAP_ERROR 0x050013
1321
1322/* Block range not used, but marked in bitmap */
1323#define PR_5_BLOCK_RANGE_UNUSED 0x050014
1324
1325/* Block range used, but not marked used in bitmap */
1326#define PR_5_BLOCK_RANGE_USED 0x050015
1327
1328/* Inode range not used, but marked in bitmap */
1329#define PR_5_INODE_RANGE_UNUSED 0x050016
1330
1331/* Inode rangeused, but not marked used in bitmap */
1332#define PR_5_INODE_RANGE_USED 0x050017
1333
1334/*
1335 * Function declarations
1336 */
1337static int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
1338static int end_problem_latch(e2fsck_t ctx, int mask);
1339static int set_latch_flags(int mask, int setflags, int clearflags);
1340static void clear_problem_context(struct problem_context *ctx);
1341
1342/* message.c */
1343static void print_e2fsck_message(e2fsck_t ctx, const char *msg,
1344 struct problem_context *pctx, int first);
1345
1346/*
1347 * Dictionary Abstract Data Type
1348 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
1349 *
1350 * Free Software License:
1351 *
1352 * All rights are reserved by the author, with the following exceptions:
1353 * Permission is granted to freely reproduce and distribute this software,
1354 * possibly in exchange for a fee, provided that this copyright notice appears
1355 * intact. Permission is also granted to adapt this software to produce
1356 * derivative works, as long as the modified versions carry this copyright
1357 * notice and additional notices stating that the work has been modified.
1358 * This source code may be translated into executable form and incorporated
1359 * into proprietary software; there is no requirement for such software to
1360 * contain a copyright notice related to this source.
1361 *
1362 * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $
1363 * $Name: kazlib_1_20 $
1364 */
1365
1366#ifndef DICT_H
1367#define DICT_H
1368
1369/*
1370 * Blurb for inclusion into C++ translation units
1371 */
1372
1373typedef unsigned long dictcount_t;
1374#define DICTCOUNT_T_MAX ULONG_MAX
1375
1376/*
1377 * The dictionary is implemented as a red-black tree
1378 */
1379
1380typedef enum { dnode_red, dnode_black } dnode_color_t;
1381
1382typedef struct dnode_t {
1383 struct dnode_t *dict_left;
1384 struct dnode_t *dict_right;
1385 struct dnode_t *dict_parent;
1386 dnode_color_t dict_color;
1387 const void *dict_key;
1388 void *dict_data;
1389} dnode_t;
1390
1391typedef int (*dict_comp_t)(const void *, const void *);
1392typedef dnode_t *(*dnode_alloc_t)(void *);
1393typedef void (*dnode_free_t)(dnode_t *, void *);
1394
1395typedef struct dict_t {
1396 dnode_t dict_nilnode;
1397 dictcount_t dict_nodecount;
1398 dictcount_t dict_maxcount;
1399 dict_comp_t dict_compare;
1400 dnode_alloc_t dict_allocnode;
1401 dnode_free_t dict_freenode;
1402 void *dict_context;
1403 int dict_dupes;
1404} dict_t;
1405
1406typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
1407
1408typedef struct dict_load_t {
1409 dict_t *dict_dictptr;
1410 dnode_t dict_nilnode;
1411} dict_load_t;
1412
1413static void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *);
1414static void dict_free_nodes(dict_t *);
1415static dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t);
1416static dnode_t *dict_lookup(dict_t *, const void *);
1417static void dict_insert(dict_t *, dnode_t *, const void *);
1418static int dict_alloc_insert(dict_t *, const void *, void *);
1419static dnode_t *dict_first(dict_t *);
1420static dnode_t *dict_next(dict_t *, dnode_t *);
1421static dictcount_t dict_count(dict_t *);
1422static dnode_t *dnode_init(dnode_t *, void *);
1423static void *dnode_get(dnode_t *);
1424static const void *dnode_getkey(dnode_t *);
1425
1426#define dict_count(D) ((D)->dict_nodecount)
1427#define dnode_get(N) ((N)->dict_data)
1428#define dnode_getkey(N) ((N)->dict_key)
1429
1430#endif
1431
1432/*
1433 * Compatibility header file for e2fsck which should be included
1434 * instead of linux/jfs.h
1435 *
1436 * Copyright (C) 2000 Stephen C. Tweedie
1437 */
1438
1439/*
1440 * Pull in the definition of the e2fsck context structure
1441 */
1442
1443
1444struct buffer_head {
1445 char b_data[8192];
1446 e2fsck_t b_ctx;
1447 io_channel b_io;
1448 int b_size;
1449 blk_t b_blocknr;
1450 int b_dirty;
1451 int b_uptodate;
1452 int b_err;
1453};
1454
1455struct inode {
1456 e2fsck_t i_ctx;
1457 ext2_ino_t i_ino;
1458 struct ext2_inode i_ext2;
1459};
1460
1461struct kdev_s {
1462 e2fsck_t k_ctx;
1463 int k_dev;
1464};
1465
1466#define K_DEV_FS 1
1467#define K_DEV_JOURNAL 2
1468
1469typedef struct kdev_s *kdev_t;
1470
1471#define lock_buffer(bh) do {} while(0)
1472#define unlock_buffer(bh) do {} while(0)
1473#define buffer_req(bh) 1
1474#define do_readahead(journal, start) do {} while(0)
1475
1476static e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
1477
1478typedef struct {
1479 int object_length;
1480} kmem_cache_t;
1481
1482#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
1483#define kmem_cache_free(cache,obj) free(obj)
1484#define kmem_cache_create(name,len,a,b,c,d) do_cache_create(len)
1485#define kmem_cache_destroy(cache) do_cache_destroy(cache)
1486#define kmalloc(len,flags) malloc(len)
1487#define kfree(p) free(p)
1488
1489/*
1490 * We use the standard libext2fs portability tricks for inline
1491 * functions.
1492 */
1493
1494static _INLINE_ kmem_cache_t * do_cache_create(int len)
1495{
1496 kmem_cache_t *new_cache;
1497 new_cache = malloc(sizeof(*new_cache));
1498 if (new_cache)
1499 new_cache->object_length = len;
1500 return new_cache;
1501}
1502
1503static _INLINE_ void do_cache_destroy(kmem_cache_t *cache)
1504{
1505 free(cache);
1506}
1507
1508/*
1509 * Now pull in the real linux/jfs.h definitions.
1510 */
1511#include "ext2fs/kernel-jbd.h"
1512
1513/*
1514 * Kernel compatibility functions are defined in journal.c
1515 */
1516static int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys);
1517static struct buffer_head *getblk(kdev_t ctx, blk_t blocknr, int blocksize);
1518static void sync_blockdev(kdev_t kdev);
1519static void ll_rw_block(int rw, int dummy, struct buffer_head *bh[]);
1520static void mark_buffer_dirty(struct buffer_head *bh);
1521static void mark_buffer_uptodate(struct buffer_head *bh, int val);
1522static void brelse(struct buffer_head *bh);
1523static int buffer_uptodate(struct buffer_head *bh);
1524static void wait_on_buffer(struct buffer_head *bh);
1525
1526/*
1527 * Define newer 2.5 interfaces
1528 */
1529#define __getblk(dev, blocknr, blocksize) getblk(dev, blocknr, blocksize)
1530#define set_buffer_uptodate(bh) mark_buffer_uptodate(bh, 1)
1531
1532/*
1533 * badblocks.c --- replace/append bad blocks to the bad block inode
1534 *
1535 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
1536 * redistributed under the terms of the GNU Public License.
1537 */
1538
1539static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
1540 void *priv_data);
1541
1542
1543static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
1544{
1545 printf(_("Bad block %u out of range; ignored.\n"), blk);
1546 return;
1547}
1548
1549void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
1550 int replace_bad_blocks)
1551{
1552 ext2_filsys fs = ctx->fs;
1553 errcode_t retval;
1554 badblocks_list bb_list = 0;
1555 FILE *f;
1556 char buf[1024];
1557
1558 e2fsck_read_bitmaps(ctx);
1559
1560 /*
1561 * Make sure the bad block inode is sane. If there are any
1562 * illegal blocks, clear them.
1563 */
1564 retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
1565 check_bb_inode_blocks, 0);
1566 if (retval) {
1567 com_err("ext2fs_block_iterate", retval,
1568 _("while sanity checking the bad blocks inode"));
1569 goto fatal;
1570 }
1571
1572 /*
1573 * If we're appending to the bad blocks inode, read in the
1574 * current bad blocks.
1575 */
1576 if (!replace_bad_blocks) {
1577 retval = ext2fs_read_bb_inode(fs, &bb_list);
1578 if (retval) {
1579 com_err("ext2fs_read_bb_inode", retval,
1580 _("while reading the bad blocks inode"));
1581 goto fatal;
1582 }
1583 }
1584
1585 /*
1586 * Now read in the bad blocks from the file; if
1587 * bad_blocks_file is null, then try to run the badblocks
1588 * command.
1589 */
1590 if (bad_blocks_file) {
1591 f = fopen(bad_blocks_file, "r");
1592 if (!f) {
1593 com_err("read_bad_blocks_file", errno,
1594 _("while trying to open %s"), bad_blocks_file);
1595 goto fatal;
1596 }
1597 } else {
1598 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
1599 (ctx->options & E2F_OPT_PREEN) ? "" : "-s ",
1600 (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "",
1601 fs->device_name, fs->super->s_blocks_count);
1602 f = popen(buf, "r");
1603 if (!f) {
1604 com_err("read_bad_blocks_file", errno,
1605 _("while trying popen '%s'"), buf);
1606 goto fatal;
1607 }
1608 }
1609 retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
1610 if (bad_blocks_file)
1611 fclose(f);
1612 else
1613 pclose(f);
1614 if (retval) {
1615 com_err("ext2fs_read_bb_FILE", retval,
1616 _("while reading in list of bad blocks from file"));
1617 goto fatal;
1618 }
1619
1620 /*
1621 * Finally, update the bad blocks from the bad_block_map
1622 */
1623 retval = ext2fs_update_bb_inode(fs, bb_list);
1624 if (retval) {
1625 com_err("ext2fs_update_bb_inode", retval,
1626 _("while updating bad block inode"));
1627 goto fatal;
1628 }
1629
1630 ext2fs_badblocks_list_free(bb_list);
1631 return;
1632
1633fatal:
1634 ctx->flags |= E2F_FLAG_ABORT;
1635 return;
1636
1637}
1638
1639static int check_bb_inode_blocks(ext2_filsys fs,
1640 blk_t *block_nr,
1641 int blockcnt EXT2FS_ATTR((unused)),
1642 void *priv_data EXT2FS_ATTR((unused)))
1643{
1644 if (!*block_nr)
1645 return 0;
1646
1647 /*
1648 * If the block number is outrageous, clear it and ignore it.
1649 */
1650 if (*block_nr >= fs->super->s_blocks_count ||
1651 *block_nr < fs->super->s_first_data_block) {
1652 printf(_("Warning illegal block %u found in bad block inode. Cleared.\n"), *block_nr);
1653 *block_nr = 0;
1654 return BLOCK_CHANGED;
1655 }
1656
1657 return 0;
1658}
1659
1660/*
1661 * Dictionary Abstract Data Type
1662 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
1663 *
1664 * Free Software License:
1665 *
1666 * All rights are reserved by the author, with the following exceptions:
1667 * Permission is granted to freely reproduce and distribute this software,
1668 * possibly in exchange for a fee, provided that this copyright notice appears
1669 * intact. Permission is also granted to adapt this software to produce
1670 * derivative works, as long as the modified versions carry this copyright
1671 * notice and additional notices stating that the work has been modified.
1672 * This source code may be translated into executable form and incorporated
1673 * into proprietary software; there is no requirement for such software to
1674 * contain a copyright notice related to this source.
1675 *
1676 * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $
1677 * $Name: kazlib_1_20 $
1678 */
1679
1680
1681/*
1682 * These macros provide short convenient names for structure members,
1683 * which are embellished with dict_ prefixes so that they are
1684 * properly confined to the documented namespace. It's legal for a
1685 * program which uses dict to define, for instance, a macro called ``parent''.
1686 * Such a macro would interfere with the dnode_t struct definition.
1687 * In general, highly portable and reusable C modules which expose their
1688 * structures need to confine structure member names to well-defined spaces.
1689 * The resulting identifiers aren't necessarily convenient to use, nor
1690 * readable, in the implementation, however!
1691 */
1692
1693#define left dict_left
1694#define right dict_right
1695#define parent dict_parent
1696#define color dict_color
1697#define key dict_key
1698#define data dict_data
1699
1700#define nilnode dict_nilnode
1701#define nodecount dict_nodecount
1702#define maxcount dict_maxcount
1703#define compare dict_compare
1704#define allocnode dict_allocnode
1705#define freenode dict_freenode
1706#define context dict_context
1707#define dupes dict_dupes
1708
1709#define dictptr dict_dictptr
1710
1711#define dict_root(D) ((D)->nilnode.left)
1712#define dict_nil(D) (&(D)->nilnode)
1713#define DICT_DEPTH_MAX 64
1714
1715static dnode_t *dnode_alloc(void *context);
1716static void dnode_free(dnode_t *node, void *context);
1717
1718/*
1719 * Perform a ``left rotation'' adjustment on the tree. The given node P and
1720 * its right child C are rearranged so that the P instead becomes the left
1721 * child of C. The left subtree of C is inherited as the new right subtree
1722 * for P. The ordering of the keys within the tree is thus preserved.
1723 */
1724
1725static void rotate_left(dnode_t *upper)
1726{
1727 dnode_t *lower, *lowleft, *upparent;
1728
1729 lower = upper->right;
1730 upper->right = lowleft = lower->left;
1731 lowleft->parent = upper;
1732
1733 lower->parent = upparent = upper->parent;
1734
1735 /* don't need to check for root node here because root->parent is
1736 the sentinel nil node, and root->parent->left points back to root */
1737
1738 if (upper == upparent->left) {
1739 upparent->left = lower;
1740 } else {
1741 assert (upper == upparent->right);
1742 upparent->right = lower;
1743 }
1744
1745 lower->left = upper;
1746 upper->parent = lower;
1747}
1748
1749/*
1750 * This operation is the ``mirror'' image of rotate_left. It is
1751 * the same procedure, but with left and right interchanged.
1752 */
1753
1754static void rotate_right(dnode_t *upper)
1755{
1756 dnode_t *lower, *lowright, *upparent;
1757
1758 lower = upper->left;
1759 upper->left = lowright = lower->right;
1760 lowright->parent = upper;
1761
1762 lower->parent = upparent = upper->parent;
1763
1764 if (upper == upparent->right) {
1765 upparent->right = lower;
1766 } else {
1767 assert (upper == upparent->left);
1768 upparent->left = lower;
1769 }
1770
1771 lower->right = upper;
1772 upper->parent = lower;
1773}
1774
1775/*
1776 * Do a postorder traversal of the tree rooted at the specified
1777 * node and free everything under it. Used by dict_free().
1778 */
1779
1780static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
1781{
1782 if (node == nil)
1783 return;
1784 free_nodes(dict, node->left, nil);
1785 free_nodes(dict, node->right, nil);
1786 dict->freenode(node, dict->context);
1787}
1788
1789/*
1790 * Verify that the tree contains the given node. This is done by
1791 * traversing all of the nodes and comparing their pointers to the
1792 * given pointer. Returns 1 if the node is found, otherwise
1793 * returns zero. It is intended for debugging purposes.
1794 */
1795
1796static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
1797{
1798 if (root != nil) {
1799 return root == node
1800 || verify_dict_has_node(nil, root->left, node)
1801 || verify_dict_has_node(nil, root->right, node);
1802 }
1803 return 0;
1804}
1805
1806
1807/*
1808 * Select a different set of node allocator routines.
1809 */
1810
1811void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
1812 dnode_free_t fr, void *context)
1813{
1814 assert (dict_count(dict) == 0);
1815 assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
1816
1817 dict->allocnode = al ? al : dnode_alloc;
1818 dict->freenode = fr ? fr : dnode_free;
1819 dict->context = context;
1820}
1821
1822/*
1823 * Free all the nodes in the dictionary by using the dictionary's
1824 * installed free routine. The dictionary is emptied.
1825 */
1826
1827void dict_free_nodes(dict_t *dict)
1828{
1829 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
1830 free_nodes(dict, root, nil);
1831 dict->nodecount = 0;
1832 dict->nilnode.left = &dict->nilnode;
1833 dict->nilnode.right = &dict->nilnode;
1834}
1835
1836/*
1837 * Initialize a user-supplied dictionary object.
1838 */
1839
1840dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
1841{
1842 dict->compare = comp;
1843 dict->allocnode = dnode_alloc;
1844 dict->freenode = dnode_free;
1845 dict->context = NULL;
1846 dict->nodecount = 0;
1847 dict->maxcount = maxcount;
1848 dict->nilnode.left = &dict->nilnode;
1849 dict->nilnode.right = &dict->nilnode;
1850 dict->nilnode.parent = &dict->nilnode;
1851 dict->nilnode.color = dnode_black;
1852 dict->dupes = 0;
1853 return dict;
1854}
1855
1856/*
1857 * Locate a node in the dictionary having the given key.
1858 * If the node is not found, a null a pointer is returned (rather than
1859 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
1860 * located node is returned.
1861 */
1862
1863dnode_t *dict_lookup(dict_t *dict, const void *key)
1864{
1865 dnode_t *root = dict_root(dict);
1866 dnode_t *nil = dict_nil(dict);
1867 dnode_t *saved;
1868 int result;
1869
1870 /* simple binary search adapted for trees that contain duplicate keys */
1871
1872 while (root != nil) {
1873 result = dict->compare(key, root->key);
1874 if (result < 0)
1875 root = root->left;
1876 else if (result > 0)
1877 root = root->right;
1878 else {
1879 if (!dict->dupes) { /* no duplicates, return match */
1880 return root;
1881 } else { /* could be dupes, find leftmost one */
1882 do {
1883 saved = root;
1884 root = root->left;
1885 while (root != nil && dict->compare(key, root->key))
1886 root = root->right;
1887 } while (root != nil);
1888 return saved;
1889 }
1890 }
1891 }
1892
1893 return NULL;
1894}
1895
1896/*
1897 * Insert a node into the dictionary. The node should have been
1898 * initialized with a data field. All other fields are ignored.
1899 * The behavior is undefined if the user attempts to insert into
1900 * a dictionary that is already full (for which the dict_isfull()
1901 * function returns true).
1902 */
1903
1904void dict_insert(dict_t *dict, dnode_t *node, const void *key)
1905{
1906 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
1907 dnode_t *parent = nil, *uncle, *grandpa;
1908 int result = -1;
1909
1910 node->key = key;
1911
1912 /* basic binary tree insert */
1913
1914 while (where != nil) {
1915 parent = where;
1916 result = dict->compare(key, where->key);
1917 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
1918 assert (dict->dupes || result != 0);
1919 if (result < 0)
1920 where = where->left;
1921 else
1922 where = where->right;
1923 }
1924
1925 assert (where == nil);
1926
1927 if (result < 0)
1928 parent->left = node;
1929 else
1930 parent->right = node;
1931
1932 node->parent = parent;
1933 node->left = nil;
1934 node->right = nil;
1935
1936 dict->nodecount++;
1937
1938 /* red black adjustments */
1939
1940 node->color = dnode_red;
1941
1942 while (parent->color == dnode_red) {
1943 grandpa = parent->parent;
1944 if (parent == grandpa->left) {
1945 uncle = grandpa->right;
1946 if (uncle->color == dnode_red) { /* red parent, red uncle */
1947 parent->color = dnode_black;
1948 uncle->color = dnode_black;
1949 grandpa->color = dnode_red;
1950 node = grandpa;
1951 parent = grandpa->parent;
1952 } else { /* red parent, black uncle */
1953 if (node == parent->right) {
1954 rotate_left(parent);
1955 parent = node;
1956 assert (grandpa == parent->parent);
1957 /* rotation between parent and child preserves grandpa */
1958 }
1959 parent->color = dnode_black;
1960 grandpa->color = dnode_red;
1961 rotate_right(grandpa);
1962 break;
1963 }
1964 } else { /* symmetric cases: parent == parent->parent->right */
1965 uncle = grandpa->left;
1966 if (uncle->color == dnode_red) {
1967 parent->color = dnode_black;
1968 uncle->color = dnode_black;
1969 grandpa->color = dnode_red;
1970 node = grandpa;
1971 parent = grandpa->parent;
1972 } else {
1973 if (node == parent->left) {
1974 rotate_right(parent);
1975 parent = node;
1976 assert (grandpa == parent->parent);
1977 }
1978 parent->color = dnode_black;
1979 grandpa->color = dnode_red;
1980 rotate_left(grandpa);
1981 break;
1982 }
1983 }
1984 }
1985
1986 dict_root(dict)->color = dnode_black;
1987
1988}
1989
1990/*
1991 * Allocate a node using the dictionary's allocator routine, give it
1992 * the data item.
1993 */
1994
1995int dict_alloc_insert(dict_t *dict, const void *key, void *data)
1996{
1997 dnode_t *node = dict->allocnode(dict->context);
1998
1999 if (node) {
2000 dnode_init(node, data);
2001 dict_insert(dict, node, key);
2002 return 1;
2003 }
2004 return 0;
2005}
2006
2007/*
2008 * Return the node with the lowest (leftmost) key. If the dictionary is empty
2009 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
2010 */
2011
2012dnode_t *dict_first(dict_t *dict)
2013{
2014 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
2015
2016 if (root != nil)
2017 while ((left = root->left) != nil)
2018 root = left;
2019
2020 return (root == nil) ? NULL : root;
2021}
2022
2023/*
2024 * Return the given node's successor node---the node which has the
2025 * next key in the the left to right ordering. If the node has
2026 * no successor, a null pointer is returned rather than a pointer to
2027 * the nil node.
2028 */
2029
2030dnode_t *dict_next(dict_t *dict, dnode_t *curr)
2031{
2032 dnode_t *nil = dict_nil(dict), *parent, *left;
2033
2034 if (curr->right != nil) {
2035 curr = curr->right;
2036 while ((left = curr->left) != nil)
2037 curr = left;
2038 return curr;
2039 }
2040
2041 parent = curr->parent;
2042
2043 while (parent != nil && curr == parent->right) {
2044 curr = parent;
2045 parent = curr->parent;
2046 }
2047
2048 return (parent == nil) ? NULL : parent;
2049}
2050
2051#undef dict_count
2052#undef dnode_get
2053#undef dnode_getkey
2054
2055dictcount_t dict_count(dict_t *dict)
2056{
2057 return dict->nodecount;
2058}
2059
2060static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused)))
2061{
2062 return malloc(sizeof *dnode_alloc(NULL));
2063}
2064
2065static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused)))
2066{
2067 free(node);
2068}
2069
2070dnode_t *dnode_init(dnode_t *dnode, void *data)
2071{
2072 dnode->data = data;
2073 dnode->parent = NULL;
2074 dnode->left = NULL;
2075 dnode->right = NULL;
2076 return dnode;
2077}
2078
2079void *dnode_get(dnode_t *dnode)
2080{
2081 return dnode->data;
2082}
2083
2084const void *dnode_getkey(dnode_t *dnode)
2085{
2086 return dnode->key;
2087}
2088
2089#undef left
2090#undef right
2091#undef parent
2092#undef color
2093#undef key
2094#undef data
2095
2096#undef nilnode
2097#undef nodecount
2098#undef maxcount
2099#undef compare
2100#undef allocnode
2101#undef freenode
2102#undef context
2103#undef dupes
2104
2105#undef dictptr
2106
2107
2108/*
2109 * dirinfo.c --- maintains the directory information table for e2fsck.
2110 *
2111 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
2112 * under the terms of the GNU Public License.
2113 */
2114
2115/*
2116 * This subroutine is called during pass1 to create a directory info
2117 * entry. During pass1, the passed-in parent is 0; it will get filled
2118 * in during pass2.
2119 */
2120void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
2121{
2122 struct dir_info *dir;
2123 int i, j;
2124 ext2_ino_t num_dirs;
2125 errcode_t retval;
2126 unsigned long old_size;
2127
2128#if 0
2129 printf("add_dir_info for inode %lu...\n", ino);
2130#endif
2131 if (!ctx->dir_info) {
2132 ctx->dir_info_count = 0;
2133 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
2134 if (retval)
2135 num_dirs = 1024; /* Guess */
2136 ctx->dir_info_size = num_dirs + 10;
2137 ctx->dir_info = (struct dir_info *)
2138 e2fsck_allocate_memory(ctx, ctx->dir_info_size
2139 * sizeof (struct dir_info),
2140 "directory map");
2141 }
2142
2143 if (ctx->dir_info_count >= ctx->dir_info_size) {
2144 old_size = ctx->dir_info_size * sizeof(struct dir_info);
2145 ctx->dir_info_size += 10;
2146 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
2147 sizeof(struct dir_info),
2148 &ctx->dir_info);
2149 if (retval) {
2150 ctx->dir_info_size -= 10;
2151 return;
2152 }
2153 }
2154
2155 /*
2156 * Normally, add_dir_info is called with each inode in
2157 * sequential order; but once in a while (like when pass 3
2158 * needs to recreate the root directory or lost+found
2159 * directory) it is called out of order. In those cases, we
2160 * need to move the dir_info entries down to make room, since
2161 * the dir_info array needs to be sorted by inode number for
2162 * get_dir_info()'s sake.
2163 */
2164 if (ctx->dir_info_count &&
2165 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
2166 for (i = ctx->dir_info_count-1; i > 0; i--)
2167 if (ctx->dir_info[i-1].ino < ino)
2168 break;
2169 dir = &ctx->dir_info[i];
2170 if (dir->ino != ino)
2171 for (j = ctx->dir_info_count++; j > i; j--)
2172 ctx->dir_info[j] = ctx->dir_info[j-1];
2173 } else
2174 dir = &ctx->dir_info[ctx->dir_info_count++];
2175
2176 dir->ino = ino;
2177 dir->dotdot = parent;
2178 dir->parent = parent;
2179}
2180
2181/*
2182 * get_dir_info() --- given an inode number, try to find the directory
2183 * information entry for it.
2184 */
2185struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
2186{
2187 int low, high, mid;
2188
2189 low = 0;
2190 high = ctx->dir_info_count-1;
2191 if (!ctx->dir_info)
2192 return 0;
2193 if (ino == ctx->dir_info[low].ino)
2194 return &ctx->dir_info[low];
2195 if (ino == ctx->dir_info[high].ino)
2196 return &ctx->dir_info[high];
2197
2198 while (low < high) {
2199 mid = (low+high)/2;
2200 if (mid == low || mid == high)
2201 break;
2202 if (ino == ctx->dir_info[mid].ino)
2203 return &ctx->dir_info[mid];
2204 if (ino < ctx->dir_info[mid].ino)
2205 high = mid;
2206 else
2207 low = mid;
2208 }
2209 return 0;
2210}
2211
2212/*
2213 * Free the dir_info structure when it isn't needed any more.
2214 */
2215void e2fsck_free_dir_info(e2fsck_t ctx)
2216{
2217 if (ctx->dir_info) {
2218 ext2fs_free_mem(&ctx->dir_info);
2219 ctx->dir_info = 0;
2220 }
2221 ctx->dir_info_size = 0;
2222 ctx->dir_info_count = 0;
2223}
2224
2225/*
2226 * Return the count of number of directories in the dir_info structure
2227 */
2228int e2fsck_get_num_dirinfo(e2fsck_t ctx)
2229{
2230 return ctx->dir_info_count;
2231}
2232
2233/*
2234 * A simple interator function
2235 */
2236struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
2237{
2238 if (*control >= ctx->dir_info_count)
2239 return 0;
2240
2241 return(ctx->dir_info + (*control)++);
2242}
2243/*
2244 * dirinfo.c --- maintains the directory information table for e2fsck.
2245 *
2246 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
2247 * under the terms of the GNU Public License.
2248 */
2249
2250#ifdef ENABLE_HTREE
2251
2252/*
2253 * This subroutine is called during pass1 to create a directory info
2254 * entry. During pass1, the passed-in parent is 0; it will get filled
2255 * in during pass2.
2256 */
2257void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
2258{
2259 struct dx_dir_info *dir;
2260 int i, j;
2261 errcode_t retval;
2262 unsigned long old_size;
2263
2264#if 0
2265 printf("add_dx_dir_info for inode %lu...\n", ino);
2266#endif
2267 if (!ctx->dx_dir_info) {
2268 ctx->dx_dir_info_count = 0;
2269 ctx->dx_dir_info_size = 100; /* Guess */
2270 ctx->dx_dir_info = (struct dx_dir_info *)
2271 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
2272 * sizeof (struct dx_dir_info),
2273 "directory map");
2274 }
2275
2276 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
2277 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
2278 ctx->dx_dir_info_size += 10;
2279 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
2280 sizeof(struct dx_dir_info),
2281 &ctx->dx_dir_info);
2282 if (retval) {
2283 ctx->dx_dir_info_size -= 10;
2284 return;
2285 }
2286 }
2287
2288 /*
2289 * Normally, add_dx_dir_info is called with each inode in
2290 * sequential order; but once in a while (like when pass 3
2291 * needs to recreate the root directory or lost+found
2292 * directory) it is called out of order. In those cases, we
2293 * need to move the dx_dir_info entries down to make room, since
2294 * the dx_dir_info array needs to be sorted by inode number for
2295 * get_dx_dir_info()'s sake.
2296 */
2297 if (ctx->dx_dir_info_count &&
2298 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
2299 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
2300 if (ctx->dx_dir_info[i-1].ino < ino)
2301 break;
2302 dir = &ctx->dx_dir_info[i];
2303 if (dir->ino != ino)
2304 for (j = ctx->dx_dir_info_count++; j > i; j--)
2305 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
2306 } else
2307 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
2308
2309 dir->ino = ino;
2310 dir->numblocks = num_blocks;
2311 dir->hashversion = 0;
2312 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
2313 * sizeof (struct dx_dirblock_info),
2314 "dx_block info array");
2315
2316}
2317
2318/*
2319 * get_dx_dir_info() --- given an inode number, try to find the directory
2320 * information entry for it.
2321 */
2322struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
2323{
2324 int low, high, mid;
2325
2326 low = 0;
2327 high = ctx->dx_dir_info_count-1;
2328 if (!ctx->dx_dir_info)
2329 return 0;
2330 if (ino == ctx->dx_dir_info[low].ino)
2331 return &ctx->dx_dir_info[low];
2332 if (ino == ctx->dx_dir_info[high].ino)
2333 return &ctx->dx_dir_info[high];
2334
2335 while (low < high) {
2336 mid = (low+high)/2;
2337 if (mid == low || mid == high)
2338 break;
2339 if (ino == ctx->dx_dir_info[mid].ino)
2340 return &ctx->dx_dir_info[mid];
2341 if (ino < ctx->dx_dir_info[mid].ino)
2342 high = mid;
2343 else
2344 low = mid;
2345 }
2346 return 0;
2347}
2348
2349/*
2350 * Free the dx_dir_info structure when it isn't needed any more.
2351 */
2352void e2fsck_free_dx_dir_info(e2fsck_t ctx)
2353{
2354 int i;
2355 struct dx_dir_info *dir;
2356
2357 if (ctx->dx_dir_info) {
2358 dir = ctx->dx_dir_info;
2359 for (i=0; i < ctx->dx_dir_info_count; i++) {
2360 if (dir->dx_block) {
2361 ext2fs_free_mem(&dir->dx_block);
2362 dir->dx_block = 0;
2363 }
2364 }
2365 ext2fs_free_mem(&ctx->dx_dir_info);
2366 ctx->dx_dir_info = 0;
2367 }
2368 ctx->dx_dir_info_size = 0;
2369 ctx->dx_dir_info_count = 0;
2370}
2371
2372/*
2373 * A simple interator function
2374 */
2375struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
2376{
2377 if (*control >= ctx->dx_dir_info_count)
2378 return 0;
2379
2380 return(ctx->dx_dir_info + (*control)++);
2381}
2382
2383#endif /* ENABLE_HTREE */
2384/*
2385 * e2fsck.c - a consistency checker for the new extended file system.
2386 *
2387 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
2388 *
2389 * %Begin-Header%
2390 * This file may be redistributed under the terms of the GNU Public
2391 * License.
2392 * %End-Header%
2393 */
2394
2395/*
2396 * This function allocates an e2fsck context
2397 */
2398errcode_t e2fsck_allocate_context(e2fsck_t *ret)
2399{
2400 e2fsck_t context;
2401 errcode_t retval;
2402
2403 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
2404 if (retval)
2405 return retval;
2406
2407 memset(context, 0, sizeof(struct e2fsck_struct));
2408
2409 context->process_inode_size = 256;
2410 context->ext_attr_ver = 2;
2411
2412 *ret = context;
2413 return 0;
2414}
2415
2416/*
2417 * This function resets an e2fsck context; it is called when e2fsck
2418 * needs to be restarted.
2419 */
2420errcode_t e2fsck_reset_context(e2fsck_t ctx)
2421{
2422 ctx->flags = 0;
2423 ctx->lost_and_found = 0;
2424 ctx->bad_lost_and_found = 0;
2425 if (ctx->inode_used_map) {
2426 ext2fs_free_inode_bitmap(ctx->inode_used_map);
2427 ctx->inode_used_map = 0;
2428 }
2429 if (ctx->inode_dir_map) {
2430 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
2431 ctx->inode_dir_map = 0;
2432 }
2433 if (ctx->inode_reg_map) {
2434 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
2435 ctx->inode_reg_map = 0;
2436 }
2437 if (ctx->block_found_map) {
2438 ext2fs_free_block_bitmap(ctx->block_found_map);
2439 ctx->block_found_map = 0;
2440 }
2441 if (ctx->inode_link_info) {
2442 ext2fs_free_icount(ctx->inode_link_info);
2443 ctx->inode_link_info = 0;
2444 }
2445 if (ctx->journal_io) {
2446 if (ctx->fs && ctx->fs->io != ctx->journal_io)
2447 io_channel_close(ctx->journal_io);
2448 ctx->journal_io = 0;
2449 }
2450 if (ctx->fs && ctx->fs->dblist) {
2451 ext2fs_free_dblist(ctx->fs->dblist);
2452 ctx->fs->dblist = 0;
2453 }
2454 e2fsck_free_dir_info(ctx);
2455#ifdef ENABLE_HTREE
2456 e2fsck_free_dx_dir_info(ctx);
2457#endif
2458 if (ctx->refcount) {
2459 ea_refcount_free(ctx->refcount);
2460 ctx->refcount = 0;
2461 }
2462 if (ctx->refcount_extra) {
2463 ea_refcount_free(ctx->refcount_extra);
2464 ctx->refcount_extra = 0;
2465 }
2466 if (ctx->block_dup_map) {
2467 ext2fs_free_block_bitmap(ctx->block_dup_map);
2468 ctx->block_dup_map = 0;
2469 }
2470 if (ctx->block_ea_map) {
2471 ext2fs_free_block_bitmap(ctx->block_ea_map);
2472 ctx->block_ea_map = 0;
2473 }
2474 if (ctx->inode_bb_map) {
2475 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
2476 ctx->inode_bb_map = 0;
2477 }
2478 if (ctx->inode_bad_map) {
2479 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
2480 ctx->inode_bad_map = 0;
2481 }
2482 if (ctx->inode_imagic_map) {
2483 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
2484 ctx->inode_imagic_map = 0;
2485 }
2486 if (ctx->dirs_to_hash) {
2487 ext2fs_u32_list_free(ctx->dirs_to_hash);
2488 ctx->dirs_to_hash = 0;
2489 }
2490
2491 /*
2492 * Clear the array of invalid meta-data flags
2493 */
2494 if (ctx->invalid_inode_bitmap_flag) {
2495 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
2496 ctx->invalid_inode_bitmap_flag = 0;
2497 }
2498 if (ctx->invalid_block_bitmap_flag) {
2499 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
2500 ctx->invalid_block_bitmap_flag = 0;
2501 }
2502 if (ctx->invalid_inode_table_flag) {
2503 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
2504 ctx->invalid_inode_table_flag = 0;
2505 }
2506
2507 /* Clear statistic counters */
2508 ctx->fs_directory_count = 0;
2509 ctx->fs_regular_count = 0;
2510 ctx->fs_blockdev_count = 0;
2511 ctx->fs_chardev_count = 0;
2512 ctx->fs_links_count = 0;
2513 ctx->fs_symlinks_count = 0;
2514 ctx->fs_fast_symlinks_count = 0;
2515 ctx->fs_fifo_count = 0;
2516 ctx->fs_total_count = 0;
2517 ctx->fs_badblocks_count = 0;
2518 ctx->fs_sockets_count = 0;
2519 ctx->fs_ind_count = 0;
2520 ctx->fs_dind_count = 0;
2521 ctx->fs_tind_count = 0;
2522 ctx->fs_fragmented = 0;
2523 ctx->large_files = 0;
2524
2525 /* Reset the superblock to the user's requested value */
2526 ctx->superblock = ctx->use_superblock;
2527
2528 return 0;
2529}
2530
2531void e2fsck_free_context(e2fsck_t ctx)
2532{
2533 if (!ctx)
2534 return;
2535
2536 e2fsck_reset_context(ctx);
2537 if (ctx->blkid)
2538 blkid_put_cache(ctx->blkid);
2539
2540 ext2fs_free_mem(&ctx);
2541}
2542
2543/*
2544 * This function runs through the e2fsck passes and calls them all,
2545 * returning restart, abort, or cancel as necessary...
2546 */
2547typedef void (*pass_t)(e2fsck_t ctx);
2548
2549static pass_t e2fsck_passes[] = {
2550 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
2551 e2fsck_pass5, 0 };
2552
2553#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
2554
2555int e2fsck_run(e2fsck_t ctx)
2556{
2557 int i;
2558 pass_t e2fsck_pass;
2559
2560 if (setjmp(ctx->abort_loc)) {
2561 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
2562 return (ctx->flags & E2F_FLAG_RUN_RETURN);
2563 }
2564 ctx->flags |= E2F_FLAG_SETJMP_OK;
2565
2566 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
2567 if (ctx->flags & E2F_FLAG_RUN_RETURN)
2568 break;
2569 e2fsck_pass(ctx);
2570 if (ctx->progress)
2571 (void) (ctx->progress)(ctx, 0, 0, 0);
2572 }
2573 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
2574
2575 if (ctx->flags & E2F_FLAG_RUN_RETURN)
2576 return (ctx->flags & E2F_FLAG_RUN_RETURN);
2577 return 0;
2578}
2579/*
2580 * ea_refcount.c
2581 *
2582 * Copyright (C) 2001 Theodore Ts'o. This file may be
2583 * redistributed under the terms of the GNU Public License.
2584 */
2585
2586/*
2587 * The strategy we use for keeping track of EA refcounts is as
2588 * follows. We keep a sorted array of first EA blocks and its
2589 * reference counts. Once the refcount has dropped to zero, it is
2590 * removed from the array to save memory space. Once the EA block is
2591 * checked, its bit is set in the block_ea_map bitmap.
2592 */
2593struct ea_refcount_el {
2594 blk_t ea_blk;
2595 int ea_count;
2596};
2597
2598struct ea_refcount {
2599 blk_t count;
2600 blk_t size;
2601 blk_t cursor;
2602 struct ea_refcount_el *list;
2603};
2604
2605void ea_refcount_free(ext2_refcount_t refcount)
2606{
2607 if (!refcount)
2608 return;
2609
2610 if (refcount->list)
2611 ext2fs_free_mem(&refcount->list);
2612 ext2fs_free_mem(&refcount);
2613}
2614
2615errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
2616{
2617 ext2_refcount_t refcount;
2618 errcode_t retval;
2619 size_t bytes;
2620
2621 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
2622 if (retval)
2623 return retval;
2624 memset(refcount, 0, sizeof(struct ea_refcount));
2625
2626 if (!size)
2627 size = 500;
2628 refcount->size = size;
2629 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
2630#ifdef DEBUG
2631 printf("Refcount allocated %d entries, %d bytes.\n",
2632 refcount->size, bytes);
2633#endif
2634 retval = ext2fs_get_mem(bytes, &refcount->list);
2635 if (retval)
2636 goto errout;
2637 memset(refcount->list, 0, bytes);
2638
2639 refcount->count = 0;
2640 refcount->cursor = 0;
2641
2642 *ret = refcount;
2643 return 0;
2644
2645errout:
2646 ea_refcount_free(refcount);
2647 return(retval);
2648}
2649
2650/*
2651 * collapse_refcount() --- go through the refcount array, and get rid
2652 * of any count == zero entries
2653 */
2654static void refcount_collapse(ext2_refcount_t refcount)
2655{
2656 unsigned int i, j;
2657 struct ea_refcount_el *list;
2658
2659 list = refcount->list;
2660 for (i = 0, j = 0; i < refcount->count; i++) {
2661 if (list[i].ea_count) {
2662 if (i != j)
2663 list[j] = list[i];
2664 j++;
2665 }
2666 }
2667#if defined(DEBUG) || defined(TEST_PROGRAM)
2668 printf("Refcount_collapse: size was %d, now %d\n",
2669 refcount->count, j);
2670#endif
2671 refcount->count = j;
2672}
2673
2674
2675/*
2676 * insert_refcount_el() --- Insert a new entry into the sorted list at a
2677 * specified position.
2678 */
2679static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
2680 blk_t blk, int pos)
2681{
2682 struct ea_refcount_el *el;
2683 errcode_t retval;
2684 blk_t new_size = 0;
2685 int num;
2686
2687 if (refcount->count >= refcount->size) {
2688 new_size = refcount->size + 100;
2689#ifdef DEBUG
2690 printf("Reallocating refcount %d entries...\n", new_size);
2691#endif
2692 retval = ext2fs_resize_mem((size_t) refcount->size *
2693 sizeof(struct ea_refcount_el),
2694 (size_t) new_size *
2695 sizeof(struct ea_refcount_el),
2696 &refcount->list);
2697 if (retval)
2698 return 0;
2699 refcount->size = new_size;
2700 }
2701 num = (int) refcount->count - pos;
2702 if (num < 0)
2703 return 0; /* should never happen */
2704 if (num) {
2705 memmove(&refcount->list[pos+1], &refcount->list[pos],
2706 sizeof(struct ea_refcount_el) * num);
2707 }
2708 refcount->count++;
2709 el = &refcount->list[pos];
2710 el->ea_count = 0;
2711 el->ea_blk = blk;
2712 return el;
2713}
2714
2715
2716/*
2717 * get_refcount_el() --- given an block number, try to find refcount
2718 * information in the sorted list. If the create flag is set,
2719 * and we can't find an entry, create one in the sorted list.
2720 */
2721static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
2722 blk_t blk, int create)
2723{
2724 float range;
2725 int low, high, mid;
2726 blk_t lowval, highval;
2727
2728 if (!refcount || !refcount->list)
2729 return 0;
2730retry:
2731 low = 0;
2732 high = (int) refcount->count-1;
2733 if (create && ((refcount->count == 0) ||
2734 (blk > refcount->list[high].ea_blk))) {
2735 if (refcount->count >= refcount->size)
2736 refcount_collapse(refcount);
2737
2738 return insert_refcount_el(refcount, blk,
2739 (unsigned) refcount->count);
2740 }
2741 if (refcount->count == 0)
2742 return 0;
2743
2744 if (refcount->cursor >= refcount->count)
2745 refcount->cursor = 0;
2746 if (blk == refcount->list[refcount->cursor].ea_blk)
2747 return &refcount->list[refcount->cursor++];
2748#ifdef DEBUG
2749 printf("Non-cursor get_refcount_el: %u\n", blk);
2750#endif
2751 while (low <= high) {
2752#if 0
2753 mid = (low+high)/2;
23#else 2754#else
24extern char *optarg; 2755 if (low == high)
25extern int optind; 2756 mid = low;
2757 else {
2758 /* Interpolate for efficiency */
2759 lowval = refcount->list[low].ea_blk;
2760 highval = refcount->list[high].ea_blk;
2761
2762 if (blk < lowval)
2763 range = 0;
2764 else if (blk > highval)
2765 range = 1;
2766 else
2767 range = ((float) (blk - lowval)) /
2768 (highval - lowval);
2769 mid = low + ((int) (range * (high-low)));
2770 }
26#endif 2771#endif
27#include <unistd.h> 2772 if (blk == refcount->list[mid].ea_blk) {
28#ifdef HAVE_ERRNO_H 2773 refcount->cursor = mid+1;
29#include <errno.h> 2774 return &refcount->list[mid];
2775 }
2776 if (blk < refcount->list[mid].ea_blk)
2777 high = mid-1;
2778 else
2779 low = mid+1;
2780 }
2781 /*
2782 * If we need to create a new entry, it should be right at
2783 * low (where high will be left at low-1).
2784 */
2785 if (create) {
2786 if (refcount->count >= refcount->size) {
2787 refcount_collapse(refcount);
2788 if (refcount->count < refcount->size)
2789 goto retry;
2790 }
2791 return insert_refcount_el(refcount, blk, low);
2792 }
2793 return 0;
2794}
2795
2796errcode_t ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
2797{
2798 struct ea_refcount_el *el;
2799
2800 el = get_refcount_el(refcount, blk, 1);
2801 if (!el)
2802 return EXT2_ET_NO_MEMORY;
2803 el->ea_count++;
2804
2805 if (ret)
2806 *ret = el->ea_count;
2807 return 0;
2808}
2809
2810errcode_t ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
2811{
2812 struct ea_refcount_el *el;
2813
2814 el = get_refcount_el(refcount, blk, 0);
2815 if (!el || el->ea_count == 0)
2816 return EXT2_ET_INVALID_ARGUMENT;
2817
2818 el->ea_count--;
2819
2820 if (ret)
2821 *ret = el->ea_count;
2822 return 0;
2823}
2824
2825errcode_t ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
2826{
2827 struct ea_refcount_el *el;
2828
2829 /*
2830 * Get the refcount element
2831 */
2832 el = get_refcount_el(refcount, blk, count ? 1 : 0);
2833 if (!el)
2834 return count ? EXT2_ET_NO_MEMORY : 0;
2835 el->ea_count = count;
2836 return 0;
2837}
2838
2839void ea_refcount_intr_begin(ext2_refcount_t refcount)
2840{
2841 refcount->cursor = 0;
2842}
2843
2844
2845blk_t ea_refcount_intr_next(ext2_refcount_t refcount,
2846 int *ret)
2847{
2848 struct ea_refcount_el *list;
2849
2850 while (1) {
2851 if (refcount->cursor >= refcount->count)
2852 return 0;
2853 list = refcount->list;
2854 if (list[refcount->cursor].ea_count) {
2855 if (ret)
2856 *ret = list[refcount->cursor].ea_count;
2857 return list[refcount->cursor++].ea_blk;
2858 }
2859 refcount->cursor++;
2860 }
2861}
2862
2863
2864/*
2865 * ehandler.c --- handle bad block errors which come up during the
2866 * course of an e2fsck session.
2867 *
2868 * Copyright (C) 1994 Theodore Ts'o. This file may be redistributed
2869 * under the terms of the GNU Public License.
2870 */
2871
2872
2873static const char *operation;
2874
2875static errcode_t e2fsck_handle_read_error(io_channel channel,
2876 unsigned long block,
2877 int count,
2878 void *data,
2879 size_t size EXT2FS_ATTR((unused)),
2880 int actual EXT2FS_ATTR((unused)),
2881 errcode_t error)
2882{
2883 int i;
2884 char *p;
2885 ext2_filsys fs = (ext2_filsys) channel->app_data;
2886 e2fsck_t ctx;
2887
2888 ctx = (e2fsck_t) fs->priv_data;
2889
2890 /*
2891 * If more than one block was read, try reading each block
2892 * separately. We could use the actual bytes read to figure
2893 * out where to start, but we don't bother.
2894 */
2895 if (count > 1) {
2896 p = (char *) data;
2897 for (i=0; i < count; i++, p += channel->block_size, block++) {
2898 error = io_channel_read_blk(channel, block,
2899 1, p);
2900 if (error)
2901 return error;
2902 }
2903 return 0;
2904 }
2905 if (operation)
2906 printf(_("Error reading block %lu (%s) while %s. "), block,
2907 error_message(error), operation);
2908 else
2909 printf(_("Error reading block %lu (%s). "), block,
2910 error_message(error));
2911 preenhalt(ctx);
2912 if (ask(ctx, _("Ignore error"), 1)) {
2913 if (ask(ctx, _("Force rewrite"), 1))
2914 io_channel_write_blk(channel, block, 1, data);
2915 return 0;
2916 }
2917
2918 return error;
2919}
2920
2921static errcode_t e2fsck_handle_write_error(io_channel channel,
2922 unsigned long block,
2923 int count,
2924 const void *data,
2925 size_t size EXT2FS_ATTR((unused)),
2926 int actual EXT2FS_ATTR((unused)),
2927 errcode_t error)
2928{
2929 int i;
2930 const char *p;
2931 ext2_filsys fs = (ext2_filsys) channel->app_data;
2932 e2fsck_t ctx;
2933
2934 ctx = (e2fsck_t) fs->priv_data;
2935
2936 /*
2937 * If more than one block was written, try writing each block
2938 * separately. We could use the actual bytes read to figure
2939 * out where to start, but we don't bother.
2940 */
2941 if (count > 1) {
2942 p = (const char *) data;
2943 for (i=0; i < count; i++, p += channel->block_size, block++) {
2944 error = io_channel_write_blk(channel, block,
2945 1, p);
2946 if (error)
2947 return error;
2948 }
2949 return 0;
2950 }
2951
2952 if (operation)
2953 printf(_("Error writing block %lu (%s) while %s. "), block,
2954 error_message(error), operation);
2955 else
2956 printf(_("Error writing block %lu (%s). "), block,
2957 error_message(error));
2958 preenhalt(ctx);
2959 if (ask(ctx, _("Ignore error"), 1))
2960 return 0;
2961
2962 return error;
2963}
2964
2965const char *ehandler_operation(const char *op)
2966{
2967 const char *ret = operation;
2968
2969 operation = op;
2970 return ret;
2971}
2972
2973void ehandler_init(io_channel channel)
2974{
2975 channel->read_error = e2fsck_handle_read_error;
2976 channel->write_error = e2fsck_handle_write_error;
2977}
2978/*
2979 * journal.c --- code for handling the "ext3" journal
2980 *
2981 * Copyright (C) 2000 Andreas Dilger
2982 * Copyright (C) 2000 Theodore Ts'o
2983 *
2984 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
2985 * Copyright (C) 1999 Red Hat Software
2986 *
2987 * This file may be redistributed under the terms of the
2988 * GNU General Public License version 2 or at your discretion
2989 * any later version.
2990 */
2991
2992#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
2993
2994
2995#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
2996static int bh_count = 0;
30#endif 2997#endif
31#ifdef HAVE_MNTENT_H 2998
32#include <mntent.h> 2999/*
3000 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
3001 * This creates a larger static binary, and a smaller binary using
3002 * shared libraries. It's also probably slightly less CPU-efficient,
3003 * which is why it's not on by default. But, it's a good way of
3004 * testing the functions in inode_io.c and fileio.c.
3005 */
3006#undef USE_INODE_IO
3007
3008/* Kernel compatibility functions for handling the journal. These allow us
3009 * to use the recovery.c file virtually unchanged from the kernel, so we
3010 * don't have to do much to keep kernel and user recovery in sync.
3011 */
3012int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
3013{
3014#ifdef USE_INODE_IO
3015 *phys = block;
3016 return 0;
3017#else
3018 struct inode *inode = journal->j_inode;
3019 errcode_t retval;
3020 blk_t pblk;
3021
3022 if (!inode) {
3023 *phys = block;
3024 return 0;
3025 }
3026
3027 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
3028 &inode->i_ext2, NULL, 0, block, &pblk);
3029 *phys = pblk;
3030 return (retval);
33#endif 3031#endif
34#ifdef HAVE_SYS_IOCTL_H 3032}
35#include <sys/ioctl.h> 3033
3034struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
3035{
3036 struct buffer_head *bh;
3037
3038 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
3039 if (!bh)
3040 return NULL;
3041
3042 jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
3043 (unsigned long) blocknr, blocksize, ++bh_count);
3044
3045 bh->b_ctx = kdev->k_ctx;
3046 if (kdev->k_dev == K_DEV_FS)
3047 bh->b_io = kdev->k_ctx->fs->io;
3048 else
3049 bh->b_io = kdev->k_ctx->journal_io;
3050 bh->b_size = blocksize;
3051 bh->b_blocknr = blocknr;
3052
3053 return bh;
3054}
3055
3056void sync_blockdev(kdev_t kdev)
3057{
3058 io_channel io;
3059
3060 if (kdev->k_dev == K_DEV_FS)
3061 io = kdev->k_ctx->fs->io;
3062 else
3063 io = kdev->k_ctx->journal_io;
3064
3065 io_channel_flush(io);
3066}
3067
3068void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
3069{
3070 int retval;
3071 struct buffer_head *bh;
3072
3073 for (; nr > 0; --nr) {
3074 bh = *bhp++;
3075 if (rw == READ && !bh->b_uptodate) {
3076 jfs_debug(3, "reading block %lu/%p\n",
3077 (unsigned long) bh->b_blocknr, (void *) bh);
3078 retval = io_channel_read_blk(bh->b_io,
3079 bh->b_blocknr,
3080 1, bh->b_data);
3081 if (retval) {
3082 com_err(bh->b_ctx->device_name, retval,
3083 "while reading block %lu\n",
3084 (unsigned long) bh->b_blocknr);
3085 bh->b_err = retval;
3086 continue;
3087 }
3088 bh->b_uptodate = 1;
3089 } else if (rw == WRITE && bh->b_dirty) {
3090 jfs_debug(3, "writing block %lu/%p\n",
3091 (unsigned long) bh->b_blocknr, (void *) bh);
3092 retval = io_channel_write_blk(bh->b_io,
3093 bh->b_blocknr,
3094 1, bh->b_data);
3095 if (retval) {
3096 com_err(bh->b_ctx->device_name, retval,
3097 "while writing block %lu\n",
3098 (unsigned long) bh->b_blocknr);
3099 bh->b_err = retval;
3100 continue;
3101 }
3102 bh->b_dirty = 0;
3103 bh->b_uptodate = 1;
3104 } else {
3105 jfs_debug(3, "no-op %s for block %lu\n",
3106 rw == READ ? "read" : "write",
3107 (unsigned long) bh->b_blocknr);
3108 }
3109 }
3110}
3111
3112void mark_buffer_dirty(struct buffer_head *bh)
3113{
3114 bh->b_dirty = 1;
3115}
3116
3117static void mark_buffer_clean(struct buffer_head * bh)
3118{
3119 bh->b_dirty = 0;
3120}
3121
3122void brelse(struct buffer_head *bh)
3123{
3124 if (bh->b_dirty)
3125 ll_rw_block(WRITE, 1, &bh);
3126 jfs_debug(3, "freeing block %lu/%p (total %d)\n",
3127 (unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
3128 ext2fs_free_mem(&bh);
3129}
3130
3131int buffer_uptodate(struct buffer_head *bh)
3132{
3133 return bh->b_uptodate;
3134}
3135
3136void mark_buffer_uptodate(struct buffer_head *bh, int val)
3137{
3138 bh->b_uptodate = val;
3139}
3140
3141void wait_on_buffer(struct buffer_head *bh)
3142{
3143 if (!bh->b_uptodate)
3144 ll_rw_block(READ, 1, &bh);
3145}
3146
3147
3148static void e2fsck_clear_recover(e2fsck_t ctx, int error)
3149{
3150 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
3151
3152 /* if we had an error doing journal recovery, we need a full fsck */
3153 if (error)
3154 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
3155 ext2fs_mark_super_dirty(ctx->fs);
3156}
3157
3158static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
3159{
3160 struct ext2_super_block *sb = ctx->fs->super;
3161 struct ext2_super_block jsuper;
3162 struct problem_context pctx;
3163 struct buffer_head *bh;
3164 struct inode *j_inode = NULL;
3165 struct kdev_s *dev_fs = NULL, *dev_journal;
3166 const char *journal_name = 0;
3167 journal_t *journal = NULL;
3168 errcode_t retval = 0;
3169 io_manager io_ptr = 0;
3170 unsigned long start = 0;
3171 blk_t blk;
3172 int ext_journal = 0;
3173 int tried_backup_jnl = 0;
3174 int i;
3175
3176 clear_problem_context(&pctx);
3177
3178 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
3179 if (!journal) {
3180 return EXT2_ET_NO_MEMORY;
3181 }
3182
3183 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
3184 if (!dev_fs) {
3185 retval = EXT2_ET_NO_MEMORY;
3186 goto errout;
3187 }
3188 dev_journal = dev_fs+1;
3189
3190 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
3191 dev_fs->k_dev = K_DEV_FS;
3192 dev_journal->k_dev = K_DEV_JOURNAL;
3193
3194 journal->j_dev = dev_journal;
3195 journal->j_fs_dev = dev_fs;
3196 journal->j_inode = NULL;
3197 journal->j_blocksize = ctx->fs->blocksize;
3198
3199 if (uuid_is_null(sb->s_journal_uuid)) {
3200 if (!sb->s_journal_inum)
3201 return EXT2_ET_BAD_INODE_NUM;
3202 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
3203 "journal inode");
3204 if (!j_inode) {
3205 retval = EXT2_ET_NO_MEMORY;
3206 goto errout;
3207 }
3208
3209 j_inode->i_ctx = ctx;
3210 j_inode->i_ino = sb->s_journal_inum;
3211
3212 if ((retval = ext2fs_read_inode(ctx->fs,
3213 sb->s_journal_inum,
3214 &j_inode->i_ext2))) {
3215 try_backup_journal:
3216 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
3217 tried_backup_jnl)
3218 goto errout;
3219 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
3220 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
3221 EXT2_N_BLOCKS*4);
3222 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
3223 j_inode->i_ext2.i_links_count = 1;
3224 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
3225 tried_backup_jnl++;
3226 }
3227 if (!j_inode->i_ext2.i_links_count ||
3228 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
3229 retval = EXT2_ET_NO_JOURNAL;
3230 goto try_backup_journal;
3231 }
3232 if (j_inode->i_ext2.i_size / journal->j_blocksize <
3233 JFS_MIN_JOURNAL_BLOCKS) {
3234 retval = EXT2_ET_JOURNAL_TOO_SMALL;
3235 goto try_backup_journal;
3236 }
3237 for (i=0; i < EXT2_N_BLOCKS; i++) {
3238 blk = j_inode->i_ext2.i_block[i];
3239 if (!blk) {
3240 if (i < EXT2_NDIR_BLOCKS) {
3241 retval = EXT2_ET_JOURNAL_TOO_SMALL;
3242 goto try_backup_journal;
3243 }
3244 continue;
3245 }
3246 if (blk < sb->s_first_data_block ||
3247 blk >= sb->s_blocks_count) {
3248 retval = EXT2_ET_BAD_BLOCK_NUM;
3249 goto try_backup_journal;
3250 }
3251 }
3252 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
3253
3254#ifdef USE_INODE_IO
3255 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
3256 &j_inode->i_ext2,
3257 &journal_name);
3258 if (retval)
3259 goto errout;
3260
3261 io_ptr = inode_io_manager;
3262#else
3263 journal->j_inode = j_inode;
3264 ctx->journal_io = ctx->fs->io;
3265 if ((retval = journal_bmap(journal, 0, &start)) != 0)
3266 goto errout;
36#endif 3267#endif
37#ifdef HAVE_MALLOC_H 3268 } else {
38#include <malloc.h> 3269 ext_journal = 1;
3270 if (!ctx->journal_name) {
3271 char uuid[37];
3272
3273 uuid_unparse(sb->s_journal_uuid, uuid);
3274 ctx->journal_name = blkid_get_devname(ctx->blkid,
3275 "UUID", uuid);
3276 if (!ctx->journal_name)
3277 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
3278 }
3279 journal_name = ctx->journal_name;
3280
3281 if (!journal_name) {
3282 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
3283 return EXT2_ET_LOAD_EXT_JOURNAL;
3284 }
3285
3286 jfs_debug(1, "Using journal file %s\n", journal_name);
3287 io_ptr = unix_io_manager;
3288 }
3289
3290#if 0
3291 test_io_backing_manager = io_ptr;
3292 io_ptr = test_io_manager;
39#endif 3293#endif
40#ifdef HAVE_SYS_TYPES_H 3294#ifndef USE_INODE_IO
41#include <sys/types.h> 3295 if (ext_journal)
42#endif 3296#endif
43#ifdef HAVE_DIRENT_H 3297 retval = io_ptr->open(journal_name, IO_FLAG_RW,
44#include <dirent.h> 3298 &ctx->journal_io);
3299 if (retval)
3300 goto errout;
3301
3302 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
3303
3304 if (ext_journal) {
3305 if (ctx->fs->blocksize == 1024)
3306 start = 1;
3307 bh = getblk(dev_journal, start, ctx->fs->blocksize);
3308 if (!bh) {
3309 retval = EXT2_ET_NO_MEMORY;
3310 goto errout;
3311 }
3312 ll_rw_block(READ, 1, &bh);
3313 if ((retval = bh->b_err) != 0)
3314 goto errout;
3315 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
3316 sizeof(jsuper));
3317 brelse(bh);
3318#ifdef EXT2FS_ENABLE_SWAPFS
3319 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
3320 ext2fs_swap_super(&jsuper);
45#endif 3321#endif
3322 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
3323 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
3324 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
3325 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3326 goto errout;
3327 }
3328 /* Make sure the journal UUID is correct */
3329 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
3330 sizeof(jsuper.s_uuid))) {
3331 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
3332 retval = EXT2_ET_LOAD_EXT_JOURNAL;
3333 goto errout;
3334 }
3335
3336 journal->j_maxlen = jsuper.s_blocks_count;
3337 start++;
3338 }
3339
3340 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
3341 retval = EXT2_ET_NO_MEMORY;
3342 goto errout;
3343 }
3344
3345 journal->j_sb_buffer = bh;
3346 journal->j_superblock = (journal_superblock_t *)bh->b_data;
3347
3348#ifdef USE_INODE_IO
3349 if (j_inode)
3350 ext2fs_free_mem(&j_inode);
3351#endif
3352
3353 *ret_journal = journal;
3354 return 0;
3355
3356errout:
3357 if (dev_fs)
3358 ext2fs_free_mem(&dev_fs);
3359 if (j_inode)
3360 ext2fs_free_mem(&j_inode);
3361 if (journal)
3362 ext2fs_free_mem(&journal);
3363 return retval;
3364
3365}
3366
3367static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
3368 struct problem_context *pctx)
3369{
3370 struct ext2_super_block *sb = ctx->fs->super;
3371 int recover = ctx->fs->super->s_feature_incompat &
3372 EXT3_FEATURE_INCOMPAT_RECOVER;
3373 int has_journal = ctx->fs->super->s_feature_compat &
3374 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3375
3376 if (has_journal || sb->s_journal_inum) {
3377 /* The journal inode is bogus, remove and force full fsck */
3378 pctx->ino = sb->s_journal_inum;
3379 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
3380 if (has_journal && sb->s_journal_inum)
3381 printf("*** ext3 journal has been deleted - "
3382 "filesystem is now ext2 only ***\n\n");
3383 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3384 sb->s_journal_inum = 0;
3385 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
3386 e2fsck_clear_recover(ctx, 1);
3387 return 0;
3388 }
3389 return EXT2_ET_BAD_INODE_NUM;
3390 } else if (recover) {
3391 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
3392 e2fsck_clear_recover(ctx, 1);
3393 return 0;
3394 }
3395 return EXT2_ET_UNSUPP_FEATURE;
3396 }
3397 return 0;
3398}
3399
3400#define V1_SB_SIZE 0x0024
3401static void clear_v2_journal_fields(journal_t *journal)
3402{
3403 e2fsck_t ctx = journal->j_dev->k_ctx;
3404 struct problem_context pctx;
3405
3406 clear_problem_context(&pctx);
3407
3408 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
3409 return;
3410
3411 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
3412 ctx->fs->blocksize-V1_SB_SIZE);
3413 mark_buffer_dirty(journal->j_sb_buffer);
3414}
3415
3416
3417static errcode_t e2fsck_journal_load(journal_t *journal)
3418{
3419 e2fsck_t ctx = journal->j_dev->k_ctx;
3420 journal_superblock_t *jsb;
3421 struct buffer_head *jbh = journal->j_sb_buffer;
3422 struct problem_context pctx;
3423
3424 clear_problem_context(&pctx);
3425
3426 ll_rw_block(READ, 1, &jbh);
3427 if (jbh->b_err) {
3428 com_err(ctx->device_name, jbh->b_err,
3429 _("reading journal superblock\n"));
3430 return jbh->b_err;
3431 }
3432
3433 jsb = journal->j_superblock;
3434 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
3435 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
3436 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3437
3438 switch (ntohl(jsb->s_header.h_blocktype)) {
3439 case JFS_SUPERBLOCK_V1:
3440 journal->j_format_version = 1;
3441 if (jsb->s_feature_compat ||
3442 jsb->s_feature_incompat ||
3443 jsb->s_feature_ro_compat ||
3444 jsb->s_nr_users)
3445 clear_v2_journal_fields(journal);
3446 break;
3447
3448 case JFS_SUPERBLOCK_V2:
3449 journal->j_format_version = 2;
3450 if (ntohl(jsb->s_nr_users) > 1 &&
3451 uuid_is_null(ctx->fs->super->s_journal_uuid))
3452 clear_v2_journal_fields(journal);
3453 if (ntohl(jsb->s_nr_users) > 1) {
3454 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
3455 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3456 }
3457 break;
3458
3459 /*
3460 * These should never appear in a journal super block, so if
3461 * they do, the journal is badly corrupted.
3462 */
3463 case JFS_DESCRIPTOR_BLOCK:
3464 case JFS_COMMIT_BLOCK:
3465 case JFS_REVOKE_BLOCK:
3466 return EXT2_ET_CORRUPT_SUPERBLOCK;
3467
3468 /* If we don't understand the superblock major type, but there
3469 * is a magic number, then it is likely to be a new format we
3470 * just don't understand, so leave it alone. */
3471 default:
3472 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
3473 }
3474
3475 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
3476 return EXT2_ET_UNSUPP_FEATURE;
3477
3478 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
3479 return EXT2_ET_RO_UNSUPP_FEATURE;
3480
3481 /* We have now checked whether we know enough about the journal
3482 * format to be able to proceed safely, so any other checks that
3483 * fail we should attempt to recover from. */
3484 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
3485 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3486 _("%s: no valid journal superblock found\n"),
3487 ctx->device_name);
3488 return EXT2_ET_CORRUPT_SUPERBLOCK;
3489 }
3490
3491 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
3492 journal->j_maxlen = ntohl(jsb->s_maxlen);
3493 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
3494 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
3495 _("%s: journal too short\n"),
3496 ctx->device_name);
3497 return EXT2_ET_CORRUPT_SUPERBLOCK;
3498 }
3499
3500 journal->j_tail_sequence = ntohl(jsb->s_sequence);
3501 journal->j_transaction_sequence = journal->j_tail_sequence;
3502 journal->j_tail = ntohl(jsb->s_start);
3503 journal->j_first = ntohl(jsb->s_first);
3504 journal->j_last = ntohl(jsb->s_maxlen);
3505
3506 return 0;
3507}
3508
3509static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
3510 journal_t *journal)
3511{
3512 char *p;
3513 union {
3514 uuid_t uuid;
3515 __u32 val[4];
3516 } u;
3517 __u32 new_seq = 0;
3518 int i;
3519
3520 /* Leave a valid existing V1 superblock signature alone.
3521 * Anything unrecognisable we overwrite with a new V2
3522 * signature. */
3523
3524 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
3525 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
3526 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
3527 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
3528 }
3529
3530 /* Zero out everything else beyond the superblock header */
3531
3532 p = ((char *) jsb) + sizeof(journal_header_t);
3533 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
3534
3535 jsb->s_blocksize = htonl(ctx->fs->blocksize);
3536 jsb->s_maxlen = htonl(journal->j_maxlen);
3537 jsb->s_first = htonl(1);
3538
3539 /* Initialize the journal sequence number so that there is "no"
3540 * chance we will find old "valid" transactions in the journal.
3541 * This avoids the need to zero the whole journal (slow to do,
3542 * and risky when we are just recovering the filesystem).
3543 */
3544 uuid_generate(u.uuid);
3545 for (i = 0; i < 4; i ++)
3546 new_seq ^= u.val[i];
3547 jsb->s_sequence = htonl(new_seq);
3548
3549 mark_buffer_dirty(journal->j_sb_buffer);
3550 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
3551}
3552
3553static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
3554 journal_t *journal,
3555 struct problem_context *pctx)
3556{
3557 struct ext2_super_block *sb = ctx->fs->super;
3558 int recover = ctx->fs->super->s_feature_incompat &
3559 EXT3_FEATURE_INCOMPAT_RECOVER;
3560
3561 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
3562 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
3563 e2fsck_journal_reset_super(ctx, journal->j_superblock,
3564 journal);
3565 journal->j_transaction_sequence = 1;
3566 e2fsck_clear_recover(ctx, recover);
3567 return 0;
3568 }
3569 return EXT2_ET_CORRUPT_SUPERBLOCK;
3570 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
3571 return EXT2_ET_CORRUPT_SUPERBLOCK;
3572
3573 return 0;
3574}
3575
3576static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
3577 int reset, int drop)
3578{
3579 journal_superblock_t *jsb;
3580
3581 if (drop)
3582 mark_buffer_clean(journal->j_sb_buffer);
3583 else if (!(ctx->options & E2F_OPT_READONLY)) {
3584 jsb = journal->j_superblock;
3585 jsb->s_sequence = htonl(journal->j_transaction_sequence);
3586 if (reset)
3587 jsb->s_start = 0; /* this marks the journal as empty */
3588 mark_buffer_dirty(journal->j_sb_buffer);
3589 }
3590 brelse(journal->j_sb_buffer);
3591
3592 if (ctx->journal_io) {
3593 if (ctx->fs && ctx->fs->io != ctx->journal_io)
3594 io_channel_close(ctx->journal_io);
3595 ctx->journal_io = 0;
3596 }
3597
3598#ifndef USE_INODE_IO
3599 if (journal->j_inode)
3600 ext2fs_free_mem(&journal->j_inode);
3601#endif
3602 if (journal->j_fs_dev)
3603 ext2fs_free_mem(&journal->j_fs_dev);
3604 ext2fs_free_mem(&journal);
3605}
3606
3607/*
3608 * This function makes sure that the superblock fields regarding the
3609 * journal are consistent.
3610 */
3611int e2fsck_check_ext3_journal(e2fsck_t ctx)
3612{
3613 struct ext2_super_block *sb = ctx->fs->super;
3614 journal_t *journal;
3615 int recover = ctx->fs->super->s_feature_incompat &
3616 EXT3_FEATURE_INCOMPAT_RECOVER;
3617 struct problem_context pctx;
3618 problem_t problem;
3619 int reset = 0, force_fsck = 0;
3620 int retval;
3621
3622 /* If we don't have any journal features, don't do anything more */
3623 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
3624 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
3625 uuid_is_null(sb->s_journal_uuid))
3626 return 0;
3627
3628 clear_problem_context(&pctx);
3629 pctx.num = sb->s_journal_inum;
3630
3631 retval = e2fsck_get_journal(ctx, &journal);
3632 if (retval) {
3633 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
3634 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
3635 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
3636 (retval == EXT2_ET_NO_JOURNAL))
3637 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
3638 return retval;
3639 }
3640
3641 retval = e2fsck_journal_load(journal);
3642 if (retval) {
3643 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
3644 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
3645 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
3646 &pctx))) ||
3647 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
3648 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
3649 &pctx))) ||
3650 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
3651 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
3652 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
3653 &pctx);
3654 e2fsck_journal_release(ctx, journal, 0, 1);
3655 return retval;
3656 }
3657
3658 /*
3659 * We want to make the flags consistent here. We will not leave with
3660 * needs_recovery set but has_journal clear. We can't get in a loop
3661 * with -y, -n, or -p, only if a user isn't making up their mind.
3662 */
3663no_has_journal:
3664 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
3665 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
3666 pctx.str = "inode";
3667 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
3668 if (recover &&
3669 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
3670 goto no_has_journal;
3671 /*
3672 * Need a full fsck if we are releasing a
3673 * journal stored on a reserved inode.
3674 */
3675 force_fsck = recover ||
3676 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
3677 /* Clear all of the journal fields */
3678 sb->s_journal_inum = 0;
3679 sb->s_journal_dev = 0;
3680 memset(sb->s_journal_uuid, 0,
3681 sizeof(sb->s_journal_uuid));
3682 e2fsck_clear_recover(ctx, force_fsck);
3683 } else if (!(ctx->options & E2F_OPT_READONLY)) {
3684 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3685 ext2fs_mark_super_dirty(ctx->fs);
3686 }
3687 }
3688
3689 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
3690 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
3691 journal->j_superblock->s_start != 0) {
3692 /* Print status information */
3693 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
3694 if (ctx->superblock)
3695 problem = PR_0_JOURNAL_RUN_DEFAULT;
3696 else
3697 problem = PR_0_JOURNAL_RUN;
3698 if (fix_problem(ctx, problem, &pctx)) {
3699 ctx->options |= E2F_OPT_FORCE;
3700 sb->s_feature_incompat |=
3701 EXT3_FEATURE_INCOMPAT_RECOVER;
3702 ext2fs_mark_super_dirty(ctx->fs);
3703 } else if (fix_problem(ctx,
3704 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
3705 reset = 1;
3706 sb->s_state &= ~EXT2_VALID_FS;
3707 ext2fs_mark_super_dirty(ctx->fs);
3708 }
3709 /*
3710 * If the user answers no to the above question, we
3711 * ignore the fact that journal apparently has data;
3712 * accidentally replaying over valid data would be far
3713 * worse than skipping a questionable recovery.
3714 *
3715 * XXX should we abort with a fatal error here? What
3716 * will the ext3 kernel code do if a filesystem with
3717 * !NEEDS_RECOVERY but with a non-zero
3718 * journal->j_superblock->s_start is mounted?
3719 */
3720 }
3721
3722 e2fsck_journal_release(ctx, journal, reset, 0);
3723 return retval;
3724}
3725
3726static errcode_t recover_ext3_journal(e2fsck_t ctx)
3727{
3728 journal_t *journal;
3729 int retval;
3730
3731 journal_init_revoke_caches();
3732 retval = e2fsck_get_journal(ctx, &journal);
3733 if (retval)
3734 return retval;
3735
3736 retval = e2fsck_journal_load(journal);
3737 if (retval)
3738 goto errout;
3739
3740 retval = journal_init_revoke(journal, 1024);
3741 if (retval)
3742 goto errout;
3743
3744 retval = -journal_recover(journal);
3745 if (retval)
3746 goto errout;
3747
3748 if (journal->j_superblock->s_errno) {
3749 ctx->fs->super->s_state |= EXT2_ERROR_FS;
3750 ext2fs_mark_super_dirty(ctx->fs);
3751 journal->j_superblock->s_errno = 0;
3752 mark_buffer_dirty(journal->j_sb_buffer);
3753 }
3754
3755errout:
3756 journal_destroy_revoke(journal);
3757 journal_destroy_revoke_caches();
3758 e2fsck_journal_release(ctx, journal, 1, 0);
3759 return retval;
3760}
3761
3762int e2fsck_run_ext3_journal(e2fsck_t ctx)
3763{
3764 io_manager io_ptr = ctx->fs->io->manager;
3765 int blocksize = ctx->fs->blocksize;
3766 errcode_t retval, recover_retval;
3767
3768 printf(_("%s: recovering journal\n"), ctx->device_name);
3769 if (ctx->options & E2F_OPT_READONLY) {
3770 printf(_("%s: won't do journal recovery while read-only\n"),
3771 ctx->device_name);
3772 return EXT2_ET_FILE_RO;
3773 }
3774
3775 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
3776 ext2fs_flush(ctx->fs); /* Force out any modifications */
3777
3778 recover_retval = recover_ext3_journal(ctx);
3779
3780 /*
3781 * Reload the filesystem context to get up-to-date data from disk
3782 * because journal recovery will change the filesystem under us.
3783 */
3784 ext2fs_close(ctx->fs);
3785 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
3786 ctx->superblock, blocksize, io_ptr,
3787 &ctx->fs);
3788
3789 if (retval) {
3790 com_err(ctx->program_name, retval,
3791 _("while trying to re-open %s"),
3792 ctx->device_name);
3793 fatal_error(ctx, 0);
3794 }
3795 ctx->fs->priv_data = ctx;
3796
3797 /* Set the superblock flags */
3798 e2fsck_clear_recover(ctx, recover_retval);
3799 return recover_retval;
3800}
3801
3802/*
3803 * This function will move the journal inode from a visible file in
3804 * the filesystem directory hierarchy to the reserved inode if necessary.
3805 */
3806static const char * const journal_names[] = {
3807 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
3808
3809void e2fsck_move_ext3_journal(e2fsck_t ctx)
3810{
3811 struct ext2_super_block *sb = ctx->fs->super;
3812 struct problem_context pctx;
3813 struct ext2_inode inode;
3814 ext2_filsys fs = ctx->fs;
3815 ext2_ino_t ino;
3816 errcode_t retval;
3817 const char * const * cpp;
3818 int group, mount_flags;
3819
3820 clear_problem_context(&pctx);
3821
3822 /*
3823 * If the filesystem is opened read-only, or there is no
3824 * journal, then do nothing.
3825 */
3826 if ((ctx->options & E2F_OPT_READONLY) ||
3827 (sb->s_journal_inum == 0) ||
3828 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
3829 return;
3830
3831 /*
3832 * Read in the journal inode
3833 */
3834 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
3835 return;
3836
3837 /*
3838 * If it's necessary to backup the journal inode, do so.
3839 */
3840 if ((sb->s_jnl_backup_type == 0) ||
3841 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
3842 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
3843 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
3844 memcpy(sb->s_jnl_blocks, inode.i_block,
3845 EXT2_N_BLOCKS*4);
3846 sb->s_jnl_blocks[16] = inode.i_size;
3847 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
3848 ext2fs_mark_super_dirty(fs);
3849 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3850 }
3851 }
3852
3853 /*
3854 * If the journal is already the hidden inode, then do nothing
3855 */
3856 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
3857 return;
3858
3859 /*
3860 * The journal inode had better have only one link and not be readable.
3861 */
3862 if (inode.i_links_count != 1)
3863 return;
3864
3865 /*
3866 * If the filesystem is mounted, or we can't tell whether
3867 * or not it's mounted, do nothing.
3868 */
3869 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
3870 if (retval || (mount_flags & EXT2_MF_MOUNTED))
3871 return;
3872
3873 /*
3874 * If we can't find the name of the journal inode, then do
3875 * nothing.
3876 */
3877 for (cpp = journal_names; *cpp; cpp++) {
3878 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
3879 strlen(*cpp), 0, &ino);
3880 if ((retval == 0) && (ino == sb->s_journal_inum))
3881 break;
3882 }
3883 if (*cpp == 0)
3884 return;
3885
3886 /* We need the inode bitmap to be loaded */
3887 retval = ext2fs_read_bitmaps(fs);
3888 if (retval)
3889 return;
3890
3891 pctx.str = *cpp;
3892 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
3893 return;
3894
3895 /*
3896 * OK, we've done all the checks, let's actually move the
3897 * journal inode. Errors at this point mean we need to force
3898 * an ext2 filesystem check.
3899 */
3900 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
3901 goto err_out;
3902 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
3903 goto err_out;
3904 sb->s_journal_inum = EXT2_JOURNAL_INO;
3905 ext2fs_mark_super_dirty(fs);
3906 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3907 inode.i_links_count = 0;
3908 inode.i_dtime = time(0);
3909 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
3910 goto err_out;
3911
3912 group = ext2fs_group_of_ino(fs, ino);
3913 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
3914 ext2fs_mark_ib_dirty(fs);
3915 fs->group_desc[group].bg_free_inodes_count++;
3916 fs->super->s_free_inodes_count++;
3917 return;
3918
3919err_out:
3920 pctx.errcode = retval;
3921 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
3922 fs->super->s_state &= ~EXT2_VALID_FS;
3923 ext2fs_mark_super_dirty(fs);
3924 return;
3925}
3926
3927/*
3928 * message.c --- print e2fsck messages (with compression)
3929 *
3930 * Copyright 1996, 1997 by Theodore Ts'o
3931 *
3932 * %Begin-Header%
3933 * This file may be redistributed under the terms of the GNU Public
3934 * License.
3935 * %End-Header%
3936 *
3937 * print_e2fsck_message() prints a message to the user, using
3938 * compression techniques and expansions of abbreviations.
3939 *
3940 * The following % expansions are supported:
3941 *
3942 * %b <blk> block number
3943 * %B <blkcount> integer
3944 * %c <blk2> block number
3945 * %Di <dirent>->ino inode number
3946 * %Dn <dirent>->name string
3947 * %Dr <dirent>->rec_len
3948 * %Dl <dirent>->name_len
3949 * %Dt <dirent>->filetype
3950 * %d <dir> inode number
3951 * %g <group> integer
3952 * %i <ino> inode number
3953 * %Is <inode> -> i_size
3954 * %IS <inode> -> i_extra_isize
3955 * %Ib <inode> -> i_blocks
3956 * %Il <inode> -> i_links_count
3957 * %Im <inode> -> i_mode
3958 * %IM <inode> -> i_mtime
3959 * %IF <inode> -> i_faddr
3960 * %If <inode> -> i_file_acl
3961 * %Id <inode> -> i_dir_acl
3962 * %Iu <inode> -> i_uid
3963 * %Ig <inode> -> i_gid
3964 * %j <ino2> inode number
3965 * %m <com_err error message>
3966 * %N <num>
3967 * %p ext2fs_get_pathname of directory <ino>
3968 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
3969 * the containing directory. (If dirent is NULL
3970 * then return the pathname of directory <ino2>)
3971 * %q ext2fs_get_pathname of directory <dir>
3972 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
3973 * the containing directory.
3974 * %s <str> miscellaneous string
3975 * %S backup superblock
3976 * %X <num> hexadecimal format
3977 *
3978 * The following '@' expansions are supported:
3979 *
3980 * @a extended attribute
3981 * @A error allocating
3982 * @b block
3983 * @B bitmap
3984 * @c compress
3985 * @C conflicts with some other fs block
3986 * @D deleted
3987 * @d directory
3988 * @e entry
3989 * @E Entry '%Dn' in %p (%i)
3990 * @f filesystem
3991 * @F for @i %i (%Q) is
3992 * @g group
3993 * @h HTREE directory inode
3994 * @i inode
3995 * @I illegal
3996 * @j journal
3997 * @l lost+found
3998 * @L is a link
3999 * @o orphaned
4000 * @p problem in
4001 * @r root inode
4002 * @s should be
4003 * @S superblock
4004 * @u unattached
4005 * @v device
4006 * @z zero-length
4007 */
4008
4009
4010/*
4011 * This structure defines the abbreviations used by the text strings
4012 * below. The first character in the string is the index letter. An
4013 * abbreviation of the form '@<i>' is expanded by looking up the index
4014 * letter <i> in the table below.
4015 */
4016static const char *abbrevs[] = {
4017 N_("aextended attribute"),
4018 N_("Aerror allocating"),
4019 N_("bblock"),
4020 N_("Bbitmap"),
4021 N_("ccompress"),
4022 N_("Cconflicts with some other fs @b"),
4023 N_("iinode"),
4024 N_("Iillegal"),
4025 N_("jjournal"),
4026 N_("Ddeleted"),
4027 N_("ddirectory"),
4028 N_("eentry"),
4029 N_("E@e '%Dn' in %p (%i)"),
4030 N_("ffilesystem"),
4031 N_("Ffor @i %i (%Q) is"),
4032 N_("ggroup"),
4033 N_("hHTREE @d @i"),
4034 N_("llost+found"),
4035 N_("Lis a link"),
4036 N_("oorphaned"),
4037 N_("pproblem in"),
4038 N_("rroot @i"),
4039 N_("sshould be"),
4040 N_("Ssuper@b"),
4041 N_("uunattached"),
4042 N_("vdevice"),
4043 N_("zzero-length"),
4044 "@@",
4045 0
4046 };
4047
4048/*
4049 * Give more user friendly names to the "special" inodes.
4050 */
4051#define num_special_inodes 11
4052static const char *special_inode_name[] =
4053{
4054 N_("<The NULL inode>"), /* 0 */
4055 N_("<The bad blocks inode>"), /* 1 */
4056 "/", /* 2 */
4057 N_("<The ACL index inode>"), /* 3 */
4058 N_("<The ACL data inode>"), /* 4 */
4059 N_("<The boot loader inode>"), /* 5 */
4060 N_("<The undelete directory inode>"), /* 6 */
4061 N_("<The group descriptor inode>"), /* 7 */
4062 N_("<The journal inode>"), /* 8 */
4063 N_("<Reserved inode 9>"), /* 9 */
4064 N_("<Reserved inode 10>"), /* 10 */
4065};
4066
4067/*
4068 * This function does "safe" printing. It will convert non-printable
4069 * ASCII characters using '^' and M- notation.
4070 */
4071static void safe_print(const char *cp, int len)
4072{
4073 unsigned char ch;
4074
4075 if (len < 0)
4076 len = strlen(cp);
4077
4078 while (len--) {
4079 ch = *cp++;
4080 if (ch > 128) {
4081 fputs("M-", stdout);
4082 ch -= 128;
4083 }
4084 if ((ch < 32) || (ch == 0x7f)) {
4085 fputc('^', stdout);
4086 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
4087 }
4088 fputc(ch, stdout);
4089 }
4090}
4091
4092
4093/*
4094 * This function prints a pathname, using the ext2fs_get_pathname
4095 * function
4096 */
4097static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
4098{
4099 errcode_t retval;
4100 char *path;
4101
4102 if (!dir && (ino < num_special_inodes)) {
4103 fputs(_(special_inode_name[ino]), stdout);
4104 return;
4105 }
4106
4107 retval = ext2fs_get_pathname(fs, dir, ino, &path);
4108 if (retval)
4109 fputs("???", stdout);
4110 else {
4111 safe_print(path, -1);
4112 ext2fs_free_mem(&path);
4113 }
4114}
4115
4116/*
4117 * This function handles the '@' expansion. We allow recursive
4118 * expansion; an @ expression can contain further '@' and '%'
4119 * expressions.
4120 */
4121static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
4122 struct problem_context *pctx,
4123 int *first)
4124{
4125 const char **cpp, *str;
4126
4127 /* Search for the abbreviation */
4128 for (cpp = abbrevs; *cpp; cpp++) {
4129 if (ch == *cpp[0])
4130 break;
4131 }
4132 if (*cpp) {
4133 str = _(*cpp) + 1;
4134 if (*first && islower(*str)) {
4135 *first = 0;
4136 fputc(toupper(*str++), stdout);
4137 }
4138 print_e2fsck_message(ctx, str, pctx, *first);
4139 } else
4140 printf("@%c", ch);
4141}
4142
4143/*
4144 * This function expands '%IX' expressions
4145 */
4146static _INLINE_ void expand_inode_expression(char ch,
4147 struct problem_context *ctx)
4148{
4149 struct ext2_inode *inode;
4150 struct ext2_inode_large *large_inode;
4151 char * time_str;
4152 time_t t;
4153 int do_gmt = -1;
4154
4155 if (!ctx || !ctx->inode)
4156 goto no_inode;
4157
4158 inode = ctx->inode;
4159 large_inode = (struct ext2_inode_large *) inode;
4160
4161 switch (ch) {
4162 case 's':
4163 if (LINUX_S_ISDIR(inode->i_mode))
4164 printf("%u", inode->i_size);
4165 else {
4166#ifdef EXT2_NO_64_TYPE
4167 if (inode->i_size_high)
4168 printf("0x%x%08x", inode->i_size_high,
4169 inode->i_size);
4170 else
4171 printf("%u", inode->i_size);
4172#else
4173 printf("%llu", (inode->i_size |
4174 ((__u64) inode->i_size_high << 32)));
4175#endif
4176 }
4177 break;
4178 case 'S':
4179 printf("%u", large_inode->i_extra_isize);
4180 break;
4181 case 'b':
4182 printf("%u", inode->i_blocks);
4183 break;
4184 case 'l':
4185 printf("%d", inode->i_links_count);
4186 break;
4187 case 'm':
4188 printf("0%o", inode->i_mode);
4189 break;
4190 case 'M':
4191 /* The diet libc doesn't respect the TZ environemnt variable */
4192 if (do_gmt == -1) {
4193 time_str = getenv("TZ");
4194 if (!time_str)
4195 time_str = "";
4196 do_gmt = !strcmp(time_str, "GMT");
4197 }
4198 t = inode->i_mtime;
4199 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
4200 printf("%.24s", time_str);
4201 break;
4202 case 'F':
4203 printf("%u", inode->i_faddr);
4204 break;
4205 case 'f':
4206 printf("%u", inode->i_file_acl);
4207 break;
4208 case 'd':
4209 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
4210 inode->i_dir_acl : 0));
4211 break;
4212 case 'u':
4213 printf("%d", (inode->i_uid |
4214 (inode->osd2.linux2.l_i_uid_high << 16)));
4215 break;
4216 case 'g':
4217 printf("%d", (inode->i_gid |
4218 (inode->osd2.linux2.l_i_gid_high << 16)));
4219 break;
4220 default:
4221 no_inode:
4222 printf("%%I%c", ch);
4223 break;
4224 }
4225}
4226
4227/*
4228 * This function expands '%dX' expressions
4229 */
4230static _INLINE_ void expand_dirent_expression(char ch,
4231 struct problem_context *ctx)
4232{
4233 struct ext2_dir_entry *dirent;
4234 int len;
4235
4236 if (!ctx || !ctx->dirent)
4237 goto no_dirent;
4238
4239 dirent = ctx->dirent;
4240
4241 switch (ch) {
4242 case 'i':
4243 printf("%u", dirent->inode);
4244 break;
4245 case 'n':
4246 len = dirent->name_len & 0xFF;
4247 if (len > EXT2_NAME_LEN)
4248 len = EXT2_NAME_LEN;
4249 if (len > dirent->rec_len)
4250 len = dirent->rec_len;
4251 safe_print(dirent->name, len);
4252 break;
4253 case 'r':
4254 printf("%u", dirent->rec_len);
4255 break;
4256 case 'l':
4257 printf("%u", dirent->name_len & 0xFF);
4258 break;
4259 case 't':
4260 printf("%u", dirent->name_len >> 8);
4261 break;
4262 default:
4263 no_dirent:
4264 printf("%%D%c", ch);
4265 break;
4266 }
4267}
4268
4269static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
4270 struct problem_context *ctx)
4271{
4272 if (!ctx)
4273 goto no_context;
4274
4275 switch (ch) {
4276 case '%':
4277 fputc('%', stdout);
4278 break;
4279 case 'b':
4280 printf("%u", ctx->blk);
4281 break;
4282 case 'B':
4283#ifdef EXT2_NO_64_TYPE
4284 printf("%d", ctx->blkcount);
4285#else
4286 printf("%lld", ctx->blkcount);
4287#endif
4288 break;
4289 case 'c':
4290 printf("%u", ctx->blk2);
4291 break;
4292 case 'd':
4293 printf("%u", ctx->dir);
4294 break;
4295 case 'g':
4296 printf("%d", ctx->group);
4297 break;
4298 case 'i':
4299 printf("%u", ctx->ino);
4300 break;
4301 case 'j':
4302 printf("%u", ctx->ino2);
4303 break;
4304 case 'm':
4305 printf("%s", error_message(ctx->errcode));
4306 break;
4307 case 'N':
4308#ifdef EXT2_NO_64_TYPE
4309 printf("%u", ctx->num);
4310#else
4311 printf("%llu", ctx->num);
4312#endif
4313 break;
4314 case 'p':
4315 print_pathname(fs, ctx->ino, 0);
4316 break;
4317 case 'P':
4318 print_pathname(fs, ctx->ino2,
4319 ctx->dirent ? ctx->dirent->inode : 0);
4320 break;
4321 case 'q':
4322 print_pathname(fs, ctx->dir, 0);
4323 break;
4324 case 'Q':
4325 print_pathname(fs, ctx->dir, ctx->ino);
4326 break;
4327 case 'S':
4328 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
4329 break;
4330 case 's':
4331 printf("%s", ctx->str ? ctx->str : "NULL");
4332 break;
4333 case 'X':
4334#ifdef EXT2_NO_64_TYPE
4335 printf("0x%x", ctx->num);
4336#else
4337 printf("0x%llx", ctx->num);
4338#endif
4339 break;
4340 default:
4341 no_context:
4342 printf("%%%c", ch);
4343 break;
4344 }
4345}
4346
4347void print_e2fsck_message(e2fsck_t ctx, const char *msg,
4348 struct problem_context *pctx, int first)
4349{
4350 ext2_filsys fs = ctx->fs;
4351 const char * cp;
4352 int i;
4353
4354 e2fsck_clear_progbar(ctx);
4355 for (cp = msg; *cp; cp++) {
4356 if (cp[0] == '@') {
4357 cp++;
4358 expand_at_expression(ctx, *cp, pctx, &first);
4359 } else if (cp[0] == '%' && cp[1] == 'I') {
4360 cp += 2;
4361 expand_inode_expression(*cp, pctx);
4362 } else if (cp[0] == '%' && cp[1] == 'D') {
4363 cp += 2;
4364 expand_dirent_expression(*cp, pctx);
4365 } else if ((cp[0] == '%')) {
4366 cp++;
4367 expand_percent_expression(fs, *cp, pctx);
4368 } else {
4369 for (i=0; cp[i]; i++)
4370 if ((cp[i] == '@') || cp[i] == '%')
4371 break;
4372 printf("%.*s", i, cp);
4373 cp += i-1;
4374 }
4375 first = 0;
4376 }
4377}
4378/*
4379 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
4380 *
4381 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
4382 *
4383 * %Begin-Header%
4384 * This file may be redistributed under the terms of the GNU Public
4385 * License.
4386 * %End-Header%
4387 *
4388 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
4389 * and applies the following tests to each inode:
4390 *
4391 * - The mode field of the inode must be legal.
4392 * - The size and block count fields of the inode are correct.
4393 * - A data block must not be used by another inode
4394 *
4395 * Pass 1 also gathers the collects the following information:
4396 *
4397 * - A bitmap of which inodes are in use. (inode_used_map)
4398 * - A bitmap of which inodes are directories. (inode_dir_map)
4399 * - A bitmap of which inodes are regular files. (inode_reg_map)
4400 * - A bitmap of which inodes have bad fields. (inode_bad_map)
4401 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
4402 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
4403 * - A bitmap of which blocks are in use. (block_found_map)
4404 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
4405 * - The data blocks of the directory inodes. (dir_map)
4406 *
4407 * Pass 1 is designed to stash away enough information so that the
4408 * other passes should not need to read in the inode information
4409 * during the normal course of a filesystem check. (Althogh if an
4410 * inconsistency is detected, other passes may need to read in an
4411 * inode to fix it.)
4412 *
4413 * Note that pass 1B will be invoked if there are any duplicate blocks
4414 * found.
4415 */
4416
4417
4418static int process_block(ext2_filsys fs, blk_t *blocknr,
4419 e2_blkcnt_t blockcnt, blk_t ref_blk,
4420 int ref_offset, void *priv_data);
4421static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
4422 e2_blkcnt_t blockcnt, blk_t ref_blk,
4423 int ref_offset, void *priv_data);
4424static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
4425 char *block_buf);
4426static void mark_table_blocks(e2fsck_t ctx);
4427static void alloc_bb_map(e2fsck_t ctx);
4428static void alloc_imagic_map(e2fsck_t ctx);
4429static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
4430static void handle_fs_bad_blocks(e2fsck_t ctx);
4431static void process_inodes(e2fsck_t ctx, char *block_buf);
4432static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
4433static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
4434 dgrp_t group, void * priv_data);
4435static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
4436 char *block_buf, int adjust_sign);
4437/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
4438
4439static void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
4440 struct ext2_inode * inode, int bufsize,
4441 const char *proc);
4442
4443struct process_block_struct_1 {
4444 ext2_ino_t ino;
4445 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
4446 fragmented:1, compressed:1, bbcheck:1;
4447 blk_t num_blocks;
4448 blk_t max_blocks;
4449 e2_blkcnt_t last_block;
4450 int num_illegal_blocks;
4451 blk_t previous_block;
4452 struct ext2_inode *inode;
4453 struct problem_context *pctx;
4454 ext2fs_block_bitmap fs_meta_blocks;
4455 e2fsck_t ctx;
4456};
4457
4458struct process_inode_block {
4459 ext2_ino_t ino;
4460 struct ext2_inode inode;
4461};
4462
4463struct scan_callback_struct {
4464 e2fsck_t ctx;
4465 char *block_buf;
4466};
4467
4468/*
4469 * For the inodes to process list.
4470 */
4471static struct process_inode_block *inodes_to_process;
4472static int process_inode_count;
4473
4474static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
4475 EXT2_MIN_BLOCK_LOG_SIZE + 1];
4476
4477/*
4478 * Free all memory allocated by pass1 in preparation for restarting
4479 * things.
4480 */
4481static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused)))
4482{
4483 ext2fs_free_mem(&inodes_to_process);
4484 inodes_to_process = 0;
4485}
4486
4487/*
4488 * Check to make sure a device inode is real. Returns 1 if the device
4489 * checks out, 0 if not.
4490 *
4491 * Note: this routine is now also used to check FIFO's and Sockets,
4492 * since they have the same requirement; the i_block fields should be
4493 * zero.
4494 */
4495int e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
4496{
4497 int i;
4498
4499 /*
4500 * If i_blocks is non-zero, or the index flag is set, then
4501 * this is a bogus device/fifo/socket
4502 */
4503 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
4504 (inode->i_flags & EXT2_INDEX_FL))
4505 return 0;
4506
4507 /*
4508 * We should be able to do the test below all the time, but
4509 * because the kernel doesn't forcibly clear the device
4510 * inode's additional i_block fields, there are some rare
4511 * occasions when a legitimate device inode will have non-zero
4512 * additional i_block fields. So for now, we only complain
4513 * when the immutable flag is set, which should never happen
4514 * for devices. (And that's when the problem is caused, since
4515 * you can't set or clear immutable flags for devices.) Once
4516 * the kernel has been fixed we can change this...
4517 */
4518 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
4519 for (i=4; i < EXT2_N_BLOCKS; i++)
4520 if (inode->i_block[i])
4521 return 0;
4522 }
4523 return 1;
4524}
4525
4526/*
4527 * Check to make sure a symlink inode is real. Returns 1 if the symlink
4528 * checks out, 0 if not.
4529 */
4530int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode,
4531 char *buf)
4532{
4533 unsigned int len;
4534 int i;
4535 blk_t blocks;
4536
4537 if ((inode->i_size_high || inode->i_size == 0) ||
4538 (inode->i_flags & EXT2_INDEX_FL))
4539 return 0;
4540
4541 blocks = ext2fs_inode_data_blocks(fs, inode);
4542 if (blocks) {
4543 if ((inode->i_size >= fs->blocksize) ||
4544 (blocks != fs->blocksize >> 9) ||
4545 (inode->i_block[0] < fs->super->s_first_data_block) ||
4546 (inode->i_block[0] >= fs->super->s_blocks_count))
4547 return 0;
4548
4549 for (i = 1; i < EXT2_N_BLOCKS; i++)
4550 if (inode->i_block[i])
4551 return 0;
4552
4553 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
4554 return 0;
4555
4556 len = strnlen(buf, fs->blocksize);
4557 if (len == fs->blocksize)
4558 return 0;
4559 } else {
4560 if (inode->i_size >= sizeof(inode->i_block))
4561 return 0;
4562
4563 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
4564 if (len == sizeof(inode->i_block))
4565 return 0;
4566 }
4567 if (len != inode->i_size)
4568 return 0;
4569 return 1;
4570}
4571
4572/*
4573 * If the immutable (or append-only) flag is set on the inode, offer
4574 * to clear it.
4575 */
4576#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
4577static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
4578{
4579 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
4580 return;
4581
4582 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
4583 return;
4584
4585 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
4586 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4587}
4588
4589/*
4590 * If device, fifo or socket, check size is zero -- if not offer to
4591 * clear it
4592 */
4593static void check_size(e2fsck_t ctx, struct problem_context *pctx)
4594{
4595 struct ext2_inode *inode = pctx->inode;
4596
4597 if ((inode->i_size == 0) && (inode->i_size_high == 0))
4598 return;
4599
4600 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
4601 return;
4602
4603 inode->i_size = 0;
4604 inode->i_size_high = 0;
4605 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
4606}
4607
4608static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
4609{
4610 struct ext2_super_block *sb = ctx->fs->super;
4611 struct ext2_inode_large *inode;
4612 struct ext2_ext_attr_entry *entry;
4613 char *start, *end;
4614 int storage_size, remain, offs;
4615 int problem = 0;
4616
4617 inode = (struct ext2_inode_large *) pctx->inode;
4618 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
4619 inode->i_extra_isize;
4620 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4621 inode->i_extra_isize + sizeof(__u32);
4622 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
4623 entry = (struct ext2_ext_attr_entry *) start;
4624
4625 /* scan all entry's headers first */
4626
4627 /* take finish entry 0UL into account */
4628 remain = storage_size - sizeof(__u32);
4629 offs = end - start;
4630
4631 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
4632
4633 /* header eats this space */
4634 remain -= sizeof(struct ext2_ext_attr_entry);
4635
4636 /* is attribute name valid? */
4637 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
4638 pctx->num = entry->e_name_len;
4639 problem = PR_1_ATTR_NAME_LEN;
4640 goto fix;
4641 }
4642
4643 /* attribute len eats this space */
4644 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
4645
4646 /* check value size */
4647 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
4648 pctx->num = entry->e_value_size;
4649 problem = PR_1_ATTR_VALUE_SIZE;
4650 goto fix;
4651 }
4652
4653 /* check value placement */
4654 if (entry->e_value_offs +
4655 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
4656 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
4657 pctx->num = entry->e_value_offs;
4658 problem = PR_1_ATTR_VALUE_OFFSET;
4659 goto fix;
4660 }
4661
4662 /* e_value_block must be 0 in inode's ea */
4663 if (entry->e_value_block != 0) {
4664 pctx->num = entry->e_value_block;
4665 problem = PR_1_ATTR_VALUE_BLOCK;
4666 goto fix;
4667 }
4668
4669 /* e_hash must be 0 in inode's ea */
4670 if (entry->e_hash != 0) {
4671 pctx->num = entry->e_hash;
4672 problem = PR_1_ATTR_HASH;
4673 goto fix;
4674 }
4675
4676 remain -= entry->e_value_size;
4677 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
4678
4679 entry = EXT2_EXT_ATTR_NEXT(entry);
4680 }
4681fix:
4682 /*
4683 * it seems like a corruption. it's very unlikely we could repair
4684 * EA(s) in automatic fashion -bzzz
4685 */
4686#if 0
4687 problem = PR_1_ATTR_HASH;
4688#endif
4689 if (problem == 0 || !fix_problem(ctx, problem, pctx))
4690 return;
4691
4692 /* simple remove all possible EA(s) */
4693 *((__u32 *)start) = 0UL;
4694 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
4695 EXT2_INODE_SIZE(sb), "pass1");
4696}
4697
4698static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
4699{
4700 struct ext2_super_block *sb = ctx->fs->super;
4701 struct ext2_inode_large *inode;
4702 __u32 *eamagic;
4703 int min, max;
4704
4705 inode = (struct ext2_inode_large *) pctx->inode;
4706 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
4707 /* this isn't large inode. so, nothing to check */
4708 return;
4709 }
4710
4711#if 0
4712 printf("inode #%u, i_extra_size %d\n", pctx->ino,
4713 inode->i_extra_isize);
4714#endif
4715 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
4716 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
4717 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
4718 /*
4719 * For now we will allow i_extra_isize to be 0, but really
4720 * implementations should never allow i_extra_isize to be 0
4721 */
4722 if (inode->i_extra_isize &&
4723 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
4724 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
4725 return;
4726 inode->i_extra_isize = min;
4727 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
4728 EXT2_INODE_SIZE(sb), "pass1");
4729 return;
4730 }
4731
4732 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
4733 inode->i_extra_isize);
4734 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
4735 /* it seems inode has an extended attribute(s) in body */
4736 check_ea_in_inode(ctx, pctx);
4737 }
4738}
4739
4740void e2fsck_pass1(e2fsck_t ctx)
4741{
4742 int i;
4743 __u64 max_sizes;
4744 ext2_filsys fs = ctx->fs;
4745 ext2_ino_t ino;
4746 struct ext2_inode *inode;
4747 ext2_inode_scan scan;
4748 char *block_buf;
4749#ifdef RESOURCE_TRACK
4750 struct resource_track rtrack;
4751#endif
4752 unsigned char frag, fsize;
4753 struct problem_context pctx;
4754 struct scan_callback_struct scan_struct;
4755 struct ext2_super_block *sb = ctx->fs->super;
4756 int imagic_fs;
4757 int busted_fs_time = 0;
4758 int inode_size;
4759
4760#ifdef RESOURCE_TRACK
4761 init_resource_track(&rtrack);
4762#endif
4763 clear_problem_context(&pctx);
4764
4765 if (!(ctx->options & E2F_OPT_PREEN))
4766 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
4767
4768 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
4769 !(ctx->options & E2F_OPT_NO)) {
4770 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
4771 ctx->dirs_to_hash = 0;
4772 }
4773
4774#ifdef MTRACE
4775 mtrace_print("Pass 1");
4776#endif
4777
4778#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
4779
4780 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
4781 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
4782 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
4783 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
4784 max_sizes = (max_sizes * (1UL << i)) - 1;
4785 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
4786 }
4787#undef EXT2_BPP
4788
4789 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
4790
4791 /*
4792 * Allocate bitmaps structures
4793 */
4794 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
4795 &ctx->inode_used_map);
4796 if (pctx.errcode) {
4797 pctx.num = 1;
4798 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4799 ctx->flags |= E2F_FLAG_ABORT;
4800 return;
4801 }
4802 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4803 _("directory inode map"), &ctx->inode_dir_map);
4804 if (pctx.errcode) {
4805 pctx.num = 2;
4806 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4807 ctx->flags |= E2F_FLAG_ABORT;
4808 return;
4809 }
4810 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
4811 _("regular file inode map"), &ctx->inode_reg_map);
4812 if (pctx.errcode) {
4813 pctx.num = 6;
4814 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
4815 ctx->flags |= E2F_FLAG_ABORT;
4816 return;
4817 }
4818 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
4819 &ctx->block_found_map);
4820 if (pctx.errcode) {
4821 pctx.num = 1;
4822 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4823 ctx->flags |= E2F_FLAG_ABORT;
4824 return;
4825 }
4826 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
4827 &ctx->inode_link_info);
4828 if (pctx.errcode) {
4829 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
4830 ctx->flags |= E2F_FLAG_ABORT;
4831 return;
4832 }
4833 inode_size = EXT2_INODE_SIZE(fs->super);
4834 inode = (struct ext2_inode *)
4835 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
4836
4837 inodes_to_process = (struct process_inode_block *)
4838 e2fsck_allocate_memory(ctx,
4839 (ctx->process_inode_size *
4840 sizeof(struct process_inode_block)),
4841 "array of inodes to process");
4842 process_inode_count = 0;
4843
4844 pctx.errcode = ext2fs_init_dblist(fs, 0);
4845 if (pctx.errcode) {
4846 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
4847 ctx->flags |= E2F_FLAG_ABORT;
4848 return;
4849 }
4850
4851 /*
4852 * If the last orphan field is set, clear it, since the pass1
4853 * processing will automatically find and clear the orphans.
4854 * In the future, we may want to try using the last_orphan
4855 * linked list ourselves, but for now, we clear it so that the
4856 * ext3 mount code won't get confused.
4857 */
4858 if (!(ctx->options & E2F_OPT_READONLY)) {
4859 if (fs->super->s_last_orphan) {
4860 fs->super->s_last_orphan = 0;
4861 ext2fs_mark_super_dirty(fs);
4862 }
4863 }
4864
4865 mark_table_blocks(ctx);
4866 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
4867 "block interate buffer");
4868 e2fsck_use_inode_shortcuts(ctx, 1);
4869 ehandler_operation(_("doing inode scan"));
4870 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
4871 &scan);
4872 if (pctx.errcode) {
4873 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4874 ctx->flags |= E2F_FLAG_ABORT;
4875 return;
4876 }
4877 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
4878 ctx->stashed_inode = inode;
4879 scan_struct.ctx = ctx;
4880 scan_struct.block_buf = block_buf;
4881 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
4882 if (ctx->progress)
4883 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
4884 return;
4885 if (fs->super->s_wtime < fs->super->s_inodes_count)
4886 busted_fs_time = 1;
4887
4888 while (1) {
4889 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
4890 inode, inode_size);
4891 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
4892 return;
4893 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
4894 if (!ctx->inode_bb_map)
4895 alloc_bb_map(ctx);
4896 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
4897 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4898 continue;
4899 }
4900 if (pctx.errcode) {
4901 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
4902 ctx->flags |= E2F_FLAG_ABORT;
4903 return;
4904 }
4905 if (!ino)
4906 break;
4907 pctx.ino = ino;
4908 pctx.inode = inode;
4909 ctx->stashed_ino = ino;
4910 if (inode->i_links_count) {
4911 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
4912 ino, inode->i_links_count);
4913 if (pctx.errcode) {
4914 pctx.num = inode->i_links_count;
4915 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
4916 ctx->flags |= E2F_FLAG_ABORT;
4917 return;
4918 }
4919 }
4920 if (ino == EXT2_BAD_INO) {
4921 struct process_block_struct_1 pb;
4922
4923 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
4924 &pb.fs_meta_blocks);
4925 if (pctx.errcode) {
4926 pctx.num = 4;
4927 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
4928 ctx->flags |= E2F_FLAG_ABORT;
4929 return;
4930 }
4931 pb.ino = EXT2_BAD_INO;
4932 pb.num_blocks = pb.last_block = 0;
4933 pb.num_illegal_blocks = 0;
4934 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
4935 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
4936 pb.inode = inode;
4937 pb.pctx = &pctx;
4938 pb.ctx = ctx;
4939 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
4940 block_buf, process_bad_block, &pb);
4941 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
4942 if (pctx.errcode) {
4943 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
4944 ctx->flags |= E2F_FLAG_ABORT;
4945 return;
4946 }
4947 if (pb.bbcheck)
4948 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
4949 ctx->flags |= E2F_FLAG_ABORT;
4950 return;
4951 }
4952 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4953 clear_problem_context(&pctx);
4954 continue;
4955 } else if (ino == EXT2_ROOT_INO) {
4956 /*
4957 * Make sure the root inode is a directory; if
4958 * not, offer to clear it. It will be
4959 * regnerated in pass #3.
4960 */
4961 if (!LINUX_S_ISDIR(inode->i_mode)) {
4962 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
4963 inode->i_dtime = time(0);
4964 inode->i_links_count = 0;
4965 ext2fs_icount_store(ctx->inode_link_info,
4966 ino, 0);
4967 e2fsck_write_inode(ctx, ino, inode,
4968 "pass1");
4969 }
4970
4971 }
4972 /*
4973 * If dtime is set, offer to clear it. mke2fs
4974 * version 0.2b created filesystems with the
4975 * dtime field set for the root and lost+found
4976 * directories. We won't worry about
4977 * /lost+found, since that can be regenerated
4978 * easily. But we will fix the root directory
4979 * as a special case.
4980 */
4981 if (inode->i_dtime && inode->i_links_count) {
4982 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
4983 inode->i_dtime = 0;
4984 e2fsck_write_inode(ctx, ino, inode,
4985 "pass1");
4986 }
4987 }
4988 } else if (ino == EXT2_JOURNAL_INO) {
4989 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
4990 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
4991 if (!LINUX_S_ISREG(inode->i_mode) &&
4992 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
4993 &pctx)) {
4994 inode->i_mode = LINUX_S_IFREG;
4995 e2fsck_write_inode(ctx, ino, inode,
4996 "pass1");
4997 }
4998 check_blocks(ctx, &pctx, block_buf);
4999 continue;
5000 }
5001 if ((inode->i_links_count || inode->i_blocks ||
5002 inode->i_blocks || inode->i_block[0]) &&
5003 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
5004 &pctx)) {
5005 memset(inode, 0, inode_size);
5006 ext2fs_icount_store(ctx->inode_link_info,
5007 ino, 0);
5008 e2fsck_write_inode_full(ctx, ino, inode,
5009 inode_size, "pass1");
5010 }
5011 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
5012 int problem = 0;
5013
5014 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
5015 if (ino == EXT2_BOOT_LOADER_INO) {
5016 if (LINUX_S_ISDIR(inode->i_mode))
5017 problem = PR_1_RESERVED_BAD_MODE;
5018 } else if (ino == EXT2_RESIZE_INO) {
5019 if (inode->i_mode &&
5020 !LINUX_S_ISREG(inode->i_mode))
5021 problem = PR_1_RESERVED_BAD_MODE;
5022 } else {
5023 if (inode->i_mode != 0)
5024 problem = PR_1_RESERVED_BAD_MODE;
5025 }
5026 if (problem) {
5027 if (fix_problem(ctx, problem, &pctx)) {
5028 inode->i_mode = 0;
5029 e2fsck_write_inode(ctx, ino, inode,
5030 "pass1");
5031 }
5032 }
5033 check_blocks(ctx, &pctx, block_buf);
5034 continue;
5035 }
5036 /*
5037 * Check for inodes who might have been part of the
5038 * orphaned list linked list. They should have gotten
5039 * dealt with by now, unless the list had somehow been
5040 * corrupted.
5041 *
5042 * FIXME: In the future, inodes which are still in use
5043 * (and which are therefore) pending truncation should
5044 * be handled specially. Right now we just clear the
5045 * dtime field, and the normal e2fsck handling of
5046 * inodes where i_size and the inode blocks are
5047 * inconsistent is to fix i_size, instead of releasing
5048 * the extra blocks. This won't catch the inodes that
5049 * was at the end of the orphan list, but it's better
5050 * than nothing. The right answer is that there
5051 * shouldn't be any bugs in the orphan list handling. :-)
5052 */
5053 if (inode->i_dtime && !busted_fs_time &&
5054 inode->i_dtime < ctx->fs->super->s_inodes_count) {
5055 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
5056 inode->i_dtime = inode->i_links_count ?
5057 0 : time(0);
5058 e2fsck_write_inode(ctx, ino, inode,
5059 "pass1");
5060 }
5061 }
5062
5063 /*
5064 * This code assumes that deleted inodes have
5065 * i_links_count set to 0.
5066 */
5067 if (!inode->i_links_count) {
5068 if (!inode->i_dtime && inode->i_mode) {
5069 if (fix_problem(ctx,
5070 PR_1_ZERO_DTIME, &pctx)) {
5071 inode->i_dtime = time(0);
5072 e2fsck_write_inode(ctx, ino, inode,
5073 "pass1");
5074 }
5075 }
5076 continue;
5077 }
5078 /*
5079 * n.b. 0.3c ext2fs code didn't clear i_links_count for
5080 * deleted files. Oops.
5081 *
5082 * Since all new ext2 implementations get this right,
5083 * we now assume that the case of non-zero
5084 * i_links_count and non-zero dtime means that we
5085 * should keep the file, not delete it.
5086 *
5087 */
5088 if (inode->i_dtime) {
5089 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
5090 inode->i_dtime = 0;
5091 e2fsck_write_inode(ctx, ino, inode, "pass1");
5092 }
5093 }
5094
5095 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
5096 switch (fs->super->s_creator_os) {
5097 case EXT2_OS_LINUX:
5098 frag = inode->osd2.linux2.l_i_frag;
5099 fsize = inode->osd2.linux2.l_i_fsize;
5100 break;
5101 case EXT2_OS_HURD:
5102 frag = inode->osd2.hurd2.h_i_frag;
5103 fsize = inode->osd2.hurd2.h_i_fsize;
5104 break;
5105 case EXT2_OS_MASIX:
5106 frag = inode->osd2.masix2.m_i_frag;
5107 fsize = inode->osd2.masix2.m_i_fsize;
5108 break;
5109 default:
5110 frag = fsize = 0;
5111 }
5112
5113 if (inode->i_faddr || frag || fsize ||
5114 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
5115 mark_inode_bad(ctx, ino);
5116 if (inode->i_flags & EXT2_IMAGIC_FL) {
5117 if (imagic_fs) {
5118 if (!ctx->inode_imagic_map)
5119 alloc_imagic_map(ctx);
5120 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
5121 ino);
5122 } else {
5123 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
5124 inode->i_flags &= ~EXT2_IMAGIC_FL;
5125 e2fsck_write_inode(ctx, ino,
5126 inode, "pass1");
5127 }
5128 }
5129 }
5130
5131 check_inode_extra_space(ctx, &pctx);
5132
5133 if (LINUX_S_ISDIR(inode->i_mode)) {
5134 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
5135 e2fsck_add_dir_info(ctx, ino, 0);
5136 ctx->fs_directory_count++;
5137 } else if (LINUX_S_ISREG (inode->i_mode)) {
5138 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
5139 ctx->fs_regular_count++;
5140 } else if (LINUX_S_ISCHR (inode->i_mode) &&
5141 e2fsck_pass1_check_device_inode(fs, inode)) {
5142 check_immutable(ctx, &pctx);
5143 check_size(ctx, &pctx);
5144 ctx->fs_chardev_count++;
5145 } else if (LINUX_S_ISBLK (inode->i_mode) &&
5146 e2fsck_pass1_check_device_inode(fs, inode)) {
5147 check_immutable(ctx, &pctx);
5148 check_size(ctx, &pctx);
5149 ctx->fs_blockdev_count++;
5150 } else if (LINUX_S_ISLNK (inode->i_mode) &&
5151 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
5152 check_immutable(ctx, &pctx);
5153 ctx->fs_symlinks_count++;
5154 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
5155 ctx->fs_fast_symlinks_count++;
5156 check_blocks(ctx, &pctx, block_buf);
5157 continue;
5158 }
5159 }
5160 else if (LINUX_S_ISFIFO (inode->i_mode) &&
5161 e2fsck_pass1_check_device_inode(fs, inode)) {
5162 check_immutable(ctx, &pctx);
5163 check_size(ctx, &pctx);
5164 ctx->fs_fifo_count++;
5165 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
5166 e2fsck_pass1_check_device_inode(fs, inode)) {
5167 check_immutable(ctx, &pctx);
5168 check_size(ctx, &pctx);
5169 ctx->fs_sockets_count++;
5170 } else
5171 mark_inode_bad(ctx, ino);
5172 if (inode->i_block[EXT2_IND_BLOCK])
5173 ctx->fs_ind_count++;
5174 if (inode->i_block[EXT2_DIND_BLOCK])
5175 ctx->fs_dind_count++;
5176 if (inode->i_block[EXT2_TIND_BLOCK])
5177 ctx->fs_tind_count++;
5178 if (inode->i_block[EXT2_IND_BLOCK] ||
5179 inode->i_block[EXT2_DIND_BLOCK] ||
5180 inode->i_block[EXT2_TIND_BLOCK] ||
5181 inode->i_file_acl) {
5182 inodes_to_process[process_inode_count].ino = ino;
5183 inodes_to_process[process_inode_count].inode = *inode;
5184 process_inode_count++;
5185 } else
5186 check_blocks(ctx, &pctx, block_buf);
5187
5188 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5189 return;
5190
5191 if (process_inode_count >= ctx->process_inode_size) {
5192 process_inodes(ctx, block_buf);
5193
5194 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5195 return;
5196 }
5197 }
5198 process_inodes(ctx, block_buf);
5199 ext2fs_close_inode_scan(scan);
5200 ehandler_operation(0);
5201
5202 /*
5203 * If any extended attribute blocks' reference counts need to
5204 * be adjusted, either up (ctx->refcount_extra), or down
5205 * (ctx->refcount), then fix them.
5206 */
5207 if (ctx->refcount) {
5208 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
5209 ea_refcount_free(ctx->refcount);
5210 ctx->refcount = 0;
5211 }
5212 if (ctx->refcount_extra) {
5213 adjust_extattr_refcount(ctx, ctx->refcount_extra,
5214 block_buf, +1);
5215 ea_refcount_free(ctx->refcount_extra);
5216 ctx->refcount_extra = 0;
5217 }
5218
5219 if (ctx->invalid_bitmaps)
5220 handle_fs_bad_blocks(ctx);
5221
5222 /* We don't need the block_ea_map any more */
5223 if (ctx->block_ea_map) {
5224 ext2fs_free_block_bitmap(ctx->block_ea_map);
5225 ctx->block_ea_map = 0;
5226 }
5227
5228 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
5229 ext2fs_block_bitmap save_bmap;
5230
5231 save_bmap = fs->block_map;
5232 fs->block_map = ctx->block_found_map;
5233 clear_problem_context(&pctx);
5234 pctx.errcode = ext2fs_create_resize_inode(fs);
5235 if (pctx.errcode) {
5236 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
5237 /* Should never get here */
5238 ctx->flags |= E2F_FLAG_ABORT;
5239 return;
5240 }
5241 fs->block_map = save_bmap;
5242 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
5243 }
5244
5245 if (ctx->flags & E2F_FLAG_RESTART) {
5246 /*
5247 * Only the master copy of the superblock and block
5248 * group descriptors are going to be written during a
5249 * restart, so set the superblock to be used to be the
5250 * master superblock.
5251 */
5252 ctx->use_superblock = 0;
5253 unwind_pass1(fs);
5254 goto endit;
5255 }
5256
5257 if (ctx->block_dup_map) {
5258 if (ctx->options & E2F_OPT_PREEN) {
5259 clear_problem_context(&pctx);
5260 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
5261 }
5262 e2fsck_pass1_dupblocks(ctx, block_buf);
5263 }
5264 ext2fs_free_mem(&inodes_to_process);
5265endit:
5266 e2fsck_use_inode_shortcuts(ctx, 0);
5267
5268 ext2fs_free_mem(&block_buf);
5269 ext2fs_free_mem(&inode);
5270
5271#ifdef RESOURCE_TRACK
5272 if (ctx->options & E2F_OPT_TIME2) {
5273 e2fsck_clear_progbar(ctx);
5274 print_resource_track(_("Pass 1"), &rtrack);
5275 }
5276#endif
5277}
5278
5279/*
5280 * When the inode_scan routines call this callback at the end of the
5281 * glock group, call process_inodes.
5282 */
5283static errcode_t scan_callback(ext2_filsys fs,
5284 ext2_inode_scan scan EXT2FS_ATTR((unused)),
5285 dgrp_t group, void * priv_data)
5286{
5287 struct scan_callback_struct *scan_struct;
5288 e2fsck_t ctx;
5289
5290 scan_struct = (struct scan_callback_struct *) priv_data;
5291 ctx = scan_struct->ctx;
5292
5293 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
5294
5295 if (ctx->progress)
5296 if ((ctx->progress)(ctx, 1, group+1,
5297 ctx->fs->group_desc_count))
5298 return EXT2_ET_CANCEL_REQUESTED;
5299
5300 return 0;
5301}
5302
5303/*
5304 * Process the inodes in the "inodes to process" list.
5305 */
5306static void process_inodes(e2fsck_t ctx, char *block_buf)
5307{
5308 int i;
5309 struct ext2_inode *old_stashed_inode;
5310 ext2_ino_t old_stashed_ino;
5311 const char *old_operation;
5312 char buf[80];
5313 struct problem_context pctx;
5314
5315#if 0
5316 printf("begin process_inodes: ");
5317#endif
5318 if (process_inode_count == 0)
5319 return;
5320 old_operation = ehandler_operation(0);
5321 old_stashed_inode = ctx->stashed_inode;
5322 old_stashed_ino = ctx->stashed_ino;
5323 qsort(inodes_to_process, process_inode_count,
5324 sizeof(struct process_inode_block), process_inode_cmp);
5325 clear_problem_context(&pctx);
5326 for (i=0; i < process_inode_count; i++) {
5327 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
5328 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
5329
5330#if 0
5331 printf("%u ", pctx.ino);
5332#endif
5333 sprintf(buf, _("reading indirect blocks of inode %u"),
5334 pctx.ino);
5335 ehandler_operation(buf);
5336 check_blocks(ctx, &pctx, block_buf);
5337 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5338 break;
5339 }
5340 ctx->stashed_inode = old_stashed_inode;
5341 ctx->stashed_ino = old_stashed_ino;
5342 process_inode_count = 0;
5343#if 0
5344 printf("end process inodes\n");
5345#endif
5346 ehandler_operation(old_operation);
5347}
5348
5349static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
5350{
5351 const struct process_inode_block *ib_a =
5352 (const struct process_inode_block *) a;
5353 const struct process_inode_block *ib_b =
5354 (const struct process_inode_block *) b;
5355 int ret;
5356
5357 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
5358 ib_b->inode.i_block[EXT2_IND_BLOCK]);
5359 if (ret == 0)
5360 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
5361 return ret;
5362}
5363
5364/*
5365 * Mark an inode as being bad in some what
5366 */
5367static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
5368{
5369 struct problem_context pctx;
5370
5371 if (!ctx->inode_bad_map) {
5372 clear_problem_context(&pctx);
5373
5374 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5375 _("bad inode map"), &ctx->inode_bad_map);
5376 if (pctx.errcode) {
5377 pctx.num = 3;
5378 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5379 /* Should never get here */
5380 ctx->flags |= E2F_FLAG_ABORT;
5381 return;
5382 }
5383 }
5384 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
5385}
5386
5387
5388/*
5389 * This procedure will allocate the inode "bb" (badblock) map table
5390 */
5391static void alloc_bb_map(e2fsck_t ctx)
5392{
5393 struct problem_context pctx;
5394
5395 clear_problem_context(&pctx);
5396 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5397 _("inode in bad block map"),
5398 &ctx->inode_bb_map);
5399 if (pctx.errcode) {
5400 pctx.num = 4;
5401 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5402 /* Should never get here */
5403 ctx->flags |= E2F_FLAG_ABORT;
5404 return;
5405 }
5406}
5407
5408/*
5409 * This procedure will allocate the inode imagic table
5410 */
5411static void alloc_imagic_map(e2fsck_t ctx)
5412{
5413 struct problem_context pctx;
5414
5415 clear_problem_context(&pctx);
5416 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
5417 _("imagic inode map"),
5418 &ctx->inode_imagic_map);
5419 if (pctx.errcode) {
5420 pctx.num = 5;
5421 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
5422 /* Should never get here */
5423 ctx->flags |= E2F_FLAG_ABORT;
5424 return;
5425 }
5426}
5427
5428/*
5429 * Marks a block as in use, setting the dup_map if it's been set
5430 * already. Called by process_block and process_bad_block.
5431 *
5432 * WARNING: Assumes checks have already been done to make sure block
5433 * is valid. This is true in both process_block and process_bad_block.
5434 */
5435static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
5436{
5437 struct problem_context pctx;
5438
5439 clear_problem_context(&pctx);
5440
5441 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
5442 if (!ctx->block_dup_map) {
5443 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
5444 _("multiply claimed block map"),
5445 &ctx->block_dup_map);
5446 if (pctx.errcode) {
5447 pctx.num = 3;
5448 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
5449 &pctx);
5450 /* Should never get here */
5451 ctx->flags |= E2F_FLAG_ABORT;
5452 return;
5453 }
5454 }
5455 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
5456 } else {
5457 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
5458 }
5459}
5460
5461/*
5462 * Adjust the extended attribute block's reference counts at the end
5463 * of pass 1, either by subtracting out references for EA blocks that
5464 * are still referenced in ctx->refcount, or by adding references for
5465 * EA blocks that had extra references as accounted for in
5466 * ctx->refcount_extra.
5467 */
5468static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
5469 char *block_buf, int adjust_sign)
5470{
5471 struct ext2_ext_attr_header *header;
5472 struct problem_context pctx;
5473 ext2_filsys fs = ctx->fs;
5474 blk_t blk;
5475 __u32 should_be;
5476 int count;
5477
5478 clear_problem_context(&pctx);
5479
5480 ea_refcount_intr_begin(refcount);
5481 while (1) {
5482 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
5483 break;
5484 pctx.blk = blk;
5485 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5486 if (pctx.errcode) {
5487 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
5488 return;
5489 }
5490 header = (struct ext2_ext_attr_header *) block_buf;
5491 pctx.blkcount = header->h_refcount;
5492 should_be = header->h_refcount + adjust_sign * count;
5493 pctx.num = should_be;
5494 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
5495 header->h_refcount = should_be;
5496 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
5497 block_buf);
5498 if (pctx.errcode) {
5499 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
5500 continue;
5501 }
5502 }
5503 }
5504}
5505
5506/*
5507 * Handle processing the extended attribute blocks
5508 */
5509static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
5510 char *block_buf)
5511{
5512 ext2_filsys fs = ctx->fs;
5513 ext2_ino_t ino = pctx->ino;
5514 struct ext2_inode *inode = pctx->inode;
5515 blk_t blk;
5516 char * end;
5517 struct ext2_ext_attr_header *header;
5518 struct ext2_ext_attr_entry *entry;
5519 int count;
5520 region_t region;
5521
5522 blk = inode->i_file_acl;
5523 if (blk == 0)
5524 return 0;
5525
5526 /*
5527 * If the Extended attribute flag isn't set, then a non-zero
5528 * file acl means that the inode is corrupted.
5529 *
5530 * Or if the extended attribute block is an invalid block,
5531 * then the inode is also corrupted.
5532 */
5533 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
5534 (blk < fs->super->s_first_data_block) ||
5535 (blk >= fs->super->s_blocks_count)) {
5536 mark_inode_bad(ctx, ino);
5537 return 0;
5538 }
5539
5540 /* If ea bitmap hasn't been allocated, create it */
5541 if (!ctx->block_ea_map) {
5542 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
5543 _("ext attr block map"),
5544 &ctx->block_ea_map);
5545 if (pctx->errcode) {
5546 pctx->num = 2;
5547 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
5548 ctx->flags |= E2F_FLAG_ABORT;
5549 return 0;
5550 }
5551 }
5552
5553 /* Create the EA refcount structure if necessary */
5554 if (!ctx->refcount) {
5555 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
5556 if (pctx->errcode) {
5557 pctx->num = 1;
5558 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5559 ctx->flags |= E2F_FLAG_ABORT;
5560 return 0;
5561 }
5562 }
5563
5564#if 0
5565 /* Debugging text */
5566 printf("Inode %u has EA block %u\n", ino, blk);
5567#endif
5568
5569 /* Have we seen this EA block before? */
5570 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
5571 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
5572 return 1;
5573 /* Ooops, this EA was referenced more than it stated */
5574 if (!ctx->refcount_extra) {
5575 pctx->errcode = ea_refcount_create(0,
5576 &ctx->refcount_extra);
5577 if (pctx->errcode) {
5578 pctx->num = 2;
5579 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
5580 ctx->flags |= E2F_FLAG_ABORT;
5581 return 0;
5582 }
5583 }
5584 ea_refcount_increment(ctx->refcount_extra, blk, 0);
5585 return 1;
5586 }
5587
5588 /*
5589 * OK, we haven't seen this EA block yet. So we need to
5590 * validate it
5591 */
5592 pctx->blk = blk;
5593 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
5594 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
5595 goto clear_extattr;
5596 header = (struct ext2_ext_attr_header *) block_buf;
5597 pctx->blk = inode->i_file_acl;
5598 if (((ctx->ext_attr_ver == 1) &&
5599 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
5600 ((ctx->ext_attr_ver == 2) &&
5601 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
5602 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
5603 goto clear_extattr;
5604 }
5605
5606 if (header->h_blocks != 1) {
5607 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
5608 goto clear_extattr;
5609 }
5610
5611 region = region_create(0, fs->blocksize);
5612 if (!region) {
5613 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
5614 ctx->flags |= E2F_FLAG_ABORT;
5615 return 0;
5616 }
5617 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
5618 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5619 goto clear_extattr;
5620 }
5621
5622 entry = (struct ext2_ext_attr_entry *)(header+1);
5623 end = block_buf + fs->blocksize;
5624 while ((char *)entry < end && *(__u32 *)entry) {
5625 if (region_allocate(region, (char *)entry - (char *)header,
5626 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
5627 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5628 goto clear_extattr;
5629 }
5630 if ((ctx->ext_attr_ver == 1 &&
5631 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
5632 (ctx->ext_attr_ver == 2 &&
5633 entry->e_name_index == 0)) {
5634 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
5635 goto clear_extattr;
5636 }
5637 if (entry->e_value_block != 0) {
5638 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
5639 goto clear_extattr;
5640 }
5641 if (entry->e_value_size &&
5642 region_allocate(region, entry->e_value_offs,
5643 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
5644 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5645 goto clear_extattr;
5646 }
5647 entry = EXT2_EXT_ATTR_NEXT(entry);
5648 }
5649 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
5650 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
5651 goto clear_extattr;
5652 }
5653 region_free(region);
5654
5655 count = header->h_refcount - 1;
5656 if (count)
5657 ea_refcount_store(ctx->refcount, blk, count);
5658 mark_block_used(ctx, blk);
5659 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
5660
5661 return 1;
5662
5663clear_extattr:
5664 inode->i_file_acl = 0;
5665 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
5666 return 0;
5667}
5668
5669/* Returns 1 if bad htree, 0 if OK */
5670static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
5671 ext2_ino_t ino EXT2FS_ATTR((unused)),
5672 struct ext2_inode *inode,
5673 char *block_buf)
5674{
5675 struct ext2_dx_root_info *root;
5676 ext2_filsys fs = ctx->fs;
5677 errcode_t retval;
5678 blk_t blk;
5679
5680 if ((!LINUX_S_ISDIR(inode->i_mode) &&
5681 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
5682 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
5683 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
5684 return 1;
5685
5686 blk = inode->i_block[0];
5687 if (((blk == 0) ||
5688 (blk < fs->super->s_first_data_block) ||
5689 (blk >= fs->super->s_blocks_count)) &&
5690 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5691 return 1;
5692
5693 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
5694 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5695 return 1;
5696
5697 /* XXX should check that beginning matches a directory */
5698 root = (struct ext2_dx_root_info *) (block_buf + 24);
5699
5700 if ((root->reserved_zero || root->info_length < 8) &&
5701 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
5702 return 1;
5703
5704 pctx->num = root->hash_version;
5705 if ((root->hash_version != EXT2_HASH_LEGACY) &&
5706 (root->hash_version != EXT2_HASH_HALF_MD4) &&
5707 (root->hash_version != EXT2_HASH_TEA) &&
5708 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
5709 return 1;
5710
5711 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
5712 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
5713 return 1;
5714
5715 pctx->num = root->indirect_levels;
5716 if ((root->indirect_levels > 1) &&
5717 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
5718 return 1;
5719
5720 return 0;
5721}
5722
5723/*
5724 * This subroutine is called on each inode to account for all of the
5725 * blocks used by that inode.
5726 */
5727static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
5728 char *block_buf)
5729{
5730 ext2_filsys fs = ctx->fs;
5731 struct process_block_struct_1 pb;
5732 ext2_ino_t ino = pctx->ino;
5733 struct ext2_inode *inode = pctx->inode;
5734 int bad_size = 0;
5735 int dirty_inode = 0;
5736 __u64 size;
5737
5738 pb.ino = ino;
5739 pb.num_blocks = 0;
5740 pb.last_block = -1;
5741 pb.num_illegal_blocks = 0;
5742 pb.suppress = 0; pb.clear = 0;
5743 pb.fragmented = 0;
5744 pb.compressed = 0;
5745 pb.previous_block = 0;
5746 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
5747 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
5748 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
5749 pb.inode = inode;
5750 pb.pctx = pctx;
5751 pb.ctx = ctx;
5752 pctx->ino = ino;
5753 pctx->errcode = 0;
5754
5755 if (inode->i_flags & EXT2_COMPRBLK_FL) {
5756 if (fs->super->s_feature_incompat &
5757 EXT2_FEATURE_INCOMPAT_COMPRESSION)
5758 pb.compressed = 1;
5759 else {
5760 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
5761 inode->i_flags &= ~EXT2_COMPRBLK_FL;
5762 dirty_inode++;
5763 }
5764 }
5765 }
5766
5767 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
5768 pb.num_blocks++;
5769
5770 if (ext2fs_inode_has_valid_blocks(inode))
5771 pctx->errcode = ext2fs_block_iterate2(fs, ino,
5772 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
5773 block_buf, process_block, &pb);
5774 end_problem_latch(ctx, PR_LATCH_BLOCK);
5775 end_problem_latch(ctx, PR_LATCH_TOOBIG);
5776 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
5777 goto out;
5778 if (pctx->errcode)
5779 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
5780
5781 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
5782 ctx->fs_fragmented++;
5783
5784 if (pb.clear) {
5785 inode->i_links_count = 0;
5786 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5787 inode->i_dtime = time(0);
5788 dirty_inode++;
5789 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5790 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5791 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5792 /*
5793 * The inode was probably partially accounted for
5794 * before processing was aborted, so we need to
5795 * restart the pass 1 scan.
5796 */
5797 ctx->flags |= E2F_FLAG_RESTART;
5798 goto out;
5799 }
5800
5801 if (inode->i_flags & EXT2_INDEX_FL) {
5802 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
5803 inode->i_flags &= ~EXT2_INDEX_FL;
5804 dirty_inode++;
5805 } else {
5806#ifdef ENABLE_HTREE
5807 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
5808#endif
5809 }
5810 }
5811 if (ctx->dirs_to_hash && pb.is_dir &&
5812 !(inode->i_flags & EXT2_INDEX_FL) &&
5813 ((inode->i_size / fs->blocksize) >= 3))
5814 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
5815
5816 if (!pb.num_blocks && pb.is_dir) {
5817 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
5818 inode->i_links_count = 0;
5819 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
5820 inode->i_dtime = time(0);
5821 dirty_inode++;
5822 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
5823 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
5824 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
5825 ctx->fs_directory_count--;
5826 goto out;
5827 }
5828 }
5829
5830 pb.num_blocks *= (fs->blocksize / 512);
5831#if 0
5832 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
5833 ino, inode->i_size, pb.last_block, inode->i_blocks,
5834 pb.num_blocks);
5835#endif
5836 if (pb.is_dir) {
5837 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
5838 if (nblock > (pb.last_block + 1))
5839 bad_size = 1;
5840 else if (nblock < (pb.last_block + 1)) {
5841 if (((pb.last_block + 1) - nblock) >
5842 fs->super->s_prealloc_dir_blocks)
5843 bad_size = 2;
5844 }
5845 } else {
5846 size = EXT2_I_SIZE(inode);
5847 if ((pb.last_block >= 0) &&
5848 (size < (__u64) pb.last_block * fs->blocksize))
5849 bad_size = 3;
5850 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
5851 bad_size = 4;
5852 }
5853 /* i_size for symlinks is checked elsewhere */
5854 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
5855 pctx->num = (pb.last_block+1) * fs->blocksize;
5856 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
5857 inode->i_size = pctx->num;
5858 if (!LINUX_S_ISDIR(inode->i_mode))
5859 inode->i_size_high = pctx->num >> 32;
5860 dirty_inode++;
5861 }
5862 pctx->num = 0;
5863 }
5864 if (LINUX_S_ISREG(inode->i_mode) &&
5865 (inode->i_size_high || inode->i_size & 0x80000000UL))
5866 ctx->large_files++;
5867 if (pb.num_blocks != inode->i_blocks) {
5868 pctx->num = pb.num_blocks;
5869 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
5870 inode->i_blocks = pb.num_blocks;
5871 dirty_inode++;
5872 }
5873 pctx->num = 0;
5874 }
5875out:
5876 if (dirty_inode)
5877 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
5878}
5879
5880#if 0
5881/*
5882 * Helper function called by process block when an illegal block is
5883 * found. It returns a description about why the block is illegal
5884 */
5885static char *describe_illegal_block(ext2_filsys fs, blk_t block)
5886{
5887 blk_t super;
5888 int i;
5889 static char problem[80];
5890
5891 super = fs->super->s_first_data_block;
5892 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
5893 if (block < super) {
5894 sprintf(problem, "< FIRSTBLOCK (%u)", super);
5895 return(problem);
5896 } else if (block >= fs->super->s_blocks_count) {
5897 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
5898 return(problem);
5899 }
5900 for (i = 0; i < fs->group_desc_count; i++) {
5901 if (block == super) {
5902 sprintf(problem, "is the superblock in group %d", i);
5903 break;
5904 }
5905 if (block > super &&
5906 block <= (super + fs->desc_blocks)) {
5907 sprintf(problem, "is in the group descriptors "
5908 "of group %d", i);
5909 break;
5910 }
5911 if (block == fs->group_desc[i].bg_block_bitmap) {
5912 sprintf(problem, "is the block bitmap of group %d", i);
5913 break;
5914 }
5915 if (block == fs->group_desc[i].bg_inode_bitmap) {
5916 sprintf(problem, "is the inode bitmap of group %d", i);
5917 break;
5918 }
5919 if (block >= fs->group_desc[i].bg_inode_table &&
5920 (block < fs->group_desc[i].bg_inode_table
5921 + fs->inode_blocks_per_group)) {
5922 sprintf(problem, "is in the inode table of group %d",
5923 i);
5924 break;
5925 }
5926 super += fs->super->s_blocks_per_group;
5927 }
5928 return(problem);
5929}
5930#endif
5931
5932/*
5933 * This is a helper function for check_blocks().
5934 */
5935static int process_block(ext2_filsys fs,
5936 blk_t *block_nr,
5937 e2_blkcnt_t blockcnt,
5938 blk_t ref_block EXT2FS_ATTR((unused)),
5939 int ref_offset EXT2FS_ATTR((unused)),
5940 void *priv_data)
5941{
5942 struct process_block_struct_1 *p;
5943 struct problem_context *pctx;
5944 blk_t blk = *block_nr;
5945 int ret_code = 0;
5946 int problem = 0;
5947 e2fsck_t ctx;
5948
5949 p = (struct process_block_struct_1 *) priv_data;
5950 pctx = p->pctx;
5951 ctx = p->ctx;
5952
5953 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
5954 /* todo: Check that the comprblk_fl is high, that the
5955 blkaddr pattern looks right (all non-holes up to
5956 first EXT2FS_COMPRESSED_BLKADDR, then all
5957 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
5958 that the feature_incompat bit is high, and that the
5959 inode is a regular file. If we're doing a "full
5960 check" (a concept introduced to e2fsck by e2compr,
5961 meaning that we look at data blocks as well as
5962 metadata) then call some library routine that
5963 checks the compressed data. I'll have to think
5964 about this, because one particularly important
5965 problem to be able to fix is to recalculate the
5966 cluster size if necessary. I think that perhaps
5967 we'd better do most/all e2compr-specific checks
5968 separately, after the non-e2compr checks. If not
5969 doing a full check, it may be useful to test that
5970 the personality is linux; e.g. if it isn't then
5971 perhaps this really is just an illegal block. */
5972 return 0;
5973 }
5974
5975 if (blk == 0) {
5976 if (p->is_dir == 0) {
5977 /*
5978 * Should never happen, since only directories
5979 * get called with BLOCK_FLAG_HOLE
5980 */
5981#if DEBUG_E2FSCK
5982 printf("process_block() called with blk == 0, "
5983 "blockcnt=%d, inode %lu???\n",
5984 blockcnt, p->ino);
5985#endif
5986 return 0;
5987 }
5988 if (blockcnt < 0)
5989 return 0;
5990 if (blockcnt * fs->blocksize < p->inode->i_size) {
5991#if 0
5992 printf("Missing block (#%d) in directory inode %lu!\n",
5993 blockcnt, p->ino);
5994#endif
5995 goto mark_dir;
5996 }
5997 return 0;
5998 }
5999
6000#if 0
6001 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
6002 blockcnt);
6003#endif
6004
6005 /*
6006 * Simplistic fragmentation check. We merely require that the
6007 * file be contiguous. (Which can never be true for really
6008 * big files that are greater than a block group.)
6009 */
6010 if (!HOLE_BLKADDR(p->previous_block)) {
6011 if (p->previous_block+1 != blk)
6012 p->fragmented = 1;
6013 }
6014 p->previous_block = blk;
6015
6016 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
6017 problem = PR_1_TOOBIG_DIR;
6018 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
6019 problem = PR_1_TOOBIG_REG;
6020 if (!p->is_dir && !p->is_reg && blockcnt > 0)
6021 problem = PR_1_TOOBIG_SYMLINK;
6022
6023 if (blk < fs->super->s_first_data_block ||
6024 blk >= fs->super->s_blocks_count)
6025 problem = PR_1_ILLEGAL_BLOCK_NUM;
6026
6027 if (problem) {
6028 p->num_illegal_blocks++;
6029 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
6030 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
6031 p->clear = 1;
6032 return BLOCK_ABORT;
6033 }
6034 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
6035 p->suppress = 1;
6036 set_latch_flags(PR_LATCH_BLOCK,
6037 PRL_SUPPRESS, 0);
6038 }
6039 }
6040 pctx->blk = blk;
6041 pctx->blkcount = blockcnt;
6042 if (fix_problem(ctx, problem, pctx)) {
6043 blk = *block_nr = 0;
6044 ret_code = BLOCK_CHANGED;
6045 goto mark_dir;
6046 } else
6047 return 0;
6048 }
6049
6050 if (p->ino == EXT2_RESIZE_INO) {
6051 /*
6052 * The resize inode has already be sanity checked
6053 * during pass #0 (the superblock checks). All we
6054 * have to do is mark the double indirect block as
6055 * being in use; all of the other blocks are handled
6056 * by mark_table_blocks()).
6057 */
6058 if (blockcnt == BLOCK_COUNT_DIND)
6059 mark_block_used(ctx, blk);
6060 } else
6061 mark_block_used(ctx, blk);
6062 p->num_blocks++;
6063 if (blockcnt >= 0)
6064 p->last_block = blockcnt;
6065mark_dir:
6066 if (p->is_dir && (blockcnt >= 0)) {
6067 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
6068 blk, blockcnt);
6069 if (pctx->errcode) {
6070 pctx->blk = blk;
6071 pctx->num = blockcnt;
6072 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
6073 /* Should never get here */
6074 ctx->flags |= E2F_FLAG_ABORT;
6075 return BLOCK_ABORT;
6076 }
6077 }
6078 return ret_code;
6079}
6080
6081static int process_bad_block(ext2_filsys fs,
6082 blk_t *block_nr,
6083 e2_blkcnt_t blockcnt,
6084 blk_t ref_block EXT2FS_ATTR((unused)),
6085 int ref_offset EXT2FS_ATTR((unused)),
6086 void *priv_data)
6087{
6088 struct process_block_struct_1 *p;
6089 blk_t blk = *block_nr;
6090 blk_t first_block;
6091 dgrp_t i;
6092 struct problem_context *pctx;
6093 e2fsck_t ctx;
6094
6095 /*
6096 * Note: This function processes blocks for the bad blocks
6097 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
6098 */
6099
6100 if (!blk)
6101 return 0;
6102
6103 p = (struct process_block_struct_1 *) priv_data;
6104 ctx = p->ctx;
6105 pctx = p->pctx;
6106
6107 pctx->ino = EXT2_BAD_INO;
6108 pctx->blk = blk;
6109 pctx->blkcount = blockcnt;
6110
6111 if ((blk < fs->super->s_first_data_block) ||
6112 (blk >= fs->super->s_blocks_count)) {
6113 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
6114 *block_nr = 0;
6115 return BLOCK_CHANGED;
6116 } else
6117 return 0;
6118 }
6119
6120 if (blockcnt < 0) {
6121 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
6122 p->bbcheck = 1;
6123 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
6124 *block_nr = 0;
6125 return BLOCK_CHANGED;
6126 }
6127 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
6128 blk)) {
6129 p->bbcheck = 1;
6130 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
6131 pctx)) {
6132 *block_nr = 0;
6133 return BLOCK_CHANGED;
6134 }
6135 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6136 return BLOCK_ABORT;
6137 } else
6138 mark_block_used(ctx, blk);
6139 return 0;
6140 }
6141#if 0
6142 printf ("DEBUG: Marking %u as bad.\n", blk);
6143#endif
6144 ctx->fs_badblocks_count++;
6145 /*
6146 * If the block is not used, then mark it as used and return.
6147 * If it is already marked as found, this must mean that
6148 * there's an overlap between the filesystem table blocks
6149 * (bitmaps and inode table) and the bad block list.
6150 */
6151 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
6152 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
6153 return 0;
6154 }
6155 /*
6156 * Try to find the where the filesystem block was used...
6157 */
6158 first_block = fs->super->s_first_data_block;
6159
6160 for (i = 0; i < fs->group_desc_count; i++ ) {
6161 pctx->group = i;
6162 pctx->blk = blk;
6163 if (!ext2fs_bg_has_super(fs, i))
6164 goto skip_super;
6165 if (blk == first_block) {
6166 if (i == 0) {
6167 if (fix_problem(ctx,
6168 PR_1_BAD_PRIMARY_SUPERBLOCK,
6169 pctx)) {
6170 *block_nr = 0;
6171 return BLOCK_CHANGED;
6172 }
6173 return 0;
6174 }
6175 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
6176 return 0;
6177 }
6178 if ((blk > first_block) &&
6179 (blk <= first_block + fs->desc_blocks)) {
6180 if (i == 0) {
6181 pctx->blk = *block_nr;
6182 if (fix_problem(ctx,
6183 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
6184 *block_nr = 0;
6185 return BLOCK_CHANGED;
6186 }
6187 return 0;
6188 }
6189 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
6190 return 0;
6191 }
6192 skip_super:
6193 if (blk == fs->group_desc[i].bg_block_bitmap) {
6194 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
6195 ctx->invalid_block_bitmap_flag[i]++;
6196 ctx->invalid_bitmaps++;
6197 }
6198 return 0;
6199 }
6200 if (blk == fs->group_desc[i].bg_inode_bitmap) {
6201 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
6202 ctx->invalid_inode_bitmap_flag[i]++;
6203 ctx->invalid_bitmaps++;
6204 }
6205 return 0;
6206 }
6207 if ((blk >= fs->group_desc[i].bg_inode_table) &&
6208 (blk < (fs->group_desc[i].bg_inode_table +
6209 fs->inode_blocks_per_group))) {
6210 /*
6211 * If there are bad blocks in the inode table,
6212 * the inode scan code will try to do
6213 * something reasonable automatically.
6214 */
6215 return 0;
6216 }
6217 first_block += fs->super->s_blocks_per_group;
6218 }
6219 /*
6220 * If we've gotten to this point, then the only
6221 * possibility is that the bad block inode meta data
6222 * is using a bad block.
6223 */
6224 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
6225 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
6226 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
6227 p->bbcheck = 1;
6228 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
6229 *block_nr = 0;
6230 return BLOCK_CHANGED;
6231 }
6232 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
6233 return BLOCK_ABORT;
6234 return 0;
6235 }
6236
6237 pctx->group = -1;
6238
6239 /* Warn user that the block wasn't claimed */
6240 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
6241
6242 return 0;
6243}
6244
6245static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
6246 const char *name, int num, blk_t *new_block)
6247{
6248 ext2_filsys fs = ctx->fs;
6249 blk_t old_block = *new_block;
6250 int i;
6251 char *buf;
6252 struct problem_context pctx;
6253
6254 clear_problem_context(&pctx);
6255
6256 pctx.group = group;
6257 pctx.blk = old_block;
6258 pctx.str = name;
6259
6260 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
6261 first_block + fs->super->s_blocks_per_group,
6262 num, ctx->block_found_map, new_block);
6263 if (pctx.errcode) {
6264 pctx.num = num;
6265 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
6266 ext2fs_unmark_valid(fs);
6267 return;
6268 }
6269 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
6270 if (pctx.errcode) {
6271 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
6272 ext2fs_unmark_valid(fs);
6273 return;
6274 }
6275 ext2fs_mark_super_dirty(fs);
6276 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
6277 pctx.blk2 = *new_block;
6278 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
6279 PR_1_RELOC_TO), &pctx);
6280 pctx.blk2 = 0;
6281 for (i = 0; i < num; i++) {
6282 pctx.blk = i;
6283 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
6284 if (old_block) {
6285 pctx.errcode = io_channel_read_blk(fs->io,
6286 old_block + i, 1, buf);
6287 if (pctx.errcode)
6288 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
6289 } else
6290 memset(buf, 0, fs->blocksize);
6291
6292 pctx.blk = (*new_block) + i;
6293 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
6294 1, buf);
6295 if (pctx.errcode)
6296 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
6297 }
6298 ext2fs_free_mem(&buf);
6299}
6300
6301/*
6302 * This routine gets called at the end of pass 1 if bad blocks are
6303 * detected in the superblock, group descriptors, inode_bitmaps, or
6304 * block bitmaps. At this point, all of the blocks have been mapped
6305 * out, so we can try to allocate new block(s) to replace the bad
6306 * blocks.
6307 */
6308static void handle_fs_bad_blocks(e2fsck_t ctx)
6309{
6310 ext2_filsys fs = ctx->fs;
6311 dgrp_t i;
6312 int first_block = fs->super->s_first_data_block;
6313
6314 for (i = 0; i < fs->group_desc_count; i++) {
6315 if (ctx->invalid_block_bitmap_flag[i]) {
6316 new_table_block(ctx, first_block, i, _("block bitmap"),
6317 1, &fs->group_desc[i].bg_block_bitmap);
6318 }
6319 if (ctx->invalid_inode_bitmap_flag[i]) {
6320 new_table_block(ctx, first_block, i, _("inode bitmap"),
6321 1, &fs->group_desc[i].bg_inode_bitmap);
6322 }
6323 if (ctx->invalid_inode_table_flag[i]) {
6324 new_table_block(ctx, first_block, i, _("inode table"),
6325 fs->inode_blocks_per_group,
6326 &fs->group_desc[i].bg_inode_table);
6327 ctx->flags |= E2F_FLAG_RESTART;
6328 }
6329 first_block += fs->super->s_blocks_per_group;
6330 }
6331 ctx->invalid_bitmaps = 0;
6332}
6333
6334/*
6335 * This routine marks all blocks which are used by the superblock,
6336 * group descriptors, inode bitmaps, and block bitmaps.
6337 */
6338static void mark_table_blocks(e2fsck_t ctx)
6339{
6340 ext2_filsys fs = ctx->fs;
6341 blk_t block, b;
6342 dgrp_t i;
6343 int j;
6344 struct problem_context pctx;
6345
6346 clear_problem_context(&pctx);
6347
6348 block = fs->super->s_first_data_block;
6349 for (i = 0; i < fs->group_desc_count; i++) {
6350 pctx.group = i;
6351
6352 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
6353
6354 /*
6355 * Mark the blocks used for the inode table
6356 */
6357 if (fs->group_desc[i].bg_inode_table) {
6358 for (j = 0, b = fs->group_desc[i].bg_inode_table;
6359 j < fs->inode_blocks_per_group;
6360 j++, b++) {
6361 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6362 b)) {
6363 pctx.blk = b;
6364 if (fix_problem(ctx,
6365 PR_1_ITABLE_CONFLICT, &pctx)) {
6366 ctx->invalid_inode_table_flag[i]++;
6367 ctx->invalid_bitmaps++;
6368 }
6369 } else {
6370 ext2fs_mark_block_bitmap(ctx->block_found_map,
6371 b);
6372 }
6373 }
6374 }
6375
6376 /*
6377 * Mark block used for the block bitmap
6378 */
6379 if (fs->group_desc[i].bg_block_bitmap) {
6380 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6381 fs->group_desc[i].bg_block_bitmap)) {
6382 pctx.blk = fs->group_desc[i].bg_block_bitmap;
6383 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
6384 ctx->invalid_block_bitmap_flag[i]++;
6385 ctx->invalid_bitmaps++;
6386 }
6387 } else {
6388 ext2fs_mark_block_bitmap(ctx->block_found_map,
6389 fs->group_desc[i].bg_block_bitmap);
6390 }
6391
6392 }
6393 /*
6394 * Mark block used for the inode bitmap
6395 */
6396 if (fs->group_desc[i].bg_inode_bitmap) {
6397 if (ext2fs_test_block_bitmap(ctx->block_found_map,
6398 fs->group_desc[i].bg_inode_bitmap)) {
6399 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
6400 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
6401 ctx->invalid_inode_bitmap_flag[i]++;
6402 ctx->invalid_bitmaps++;
6403 }
6404 } else {
6405 ext2fs_mark_block_bitmap(ctx->block_found_map,
6406 fs->group_desc[i].bg_inode_bitmap);
6407 }
6408 }
6409 block += fs->super->s_blocks_per_group;
6410 }
6411}
6412
6413/*
6414 * Thes subroutines short circuits ext2fs_get_blocks and
6415 * ext2fs_check_directory; we use them since we already have the inode
6416 * structure, so there's no point in letting the ext2fs library read
6417 * the inode again.
6418 */
6419static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
6420 blk_t *blocks)
6421{
6422 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6423 int i;
6424
6425 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6426 return EXT2_ET_CALLBACK_NOTHANDLED;
6427
6428 for (i=0; i < EXT2_N_BLOCKS; i++)
6429 blocks[i] = ctx->stashed_inode->i_block[i];
6430 return 0;
6431}
6432
6433static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
6434 struct ext2_inode *inode)
6435{
6436 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6437
6438 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6439 return EXT2_ET_CALLBACK_NOTHANDLED;
6440 *inode = *ctx->stashed_inode;
6441 return 0;
6442}
6443
6444static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
6445 struct ext2_inode *inode)
6446{
6447 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6448
6449 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
6450 *ctx->stashed_inode = *inode;
6451 return EXT2_ET_CALLBACK_NOTHANDLED;
6452}
6453
6454static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
6455{
6456 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
6457
6458 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
6459 return EXT2_ET_CALLBACK_NOTHANDLED;
6460
6461 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
6462 return EXT2_ET_NO_DIRECTORY;
6463 return 0;
6464}
6465
6466void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
6467{
6468 ext2_filsys fs = ctx->fs;
6469
6470 if (bool) {
6471 fs->get_blocks = pass1_get_blocks;
6472 fs->check_directory = pass1_check_directory;
6473 fs->read_inode = pass1_read_inode;
6474 fs->write_inode = pass1_write_inode;
6475 ctx->stashed_ino = 0;
6476 } else {
6477 fs->get_blocks = 0;
6478 fs->check_directory = 0;
6479 fs->read_inode = 0;
6480 fs->write_inode = 0;
6481 }
6482}
6483/*
6484 * pass1b.c --- Pass #1b of e2fsck
6485 *
6486 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
6487 * only invoked if pass 1 discovered blocks which are in use by more
6488 * than one inode.
6489 *
6490 * Pass1B scans the data blocks of all the inodes again, generating a
6491 * complete list of duplicate blocks and which inodes have claimed
6492 * them.
6493 *
6494 * Pass1C does a tree-traversal of the filesystem, to determine the
6495 * parent directories of these inodes. This step is necessary so that
6496 * e2fsck can print out the pathnames of affected inodes.
6497 *
6498 * Pass1D is a reconciliation pass. For each inode with duplicate
6499 * blocks, the user is prompted if s/he would like to clone the file
6500 * (so that the file gets a fresh copy of the duplicated blocks) or
6501 * simply to delete the file.
6502 *
6503 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
6504 *
6505 * %Begin-Header%
6506 * This file may be redistributed under the terms of the GNU Public
6507 * License.
6508 * %End-Header%
6509 *
6510 */
6511
6512
6513/* Needed for architectures where sizeof(int) != sizeof(void *) */
6514#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
6515#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
6516
6517/* Define an extension to the ext2 library's block count information */
6518#define BLOCK_COUNT_EXTATTR (-5)
6519
6520struct block_el {
6521 blk_t block;
6522 struct block_el *next;
6523};
6524
6525struct inode_el {
6526 ext2_ino_t inode;
6527 struct inode_el *next;
6528};
6529
6530struct dup_block {
6531 int num_bad;
6532 struct inode_el *inode_list;
6533};
6534
6535/*
6536 * This structure stores information about a particular inode which
6537 * is sharing blocks with other inodes. This information is collected
6538 * to display to the user, so that the user knows what files he or she
6539 * is dealing with, when trying to decide how to resolve the conflict
6540 * of multiply-claimed blocks.
6541 */
6542struct dup_inode {
6543 ext2_ino_t dir;
6544 int num_dupblocks;
6545 struct ext2_inode inode;
6546 struct block_el *block_list;
6547};
6548
6549static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
6550 e2_blkcnt_t blockcnt, blk_t ref_blk,
6551 int ref_offset, void *priv_data);
6552static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
6553 struct dup_inode *dp, char *block_buf);
6554static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
6555 struct dup_inode *dp, char* block_buf);
6556static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
6557
6558static void pass1b(e2fsck_t ctx, char *block_buf);
6559static void pass1c(e2fsck_t ctx, char *block_buf);
6560static void pass1d(e2fsck_t ctx, char *block_buf);
6561
6562static int dup_inode_count = 0;
6563
6564static dict_t blk_dict, ino_dict;
6565
6566static ext2fs_inode_bitmap inode_dup_map;
6567
6568static int dict_int_cmp(const void *a, const void *b)
6569{
6570 intptr_t ia, ib;
6571
6572 ia = (intptr_t)a;
6573 ib = (intptr_t)b;
6574
6575 return (ia-ib);
6576}
6577
6578/*
6579 * Add a duplicate block record
6580 */
6581static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
6582 struct ext2_inode *inode)
6583{
6584 dnode_t *n;
6585 struct dup_block *db;
6586 struct dup_inode *di;
6587 struct block_el *blk_el;
6588 struct inode_el *ino_el;
6589
6590 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
6591 if (n)
6592 db = (struct dup_block *) dnode_get(n);
6593 else {
6594 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
6595 sizeof(struct dup_block), "duplicate block header");
6596 db->num_bad = 0;
6597 db->inode_list = 0;
6598 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
6599 }
6600 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
6601 sizeof(struct inode_el), "inode element");
6602 ino_el->inode = ino;
6603 ino_el->next = db->inode_list;
6604 db->inode_list = ino_el;
6605 db->num_bad++;
6606
6607 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
6608 if (n)
6609 di = (struct dup_inode *) dnode_get(n);
6610 else {
6611 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
6612 sizeof(struct dup_inode), "duplicate inode header");
6613 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
6614 di->num_dupblocks = 0;
6615 di->block_list = 0;
6616 di->inode = *inode;
6617 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
6618 }
6619 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
6620 sizeof(struct block_el), "block element");
6621 blk_el->block = blk;
6622 blk_el->next = di->block_list;
6623 di->block_list = blk_el;
6624 di->num_dupblocks++;
6625}
6626
6627/*
6628 * Free a duplicate inode record
6629 */
6630static void inode_dnode_free(dnode_t *node,
6631 void *context EXT2FS_ATTR((unused)))
6632{
6633 struct dup_inode *di;
6634 struct block_el *p, *next;
6635
6636 di = (struct dup_inode *) dnode_get(node);
6637 for (p = di->block_list; p; p = next) {
6638 next = p->next;
6639 free(p);
6640 }
6641 free(node);
6642}
6643
6644/*
6645 * Free a duplicate block record
6646 */
6647static void block_dnode_free(dnode_t *node,
6648 void *context EXT2FS_ATTR((unused)))
6649{
6650 struct dup_block *db;
6651 struct inode_el *p, *next;
6652
6653 db = (struct dup_block *) dnode_get(node);
6654 for (p = db->inode_list; p; p = next) {
6655 next = p->next;
6656 free(p);
6657 }
6658 free(node);
6659}
6660
6661
6662/*
6663 * Main procedure for handling duplicate blocks
6664 */
6665void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
6666{
6667 ext2_filsys fs = ctx->fs;
6668 struct problem_context pctx;
6669
6670 clear_problem_context(&pctx);
6671
6672 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
6673 _("multiply claimed inode map"), &inode_dup_map);
6674 if (pctx.errcode) {
6675 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
6676 ctx->flags |= E2F_FLAG_ABORT;
6677 return;
6678 }
6679
6680 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
6681 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
6682 dict_set_allocator(&ino_dict, NULL, inode_dnode_free, NULL);
6683 dict_set_allocator(&blk_dict, NULL, block_dnode_free, NULL);
6684
6685 pass1b(ctx, block_buf);
6686 pass1c(ctx, block_buf);
6687 pass1d(ctx, block_buf);
6688
6689 /*
6690 * Time to free all of the accumulated data structures that we
6691 * don't need anymore.
6692 */
6693 dict_free_nodes(&ino_dict);
6694 dict_free_nodes(&blk_dict);
6695}
6696
6697/*
6698 * Scan the inodes looking for inodes that contain duplicate blocks.
6699 */
6700struct process_block_struct_1b {
6701 e2fsck_t ctx;
6702 ext2_ino_t ino;
6703 int dup_blocks;
6704 struct ext2_inode *inode;
6705 struct problem_context *pctx;
6706};
6707
6708static void pass1b(e2fsck_t ctx, char *block_buf)
6709{
6710 ext2_filsys fs = ctx->fs;
6711 ext2_ino_t ino;
6712 struct ext2_inode inode;
6713 ext2_inode_scan scan;
6714 struct process_block_struct_1b pb;
6715 struct problem_context pctx;
6716
6717 clear_problem_context(&pctx);
6718
6719 if (!(ctx->options & E2F_OPT_PREEN))
6720 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
6721 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
6722 &scan);
6723 if (pctx.errcode) {
6724 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6725 ctx->flags |= E2F_FLAG_ABORT;
6726 return;
6727 }
6728 ctx->stashed_inode = &inode;
6729 pb.ctx = ctx;
6730 pb.pctx = &pctx;
6731 pctx.str = "pass1b";
6732 while (1) {
6733 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
6734 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
6735 continue;
6736 if (pctx.errcode) {
6737 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
6738 ctx->flags |= E2F_FLAG_ABORT;
6739 return;
6740 }
6741 if (!ino)
6742 break;
6743 pctx.ino = ctx->stashed_ino = ino;
6744 if ((ino != EXT2_BAD_INO) &&
6745 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
6746 continue;
6747
6748 pb.ino = ino;
6749 pb.dup_blocks = 0;
6750 pb.inode = &inode;
6751
6752 if (ext2fs_inode_has_valid_blocks(&inode) ||
6753 (ino == EXT2_BAD_INO))
6754 pctx.errcode = ext2fs_block_iterate2(fs, ino,
6755 0, block_buf, process_pass1b_block, &pb);
6756 if (inode.i_file_acl)
6757 process_pass1b_block(fs, &inode.i_file_acl,
6758 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
6759 if (pb.dup_blocks) {
6760 end_problem_latch(ctx, PR_LATCH_DBLOCK);
6761 if (ino >= EXT2_FIRST_INODE(fs->super) ||
6762 ino == EXT2_ROOT_INO)
6763 dup_inode_count++;
6764 }
6765 if (pctx.errcode)
6766 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
6767 }
6768 ext2fs_close_inode_scan(scan);
6769 e2fsck_use_inode_shortcuts(ctx, 0);
6770}
6771
6772static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
6773 blk_t *block_nr,
6774 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
6775 blk_t ref_blk EXT2FS_ATTR((unused)),
6776 int ref_offset EXT2FS_ATTR((unused)),
6777 void *priv_data)
6778{
6779 struct process_block_struct_1b *p;
6780 e2fsck_t ctx;
6781
6782 if (HOLE_BLKADDR(*block_nr))
6783 return 0;
6784 p = (struct process_block_struct_1b *) priv_data;
6785 ctx = p->ctx;
6786
6787 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
6788 return 0;
6789
6790 /* OK, this is a duplicate block */
6791 if (p->ino != EXT2_BAD_INO) {
6792 p->pctx->blk = *block_nr;
6793 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
6794 }
6795 p->dup_blocks++;
6796 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
6797
6798 add_dupe(ctx, p->ino, *block_nr, p->inode);
6799
6800 return 0;
6801}
6802
6803/*
6804 * Pass 1c: Scan directories for inodes with duplicate blocks. This
6805 * is used so that we can print pathnames when prompting the user for
6806 * what to do.
6807 */
6808struct search_dir_struct {
6809 int count;
6810 ext2_ino_t first_inode;
6811 ext2_ino_t max_inode;
6812};
6813
6814static int search_dirent_proc(ext2_ino_t dir, int entry,
6815 struct ext2_dir_entry *dirent,
6816 int offset EXT2FS_ATTR((unused)),
6817 int blocksize EXT2FS_ATTR((unused)),
6818 char *buf EXT2FS_ATTR((unused)),
6819 void *priv_data)
6820{
6821 struct search_dir_struct *sd;
6822 struct dup_inode *p;
6823 dnode_t *n;
6824
6825 sd = (struct search_dir_struct *) priv_data;
6826
6827 if (dirent->inode > sd->max_inode)
6828 /* Should abort this inode, but not everything */
6829 return 0;
6830
6831 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
6832 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
6833 return 0;
6834
6835 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
6836 if (!n)
6837 return 0;
6838 p = (struct dup_inode *) dnode_get(n);
6839 p->dir = dir;
6840 sd->count--;
6841
6842 return(sd->count ? 0 : DIRENT_ABORT);
6843}
6844
6845
6846static void pass1c(e2fsck_t ctx, char *block_buf)
6847{
6848 ext2_filsys fs = ctx->fs;
6849 struct search_dir_struct sd;
6850 struct problem_context pctx;
6851
6852 clear_problem_context(&pctx);
6853
6854 if (!(ctx->options & E2F_OPT_PREEN))
6855 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
6856
6857 /*
6858 * Search through all directories to translate inodes to names
6859 * (by searching for the containing directory for that inode.)
6860 */
6861 sd.count = dup_inode_count;
6862 sd.first_inode = EXT2_FIRST_INODE(fs->super);
6863 sd.max_inode = fs->super->s_inodes_count;
6864 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
6865 search_dirent_proc, &sd);
6866}
6867
6868static void pass1d(e2fsck_t ctx, char *block_buf)
6869{
6870 ext2_filsys fs = ctx->fs;
6871 struct dup_inode *p, *t;
6872 struct dup_block *q;
6873 ext2_ino_t *shared, ino;
6874 int shared_len;
6875 int i;
6876 int file_ok;
6877 int meta_data = 0;
6878 struct problem_context pctx;
6879 dnode_t *n, *m;
6880 struct block_el *s;
6881 struct inode_el *r;
6882
6883 clear_problem_context(&pctx);
6884
6885 if (!(ctx->options & E2F_OPT_PREEN))
6886 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
6887 e2fsck_read_bitmaps(ctx);
6888
6889 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
6890 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
6891 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
6892 sizeof(ext2_ino_t) * dict_count(&ino_dict),
6893 "Shared inode list");
6894 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
6895 p = (struct dup_inode *) dnode_get(n);
6896 shared_len = 0;
6897 file_ok = 1;
6898 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
6899 if (ino == EXT2_BAD_INO)
6900 continue;
6901
6902 /*
6903 * Find all of the inodes which share blocks with this
6904 * one. First we find all of the duplicate blocks
6905 * belonging to this inode, and then search each block
6906 * get the list of inodes, and merge them together.
6907 */
6908 for (s = p->block_list; s; s = s->next) {
6909 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
6910 if (!m)
6911 continue; /* Should never happen... */
6912 q = (struct dup_block *) dnode_get(m);
6913 if (q->num_bad > 1)
6914 file_ok = 0;
6915 if (check_if_fs_block(ctx, s->block)) {
6916 file_ok = 0;
6917 meta_data = 1;
6918 }
6919
6920 /*
6921 * Add all inodes used by this block to the
6922 * shared[] --- which is a unique list, so
6923 * if an inode is already in shared[], don't
6924 * add it again.
6925 */
6926 for (r = q->inode_list; r; r = r->next) {
6927 if (r->inode == ino)
6928 continue;
6929 for (i = 0; i < shared_len; i++)
6930 if (shared[i] == r->inode)
6931 break;
6932 if (i == shared_len) {
6933 shared[shared_len++] = r->inode;
6934 }
6935 }
6936 }
6937
6938 /*
6939 * Report the inode that we are working on
6940 */
6941 pctx.inode = &p->inode;
6942 pctx.ino = ino;
6943 pctx.dir = p->dir;
6944 pctx.blkcount = p->num_dupblocks;
6945 pctx.num = meta_data ? shared_len+1 : shared_len;
6946 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
6947 pctx.blkcount = 0;
6948 pctx.num = 0;
6949
6950 if (meta_data)
6951 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
6952
6953 for (i = 0; i < shared_len; i++) {
6954 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
6955 if (!m)
6956 continue; /* should never happen */
6957 t = (struct dup_inode *) dnode_get(m);
6958 /*
6959 * Report the inode that we are sharing with
6960 */
6961 pctx.inode = &t->inode;
6962 pctx.ino = shared[i];
6963 pctx.dir = t->dir;
6964 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
6965 }
6966 if (file_ok) {
6967 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
6968 continue;
6969 }
6970 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
6971 pctx.errcode = clone_file(ctx, ino, p, block_buf);
6972 if (pctx.errcode)
6973 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
6974 else
6975 continue;
6976 }
6977 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
6978 delete_file(ctx, ino, p, block_buf);
6979 else
6980 ext2fs_unmark_valid(fs);
6981 }
6982 ext2fs_free_mem(&shared);
6983}
6984
6985/*
6986 * Drop the refcount on the dup_block structure, and clear the entry
6987 * in the block_dup_map if appropriate.
6988 */
6989static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
6990{
6991 p->num_bad--;
6992 if (p->num_bad <= 0 ||
6993 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
6994 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
6995}
6996
6997static int delete_file_block(ext2_filsys fs,
6998 blk_t *block_nr,
6999 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
7000 blk_t ref_block EXT2FS_ATTR((unused)),
7001 int ref_offset EXT2FS_ATTR((unused)),
7002 void *priv_data)
7003{
7004 struct process_block_struct_1b *pb;
7005 struct dup_block *p;
7006 dnode_t *n;
7007 e2fsck_t ctx;
7008
7009 pb = (struct process_block_struct_1b *) priv_data;
7010 ctx = pb->ctx;
7011
7012 if (HOLE_BLKADDR(*block_nr))
7013 return 0;
7014
7015 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
7016 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
7017 if (n) {
7018 p = (struct dup_block *) dnode_get(n);
7019 decrement_badcount(ctx, *block_nr, p);
7020 } else
7021 com_err("delete_file_block", 0,
7022 _("internal error; can't find dup_blk for %d\n"),
7023 *block_nr);
7024 } else {
7025 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
7026 ext2fs_block_alloc_stats(fs, *block_nr, -1);
7027 }
7028
7029 return 0;
7030}
7031
7032static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
7033 struct dup_inode *dp, char* block_buf)
7034{
7035 ext2_filsys fs = ctx->fs;
7036 struct process_block_struct_1b pb;
7037 struct ext2_inode inode;
7038 struct problem_context pctx;
7039 unsigned int count;
7040
7041 clear_problem_context(&pctx);
7042 pctx.ino = pb.ino = ino;
7043 pb.dup_blocks = dp->num_dupblocks;
7044 pb.ctx = ctx;
7045 pctx.str = "delete_file";
7046
7047 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
7048 if (ext2fs_inode_has_valid_blocks(&inode))
7049 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
7050 delete_file_block, &pb);
7051 if (pctx.errcode)
7052 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
7053 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
7054 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
7055 if (ctx->inode_bad_map)
7056 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
7057 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
7058
7059 /* Inode may have changed by block_iterate, so reread it */
7060 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
7061 inode.i_links_count = 0;
7062 inode.i_dtime = time(0);
7063 if (inode.i_file_acl &&
7064 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
7065 count = 1;
7066 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
7067 block_buf, -1, &count);
7068 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
7069 pctx.errcode = 0;
7070 count = 1;
7071 }
7072 if (pctx.errcode) {
7073 pctx.blk = inode.i_file_acl;
7074 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
7075 }
7076 /*
7077 * If the count is zero, then arrange to have the
7078 * block deleted. If the block is in the block_dup_map,
7079 * also call delete_file_block since it will take care
7080 * of keeping the accounting straight.
7081 */
7082 if ((count == 0) ||
7083 ext2fs_test_block_bitmap(ctx->block_dup_map,
7084 inode.i_file_acl))
7085 delete_file_block(fs, &inode.i_file_acl,
7086 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
7087 }
7088 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
7089}
7090
7091struct clone_struct {
7092 errcode_t errcode;
7093 ext2_ino_t dir;
7094 char *buf;
7095 e2fsck_t ctx;
7096};
7097
7098static int clone_file_block(ext2_filsys fs,
7099 blk_t *block_nr,
7100 e2_blkcnt_t blockcnt,
7101 blk_t ref_block EXT2FS_ATTR((unused)),
7102 int ref_offset EXT2FS_ATTR((unused)),
7103 void *priv_data)
7104{
7105 struct dup_block *p;
7106 blk_t new_block;
7107 errcode_t retval;
7108 struct clone_struct *cs = (struct clone_struct *) priv_data;
7109 dnode_t *n;
7110 e2fsck_t ctx;
7111
7112 ctx = cs->ctx;
7113
7114 if (HOLE_BLKADDR(*block_nr))
7115 return 0;
7116
7117 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
7118 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
7119 if (n) {
7120 p = (struct dup_block *) dnode_get(n);
7121 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
7122 &new_block);
7123 if (retval) {
7124 cs->errcode = retval;
7125 return BLOCK_ABORT;
7126 }
7127 if (cs->dir && (blockcnt >= 0)) {
7128 retval = ext2fs_set_dir_block(fs->dblist,
7129 cs->dir, new_block, blockcnt);
7130 if (retval) {
7131 cs->errcode = retval;
7132 return BLOCK_ABORT;
7133 }
7134 }
7135#if 0
7136 printf("Cloning block %u to %u\n", *block_nr,
7137 new_block);
7138#endif
7139 retval = io_channel_read_blk(fs->io, *block_nr, 1,
7140 cs->buf);
7141 if (retval) {
7142 cs->errcode = retval;
7143 return BLOCK_ABORT;
7144 }
7145 retval = io_channel_write_blk(fs->io, new_block, 1,
7146 cs->buf);
7147 if (retval) {
7148 cs->errcode = retval;
7149 return BLOCK_ABORT;
7150 }
7151 decrement_badcount(ctx, *block_nr, p);
7152 *block_nr = new_block;
7153 ext2fs_mark_block_bitmap(ctx->block_found_map,
7154 new_block);
7155 ext2fs_mark_block_bitmap(fs->block_map, new_block);
7156 return BLOCK_CHANGED;
7157 } else
7158 com_err("clone_file_block", 0,
7159 _("internal error; can't find dup_blk for %d\n"),
7160 *block_nr);
7161 }
7162 return 0;
7163}
7164
7165static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
7166 struct dup_inode *dp, char* block_buf)
7167{
7168 ext2_filsys fs = ctx->fs;
7169 errcode_t retval;
7170 struct clone_struct cs;
7171 struct problem_context pctx;
7172 blk_t blk;
7173 dnode_t *n;
7174 struct inode_el *ino_el;
7175 struct dup_block *db;
7176 struct dup_inode *di;
7177
7178 clear_problem_context(&pctx);
7179 cs.errcode = 0;
7180 cs.dir = 0;
7181 cs.ctx = ctx;
7182 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
7183 if (retval)
7184 return retval;
7185
7186 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
7187 cs.dir = ino;
7188
7189 pctx.ino = ino;
7190 pctx.str = "clone_file";
7191 if (ext2fs_inode_has_valid_blocks(&dp->inode))
7192 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
7193 clone_file_block, &cs);
7194 ext2fs_mark_bb_dirty(fs);
7195 if (pctx.errcode) {
7196 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
7197 retval = pctx.errcode;
7198 goto errout;
7199 }
7200 if (cs.errcode) {
7201 com_err("clone_file", cs.errcode,
7202 _("returned from clone_file_block"));
7203 retval = cs.errcode;
7204 goto errout;
7205 }
7206 /* The inode may have changed on disk, so we have to re-read it */
7207 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
7208 blk = dp->inode.i_file_acl;
7209 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
7210 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
7211 BLOCK_CHANGED)) {
7212 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
7213 /*
7214 * If we cloned the EA block, find all other inodes
7215 * which refered to that EA block, and modify
7216 * them to point to the new EA block.
7217 */
7218 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
7219 db = (struct dup_block *) dnode_get(n);
7220 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
7221 if (ino_el->inode == ino)
7222 continue;
7223 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
7224 di = (struct dup_inode *) dnode_get(n);
7225 if (di->inode.i_file_acl == blk) {
7226 di->inode.i_file_acl = dp->inode.i_file_acl;
7227 e2fsck_write_inode(ctx, ino_el->inode,
7228 &di->inode, "clone file EA");
7229 decrement_badcount(ctx, blk, db);
7230 }
7231 }
7232 }
7233 retval = 0;
7234errout:
7235 ext2fs_free_mem(&cs.buf);
7236 return retval;
7237}
7238
7239/*
7240 * This routine returns 1 if a block overlaps with one of the superblocks,
7241 * group descriptors, inode bitmaps, or block bitmaps.
7242 */
7243static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
7244{
7245 ext2_filsys fs = ctx->fs;
7246 blk_t block;
7247 dgrp_t i;
7248
7249 block = fs->super->s_first_data_block;
7250 for (i = 0; i < fs->group_desc_count; i++) {
7251
7252 /* Check superblocks/block group descriptros */
7253 if (ext2fs_bg_has_super(fs, i)) {
7254 if (test_block >= block &&
7255 (test_block <= block + fs->desc_blocks))
7256 return 1;
7257 }
7258
7259 /* Check the inode table */
7260 if ((fs->group_desc[i].bg_inode_table) &&
7261 (test_block >= fs->group_desc[i].bg_inode_table) &&
7262 (test_block < (fs->group_desc[i].bg_inode_table +
7263 fs->inode_blocks_per_group)))
7264 return 1;
7265
7266 /* Check the bitmap blocks */
7267 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
7268 (test_block == fs->group_desc[i].bg_inode_bitmap))
7269 return 1;
7270
7271 block += fs->super->s_blocks_per_group;
7272 }
7273 return 0;
7274}
7275/*
7276 * pass2.c --- check directory structure
7277 *
7278 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o
7279 *
7280 * %Begin-Header%
7281 * This file may be redistributed under the terms of the GNU Public
7282 * License.
7283 * %End-Header%
7284 *
7285 * Pass 2 of e2fsck iterates through all active directory inodes, and
7286 * applies to following tests to each directory entry in the directory
7287 * blocks in the inodes:
7288 *
7289 * - The length of the directory entry (rec_len) should be at
7290 * least 8 bytes, and no more than the remaining space
7291 * left in the directory block.
7292 * - The length of the name in the directory entry (name_len)
7293 * should be less than (rec_len - 8).
7294 * - The inode number in the directory entry should be within
7295 * legal bounds.
7296 * - The inode number should refer to a in-use inode.
7297 * - The first entry should be '.', and its inode should be
7298 * the inode of the directory.
7299 * - The second entry should be '..'.
7300 *
7301 * To minimize disk seek time, the directory blocks are processed in
7302 * sorted order of block numbers.
7303 *
7304 * Pass 2 also collects the following information:
7305 * - The inode numbers of the subdirectories for each directory.
7306 *
7307 * Pass 2 relies on the following information from previous passes:
7308 * - The directory information collected in pass 1.
7309 * - The inode_used_map bitmap
7310 * - The inode_bad_map bitmap
7311 * - The inode_dir_map bitmap
7312 *
7313 * Pass 2 frees the following data structures
7314 * - The inode_bad_map bitmap
7315 * - The inode_reg_map bitmap
7316 */
7317
7318/* #define DX_DEBUG */
7319
7320/*
7321 * Keeps track of how many times an inode is referenced.
7322 */
7323static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
7324static int check_dir_block(ext2_filsys fs,
7325 struct ext2_db_entry *dir_blocks_info,
7326 void *priv_data);
7327static int allocate_dir_block(e2fsck_t ctx,
7328 struct ext2_db_entry *dir_blocks_info,
7329 char *buf, struct problem_context *pctx);
7330static int update_dir_block(ext2_filsys fs,
7331 blk_t *block_nr,
7332 e2_blkcnt_t blockcnt,
7333 blk_t ref_block,
7334 int ref_offset,
7335 void *priv_data);
7336static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
7337static int htree_depth(struct dx_dir_info *dx_dir,
7338 struct dx_dirblock_info *dx_db);
7339static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
7340
7341struct check_dir_struct {
7342 char *buf;
7343 struct problem_context pctx;
7344 int count, max;
7345 e2fsck_t ctx;
7346};
7347
7348void e2fsck_pass2(e2fsck_t ctx)
7349{
7350 struct ext2_super_block *sb = ctx->fs->super;
7351 struct problem_context pctx;
7352 ext2_filsys fs = ctx->fs;
7353 char *buf;
7354#ifdef RESOURCE_TRACK
7355 struct resource_track rtrack;
7356#endif
7357 struct dir_info *dir;
7358 struct check_dir_struct cd;
7359 struct dx_dir_info *dx_dir;
7360 struct dx_dirblock_info *dx_db, *dx_parent;
7361 int b;
7362 int i, depth;
7363 problem_t code;
7364 int bad_dir;
7365
7366#ifdef RESOURCE_TRACK
7367 init_resource_track(&rtrack);
7368#endif
7369
7370 clear_problem_context(&cd.pctx);
7371
7372#ifdef MTRACE
7373 mtrace_print("Pass 2");
7374#endif
7375
7376 if (!(ctx->options & E2F_OPT_PREEN))
7377 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
7378
7379 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
7380 0, ctx->inode_link_info,
7381 &ctx->inode_count);
7382 if (cd.pctx.errcode) {
7383 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
7384 ctx->flags |= E2F_FLAG_ABORT;
7385 return;
7386 }
7387 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
7388 "directory scan buffer");
7389
7390 /*
7391 * Set up the parent pointer for the root directory, if
7392 * present. (If the root directory is not present, we will
7393 * create it in pass 3.)
7394 */
7395 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
7396 if (dir)
7397 dir->parent = EXT2_ROOT_INO;
7398
7399 cd.buf = buf;
7400 cd.ctx = ctx;
7401 cd.count = 1;
7402 cd.max = ext2fs_dblist_count(fs->dblist);
7403
7404 if (ctx->progress)
7405 (void) (ctx->progress)(ctx, 2, 0, cd.max);
7406
7407 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
7408 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
7409
7410 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
7411 &cd);
7412 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7413 return;
7414 if (cd.pctx.errcode) {
7415 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
7416 ctx->flags |= E2F_FLAG_ABORT;
7417 return;
7418 }
7419
7420#ifdef ENABLE_HTREE
7421 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
7422 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7423 return;
7424 if (dx_dir->numblocks == 0)
7425 continue;
7426 clear_problem_context(&pctx);
7427 bad_dir = 0;
7428 pctx.dir = dx_dir->ino;
7429 dx_db = dx_dir->dx_block;
7430 if (dx_db->flags & DX_FLAG_REFERENCED)
7431 dx_db->flags |= DX_FLAG_DUP_REF;
7432 else
7433 dx_db->flags |= DX_FLAG_REFERENCED;
7434 /*
7435 * Find all of the first and last leaf blocks, and
7436 * update their parent's min and max hash values
7437 */
7438 for (b=0, dx_db = dx_dir->dx_block;
7439 b < dx_dir->numblocks;
7440 b++, dx_db++) {
7441 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
7442 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
7443 continue;
7444 dx_parent = &dx_dir->dx_block[dx_db->parent];
7445 /*
7446 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
7447 */
7448 if (dx_db->flags & DX_FLAG_FIRST)
7449 dx_parent->min_hash = dx_db->min_hash;
7450 /*
7451 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
7452 */
7453 if (dx_db->flags & DX_FLAG_LAST)
7454 dx_parent->max_hash = dx_db->max_hash;
7455 }
7456
7457 for (b=0, dx_db = dx_dir->dx_block;
7458 b < dx_dir->numblocks;
7459 b++, dx_db++) {
7460 pctx.blkcount = b;
7461 pctx.group = dx_db->parent;
7462 code = 0;
7463 if (!(dx_db->flags & DX_FLAG_FIRST) &&
7464 (dx_db->min_hash < dx_db->node_min_hash)) {
7465 pctx.blk = dx_db->min_hash;
7466 pctx.blk2 = dx_db->node_min_hash;
7467 code = PR_2_HTREE_MIN_HASH;
7468 fix_problem(ctx, code, &pctx);
7469 bad_dir++;
7470 }
7471 if (dx_db->type == DX_DIRBLOCK_LEAF) {
7472 depth = htree_depth(dx_dir, dx_db);
7473 if (depth != dx_dir->depth) {
7474 code = PR_2_HTREE_BAD_DEPTH;
7475 fix_problem(ctx, code, &pctx);
7476 bad_dir++;
7477 }
7478 }
7479 /*
7480 * This test doesn't apply for the root block
7481 * at block #0
7482 */
7483 if (b &&
7484 (dx_db->max_hash > dx_db->node_max_hash)) {
7485 pctx.blk = dx_db->max_hash;
7486 pctx.blk2 = dx_db->node_max_hash;
7487 code = PR_2_HTREE_MAX_HASH;
7488 fix_problem(ctx, code, &pctx);
7489 bad_dir++;
7490 }
7491 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
7492 code = PR_2_HTREE_NOTREF;
7493 fix_problem(ctx, code, &pctx);
7494 bad_dir++;
7495 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
7496 code = PR_2_HTREE_DUPREF;
7497 fix_problem(ctx, code, &pctx);
7498 bad_dir++;
7499 }
7500 if (code == 0)
7501 continue;
7502 }
7503 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
7504 clear_htree(ctx, dx_dir->ino);
7505 dx_dir->numblocks = 0;
7506 }
7507 }
7508#endif
7509 ext2fs_free_mem(&buf);
7510 ext2fs_free_dblist(fs->dblist);
7511
7512 if (ctx->inode_bad_map) {
7513 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
7514 ctx->inode_bad_map = 0;
7515 }
7516 if (ctx->inode_reg_map) {
7517 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
7518 ctx->inode_reg_map = 0;
7519 }
7520
7521 clear_problem_context(&pctx);
7522 if (ctx->large_files) {
7523 if (!(sb->s_feature_ro_compat &
7524 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
7525 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
7526 sb->s_feature_ro_compat |=
7527 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7528 ext2fs_mark_super_dirty(fs);
7529 }
7530 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
7531 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
7532 ext2fs_update_dynamic_rev(fs);
7533 ext2fs_mark_super_dirty(fs);
7534 }
7535 } else if (!ctx->large_files &&
7536 (sb->s_feature_ro_compat &
7537 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
7538 if (fs->flags & EXT2_FLAG_RW) {
7539 sb->s_feature_ro_compat &=
7540 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
7541 ext2fs_mark_super_dirty(fs);
7542 }
7543 }
7544
7545#ifdef RESOURCE_TRACK
7546 if (ctx->options & E2F_OPT_TIME2) {
7547 e2fsck_clear_progbar(ctx);
7548 print_resource_track(_("Pass 2"), &rtrack);
7549 }
7550#endif
7551}
7552
7553#define MAX_DEPTH 32000
7554static int htree_depth(struct dx_dir_info *dx_dir,
7555 struct dx_dirblock_info *dx_db)
7556{
7557 int depth = 0;
7558
7559 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
7560 dx_db = &dx_dir->dx_block[dx_db->parent];
7561 depth++;
7562 }
7563 return depth;
7564}
7565
7566static int dict_de_cmp(const void *a, const void *b)
7567{
7568 const struct ext2_dir_entry *de_a, *de_b;
7569 int a_len, b_len;
7570
7571 de_a = (const struct ext2_dir_entry *) a;
7572 a_len = de_a->name_len & 0xFF;
7573 de_b = (const struct ext2_dir_entry *) b;
7574 b_len = de_b->name_len & 0xFF;
7575
7576 if (a_len != b_len)
7577 return (a_len - b_len);
7578
7579 return strncmp(de_a->name, de_b->name, a_len);
7580}
7581
7582/*
7583 * This is special sort function that makes sure that directory blocks
7584 * with a dirblock of zero are sorted to the beginning of the list.
7585 * This guarantees that the root node of the htree directories are
7586 * processed first, so we know what hash version to use.
7587 */
7588static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
7589{
7590 const struct ext2_db_entry *db_a =
7591 (const struct ext2_db_entry *) a;
7592 const struct ext2_db_entry *db_b =
7593 (const struct ext2_db_entry *) b;
7594
7595 if (db_a->blockcnt && !db_b->blockcnt)
7596 return 1;
7597
7598 if (!db_a->blockcnt && db_b->blockcnt)
7599 return -1;
7600
7601 if (db_a->blk != db_b->blk)
7602 return (int) (db_a->blk - db_b->blk);
7603
7604 if (db_a->ino != db_b->ino)
7605 return (int) (db_a->ino - db_b->ino);
7606
7607 return (int) (db_a->blockcnt - db_b->blockcnt);
7608}
7609
7610
7611/*
7612 * Make sure the first entry in the directory is '.', and that the
7613 * directory entry is sane.
7614 */
7615static int check_dot(e2fsck_t ctx,
7616 struct ext2_dir_entry *dirent,
7617 ext2_ino_t ino, struct problem_context *pctx)
7618{
7619 struct ext2_dir_entry *nextdir;
7620 int status = 0;
7621 int created = 0;
7622 int new_len;
7623 int problem = 0;
7624
7625 if (!dirent->inode)
7626 problem = PR_2_MISSING_DOT;
7627 else if (((dirent->name_len & 0xFF) != 1) ||
7628 (dirent->name[0] != '.'))
7629 problem = PR_2_1ST_NOT_DOT;
7630 else if (dirent->name[1] != '\0')
7631 problem = PR_2_DOT_NULL_TERM;
7632
7633 if (problem) {
7634 if (fix_problem(ctx, problem, pctx)) {
7635 if (dirent->rec_len < 12)
7636 dirent->rec_len = 12;
7637 dirent->inode = ino;
7638 dirent->name_len = 1;
7639 dirent->name[0] = '.';
7640 dirent->name[1] = '\0';
7641 status = 1;
7642 created = 1;
7643 }
7644 }
7645 if (dirent->inode != ino) {
7646 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
7647 dirent->inode = ino;
7648 status = 1;
7649 }
7650 }
7651 if (dirent->rec_len > 12) {
7652 new_len = dirent->rec_len - 12;
7653 if (new_len > 12) {
7654 if (created ||
7655 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
7656 nextdir = (struct ext2_dir_entry *)
7657 ((char *) dirent + 12);
7658 dirent->rec_len = 12;
7659 nextdir->rec_len = new_len;
7660 nextdir->inode = 0;
7661 nextdir->name_len = 0;
7662 status = 1;
7663 }
7664 }
7665 }
7666 return status;
7667}
7668
7669/*
7670 * Make sure the second entry in the directory is '..', and that the
7671 * directory entry is sane. We do not check the inode number of '..'
7672 * here; this gets done in pass 3.
7673 */
7674static int check_dotdot(e2fsck_t ctx,
7675 struct ext2_dir_entry *dirent,
7676 struct dir_info *dir, struct problem_context *pctx)
7677{
7678 int problem = 0;
7679
7680 if (!dirent->inode)
7681 problem = PR_2_MISSING_DOT_DOT;
7682 else if (((dirent->name_len & 0xFF) != 2) ||
7683 (dirent->name[0] != '.') ||
7684 (dirent->name[1] != '.'))
7685 problem = PR_2_2ND_NOT_DOT_DOT;
7686 else if (dirent->name[2] != '\0')
7687 problem = PR_2_DOT_DOT_NULL_TERM;
7688
7689 if (problem) {
7690 if (fix_problem(ctx, problem, pctx)) {
7691 if (dirent->rec_len < 12)
7692 dirent->rec_len = 12;
7693 /*
7694 * Note: we don't have the parent inode just
7695 * yet, so we will fill it in with the root
7696 * inode. This will get fixed in pass 3.
7697 */
7698 dirent->inode = EXT2_ROOT_INO;
7699 dirent->name_len = 2;
7700 dirent->name[0] = '.';
7701 dirent->name[1] = '.';
7702 dirent->name[2] = '\0';
7703 return 1;
7704 }
7705 return 0;
7706 }
7707 dir->dotdot = dirent->inode;
7708 return 0;
7709}
7710
7711/*
7712 * Check to make sure a directory entry doesn't contain any illegal
7713 * characters.
7714 */
7715static int check_name(e2fsck_t ctx,
7716 struct ext2_dir_entry *dirent,
7717 ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
7718 struct problem_context *pctx)
7719{
7720 int i;
7721 int fixup = -1;
7722 int ret = 0;
7723
7724 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
7725 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
7726 if (fixup < 0) {
7727 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
7728 }
7729 if (fixup) {
7730 dirent->name[i] = '.';
7731 ret = 1;
7732 }
7733 }
7734 }
7735 return ret;
7736}
7737
7738/*
7739 * Check the directory filetype (if present)
7740 */
7741static _INLINE_ int check_filetype(e2fsck_t ctx,
7742 struct ext2_dir_entry *dirent,
7743 ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
7744 struct problem_context *pctx)
7745{
7746 int filetype = dirent->name_len >> 8;
7747 int should_be = EXT2_FT_UNKNOWN;
7748 struct ext2_inode inode;
7749
7750 if (!(ctx->fs->super->s_feature_incompat &
7751 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
7752 if (filetype == 0 ||
7753 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
7754 return 0;
7755 dirent->name_len = dirent->name_len & 0xFF;
7756 return 1;
7757 }
7758
7759 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
7760 should_be = EXT2_FT_DIR;
7761 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
7762 dirent->inode)) {
7763 should_be = EXT2_FT_REG_FILE;
7764 } else if (ctx->inode_bad_map &&
7765 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
7766 dirent->inode))
7767 should_be = 0;
7768 else {
7769 e2fsck_read_inode(ctx, dirent->inode, &inode,
7770 "check_filetype");
7771 should_be = ext2_file_type(inode.i_mode);
7772 }
7773 if (filetype == should_be)
7774 return 0;
7775 pctx->num = should_be;
7776
7777 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
7778 pctx) == 0)
7779 return 0;
7780
7781 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
7782 return 1;
7783}
7784
7785#ifdef ENABLE_HTREE
7786static void parse_int_node(ext2_filsys fs,
7787 struct ext2_db_entry *db,
7788 struct check_dir_struct *cd,
7789 struct dx_dir_info *dx_dir,
7790 char *block_buf)
7791{
7792 struct ext2_dx_root_info *root;
7793 struct ext2_dx_entry *ent;
7794 struct ext2_dx_countlimit *limit;
7795 struct dx_dirblock_info *dx_db;
7796 int i, expect_limit, count;
7797 blk_t blk;
7798 ext2_dirhash_t min_hash = 0xffffffff;
7799 ext2_dirhash_t max_hash = 0;
7800 ext2_dirhash_t hash = 0, prev_hash;
7801
7802 if (db->blockcnt == 0) {
7803 root = (struct ext2_dx_root_info *) (block_buf + 24);
7804
7805#ifdef DX_DEBUG
7806 printf("Root node dump:\n");
7807 printf("\t Reserved zero: %d\n", root->reserved_zero);
7808 printf("\t Hash Version: %d\n", root->hash_version);
7809 printf("\t Info length: %d\n", root->info_length);
7810 printf("\t Indirect levels: %d\n", root->indirect_levels);
7811 printf("\t Flags: %d\n", root->unused_flags);
7812#endif
7813
7814 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
7815 } else {
7816 ent = (struct ext2_dx_entry *) (block_buf+8);
7817 }
7818 limit = (struct ext2_dx_countlimit *) ent;
7819
7820#ifdef DX_DEBUG
7821 printf("Number of entries (count): %d\n",
7822 ext2fs_le16_to_cpu(limit->count));
7823 printf("Number of entries (limit): %d\n",
7824 ext2fs_le16_to_cpu(limit->limit));
7825#endif
7826
7827 count = ext2fs_le16_to_cpu(limit->count);
7828 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
7829 sizeof(struct ext2_dx_entry);
7830 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
7831 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
7832 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
7833 goto clear_and_exit;
7834 }
7835 if (count > expect_limit) {
7836 cd->pctx.num = count;
7837 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
7838 goto clear_and_exit;
7839 count = expect_limit;
7840 }
7841
7842 for (i=0; i < count; i++) {
7843 prev_hash = hash;
7844 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
7845#ifdef DX_DEBUG
7846 printf("Entry #%d: Hash 0x%08x, block %d\n", i,
7847 hash, ext2fs_le32_to_cpu(ent[i].block));
7848#endif
7849 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
7850 /* Check to make sure the block is valid */
7851 if (blk > (blk_t) dx_dir->numblocks) {
7852 cd->pctx.blk = blk;
7853 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
7854 &cd->pctx))
7855 goto clear_and_exit;
7856 }
7857 if (hash < prev_hash &&
7858 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
7859 goto clear_and_exit;
7860 dx_db = &dx_dir->dx_block[blk];
7861 if (dx_db->flags & DX_FLAG_REFERENCED) {
7862 dx_db->flags |= DX_FLAG_DUP_REF;
7863 } else {
7864 dx_db->flags |= DX_FLAG_REFERENCED;
7865 dx_db->parent = db->blockcnt;
7866 }
7867 if (hash < min_hash)
7868 min_hash = hash;
7869 if (hash > max_hash)
7870 max_hash = hash;
7871 dx_db->node_min_hash = hash;
7872 if ((i+1) < count)
7873 dx_db->node_max_hash =
7874 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
7875 else {
7876 dx_db->node_max_hash = 0xfffffffe;
7877 dx_db->flags |= DX_FLAG_LAST;
7878 }
7879 if (i == 0)
7880 dx_db->flags |= DX_FLAG_FIRST;
7881 }
7882#ifdef DX_DEBUG
7883 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
7884 db->blockcnt, min_hash, max_hash);
7885#endif
7886 dx_db = &dx_dir->dx_block[db->blockcnt];
7887 dx_db->min_hash = min_hash;
7888 dx_db->max_hash = max_hash;
7889 return;
7890
7891clear_and_exit:
7892 clear_htree(cd->ctx, cd->pctx.ino);
7893 dx_dir->numblocks = 0;
7894}
7895#endif /* ENABLE_HTREE */
7896
7897/*
7898 * Given a busted directory, try to salvage it somehow.
7899 *
7900 */
7901static void salvage_directory(ext2_filsys fs,
7902 struct ext2_dir_entry *dirent,
7903 struct ext2_dir_entry *prev,
7904 unsigned int *offset)
7905{
7906 char *cp = (char *) dirent;
7907 int left = fs->blocksize - *offset - dirent->rec_len;
7908 int name_len = dirent->name_len & 0xFF;
7909
7910 /*
7911 * Special case of directory entry of size 8: copy what's left
7912 * of the directory block up to cover up the invalid hole.
7913 */
7914 if ((left >= 12) && (dirent->rec_len == 8)) {
7915 memmove(cp, cp+8, left);
7916 memset(cp + left, 0, 8);
7917 return;
7918 }
7919 /*
7920 * If the directory entry overruns the end of the directory
7921 * block, and the name is small enough to fit, then adjust the
7922 * record length.
7923 */
7924 if ((left < 0) &&
7925 (name_len + 8 <= dirent->rec_len + left) &&
7926 dirent->inode <= fs->super->s_inodes_count &&
7927 strnlen(dirent->name, name_len) == name_len) {
7928 dirent->rec_len += left;
7929 return;
7930 }
7931 /*
7932 * If the directory entry is a multiple of four, so it is
7933 * valid, let the previous directory entry absorb the invalid
7934 * one.
7935 */
7936 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
7937 prev->rec_len += dirent->rec_len;
7938 *offset += dirent->rec_len;
7939 return;
7940 }
7941 /*
7942 * Default salvage method --- kill all of the directory
7943 * entries for the rest of the block. We will either try to
7944 * absorb it into the previous directory entry, or create a
7945 * new empty directory entry the rest of the directory block.
7946 */
7947 if (prev) {
7948 prev->rec_len += fs->blocksize - *offset;
7949 *offset = fs->blocksize;
7950 } else {
7951 dirent->rec_len = fs->blocksize - *offset;
7952 dirent->name_len = 0;
7953 dirent->inode = 0;
7954 }
7955}
7956
7957static int check_dir_block(ext2_filsys fs,
7958 struct ext2_db_entry *db,
7959 void *priv_data)
7960{
7961 struct dir_info *subdir, *dir;
7962 struct dx_dir_info *dx_dir;
7963#ifdef ENABLE_HTREE
7964 struct dx_dirblock_info *dx_db = 0;
7965#endif /* ENABLE_HTREE */
7966 struct ext2_dir_entry *dirent, *prev;
7967 ext2_dirhash_t hash;
7968 unsigned int offset = 0;
7969 int dir_modified = 0;
7970 int dot_state;
7971 blk_t block_nr = db->blk;
7972 ext2_ino_t ino = db->ino;
7973 __u16 links;
7974 struct check_dir_struct *cd;
7975 char *buf;
7976 e2fsck_t ctx;
7977 int problem;
7978 struct ext2_dx_root_info *root;
7979 struct ext2_dx_countlimit *limit;
7980 static dict_t de_dict;
7981 struct problem_context pctx;
7982 int dups_found = 0;
7983
7984 cd = (struct check_dir_struct *) priv_data;
7985 buf = cd->buf;
7986 ctx = cd->ctx;
7987
7988 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
7989 return DIRENT_ABORT;
7990
7991 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
7992 return DIRENT_ABORT;
7993
7994 /*
7995 * Make sure the inode is still in use (could have been
7996 * deleted in the duplicate/bad blocks pass.
7997 */
7998 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
7999 return 0;
8000
8001 cd->pctx.ino = ino;
8002 cd->pctx.blk = block_nr;
8003 cd->pctx.blkcount = db->blockcnt;
8004 cd->pctx.ino2 = 0;
8005 cd->pctx.dirent = 0;
8006 cd->pctx.num = 0;
8007
8008 if (db->blk == 0) {
8009 if (allocate_dir_block(ctx, db, buf, &cd->pctx))
8010 return 0;
8011 block_nr = db->blk;
8012 }
8013
8014 if (db->blockcnt)
8015 dot_state = 2;
8016 else
8017 dot_state = 0;
8018
8019 if (ctx->dirs_to_hash &&
8020 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
8021 dups_found++;
8022
8023#if 0
8024 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
8025 db->blockcnt, ino);
8026#endif
8027
8028 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
8029 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
8030 cd->pctx.errcode = 0; /* We'll handle this ourselves */
8031 if (cd->pctx.errcode) {
8032 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
8033 ctx->flags |= E2F_FLAG_ABORT;
8034 return DIRENT_ABORT;
8035 }
8036 memset(buf, 0, fs->blocksize);
8037 }
8038#ifdef ENABLE_HTREE
8039 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
8040 if (dx_dir && dx_dir->numblocks) {
8041 if (db->blockcnt >= dx_dir->numblocks) {
8042 printf("XXX should never happen!!!\n");
8043 abort();
8044 }
8045 dx_db = &dx_dir->dx_block[db->blockcnt];
8046 dx_db->type = DX_DIRBLOCK_LEAF;
8047 dx_db->phys = block_nr;
8048 dx_db->min_hash = ~0;
8049 dx_db->max_hash = 0;
8050
8051 dirent = (struct ext2_dir_entry *) buf;
8052 limit = (struct ext2_dx_countlimit *) (buf+8);
8053 if (db->blockcnt == 0) {
8054 root = (struct ext2_dx_root_info *) (buf + 24);
8055 dx_db->type = DX_DIRBLOCK_ROOT;
8056 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
8057 if ((root->reserved_zero ||
8058 root->info_length < 8 ||
8059 root->indirect_levels > 1) &&
8060 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
8061 clear_htree(ctx, ino);
8062 dx_dir->numblocks = 0;
8063 dx_db = 0;
8064 }
8065 dx_dir->hashversion = root->hash_version;
8066 dx_dir->depth = root->indirect_levels + 1;
8067 } else if ((dirent->inode == 0) &&
8068 (dirent->rec_len == fs->blocksize) &&
8069 (dirent->name_len == 0) &&
8070 (ext2fs_le16_to_cpu(limit->limit) ==
8071 ((fs->blocksize-8) /
8072 sizeof(struct ext2_dx_entry))))
8073 dx_db->type = DX_DIRBLOCK_NODE;
8074 }
8075#endif /* ENABLE_HTREE */
8076
8077 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
8078 prev = 0;
8079 do {
8080 problem = 0;
8081 dirent = (struct ext2_dir_entry *) (buf + offset);
8082 cd->pctx.dirent = dirent;
8083 cd->pctx.num = offset;
8084 if (((offset + dirent->rec_len) > fs->blocksize) ||
8085 (dirent->rec_len < 12) ||
8086 ((dirent->rec_len % 4) != 0) ||
8087 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
8088 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
8089 salvage_directory(fs, dirent, prev, &offset);
8090 dir_modified++;
8091 continue;
8092 } else
8093 goto abort_free_dict;
8094 }
8095 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
8096 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
8097 dirent->name_len = EXT2_NAME_LEN;
8098 dir_modified++;
8099 }
8100 }
8101
8102 if (dot_state == 0) {
8103 if (check_dot(ctx, dirent, ino, &cd->pctx))
8104 dir_modified++;
8105 } else if (dot_state == 1) {
8106 dir = e2fsck_get_dir_info(ctx, ino);
8107 if (!dir) {
8108 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
8109 goto abort_free_dict;
8110 }
8111 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
8112 dir_modified++;
8113 } else if (dirent->inode == ino) {
8114 problem = PR_2_LINK_DOT;
8115 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
8116 dirent->inode = 0;
8117 dir_modified++;
8118 goto next;
8119 }
8120 }
8121 if (!dirent->inode)
8122 goto next;
8123
8124 /*
8125 * Make sure the inode listed is a legal one.
8126 */
8127 if (((dirent->inode != EXT2_ROOT_INO) &&
8128 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
8129 (dirent->inode > fs->super->s_inodes_count)) {
8130 problem = PR_2_BAD_INO;
8131 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
8132 dirent->inode))) {
8133 /*
8134 * If the inode is unused, offer to clear it.
8135 */
8136 problem = PR_2_UNUSED_INODE;
8137 } else if (ctx->inode_bb_map &&
8138 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
8139 dirent->inode))) {
8140 /*
8141 * If the inode is in a bad block, offer to
8142 * clear it.
8143 */
8144 problem = PR_2_BB_INODE;
8145 } else if ((dot_state > 1) &&
8146 ((dirent->name_len & 0xFF) == 1) &&
8147 (dirent->name[0] == '.')) {
8148 /*
8149 * If there's a '.' entry in anything other
8150 * than the first directory entry, it's a
8151 * duplicate entry that should be removed.
8152 */
8153 problem = PR_2_DUP_DOT;
8154 } else if ((dot_state > 1) &&
8155 ((dirent->name_len & 0xFF) == 2) &&
8156 (dirent->name[0] == '.') &&
8157 (dirent->name[1] == '.')) {
8158 /*
8159 * If there's a '..' entry in anything other
8160 * than the second directory entry, it's a
8161 * duplicate entry that should be removed.
8162 */
8163 problem = PR_2_DUP_DOT_DOT;
8164 } else if ((dot_state > 1) &&
8165 (dirent->inode == EXT2_ROOT_INO)) {
8166 /*
8167 * Don't allow links to the root directory.
8168 * We check this specially to make sure we
8169 * catch this error case even if the root
8170 * directory hasn't been created yet.
8171 */
8172 problem = PR_2_LINK_ROOT;
8173 } else if ((dot_state > 1) &&
8174 (dirent->name_len & 0xFF) == 0) {
8175 /*
8176 * Don't allow zero-length directory names.
8177 */
8178 problem = PR_2_NULL_NAME;
8179 }
8180
8181 if (problem) {
8182 if (fix_problem(ctx, problem, &cd->pctx)) {
8183 dirent->inode = 0;
8184 dir_modified++;
8185 goto next;
8186 } else {
8187 ext2fs_unmark_valid(fs);
8188 if (problem == PR_2_BAD_INO)
8189 goto next;
8190 }
8191 }
8192
8193 /*
8194 * If the inode was marked as having bad fields in
8195 * pass1, process it and offer to fix/clear it.
8196 * (We wait until now so that we can display the
8197 * pathname to the user.)
8198 */
8199 if (ctx->inode_bad_map &&
8200 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
8201 dirent->inode)) {
8202 if (e2fsck_process_bad_inode(ctx, ino,
8203 dirent->inode,
8204 buf + fs->blocksize)) {
8205 dirent->inode = 0;
8206 dir_modified++;
8207 goto next;
8208 }
8209 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8210 return DIRENT_ABORT;
8211 }
8212
8213 if (check_name(ctx, dirent, ino, &cd->pctx))
8214 dir_modified++;
8215
8216 if (check_filetype(ctx, dirent, ino, &cd->pctx))
8217 dir_modified++;
8218
8219#ifdef ENABLE_HTREE
8220 if (dx_db) {
8221 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
8222 (dirent->name_len & 0xFF),
8223 fs->super->s_hash_seed, &hash, 0);
8224 if (hash < dx_db->min_hash)
8225 dx_db->min_hash = hash;
8226 if (hash > dx_db->max_hash)
8227 dx_db->max_hash = hash;
8228 }
8229#endif
8230
8231 /*
8232 * If this is a directory, then mark its parent in its
8233 * dir_info structure. If the parent field is already
8234 * filled in, then this directory has more than one
8235 * hard link. We assume the first link is correct,
8236 * and ask the user if he/she wants to clear this one.
8237 */
8238 if ((dot_state > 1) &&
8239 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8240 dirent->inode))) {
8241 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
8242 if (!subdir) {
8243 cd->pctx.ino = dirent->inode;
8244 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
8245 goto abort_free_dict;
8246 }
8247 if (subdir->parent) {
8248 cd->pctx.ino2 = subdir->parent;
8249 if (fix_problem(ctx, PR_2_LINK_DIR,
8250 &cd->pctx)) {
8251 dirent->inode = 0;
8252 dir_modified++;
8253 goto next;
8254 }
8255 cd->pctx.ino2 = 0;
8256 } else
8257 subdir->parent = ino;
8258 }
8259
8260 if (dups_found) {
8261 ;
8262 } else if (dict_lookup(&de_dict, dirent)) {
8263 clear_problem_context(&pctx);
8264 pctx.ino = ino;
8265 pctx.dirent = dirent;
8266 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
8267 if (!ctx->dirs_to_hash)
8268 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
8269 if (ctx->dirs_to_hash)
8270 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8271 dups_found++;
8272 } else
8273 dict_alloc_insert(&de_dict, dirent, dirent);
8274
8275 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
8276 &links);
8277 if (links > 1)
8278 ctx->fs_links_count++;
8279 ctx->fs_total_count++;
8280 next:
8281 prev = dirent;
8282 offset += dirent->rec_len;
8283 dot_state++;
8284 } while (offset < fs->blocksize);
8285#if 0
8286 printf("\n");
8287#endif
8288#ifdef ENABLE_HTREE
8289 if (dx_db) {
8290#ifdef DX_DEBUG
8291 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
8292 db->blockcnt, dx_db->type,
8293 dx_db->min_hash, dx_db->max_hash);
8294#endif
8295 cd->pctx.dir = cd->pctx.ino;
8296 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
8297 (dx_db->type == DX_DIRBLOCK_NODE))
8298 parse_int_node(fs, db, cd, dx_dir, buf);
8299 }
8300#endif /* ENABLE_HTREE */
8301 if (offset != fs->blocksize) {
8302 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
8303 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
8304 dirent->rec_len = cd->pctx.num;
8305 dir_modified++;
8306 }
8307 }
8308 if (dir_modified) {
8309 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
8310 if (cd->pctx.errcode) {
8311 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
8312 &cd->pctx))
8313 goto abort_free_dict;
8314 }
8315 ext2fs_mark_changed(fs);
8316 }
8317 dict_free_nodes(&de_dict);
8318 return 0;
8319abort_free_dict:
8320 dict_free_nodes(&de_dict);
8321 ctx->flags |= E2F_FLAG_ABORT;
8322 return DIRENT_ABORT;
8323}
8324
8325/*
8326 * This function is called to deallocate a block, and is an interator
8327 * functioned called by deallocate inode via ext2fs_iterate_block().
8328 */
8329static int deallocate_inode_block(ext2_filsys fs,
8330 blk_t *block_nr,
8331 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
8332 blk_t ref_block EXT2FS_ATTR((unused)),
8333 int ref_offset EXT2FS_ATTR((unused)),
8334 void *priv_data)
8335{
8336 e2fsck_t ctx = (e2fsck_t) priv_data;
8337
8338 if (HOLE_BLKADDR(*block_nr))
8339 return 0;
8340 if ((*block_nr < fs->super->s_first_data_block) ||
8341 (*block_nr >= fs->super->s_blocks_count))
8342 return 0;
8343 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
8344 ext2fs_block_alloc_stats(fs, *block_nr, -1);
8345 return 0;
8346}
8347
8348/*
8349 * This fuction deallocates an inode
8350 */
8351static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
8352{
8353 ext2_filsys fs = ctx->fs;
8354 struct ext2_inode inode;
8355 struct problem_context pctx;
8356 __u32 count;
8357
8358 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
8359 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
8360 inode.i_links_count = 0;
8361 inode.i_dtime = time(0);
8362 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
8363 clear_problem_context(&pctx);
8364 pctx.ino = ino;
8365
8366 /*
8367 * Fix up the bitmaps...
8368 */
8369 e2fsck_read_bitmaps(ctx);
8370 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
8371 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
8372 if (ctx->inode_bad_map)
8373 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8374 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
8375
8376 if (inode.i_file_acl &&
8377 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
8378 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
8379 block_buf, -1, &count);
8380 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
8381 pctx.errcode = 0;
8382 count = 1;
8383 }
8384 if (pctx.errcode) {
8385 pctx.blk = inode.i_file_acl;
8386 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
8387 ctx->flags |= E2F_FLAG_ABORT;
8388 return;
8389 }
8390 if (count == 0) {
8391 ext2fs_unmark_block_bitmap(ctx->block_found_map,
8392 inode.i_file_acl);
8393 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
8394 }
8395 inode.i_file_acl = 0;
8396 }
8397
8398 if (!ext2fs_inode_has_valid_blocks(&inode))
8399 return;
8400
8401 if (LINUX_S_ISREG(inode.i_mode) &&
8402 (inode.i_size_high || inode.i_size & 0x80000000UL))
8403 ctx->large_files--;
8404
8405 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
8406 deallocate_inode_block, ctx);
8407 if (pctx.errcode) {
8408 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
8409 ctx->flags |= E2F_FLAG_ABORT;
8410 return;
8411 }
8412}
8413
8414/*
8415 * This fuction clears the htree flag on an inode
8416 */
8417static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
8418{
8419 struct ext2_inode inode;
8420
8421 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
8422 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
8423 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
8424 if (ctx->dirs_to_hash)
8425 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8426}
8427
8428
8429static int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
8430 ext2_ino_t ino, char *buf)
8431{
8432 ext2_filsys fs = ctx->fs;
8433 struct ext2_inode inode;
8434 int inode_modified = 0;
8435 int not_fixed = 0;
8436 unsigned char *frag, *fsize;
8437 struct problem_context pctx;
8438 int problem = 0;
8439
8440 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
8441
8442 clear_problem_context(&pctx);
8443 pctx.ino = ino;
8444 pctx.dir = dir;
8445 pctx.inode = &inode;
8446
8447 if (inode.i_file_acl &&
8448 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
8449 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
8450 inode.i_file_acl = 0;
8451#ifdef EXT2FS_ENABLE_SWAPFS
8452 /*
8453 * This is a special kludge to deal with long symlinks
8454 * on big endian systems. i_blocks had already been
8455 * decremented earlier in pass 1, but since i_file_acl
8456 * hadn't yet been cleared, ext2fs_read_inode()
8457 * assumed that the file was short symlink and would
8458 * not have byte swapped i_block[0]. Hence, we have
8459 * to byte-swap it here.
8460 */
8461 if (LINUX_S_ISLNK(inode.i_mode) &&
8462 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
8463 (inode.i_blocks == fs->blocksize >> 9))
8464 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
8465#endif
8466 inode_modified++;
8467 } else
8468 not_fixed++;
8469
8470 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
8471 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
8472 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
8473 !(LINUX_S_ISSOCK(inode.i_mode)))
8474 problem = PR_2_BAD_MODE;
8475 else if (LINUX_S_ISCHR(inode.i_mode)
8476 && !e2fsck_pass1_check_device_inode(fs, &inode))
8477 problem = PR_2_BAD_CHAR_DEV;
8478 else if (LINUX_S_ISBLK(inode.i_mode)
8479 && !e2fsck_pass1_check_device_inode(fs, &inode))
8480 problem = PR_2_BAD_BLOCK_DEV;
8481 else if (LINUX_S_ISFIFO(inode.i_mode)
8482 && !e2fsck_pass1_check_device_inode(fs, &inode))
8483 problem = PR_2_BAD_FIFO;
8484 else if (LINUX_S_ISSOCK(inode.i_mode)
8485 && !e2fsck_pass1_check_device_inode(fs, &inode))
8486 problem = PR_2_BAD_SOCKET;
8487 else if (LINUX_S_ISLNK(inode.i_mode)
8488 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
8489 problem = PR_2_INVALID_SYMLINK;
8490 }
8491
8492 if (problem) {
8493 if (fix_problem(ctx, problem, &pctx)) {
8494 deallocate_inode(ctx, ino, 0);
8495 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8496 return 0;
8497 return 1;
8498 } else
8499 not_fixed++;
8500 problem = 0;
8501 }
8502
8503 if (inode.i_faddr) {
8504 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
8505 inode.i_faddr = 0;
8506 inode_modified++;
8507 } else
8508 not_fixed++;
8509 }
8510
8511 switch (fs->super->s_creator_os) {
8512 case EXT2_OS_LINUX:
8513 frag = &inode.osd2.linux2.l_i_frag;
8514 fsize = &inode.osd2.linux2.l_i_fsize;
8515 break;
8516 case EXT2_OS_HURD:
8517 frag = &inode.osd2.hurd2.h_i_frag;
8518 fsize = &inode.osd2.hurd2.h_i_fsize;
8519 break;
8520 case EXT2_OS_MASIX:
8521 frag = &inode.osd2.masix2.m_i_frag;
8522 fsize = &inode.osd2.masix2.m_i_fsize;
8523 break;
8524 default:
8525 frag = fsize = 0;
8526 }
8527 if (frag && *frag) {
8528 pctx.num = *frag;
8529 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
8530 *frag = 0;
8531 inode_modified++;
8532 } else
8533 not_fixed++;
8534 pctx.num = 0;
8535 }
8536 if (fsize && *fsize) {
8537 pctx.num = *fsize;
8538 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
8539 *fsize = 0;
8540 inode_modified++;
8541 } else
8542 not_fixed++;
8543 pctx.num = 0;
8544 }
8545
8546 if (inode.i_file_acl &&
8547 ((inode.i_file_acl < fs->super->s_first_data_block) ||
8548 (inode.i_file_acl >= fs->super->s_blocks_count))) {
8549 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
8550 inode.i_file_acl = 0;
8551 inode_modified++;
8552 } else
8553 not_fixed++;
8554 }
8555 if (inode.i_dir_acl &&
8556 LINUX_S_ISDIR(inode.i_mode)) {
8557 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
8558 inode.i_dir_acl = 0;
8559 inode_modified++;
8560 } else
8561 not_fixed++;
8562 }
8563
8564 if (inode_modified)
8565 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
8566 if (!not_fixed)
8567 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
8568 return 0;
8569}
8570
8571
8572/*
8573 * allocate_dir_block --- this function allocates a new directory
8574 * block for a particular inode; this is done if a directory has
8575 * a "hole" in it, or if a directory has a illegal block number
8576 * that was zeroed out and now needs to be replaced.
8577 */
8578static int allocate_dir_block(e2fsck_t ctx,
8579 struct ext2_db_entry *db,
8580 char *buf EXT2FS_ATTR((unused)),
8581 struct problem_context *pctx)
8582{
8583 ext2_filsys fs = ctx->fs;
8584 blk_t blk;
8585 char *block;
8586 struct ext2_inode inode;
8587
8588 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
8589 return 1;
8590
8591 /*
8592 * Read the inode and block bitmaps in; we'll be messing with
8593 * them.
8594 */
8595 e2fsck_read_bitmaps(ctx);
8596
8597 /*
8598 * First, find a free block
8599 */
8600 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8601 if (pctx->errcode) {
8602 pctx->str = "ext2fs_new_block";
8603 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8604 return 1;
8605 }
8606 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8607 ext2fs_mark_block_bitmap(fs->block_map, blk);
8608 ext2fs_mark_bb_dirty(fs);
8609
8610 /*
8611 * Now let's create the actual data block for the inode
8612 */
8613 if (db->blockcnt)
8614 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
8615 else
8616 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
8617 EXT2_ROOT_INO, &block);
8618
8619 if (pctx->errcode) {
8620 pctx->str = "ext2fs_new_dir_block";
8621 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8622 return 1;
8623 }
8624
8625 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
8626 ext2fs_free_mem(&block);
8627 if (pctx->errcode) {
8628 pctx->str = "ext2fs_write_dir_block";
8629 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8630 return 1;
8631 }
8632
8633 /*
8634 * Update the inode block count
8635 */
8636 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
8637 inode.i_blocks += fs->blocksize / 512;
8638 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
8639 inode.i_size = (db->blockcnt+1) * fs->blocksize;
8640 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
8641
8642 /*
8643 * Finally, update the block pointers for the inode
8644 */
8645 db->blk = blk;
8646 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
8647 0, update_dir_block, db);
8648 if (pctx->errcode) {
8649 pctx->str = "ext2fs_block_iterate";
8650 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
8651 return 1;
8652 }
8653
8654 return 0;
8655}
8656
8657/*
8658 * This is a helper function for allocate_dir_block().
8659 */
8660static int update_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
8661 blk_t *block_nr,
8662 e2_blkcnt_t blockcnt,
8663 blk_t ref_block EXT2FS_ATTR((unused)),
8664 int ref_offset EXT2FS_ATTR((unused)),
8665 void *priv_data)
8666{
8667 struct ext2_db_entry *db;
8668
8669 db = (struct ext2_db_entry *) priv_data;
8670 if (db->blockcnt == (int) blockcnt) {
8671 *block_nr = db->blk;
8672 return BLOCK_CHANGED;
8673 }
8674 return 0;
8675}
8676/*
8677 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
8678 *
8679 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
8680 *
8681 * %Begin-Header%
8682 * This file may be redistributed under the terms of the GNU Public
8683 * License.
8684 * %End-Header%
8685 *
8686 * Pass #3 assures that all directories are connected to the
8687 * filesystem tree, using the following algorithm:
8688 *
8689 * First, the root directory is checked to make sure it exists; if
8690 * not, e2fsck will offer to create a new one. It is then marked as
8691 * "done".
8692 *
8693 * Then, pass3 interates over all directory inodes; for each directory
8694 * it attempts to trace up the filesystem tree, using dirinfo.parent
8695 * until it reaches a directory which has been marked "done". If it
8696 * can not do so, then the directory must be disconnected, and e2fsck
8697 * will offer to reconnect it to /lost+found. While it is chasing
8698 * parent pointers up the filesystem tree, if pass3 sees a directory
8699 * twice, then it has detected a filesystem loop, and it will again
8700 * offer to reconnect the directory to /lost+found in to break the
8701 * filesystem loop.
8702 *
8703 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
8704 * reconnect inodes to /lost+found; this subroutine is also used by
8705 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
8706 * is responsible for creating /lost+found if it does not exist.
8707 *
8708 * Pass 3 frees the following data structures:
8709 * - The dirinfo directory information cache.
8710 */
8711
8712static void check_root(e2fsck_t ctx);
8713static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8714 struct problem_context *pctx);
8715static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
8716
8717static ext2fs_inode_bitmap inode_loop_detect = 0;
8718static ext2fs_inode_bitmap inode_done_map = 0;
8719
8720void e2fsck_pass3(e2fsck_t ctx)
8721{
8722 ext2_filsys fs = ctx->fs;
8723 int i;
8724#ifdef RESOURCE_TRACK
8725 struct resource_track rtrack;
8726#endif
8727 struct problem_context pctx;
8728 struct dir_info *dir;
8729 unsigned long maxdirs, count;
8730
8731#ifdef RESOURCE_TRACK
8732 init_resource_track(&rtrack);
8733#endif
8734
8735 clear_problem_context(&pctx);
8736
8737#ifdef MTRACE
8738 mtrace_print("Pass 3");
8739#endif
8740
8741 if (!(ctx->options & E2F_OPT_PREEN))
8742 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
8743
8744 /*
8745 * Allocate some bitmaps to do loop detection.
8746 */
8747 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
8748 &inode_done_map);
8749 if (pctx.errcode) {
8750 pctx.num = 2;
8751 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
8752 ctx->flags |= E2F_FLAG_ABORT;
8753 goto abort_exit;
8754 }
8755#ifdef RESOURCE_TRACK
8756 if (ctx->options & E2F_OPT_TIME) {
8757 e2fsck_clear_progbar(ctx);
8758 print_resource_track(_("Peak memory"), &ctx->global_rtrack);
8759 }
8760#endif
8761
8762 check_root(ctx);
8763 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8764 goto abort_exit;
8765
8766 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
8767
8768 maxdirs = e2fsck_get_num_dirinfo(ctx);
8769 count = 1;
8770
8771 if (ctx->progress)
8772 if ((ctx->progress)(ctx, 3, 0, maxdirs))
8773 goto abort_exit;
8774
8775 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
8776 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
8777 goto abort_exit;
8778 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
8779 goto abort_exit;
8780 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
8781 if (check_directory(ctx, dir, &pctx))
8782 goto abort_exit;
8783 }
8784
8785 /*
8786 * Force the creation of /lost+found if not present
8787 */
8788 if ((ctx->flags & E2F_OPT_READONLY) == 0)
8789 e2fsck_get_lost_and_found(ctx, 1);
8790
8791 /*
8792 * If there are any directories that need to be indexed or
8793 * optimized, do it here.
8794 */
8795 e2fsck_rehash_directories(ctx);
8796
8797abort_exit:
8798 e2fsck_free_dir_info(ctx);
8799 if (inode_loop_detect) {
8800 ext2fs_free_inode_bitmap(inode_loop_detect);
8801 inode_loop_detect = 0;
8802 }
8803 if (inode_done_map) {
8804 ext2fs_free_inode_bitmap(inode_done_map);
8805 inode_done_map = 0;
8806 }
8807
8808#ifdef RESOURCE_TRACK
8809 if (ctx->options & E2F_OPT_TIME2) {
8810 e2fsck_clear_progbar(ctx);
8811 print_resource_track(_("Pass 3"), &rtrack);
8812 }
8813#endif
8814}
8815
8816/*
8817 * This makes sure the root inode is present; if not, we ask if the
8818 * user wants us to create it. Not creating it is a fatal error.
8819 */
8820static void check_root(e2fsck_t ctx)
8821{
8822 ext2_filsys fs = ctx->fs;
8823 blk_t blk;
8824 struct ext2_inode inode;
8825 char * block;
8826 struct problem_context pctx;
8827
8828 clear_problem_context(&pctx);
8829
8830 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
8831 /*
8832 * If the root inode is not a directory, die here. The
8833 * user must have answered 'no' in pass1 when we
8834 * offered to clear it.
8835 */
8836 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
8837 EXT2_ROOT_INO))) {
8838 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
8839 ctx->flags |= E2F_FLAG_ABORT;
8840 }
8841 return;
8842 }
8843
8844 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
8845 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
8846 ctx->flags |= E2F_FLAG_ABORT;
8847 return;
8848 }
8849
8850 e2fsck_read_bitmaps(ctx);
8851
8852 /*
8853 * First, find a free block
8854 */
8855 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
8856 if (pctx.errcode) {
8857 pctx.str = "ext2fs_new_block";
8858 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8859 ctx->flags |= E2F_FLAG_ABORT;
8860 return;
8861 }
8862 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
8863 ext2fs_mark_block_bitmap(fs->block_map, blk);
8864 ext2fs_mark_bb_dirty(fs);
8865
8866 /*
8867 * Now let's create the actual data block for the inode
8868 */
8869 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
8870 &block);
8871 if (pctx.errcode) {
8872 pctx.str = "ext2fs_new_dir_block";
8873 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8874 ctx->flags |= E2F_FLAG_ABORT;
8875 return;
8876 }
8877
8878 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
8879 if (pctx.errcode) {
8880 pctx.str = "ext2fs_write_dir_block";
8881 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8882 ctx->flags |= E2F_FLAG_ABORT;
8883 return;
8884 }
8885 ext2fs_free_mem(&block);
8886
8887 /*
8888 * Set up the inode structure
8889 */
8890 memset(&inode, 0, sizeof(inode));
8891 inode.i_mode = 040755;
8892 inode.i_size = fs->blocksize;
8893 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
8894 inode.i_links_count = 2;
8895 inode.i_blocks = fs->blocksize / 512;
8896 inode.i_block[0] = blk;
8897
8898 /*
8899 * Write out the inode.
8900 */
8901 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
8902 if (pctx.errcode) {
8903 pctx.str = "ext2fs_write_inode";
8904 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
8905 ctx->flags |= E2F_FLAG_ABORT;
8906 return;
8907 }
8908
8909 /*
8910 * Miscellaneous bookkeeping...
8911 */
8912 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
8913 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
8914 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
8915
8916 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
8917 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
8918 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
8919 ext2fs_mark_ib_dirty(fs);
8920}
8921
8922/*
8923 * This subroutine is responsible for making sure that a particular
8924 * directory is connected to the root; if it isn't we trace it up as
8925 * far as we can go, and then offer to connect the resulting parent to
8926 * the lost+found. We have to do loop detection; if we ever discover
8927 * a loop, we treat that as a disconnected directory and offer to
8928 * reparent it to lost+found.
8929 *
8930 * However, loop detection is expensive, because for very large
8931 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
8932 * is non-trivial. Loops in filesystems are also a rare error case,
8933 * and we shouldn't optimize for error cases. So we try two passes of
8934 * the algorithm. The first time, we ignore loop detection and merely
8935 * increment a counter; if the counter exceeds some extreme threshold,
8936 * then we try again with the loop detection bitmap enabled.
8937 */
8938static int check_directory(e2fsck_t ctx, struct dir_info *dir,
8939 struct problem_context *pctx)
8940{
8941 ext2_filsys fs = ctx->fs;
8942 struct dir_info *p = dir;
8943 int loop_pass = 0, parent_count = 0;
8944
8945 if (!p)
8946 return 0;
8947
8948 while (1) {
8949 /*
8950 * Mark this inode as being "done"; by the time we
8951 * return from this function, the inode we either be
8952 * verified as being connected to the directory tree,
8953 * or we will have offered to reconnect this to
8954 * lost+found.
8955 *
8956 * If it was marked done already, then we've reached a
8957 * parent we've already checked.
8958 */
8959 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
8960 break;
8961
8962 /*
8963 * If this directory doesn't have a parent, or we've
8964 * seen the parent once already, then offer to
8965 * reparent it to lost+found
8966 */
8967 if (!p->parent ||
8968 (loop_pass &&
8969 (ext2fs_test_inode_bitmap(inode_loop_detect,
8970 p->parent)))) {
8971 pctx->ino = p->ino;
8972 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
8973 if (e2fsck_reconnect_file(ctx, pctx->ino))
8974 ext2fs_unmark_valid(fs);
8975 else {
8976 p = e2fsck_get_dir_info(ctx, pctx->ino);
8977 p->parent = ctx->lost_and_found;
8978 fix_dotdot(ctx, p, ctx->lost_and_found);
8979 }
8980 }
8981 break;
8982 }
8983 p = e2fsck_get_dir_info(ctx, p->parent);
8984 if (!p) {
8985 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
8986 return 0;
8987 }
8988 if (loop_pass) {
8989 ext2fs_mark_inode_bitmap(inode_loop_detect,
8990 p->ino);
8991 } else if (parent_count++ > 2048) {
8992 /*
8993 * If we've run into a path depth that's
8994 * greater than 2048, try again with the inode
8995 * loop bitmap turned on and start from the
8996 * top.
8997 */
8998 loop_pass = 1;
8999 if (inode_loop_detect)
9000 ext2fs_clear_inode_bitmap(inode_loop_detect);
9001 else {
9002 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
9003 if (pctx->errcode) {
9004 pctx->num = 1;
9005 fix_problem(ctx,
9006 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
9007 ctx->flags |= E2F_FLAG_ABORT;
9008 return -1;
9009 }
9010 }
9011 p = dir;
9012 }
9013 }
9014
9015 /*
9016 * Make sure that .. and the parent directory are the same;
9017 * offer to fix it if not.
9018 */
9019 if (dir->parent != dir->dotdot) {
9020 pctx->ino = dir->ino;
9021 pctx->ino2 = dir->dotdot;
9022 pctx->dir = dir->parent;
9023 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
9024 fix_dotdot(ctx, dir, dir->parent);
9025 }
9026 return 0;
9027}
9028
9029/*
9030 * This routine gets the lost_and_found inode, making it a directory
9031 * if necessary
9032 */
9033ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
9034{
9035 ext2_filsys fs = ctx->fs;
9036 ext2_ino_t ino;
9037 blk_t blk;
9038 errcode_t retval;
9039 struct ext2_inode inode;
9040 char * block;
9041 static const char name[] = "lost+found";
9042 struct problem_context pctx;
9043 struct dir_info *dirinfo;
9044
9045 if (ctx->lost_and_found)
9046 return ctx->lost_and_found;
9047
9048 clear_problem_context(&pctx);
9049
9050 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
9051 sizeof(name)-1, 0, &ino);
9052 if (retval && !fix)
9053 return 0;
9054 if (!retval) {
9055 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
9056 ctx->lost_and_found = ino;
9057 return ino;
9058 }
9059
9060 /* Lost+found isn't a directory! */
9061 if (!fix)
9062 return 0;
9063 pctx.ino = ino;
9064 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
9065 return 0;
9066
9067 /* OK, unlink the old /lost+found file. */
9068 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
9069 if (pctx.errcode) {
9070 pctx.str = "ext2fs_unlink";
9071 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9072 return 0;
9073 }
9074 dirinfo = e2fsck_get_dir_info(ctx, ino);
9075 if (dirinfo)
9076 dirinfo->parent = 0;
9077 e2fsck_adjust_inode_count(ctx, ino, -1);
9078 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
9079 pctx.errcode = retval;
9080 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
9081 }
9082 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
9083 return 0;
9084
9085 /*
9086 * Read the inode and block bitmaps in; we'll be messing with
9087 * them.
9088 */
9089 e2fsck_read_bitmaps(ctx);
9090
9091 /*
9092 * First, find a free block
9093 */
9094 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
9095 if (retval) {
9096 pctx.errcode = retval;
9097 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
9098 return 0;
9099 }
9100 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
9101 ext2fs_block_alloc_stats(fs, blk, +1);
9102
9103 /*
9104 * Next find a free inode.
9105 */
9106 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
9107 ctx->inode_used_map, &ino);
9108 if (retval) {
9109 pctx.errcode = retval;
9110 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
9111 return 0;
9112 }
9113 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
9114 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
9115 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
9116
9117 /*
9118 * Now let's create the actual data block for the inode
9119 */
9120 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
9121 if (retval) {
9122 pctx.errcode = retval;
9123 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
9124 return 0;
9125 }
9126
9127 retval = ext2fs_write_dir_block(fs, blk, block);
9128 ext2fs_free_mem(&block);
9129 if (retval) {
9130 pctx.errcode = retval;
9131 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
9132 return 0;
9133 }
9134
9135 /*
9136 * Set up the inode structure
9137 */
9138 memset(&inode, 0, sizeof(inode));
9139 inode.i_mode = 040700;
9140 inode.i_size = fs->blocksize;
9141 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
9142 inode.i_links_count = 2;
9143 inode.i_blocks = fs->blocksize / 512;
9144 inode.i_block[0] = blk;
9145
9146 /*
9147 * Next, write out the inode.
9148 */
9149 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
9150 if (pctx.errcode) {
9151 pctx.str = "ext2fs_write_inode";
9152 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9153 return 0;
9154 }
9155 /*
9156 * Finally, create the directory link
9157 */
9158 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
9159 if (pctx.errcode) {
9160 pctx.str = "ext2fs_link";
9161 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
9162 return 0;
9163 }
9164
9165 /*
9166 * Miscellaneous bookkeeping that needs to be kept straight.
9167 */
9168 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
9169 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
9170 ext2fs_icount_store(ctx->inode_count, ino, 2);
9171 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
9172 ctx->lost_and_found = ino;
9173#if 0
9174 printf("/lost+found created; inode #%lu\n", ino);
9175#endif
9176 return ino;
9177}
9178
9179/*
9180 * This routine will connect a file to lost+found
9181 */
9182int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
9183{
9184 ext2_filsys fs = ctx->fs;
9185 errcode_t retval;
9186 char name[80];
9187 struct problem_context pctx;
9188 struct ext2_inode inode;
9189 int file_type = 0;
9190
9191 clear_problem_context(&pctx);
9192 pctx.ino = ino;
9193
9194 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
9195 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
9196 ctx->bad_lost_and_found++;
9197 }
9198 if (ctx->bad_lost_and_found) {
9199 fix_problem(ctx, PR_3_NO_LPF, &pctx);
9200 return 1;
9201 }
9202
9203 sprintf(name, "#%u", ino);
9204 if (ext2fs_read_inode(fs, ino, &inode) == 0)
9205 file_type = ext2_file_type(inode.i_mode);
9206 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
9207 if (retval == EXT2_ET_DIR_NO_SPACE) {
9208 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
9209 return 1;
9210 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
9211 1, 0);
9212 if (retval) {
9213 pctx.errcode = retval;
9214 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
9215 return 1;
9216 }
9217 retval = ext2fs_link(fs, ctx->lost_and_found, name,
9218 ino, file_type);
9219 }
9220 if (retval) {
9221 pctx.errcode = retval;
9222 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
9223 return 1;
9224 }
9225 e2fsck_adjust_inode_count(ctx, ino, 1);
9226
9227 return 0;
9228}
9229
9230/*
9231 * Utility routine to adjust the inode counts on an inode.
9232 */
9233errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
9234{
9235 ext2_filsys fs = ctx->fs;
9236 errcode_t retval;
9237 struct ext2_inode inode;
9238
9239 if (!ino)
9240 return 0;
9241
9242 retval = ext2fs_read_inode(fs, ino, &inode);
9243 if (retval)
9244 return retval;
9245
9246#if 0
9247 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
9248 inode.i_links_count);
9249#endif
9250
9251 if (adj == 1) {
9252 ext2fs_icount_increment(ctx->inode_count, ino, 0);
9253 if (inode.i_links_count == (__u16) ~0)
9254 return 0;
9255 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
9256 inode.i_links_count++;
9257 } else if (adj == -1) {
9258 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
9259 if (inode.i_links_count == 0)
9260 return 0;
9261 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
9262 inode.i_links_count--;
9263 }
9264
9265 retval = ext2fs_write_inode(fs, ino, &inode);
9266 if (retval)
9267 return retval;
9268
9269 return 0;
9270}
9271
9272/*
9273 * Fix parent --- this routine fixes up the parent of a directory.
9274 */
9275struct fix_dotdot_struct {
9276 ext2_filsys fs;
9277 ext2_ino_t parent;
9278 int done;
9279 e2fsck_t ctx;
9280};
9281
9282static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
9283 int offset EXT2FS_ATTR((unused)),
9284 int blocksize EXT2FS_ATTR((unused)),
9285 char *buf EXT2FS_ATTR((unused)),
9286 void *priv_data)
9287{
9288 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
9289 errcode_t retval;
9290 struct problem_context pctx;
9291
9292 if ((dirent->name_len & 0xFF) != 2)
9293 return 0;
9294 if (strncmp(dirent->name, "..", 2))
9295 return 0;
9296
9297 clear_problem_context(&pctx);
9298
9299 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
9300 if (retval) {
9301 pctx.errcode = retval;
9302 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9303 }
9304 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
9305 if (retval) {
9306 pctx.errcode = retval;
9307 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
9308 }
9309 dirent->inode = fp->parent;
9310
9311 fp->done++;
9312 return DIRENT_ABORT | DIRENT_CHANGED;
9313}
9314
9315static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
9316{
9317 ext2_filsys fs = ctx->fs;
9318 errcode_t retval;
9319 struct fix_dotdot_struct fp;
9320 struct problem_context pctx;
9321
9322 fp.fs = fs;
9323 fp.parent = parent;
9324 fp.done = 0;
9325 fp.ctx = ctx;
9326
9327#if 0
9328 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
9329#endif
9330
9331 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
9332 0, fix_dotdot_proc, &fp);
9333 if (retval || !fp.done) {
9334 clear_problem_context(&pctx);
9335 pctx.ino = dir->ino;
9336 pctx.errcode = retval;
9337 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
9338 PR_3_FIX_PARENT_NOFIND, &pctx);
9339 ext2fs_unmark_valid(fs);
9340 }
9341 dir->dotdot = parent;
9342
9343 return;
9344}
9345
9346/*
9347 * These routines are responsible for expanding a /lost+found if it is
9348 * too small.
9349 */
9350
9351struct expand_dir_struct {
9352 int num;
9353 int guaranteed_size;
9354 int newblocks;
9355 int last_block;
9356 errcode_t err;
9357 e2fsck_t ctx;
9358};
9359
9360static int expand_dir_proc(ext2_filsys fs,
9361 blk_t *blocknr,
9362 e2_blkcnt_t blockcnt,
9363 blk_t ref_block EXT2FS_ATTR((unused)),
9364 int ref_offset EXT2FS_ATTR((unused)),
9365 void *priv_data)
9366{
9367 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
9368 blk_t new_blk;
9369 static blk_t last_blk = 0;
9370 char *block;
9371 errcode_t retval;
9372 e2fsck_t ctx;
9373
9374 ctx = es->ctx;
9375
9376 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
9377 return BLOCK_ABORT;
9378
9379 if (blockcnt > 0)
9380 es->last_block = blockcnt;
9381 if (*blocknr) {
9382 last_blk = *blocknr;
9383 return 0;
9384 }
9385 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
9386 &new_blk);
9387 if (retval) {
9388 es->err = retval;
9389 return BLOCK_ABORT;
9390 }
9391 if (blockcnt > 0) {
9392 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
9393 if (retval) {
9394 es->err = retval;
9395 return BLOCK_ABORT;
9396 }
9397 es->num--;
9398 retval = ext2fs_write_dir_block(fs, new_blk, block);
9399 } else {
9400 retval = ext2fs_get_mem(fs->blocksize, &block);
9401 if (retval) {
9402 es->err = retval;
9403 return BLOCK_ABORT;
9404 }
9405 memset(block, 0, fs->blocksize);
9406 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
9407 }
9408 if (retval) {
9409 es->err = retval;
9410 return BLOCK_ABORT;
9411 }
9412 ext2fs_free_mem(&block);
9413 *blocknr = new_blk;
9414 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
9415 ext2fs_block_alloc_stats(fs, new_blk, +1);
9416 es->newblocks++;
9417
9418 if (es->num == 0)
9419 return (BLOCK_CHANGED | BLOCK_ABORT);
9420 else
9421 return BLOCK_CHANGED;
9422}
9423
9424errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
9425 int num, int guaranteed_size)
9426{
9427 ext2_filsys fs = ctx->fs;
9428 errcode_t retval;
9429 struct expand_dir_struct es;
9430 struct ext2_inode inode;
9431
9432 if (!(fs->flags & EXT2_FLAG_RW))
9433 return EXT2_ET_RO_FILSYS;
9434
9435 /*
9436 * Read the inode and block bitmaps in; we'll be messing with
9437 * them.
9438 */
9439 e2fsck_read_bitmaps(ctx);
9440
9441 retval = ext2fs_check_directory(fs, dir);
9442 if (retval)
9443 return retval;
9444
9445 es.num = num;
9446 es.guaranteed_size = guaranteed_size;
9447 es.last_block = 0;
9448 es.err = 0;
9449 es.newblocks = 0;
9450 es.ctx = ctx;
9451
9452 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
9453 0, expand_dir_proc, &es);
9454
9455 if (es.err)
9456 return es.err;
9457
9458 /*
9459 * Update the size and block count fields in the inode.
9460 */
9461 retval = ext2fs_read_inode(fs, dir, &inode);
9462 if (retval)
9463 return retval;
9464
9465 inode.i_size = (es.last_block + 1) * fs->blocksize;
9466 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
9467
9468 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
9469
9470 return 0;
9471}
9472
9473/*
9474 * pass4.c -- pass #4 of e2fsck: Check reference counts
9475 *
9476 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
9477 *
9478 * %Begin-Header%
9479 * This file may be redistributed under the terms of the GNU Public
9480 * License.
9481 * %End-Header%
9482 *
9483 * Pass 4 frees the following data structures:
9484 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
9485 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
9486 */
9487
9488/*
9489 * This routine is called when an inode is not connected to the
9490 * directory tree.
9491 *
9492 * This subroutine returns 1 then the caller shouldn't bother with the
9493 * rest of the pass 4 tests.
9494 */
9495static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
9496{
9497 ext2_filsys fs = ctx->fs;
9498 struct ext2_inode inode;
9499 struct problem_context pctx;
9500
9501 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
9502 clear_problem_context(&pctx);
9503 pctx.ino = i;
9504 pctx.inode = &inode;
9505
9506 /*
9507 * Offer to delete any zero-length files that does not have
9508 * blocks. If there is an EA block, it might have useful
9509 * information, so we won't prompt to delete it, but let it be
9510 * reconnected to lost+found.
9511 */
9512 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
9513 LINUX_S_ISDIR(inode.i_mode))) {
9514 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
9515 ext2fs_icount_store(ctx->inode_link_info, i, 0);
9516 inode.i_links_count = 0;
9517 inode.i_dtime = time(0);
9518 e2fsck_write_inode(ctx, i, &inode,
9519 "disconnect_inode");
9520 /*
9521 * Fix up the bitmaps...
9522 */
9523 e2fsck_read_bitmaps(ctx);
9524 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
9525 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
9526 ext2fs_inode_alloc_stats2(fs, i, -1,
9527 LINUX_S_ISDIR(inode.i_mode));
9528 return 0;
9529 }
9530 }
9531
9532 /*
9533 * Prompt to reconnect.
9534 */
9535 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
9536 if (e2fsck_reconnect_file(ctx, i))
9537 ext2fs_unmark_valid(fs);
9538 } else {
9539 /*
9540 * If we don't attach the inode, then skip the
9541 * i_links_test since there's no point in trying to
9542 * force i_links_count to zero.
9543 */
9544 ext2fs_unmark_valid(fs);
9545 return 1;
9546 }
9547 return 0;
9548}
9549
9550
9551void e2fsck_pass4(e2fsck_t ctx)
9552{
9553 ext2_filsys fs = ctx->fs;
9554 ext2_ino_t i;
9555 struct ext2_inode inode;
9556#ifdef RESOURCE_TRACK
9557 struct resource_track rtrack;
9558#endif
9559 struct problem_context pctx;
9560 __u16 link_count, link_counted;
9561 char *buf = 0;
9562 int group, maxgroup;
9563
9564#ifdef RESOURCE_TRACK
9565 init_resource_track(&rtrack);
9566#endif
9567
9568#ifdef MTRACE
9569 mtrace_print("Pass 4");
9570#endif
9571
9572 clear_problem_context(&pctx);
9573
9574 if (!(ctx->options & E2F_OPT_PREEN))
9575 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
9576
9577 group = 0;
9578 maxgroup = fs->group_desc_count;
9579 if (ctx->progress)
9580 if ((ctx->progress)(ctx, 4, 0, maxgroup))
9581 return;
9582
9583 for (i=1; i <= fs->super->s_inodes_count; i++) {
9584 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9585 return;
9586 if ((i % fs->super->s_inodes_per_group) == 0) {
9587 group++;
9588 if (ctx->progress)
9589 if ((ctx->progress)(ctx, 4, group, maxgroup))
9590 return;
9591 }
9592 if (i == EXT2_BAD_INO ||
9593 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
9594 continue;
9595 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
9596 (ctx->inode_imagic_map &&
9597 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
9598 (ctx->inode_bb_map &&
9599 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
9600 continue;
9601 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
9602 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
9603 if (link_counted == 0) {
9604 if (!buf)
9605 buf = e2fsck_allocate_memory(ctx,
9606 fs->blocksize, "bad_inode buffer");
9607 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
9608 continue;
9609 if (disconnect_inode(ctx, i))
9610 continue;
9611 ext2fs_icount_fetch(ctx->inode_link_info, i,
9612 &link_count);
9613 ext2fs_icount_fetch(ctx->inode_count, i,
9614 &link_counted);
9615 }
9616 if (link_counted != link_count) {
9617 e2fsck_read_inode(ctx, i, &inode, "pass4");
9618 pctx.ino = i;
9619 pctx.inode = &inode;
9620 if (link_count != inode.i_links_count) {
9621 pctx.num = link_count;
9622 fix_problem(ctx,
9623 PR_4_INCONSISTENT_COUNT, &pctx);
9624 }
9625 pctx.num = link_counted;
9626 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
9627 inode.i_links_count = link_counted;
9628 e2fsck_write_inode(ctx, i, &inode, "pass4");
9629 }
9630 }
9631 }
9632 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
9633 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
9634 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
9635 ctx->inode_bb_map = 0;
9636 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
9637 ctx->inode_imagic_map = 0;
9638 if (buf)
9639 ext2fs_free_mem(&buf);
9640#ifdef RESOURCE_TRACK
9641 if (ctx->options & E2F_OPT_TIME2) {
9642 e2fsck_clear_progbar(ctx);
9643 print_resource_track(_("Pass 4"), &rtrack);
9644 }
9645#endif
9646}
9647
9648/*
9649 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
9650 *
9651 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
9652 *
9653 * %Begin-Header%
9654 * This file may be redistributed under the terms of the GNU Public
9655 * License.
9656 * %End-Header%
9657 *
9658 */
9659
9660static void check_block_bitmaps(e2fsck_t ctx);
9661static void check_inode_bitmaps(e2fsck_t ctx);
9662static void check_inode_end(e2fsck_t ctx);
9663static void check_block_end(e2fsck_t ctx);
9664
9665void e2fsck_pass5(e2fsck_t ctx)
9666{
9667#ifdef RESOURCE_TRACK
9668 struct resource_track rtrack;
9669#endif
9670 struct problem_context pctx;
9671
9672#ifdef MTRACE
9673 mtrace_print("Pass 5");
9674#endif
9675
9676#ifdef RESOURCE_TRACK
9677 init_resource_track(&rtrack);
9678#endif
9679
9680 clear_problem_context(&pctx);
9681
9682 if (!(ctx->options & E2F_OPT_PREEN))
9683 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
9684
9685 if (ctx->progress)
9686 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
9687 return;
9688
9689 e2fsck_read_bitmaps(ctx);
9690
9691 check_block_bitmaps(ctx);
9692 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9693 return;
9694 check_inode_bitmaps(ctx);
9695 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9696 return;
9697 check_inode_end(ctx);
9698 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9699 return;
9700 check_block_end(ctx);
9701 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
9702 return;
9703
9704 ext2fs_free_inode_bitmap(ctx->inode_used_map);
9705 ctx->inode_used_map = 0;
9706 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
9707 ctx->inode_dir_map = 0;
9708 ext2fs_free_block_bitmap(ctx->block_found_map);
9709 ctx->block_found_map = 0;
9710
9711#ifdef RESOURCE_TRACK
9712 if (ctx->options & E2F_OPT_TIME2) {
9713 e2fsck_clear_progbar(ctx);
9714 print_resource_track(_("Pass 5"), &rtrack);
9715 }
9716#endif
9717}
9718
9719#define NO_BLK ((blk_t) -1)
9720
9721static void print_bitmap_problem(e2fsck_t ctx, int problem,
9722 struct problem_context *pctx)
9723{
9724 switch (problem) {
9725 case PR_5_BLOCK_UNUSED:
9726 if (pctx->blk == pctx->blk2)
9727 pctx->blk2 = 0;
9728 else
9729 problem = PR_5_BLOCK_RANGE_UNUSED;
9730 break;
9731 case PR_5_BLOCK_USED:
9732 if (pctx->blk == pctx->blk2)
9733 pctx->blk2 = 0;
9734 else
9735 problem = PR_5_BLOCK_RANGE_USED;
9736 break;
9737 case PR_5_INODE_UNUSED:
9738 if (pctx->ino == pctx->ino2)
9739 pctx->ino2 = 0;
9740 else
9741 problem = PR_5_INODE_RANGE_UNUSED;
9742 break;
9743 case PR_5_INODE_USED:
9744 if (pctx->ino == pctx->ino2)
9745 pctx->ino2 = 0;
9746 else
9747 problem = PR_5_INODE_RANGE_USED;
9748 break;
9749 }
9750 fix_problem(ctx, problem, pctx);
9751 pctx->blk = pctx->blk2 = NO_BLK;
9752 pctx->ino = pctx->ino2 = 0;
9753}
9754
9755static void check_block_bitmaps(e2fsck_t ctx)
9756{
9757 ext2_filsys fs = ctx->fs;
9758 blk_t i;
9759 int *free_array;
9760 int group = 0;
9761 unsigned int blocks = 0;
9762 unsigned int free_blocks = 0;
9763 int group_free = 0;
9764 int actual, bitmap;
9765 struct problem_context pctx;
9766 int problem, save_problem, fixit, had_problem;
9767 errcode_t retval;
9768
9769 clear_problem_context(&pctx);
9770 free_array = (int *) e2fsck_allocate_memory(ctx,
9771 fs->group_desc_count * sizeof(int), "free block count array");
9772
9773 if ((fs->super->s_first_data_block <
9774 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
9775 (fs->super->s_blocks_count-1 >
9776 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
9777 pctx.num = 1;
9778 pctx.blk = fs->super->s_first_data_block;
9779 pctx.blk2 = fs->super->s_blocks_count -1;
9780 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
9781 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
9782 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9783
9784 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9785 return;
9786 }
9787
9788 if ((fs->super->s_first_data_block <
9789 ext2fs_get_block_bitmap_start(fs->block_map)) ||
9790 (fs->super->s_blocks_count-1 >
9791 ext2fs_get_block_bitmap_end(fs->block_map))) {
9792 pctx.num = 2;
9793 pctx.blk = fs->super->s_first_data_block;
9794 pctx.blk2 = fs->super->s_blocks_count -1;
9795 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
9796 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
9797 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9798
9799 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9800 return;
9801 }
9802
9803redo_counts:
9804 had_problem = 0;
9805 save_problem = 0;
9806 pctx.blk = pctx.blk2 = NO_BLK;
9807 for (i = fs->super->s_first_data_block;
9808 i < fs->super->s_blocks_count;
9809 i++) {
9810 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
9811 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
9812
9813 if (actual == bitmap)
9814 goto do_counts;
9815
9816 if (!actual && bitmap) {
9817 /*
9818 * Block not used, but marked in use in the bitmap.
9819 */
9820 problem = PR_5_BLOCK_UNUSED;
9821 } else {
9822 /*
9823 * Block used, but not marked in use in the bitmap.
9824 */
9825 problem = PR_5_BLOCK_USED;
9826 }
9827 if (pctx.blk == NO_BLK) {
9828 pctx.blk = pctx.blk2 = i;
9829 save_problem = problem;
9830 } else {
9831 if ((problem == save_problem) &&
9832 (pctx.blk2 == i-1))
9833 pctx.blk2++;
9834 else {
9835 print_bitmap_problem(ctx, save_problem, &pctx);
9836 pctx.blk = pctx.blk2 = i;
9837 save_problem = problem;
9838 }
9839 }
9840 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
9841 had_problem++;
9842
9843 do_counts:
9844 if (!bitmap) {
9845 group_free++;
9846 free_blocks++;
9847 }
9848 blocks ++;
9849 if ((blocks == fs->super->s_blocks_per_group) ||
9850 (i == fs->super->s_blocks_count-1)) {
9851 free_array[group] = group_free;
9852 group ++;
9853 blocks = 0;
9854 group_free = 0;
9855 if (ctx->progress)
9856 if ((ctx->progress)(ctx, 5, group,
9857 fs->group_desc_count*2))
9858 return;
9859 }
9860 }
9861 if (pctx.blk != NO_BLK)
9862 print_bitmap_problem(ctx, save_problem, &pctx);
9863 if (had_problem)
9864 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
9865 else
9866 fixit = -1;
9867 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
9868
9869 if (fixit == 1) {
9870 ext2fs_free_block_bitmap(fs->block_map);
9871 retval = ext2fs_copy_bitmap(ctx->block_found_map,
9872 &fs->block_map);
9873 if (retval) {
9874 clear_problem_context(&pctx);
9875 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
9876 ctx->flags |= E2F_FLAG_ABORT;
9877 return;
9878 }
9879 ext2fs_set_bitmap_padding(fs->block_map);
9880 ext2fs_mark_bb_dirty(fs);
9881
9882 /* Redo the counts */
9883 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
9884 memset(free_array, 0, fs->group_desc_count * sizeof(int));
9885 goto redo_counts;
9886 } else if (fixit == 0)
9887 ext2fs_unmark_valid(fs);
9888
9889 for (i = 0; i < fs->group_desc_count; i++) {
9890 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
9891 pctx.group = i;
9892 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
9893 pctx.blk2 = free_array[i];
9894
9895 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
9896 &pctx)) {
9897 fs->group_desc[i].bg_free_blocks_count =
9898 free_array[i];
9899 ext2fs_mark_super_dirty(fs);
9900 } else
9901 ext2fs_unmark_valid(fs);
9902 }
9903 }
9904 if (free_blocks != fs->super->s_free_blocks_count) {
9905 pctx.group = 0;
9906 pctx.blk = fs->super->s_free_blocks_count;
9907 pctx.blk2 = free_blocks;
9908
9909 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
9910 fs->super->s_free_blocks_count = free_blocks;
9911 ext2fs_mark_super_dirty(fs);
9912 } else
9913 ext2fs_unmark_valid(fs);
9914 }
9915 ext2fs_free_mem(&free_array);
9916}
9917
9918static void check_inode_bitmaps(e2fsck_t ctx)
9919{
9920 ext2_filsys fs = ctx->fs;
9921 ext2_ino_t i;
9922 unsigned int free_inodes = 0;
9923 int group_free = 0;
9924 int dirs_count = 0;
9925 int group = 0;
9926 unsigned int inodes = 0;
9927 int *free_array;
9928 int *dir_array;
9929 int actual, bitmap;
9930 errcode_t retval;
9931 struct problem_context pctx;
9932 int problem, save_problem, fixit, had_problem;
9933
9934 clear_problem_context(&pctx);
9935 free_array = (int *) e2fsck_allocate_memory(ctx,
9936 fs->group_desc_count * sizeof(int), "free inode count array");
9937
9938 dir_array = (int *) e2fsck_allocate_memory(ctx,
9939 fs->group_desc_count * sizeof(int), "directory count array");
9940
9941 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
9942 (fs->super->s_inodes_count >
9943 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
9944 pctx.num = 3;
9945 pctx.blk = 1;
9946 pctx.blk2 = fs->super->s_inodes_count;
9947 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
9948 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
9949 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9950
9951 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9952 return;
9953 }
9954 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
9955 (fs->super->s_inodes_count >
9956 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
9957 pctx.num = 4;
9958 pctx.blk = 1;
9959 pctx.blk2 = fs->super->s_inodes_count;
9960 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
9961 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
9962 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
9963
9964 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
9965 return;
9966 }
9967
9968redo_counts:
9969 had_problem = 0;
9970 save_problem = 0;
9971 pctx.ino = pctx.ino2 = 0;
9972 for (i = 1; i <= fs->super->s_inodes_count; i++) {
9973 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
9974 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
9975
9976 if (actual == bitmap)
9977 goto do_counts;
9978
9979 if (!actual && bitmap) {
9980 /*
9981 * Inode wasn't used, but marked in bitmap
9982 */
9983 problem = PR_5_INODE_UNUSED;
9984 } else /* if (actual && !bitmap) */ {
9985 /*
9986 * Inode used, but not in bitmap
9987 */
9988 problem = PR_5_INODE_USED;
9989 }
9990 if (pctx.ino == 0) {
9991 pctx.ino = pctx.ino2 = i;
9992 save_problem = problem;
9993 } else {
9994 if ((problem == save_problem) &&
9995 (pctx.ino2 == i-1))
9996 pctx.ino2++;
9997 else {
9998 print_bitmap_problem(ctx, save_problem, &pctx);
9999 pctx.ino = pctx.ino2 = i;
10000 save_problem = problem;
10001 }
10002 }
10003 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
10004 had_problem++;
10005
10006do_counts:
10007 if (!bitmap) {
10008 group_free++;
10009 free_inodes++;
10010 } else {
10011 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
10012 dirs_count++;
10013 }
10014 inodes++;
10015 if ((inodes == fs->super->s_inodes_per_group) ||
10016 (i == fs->super->s_inodes_count)) {
10017 free_array[group] = group_free;
10018 dir_array[group] = dirs_count;
10019 group ++;
10020 inodes = 0;
10021 group_free = 0;
10022 dirs_count = 0;
10023 if (ctx->progress)
10024 if ((ctx->progress)(ctx, 5,
10025 group + fs->group_desc_count,
10026 fs->group_desc_count*2))
10027 return;
10028 }
10029 }
10030 if (pctx.ino)
10031 print_bitmap_problem(ctx, save_problem, &pctx);
10032
10033 if (had_problem)
10034 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
10035 else
10036 fixit = -1;
10037 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
10038
10039 if (fixit == 1) {
10040 ext2fs_free_inode_bitmap(fs->inode_map);
10041 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
10042 &fs->inode_map);
10043 if (retval) {
10044 clear_problem_context(&pctx);
10045 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
10046 ctx->flags |= E2F_FLAG_ABORT;
10047 return;
10048 }
10049 ext2fs_set_bitmap_padding(fs->inode_map);
10050 ext2fs_mark_ib_dirty(fs);
10051
10052 /* redo counts */
10053 inodes = 0; free_inodes = 0; group_free = 0;
10054 dirs_count = 0; group = 0;
10055 memset(free_array, 0, fs->group_desc_count * sizeof(int));
10056 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
10057 goto redo_counts;
10058 } else if (fixit == 0)
10059 ext2fs_unmark_valid(fs);
10060
10061 for (i = 0; i < fs->group_desc_count; i++) {
10062 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
10063 pctx.group = i;
10064 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
10065 pctx.ino2 = free_array[i];
10066 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
10067 &pctx)) {
10068 fs->group_desc[i].bg_free_inodes_count =
10069 free_array[i];
10070 ext2fs_mark_super_dirty(fs);
10071 } else
10072 ext2fs_unmark_valid(fs);
10073 }
10074 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
10075 pctx.group = i;
10076 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
10077 pctx.ino2 = dir_array[i];
10078
10079 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
10080 &pctx)) {
10081 fs->group_desc[i].bg_used_dirs_count =
10082 dir_array[i];
10083 ext2fs_mark_super_dirty(fs);
10084 } else
10085 ext2fs_unmark_valid(fs);
10086 }
10087 }
10088 if (free_inodes != fs->super->s_free_inodes_count) {
10089 pctx.group = -1;
10090 pctx.ino = fs->super->s_free_inodes_count;
10091 pctx.ino2 = free_inodes;
10092
10093 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
10094 fs->super->s_free_inodes_count = free_inodes;
10095 ext2fs_mark_super_dirty(fs);
10096 } else
10097 ext2fs_unmark_valid(fs);
10098 }
10099 ext2fs_free_mem(&free_array);
10100 ext2fs_free_mem(&dir_array);
10101}
10102
10103static void check_inode_end(e2fsck_t ctx)
10104{
10105 ext2_filsys fs = ctx->fs;
10106 ext2_ino_t end, save_inodes_count, i;
10107 struct problem_context pctx;
10108
10109 clear_problem_context(&pctx);
10110
10111 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
10112 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
10113 &save_inodes_count);
10114 if (pctx.errcode) {
10115 pctx.num = 1;
10116 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
10117 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
10118 return;
10119 }
10120 if (save_inodes_count == end)
10121 return;
10122
10123 for (i = save_inodes_count + 1; i <= end; i++) {
10124 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
10125 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
10126 for (i = save_inodes_count + 1; i <= end; i++)
10127 ext2fs_mark_inode_bitmap(fs->inode_map,
10128 i);
10129 ext2fs_mark_ib_dirty(fs);
10130 } else
10131 ext2fs_unmark_valid(fs);
10132 break;
10133 }
10134 }
10135
10136 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
10137 save_inodes_count, 0);
10138 if (pctx.errcode) {
10139 pctx.num = 2;
10140 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
10141 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
10142 return;
10143 }
10144}
10145
10146static void check_block_end(e2fsck_t ctx)
10147{
10148 ext2_filsys fs = ctx->fs;
10149 blk_t end, save_blocks_count, i;
10150 struct problem_context pctx;
10151
10152 clear_problem_context(&pctx);
10153
10154 end = fs->block_map->start +
10155 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
10156 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
10157 &save_blocks_count);
10158 if (pctx.errcode) {
10159 pctx.num = 3;
10160 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
10161 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
10162 return;
10163 }
10164 if (save_blocks_count == end)
10165 return;
10166
10167 for (i = save_blocks_count + 1; i <= end; i++) {
10168 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
10169 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
10170 for (i = save_blocks_count + 1; i <= end; i++)
10171 ext2fs_mark_block_bitmap(fs->block_map,
10172 i);
10173 ext2fs_mark_bb_dirty(fs);
10174 } else
10175 ext2fs_unmark_valid(fs);
10176 break;
10177 }
10178 }
10179
10180 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
10181 save_blocks_count, 0);
10182 if (pctx.errcode) {
10183 pctx.num = 4;
10184 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
10185 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
10186 return;
10187 }
10188}
10189
10190
10191
10192/*
10193 * problem.c --- report filesystem problems to the user
10194 *
10195 * Copyright 1996, 1997 by Theodore Ts'o
10196 *
10197 * %Begin-Header%
10198 * This file may be redistributed under the terms of the GNU Public
10199 * License.
10200 * %End-Header%
10201 */
10202
10203#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
10204#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
10205#define PR_NO_DEFAULT 0x000004 /* Default to no */
10206#define PR_MSG_ONLY 0x000008 /* Print message only */
10207
10208/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
10209
10210#define PR_FATAL 0x001000 /* Fatal error */
10211#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
10212 /* ask another */
10213#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
10214#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
10215#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
10216#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
10217#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
10218
10219
10220#define PROMPT_NONE 0
10221#define PROMPT_FIX 1
10222#define PROMPT_CLEAR 2
10223#define PROMPT_RELOCATE 3
10224#define PROMPT_ALLOCATE 4
10225#define PROMPT_EXPAND 5
10226#define PROMPT_CONNECT 6
10227#define PROMPT_CREATE 7
10228#define PROMPT_SALVAGE 8
10229#define PROMPT_TRUNCATE 9
10230#define PROMPT_CLEAR_INODE 10
10231#define PROMPT_ABORT 11
10232#define PROMPT_SPLIT 12
10233#define PROMPT_CONTINUE 13
10234#define PROMPT_CLONE 14
10235#define PROMPT_DELETE 15
10236#define PROMPT_SUPPRESS 16
10237#define PROMPT_UNLINK 17
10238#define PROMPT_CLEAR_HTREE 18
10239#define PROMPT_RECREATE 19
10240#define PROMPT_NULL 20
10241
10242struct e2fsck_problem {
10243 problem_t e2p_code;
10244 const char * e2p_description;
10245 char prompt;
10246 int flags;
10247 problem_t second_code;
10248};
10249
10250struct latch_descr {
10251 int latch_code;
10252 problem_t question;
10253 problem_t end_message;
10254 int flags;
10255};
10256
10257/*
10258 * These are the prompts which are used to ask the user if they want
10259 * to fix a problem.
10260 */
10261static const char *prompt[] = {
10262 N_("(no prompt)"), /* 0 */
10263 N_("Fix"), /* 1 */
10264 N_("Clear"), /* 2 */
10265 N_("Relocate"), /* 3 */
10266 N_("Allocate"), /* 4 */
10267 N_("Expand"), /* 5 */
10268 N_("Connect to /lost+found"), /* 6 */
10269 N_("Create"), /* 7 */
10270 N_("Salvage"), /* 8 */
10271 N_("Truncate"), /* 9 */
10272 N_("Clear inode"), /* 10 */
10273 N_("Abort"), /* 11 */
10274 N_("Split"), /* 12 */
10275 N_("Continue"), /* 13 */
10276 N_("Clone duplicate/bad blocks"), /* 14 */
10277 N_("Delete file"), /* 15 */
10278 N_("Suppress messages"),/* 16 */
10279 N_("Unlink"), /* 17 */
10280 N_("Clear HTree index"),/* 18 */
10281 N_("Recreate"), /* 19 */
10282 "", /* 20 */
10283};
10284
10285/*
10286 * These messages are printed when we are preen mode and we will be
10287 * automatically fixing the problem.
10288 */
10289static const char *preen_msg[] = {
10290 N_("(NONE)"), /* 0 */
10291 N_("FIXED"), /* 1 */
10292 N_("CLEARED"), /* 2 */
10293 N_("RELOCATED"), /* 3 */
10294 N_("ALLOCATED"), /* 4 */
10295 N_("EXPANDED"), /* 5 */
10296 N_("RECONNECTED"), /* 6 */
10297 N_("CREATED"), /* 7 */
10298 N_("SALVAGED"), /* 8 */
10299 N_("TRUNCATED"), /* 9 */
10300 N_("INODE CLEARED"), /* 10 */
10301 N_("ABORTED"), /* 11 */
10302 N_("SPLIT"), /* 12 */
10303 N_("CONTINUING"), /* 13 */
10304 N_("DUPLICATE/BAD BLOCKS CLONED"), /* 14 */
10305 N_("FILE DELETED"), /* 15 */
10306 N_("SUPPRESSED"), /* 16 */
10307 N_("UNLINKED"), /* 17 */
10308 N_("HTREE INDEX CLEARED"),/* 18 */
10309 N_("WILL RECREATE"), /* 19 */
10310 "", /* 20 */
10311};
10312
10313static const struct e2fsck_problem problem_table[] = {
10314
10315 /* Pre-Pass 1 errors */
10316
10317 /* Block bitmap not in group */
10318 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
10319 PROMPT_RELOCATE, PR_LATCH_RELOC },
10320
10321 /* Inode bitmap not in group */
10322 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
10323 PROMPT_RELOCATE, PR_LATCH_RELOC },
10324
10325 /* Inode table not in group */
10326 { PR_0_ITABLE_NOT_GROUP,
10327 N_("@i table for @g %g is not in @g. (@b %b)\n"
10328 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
10329 PROMPT_RELOCATE, PR_LATCH_RELOC },
10330
10331 /* Superblock corrupt */
10332 { PR_0_SB_CORRUPT,
10333 N_("\nThe @S could not be read or does not describe a correct ext2\n"
10334 "@f. If the @v is valid and it really contains an ext2\n"
10335 "@f (and not swap or ufs or something else), then the @S\n"
10336 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
10337 " e2fsck -b %S <@v>\n\n"),
10338 PROMPT_NONE, PR_FATAL },
10339
10340 /* Filesystem size is wrong */
10341 { PR_0_FS_SIZE_WRONG,
10342 N_("The @f size (according to the @S) is %b @bs\n"
10343 "The physical size of the @v is %c @bs\n"
10344 "Either the @S or the partition table is likely to be corrupt!\n"),
10345 PROMPT_ABORT, 0 },
10346
10347 /* Fragments not supported */
10348 { PR_0_NO_FRAGMENTS,
10349 N_("@S @b_size = %b, fragsize = %c.\n"
10350 "This version of e2fsck does not support fragment sizes different\n"
10351 "from the @b size.\n"),
10352 PROMPT_NONE, PR_FATAL },
10353
10354 /* Bad blocks_per_group */
10355 { PR_0_BLOCKS_PER_GROUP,
10356 N_("@S @bs_per_group = %b, should have been %c\n"),
10357 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10358
10359 /* Bad first_data_block */
10360 { PR_0_FIRST_DATA_BLOCK,
10361 N_("@S first_data_@b = %b, should have been %c\n"),
10362 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10363
10364 /* Adding UUID to filesystem */
10365 { PR_0_ADD_UUID,
10366 N_("@f did not have a UUID; generating one.\n\n"),
10367 PROMPT_NONE, 0 },
10368
10369 /* Relocate hint */
10370 { PR_0_RELOCATE_HINT,
10371 N_("Note: if there is several inode or block bitmap blocks\n"
10372 "which require relocation, or one part of the inode table\n"
10373 "which must be moved, you may wish to try running e2fsck\n"
10374 "with the '-b %S' option first. The problem may lie only\n"
10375 "with the primary block group descriptor, and the backup\n"
10376 "block group descriptor may be OK.\n\n"),
10377 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
10378
10379 /* Miscellaneous superblock corruption */
10380 { PR_0_MISC_CORRUPT_SUPER,
10381 N_("Corruption found in @S. (%s = %N).\n"),
10382 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
10383
10384 /* Error determing physical device size of filesystem */
10385 { PR_0_GETSIZE_ERROR,
10386 N_("Error determining size of the physical @v: %m\n"),
10387 PROMPT_NONE, PR_FATAL },
10388
10389 /* Inode count in superblock is incorrect */
10390 { PR_0_INODE_COUNT_WRONG,
10391 N_("@i count in @S is %i, should be %j.\n"),
10392 PROMPT_FIX, 0 },
10393
10394 { PR_0_HURD_CLEAR_FILETYPE,
10395 N_("The Hurd does not support the filetype feature.\n"),
10396 PROMPT_CLEAR, 0 },
10397
10398 /* Journal inode is invalid */
10399 { PR_0_JOURNAL_BAD_INODE,
10400 N_("@S has a bad ext3 @j (@i %i).\n"),
10401 PROMPT_CLEAR, PR_PREEN_OK },
10402
10403 /* The external journal has (unsupported) multiple filesystems */
10404 { PR_0_JOURNAL_UNSUPP_MULTIFS,
10405 N_("External @j has multiple @f users (unsupported).\n"),
10406 PROMPT_NONE, PR_FATAL },
10407
10408 /* Can't find external journal */
10409 { PR_0_CANT_FIND_JOURNAL,
10410 N_("Can't find external @j\n"),
10411 PROMPT_NONE, PR_FATAL },
10412
10413 /* External journal has bad superblock */
10414 { PR_0_EXT_JOURNAL_BAD_SUPER,
10415 N_("External @j has bad @S\n"),
10416 PROMPT_NONE, PR_FATAL },
10417
10418 /* Superblock has a bad journal UUID */
10419 { PR_0_JOURNAL_BAD_UUID,
10420 N_("External @j does not support this @f\n"),
10421 PROMPT_NONE, PR_FATAL },
10422
10423 /* Journal has an unknown superblock type */
10424 { PR_0_JOURNAL_UNSUPP_SUPER,
10425 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
10426 "It is likely that your copy of e2fsck is old and/or doesn't "
10427 "support this @j format.\n"
10428 "It is also possible the @j @S is corrupt.\n"),
10429 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
10430
10431 /* Journal superblock is corrupt */
10432 { PR_0_JOURNAL_BAD_SUPER,
10433 N_("Ext3 @j @S is corrupt.\n"),
10434 PROMPT_FIX, PR_PREEN_OK },
10435
10436 /* Superblock flag should be cleared */
10437 { PR_0_JOURNAL_HAS_JOURNAL,
10438 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
10439 PROMPT_CLEAR, PR_PREEN_OK },
10440
10441 /* Superblock flag is incorrect */
10442 { PR_0_JOURNAL_RECOVER_SET,
10443 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
10444 PROMPT_CLEAR, PR_PREEN_OK },
10445
10446 /* Journal has data, but recovery flag is clear */
10447 { PR_0_JOURNAL_RECOVERY_CLEAR,
10448 N_("ext3 recovery flag clear, but @j has data.\n"),
10449 PROMPT_NONE, 0 },
10450
10451 /* Ask if we should clear the journal */
10452 { PR_0_JOURNAL_RESET_JOURNAL,
10453 N_("Clear @j"),
10454 PROMPT_NULL, PR_PREEN_NOMSG },
10455
10456 /* Ask if we should run the journal anyway */
10457 { PR_0_JOURNAL_RUN,
10458 N_("Run @j anyway"),
10459 PROMPT_NULL, 0 },
10460
10461 /* Run the journal by default */
10462 { PR_0_JOURNAL_RUN_DEFAULT,
10463 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
10464 PROMPT_NONE, 0 },
10465
10466 /* Clearing orphan inode */
10467 { PR_0_ORPHAN_CLEAR_INODE,
10468 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
10469 PROMPT_NONE, 0 },
10470
10471 /* Illegal block found in orphaned inode */
10472 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
10473 N_("@I @b #%B (%b) found in @o @i %i.\n"),
10474 PROMPT_NONE, 0 },
10475
10476 /* Already cleared block found in orphaned inode */
10477 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
10478 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
10479 PROMPT_NONE, 0 },
10480
10481 /* Illegal orphan inode in superblock */
10482 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
10483 N_("@I @o @i %i in @S.\n"),
10484 PROMPT_NONE, 0 },
10485
10486 /* Illegal inode in orphaned inode list */
10487 { PR_0_ORPHAN_ILLEGAL_INODE,
10488 N_("@I @i %i in @o @i list.\n"),
10489 PROMPT_NONE, 0 },
10490
10491 /* Filesystem revision is 0, but feature flags are set */
10492 { PR_0_FS_REV_LEVEL,
10493 "@f has feature flag(s) set, but is a revision 0 @f. ",
10494 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10495
10496 /* Journal superblock has an unknown read-only feature flag set */
10497 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
10498 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
10499 PROMPT_ABORT, 0 },
10500
10501 /* Journal superblock has an unknown incompatible feature flag set */
10502 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
10503 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
10504 PROMPT_ABORT, 0 },
10505
10506 /* Journal has unsupported version number */
10507 { PR_0_JOURNAL_UNSUPP_VERSION,
10508 N_("@j version not supported by this e2fsck.\n"),
10509 PROMPT_ABORT, 0 },
10510
10511 /* Moving journal to hidden file */
10512 { PR_0_MOVE_JOURNAL,
10513 N_("Moving @j from /%s to hidden inode.\n\n"),
10514 PROMPT_NONE, 0 },
10515
10516 /* Error moving journal to hidden file */
10517 { PR_0_ERR_MOVE_JOURNAL,
10518 N_("Error moving @j: %m\n\n"),
10519 PROMPT_NONE, 0 },
10520
10521 /* Clearing V2 journal superblock */
10522 { PR_0_CLEAR_V2_JOURNAL,
10523 N_("Found invalid V2 @j @S fields (from V1 journal).\n"
10524 "Clearing fields beyond the V1 @j @S...\n\n"),
10525 PROMPT_NONE, 0 },
10526
10527 /* Backup journal inode blocks */
10528 { PR_0_BACKUP_JNL,
10529 N_("Backing up @j @i @b information.\n\n"),
10530 PROMPT_NONE, 0 },
10531
10532 /* Reserved blocks w/o resize_inode */
10533 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
10534 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
10535 "is %N; @s zero. "),
10536 PROMPT_FIX, 0 },
10537
10538 /* Resize_inode not enabled, but resize inode is non-zero */
10539 { PR_0_CLEAR_RESIZE_INODE,
10540 N_("Resize_@i not enabled, but the resize inode is non-zero. "),
10541 PROMPT_CLEAR, 0 },
10542
10543 /* Resize inode invalid */
10544 { PR_0_RESIZE_INODE_INVALID,
10545 N_("Resize @i not valid. "),
10546 PROMPT_RECREATE, 0 },
10547
10548 /* Pass 1 errors */
10549
10550 /* Pass 1: Checking inodes, blocks, and sizes */
10551 { PR_1_PASS_HEADER,
10552 N_("Pass 1: Checking @is, @bs, and sizes\n"),
10553 PROMPT_NONE, 0 },
10554
10555 /* Root directory is not an inode */
10556 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
10557 PROMPT_CLEAR, 0 },
10558
10559 /* Root directory has dtime set */
10560 { PR_1_ROOT_DTIME,
10561 N_("@r has dtime set (probably due to old mke2fs). "),
10562 PROMPT_FIX, PR_PREEN_OK },
10563
10564 /* Reserved inode has bad mode */
10565 { PR_1_RESERVED_BAD_MODE,
10566 N_("Reserved @i %i %Q has bad mode. "),
10567 PROMPT_CLEAR, PR_PREEN_OK },
10568
10569 /* Deleted inode has zero dtime */
10570 { PR_1_ZERO_DTIME,
10571 N_("@D @i %i has zero dtime. "),
10572 PROMPT_FIX, PR_PREEN_OK },
10573
10574 /* Inode in use, but dtime set */
10575 { PR_1_SET_DTIME,
10576 N_("@i %i is in use, but has dtime set. "),
10577 PROMPT_FIX, PR_PREEN_OK },
10578
10579 /* Zero-length directory */
10580 { PR_1_ZERO_LENGTH_DIR,
10581 N_("@i %i is a @z @d. "),
10582 PROMPT_CLEAR, PR_PREEN_OK },
10583
10584 /* Block bitmap conflicts with some other fs block */
10585 { PR_1_BB_CONFLICT,
10586 N_("@g %g's @b @B at %b @C.\n"),
10587 PROMPT_RELOCATE, 0 },
10588
10589 /* Inode bitmap conflicts with some other fs block */
10590 { PR_1_IB_CONFLICT,
10591 N_("@g %g's @i @B at %b @C.\n"),
10592 PROMPT_RELOCATE, 0 },
10593
10594 /* Inode table conflicts with some other fs block */
10595 { PR_1_ITABLE_CONFLICT,
10596 N_("@g %g's @i table at %b @C.\n"),
10597 PROMPT_RELOCATE, 0 },
10598
10599 /* Block bitmap is on a bad block */
10600 { PR_1_BB_BAD_BLOCK,
10601 N_("@g %g's @b @B (%b) is bad. "),
10602 PROMPT_RELOCATE, 0 },
10603
10604 /* Inode bitmap is on a bad block */
10605 { PR_1_IB_BAD_BLOCK,
10606 N_("@g %g's @i @B (%b) is bad. "),
10607 PROMPT_RELOCATE, 0 },
10608
10609 /* Inode has incorrect i_size */
10610 { PR_1_BAD_I_SIZE,
10611 N_("@i %i, i_size is %Is, @s %N. "),
10612 PROMPT_FIX, PR_PREEN_OK },
10613
10614 /* Inode has incorrect i_blocks */
10615 { PR_1_BAD_I_BLOCKS,
10616 N_("@i %i, i_@bs is %Ib, @s %N. "),
10617 PROMPT_FIX, PR_PREEN_OK },
10618
10619 /* Illegal blocknumber in inode */
10620 { PR_1_ILLEGAL_BLOCK_NUM,
10621 N_("@I @b #%B (%b) in @i %i. "),
10622 PROMPT_CLEAR, PR_LATCH_BLOCK },
10623
10624 /* Block number overlaps fs metadata */
10625 { PR_1_BLOCK_OVERLAPS_METADATA,
10626 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
10627 PROMPT_CLEAR, PR_LATCH_BLOCK },
10628
10629 /* Inode has illegal blocks (latch question) */
10630 { PR_1_INODE_BLOCK_LATCH,
10631 N_("@i %i has illegal @b(s). "),
10632 PROMPT_CLEAR, 0 },
10633
10634 /* Too many bad blocks in inode */
10635 { PR_1_TOO_MANY_BAD_BLOCKS,
10636 N_("Too many illegal @bs in @i %i.\n"),
10637 PROMPT_CLEAR_INODE, PR_NO_OK },
10638
10639 /* Illegal block number in bad block inode */
10640 { PR_1_BB_ILLEGAL_BLOCK_NUM,
10641 N_("@I @b #%B (%b) in bad @b @i. "),
10642 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10643
10644 /* Bad block inode has illegal blocks (latch question) */
10645 { PR_1_INODE_BBLOCK_LATCH,
10646 N_("Bad @b @i has illegal @b(s). "),
10647 PROMPT_CLEAR, 0 },
10648
10649 /* Duplicate or bad blocks in use! */
10650 { PR_1_DUP_BLOCKS_PREENSTOP,
10651 N_("Duplicate or bad @b in use!\n"),
10652 PROMPT_NONE, 0 },
10653
10654 /* Bad block used as bad block indirect block */
10655 { PR_1_BBINODE_BAD_METABLOCK,
10656 N_("Bad @b %b used as bad @b @i indirect @b. "),
10657 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10658
10659 /* Inconsistency can't be fixed prompt */
10660 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
10661 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
10662 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
10663 "in the @f.\n"),
10664 PROMPT_CONTINUE, PR_PREEN_NOMSG },
10665
10666 /* Bad primary block */
10667 { PR_1_BAD_PRIMARY_BLOCK,
10668 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
10669 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
10670
10671 /* Bad primary block prompt */
10672 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
10673 N_("You can clear the this @b (and hope for the best) from the\n"
10674 "bad @b list and hope that @b is really OK, but there are no\n"
10675 "guarantees.\n\n"),
10676 PROMPT_CLEAR, PR_PREEN_NOMSG },
10677
10678 /* Bad primary superblock */
10679 { PR_1_BAD_PRIMARY_SUPERBLOCK,
10680 N_("The primary @S (%b) is on the bad @b list.\n"),
10681 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10682
10683 /* Bad primary block group descriptors */
10684 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
10685 N_("Block %b in the primary @g descriptors "
10686 "is on the bad @b list\n"),
10687 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
10688
10689 /* Bad superblock in group */
10690 { PR_1_BAD_SUPERBLOCK,
10691 N_("Warning: Group %g's @S (%b) is bad.\n"),
10692 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10693
10694 /* Bad block group descriptors in group */
10695 { PR_1_BAD_GROUP_DESCRIPTORS,
10696 N_("Warning: Group %g's copy of the @g descriptors has a bad "
10697 "@b (%b).\n"),
10698 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
10699
10700 /* Block claimed for no reason */
10701 { PR_1_PROGERR_CLAIMED_BLOCK,
10702 N_("Programming error? @b #%b claimed for no reason in "
10703 "process_bad_@b.\n"),
10704 PROMPT_NONE, PR_PREEN_OK },
10705
10706 /* Error allocating blocks for relocating metadata */
10707 { PR_1_RELOC_BLOCK_ALLOCATE,
10708 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
10709 PROMPT_NONE, PR_PREEN_OK },
10710
10711 /* Error allocating block buffer during relocation process */
10712 { PR_1_RELOC_MEMORY_ALLOCATE,
10713 N_("@A @b buffer for relocating %s\n"),
10714 PROMPT_NONE, PR_PREEN_OK },
10715
10716 /* Relocating metadata group information from X to Y */
10717 { PR_1_RELOC_FROM_TO,
10718 N_("Relocating @g %g's %s from %b to %c...\n"),
10719 PROMPT_NONE, PR_PREEN_OK },
10720
10721 /* Relocating metatdata group information to X */
10722 { PR_1_RELOC_TO,
10723 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
10724 PROMPT_NONE, PR_PREEN_OK },
10725
10726 /* Block read error during relocation process */
10727 { PR_1_RELOC_READ_ERR,
10728 N_("Warning: could not read @b %b of %s: %m\n"),
10729 PROMPT_NONE, PR_PREEN_OK },
10730
10731 /* Block write error during relocation process */
10732 { PR_1_RELOC_WRITE_ERR,
10733 N_("Warning: could not write @b %b for %s: %m\n"),
10734 PROMPT_NONE, PR_PREEN_OK },
10735
10736 /* Error allocating inode bitmap */
10737 { PR_1_ALLOCATE_IBITMAP_ERROR,
10738 "@A @i @B (%N): %m\n",
10739 PROMPT_NONE, PR_FATAL },
10740
10741 /* Error allocating block bitmap */
10742 { PR_1_ALLOCATE_BBITMAP_ERROR,
10743 "@A @b @B (%N): %m\n",
10744 PROMPT_NONE, PR_FATAL },
10745
10746 /* Error allocating icount structure */
10747 { PR_1_ALLOCATE_ICOUNT,
10748 N_("@A icount link information: %m\n"),
10749 PROMPT_NONE, PR_FATAL },
10750
10751 /* Error allocating dbcount */
10752 { PR_1_ALLOCATE_DBCOUNT,
10753 N_("@A @d @b array: %m\n"),
10754 PROMPT_NONE, PR_FATAL },
10755
10756 /* Error while scanning inodes */
10757 { PR_1_ISCAN_ERROR,
10758 N_("Error while scanning @is (%i): %m\n"),
10759 PROMPT_NONE, PR_FATAL },
10760
10761 /* Error while iterating over blocks */
10762 { PR_1_BLOCK_ITERATE,
10763 N_("Error while iterating over @bs in @i %i: %m\n"),
10764 PROMPT_NONE, PR_FATAL },
10765
10766 /* Error while storing inode count information */
10767 { PR_1_ICOUNT_STORE,
10768 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
10769 PROMPT_NONE, PR_FATAL },
10770
10771 /* Error while storing directory block information */
10772 { PR_1_ADD_DBLOCK,
10773 N_("Error storing @d @b information "
10774 "(@i=%i, @b=%b, num=%N): %m\n"),
10775 PROMPT_NONE, PR_FATAL },
10776
10777 /* Error while reading inode (for clearing) */
10778 { PR_1_READ_INODE,
10779 N_("Error reading @i %i: %m\n"),
10780 PROMPT_NONE, PR_FATAL },
10781
10782 /* Suppress messages prompt */
10783 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
10784
10785 /* Imagic flag set on an inode when filesystem doesn't support it */
10786 { PR_1_SET_IMAGIC,
10787 N_("@i %i has imagic flag set. "),
10788 PROMPT_CLEAR, 0 },
10789
10790 /* Immutable flag set on a device or socket inode */
10791 { PR_1_SET_IMMUTABLE,
10792 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
10793 "or append-only flag set. "),
10794 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
10795
10796 /* Compression flag set on an inode when filesystem doesn't support it */
10797 { PR_1_COMPR_SET,
10798 N_("@i %i has @cion flag set on @f without @cion support. "),
10799 PROMPT_CLEAR, 0 },
10800
10801 /* Non-zero size for device, fifo or socket inode */
10802 { PR_1_SET_NONZSIZE,
10803 "Special (@v/socket/fifo) @i %i has non-zero size. ",
10804 PROMPT_FIX, PR_PREEN_OK },
10805
10806 /* Filesystem revision is 0, but feature flags are set */
10807 { PR_1_FS_REV_LEVEL,
10808 "@f has feature flag(s) set, but is a revision 0 @f. ",
10809 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
10810
10811 /* Journal inode is not in use, but contains data */
10812 { PR_1_JOURNAL_INODE_NOT_CLEAR,
10813 "@j @i is not in use, but contains data. ",
10814 PROMPT_CLEAR, PR_PREEN_OK },
10815
10816 /* Journal has bad mode */
10817 { PR_1_JOURNAL_BAD_MODE,
10818 N_("@j is not regular file. "),
10819 PROMPT_FIX, PR_PREEN_OK },
10820
10821 /* Deal with inodes that were part of orphan linked list */
10822 { PR_1_LOW_DTIME,
10823 N_("@i %i was part of the orphaned @i list. "),
10824 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
10825
10826 /* Deal with inodes that were part of corrupted orphan linked
10827 list (latch question) */
10828 { PR_1_ORPHAN_LIST_REFUGEES,
10829 N_("@is that were part of a corrupted orphan linked list found. "),
10830 PROMPT_FIX, 0 },
10831
10832 /* Error allocating refcount structure */
10833 { PR_1_ALLOCATE_REFCOUNT,
10834 "@A refcount structure (%N): %m\n",
10835 PROMPT_NONE, PR_FATAL },
10836
10837 /* Error reading extended attribute block */
10838 { PR_1_READ_EA_BLOCK,
10839 N_("Error reading @a @b %b for @i %i. "),
10840 PROMPT_CLEAR, 0 },
10841
10842 /* Invalid extended attribute block */
10843 { PR_1_BAD_EA_BLOCK,
10844 N_("@i %i has a bad @a @b %b. "),
10845 PROMPT_CLEAR, 0 },
10846
10847 /* Error reading Extended Attribute block while fixing refcount */
10848 { PR_1_EXTATTR_READ_ABORT,
10849 N_("Error reading @a @b %b (%m). "),
10850 PROMPT_ABORT, 0 },
10851
10852 /* Extended attribute reference count incorrect */
10853 { PR_1_EXTATTR_REFCOUNT,
10854 N_("@a @b %b has reference count %B, should be %N. "),
10855 PROMPT_FIX, 0 },
10856
10857 /* Error writing Extended Attribute block while fixing refcount */
10858 { PR_1_EXTATTR_WRITE,
10859 N_("Error writing @a @b %b (%m). "),
10860 PROMPT_ABORT, 0 },
10861
10862 /* Multiple EA blocks not supported */
10863 { PR_1_EA_MULTI_BLOCK,
10864 N_("@a @b %b has h_blocks > 1. "),
10865 PROMPT_CLEAR, 0},
10866
10867 /* Error allocating EA region allocation structure */
10868 { PR_1_EA_ALLOC_REGION,
10869 N_("Error allocating @a @b %b. "),
10870 PROMPT_ABORT, 0},
10871
10872 /* Error EA allocation collision */
10873 { PR_1_EA_ALLOC_COLLISION,
10874 N_("@a @b %b is corrupt (allocation collision). "),
10875 PROMPT_CLEAR, 0},
10876
10877 /* Bad extended attribute name */
10878 { PR_1_EA_BAD_NAME,
10879 N_("@a @b %b is corrupt (invalid name). "),
10880 PROMPT_CLEAR, 0},
10881
10882 /* Bad extended attribute value */
10883 { PR_1_EA_BAD_VALUE,
10884 N_("@a @b %b is corrupt (invalid value). "),
10885 PROMPT_CLEAR, 0},
10886
10887 /* Inode too big (latch question) */
10888 { PR_1_INODE_TOOBIG,
10889 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
10890
10891 /* Directory too big */
10892 { PR_1_TOOBIG_DIR,
10893 N_("@b #%B (%b) causes @d to be too big. "),
10894 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10895
10896 /* Regular file too big */
10897 { PR_1_TOOBIG_REG,
10898 N_("@b #%B (%b) causes file to be too big. "),
10899 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10900
10901 /* Symlink too big */
10902 { PR_1_TOOBIG_SYMLINK,
10903 N_("@b #%B (%b) causes symlink to be too big. "),
10904 PROMPT_CLEAR, PR_LATCH_TOOBIG },
10905
10906 /* INDEX_FL flag set on a non-HTREE filesystem */
10907 { PR_1_HTREE_SET,
10908 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
10909 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10910
10911 /* INDEX_FL flag set on a non-directory */
10912 { PR_1_HTREE_NODIR,
10913 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
10914 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10915
10916 /* Invalid root node in HTREE directory */
10917 { PR_1_HTREE_BADROOT,
10918 N_("@h %i has an invalid root node.\n"),
10919 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10920
10921 /* Unsupported hash version in HTREE directory */
10922 { PR_1_HTREE_HASHV,
10923 N_("@h %i has an unsupported hash version (%N)\n"),
10924 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10925
10926 /* Incompatible flag in HTREE root node */
10927 { PR_1_HTREE_INCOMPAT,
10928 N_("@h %i uses an incompatible htree root node flag.\n"),
10929 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10930
10931 /* HTREE too deep */
10932 { PR_1_HTREE_DEPTH,
10933 N_("@h %i has a tree depth (%N) which is too big\n"),
10934 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
10935
10936 /* Bad block has indirect block that conflicts with filesystem block */
10937 { PR_1_BB_FS_BLOCK,
10938 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
10939 "@f metadata. "),
10940 PROMPT_CLEAR, PR_LATCH_BBLOCK },
10941
10942 /* Resize inode failed */
10943 { PR_1_RESIZE_INODE_CREATE,
10944 N_("Resize @i (re)creation failed: %m."),
10945 PROMPT_ABORT, 0 },
10946
10947 /* invalid inode->i_extra_isize */
10948 { PR_1_EXTRA_ISIZE,
10949 N_("@i %i has a extra size (%IS) which is invalid\n"),
10950 PROMPT_FIX, PR_PREEN_OK },
10951
10952 /* invalid ea entry->e_name_len */
10953 { PR_1_ATTR_NAME_LEN,
10954 N_("@a in @i %i has a namelen (%N) which is invalid\n"),
10955 PROMPT_CLEAR, PR_PREEN_OK },
10956
10957 /* invalid ea entry->e_value_size */
10958 { PR_1_ATTR_VALUE_SIZE,
10959 N_("@a in @i %i has a value size (%N) which is invalid\n"),
10960 PROMPT_CLEAR, PR_PREEN_OK },
10961
10962 /* invalid ea entry->e_value_offs */
10963 { PR_1_ATTR_VALUE_OFFSET,
10964 N_("@a in @i %i has a value offset (%N) which is invalid\n"),
10965 PROMPT_CLEAR, PR_PREEN_OK },
10966
10967 /* invalid ea entry->e_value_block */
10968 { PR_1_ATTR_VALUE_BLOCK,
10969 N_("@a in @i %i has a value block (%N) which is invalid (must be 0)\n"),
10970 PROMPT_CLEAR, PR_PREEN_OK },
10971
10972 /* invalid ea entry->e_hash */
10973 { PR_1_ATTR_HASH,
10974 N_("@a in @i %i has a hash (%N) which is invalid (must be 0)\n"),
10975 PROMPT_CLEAR, PR_PREEN_OK },
10976
10977 /* Pass 1b errors */
10978
10979 /* Pass 1B: Rescan for duplicate/bad blocks */
10980 { PR_1B_PASS_HEADER,
10981 N_("Duplicate @bs found... invoking duplicate @b passes.\n"
10982 "Pass 1B: Rescan for duplicate/bad @bs\n"),
10983 PROMPT_NONE, 0 },
10984
10985 /* Duplicate/bad block(s) header */
10986 { PR_1B_DUP_BLOCK_HEADER,
10987 N_("Duplicate/bad @b(s) in @i %i:"),
10988 PROMPT_NONE, 0 },
10989
10990 /* Duplicate/bad block(s) in inode */
10991 { PR_1B_DUP_BLOCK,
10992 " %b",
10993 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
10994
10995 /* Duplicate/bad block(s) end */
10996 { PR_1B_DUP_BLOCK_END,
10997 "\n",
10998 PROMPT_NONE, PR_PREEN_NOHDR },
10999
11000 /* Error while scanning inodes */
11001 { PR_1B_ISCAN_ERROR,
11002 N_("Error while scanning inodes (%i): %m\n"),
11003 PROMPT_NONE, PR_FATAL },
11004
11005 /* Error allocating inode bitmap */
11006 { PR_1B_ALLOCATE_IBITMAP_ERROR,
11007 N_("@A @i @B (inode_dup_map): %m\n"),
11008 PROMPT_NONE, PR_FATAL },
11009
11010 /* Error while iterating over blocks */
11011 { PR_1B_BLOCK_ITERATE,
11012 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
11013 PROMPT_NONE, 0 },
11014
11015 /* Error adjusting EA refcount */
11016 { PR_1B_ADJ_EA_REFCOUNT,
11017 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
11018 PROMPT_NONE, 0 },
11019
11020
11021 /* Pass 1C: Scan directories for inodes with dup blocks. */
11022 { PR_1C_PASS_HEADER,
11023 N_("Pass 1C: Scan directories for @is with dup @bs.\n"),
11024 PROMPT_NONE, 0 },
11025
11026
11027 /* Pass 1D: Reconciling duplicate blocks */
11028 { PR_1D_PASS_HEADER,
11029 N_("Pass 1D: Reconciling duplicate @bs\n"),
11030 PROMPT_NONE, 0 },
11031
11032 /* File has duplicate blocks */
11033 { PR_1D_DUP_FILE,
11034 N_("File %Q (@i #%i, mod time %IM) \n"
11035 " has %B duplicate @b(s), shared with %N file(s):\n"),
11036 PROMPT_NONE, 0 },
11037
11038 /* List of files sharing duplicate blocks */
11039 { PR_1D_DUP_FILE_LIST,
11040 N_("\t%Q (@i #%i, mod time %IM)\n"),
11041 PROMPT_NONE, 0 },
11042
11043 /* File sharing blocks with filesystem metadata */
11044 { PR_1D_SHARE_METADATA,
11045 N_("\t<@f metadata>\n"),
11046 PROMPT_NONE, 0 },
11047
11048 /* Report of how many duplicate/bad inodes */
11049 { PR_1D_NUM_DUP_INODES,
11050 N_("(There are %N @is containing duplicate/bad @bs.)\n\n"),
11051 PROMPT_NONE, 0 },
11052
11053 /* Duplicated blocks already reassigned or cloned. */
11054 { PR_1D_DUP_BLOCKS_DEALT,
11055 N_("Duplicated @bs already reassigned or cloned.\n\n"),
11056 PROMPT_NONE, 0 },
11057
11058 /* Clone duplicate/bad blocks? */
11059 { PR_1D_CLONE_QUESTION,
11060 "", PROMPT_CLONE, PR_NO_OK },
11061
11062 /* Delete file? */
11063 { PR_1D_DELETE_QUESTION,
11064 "", PROMPT_DELETE, 0 },
11065
11066 /* Couldn't clone file (error) */
11067 { PR_1D_CLONE_ERROR,
11068 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
11069
11070 /* Pass 2 errors */
11071
11072 /* Pass 2: Checking directory structure */
11073 { PR_2_PASS_HEADER,
11074 N_("Pass 2: Checking @d structure\n"),
11075 PROMPT_NONE, 0 },
11076
11077 /* Bad inode number for '.' */
11078 { PR_2_BAD_INODE_DOT,
11079 N_("Bad @i number for '.' in @d @i %i.\n"),
11080 PROMPT_FIX, 0 },
11081
11082 /* Directory entry has bad inode number */
11083 { PR_2_BAD_INO,
11084 N_("@E has bad @i #: %Di.\n"),
11085 PROMPT_CLEAR, 0 },
11086
11087 /* Directory entry has deleted or unused inode */
11088 { PR_2_UNUSED_INODE,
11089 N_("@E has @D/unused @i %Di. "),
11090 PROMPT_CLEAR, PR_PREEN_OK },
11091
11092 /* Directry entry is link to '.' */
11093 { PR_2_LINK_DOT,
11094 N_("@E @L to '.' "),
11095 PROMPT_CLEAR, 0 },
11096
11097 /* Directory entry points to inode now located in a bad block */
11098 { PR_2_BB_INODE,
11099 N_("@E points to @i (%Di) located in a bad @b.\n"),
11100 PROMPT_CLEAR, 0 },
11101
11102 /* Directory entry contains a link to a directory */
11103 { PR_2_LINK_DIR,
11104 N_("@E @L to @d %P (%Di).\n"),
11105 PROMPT_CLEAR, 0 },
11106
11107 /* Directory entry contains a link to the root directry */
11108 { PR_2_LINK_ROOT,
11109 N_("@E @L to the @r.\n"),
11110 PROMPT_CLEAR, 0 },
11111
11112 /* Directory entry has illegal characters in its name */
11113 { PR_2_BAD_NAME,
11114 N_("@E has illegal characters in its name.\n"),
11115 PROMPT_FIX, 0 },
11116
11117 /* Missing '.' in directory inode */
11118 { PR_2_MISSING_DOT,
11119 N_("Missing '.' in @d @i %i.\n"),
11120 PROMPT_FIX, 0 },
11121
11122 /* Missing '..' in directory inode */
11123 { PR_2_MISSING_DOT_DOT,
11124 N_("Missing '..' in @d @i %i.\n"),
11125 PROMPT_FIX, 0 },
11126
11127 /* First entry in directory inode doesn't contain '.' */
11128 { PR_2_1ST_NOT_DOT,
11129 N_("First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n"),
11130 PROMPT_FIX, 0 },
11131
11132 /* Second entry in directory inode doesn't contain '..' */
11133 { PR_2_2ND_NOT_DOT_DOT,
11134 N_("Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n"),
11135 PROMPT_FIX, 0 },
11136
11137 /* i_faddr should be zero */
11138 { PR_2_FADDR_ZERO,
11139 N_("i_faddr @F %IF, @s zero.\n"),
11140 PROMPT_CLEAR, 0 },
11141
11142 /* i_file_acl should be zero */
11143 { PR_2_FILE_ACL_ZERO,
11144 N_("i_file_acl @F %If, @s zero.\n"),
11145 PROMPT_CLEAR, 0 },
11146
11147 /* i_dir_acl should be zero */
11148 { PR_2_DIR_ACL_ZERO,
11149 N_("i_dir_acl @F %Id, @s zero.\n"),
11150 PROMPT_CLEAR, 0 },
11151
11152 /* i_frag should be zero */
11153 { PR_2_FRAG_ZERO,
11154 N_("i_frag @F %N, @s zero.\n"),
11155 PROMPT_CLEAR, 0 },
11156
11157 /* i_fsize should be zero */
11158 { PR_2_FSIZE_ZERO,
11159 N_("i_fsize @F %N, @s zero.\n"),
11160 PROMPT_CLEAR, 0 },
11161
11162 /* inode has bad mode */
11163 { PR_2_BAD_MODE,
11164 N_("@i %i (%Q) has a bad mode (%Im).\n"),
11165 PROMPT_CLEAR, 0 },
11166
11167 /* directory corrupted */
11168 { PR_2_DIR_CORRUPTED,
11169 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
11170 PROMPT_SALVAGE, 0 },
11171
11172 /* filename too long */
11173 { PR_2_FILENAME_LONG,
11174 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
11175 PROMPT_TRUNCATE, 0 },
11176
11177 /* Directory inode has a missing block (hole) */
11178 { PR_2_DIRECTORY_HOLE,
11179 N_("@d @i %i has an unallocated @b #%B. "),
11180 PROMPT_ALLOCATE, 0 },
11181
11182 /* '.' is not NULL terminated */
11183 { PR_2_DOT_NULL_TERM,
11184 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
11185 PROMPT_FIX, 0 },
11186
11187 /* '..' is not NULL terminated */
11188 { PR_2_DOT_DOT_NULL_TERM,
11189 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
11190 PROMPT_FIX, 0 },
11191
11192 /* Illegal character device inode */
11193 { PR_2_BAD_CHAR_DEV,
11194 N_("@i %i (%Q) is an @I character @v.\n"),
11195 PROMPT_CLEAR, 0 },
11196
11197 /* Illegal block device inode */
11198 { PR_2_BAD_BLOCK_DEV,
11199 N_("@i %i (%Q) is an @I @b @v.\n"),
11200 PROMPT_CLEAR, 0 },
11201
11202 /* Duplicate '.' entry */
11203 { PR_2_DUP_DOT,
11204 N_("@E is duplicate '.' @e.\n"),
11205 PROMPT_FIX, 0 },
11206
11207 /* Duplicate '..' entry */
11208 { PR_2_DUP_DOT_DOT,
11209 N_("@E is duplicate '..' @e.\n"),
11210 PROMPT_FIX, 0 },
11211
11212 /* Internal error: couldn't find dir_info */
11213 { PR_2_NO_DIRINFO,
11214 N_("Internal error: couldn't find dir_info for %i.\n"),
11215 PROMPT_NONE, PR_FATAL },
11216
11217 /* Final rec_len is wrong */
11218 { PR_2_FINAL_RECLEN,
11219 N_("@E has rec_len of %Dr, should be %N.\n"),
11220 PROMPT_FIX, 0 },
11221
11222 /* Error allocating icount structure */
11223 { PR_2_ALLOCATE_ICOUNT,
11224 N_("@A icount structure: %m\n"),
11225 PROMPT_NONE, PR_FATAL },
11226
11227 /* Error iterating over directory blocks */
11228 { PR_2_DBLIST_ITERATE,
11229 N_("Error iterating over @d @bs: %m\n"),
11230 PROMPT_NONE, PR_FATAL },
11231
11232 /* Error reading directory block */
11233 { PR_2_READ_DIRBLOCK,
11234 N_("Error reading @d @b %b (@i %i): %m\n"),
11235 PROMPT_CONTINUE, 0 },
11236
11237 /* Error writing directory block */
11238 { PR_2_WRITE_DIRBLOCK,
11239 N_("Error writing @d @b %b (@i %i): %m\n"),
11240 PROMPT_CONTINUE, 0 },
11241
11242 /* Error allocating new directory block */
11243 { PR_2_ALLOC_DIRBOCK,
11244 N_("@A new @d @b for @i %i (%s): %m\n"),
11245 PROMPT_NONE, 0 },
11246
11247 /* Error deallocating inode */
11248 { PR_2_DEALLOC_INODE,
11249 N_("Error deallocating @i %i: %m\n"),
11250 PROMPT_NONE, PR_FATAL },
11251
11252 /* Directory entry for '.' is big. Split? */
11253 { PR_2_SPLIT_DOT,
11254 N_("@d @e for '.' is big. "),
11255 PROMPT_SPLIT, PR_NO_OK },
11256
11257 /* Illegal FIFO inode */
11258 { PR_2_BAD_FIFO,
11259 N_("@i %i (%Q) is an @I FIFO.\n"),
11260 PROMPT_CLEAR, 0 },
11261
11262 /* Illegal socket inode */
11263 { PR_2_BAD_SOCKET,
11264 N_("@i %i (%Q) is an @I socket.\n"),
11265 PROMPT_CLEAR, 0 },
11266
11267 /* Directory filetype not set */
11268 { PR_2_SET_FILETYPE,
11269 N_("Setting filetype for @E to %N.\n"),
11270 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
11271
11272 /* Directory filetype incorrect */
11273 { PR_2_BAD_FILETYPE,
11274 N_("@E has an incorrect filetype (was %Dt, should be %N).\n"),
11275 PROMPT_FIX, 0 },
11276
11277 /* Directory filetype set on filesystem */
11278 { PR_2_CLEAR_FILETYPE,
11279 N_("@E has filetype set.\n"),
11280 PROMPT_CLEAR, PR_PREEN_OK },
11281
11282 /* Directory filename is null */
11283 { PR_2_NULL_NAME,
11284 N_("@E has a zero-length name.\n"),
11285 PROMPT_CLEAR, 0 },
11286
11287 /* Invalid symlink */
11288 { PR_2_INVALID_SYMLINK,
11289 N_("Symlink %Q (@i #%i) is invalid.\n"),
11290 PROMPT_CLEAR, 0 },
11291
11292 /* i_file_acl (extended attribute block) is bad */
11293 { PR_2_FILE_ACL_BAD,
11294 N_("@a @b @F invalid (%If).\n"),
11295 PROMPT_CLEAR, 0 },
11296
11297 /* Filesystem contains large files, but has no such flag in sb */
11298 { PR_2_FEATURE_LARGE_FILES,
11299 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
11300 PROMPT_FIX, 0 },
11301
11302 /* Node in HTREE directory not referenced */
11303 { PR_2_HTREE_NOTREF,
11304 N_("@p @h %d: node (%B) not referenced\n"),
11305 PROMPT_NONE, 0 },
11306
11307 /* Node in HTREE directory referenced twice */
11308 { PR_2_HTREE_DUPREF,
11309 N_("@p @h %d: node (%B) referenced twice\n"),
11310 PROMPT_NONE, 0 },
11311
11312 /* Node in HTREE directory has bad min hash */
11313 { PR_2_HTREE_MIN_HASH,
11314 N_("@p @h %d: node (%B) has bad min hash\n"),
11315 PROMPT_NONE, 0 },
11316
11317 /* Node in HTREE directory has bad max hash */
11318 { PR_2_HTREE_MAX_HASH,
11319 N_("@p @h %d: node (%B) has bad max hash\n"),
11320 PROMPT_NONE, 0 },
11321
11322 /* Clear invalid HTREE directory */
11323 { PR_2_HTREE_CLEAR,
11324 N_("Invalid @h %d (%q). "), PROMPT_CLEAR, 0 },
11325
11326 /* Bad block in htree interior node */
11327 { PR_2_HTREE_BADBLK,
11328 N_("@p @h %d (%q): bad @b number %b.\n"),
11329 PROMPT_CLEAR_HTREE, 0 },
11330
11331 /* Error adjusting EA refcount */
11332 { PR_2_ADJ_EA_REFCOUNT,
11333 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
11334 PROMPT_NONE, PR_FATAL },
11335
11336 /* Invalid HTREE root node */
11337 { PR_2_HTREE_BAD_ROOT,
11338 N_("@p @h %d: root node is invalid\n"),
11339 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11340
11341 /* Invalid HTREE limit */
11342 { PR_2_HTREE_BAD_LIMIT,
11343 N_("@p @h %d: node (%B) has bad limit (%N)\n"),
11344 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11345
11346 /* Invalid HTREE count */
11347 { PR_2_HTREE_BAD_COUNT,
11348 N_("@p @h %d: node (%B) has bad count (%N)\n"),
11349 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11350
11351 /* HTREE interior node has out-of-order hashes in table */
11352 { PR_2_HTREE_HASH_ORDER,
11353 N_("@p @h %d: node (%B) has an unordered hash table\n"),
11354 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
11355
11356 /* Node in HTREE directory has bad depth */
11357 { PR_2_HTREE_BAD_DEPTH,
11358 N_("@p @h %d: node (%B) has bad depth\n"),
11359 PROMPT_NONE, 0 },
11360
11361 /* Duplicate directory entry found */
11362 { PR_2_DUPLICATE_DIRENT,
11363 N_("Duplicate @E found. "),
11364 PROMPT_CLEAR, 0 },
11365
11366 /* Non-unique filename found */
11367 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
11368 N_("@E has a non-unique filename.\nRename to %s"),
11369 PROMPT_NULL, 0 },
11370
11371 /* Duplicate directory entry found */
11372 { PR_2_REPORT_DUP_DIRENT,
11373 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
11374 PROMPT_NONE, 0 },
11375
11376 /* Pass 3 errors */
11377
11378 /* Pass 3: Checking directory connectivity */
11379 { PR_3_PASS_HEADER,
11380 N_("Pass 3: Checking @d connectivity\n"),
11381 PROMPT_NONE, 0 },
11382
11383 /* Root inode not allocated */
11384 { PR_3_NO_ROOT_INODE,
11385 N_("@r not allocated. "),
11386 PROMPT_ALLOCATE, 0 },
11387
11388 /* No room in lost+found */
11389 { PR_3_EXPAND_LF_DIR,
11390 N_("No room in @l @d. "),
11391 PROMPT_EXPAND, 0 },
11392
11393 /* Unconnected directory inode */
11394 { PR_3_UNCONNECTED_DIR,
11395 N_("Unconnected @d @i %i (%p)\n"),
11396 PROMPT_CONNECT, 0 },
11397
11398 /* /lost+found not found */
11399 { PR_3_NO_LF_DIR,
11400 N_("/@l not found. "),
11401 PROMPT_CREATE, PR_PREEN_OK },
11402
11403 /* .. entry is incorrect */
11404 { PR_3_BAD_DOT_DOT,
11405 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
11406 PROMPT_FIX, 0 },
11407
11408 /* Bad or non-existent /lost+found. Cannot reconnect */
11409 { PR_3_NO_LPF,
11410 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
11411 PROMPT_NONE, 0 },
11412
11413 /* Could not expand /lost+found */
11414 { PR_3_CANT_EXPAND_LPF,
11415 N_("Could not expand /@l: %m\n"),
11416 PROMPT_NONE, 0 },
11417
11418 /* Could not reconnect inode */
11419 { PR_3_CANT_RECONNECT,
11420 N_("Could not reconnect %i: %m\n"),
11421 PROMPT_NONE, 0 },
11422
11423 /* Error while trying to find /lost+found */
11424 { PR_3_ERR_FIND_LPF,
11425 N_("Error while trying to find /@l: %m\n"),
11426 PROMPT_NONE, 0 },
11427
11428 /* Error in ext2fs_new_block while creating /lost+found */
11429 { PR_3_ERR_LPF_NEW_BLOCK,
11430 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
11431 PROMPT_NONE, 0 },
11432
11433 /* Error in ext2fs_new_inode while creating /lost+found */
11434 { PR_3_ERR_LPF_NEW_INODE,
11435 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
11436 PROMPT_NONE, 0 },
11437
11438 /* Error in ext2fs_new_dir_block while creating /lost+found */
11439 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
11440 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
11441 PROMPT_NONE, 0 },
11442
11443 /* Error while writing directory block for /lost+found */
11444 { PR_3_ERR_LPF_WRITE_BLOCK,
11445 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
11446 PROMPT_NONE, 0 },
11447
11448 /* Error while adjusting inode count */
11449 { PR_3_ADJUST_INODE,
11450 N_("Error while adjusting @i count on @i %i\n"),
11451 PROMPT_NONE, 0 },
11452
11453 /* Couldn't fix parent directory -- error */
11454 { PR_3_FIX_PARENT_ERR,
11455 N_("Couldn't fix parent of @i %i: %m\n\n"),
11456 PROMPT_NONE, 0 },
11457
11458 /* Couldn't fix parent directory -- couldn't find it */
11459 { PR_3_FIX_PARENT_NOFIND,
11460 N_("Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n"),
11461 PROMPT_NONE, 0 },
11462
11463 /* Error allocating inode bitmap */
11464 { PR_3_ALLOCATE_IBITMAP_ERROR,
11465 N_("@A @i @B (%N): %m\n"),
11466 PROMPT_NONE, PR_FATAL },
11467
11468 /* Error creating root directory */
11469 { PR_3_CREATE_ROOT_ERROR,
11470 N_("Error creating root @d (%s): %m\n"),
11471 PROMPT_NONE, PR_FATAL },
11472
11473 /* Error creating lost and found directory */
11474 { PR_3_CREATE_LPF_ERROR,
11475 N_("Error creating /@l @d (%s): %m\n"),
11476 PROMPT_NONE, PR_FATAL },
11477
11478 /* Root inode is not directory; aborting */
11479 { PR_3_ROOT_NOT_DIR_ABORT,
11480 N_("@r is not a @d; aborting.\n"),
11481 PROMPT_NONE, PR_FATAL },
11482
11483 /* Cannot proceed without a root inode. */
11484 { PR_3_NO_ROOT_INODE_ABORT,
11485 N_("Cannot proceed without a @r.\n"),
11486 PROMPT_NONE, PR_FATAL },
11487
11488 /* Internal error: couldn't find dir_info */
11489 { PR_3_NO_DIRINFO,
11490 N_("Internal error: couldn't find dir_info for %i.\n"),
11491 PROMPT_NONE, PR_FATAL },
11492
11493 /* Lost+found not a directory */
11494 { PR_3_LPF_NOTDIR,
11495 N_("/@l is not a @d (ino=%i)\n"),
11496 PROMPT_UNLINK, 0 },
11497
11498 /* Pass 3A Directory Optimization */
11499
11500 /* Pass 3A: Optimizing directories */
11501 { PR_3A_PASS_HEADER,
11502 N_("Pass 3A: Optimizing directories\n"),
11503 PROMPT_NONE, PR_PREEN_NOMSG },
11504
11505 /* Error iterating over directories */
11506 { PR_3A_OPTIMIZE_ITER,
11507 N_("Failed to create dirs_to_hash iterator: %m"),
11508 PROMPT_NONE, 0 },
11509
11510 /* Error rehash directory */
11511 { PR_3A_OPTIMIZE_DIR_ERR,
11512 N_("Failed to optimize directory %q (%d): %m"),
11513 PROMPT_NONE, 0 },
11514
11515 /* Rehashing dir header */
11516 { PR_3A_OPTIMIZE_DIR_HEADER,
11517 N_("Optimizing directories: "),
11518 PROMPT_NONE, PR_MSG_ONLY },
11519
11520 /* Rehashing directory %d */
11521 { PR_3A_OPTIMIZE_DIR,
11522 " %d",
11523 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
11524
11525 /* Rehashing dir end */
11526 { PR_3A_OPTIMIZE_DIR_END,
11527 "\n",
11528 PROMPT_NONE, PR_PREEN_NOHDR },
11529
11530 /* Pass 4 errors */
11531
11532 /* Pass 4: Checking reference counts */
11533 { PR_4_PASS_HEADER,
11534 N_("Pass 4: Checking reference counts\n"),
11535 PROMPT_NONE, 0 },
11536
11537 /* Unattached zero-length inode */
11538 { PR_4_ZERO_LEN_INODE,
11539 "@u @z @i %i. ",
11540 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
11541
11542 /* Unattached inode */
11543 { PR_4_UNATTACHED_INODE,
11544 "@u @i %i\n",
11545 PROMPT_CONNECT, 0 },
11546
11547 /* Inode ref count wrong */
11548 { PR_4_BAD_REF_COUNT,
11549 N_("@i %i ref count is %Il, @s %N. "),
11550 PROMPT_FIX, PR_PREEN_OK },
11551
11552 { PR_4_INCONSISTENT_COUNT,
11553 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
11554 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
11555 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
11556 "They should be the same!\n"),
11557 PROMPT_NONE, 0 },
11558
11559 /* Pass 5 errors */
11560
11561 /* Pass 5: Checking group summary information */
11562 { PR_5_PASS_HEADER,
11563 N_("Pass 5: Checking @g summary information\n"),
11564 PROMPT_NONE, 0 },
11565
11566 /* Padding at end of inode bitmap is not set. */
11567 { PR_5_INODE_BMAP_PADDING,
11568 N_("Padding at end of @i @B is not set. "),
11569 PROMPT_FIX, PR_PREEN_OK },
11570
11571 /* Padding at end of block bitmap is not set. */
11572 { PR_5_BLOCK_BMAP_PADDING,
11573 N_("Padding at end of @b @B is not set. "),
11574 PROMPT_FIX, PR_PREEN_OK },
11575
11576 /* Block bitmap differences header */
11577 { PR_5_BLOCK_BITMAP_HEADER,
11578 N_("@b @B differences: "),
11579 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
11580
11581 /* Block not used, but marked in bitmap */
11582 { PR_5_BLOCK_UNUSED,
11583 " -%b",
11584 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11585
11586 /* Block used, but not marked used in bitmap */
11587 { PR_5_BLOCK_USED,
11588 " +%b",
11589 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11590
11591 /* Block bitmap differences end */
11592 { PR_5_BLOCK_BITMAP_END,
11593 "\n",
11594 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11595
11596 /* Inode bitmap differences header */
11597 { PR_5_INODE_BITMAP_HEADER,
11598 N_("@i @B differences: "),
11599 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
11600
11601 /* Inode not used, but marked in bitmap */
11602 { PR_5_INODE_UNUSED,
11603 " -%i",
11604 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11605
11606 /* Inode used, but not marked used in bitmap */
11607 { PR_5_INODE_USED,
11608 " +%i",
11609 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11610
11611 /* Inode bitmap differences end */
11612 { PR_5_INODE_BITMAP_END,
11613 "\n",
11614 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11615
11616 /* Free inodes count for group wrong */
11617 { PR_5_FREE_INODE_COUNT_GROUP,
11618 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
11619 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11620
11621 /* Directories count for group wrong */
11622 { PR_5_FREE_DIR_COUNT_GROUP,
11623 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
11624 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11625
11626 /* Free inodes count wrong */
11627 { PR_5_FREE_INODE_COUNT,
11628 N_("Free @is count wrong (%i, counted=%j).\n"),
11629 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11630
11631 /* Free blocks count for group wrong */
11632 { PR_5_FREE_BLOCK_COUNT_GROUP,
11633 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
11634 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11635
11636 /* Free blocks count wrong */
11637 { PR_5_FREE_BLOCK_COUNT,
11638 N_("Free @bs count wrong (%b, counted=%c).\n"),
11639 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
11640
11641 /* Programming error: bitmap endpoints don't match */
11642 { PR_5_BMAP_ENDPOINTS,
11643 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
11644 "match calculated @B endpoints (%i, %j)\n"),
11645 PROMPT_NONE, PR_FATAL },
11646
11647 /* Internal error: fudging end of bitmap */
11648 { PR_5_FUDGE_BITMAP_ERROR,
11649 N_("Internal error: fudging end of bitmap (%N)\n"),
11650 PROMPT_NONE, PR_FATAL },
11651
11652 /* Error copying in replacement inode bitmap */
11653 { PR_5_COPY_IBITMAP_ERROR,
11654 "Error copying in replacement @i @B: %m\n",
11655 PROMPT_NONE, PR_FATAL },
11656
11657 /* Error copying in replacement block bitmap */
11658 { PR_5_COPY_BBITMAP_ERROR,
11659 "Error copying in replacement @b @B: %m\n",
11660 PROMPT_NONE, PR_FATAL },
11661
11662 /* Block range not used, but marked in bitmap */
11663 { PR_5_BLOCK_RANGE_UNUSED,
11664 " -(%b--%c)",
11665 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11666
11667 /* Block range used, but not marked used in bitmap */
11668 { PR_5_BLOCK_RANGE_USED,
11669 " +(%b--%c)",
11670 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11671
11672 /* Inode range not used, but marked in bitmap */
11673 { PR_5_INODE_RANGE_UNUSED,
11674 " -(%i--%j)",
11675 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11676
11677 /* Inode range used, but not marked used in bitmap */
11678 { PR_5_INODE_RANGE_USED,
11679 " +(%i--%j)",
11680 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
11681
11682 { 0 }
11683};
11684
11685/*
11686 * This is the latch flags register. It allows several problems to be
11687 * "latched" together. This means that the user has to answer but one
11688 * question for the set of problems, and all of the associated
11689 * problems will be either fixed or not fixed.
11690 */
11691static struct latch_descr pr_latch_info[] = {
11692 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
11693 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
11694 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
11695 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
11696 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
11697 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
11698 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
11699 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
11700 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
11701 { -1, 0, 0 },
11702};
11703
11704static const struct e2fsck_problem *find_problem(problem_t code)
11705{
11706 int i;
11707
11708 for (i=0; problem_table[i].e2p_code; i++) {
11709 if (problem_table[i].e2p_code == code)
11710 return &problem_table[i];
11711 }
11712 return 0;
11713}
11714
11715static struct latch_descr *find_latch(int code)
11716{
11717 int i;
11718
11719 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
11720 if (pr_latch_info[i].latch_code == code)
11721 return &pr_latch_info[i];
11722 }
11723 return 0;
11724}
11725
11726int end_problem_latch(e2fsck_t ctx, int mask)
11727{
11728 struct latch_descr *ldesc;
11729 struct problem_context pctx;
11730 int answer = -1;
11731
11732 ldesc = find_latch(mask);
11733 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
11734 clear_problem_context(&pctx);
11735 answer = fix_problem(ctx, ldesc->end_message, &pctx);
11736 }
11737 ldesc->flags &= ~(PRL_VARIABLE);
11738 return answer;
11739}
11740
11741int set_latch_flags(int mask, int setflags, int clearflags)
11742{
11743 struct latch_descr *ldesc;
11744
11745 ldesc = find_latch(mask);
11746 if (!ldesc)
11747 return -1;
11748 ldesc->flags |= setflags;
11749 ldesc->flags &= ~clearflags;
11750 return 0;
11751}
11752
11753void clear_problem_context(struct problem_context *ctx)
11754{
11755 memset(ctx, 0, sizeof(struct problem_context));
11756 ctx->blkcount = -1;
11757 ctx->group = -1;
11758}
11759
11760int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
11761{
11762 ext2_filsys fs = ctx->fs;
11763 const struct e2fsck_problem *ptr;
11764 struct latch_descr *ldesc = 0;
11765 const char *message;
11766 int def_yn, answer, ans;
11767 int print_answer = 0;
11768 int suppress = 0;
11769
11770 ptr = find_problem(code);
11771 if (!ptr) {
11772 printf(_("Unhandled error code (0x%x)!\n"), code);
11773 return 0;
11774 }
11775 def_yn = 1;
11776 if ((ptr->flags & PR_NO_DEFAULT) ||
11777 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
11778 (ctx->options & E2F_OPT_NO))
11779 def_yn= 0;
11780
11781 /*
11782 * Do special latch processing. This is where we ask the
11783 * latch question, if it exists
11784 */
11785 if (ptr->flags & PR_LATCH_MASK) {
11786 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
11787 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
11788 ans = fix_problem(ctx, ldesc->question, pctx);
11789 if (ans == 1)
11790 ldesc->flags |= PRL_YES;
11791 if (ans == 0)
11792 ldesc->flags |= PRL_NO;
11793 ldesc->flags |= PRL_LATCHED;
11794 }
11795 if (ldesc->flags & PRL_SUPPRESS)
11796 suppress++;
11797 }
11798 if ((ptr->flags & PR_PREEN_NOMSG) &&
11799 (ctx->options & E2F_OPT_PREEN))
11800 suppress++;
11801 if ((ptr->flags & PR_NO_NOMSG) &&
11802 (ctx->options & E2F_OPT_NO))
11803 suppress++;
11804 if (!suppress) {
11805 message = ptr->e2p_description;
11806 if ((ctx->options & E2F_OPT_PREEN) &&
11807 !(ptr->flags & PR_PREEN_NOHDR)) {
11808 printf("%s: ", ctx->device_name ?
11809 ctx->device_name : ctx->filesystem_name);
11810 }
11811 if (*message)
11812 print_e2fsck_message(ctx, _(message), pctx, 1);
11813 }
11814 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
11815 preenhalt(ctx);
11816
11817 if (ptr->flags & PR_FATAL)
11818 fatal_error(ctx, 0);
11819
11820 if (ptr->prompt == PROMPT_NONE) {
11821 if (ptr->flags & PR_NOCOLLATE)
11822 answer = -1;
11823 else
11824 answer = def_yn;
11825 } else {
11826 if (ctx->options & E2F_OPT_PREEN) {
11827 answer = def_yn;
11828 if (!(ptr->flags & PR_PREEN_NOMSG))
11829 print_answer = 1;
11830 } else if ((ptr->flags & PR_LATCH_MASK) &&
11831 (ldesc->flags & (PRL_YES | PRL_NO))) {
11832 if (!suppress)
11833 print_answer = 1;
11834 if (ldesc->flags & PRL_YES)
11835 answer = 1;
11836 else
11837 answer = 0;
11838 } else
11839 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
11840 if (!answer && !(ptr->flags & PR_NO_OK))
11841 ext2fs_unmark_valid(fs);
11842
11843 if (print_answer)
11844 printf("%s.\n", answer ?
11845 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
11846
11847 }
11848
11849 if ((ptr->prompt == PROMPT_ABORT) && answer)
11850 fatal_error(ctx, 0);
11851
11852 if (ptr->flags & PR_AFTER_CODE)
11853 answer = fix_problem(ctx, ptr->second_code, pctx);
11854
11855 return answer;
11856}
11857/*
11858 * linux/fs/recovery.c
11859 *
11860 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
11861 *
11862 * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
11863 *
11864 * This file is part of the Linux kernel and is made available under
11865 * the terms of the GNU General Public License, version 2, or at your
11866 * option, any later version, incorporated herein by reference.
11867 *
11868 * Journal recovery routines for the generic filesystem journaling code;
11869 * part of the ext2fs journaling system.
11870 */
11871
11872/*
11873 * Maintain information about the progress of the recovery job, so that
11874 * the different passes can carry information between them.
11875 */
11876struct recovery_info
11877{
11878 tid_t start_transaction;
11879 tid_t end_transaction;
11880
11881 int nr_replays;
11882 int nr_revokes;
11883 int nr_revoke_hits;
11884};
11885
11886enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
11887static int do_one_pass(journal_t *journal,
11888 struct recovery_info *info, enum passtype pass);
11889static int scan_revoke_records(journal_t *, struct buffer_head *,
11890 tid_t, struct recovery_info *);
11891
11892#ifdef __KERNEL__
11893
11894/* Release readahead buffers after use */
11895void journal_brelse_array(struct buffer_head *b[], int n)
11896{
11897 while (--n >= 0)
11898 brelse (b[n]);
11899}
11900
11901
11902/*
11903 * When reading from the journal, we are going through the block device
11904 * layer directly and so there is no readahead being done for us. We
11905 * need to implement any readahead ourselves if we want it to happen at
11906 * all. Recovery is basically one long sequential read, so make sure we
11907 * do the IO in reasonably large chunks.
11908 *
11909 * This is not so critical that we need to be enormously clever about
11910 * the readahead size, though. 128K is a purely arbitrary, good-enough
11911 * fixed value.
11912 */
11913
11914#define MAXBUF 8
11915static int do_readahead(journal_t *journal, unsigned int start)
11916{
11917 int err;
11918 unsigned int max, nbufs, next;
11919 unsigned long blocknr;
11920 struct buffer_head *bh;
11921
11922 struct buffer_head * bufs[MAXBUF];
11923
11924 /* Do up to 128K of readahead */
11925 max = start + (128 * 1024 / journal->j_blocksize);
11926 if (max > journal->j_maxlen)
11927 max = journal->j_maxlen;
11928
11929 /* Do the readahead itself. We'll submit MAXBUF buffer_heads at
11930 * a time to the block device IO layer. */
11931
11932 nbufs = 0;
11933
11934 for (next = start; next < max; next++) {
11935 err = journal_bmap(journal, next, &blocknr);
11936
11937 if (err) {
11938 printk (KERN_ERR "JBD: bad block at offset %u\n",
11939 next);
11940 goto failed;
11941 }
11942
11943 bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
11944 if (!bh) {
11945 err = -ENOMEM;
11946 goto failed;
11947 }
11948
11949 if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
11950 bufs[nbufs++] = bh;
11951 if (nbufs == MAXBUF) {
11952 ll_rw_block(READ, nbufs, bufs);
11953 journal_brelse_array(bufs, nbufs);
11954 nbufs = 0;
11955 }
11956 } else
11957 brelse(bh);
11958 }
11959
11960 if (nbufs)
11961 ll_rw_block(READ, nbufs, bufs);
11962 err = 0;
11963
11964failed:
11965 if (nbufs)
11966 journal_brelse_array(bufs, nbufs);
11967 return err;
11968}
11969
11970#endif /* __KERNEL__ */
11971
11972
11973/*
11974 * Read a block from the journal
11975 */
11976
11977static int jread(struct buffer_head **bhp, journal_t *journal,
11978 unsigned int offset)
11979{
11980 int err;
11981 unsigned long blocknr;
11982 struct buffer_head *bh;
11983
11984 *bhp = NULL;
11985
11986 J_ASSERT (offset < journal->j_maxlen);
11987
11988 err = journal_bmap(journal, offset, &blocknr);
11989
11990 if (err) {
11991 printk (KERN_ERR "JBD: bad block at offset %u\n",
11992 offset);
11993 return err;
11994 }
11995
11996 bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
11997 if (!bh)
11998 return -ENOMEM;
11999
12000 if (!buffer_uptodate(bh)) {
12001 /* If this is a brand new buffer, start readahead.
12002 Otherwise, we assume we are already reading it. */
12003 if (!buffer_req(bh))
12004 do_readahead(journal, offset);
12005 wait_on_buffer(bh);
12006 }
12007
12008 if (!buffer_uptodate(bh)) {
12009 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
12010 offset);
12011 brelse(bh);
12012 return -EIO;
12013 }
12014
12015 *bhp = bh;
12016 return 0;
12017}
12018
12019
12020/*
12021 * Count the number of in-use tags in a journal descriptor block.
12022 */
12023
12024static int count_tags(struct buffer_head *bh, int size)
12025{
12026 char * tagp;
12027 journal_block_tag_t * tag;
12028 int nr = 0;
12029
12030 tagp = &bh->b_data[sizeof(journal_header_t)];
12031
12032 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
12033 tag = (journal_block_tag_t *) tagp;
12034
12035 nr++;
12036 tagp += sizeof(journal_block_tag_t);
12037 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
12038 tagp += 16;
12039
12040 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
12041 break;
12042 }
12043
12044 return nr;
12045}
12046
12047
12048/* Make sure we wrap around the log correctly! */
12049#define wrap(journal, var) \
12050do { \
12051 if (var >= (journal)->j_last) \
12052 var -= ((journal)->j_last - (journal)->j_first); \
12053} while (0)
12054
12055/**
12056 * int journal_recover(journal_t *journal) - recovers a on-disk journal
12057 * @journal: the journal to recover
12058 *
12059 * The primary function for recovering the log contents when mounting a
12060 * journaled device.
12061 *
12062 * Recovery is done in three passes. In the first pass, we look for the
12063 * end of the log. In the second, we assemble the list of revoke
12064 * blocks. In the third and final pass, we replay any un-revoked blocks
12065 * in the log.
12066 */
12067int journal_recover(journal_t *journal)
12068{
12069 int err;
12070 journal_superblock_t * sb;
12071
12072 struct recovery_info info;
12073
12074 memset(&info, 0, sizeof(info));
12075 sb = journal->j_superblock;
12076
12077 /*
12078 * The journal superblock's s_start field (the current log head)
12079 * is always zero if, and only if, the journal was cleanly
12080 * unmounted.
12081 */
12082
12083 if (!sb->s_start) {
12084 jbd_debug(1, "No recovery required, last transaction %d\n",
12085 ntohl(sb->s_sequence));
12086 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
12087 return 0;
12088 }
12089
12090 err = do_one_pass(journal, &info, PASS_SCAN);
12091 if (!err)
12092 err = do_one_pass(journal, &info, PASS_REVOKE);
12093 if (!err)
12094 err = do_one_pass(journal, &info, PASS_REPLAY);
12095
12096 jbd_debug(0, "JBD: recovery, exit status %d, "
12097 "recovered transactions %u to %u\n",
12098 err, info.start_transaction, info.end_transaction);
12099 jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
12100 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
12101
12102 /* Restart the log at the next transaction ID, thus invalidating
12103 * any existing commit records in the log. */
12104 journal->j_transaction_sequence = ++info.end_transaction;
12105
12106 journal_clear_revoke(journal);
12107 sync_blockdev(journal->j_fs_dev);
12108 return err;
12109}
12110
12111static int do_one_pass(journal_t *journal,
12112 struct recovery_info *info, enum passtype pass)
12113{
12114 unsigned int first_commit_ID, next_commit_ID;
12115 unsigned long next_log_block;
12116 int err, success = 0;
12117 journal_superblock_t * sb;
12118 journal_header_t * tmp;
12119 struct buffer_head * bh;
12120 unsigned int sequence;
12121 int blocktype;
12122
12123 /* Precompute the maximum metadata descriptors in a descriptor block */
12124 int MAX_BLOCKS_PER_DESC;
12125 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
12126 / sizeof(journal_block_tag_t));
12127
12128 /*
12129 * First thing is to establish what we expect to find in the log
12130 * (in terms of transaction IDs), and where (in terms of log
12131 * block offsets): query the superblock.
12132 */
12133
12134 sb = journal->j_superblock;
12135 next_commit_ID = ntohl(sb->s_sequence);
12136 next_log_block = ntohl(sb->s_start);
12137
12138 first_commit_ID = next_commit_ID;
12139 if (pass == PASS_SCAN)
12140 info->start_transaction = first_commit_ID;
12141
12142 jbd_debug(1, "Starting recovery pass %d\n", pass);
12143
12144 /*
12145 * Now we walk through the log, transaction by transaction,
12146 * making sure that each transaction has a commit block in the
12147 * expected place. Each complete transaction gets replayed back
12148 * into the main filesystem.
12149 */
12150
12151 while (1) {
12152 int flags;
12153 char * tagp;
12154 journal_block_tag_t * tag;
12155 struct buffer_head * obh;
12156 struct buffer_head * nbh;
12157
12158 /* If we already know where to stop the log traversal,
12159 * check right now that we haven't gone past the end of
12160 * the log. */
12161
12162 if (pass != PASS_SCAN)
12163 if (tid_geq(next_commit_ID, info->end_transaction))
12164 break;
12165
12166 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
12167 next_commit_ID, next_log_block, journal->j_last);
12168
12169 /* Skip over each chunk of the transaction looking
12170 * either the next descriptor block or the final commit
12171 * record. */
12172
12173 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
12174 err = jread(&bh, journal, next_log_block);
12175 if (err)
12176 goto failed;
12177
12178 next_log_block++;
12179 wrap(journal, next_log_block);
12180
12181 /* What kind of buffer is it?
12182 *
12183 * If it is a descriptor block, check that it has the
12184 * expected sequence number. Otherwise, we're all done
12185 * here. */
12186
12187 tmp = (journal_header_t *)bh->b_data;
12188
12189 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
12190 brelse(bh);
12191 break;
12192 }
12193
12194 blocktype = ntohl(tmp->h_blocktype);
12195 sequence = ntohl(tmp->h_sequence);
12196 jbd_debug(3, "Found magic %d, sequence %d\n",
12197 blocktype, sequence);
12198
12199 if (sequence != next_commit_ID) {
12200 brelse(bh);
12201 break;
12202 }
12203
12204 /* OK, we have a valid descriptor block which matches
12205 * all of the sequence number checks. What are we going
12206 * to do with it? That depends on the pass... */
12207
12208 switch(blocktype) {
12209 case JFS_DESCRIPTOR_BLOCK:
12210 /* If it is a valid descriptor block, replay it
12211 * in pass REPLAY; otherwise, just skip over the
12212 * blocks it describes. */
12213 if (pass != PASS_REPLAY) {
12214 next_log_block +=
12215 count_tags(bh, journal->j_blocksize);
12216 wrap(journal, next_log_block);
12217 brelse(bh);
12218 continue;
12219 }
12220
12221 /* A descriptor block: we can now write all of
12222 * the data blocks. Yay, useful work is finally
12223 * getting done here! */
12224
12225 tagp = &bh->b_data[sizeof(journal_header_t)];
12226 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
12227 <= journal->j_blocksize) {
12228 unsigned long io_block;
12229
12230 tag = (journal_block_tag_t *) tagp;
12231 flags = ntohl(tag->t_flags);
12232
12233 io_block = next_log_block++;
12234 wrap(journal, next_log_block);
12235 err = jread(&obh, journal, io_block);
12236 if (err) {
12237 /* Recover what we can, but
12238 * report failure at the end. */
12239 success = err;
12240 printk (KERN_ERR
12241 "JBD: IO error %d recovering "
12242 "block %ld in log\n",
12243 err, io_block);
12244 } else {
12245 unsigned long blocknr;
12246
12247 J_ASSERT(obh != NULL);
12248 blocknr = ntohl(tag->t_blocknr);
12249
12250 /* If the block has been
12251 * revoked, then we're all done
12252 * here. */
12253 if (journal_test_revoke
12254 (journal, blocknr,
12255 next_commit_ID)) {
12256 brelse(obh);
12257 ++info->nr_revoke_hits;
12258 goto skip_write;
12259 }
12260
12261 /* Find a buffer for the new
12262 * data being restored */
12263 nbh = __getblk(journal->j_fs_dev,
12264 blocknr,
12265 journal->j_blocksize);
12266 if (nbh == NULL) {
12267 printk(KERN_ERR
12268 "JBD: Out of memory "
12269 "during recovery.\n");
12270 err = -ENOMEM;
12271 brelse(bh);
12272 brelse(obh);
12273 goto failed;
12274 }
12275
12276 lock_buffer(nbh);
12277 memcpy(nbh->b_data, obh->b_data,
12278 journal->j_blocksize);
12279 if (flags & JFS_FLAG_ESCAPE) {
12280 *((unsigned int *)bh->b_data) =
12281 htonl(JFS_MAGIC_NUMBER);
12282 }
12283
12284 BUFFER_TRACE(nbh, "marking dirty");
12285 set_buffer_uptodate(nbh);
12286 mark_buffer_dirty(nbh);
12287 BUFFER_TRACE(nbh, "marking uptodate");
12288 ++info->nr_replays;
12289 /* ll_rw_block(WRITE, 1, &nbh); */
12290 unlock_buffer(nbh);
12291 brelse(obh);
12292 brelse(nbh);
12293 }
12294
12295 skip_write:
12296 tagp += sizeof(journal_block_tag_t);
12297 if (!(flags & JFS_FLAG_SAME_UUID))
12298 tagp += 16;
12299
12300 if (flags & JFS_FLAG_LAST_TAG)
12301 break;
12302 }
12303
12304 brelse(bh);
12305 continue;
12306
12307 case JFS_COMMIT_BLOCK:
12308 /* Found an expected commit block: not much to
12309 * do other than move on to the next sequence
12310 * number. */
12311 brelse(bh);
12312 next_commit_ID++;
12313 continue;
12314
12315 case JFS_REVOKE_BLOCK:
12316 /* If we aren't in the REVOKE pass, then we can
12317 * just skip over this block. */
12318 if (pass != PASS_REVOKE) {
12319 brelse(bh);
12320 continue;
12321 }
12322
12323 err = scan_revoke_records(journal, bh,
12324 next_commit_ID, info);
12325 brelse(bh);
12326 if (err)
12327 goto failed;
12328 continue;
12329
12330 default:
12331 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
12332 blocktype);
12333 goto done;
12334 }
12335 }
12336
12337 done:
12338 /*
12339 * We broke out of the log scan loop: either we came to the
12340 * known end of the log or we found an unexpected block in the
12341 * log. If the latter happened, then we know that the "current"
12342 * transaction marks the end of the valid log.
12343 */
12344
12345 if (pass == PASS_SCAN)
12346 info->end_transaction = next_commit_ID;
12347 else {
12348 /* It's really bad news if different passes end up at
12349 * different places (but possible due to IO errors). */
12350 if (info->end_transaction != next_commit_ID) {
12351 printk (KERN_ERR "JBD: recovery pass %d ended at "
12352 "transaction %u, expected %u\n",
12353 pass, next_commit_ID, info->end_transaction);
12354 if (!success)
12355 success = -EIO;
12356 }
12357 }
12358
12359 return success;
12360
12361 failed:
12362 return err;
12363}
12364
12365
12366/* Scan a revoke record, marking all blocks mentioned as revoked. */
12367
12368static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
12369 tid_t sequence, struct recovery_info *info)
12370{
12371 journal_revoke_header_t *header;
12372 int offset, max;
12373
12374 header = (journal_revoke_header_t *) bh->b_data;
12375 offset = sizeof(journal_revoke_header_t);
12376 max = ntohl(header->r_count);
12377
12378 while (offset < max) {
12379 unsigned long blocknr;
12380 int err;
12381
12382 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
12383 offset += 4;
12384 err = journal_set_revoke(journal, blocknr, sequence);
12385 if (err)
12386 return err;
12387 ++info->nr_revokes;
12388 }
12389 return 0;
12390}
12391/*
12392 * region.c --- code which manages allocations within a region.
12393 *
12394 * Copyright (C) 2001 Theodore Ts'o.
12395 *
12396 * %Begin-Header%
12397 * This file may be redistributed under the terms of the GNU Public
12398 * License.
12399 * %End-Header%
12400 */
12401
12402struct region_el {
12403 region_addr_t start;
12404 region_addr_t end;
12405 struct region_el *next;
12406};
12407
12408struct region_struct {
12409 region_addr_t min;
12410 region_addr_t max;
12411 struct region_el *allocated;
12412};
12413
12414region_t region_create(region_addr_t min, region_addr_t max)
12415{
12416 region_t region;
12417
12418 region = malloc(sizeof(struct region_struct));
12419 if (!region)
12420 return NULL;
12421 memset(region, 0, sizeof(struct region_struct));
12422 region->min = min;
12423 region->max = max;
12424 return region;
12425}
12426
12427void region_free(region_t region)
12428{
12429 struct region_el *r, *next;
12430
12431 for (r = region->allocated; r; r = next) {
12432 next = r->next;
12433 free(r);
12434 }
12435 memset(region, 0, sizeof(struct region_struct));
12436 free(region);
12437}
12438
12439int region_allocate(region_t region, region_addr_t start, int n)
12440{
12441 struct region_el *r, *new_region, *prev, *next;
12442 region_addr_t end;
12443
12444 end = start+n;
12445 if ((start < region->min) || (end > region->max))
12446 return -1;
12447 if (n == 0)
12448 return 1;
12449
12450 /*
12451 * Search through the linked list. If we find that it
12452 * conflicts witih something that's already allocated, return
12453 * 1; if we can find an existing region which we can grow, do
12454 * so. Otherwise, stop when we find the appropriate place
12455 * insert a new region element into the linked list.
12456 */
12457 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
12458 if (((start >= r->start) && (start < r->end)) ||
12459 ((end > r->start) && (end <= r->end)) ||
12460 ((start <= r->start) && (end >= r->end)))
12461 return 1;
12462 if (end == r->start) {
12463 r->start = start;
12464 return 0;
12465 }
12466 if (start == r->end) {
12467 if ((next = r->next)) {
12468 if (end > next->start)
12469 return 1;
12470 if (end == next->start) {
12471 r->end = next->end;
12472 r->next = next->next;
12473 free(next);
12474 return 0;
12475 }
12476 }
12477 r->end = end;
12478 return 0;
12479 }
12480 if (start < r->start)
12481 break;
12482 }
12483 /*
12484 * Insert a new region element structure into the linked list
12485 */
12486 new_region = malloc(sizeof(struct region_el));
12487 if (!new_region)
12488 return -1;
12489 new_region->start = start;
12490 new_region->end = start + n;
12491 new_region->next = r;
12492 if (prev)
12493 prev->next = new_region;
12494 else
12495 region->allocated = new_region;
12496 return 0;
12497}
12498
12499/*
12500 * rehash.c --- rebuild hash tree directories
12501 *
12502 * Copyright (C) 2002 Theodore Ts'o
12503 *
12504 * %Begin-Header%
12505 * This file may be redistributed under the terms of the GNU Public
12506 * License.
12507 * %End-Header%
12508 *
12509 * This algorithm is designed for simplicity of implementation and to
12510 * pack the directory as much as possible. It however requires twice
12511 * as much memory as the size of the directory. The maximum size
12512 * directory supported using a 4k blocksize is roughly a gigabyte, and
12513 * so there may very well be problems with machines that don't have
12514 * virtual memory, and obscenely large directories.
12515 *
12516 * An alternate algorithm which is much more disk intensive could be
12517 * written, and probably will need to be written in the future. The
12518 * design goals of such an algorithm are: (a) use (roughly) constant
12519 * amounts of memory, no matter how large the directory, (b) the
12520 * directory must be safe at all times, even if e2fsck is interrupted
12521 * in the middle, (c) we must use minimal amounts of extra disk
12522 * blocks. This pretty much requires an incremental approach, where
12523 * we are reading from one part of the directory, and inserting into
12524 * the front half. So the algorithm will have to keep track of a
12525 * moving block boundary between the new tree and the old tree, and
12526 * files will need to be moved from the old directory and inserted
12527 * into the new tree. If the new directory requires space which isn't
12528 * yet available, blocks from the beginning part of the old directory
12529 * may need to be moved to the end of the directory to make room for
12530 * the new tree:
12531 *
12532 * --------------------------------------------------------
12533 * | new tree | | old tree |
12534 * --------------------------------------------------------
12535 * ^ ptr ^ptr
12536 * tail new head old
12537 *
12538 * This is going to be a pain in the tuckus to implement, and will
12539 * require a lot more disk accesses. So I'm going to skip it for now;
12540 * it's only really going to be an issue for really, really big
12541 * filesystems (when we reach the level of tens of millions of files
12542 * in a single directory). It will probably be easier to simply
12543 * require that e2fsck use VM first.
12544 */
12545
12546struct fill_dir_struct {
12547 char *buf;
12548 struct ext2_inode *inode;
12549 int err;
12550 e2fsck_t ctx;
12551 struct hash_entry *harray;
12552 int max_array, num_array;
12553 int dir_size;
12554 int compress;
12555 ino_t parent;
12556};
12557
12558struct hash_entry {
12559 ext2_dirhash_t hash;
12560 ext2_dirhash_t minor_hash;
12561 struct ext2_dir_entry *dir;
12562};
12563
12564struct out_dir {
12565 int num;
12566 int max;
12567 char *buf;
12568 ext2_dirhash_t *hashes;
12569};
12570
12571static int fill_dir_block(ext2_filsys fs,
12572 blk_t *block_nr,
12573 e2_blkcnt_t blockcnt,
12574 blk_t ref_block EXT2FS_ATTR((unused)),
12575 int ref_offset EXT2FS_ATTR((unused)),
12576 void *priv_data)
12577{
12578 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
12579 struct hash_entry *new_array, *ent;
12580 struct ext2_dir_entry *dirent;
12581 char *dir;
12582 unsigned int offset, dir_offset;
12583
12584 if (blockcnt < 0)
12585 return 0;
12586
12587 offset = blockcnt * fs->blocksize;
12588 if (offset + fs->blocksize > fd->inode->i_size) {
12589 fd->err = EXT2_ET_DIR_CORRUPTED;
12590 return BLOCK_ABORT;
12591 }
12592 dir = (fd->buf+offset);
12593 if (HOLE_BLKADDR(*block_nr)) {
12594 memset(dir, 0, fs->blocksize);
12595 dirent = (struct ext2_dir_entry *) dir;
12596 dirent->rec_len = fs->blocksize;
12597 } else {
12598 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
12599 if (fd->err)
12600 return BLOCK_ABORT;
12601 }
12602 /* While the directory block is "hot", index it. */
12603 dir_offset = 0;
12604 while (dir_offset < fs->blocksize) {
12605 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
12606 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
12607 (dirent->rec_len < 8) ||
12608 ((dirent->rec_len % 4) != 0) ||
12609 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
12610 fd->err = EXT2_ET_DIR_CORRUPTED;
12611 return BLOCK_ABORT;
12612 }
12613 dir_offset += dirent->rec_len;
12614 if (dirent->inode == 0)
12615 continue;
12616 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
12617 (dirent->name[0] == '.'))
12618 continue;
12619 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
12620 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
12621 fd->parent = dirent->inode;
12622 continue;
12623 }
12624 if (fd->num_array >= fd->max_array) {
12625 new_array = realloc(fd->harray,
12626 sizeof(struct hash_entry) * (fd->max_array+500));
12627 if (!new_array) {
12628 fd->err = ENOMEM;
12629 return BLOCK_ABORT;
12630 }
12631 fd->harray = new_array;
12632 fd->max_array += 500;
12633 }
12634 ent = fd->harray + fd->num_array++;
12635 ent->dir = dirent;
12636 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
12637 if (fd->compress)
12638 ent->hash = ent->minor_hash = 0;
12639 else {
12640 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
12641 dirent->name,
12642 dirent->name_len & 0xFF,
12643 fs->super->s_hash_seed,
12644 &ent->hash, &ent->minor_hash);
12645 if (fd->err)
12646 return BLOCK_ABORT;
12647 }
12648 }
12649
12650 return 0;
12651}
12652
12653/* Used for sorting the hash entry */
12654static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
12655{
12656 const struct hash_entry *he_a = (const struct hash_entry *) a;
12657 const struct hash_entry *he_b = (const struct hash_entry *) b;
12658 int ret;
12659 int min_len;
12660
12661 min_len = he_a->dir->name_len;
12662 if (min_len > he_b->dir->name_len)
12663 min_len = he_b->dir->name_len;
12664
12665 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
12666 if (ret == 0) {
12667 if (he_a->dir->name_len > he_b->dir->name_len)
12668 ret = 1;
12669 else if (he_a->dir->name_len < he_b->dir->name_len)
12670 ret = -1;
12671 else
12672 ret = he_b->dir->inode - he_a->dir->inode;
12673 }
12674 return ret;
12675}
12676
12677/* Used for sorting the hash entry */
12678static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
12679{
12680 const struct hash_entry *he_a = (const struct hash_entry *) a;
12681 const struct hash_entry *he_b = (const struct hash_entry *) b;
12682 int ret;
12683
12684 if (he_a->hash > he_b->hash)
12685 ret = 1;
12686 else if (he_a->hash < he_b->hash)
12687 ret = -1;
12688 else {
12689 if (he_a->minor_hash > he_b->minor_hash)
12690 ret = 1;
12691 else if (he_a->minor_hash < he_b->minor_hash)
12692 ret = -1;
12693 else
12694 ret = name_cmp(a, b);
12695 }
12696 return ret;
12697}
12698
12699static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
12700 int blocks)
12701{
12702 void *new_mem;
12703
12704 if (outdir->max) {
12705 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
12706 if (!new_mem)
12707 return ENOMEM;
12708 outdir->buf = new_mem;
12709 new_mem = realloc(outdir->hashes,
12710 blocks * sizeof(ext2_dirhash_t));
12711 if (!new_mem)
12712 return ENOMEM;
12713 outdir->hashes = new_mem;
12714 } else {
12715 outdir->buf = malloc(blocks * fs->blocksize);
12716 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
12717 outdir->num = 0;
12718 }
12719 outdir->max = blocks;
12720 return 0;
12721}
12722
12723static void free_out_dir(struct out_dir *outdir)
12724{
12725 if (outdir->buf)
12726 free(outdir->buf);
12727 if (outdir->hashes)
12728 free(outdir->hashes);
12729 outdir->max = 0;
12730 outdir->num =0;
12731}
12732
12733static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
12734 char ** ret)
12735{
12736 errcode_t retval;
12737
12738 if (outdir->num >= outdir->max) {
12739 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
12740 if (retval)
12741 return retval;
12742 }
12743 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
12744 memset(*ret, 0, fs->blocksize);
12745 return 0;
12746}
12747
12748/*
12749 * This function is used to make a unique filename. We do this by
12750 * appending ~0, and then incrementing the number. However, we cannot
12751 * expand the length of the filename beyond the padding available in
12752 * the directory entry.
12753 */
12754static void mutate_name(char *str, __u16 *len)
12755{
12756 int i;
12757 __u16 l = *len & 0xFF, h = *len & 0xff00;
12758
12759 /*
12760 * First check to see if it looks the name has been mutated
12761 * already
12762 */
12763 for (i = l-1; i > 0; i--) {
12764 if (!isdigit(str[i]))
12765 break;
12766 }
12767 if ((i == l-1) || (str[i] != '~')) {
12768 if (((l-1) & 3) < 2)
12769 l += 2;
12770 else
12771 l = (l+3) & ~3;
12772 str[l-2] = '~';
12773 str[l-1] = '0';
12774 *len = l | h;
12775 return;
12776 }
12777 for (i = l-1; i >= 0; i--) {
12778 if (isdigit(str[i])) {
12779 if (str[i] == '9')
12780 str[i] = '0';
12781 else {
12782 str[i]++;
12783 return;
12784 }
12785 continue;
12786 }
12787 if (i == 1) {
12788 if (str[0] == 'z')
12789 str[0] = 'A';
12790 else if (str[0] == 'Z') {
12791 str[0] = '~';
12792 str[1] = '0';
12793 } else
12794 str[0]++;
12795 } else if (i > 0) {
12796 str[i] = '1';
12797 str[i-1] = '~';
12798 } else {
12799 if (str[0] == '~')
12800 str[0] = 'a';
12801 else
12802 str[0]++;
12803 }
12804 break;
12805 }
12806}
12807
12808static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
12809 ext2_ino_t ino,
12810 struct fill_dir_struct *fd)
12811{
12812 struct problem_context pctx;
12813 struct hash_entry *ent, *prev;
12814 int i, j;
12815 int fixed = 0;
12816 char new_name[256];
12817 __u16 new_len;
12818
12819 clear_problem_context(&pctx);
12820 pctx.ino = ino;
12821
12822 for (i=1; i < fd->num_array; i++) {
12823 ent = fd->harray + i;
12824 prev = ent - 1;
12825 if (!ent->dir->inode ||
12826 ((ent->dir->name_len & 0xFF) !=
12827 (prev->dir->name_len & 0xFF)) ||
12828 (strncmp(ent->dir->name, prev->dir->name,
12829 ent->dir->name_len & 0xFF)))
12830 continue;
12831 pctx.dirent = ent->dir;
12832 if ((ent->dir->inode == prev->dir->inode) &&
12833 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
12834 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
12835 ent->dir->inode = 0;
12836 fixed++;
12837 continue;
12838 }
12839 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
12840 new_len = ent->dir->name_len;
12841 mutate_name(new_name, &new_len);
12842 for (j=0; j < fd->num_array; j++) {
12843 if ((i==j) ||
12844 ((ent->dir->name_len & 0xFF) !=
12845 (fd->harray[j].dir->name_len & 0xFF)) ||
12846 (strncmp(new_name, fd->harray[j].dir->name,
12847 new_len & 0xFF)))
12848 continue;
12849 mutate_name(new_name, &new_len);
12850
12851 j = -1;
12852 }
12853 new_name[new_len & 0xFF] = 0;
12854 pctx.str = new_name;
12855 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
12856 memcpy(ent->dir->name, new_name, new_len & 0xFF);
12857 ent->dir->name_len = new_len;
12858 ext2fs_dirhash(fs->super->s_def_hash_version,
12859 ent->dir->name,
12860 ent->dir->name_len & 0xFF,
12861 fs->super->s_hash_seed,
12862 &ent->hash, &ent->minor_hash);
12863 fixed++;
12864 }
12865 }
12866 return fixed;
12867}
12868
12869
12870static errcode_t copy_dir_entries(ext2_filsys fs,
12871 struct fill_dir_struct *fd,
12872 struct out_dir *outdir)
12873{
12874 errcode_t retval;
12875 char *block_start;
12876 struct hash_entry *ent;
12877 struct ext2_dir_entry *dirent;
12878 int i, rec_len, left;
12879 ext2_dirhash_t prev_hash;
12880 int offset;
12881
12882 outdir->max = 0;
12883 retval = alloc_size_dir(fs, outdir,
12884 (fd->dir_size / fs->blocksize) + 2);
12885 if (retval)
12886 return retval;
12887 outdir->num = fd->compress ? 0 : 1;
12888 offset = 0;
12889 outdir->hashes[0] = 0;
12890 prev_hash = 1;
12891 if ((retval = get_next_block(fs, outdir, &block_start)))
12892 return retval;
12893 dirent = (struct ext2_dir_entry *) block_start;
12894 left = fs->blocksize;
12895 for (i=0; i < fd->num_array; i++) {
12896 ent = fd->harray + i;
12897 if (ent->dir->inode == 0)
12898 continue;
12899 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
12900 if (rec_len > left) {
12901 if (left)
12902 dirent->rec_len += left;
12903 if ((retval = get_next_block(fs, outdir,
12904 &block_start)))
12905 return retval;
12906 offset = 0;
12907 }
12908 left = fs->blocksize - offset;
12909 dirent = (struct ext2_dir_entry *) (block_start + offset);
12910 if (offset == 0) {
12911 if (ent->hash == prev_hash)
12912 outdir->hashes[outdir->num-1] = ent->hash | 1;
12913 else
12914 outdir->hashes[outdir->num-1] = ent->hash;
12915 }
12916 dirent->inode = ent->dir->inode;
12917 dirent->name_len = ent->dir->name_len;
12918 dirent->rec_len = rec_len;
12919 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
12920 offset += rec_len;
12921 left -= rec_len;
12922 if (left < 12) {
12923 dirent->rec_len += left;
12924 offset += left;
12925 left = 0;
12926 }
12927 prev_hash = ent->hash;
12928 }
12929 if (left)
12930 dirent->rec_len += left;
12931
12932 return 0;
12933}
12934
12935
12936static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
12937 ext2_ino_t ino, ext2_ino_t parent)
12938{
12939 struct ext2_dir_entry *dir;
12940 struct ext2_dx_root_info *root;
12941 struct ext2_dx_countlimit *limits;
12942 int filetype = 0;
12943
12944 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
12945 filetype = EXT2_FT_DIR << 8;
12946
12947 memset(buf, 0, fs->blocksize);
12948 dir = (struct ext2_dir_entry *) buf;
12949 dir->inode = ino;
12950 dir->name[0] = '.';
12951 dir->name_len = 1 | filetype;
12952 dir->rec_len = 12;
12953 dir = (struct ext2_dir_entry *) (buf + 12);
12954 dir->inode = parent;
12955 dir->name[0] = '.';
12956 dir->name[1] = '.';
12957 dir->name_len = 2 | filetype;
12958 dir->rec_len = fs->blocksize - 12;
12959
12960 root = (struct ext2_dx_root_info *) (buf+24);
12961 root->reserved_zero = 0;
12962 root->hash_version = fs->super->s_def_hash_version;
12963 root->info_length = 8;
12964 root->indirect_levels = 0;
12965 root->unused_flags = 0;
12966
12967 limits = (struct ext2_dx_countlimit *) (buf+32);
12968 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
12969 limits->count = 0;
12970
12971 return root;
12972}
12973
12974
12975static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
12976{
12977 struct ext2_dir_entry *dir;
12978 struct ext2_dx_countlimit *limits;
12979
12980 memset(buf, 0, fs->blocksize);
12981 dir = (struct ext2_dir_entry *) buf;
12982 dir->inode = 0;
12983 dir->rec_len = fs->blocksize;
12984
12985 limits = (struct ext2_dx_countlimit *) (buf+8);
12986 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
12987 limits->count = 0;
12988
12989 return (struct ext2_dx_entry *) limits;
12990}
12991
12992/*
12993 * This function takes the leaf nodes which have been written in
12994 * outdir, and populates the root node and any necessary interior nodes.
12995 */
12996static errcode_t calculate_tree(ext2_filsys fs,
12997 struct out_dir *outdir,
12998 ext2_ino_t ino,
12999 ext2_ino_t parent)
13000{
13001 struct ext2_dx_root_info *root_info;
13002 struct ext2_dx_entry *root, *dx_ent = 0;
13003 struct ext2_dx_countlimit *root_limit, *limit;
13004 errcode_t retval;
13005 char * block_start;
13006 int i, c1, c2, nblks;
13007 int limit_offset, root_offset;
13008
13009 root_info = set_root_node(fs, outdir->buf, ino, parent);
13010 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
13011 root_info->info_length;
13012 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
13013 c1 = root_limit->limit;
13014 nblks = outdir->num;
13015
13016 /* Write out the pointer blocks */
13017 if (nblks-1 <= c1) {
13018 /* Just write out the root block, and we're done */
13019 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
13020 for (i=1; i < nblks; i++) {
13021 root->block = ext2fs_cpu_to_le32(i);
13022 if (i != 1)
13023 root->hash =
13024 ext2fs_cpu_to_le32(outdir->hashes[i]);
13025 root++;
13026 c1--;
13027 }
13028 } else {
13029 c2 = 0;
13030 limit = 0;
13031 root_info->indirect_levels = 1;
13032 for (i=1; i < nblks; i++) {
13033 if (c1 == 0)
13034 return ENOSPC;
13035 if (c2 == 0) {
13036 if (limit)
13037 limit->limit = limit->count =
13038 ext2fs_cpu_to_le16(limit->limit);
13039 root = (struct ext2_dx_entry *)
13040 (outdir->buf + root_offset);
13041 root->block = ext2fs_cpu_to_le32(outdir->num);
13042 if (i != 1)
13043 root->hash =
13044 ext2fs_cpu_to_le32(outdir->hashes[i]);
13045 if ((retval = get_next_block(fs, outdir,
13046 &block_start)))
13047 return retval;
13048 dx_ent = set_int_node(fs, block_start);
13049 limit = (struct ext2_dx_countlimit *) dx_ent;
13050 c2 = limit->limit;
13051 root_offset += sizeof(struct ext2_dx_entry);
13052 c1--;
13053 }
13054 dx_ent->block = ext2fs_cpu_to_le32(i);
13055 if (c2 != limit->limit)
13056 dx_ent->hash =
13057 ext2fs_cpu_to_le32(outdir->hashes[i]);
13058 dx_ent++;
13059 c2--;
13060 }
13061 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
13062 limit->limit = ext2fs_cpu_to_le16(limit->limit);
13063 }
13064 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
13065 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
13066 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
13067
13068 return 0;
13069}
13070
13071struct write_dir_struct {
13072 struct out_dir *outdir;
13073 errcode_t err;
13074 e2fsck_t ctx;
13075 int cleared;
13076};
13077
13078/*
13079 * Helper function which writes out a directory block.
13080 */
13081static int write_dir_block(ext2_filsys fs,
13082 blk_t *block_nr,
13083 e2_blkcnt_t blockcnt,
13084 blk_t ref_block EXT2FS_ATTR((unused)),
13085 int ref_offset EXT2FS_ATTR((unused)),
13086 void *priv_data)
13087{
13088 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
13089 blk_t blk;
13090 char *dir;
13091
13092 if (*block_nr == 0)
13093 return 0;
13094 if (blockcnt >= wd->outdir->num) {
13095 e2fsck_read_bitmaps(wd->ctx);
13096 blk = *block_nr;
13097 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
13098 ext2fs_block_alloc_stats(fs, blk, -1);
13099 *block_nr = 0;
13100 wd->cleared++;
13101 return BLOCK_CHANGED;
13102 }
13103 if (blockcnt < 0)
13104 return 0;
13105
13106 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
13107 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
13108 if (wd->err)
13109 return BLOCK_ABORT;
13110 return 0;
13111}
13112
13113static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
13114 struct out_dir *outdir,
13115 ext2_ino_t ino, int compress)
13116{
13117 struct write_dir_struct wd;
13118 errcode_t retval;
13119 struct ext2_inode inode;
13120
13121 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
13122 if (retval)
13123 return retval;
13124
13125 wd.outdir = outdir;
13126 wd.err = 0;
13127 wd.ctx = ctx;
13128 wd.cleared = 0;
13129
13130 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
13131 write_dir_block, &wd);
13132 if (retval)
13133 return retval;
13134 if (wd.err)
13135 return wd.err;
13136
13137 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
13138 if (compress)
13139 inode.i_flags &= ~EXT2_INDEX_FL;
13140 else
13141 inode.i_flags |= EXT2_INDEX_FL;
13142 inode.i_size = outdir->num * fs->blocksize;
13143 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
13144 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
13145
13146 return 0;
13147}
13148
13149errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
13150{
13151 ext2_filsys fs = ctx->fs;
13152 errcode_t retval;
13153 struct ext2_inode inode;
13154 char *dir_buf = 0;
13155 struct fill_dir_struct fd;
13156 struct out_dir outdir;
13157
13158 outdir.max = outdir.num = 0;
13159 outdir.buf = 0;
13160 outdir.hashes = 0;
13161 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
13162
13163 retval = ENOMEM;
13164 fd.harray = 0;
13165 dir_buf = malloc(inode.i_size);
13166 if (!dir_buf)
13167 goto errout;
13168
13169 fd.max_array = inode.i_size / 32;
13170 fd.num_array = 0;
13171 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
13172 if (!fd.harray)
13173 goto errout;
13174
13175 fd.ctx = ctx;
13176 fd.buf = dir_buf;
13177 fd.inode = &inode;
13178 fd.err = 0;
13179 fd.dir_size = 0;
13180 fd.compress = 0;
13181 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
13182 (inode.i_size / fs->blocksize) < 2)
13183 fd.compress = 1;
13184 fd.parent = 0;
13185
13186 /* Read in the entire directory into memory */
13187 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
13188 fill_dir_block, &fd);
13189 if (fd.err) {
13190 retval = fd.err;
13191 goto errout;
13192 }
13193
13194#if 0
13195 printf("%d entries (%d bytes) found in inode %d\n",
13196 fd.num_array, fd.dir_size, ino);
13197#endif
13198
13199 /* Sort the list */
13200resort:
13201 if (fd.compress)
13202 qsort(fd.harray+2, fd.num_array-2,
13203 sizeof(struct hash_entry), name_cmp);
13204 else
13205 qsort(fd.harray, fd.num_array,
13206 sizeof(struct hash_entry), hash_cmp);
13207
13208 /*
13209 * Look for duplicates
13210 */
13211 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
13212 goto resort;
13213
13214 if (ctx->options & E2F_OPT_NO) {
13215 retval = 0;
13216 goto errout;
13217 }
13218
13219 /*
13220 * Copy the directory entries. In a htree directory these
13221 * will become the leaf nodes.
13222 */
13223 retval = copy_dir_entries(fs, &fd, &outdir);
13224 if (retval)
13225 goto errout;
13226
13227 free(dir_buf); dir_buf = 0;
13228
13229 if (!fd.compress) {
13230 /* Calculate the interior nodes */
13231 retval = calculate_tree(fs, &outdir, ino, fd.parent);
13232 if (retval)
13233 goto errout;
13234 }
13235
13236 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
13237 if (retval)
13238 goto errout;
13239
13240errout:
13241 if (dir_buf)
13242 free(dir_buf);
13243 if (fd.harray)
13244 free(fd.harray);
13245
13246 free_out_dir(&outdir);
13247 return retval;
13248}
13249
13250void e2fsck_rehash_directories(e2fsck_t ctx)
13251{
13252 struct problem_context pctx;
13253#ifdef RESOURCE_TRACK
13254 struct resource_track rtrack;
13255#endif
13256 struct dir_info *dir;
13257 ext2_u32_iterate iter;
13258 ext2_ino_t ino;
13259 errcode_t retval;
13260 int i, cur, max, all_dirs, dir_index, first = 1;
13261
13262#ifdef RESOURCE_TRACK
13263 init_resource_track(&rtrack);
13264#endif
13265
13266 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
13267
13268 if (!ctx->dirs_to_hash && !all_dirs)
13269 return;
13270
13271 e2fsck_get_lost_and_found(ctx, 0);
13272
13273 clear_problem_context(&pctx);
13274
13275 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
13276 cur = 0;
13277 if (all_dirs) {
13278 i = 0;
13279 max = e2fsck_get_num_dirinfo(ctx);
13280 } else {
13281 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
13282 &iter);
13283 if (retval) {
13284 pctx.errcode = retval;
13285 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
13286 return;
13287 }
13288 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
13289 }
13290 while (1) {
13291 if (all_dirs) {
13292 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
13293 break;
13294 ino = dir->ino;
13295 } else {
13296 if (!ext2fs_u32_list_iterate(iter, &ino))
13297 break;
13298 }
13299 if (ino == ctx->lost_and_found)
13300 continue;
13301 pctx.dir = ino;
13302 if (first) {
13303 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
13304 first = 0;
13305 }
13306#if 0
13307 fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
13308#endif
13309 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
13310 if (pctx.errcode) {
13311 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
13312 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
13313 }
13314 if (ctx->progress && !ctx->progress_fd)
13315 e2fsck_simple_progress(ctx, "Rebuilding directory",
13316 100.0 * (float) (++cur) / (float) max, ino);
13317 }
13318 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
13319 if (!all_dirs)
13320 ext2fs_u32_list_iterate_end(iter);
13321
13322 if (ctx->dirs_to_hash)
13323 ext2fs_u32_list_free(ctx->dirs_to_hash);
13324 ctx->dirs_to_hash = 0;
13325
13326#ifdef RESOURCE_TRACK
13327 if (ctx->options & E2F_OPT_TIME2) {
13328 e2fsck_clear_progbar(ctx);
13329 print_resource_track("Pass 3A", &rtrack);
13330 }
13331#endif
13332}
13333/*
13334 * linux/fs/revoke.c
13335 *
13336 * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
13337 *
13338 * Copyright 2000 Red Hat corp --- All Rights Reserved
13339 *
13340 * This file is part of the Linux kernel and is made available under
13341 * the terms of the GNU General Public License, version 2, or at your
13342 * option, any later version, incorporated herein by reference.
13343 *
13344 * Journal revoke routines for the generic filesystem journaling code;
13345 * part of the ext2fs journaling system.
13346 *
13347 * Revoke is the mechanism used to prevent old log records for deleted
13348 * metadata from being replayed on top of newer data using the same
13349 * blocks. The revoke mechanism is used in two separate places:
13350 *
13351 * + Commit: during commit we write the entire list of the current
13352 * transaction's revoked blocks to the journal
13353 *
13354 * + Recovery: during recovery we record the transaction ID of all
13355 * revoked blocks. If there are multiple revoke records in the log
13356 * for a single block, only the last one counts, and if there is a log
13357 * entry for a block beyond the last revoke, then that log entry still
13358 * gets replayed.
13359 *
13360 * We can get interactions between revokes and new log data within a
13361 * single transaction:
13362 *
13363 * Block is revoked and then journaled:
13364 * The desired end result is the journaling of the new block, so we
13365 * cancel the revoke before the transaction commits.
13366 *
13367 * Block is journaled and then revoked:
13368 * The revoke must take precedence over the write of the block, so we
13369 * need either to cancel the journal entry or to write the revoke
13370 * later in the log than the log block. In this case, we choose the
13371 * latter: journaling a block cancels any revoke record for that block
13372 * in the current transaction, so any revoke for that block in the
13373 * transaction must have happened after the block was journaled and so
13374 * the revoke must take precedence.
13375 *
13376 * Block is revoked and then written as data:
13377 * The data write is allowed to succeed, but the revoke is _not_
13378 * cancelled. We still need to prevent old log records from
13379 * overwriting the new data. We don't even need to clear the revoke
13380 * bit here.
13381 *
13382 * Revoke information on buffers is a tri-state value:
13383 *
13384 * RevokeValid clear: no cached revoke status, need to look it up
13385 * RevokeValid set, Revoked clear:
13386 * buffer has not been revoked, and cancel_revoke
13387 * need do nothing.
13388 * RevokeValid set, Revoked set:
13389 * buffer has been revoked.
13390 */
13391
13392static kmem_cache_t *revoke_record_cache;
13393static kmem_cache_t *revoke_table_cache;
13394
13395/* Each revoke record represents one single revoked block. During
13396 journal replay, this involves recording the transaction ID of the
13397 last transaction to revoke this block. */
13398
13399struct jbd_revoke_record_s
13400{
13401 struct list_head hash;
13402 tid_t sequence; /* Used for recovery only */
13403 unsigned long blocknr;
13404};
13405
13406
13407/* The revoke table is just a simple hash table of revoke records. */
13408struct jbd_revoke_table_s
13409{
13410 /* It is conceivable that we might want a larger hash table
13411 * for recovery. Must be a power of two. */
13412 int hash_size;
13413 int hash_shift;
13414 struct list_head *hash_table;
13415};
13416
13417
13418#ifdef __KERNEL__
13419static void write_one_revoke_record(journal_t *, transaction_t *,
13420 struct journal_head **, int *,
13421 struct jbd_revoke_record_s *);
13422static void flush_descriptor(journal_t *, struct journal_head *, int);
13423#endif
13424
13425/* Utility functions to maintain the revoke table */
13426
13427/* Borrowed from buffer.c: this is a tried and tested block hash function */
13428static inline int hash(journal_t *journal, unsigned long block)
13429{
13430 struct jbd_revoke_table_s *table = journal->j_revoke;
13431 int hash_shift = table->hash_shift;
13432
13433 return ((block << (hash_shift - 6)) ^
13434 (block >> 13) ^
13435 (block << (hash_shift - 12))) & (table->hash_size - 1);
13436}
13437
13438static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
13439 tid_t seq)
13440{
13441 struct list_head *hash_list;
13442 struct jbd_revoke_record_s *record;
13443
13444#ifdef __KERNEL__
13445repeat:
13446#endif
13447 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
13448 if (!record)
13449 goto oom;
13450
13451 record->sequence = seq;
13452 record->blocknr = blocknr;
13453 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13454 list_add(&record->hash, hash_list);
13455 return 0;
13456
13457oom:
13458#ifdef __KERNEL__
13459 if (!journal_oom_retry)
13460 return -ENOMEM;
13461 jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n");
13462 current->policy |= SCHED_YIELD;
13463 schedule();
13464 goto repeat;
13465#else
13466 return -ENOMEM;
13467#endif
13468}
13469
13470/* Find a revoke record in the journal's hash table. */
13471
13472static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
13473 unsigned long blocknr)
13474{
13475 struct list_head *hash_list;
13476 struct jbd_revoke_record_s *record;
13477
13478 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
13479
13480 record = (struct jbd_revoke_record_s *) hash_list->next;
13481 while (&(record->hash) != hash_list) {
13482 if (record->blocknr == blocknr)
13483 return record;
13484 record = (struct jbd_revoke_record_s *) record->hash.next;
13485 }
13486 return NULL;
13487}
13488
13489int journal_init_revoke_caches(void)
13490{
13491 revoke_record_cache = kmem_cache_create("revoke_record",
13492 sizeof(struct jbd_revoke_record_s),
13493 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
13494 if (revoke_record_cache == 0)
13495 return -ENOMEM;
13496
13497 revoke_table_cache = kmem_cache_create("revoke_table",
13498 sizeof(struct jbd_revoke_table_s),
13499 0, 0, NULL, NULL);
13500 if (revoke_table_cache == 0) {
13501 kmem_cache_destroy(revoke_record_cache);
13502 revoke_record_cache = NULL;
13503 return -ENOMEM;
13504 }
13505 return 0;
13506}
13507
13508void journal_destroy_revoke_caches(void)
13509{
13510 kmem_cache_destroy(revoke_record_cache);
13511 revoke_record_cache = 0;
13512 kmem_cache_destroy(revoke_table_cache);
13513 revoke_table_cache = 0;
13514}
13515
13516/* Initialise the revoke table for a given journal to a given size. */
13517
13518int journal_init_revoke(journal_t *journal, int hash_size)
13519{
13520 int shift, tmp;
13521
13522 J_ASSERT (journal->j_revoke == NULL);
13523
13524 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
13525 if (!journal->j_revoke)
13526 return -ENOMEM;
13527
13528 /* Check that the hash_size is a power of two */
13529 J_ASSERT ((hash_size & (hash_size-1)) == 0);
13530
13531 journal->j_revoke->hash_size = hash_size;
13532
13533 shift = 0;
13534 tmp = hash_size;
13535 while((tmp >>= 1UL) != 0UL)
13536 shift++;
13537 journal->j_revoke->hash_shift = shift;
13538
13539 journal->j_revoke->hash_table =
13540 kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
13541 if (!journal->j_revoke->hash_table) {
13542 kmem_cache_free(revoke_table_cache, journal->j_revoke);
13543 journal->j_revoke = NULL;
13544 return -ENOMEM;
13545 }
13546
13547 for (tmp = 0; tmp < hash_size; tmp++)
13548 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
13549
13550 return 0;
13551}
13552
13553/* Destoy a journal's revoke table. The table must already be empty! */
13554
13555void journal_destroy_revoke(journal_t *journal)
13556{
13557 struct jbd_revoke_table_s *table;
13558 struct list_head *hash_list;
13559 int i;
13560
13561 table = journal->j_revoke;
13562 if (!table)
13563 return;
13564
13565 for (i=0; i<table->hash_size; i++) {
13566 hash_list = &table->hash_table[i];
13567 J_ASSERT (list_empty(hash_list));
13568 }
13569
13570 kfree(table->hash_table);
13571 kmem_cache_free(revoke_table_cache, table);
13572 journal->j_revoke = NULL;
13573}
13574
13575
13576#ifdef __KERNEL__
13577
13578/*
13579 * journal_revoke: revoke a given buffer_head from the journal. This
13580 * prevents the block from being replayed during recovery if we take a
13581 * crash after this current transaction commits. Any subsequent
13582 * metadata writes of the buffer in this transaction cancel the
13583 * revoke.
13584 *
13585 * Note that this call may block --- it is up to the caller to make
13586 * sure that there are no further calls to journal_write_metadata
13587 * before the revoke is complete. In ext3, this implies calling the
13588 * revoke before clearing the block bitmap when we are deleting
13589 * metadata.
13590 *
13591 * Revoke performs a journal_forget on any buffer_head passed in as a
13592 * parameter, but does _not_ forget the buffer_head if the bh was only
13593 * found implicitly.
13594 *
13595 * bh_in may not be a journalled buffer - it may have come off
13596 * the hash tables without an attached journal_head.
13597 *
13598 * If bh_in is non-zero, journal_revoke() will decrement its b_count
13599 * by one.
13600 */
13601
13602int journal_revoke(handle_t *handle, unsigned long blocknr,
13603 struct buffer_head *bh_in)
13604{
13605 struct buffer_head *bh = NULL;
13606 journal_t *journal;
13607 kdev_t dev;
13608 int err;
13609
13610 if (bh_in)
13611 BUFFER_TRACE(bh_in, "enter");
13612
13613 journal = handle->h_transaction->t_journal;
13614 if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){
13615 J_ASSERT (!"Cannot set revoke feature!");
13616 return -EINVAL;
13617 }
13618
13619 dev = journal->j_fs_dev;
13620 bh = bh_in;
13621
13622 if (!bh) {
13623 bh = get_hash_table(dev, blocknr, journal->j_blocksize);
13624 if (bh)
13625 BUFFER_TRACE(bh, "found on hash");
13626 }
13627#ifdef JBD_EXPENSIVE_CHECKING
13628 else {
13629 struct buffer_head *bh2;
13630
13631 /* If there is a different buffer_head lying around in
13632 * memory anywhere... */
13633 bh2 = get_hash_table(dev, blocknr, journal->j_blocksize);
13634 if (bh2) {
13635 /* ... and it has RevokeValid status... */
13636 if ((bh2 != bh) &&
13637 test_bit(BH_RevokeValid, &bh2->b_state))
13638 /* ...then it better be revoked too,
13639 * since it's illegal to create a revoke
13640 * record against a buffer_head which is
13641 * not marked revoked --- that would
13642 * risk missing a subsequent revoke
13643 * cancel. */
13644 J_ASSERT_BH(bh2, test_bit(BH_Revoked, &
13645 bh2->b_state));
13646 __brelse(bh2);
13647 }
13648 }
13649#endif
13650
13651 /* We really ought not ever to revoke twice in a row without
13652 first having the revoke cancelled: it's illegal to free a
13653 block twice without allocating it in between! */
13654 if (bh) {
13655 J_ASSERT_BH(bh, !test_bit(BH_Revoked, &bh->b_state));
13656 set_bit(BH_Revoked, &bh->b_state);
13657 set_bit(BH_RevokeValid, &bh->b_state);
13658 if (bh_in) {
13659 BUFFER_TRACE(bh_in, "call journal_forget");
13660 journal_forget(handle, bh_in);
13661 } else {
13662 BUFFER_TRACE(bh, "call brelse");
13663 __brelse(bh);
13664 }
13665 }
13666
13667 lock_journal(journal);
13668 jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in);
13669 err = insert_revoke_hash(journal, blocknr,
13670 handle->h_transaction->t_tid);
13671 unlock_journal(journal);
13672 BUFFER_TRACE(bh_in, "exit");
13673 return err;
13674}
13675
13676/*
13677 * Cancel an outstanding revoke. For use only internally by the
13678 * journaling code (called from journal_get_write_access).
13679 *
13680 * We trust the BH_Revoked bit on the buffer if the buffer is already
13681 * being journaled: if there is no revoke pending on the buffer, then we
13682 * don't do anything here.
13683 *
13684 * This would break if it were possible for a buffer to be revoked and
13685 * discarded, and then reallocated within the same transaction. In such
13686 * a case we would have lost the revoked bit, but when we arrived here
13687 * the second time we would still have a pending revoke to cancel. So,
13688 * do not trust the Revoked bit on buffers unless RevokeValid is also
13689 * set.
13690 *
13691 * The caller must have the journal locked.
13692 */
13693int journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
13694{
13695 struct jbd_revoke_record_s *record;
13696 journal_t *journal = handle->h_transaction->t_journal;
13697 int need_cancel;
13698 int did_revoke = 0; /* akpm: debug */
13699 struct buffer_head *bh = jh2bh(jh);
13700
13701 jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
13702
13703 /* Is the existing Revoke bit valid? If so, we trust it, and
13704 * only perform the full cancel if the revoke bit is set. If
13705 * not, we can't trust the revoke bit, and we need to do the
13706 * full search for a revoke record. */
13707 if (test_and_set_bit(BH_RevokeValid, &bh->b_state))
13708 need_cancel = (test_and_clear_bit(BH_Revoked, &bh->b_state));
13709 else {
13710 need_cancel = 1;
13711 clear_bit(BH_Revoked, &bh->b_state);
13712 }
13713
13714 if (need_cancel) {
13715 record = find_revoke_record(journal, bh->b_blocknr);
13716 if (record) {
13717 jbd_debug(4, "cancelled existing revoke on "
13718 "blocknr %lu\n", bh->b_blocknr);
13719 list_del(&record->hash);
13720 kmem_cache_free(revoke_record_cache, record);
13721 did_revoke = 1;
13722 }
13723 }
13724
13725#ifdef JBD_EXPENSIVE_CHECKING
13726 /* There better not be one left behind by now! */
13727 record = find_revoke_record(journal, bh->b_blocknr);
13728 J_ASSERT_JH(jh, record == NULL);
13729#endif
13730
13731 /* Finally, have we just cleared revoke on an unhashed
13732 * buffer_head? If so, we'd better make sure we clear the
13733 * revoked status on any hashed alias too, otherwise the revoke
13734 * state machine will get very upset later on. */
13735 if (need_cancel && !bh->b_pprev) {
13736 struct buffer_head *bh2;
13737 bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
13738 if (bh2) {
13739 clear_bit(BH_Revoked, &bh2->b_state);
13740 __brelse(bh2);
13741 }
13742 }
13743
13744 return did_revoke;
13745}
13746
13747
13748/*
13749 * Write revoke records to the journal for all entries in the current
13750 * revoke hash, deleting the entries as we go.
13751 *
13752 * Called with the journal lock held.
13753 */
13754
13755void journal_write_revoke_records(journal_t *journal,
13756 transaction_t *transaction)
13757{
13758 struct journal_head *descriptor;
13759 struct jbd_revoke_record_s *record;
13760 struct jbd_revoke_table_s *revoke;
13761 struct list_head *hash_list;
13762 int i, offset, count;
13763
13764 descriptor = NULL;
13765 offset = 0;
13766 count = 0;
13767 revoke = journal->j_revoke;
13768
13769 for (i = 0; i < revoke->hash_size; i++) {
13770 hash_list = &revoke->hash_table[i];
13771
13772 while (!list_empty(hash_list)) {
13773 record = (struct jbd_revoke_record_s *)
13774 hash_list->next;
13775 write_one_revoke_record(journal, transaction,
13776 &descriptor, &offset,
13777 record);
13778 count++;
13779 list_del(&record->hash);
13780 kmem_cache_free(revoke_record_cache, record);
13781 }
13782 }
13783 if (descriptor)
13784 flush_descriptor(journal, descriptor, offset);
13785 jbd_debug(1, "Wrote %d revoke records\n", count);
13786}
13787
13788/*
13789 * Write out one revoke record. We need to create a new descriptor
13790 * block if the old one is full or if we have not already created one.
13791 */
13792
13793static void write_one_revoke_record(journal_t *journal,
13794 transaction_t *transaction,
13795 struct journal_head **descriptorp,
13796 int *offsetp,
13797 struct jbd_revoke_record_s *record)
13798{
13799 struct journal_head *descriptor;
13800 int offset;
13801 journal_header_t *header;
13802
13803 /* If we are already aborting, this all becomes a noop. We
13804 still need to go round the loop in
13805 journal_write_revoke_records in order to free all of the
13806 revoke records: only the IO to the journal is omitted. */
13807 if (is_journal_aborted(journal))
13808 return;
13809
13810 descriptor = *descriptorp;
13811 offset = *offsetp;
13812
13813 /* Make sure we have a descriptor with space left for the record */
13814 if (descriptor) {
13815 if (offset == journal->j_blocksize) {
13816 flush_descriptor(journal, descriptor, offset);
13817 descriptor = NULL;
13818 }
13819 }
13820
13821 if (!descriptor) {
13822 descriptor = journal_get_descriptor_buffer(journal);
13823 if (!descriptor)
13824 return;
13825 header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
13826 header->h_magic = htonl(JFS_MAGIC_NUMBER);
13827 header->h_blocktype = htonl(JFS_REVOKE_BLOCK);
13828 header->h_sequence = htonl(transaction->t_tid);
13829
13830 /* Record it so that we can wait for IO completion later */
13831 JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");
13832 journal_file_buffer(descriptor, transaction, BJ_LogCtl);
13833
13834 offset = sizeof(journal_revoke_header_t);
13835 *descriptorp = descriptor;
13836 }
13837
13838 * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) =
13839 htonl(record->blocknr);
13840 offset += 4;
13841 *offsetp = offset;
13842}
13843
13844/*
13845 * Flush a revoke descriptor out to the journal. If we are aborting,
13846 * this is a noop; otherwise we are generating a buffer which needs to
13847 * be waited for during commit, so it has to go onto the appropriate
13848 * journal buffer list.
13849 */
13850
13851static void flush_descriptor(journal_t *journal,
13852 struct journal_head *descriptor,
13853 int offset)
13854{
13855 journal_revoke_header_t *header;
13856
13857 if (is_journal_aborted(journal)) {
13858 JBUFFER_TRACE(descriptor, "brelse");
13859 __brelse(jh2bh(descriptor));
13860 return;
13861 }
13862
13863 header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data;
13864 header->r_count = htonl(offset);
13865 set_bit(BH_JWrite, &jh2bh(descriptor)->b_state);
13866 {
13867 struct buffer_head *bh = jh2bh(descriptor);
13868 BUFFER_TRACE(bh, "write");
13869 ll_rw_block (WRITE, 1, &bh);
13870 }
13871}
13872
13873#endif
13874
13875/*
13876 * Revoke support for recovery.
13877 *
13878 * Recovery needs to be able to:
13879 *
13880 * record all revoke records, including the tid of the latest instance
13881 * of each revoke in the journal
13882 *
13883 * check whether a given block in a given transaction should be replayed
13884 * (ie. has not been revoked by a revoke record in that or a subsequent
13885 * transaction)
13886 *
13887 * empty the revoke table after recovery.
13888 */
13889
13890/*
13891 * First, setting revoke records. We create a new revoke record for
13892 * every block ever revoked in the log as we scan it for recovery, and
13893 * we update the existing records if we find multiple revokes for a
13894 * single block.
13895 */
13896
13897int journal_set_revoke(journal_t *journal,
13898 unsigned long blocknr,
13899 tid_t sequence)
13900{
13901 struct jbd_revoke_record_s *record;
13902
13903 record = find_revoke_record(journal, blocknr);
13904 if (record) {
13905 /* If we have multiple occurences, only record the
13906 * latest sequence number in the hashed record */
13907 if (tid_gt(sequence, record->sequence))
13908 record->sequence = sequence;
13909 return 0;
13910 }
13911 return insert_revoke_hash(journal, blocknr, sequence);
13912}
13913
13914/*
13915 * Test revoke records. For a given block referenced in the log, has
13916 * that block been revoked? A revoke record with a given transaction
13917 * sequence number revokes all blocks in that transaction and earlier
13918 * ones, but later transactions still need replayed.
13919 */
13920
13921int journal_test_revoke(journal_t *journal,
13922 unsigned long blocknr,
13923 tid_t sequence)
13924{
13925 struct jbd_revoke_record_s *record;
13926
13927 record = find_revoke_record(journal, blocknr);
13928 if (!record)
13929 return 0;
13930 if (tid_gt(sequence, record->sequence))
13931 return 0;
13932 return 1;
13933}
13934
13935/*
13936 * Finally, once recovery is over, we need to clear the revoke table so
13937 * that it can be reused by the running filesystem.
13938 */
13939
13940void journal_clear_revoke(journal_t *journal)
13941{
13942 int i;
13943 struct list_head *hash_list;
13944 struct jbd_revoke_record_s *record;
13945 struct jbd_revoke_table_s *revoke_var;
13946
13947 revoke_var = journal->j_revoke;
13948
13949 for (i = 0; i < revoke_var->hash_size; i++) {
13950 hash_list = &revoke_var->hash_table[i];
13951 while (!list_empty(hash_list)) {
13952 record = (struct jbd_revoke_record_s*) hash_list->next;
13953 list_del(&record->hash);
13954 kmem_cache_free(revoke_record_cache, record);
13955 }
13956 }
13957}
13958
13959/*
13960 * e2fsck.c - superblock checks
13961 *
13962 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
13963 *
13964 * %Begin-Header%
13965 * This file may be redistributed under the terms of the GNU Public
13966 * License.
13967 * %End-Header%
13968 */
13969
13970#define MIN_CHECK 1
13971#define MAX_CHECK 2
13972
13973static void check_super_value(e2fsck_t ctx, const char *descr,
13974 unsigned long value, int flags,
13975 unsigned long min_val, unsigned long max_val)
13976{
13977 struct problem_context pctx;
13978
13979 if (((flags & MIN_CHECK) && (value < min_val)) ||
13980 ((flags & MAX_CHECK) && (value > max_val))) {
13981 clear_problem_context(&pctx);
13982 pctx.num = value;
13983 pctx.str = descr;
13984 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
13985 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
13986 }
13987}
13988
13989/*
13990 * This routine may get stubbed out in special compilations of the
13991 * e2fsck code..
13992 */
13993#ifndef EXT2_SPECIAL_DEVICE_SIZE
13994errcode_t e2fsck_get_device_size(e2fsck_t ctx)
13995{
13996 return (ext2fs_get_device_size(ctx->filesystem_name,
13997 EXT2_BLOCK_SIZE(ctx->fs->super),
13998 &ctx->num_blocks));
13999}
14000#endif
14001
14002/*
14003 * helper function to release an inode
14004 */
14005struct process_block_struct {
14006 e2fsck_t ctx;
14007 char *buf;
14008 struct problem_context *pctx;
14009 int truncating;
14010 int truncate_offset;
14011 e2_blkcnt_t truncate_block;
14012 int truncated_blocks;
14013 int abort;
14014 errcode_t errcode;
14015};
14016
14017static int release_inode_block(ext2_filsys fs,
14018 blk_t *block_nr,
14019 e2_blkcnt_t blockcnt,
14020 blk_t ref_blk EXT2FS_ATTR((unused)),
14021 int ref_offset EXT2FS_ATTR((unused)),
14022 void *priv_data)
14023{
14024 struct process_block_struct *pb;
14025 e2fsck_t ctx;
14026 struct problem_context *pctx;
14027 blk_t blk = *block_nr;
14028 int retval = 0;
14029
14030 pb = (struct process_block_struct *) priv_data;
14031 ctx = pb->ctx;
14032 pctx = pb->pctx;
14033
14034 pctx->blk = blk;
14035 pctx->blkcount = blockcnt;
14036
14037 if (HOLE_BLKADDR(blk))
14038 return 0;
14039
14040 if ((blk < fs->super->s_first_data_block) ||
14041 (blk >= fs->super->s_blocks_count)) {
14042 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
14043 return_abort:
14044 pb->abort = 1;
14045 return BLOCK_ABORT;
14046 }
14047
14048 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
14049 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
14050 goto return_abort;
14051 }
14052
14053 /*
14054 * If we are deleting an orphan, then we leave the fields alone.
14055 * If we are truncating an orphan, then update the inode fields
14056 * and clean up any partial block data.
14057 */
14058 if (pb->truncating) {
14059 /*
14060 * We only remove indirect blocks if they are
14061 * completely empty.
14062 */
14063 if (blockcnt < 0) {
14064 int i, limit;
14065 blk_t *bp;
14066
14067 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
14068 pb->buf);
14069 if (pb->errcode)
14070 goto return_abort;
14071
14072 limit = fs->blocksize >> 2;
14073 for (i = 0, bp = (blk_t *) pb->buf;
14074 i < limit; i++, bp++)
14075 if (*bp)
14076 return 0;
14077 }
14078 /*
14079 * We don't remove direct blocks until we've reached
14080 * the truncation block.
14081 */
14082 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
14083 return 0;
14084 /*
14085 * If part of the last block needs truncating, we do
14086 * it here.
14087 */
14088 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
14089 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
14090 pb->buf);
14091 if (pb->errcode)
14092 goto return_abort;
14093 memset(pb->buf + pb->truncate_offset, 0,
14094 fs->blocksize - pb->truncate_offset);
14095 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
14096 pb->buf);
14097 if (pb->errcode)
14098 goto return_abort;
14099 }
14100 pb->truncated_blocks++;
14101 *block_nr = 0;
14102 retval |= BLOCK_CHANGED;
14103 }
14104
14105 ext2fs_block_alloc_stats(fs, blk, -1);
14106 return retval;
14107}
14108
14109/*
14110 * This function releases an inode. Returns 1 if an inconsistency was
14111 * found. If the inode has a link count, then it is being truncated and
14112 * not deleted.
14113 */
14114static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
14115 struct ext2_inode *inode, char *block_buf,
14116 struct problem_context *pctx)
14117{
14118 struct process_block_struct pb;
14119 ext2_filsys fs = ctx->fs;
14120 errcode_t retval;
14121 __u32 count;
14122
14123 if (!ext2fs_inode_has_valid_blocks(inode))
14124 return 0;
14125
14126 pb.buf = block_buf + 3 * ctx->fs->blocksize;
14127 pb.ctx = ctx;
14128 pb.abort = 0;
14129 pb.errcode = 0;
14130 pb.pctx = pctx;
14131 if (inode->i_links_count) {
14132 pb.truncating = 1;
14133 pb.truncate_block = (e2_blkcnt_t)
14134 ((((long long)inode->i_size_high << 32) +
14135 inode->i_size + fs->blocksize - 1) /
14136 fs->blocksize);
14137 pb.truncate_offset = inode->i_size % fs->blocksize;
14138 } else {
14139 pb.truncating = 0;
14140 pb.truncate_block = 0;
14141 pb.truncate_offset = 0;
14142 }
14143 pb.truncated_blocks = 0;
14144 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
14145 block_buf, release_inode_block, &pb);
14146 if (retval) {
14147 com_err("release_inode_blocks", retval,
14148 _("while calling ext2fs_block_iterate for inode %d"),
14149 ino);
14150 return 1;
14151 }
14152 if (pb.abort)
14153 return 1;
14154
14155 /* Refresh the inode since ext2fs_block_iterate may have changed it */
14156 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
14157
14158 if (pb.truncated_blocks)
14159 inode->i_blocks -= pb.truncated_blocks *
14160 (fs->blocksize / 512);
14161
14162 if (inode->i_file_acl) {
14163 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
14164 block_buf, -1, &count);
14165 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
14166 retval = 0;
14167 count = 1;
14168 }
14169 if (retval) {
14170 com_err("release_inode_blocks", retval,
14171 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
14172 ino);
14173 return 1;
14174 }
14175 if (count == 0)
14176 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
14177 inode->i_file_acl = 0;
14178 }
14179 return 0;
14180}
14181
14182/*
14183 * This function releases all of the orphan inodes. It returns 1 if
14184 * it hit some error, and 0 on success.
14185 */
14186static int release_orphan_inodes(e2fsck_t ctx)
14187{
14188 ext2_filsys fs = ctx->fs;
14189 ext2_ino_t ino, next_ino;
14190 struct ext2_inode inode;
14191 struct problem_context pctx;
14192 char *block_buf;
14193
14194 if ((ino = fs->super->s_last_orphan) == 0)
14195 return 0;
14196
14197 /*
14198 * Win or lose, we won't be using the head of the orphan inode
14199 * list again.
14200 */
14201 fs->super->s_last_orphan = 0;
14202 ext2fs_mark_super_dirty(fs);
14203
14204 /*
14205 * If the filesystem contains errors, don't run the orphan
14206 * list, since the orphan list can't be trusted; and we're
14207 * going to be running a full e2fsck run anyway...
14208 */
14209 if (fs->super->s_state & EXT2_ERROR_FS)
14210 return 0;
14211
14212 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
14213 (ino > fs->super->s_inodes_count)) {
14214 clear_problem_context(&pctx);
14215 pctx.ino = ino;
14216 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
14217 return 1;
14218 }
14219
14220 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
14221 "block iterate buffer");
14222 e2fsck_read_bitmaps(ctx);
14223
14224 while (ino) {
14225 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
14226 clear_problem_context(&pctx);
14227 pctx.ino = ino;
14228 pctx.inode = &inode;
14229 pctx.str = inode.i_links_count ? _("Truncating") :
14230 _("Clearing");
14231
14232 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
14233
14234 next_ino = inode.i_dtime;
14235 if (next_ino &&
14236 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
14237 (next_ino > fs->super->s_inodes_count))) {
14238 pctx.ino = next_ino;
14239 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
14240 goto return_abort;
14241 }
14242
14243 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
14244 goto return_abort;
14245
14246 if (!inode.i_links_count) {
14247 ext2fs_inode_alloc_stats2(fs, ino, -1,
14248 LINUX_S_ISDIR(inode.i_mode));
14249 inode.i_dtime = time(0);
14250 } else {
14251 inode.i_dtime = 0;
14252 }
14253 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
14254 ino = next_ino;
14255 }
14256 ext2fs_free_mem(&block_buf);
14257 return 0;
14258return_abort:
14259 ext2fs_free_mem(&block_buf);
14260 return 1;
14261}
14262
14263/*
14264 * Check the resize inode to make sure it is sane. We check both for
14265 * the case where on-line resizing is not enabled (in which case the
14266 * resize inode should be cleared) as well as the case where on-line
14267 * resizing is enabled.
14268 */
14269static void check_resize_inode(e2fsck_t ctx)
14270{
14271 ext2_filsys fs = ctx->fs;
14272 struct ext2_inode inode;
14273 struct problem_context pctx;
14274 int i, j, gdt_off, ind_off;
14275 blk_t blk, pblk, expect;
14276 __u32 *dind_buf = 0, *ind_buf;
14277 errcode_t retval;
14278
14279 clear_problem_context(&pctx);
14280
14281 /*
14282 * If the resize inode feature isn't set, then
14283 * s_reserved_gdt_blocks must be zero.
14284 */
14285 if (!(fs->super->s_feature_compat &
14286 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
14287 if (fs->super->s_reserved_gdt_blocks) {
14288 pctx.num = fs->super->s_reserved_gdt_blocks;
14289 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
14290 &pctx)) {
14291 fs->super->s_reserved_gdt_blocks = 0;
14292 ext2fs_mark_super_dirty(fs);
14293 }
14294 }
14295 }
14296
14297 /* Read the resizde inode */
14298 pctx.ino = EXT2_RESIZE_INO;
14299 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
14300 if (retval) {
14301 if (fs->super->s_feature_compat &
14302 EXT2_FEATURE_COMPAT_RESIZE_INODE)
14303 ctx->flags |= E2F_FLAG_RESIZE_INODE;
14304 return;
14305 }
14306
14307 /*
14308 * If the resize inode feature isn't set, check to make sure
14309 * the resize inode is cleared; then we're done.
14310 */
14311 if (!(fs->super->s_feature_compat &
14312 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
14313 for (i=0; i < EXT2_N_BLOCKS; i++) {
14314 if (inode.i_block[i])
14315 break;
14316 }
14317 if ((i < EXT2_N_BLOCKS) &&
14318 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
14319 memset(&inode, 0, sizeof(inode));
14320 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
14321 "clear_resize");
14322 }
14323 return;
14324 }
14325
14326 /*
14327 * The resize inode feature is enabled; check to make sure the
14328 * only block in use is the double indirect block
14329 */
14330 blk = inode.i_block[EXT2_DIND_BLOCK];
14331 for (i=0; i < EXT2_N_BLOCKS; i++) {
14332 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
14333 break;
14334 }
14335 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
14336 !(inode.i_mode & LINUX_S_IFREG) ||
14337 (blk < fs->super->s_first_data_block ||
14338 blk >= fs->super->s_blocks_count)) {
14339 resize_inode_invalid:
14340 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
14341 memset(&inode, 0, sizeof(inode));
14342 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
14343 "clear_resize");
14344 ctx->flags |= E2F_FLAG_RESIZE_INODE;
14345 }
14346 if (!(ctx->options & E2F_OPT_READONLY)) {
14347 fs->super->s_state &= ~EXT2_VALID_FS;
14348 ext2fs_mark_super_dirty(fs);
14349 }
14350 goto cleanup;
14351 }
14352 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
14353 "resize dind buffer");
14354 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
14355
14356 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
14357 if (retval)
14358 goto resize_inode_invalid;
14359
14360 gdt_off = fs->desc_blocks;
14361 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
14362 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
14363 i++, gdt_off++, pblk++) {
14364 gdt_off %= fs->blocksize/4;
14365 if (dind_buf[gdt_off] != pblk)
14366 goto resize_inode_invalid;
14367 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
14368 if (retval)
14369 goto resize_inode_invalid;
14370 ind_off = 0;
14371 for (j = 1; j < fs->group_desc_count; j++) {
14372 if (!ext2fs_bg_has_super(fs, j))
14373 continue;
14374 expect = pblk + (j * fs->super->s_blocks_per_group);
14375 if (ind_buf[ind_off] != expect)
14376 goto resize_inode_invalid;
14377 ind_off++;
14378 }
14379 }
14380
14381cleanup:
14382 if (dind_buf)
14383 ext2fs_free_mem(&dind_buf);
14384
14385 }
14386
14387void check_super_block(e2fsck_t ctx)
14388{
14389 ext2_filsys fs = ctx->fs;
14390 blk_t first_block, last_block;
14391 struct ext2_super_block *sb = fs->super;
14392 struct ext2_group_desc *gd;
14393 blk_t blocks_per_group = fs->super->s_blocks_per_group;
14394 blk_t bpg_max;
14395 int inodes_per_block;
14396 int ipg_max;
14397 int inode_size;
14398 dgrp_t i;
14399 blk_t should_be;
14400 struct problem_context pctx;
14401 __u32 free_blocks = 0, free_inodes = 0;
14402
14403 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
14404 ipg_max = inodes_per_block * (blocks_per_group - 4);
14405 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
14406 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
14407 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
14408 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
14409 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
14410
14411 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
14412 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
14413 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
14414 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
14415 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
14416 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
14417
14418 clear_problem_context(&pctx);
14419
14420 /*
14421 * Verify the super block constants...
14422 */
14423 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
14424 MIN_CHECK, 1, 0);
14425 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
14426 MIN_CHECK, 1, 0);
14427 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
14428 MAX_CHECK, 0, sb->s_blocks_count);
14429 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
14430 MIN_CHECK | MAX_CHECK, 0,
14431 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
14432 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
14433 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
14434 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
14435 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
14436 bpg_max);
14437 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
14438 MIN_CHECK | MAX_CHECK, 8, bpg_max);
14439 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
14440 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
14441 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
14442 MAX_CHECK, 0, sb->s_blocks_count / 2);
14443 check_super_value(ctx, "reserved_gdt_blocks",
14444 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
14445 fs->blocksize/4);
14446 inode_size = EXT2_INODE_SIZE(sb);
14447 check_super_value(ctx, "inode_size",
14448 inode_size, MIN_CHECK | MAX_CHECK,
14449 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
14450 if (inode_size & (inode_size - 1)) {
14451 pctx.num = inode_size;
14452 pctx.str = "inode_size";
14453 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
14454 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
14455 return;
14456 }
14457
14458 if (!ctx->num_blocks) {
14459 pctx.errcode = e2fsck_get_device_size(ctx);
14460 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
14461 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
14462 ctx->flags |= E2F_FLAG_ABORT;
14463 return;
14464 }
14465 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
14466 (ctx->num_blocks < sb->s_blocks_count)) {
14467 pctx.blk = sb->s_blocks_count;
14468 pctx.blk2 = ctx->num_blocks;
14469 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
14470 ctx->flags |= E2F_FLAG_ABORT;
14471 return;
14472 }
14473 }
14474 }
14475
14476 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
14477 pctx.blk = EXT2_BLOCK_SIZE(sb);
14478 pctx.blk2 = EXT2_FRAG_SIZE(sb);
14479 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
14480 ctx->flags |= E2F_FLAG_ABORT;
14481 return;
14482 }
14483
14484 should_be = sb->s_frags_per_group >>
14485 (sb->s_log_block_size - sb->s_log_frag_size);
14486 if (sb->s_blocks_per_group != should_be) {
14487 pctx.blk = sb->s_blocks_per_group;
14488 pctx.blk2 = should_be;
14489 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
14490 ctx->flags |= E2F_FLAG_ABORT;
14491 return;
14492 }
14493
14494 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
14495 if (sb->s_first_data_block != should_be) {
14496 pctx.blk = sb->s_first_data_block;
14497 pctx.blk2 = should_be;
14498 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
14499 ctx->flags |= E2F_FLAG_ABORT;
14500 return;
14501 }
14502
14503 should_be = sb->s_inodes_per_group * fs->group_desc_count;
14504 if (sb->s_inodes_count != should_be) {
14505 pctx.ino = sb->s_inodes_count;
14506 pctx.ino2 = should_be;
14507 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
14508 sb->s_inodes_count = should_be;
14509 ext2fs_mark_super_dirty(fs);
14510 }
14511 }
14512
14513 /*
14514 * Verify the group descriptors....
14515 */
14516 first_block = sb->s_first_data_block;
14517 last_block = first_block + blocks_per_group;
14518
14519 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
14520 pctx.group = i;
14521
14522 if (i == fs->group_desc_count - 1)
14523 last_block = sb->s_blocks_count;
14524 if ((gd->bg_block_bitmap < first_block) ||
14525 (gd->bg_block_bitmap >= last_block)) {
14526 pctx.blk = gd->bg_block_bitmap;
14527 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
14528 gd->bg_block_bitmap = 0;
14529 }
14530 if (gd->bg_block_bitmap == 0) {
14531 ctx->invalid_block_bitmap_flag[i]++;
14532 ctx->invalid_bitmaps++;
14533 }
14534 if ((gd->bg_inode_bitmap < first_block) ||
14535 (gd->bg_inode_bitmap >= last_block)) {
14536 pctx.blk = gd->bg_inode_bitmap;
14537 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
14538 gd->bg_inode_bitmap = 0;
14539 }
14540 if (gd->bg_inode_bitmap == 0) {
14541 ctx->invalid_inode_bitmap_flag[i]++;
14542 ctx->invalid_bitmaps++;
14543 }
14544 if ((gd->bg_inode_table < first_block) ||
14545 ((gd->bg_inode_table +
14546 fs->inode_blocks_per_group - 1) >= last_block)) {
14547 pctx.blk = gd->bg_inode_table;
14548 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
14549 gd->bg_inode_table = 0;
14550 }
14551 if (gd->bg_inode_table == 0) {
14552 ctx->invalid_inode_table_flag[i]++;
14553 ctx->invalid_bitmaps++;
14554 }
14555 free_blocks += gd->bg_free_blocks_count;
14556 free_inodes += gd->bg_free_inodes_count;
14557 first_block += sb->s_blocks_per_group;
14558 last_block += sb->s_blocks_per_group;
14559
14560 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
14561 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
14562 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
14563 ext2fs_unmark_valid(fs);
14564
14565 }
14566
14567 /*
14568 * Update the global counts from the block group counts. This
14569 * is needed for an experimental patch which eliminates
14570 * locking the entire filesystem when allocating blocks or
14571 * inodes; if the filesystem is not unmounted cleanly, the
14572 * global counts may not be accurate.
14573 */
14574 if ((free_blocks != sb->s_free_blocks_count) ||
14575 (free_inodes != sb->s_free_inodes_count)) {
14576 if (ctx->options & E2F_OPT_READONLY)
14577 ext2fs_unmark_valid(fs);
14578 else {
14579 sb->s_free_blocks_count = free_blocks;
14580 sb->s_free_inodes_count = free_inodes;
14581 ext2fs_mark_super_dirty(fs);
14582 }
14583 }
14584
14585 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
14586 (sb->s_free_inodes_count > sb->s_inodes_count))
14587 ext2fs_unmark_valid(fs);
14588
14589
14590 /*
14591 * If we have invalid bitmaps, set the error state of the
14592 * filesystem.
14593 */
14594 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
14595 sb->s_state &= ~EXT2_VALID_FS;
14596 ext2fs_mark_super_dirty(fs);
14597 }
14598
14599 clear_problem_context(&pctx);
14600
14601#ifndef EXT2_SKIP_UUID
14602 /*
14603 * If the UUID field isn't assigned, assign it.
14604 */
14605 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
14606 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
14607 uuid_generate(sb->s_uuid);
14608 ext2fs_mark_super_dirty(fs);
14609 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
14610 }
14611 }
14612#endif
14613
14614 /*
14615 * For the Hurd, check to see if the filetype option is set,
14616 * since it doesn't support it.
14617 */
14618 if (!(ctx->options & E2F_OPT_READONLY) &&
14619 fs->super->s_creator_os == EXT2_OS_HURD &&
14620 (fs->super->s_feature_incompat &
14621 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
14622 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
14623 fs->super->s_feature_incompat &=
14624 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
14625 ext2fs_mark_super_dirty(fs);
14626
14627 }
14628 }
14629
14630 /*
14631 * If we have any of the compatibility flags set, we need to have a
14632 * revision 1 filesystem. Most kernels will not check the flags on
14633 * a rev 0 filesystem and we may have corruption issues because of
14634 * the incompatible changes to the filesystem.
14635 */
14636 if (!(ctx->options & E2F_OPT_READONLY) &&
14637 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
14638 (fs->super->s_feature_compat ||
14639 fs->super->s_feature_ro_compat ||
14640 fs->super->s_feature_incompat) &&
14641 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
14642 ext2fs_update_dynamic_rev(fs);
14643 ext2fs_mark_super_dirty(fs);
14644 }
14645
14646 check_resize_inode(ctx);
14647
14648 /*
14649 * Clean up any orphan inodes, if present.
14650 */
14651 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
14652 fs->super->s_state &= ~EXT2_VALID_FS;
14653 ext2fs_mark_super_dirty(fs);
14654 }
14655
14656 /*
14657 * Move the ext3 journal file, if necessary.
14658 */
14659 e2fsck_move_ext3_journal(ctx);
14660 return;
14661}
14662/*
14663 * swapfs.c --- byte-swap an ext2 filesystem
14664 *
14665 * Copyright 1996, 1997 by Theodore Ts'o
14666 *
14667 * %Begin-Header%
14668 * This file may be redistributed under the terms of the GNU Public
14669 * License.
14670 * %End-Header%
14671 *
14672 */
14673
14674#ifdef ENABLE_SWAPFS
14675
14676struct swap_block_struct {
14677 ext2_ino_t ino;
14678 int isdir;
14679 errcode_t errcode;
14680 char *dir_buf;
14681 struct ext2_inode *inode;
14682};
14683
14684/*
14685 * This is a helper function for block_iterate. We mark all of the
14686 * indirect and direct blocks as changed, so that block_iterate will
14687 * write them out.
14688 */
14689static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
14690 void *priv_data)
14691{
14692 errcode_t retval;
14693
14694 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
14695
14696 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
14697 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
14698 if (retval) {
14699 sb->errcode = retval;
14700 return BLOCK_ABORT;
14701 }
14702 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
14703 if (retval) {
14704 sb->errcode = retval;
14705 return BLOCK_ABORT;
14706 }
14707 }
14708 if (blockcnt >= 0) {
14709 if (blockcnt < EXT2_NDIR_BLOCKS)
14710 return 0;
14711 return BLOCK_CHANGED;
14712 }
14713 if (blockcnt == BLOCK_COUNT_IND) {
14714 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
14715 return 0;
14716 return BLOCK_CHANGED;
14717 }
14718 if (blockcnt == BLOCK_COUNT_DIND) {
14719 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
14720 return 0;
14721 return BLOCK_CHANGED;
14722 }
14723 if (blockcnt == BLOCK_COUNT_TIND) {
14724 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
14725 return 0;
14726 return BLOCK_CHANGED;
14727 }
14728 return BLOCK_CHANGED;
14729}
14730
14731/*
14732 * This function is responsible for byte-swapping all of the indirect,
14733 * block pointers. It is also responsible for byte-swapping directories.
14734 */
14735static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
14736 struct ext2_inode *inode)
14737{
14738 errcode_t retval;
14739 struct swap_block_struct sb;
14740
14741 sb.ino = ino;
14742 sb.inode = inode;
14743 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
14744 sb.errcode = 0;
14745 sb.isdir = 0;
14746 if (LINUX_S_ISDIR(inode->i_mode))
14747 sb.isdir = 1;
14748
14749 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
14750 swap_block, &sb);
14751 if (retval) {
14752 com_err("swap_inode_blocks", retval,
14753 _("while calling ext2fs_block_iterate"));
14754 ctx->flags |= E2F_FLAG_ABORT;
14755 return;
14756 }
14757 if (sb.errcode) {
14758 com_err("swap_inode_blocks", sb.errcode,
14759 _("while calling iterator function"));
14760 ctx->flags |= E2F_FLAG_ABORT;
14761 return;
14762 }
14763}
14764
14765static void swap_inodes(e2fsck_t ctx)
14766{
14767 ext2_filsys fs = ctx->fs;
14768 dgrp_t group;
14769 unsigned int i;
14770 ext2_ino_t ino = 1;
14771 char *buf, *block_buf;
14772 errcode_t retval;
14773 struct ext2_inode * inode;
14774
14775 e2fsck_use_inode_shortcuts(ctx, 1);
14776
14777 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
14778 &buf);
14779 if (retval) {
14780 com_err("swap_inodes", retval,
14781 _("while allocating inode buffer"));
14782 ctx->flags |= E2F_FLAG_ABORT;
14783 return;
14784 }
14785 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
14786 "block interate buffer");
14787 for (group = 0; group < fs->group_desc_count; group++) {
14788 retval = io_channel_read_blk(fs->io,
14789 fs->group_desc[group].bg_inode_table,
14790 fs->inode_blocks_per_group, buf);
14791 if (retval) {
14792 com_err("swap_inodes", retval,
14793 _("while reading inode table (group %d)"),
14794 group);
14795 ctx->flags |= E2F_FLAG_ABORT;
14796 return;
14797 }
14798 inode = (struct ext2_inode *) buf;
14799 for (i=0; i < fs->super->s_inodes_per_group;
14800 i++, ino++, inode++) {
14801 ctx->stashed_ino = ino;
14802 ctx->stashed_inode = inode;
14803
14804 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
14805 ext2fs_swap_inode(fs, inode, inode, 0);
14806
14807 /*
14808 * Skip deleted files.
14809 */
14810 if (inode->i_links_count == 0)
14811 continue;
14812
14813 if (LINUX_S_ISDIR(inode->i_mode) ||
14814 ((inode->i_block[EXT2_IND_BLOCK] ||
14815 inode->i_block[EXT2_DIND_BLOCK] ||
14816 inode->i_block[EXT2_TIND_BLOCK]) &&
14817 ext2fs_inode_has_valid_blocks(inode)))
14818 swap_inode_blocks(ctx, ino, block_buf, inode);
14819
14820 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14821 return;
14822
14823 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14824 ext2fs_swap_inode(fs, inode, inode, 1);
14825 }
14826 retval = io_channel_write_blk(fs->io,
14827 fs->group_desc[group].bg_inode_table,
14828 fs->inode_blocks_per_group, buf);
14829 if (retval) {
14830 com_err("swap_inodes", retval,
14831 _("while writing inode table (group %d)"),
14832 group);
14833 ctx->flags |= E2F_FLAG_ABORT;
14834 return;
14835 }
14836 }
14837 ext2fs_free_mem(&buf);
14838 ext2fs_free_mem(&block_buf);
14839 e2fsck_use_inode_shortcuts(ctx, 0);
14840 ext2fs_flush_icache(fs);
14841}
14842
14843#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
14844/*
14845 * On the PowerPC, the big-endian variant of the ext2 filesystem
14846 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
14847 * of each word. Thus a bitmap with only bit 0 set would be, as
14848 * a string of bytes, 00 00 00 01 00 ...
14849 * To cope with this, we byte-reverse each word of a bitmap if
14850 * we have a big-endian filesystem, that is, if we are *not*
14851 * byte-swapping other word-sized numbers.
14852 */
14853#define EXT2_BIG_ENDIAN_BITMAPS
14854#endif
14855
14856#ifdef EXT2_BIG_ENDIAN_BITMAPS
14857static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
14858{
14859 __u32 *p = (__u32 *) bmap->bitmap;
14860 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
14861
14862 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
14863 *p = ext2fs_swab32(*p);
14864}
14865#endif
14866
14867
14868#ifdef ENABLE_SWAPFS
14869void swap_filesys(e2fsck_t ctx)
14870{
14871 ext2_filsys fs = ctx->fs;
14872#ifdef RESOURCE_TRACK
14873 struct resource_track rtrack;
14874
14875 init_resource_track(&rtrack);
14876#endif
14877
14878 if (!(ctx->options & E2F_OPT_PREEN))
14879 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
14880
14881#ifdef MTRACE
14882 mtrace_print("Byte swap");
14883#endif
14884
14885 if (fs->super->s_mnt_count) {
14886 fprintf(stderr, _("%s: the filesystem must be freshly "
14887 "checked using fsck\n"
14888 "and not mounted before trying to "
14889 "byte-swap it.\n"), ctx->device_name);
14890 ctx->flags |= E2F_FLAG_ABORT;
14891 return;
14892 }
14893 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
14894 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
14895 EXT2_FLAG_SWAP_BYTES_WRITE);
14896 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
14897 } else {
14898 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
14899 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
14900 }
14901 swap_inodes(ctx);
14902 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
14903 return;
14904 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
14905 fs->flags |= EXT2_FLAG_SWAP_BYTES;
14906 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
14907 EXT2_FLAG_SWAP_BYTES_WRITE);
14908
14909#ifdef EXT2_BIG_ENDIAN_BITMAPS
14910 e2fsck_read_bitmaps(ctx);
14911 ext2fs_swap_bitmap(fs->inode_map);
14912 ext2fs_swap_bitmap(fs->block_map);
14913 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
14914#endif
14915 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
14916 ext2fs_flush(fs);
14917 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
14918
14919#ifdef RESOURCE_TRACK
14920 if (ctx->options & E2F_OPT_TIME2)
14921 print_resource_track(_("Byte swap"), &rtrack);
14922#endif
14923}
14924#endif /* ENABLE_SWAPFS */
14925
14926#endif
14927/*
14928 * util.c --- miscellaneous utilities
14929 *
14930 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
14931 *
14932 * %Begin-Header%
14933 * This file may be redistributed under the terms of the GNU Public
14934 * License.
14935 * %End-Header%
14936 */
14937
14938#ifdef HAVE_CONIO_H
14939#undef HAVE_TERMIOS_H
14940#include <conio.h>
14941#define read_a_char() getch()
14942#else
14943#ifdef HAVE_TERMIOS_H
14944#include <termios.h>
14945#endif
14946#endif
14947
14948#if 0
14949void fatal_error(e2fsck_t ctx, const char *msg)
14950{
14951 if (msg)
14952 fprintf (stderr, "e2fsck: %s\n", msg);
14953 if (ctx->fs && ctx->fs->io) {
14954 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
14955 io_channel_flush(ctx->fs->io);
14956 else
14957 fprintf(stderr, "e2fsck: io manager magic bad!\n");
14958 }
14959 ctx->flags |= E2F_FLAG_ABORT;
14960 if (ctx->flags & E2F_FLAG_SETJMP_OK)
14961 longjmp(ctx->abort_loc, 1);
14962 exit(FSCK_ERROR);
14963}
14964#endif
14965
14966void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
14967 const char *description)
14968{
14969 void *ret;
14970 char buf[256];
14971
14972#ifdef DEBUG_ALLOCATE_MEMORY
14973 printf("Allocating %d bytes for %s...\n", size, description);
14974#endif
14975 ret = malloc(size);
14976 if (!ret) {
14977 sprintf(buf, "Can't allocate %s\n", description);
14978 fatal_error(ctx, buf);
14979 }
14980 memset(ret, 0, size);
14981 return ret;
14982}
14983
14984char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
14985 const char *str, int len)
14986{
14987 char *ret;
14988
14989 if (!str)
14990 return NULL;
14991 if (!len)
14992 len = strlen(str);
14993 ret = malloc(len+1);
14994 if (ret) {
14995 strncpy(ret, str, len);
14996 ret[len] = 0;
14997 }
14998 return ret;
14999}
15000
15001#ifndef HAVE_CONIO_H
15002static int read_a_char(void)
15003{
15004 char c;
15005 int r;
15006 int fail = 0;
15007
15008 while(1) {
15009 if (e2fsck_global_ctx &&
15010 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
15011 return 3;
15012 }
15013 r = read(0, &c, 1);
15014 if (r == 1)
15015 return c;
15016 if (fail++ > 100)
15017 break;
15018 }
15019 return EOF;
15020}
15021#endif
15022
15023int ask_yn(const char * string, int def)
15024{
15025 int c;
15026 const char *defstr;
15027 const char *short_yes = _("yY");
15028 const char *short_no = _("nN");
15029
15030#ifdef HAVE_TERMIOS_H
15031 struct termios termios, tmp;
15032
15033 tcgetattr (0, &termios);
15034 tmp = termios;
15035 tmp.c_lflag &= ~(ICANON | ECHO);
15036 tmp.c_cc[VMIN] = 1;
15037 tmp.c_cc[VTIME] = 0;
15038 tcsetattr (0, TCSANOW, &tmp);
15039#endif
15040
15041 if (def == 1)
15042 defstr = _(_("<y>"));
15043 else if (def == 0)
15044 defstr = _(_("<n>"));
15045 else
15046 defstr = _(" (y/n)");
15047 printf("%s%s? ", string, defstr);
15048 while (1) {
15049 fflush (stdout);
15050 if ((c = read_a_char()) == EOF)
15051 break;
15052 if (c == 3) {
15053#ifdef HAVE_TERMIOS_H
15054 tcsetattr (0, TCSANOW, &termios);
15055#endif
15056 if (e2fsck_global_ctx &&
15057 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
15058 puts("\n");
15059 longjmp(e2fsck_global_ctx->abort_loc, 1);
15060 }
15061 puts(_("cancelled!\n"));
15062 return 0;
15063 }
15064 if (strchr(short_yes, (char) c)) {
15065 def = 1;
15066 break;
15067 }
15068 else if (strchr(short_no, (char) c)) {
15069 def = 0;
15070 break;
15071 }
15072 else if ((c == ' ' || c == '\n') && (def != -1))
15073 break;
15074 }
15075 if (def)
15076 puts(_("yes\n"));
15077 else
15078 puts (_("no\n"));
15079#ifdef HAVE_TERMIOS_H
15080 tcsetattr (0, TCSANOW, &termios);
15081#endif
15082 return def;
15083}
15084
15085int ask (e2fsck_t ctx, const char * string, int def)
15086{
15087 if (ctx->options & E2F_OPT_NO) {
15088 printf (_("%s? no\n\n"), string);
15089 return 0;
15090 }
15091 if (ctx->options & E2F_OPT_YES) {
15092 printf (_("%s? yes\n\n"), string);
15093 return 1;
15094 }
15095 if (ctx->options & E2F_OPT_PREEN) {
15096 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
15097 return def;
15098 }
15099 return ask_yn(string, def);
15100}
15101
15102void e2fsck_read_bitmaps(e2fsck_t ctx)
15103{
15104 ext2_filsys fs = ctx->fs;
15105 errcode_t retval;
15106
15107 if (ctx->invalid_bitmaps) {
15108 com_err(ctx->program_name, 0,
15109 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
15110 ctx->device_name);
15111 fatal_error(ctx, 0);
15112 }
15113
15114 ehandler_operation(_("reading inode and block bitmaps"));
15115 retval = ext2fs_read_bitmaps(fs);
15116 ehandler_operation(0);
15117 if (retval) {
15118 com_err(ctx->program_name, retval,
15119 _("while retrying to read bitmaps for %s"),
15120 ctx->device_name);
15121 fatal_error(ctx, 0);
15122 }
15123}
15124
15125void e2fsck_write_bitmaps(e2fsck_t ctx)
15126{
15127 ext2_filsys fs = ctx->fs;
15128 errcode_t retval;
15129
15130 if (ext2fs_test_bb_dirty(fs)) {
15131 ehandler_operation(_("writing block bitmaps"));
15132 retval = ext2fs_write_block_bitmap(fs);
15133 ehandler_operation(0);
15134 if (retval) {
15135 com_err(ctx->program_name, retval,
15136 _("while retrying to write block bitmaps for %s"),
15137 ctx->device_name);
15138 fatal_error(ctx, 0);
15139 }
15140 }
15141
15142 if (ext2fs_test_ib_dirty(fs)) {
15143 ehandler_operation(_("writing inode bitmaps"));
15144 retval = ext2fs_write_inode_bitmap(fs);
15145 ehandler_operation(0);
15146 if (retval) {
15147 com_err(ctx->program_name, retval,
15148 _("while retrying to write inode bitmaps for %s"),
15149 ctx->device_name);
15150 fatal_error(ctx, 0);
15151 }
15152 }
15153}
15154
15155void preenhalt(e2fsck_t ctx)
15156{
15157 ext2_filsys fs = ctx->fs;
15158
15159 if (!(ctx->options & E2F_OPT_PREEN))
15160 return;
15161 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
15162 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
15163 ctx->device_name);
15164 if (fs != NULL) {
15165 fs->super->s_state |= EXT2_ERROR_FS;
15166 ext2fs_mark_super_dirty(fs);
15167 ext2fs_close(fs);
15168 }
15169 exit(FSCK_UNCORRECTED);
15170}
15171
15172#ifdef RESOURCE_TRACK
15173void init_resource_track(struct resource_track *track)
15174{
15175#ifdef HAVE_GETRUSAGE
15176 struct rusage r;
15177#endif
15178
15179 track->brk_start = sbrk(0);
15180 gettimeofday(&track->time_start, 0);
15181#ifdef HAVE_GETRUSAGE
15182#ifdef sun
15183 memset(&r, 0, sizeof(struct rusage));
15184#endif
15185 getrusage(RUSAGE_SELF, &r);
15186 track->user_start = r.ru_utime;
15187 track->system_start = r.ru_stime;
15188#else
15189 track->user_start.tv_sec = track->user_start.tv_usec = 0;
15190 track->system_start.tv_sec = track->system_start.tv_usec = 0;
15191#endif
15192}
15193
15194static _INLINE_ float timeval_subtract(struct timeval *tv1,
15195 struct timeval *tv2)
15196{
15197 return ((tv1->tv_sec - tv2->tv_sec) +
15198 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
15199}
15200
15201void print_resource_track(const char *desc, struct resource_track *track)
15202{
15203#ifdef HAVE_GETRUSAGE
15204 struct rusage r;
15205#endif
15206#ifdef HAVE_MALLINFO
15207 struct mallinfo malloc_info;
15208#endif
15209 struct timeval time_end;
15210
15211 gettimeofday(&time_end, 0);
15212
15213 if (desc)
15214 printf("%s: ", desc);
15215
15216#ifdef HAVE_MALLINFO
15217#define kbytes(x) (((x) + 1023) / 1024)
15218
15219 malloc_info = mallinfo();
15220 printf(_("Memory used: %dk/%dk (%dk/%dk), "),
15221 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
15222 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
15223#else
15224 printf(_("Memory used: %d, "),
15225 (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
15226#endif
15227#ifdef HAVE_GETRUSAGE
15228 getrusage(RUSAGE_SELF, &r);
15229
15230 printf(_("time: %5.2f/%5.2f/%5.2f\n"),
15231 timeval_subtract(&time_end, &track->time_start),
15232 timeval_subtract(&r.ru_utime, &track->user_start),
15233 timeval_subtract(&r.ru_stime, &track->system_start));
15234#else
15235 printf(_("elapsed time: %6.3f\n"),
15236 timeval_subtract(&time_end, &track->time_start));
15237#endif
15238}
15239#endif /* RESOURCE_TRACK */
15240
15241void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
15242 struct ext2_inode * inode, const char *proc)
15243{
15244 int retval;
15245
15246 retval = ext2fs_read_inode(ctx->fs, ino, inode);
15247 if (retval) {
15248 com_err("ext2fs_read_inode", retval,
15249 _("while reading inode %ld in %s"), ino, proc);
15250 fatal_error(ctx, 0);
15251 }
15252}
15253
15254extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
15255 struct ext2_inode * inode, int bufsize,
15256 const char *proc)
15257{
15258 int retval;
15259
15260 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
15261 if (retval) {
15262 com_err("ext2fs_write_inode", retval,
15263 _("while writing inode %ld in %s"), ino, proc);
15264 fatal_error(ctx, 0);
15265 }
15266}
15267
15268extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
15269 struct ext2_inode * inode, const char *proc)
15270{
15271 int retval;
15272
15273 retval = ext2fs_write_inode(ctx->fs, ino, inode);
15274 if (retval) {
15275 com_err("ext2fs_write_inode", retval,
15276 _("while writing inode %ld in %s"), ino, proc);
15277 fatal_error(ctx, 0);
15278 }
15279}
15280
15281#ifdef MTRACE
15282void mtrace_print(char *mesg)
15283{
15284 FILE *malloc_get_mallstream();
15285 FILE *f = malloc_get_mallstream();
15286
15287 if (f)
15288 fprintf(f, "============= %s\n", mesg);
15289}
15290#endif
15291
15292blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
15293 io_manager manager)
15294{
15295 struct ext2_super_block *sb;
15296 io_channel io = NULL;
15297 void *buf = NULL;
15298 int blocksize;
15299 blk_t superblock, ret_sb = 8193;
15300
15301 if (fs && fs->super) {
15302 ret_sb = (fs->super->s_blocks_per_group +
15303 fs->super->s_first_data_block);
15304 if (ctx) {
15305 ctx->superblock = ret_sb;
15306 ctx->blocksize = fs->blocksize;
15307 }
15308 return ret_sb;
15309 }
15310
15311 if (ctx) {
15312 if (ctx->blocksize) {
15313 ret_sb = ctx->blocksize * 8;
15314 if (ctx->blocksize == 1024)
15315 ret_sb++;
15316 ctx->superblock = ret_sb;
15317 return ret_sb;
15318 }
15319 ctx->superblock = ret_sb;
15320 ctx->blocksize = 1024;
15321 }
15322
15323 if (!name || !manager)
15324 goto cleanup;
15325
15326 if (manager->open(name, 0, &io) != 0)
15327 goto cleanup;
15328
15329 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
15330 goto cleanup;
15331 sb = (struct ext2_super_block *) buf;
15332
15333 for (blocksize = EXT2_MIN_BLOCK_SIZE;
15334 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
15335 superblock = blocksize*8;
15336 if (blocksize == 1024)
15337 superblock++;
15338 io_channel_set_blksize(io, blocksize);
15339 if (io_channel_read_blk(io, superblock,
15340 -SUPERBLOCK_SIZE, buf))
15341 continue;
15342#ifdef EXT2FS_ENABLE_SWAPFS
15343 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
15344 ext2fs_swap_super(sb);
15345#endif
15346 if (sb->s_magic == EXT2_SUPER_MAGIC) {
15347 ret_sb = superblock;
15348 if (ctx) {
15349 ctx->superblock = superblock;
15350 ctx->blocksize = blocksize;
15351 }
15352 break;
15353 }
15354 }
15355
15356cleanup:
15357 if (io)
15358 io_channel_close(io);
15359 if (buf)
15360 ext2fs_free_mem(&buf);
15361 return (ret_sb);
15362}
15363
15364/*
15365 * Given a mode, return the ext2 file type
15366 */
15367int ext2_file_type(unsigned int mode)
15368{
15369 if (LINUX_S_ISREG(mode))
15370 return EXT2_FT_REG_FILE;
15371
15372 if (LINUX_S_ISDIR(mode))
15373 return EXT2_FT_DIR;
15374
15375 if (LINUX_S_ISCHR(mode))
15376 return EXT2_FT_CHRDEV;
15377
15378 if (LINUX_S_ISBLK(mode))
15379 return EXT2_FT_BLKDEV;
15380
15381 if (LINUX_S_ISLNK(mode))
15382 return EXT2_FT_SYMLINK;
15383
15384 if (LINUX_S_ISFIFO(mode))
15385 return EXT2_FT_FIFO;
15386
15387 if (LINUX_S_ISSOCK(mode))
15388 return EXT2_FT_SOCK;
15389
15390 return 0;
15391}
15392/*
15393 * unix.c - The unix-specific code for e2fsck
15394 *
15395 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
15396 *
15397 * %Begin-Header%
15398 * This file may be redistributed under the terms of the GNU Public
15399 * License.
15400 * %End-Header%
15401 */
15402
46 15403
47#include "e2fsbb.h"
48#include "e2fsck/e2fsck.h"
49#include "e2fsck/problem.h"
50 15404
51/* Command line options */ 15405/* Command line options */
52static int swapfs; 15406static int swapfs;
53#ifdef ENABLE_SWAPFS 15407#ifdef ENABLE_SWAPFS
54static int normalize_swapfs; 15408static int normalize_swapfs;
55#endif 15409#endif
56static int cflag; /* check disk */ 15410static int cflag; /* check disk */
57static int show_version_only; 15411static int show_version_only;
58static int verbose; 15412static int verbose;
59 15413
@@ -61,9 +15415,7 @@ static int replace_bad_blocks;
61static int keep_bad_blocks; 15415static int keep_bad_blocks;
62static char *bad_blocks_file; 15416static char *bad_blocks_file;
63 15417
64e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ 15418#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
65
66#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
67int journal_enable_debug = -1; 15419int journal_enable_debug = -1;
68#endif 15420#endif
69 15421
@@ -96,7 +15448,7 @@ static void usage(e2fsck_t ctx)
96} 15448}
97#endif 15449#endif
98 15450
99static void show_stats(e2fsck_t ctx) 15451static void show_stats(e2fsck_t ctx)
100{ 15452{
101 ext2_filsys fs = ctx->fs; 15453 ext2_filsys fs = ctx->fs;
102 int inodes, inodes_used, blocks, blocks_used; 15454 int inodes, inodes_used, blocks, blocks_used;
@@ -116,7 +15468,7 @@ static void show_stats(e2fsck_t ctx)
116 15468
117 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used; 15469 frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
118 frag_percent = (frag_percent + 5) / 10; 15470 frag_percent = (frag_percent + 5) / 10;
119 15471
120 if (!verbose) { 15472 if (!verbose) {
121 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", 15473 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
122 ctx->device_name, inodes_used, inodes, 15474 ctx->device_name, inodes_used, inodes,
@@ -167,8 +15519,8 @@ static void show_stats(e2fsck_t ctx)
167 15519
168static void check_mount(e2fsck_t ctx) 15520static void check_mount(e2fsck_t ctx)
169{ 15521{
170 errcode_t retval; 15522 errcode_t retval;
171 int cont; 15523 int cont;
172 15524
173 retval = ext2fs_check_if_mounted(ctx->filesystem_name, 15525 retval = ext2fs_check_if_mounted(ctx->filesystem_name,
174 &ctx->mount_flags); 15526 &ctx->mount_flags);
@@ -209,15 +15561,15 @@ static void check_mount(e2fsck_t ctx)
209 15561
210static int is_on_batt(void) 15562static int is_on_batt(void)
211{ 15563{
212 FILE *f; 15564 FILE *f;
213 DIR *d; 15565 DIR *d;
214 char tmp[80], tmp2[80], fname[80]; 15566 char tmp[80], tmp2[80], fname[80];
215 unsigned int acflag; 15567 unsigned int acflag;
216 struct dirent* de; 15568 struct dirent* de;
217 15569
218 f = fopen("/proc/apm", "r"); 15570 f = fopen("/proc/apm", "r");
219 if (f) { 15571 if (f) {
220 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4) 15572 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
221 acflag = 1; 15573 acflag = 1;
222 fclose(f); 15574 fclose(f);
223 return (acflag != 1); 15575 return (acflag != 1);
@@ -227,7 +15579,7 @@ static int is_on_batt(void)
227 while ((de=readdir(d)) != NULL) { 15579 while ((de=readdir(d)) != NULL) {
228 if (!strncmp(".", de->d_name, 1)) 15580 if (!strncmp(".", de->d_name, 1))
229 continue; 15581 continue;
230 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state", 15582 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state",
231 de->d_name); 15583 de->d_name);
232 f = fopen(fname, "r"); 15584 f = fopen(fname, "r");
233 if (!f) 15585 if (!f)
@@ -258,11 +15610,11 @@ static void check_if_skip(e2fsck_t ctx)
258 long next_check; 15610 long next_check;
259 int batt = is_on_batt(); 15611 int batt = is_on_batt();
260 time_t now = time(0); 15612 time_t now = time(0);
261 15613
262 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file || 15614 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file ||
263 cflag || swapfs) 15615 cflag || swapfs)
264 return; 15616 return;
265 15617
266 if ((fs->super->s_state & EXT2_ERROR_FS) || 15618 if ((fs->super->s_state & EXT2_ERROR_FS) ||
267 !ext2fs_test_valid(fs)) 15619 !ext2fs_test_valid(fs))
268 reason = _(" contains a file system with errors"); 15620 reason = _(" contains a file system with errors");
@@ -273,15 +15625,15 @@ static void check_if_skip(e2fsck_t ctx)
273 (unsigned) fs->super->s_max_mnt_count)) { 15625 (unsigned) fs->super->s_max_mnt_count)) {
274 reason = _(" has been mounted %u times without being checked"); 15626 reason = _(" has been mounted %u times without being checked");
275 reason_arg = fs->super->s_mnt_count; 15627 reason_arg = fs->super->s_mnt_count;
276 if (batt && (fs->super->s_mnt_count < 15628 if (batt && (fs->super->s_mnt_count <
277 (unsigned) fs->super->s_max_mnt_count*2)) 15629 (unsigned) fs->super->s_max_mnt_count*2))
278 reason = 0; 15630 reason = 0;
279 } else if (fs->super->s_checkinterval && 15631 } else if (fs->super->s_checkinterval &&
280 ((now - fs->super->s_lastcheck) >= 15632 ((now - fs->super->s_lastcheck) >=
281 fs->super->s_checkinterval)) { 15633 fs->super->s_checkinterval)) {
282 reason = _(" has gone %u days without being checked"); 15634 reason = _(" has gone %u days without being checked");
283 reason_arg = (now - fs->super->s_lastcheck)/(3600*24); 15635 reason_arg = (now - fs->super->s_lastcheck)/(3600*24);
284 if (batt && ((now - fs->super->s_lastcheck) < 15636 if (batt && ((now - fs->super->s_lastcheck) <
285 fs->super->s_checkinterval*2)) 15637 fs->super->s_checkinterval*2))
286 reason = 0; 15638 reason = 0;
287 } 15639 }
@@ -299,7 +15651,7 @@ static void check_if_skip(e2fsck_t ctx)
299 next_check = 100000; 15651 next_check = 100000;
300 if (fs->super->s_max_mnt_count > 0) { 15652 if (fs->super->s_max_mnt_count > 0) {
301 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count; 15653 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count;
302 if (next_check <= 0) 15654 if (next_check <= 0)
303 next_check = 1; 15655 next_check = 1;
304 } 15656 }
305 if (fs->super->s_checkinterval && 15657 if (fs->super->s_checkinterval &&
@@ -322,10 +15674,10 @@ static void check_if_skip(e2fsck_t ctx)
322 * For completion notice 15674 * For completion notice
323 */ 15675 */
324struct percent_tbl { 15676struct percent_tbl {
325 int max_pass; 15677 int max_pass;
326 int table[32]; 15678 int table[32];
327}; 15679};
328struct percent_tbl e2fsck_tbl = { 15680static struct percent_tbl e2fsck_tbl = {
329 5, { 0, 70, 90, 92, 95, 100 } 15681 5, { 0, 70, 90, 92, 95, 100 }
330}; 15682};
331static char bar[128], spaces[128]; 15683static char bar[128], spaces[128];
@@ -333,8 +15685,8 @@ static char bar[128], spaces[128];
333static float calc_percent(struct percent_tbl *tbl, int pass, int curr, 15685static float calc_percent(struct percent_tbl *tbl, int pass, int curr,
334 int max) 15686 int max)
335{ 15687{
336 float percent; 15688 float percent;
337 15689
338 if (pass <= 0) 15690 if (pass <= 0)
339 return 0.0; 15691 return 0.0;
340 if (pass > tbl->max_pass || max == 0) 15692 if (pass > tbl->max_pass || max == 0)
@@ -348,7 +15700,7 @@ extern void e2fsck_clear_progbar(e2fsck_t ctx)
348{ 15700{
349 if (!(ctx->flags & E2F_FLAG_PROG_BAR)) 15701 if (!(ctx->flags & E2F_FLAG_PROG_BAR))
350 return; 15702 return;
351 15703
352 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80), 15704 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80),
353 ctx->stop_meta); 15705 ctx->stop_meta);
354 fflush(stdout); 15706 fflush(stdout);
@@ -359,9 +15711,9 @@ int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
359 unsigned int dpynum) 15711 unsigned int dpynum)
360{ 15712{
361 static const char spinner[] = "\\|/-"; 15713 static const char spinner[] = "\\|/-";
362 int i; 15714 int i;
363 unsigned int tick; 15715 unsigned int tick;
364 struct timeval tv; 15716 struct timeval tv;
365 int dpywidth; 15717 int dpywidth;
366 int fixed_percent; 15718 int fixed_percent;
367 15719
@@ -371,7 +15723,7 @@ int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
371 /* 15723 /*
372 * Calculate the new progress position. If the 15724 * Calculate the new progress position. If the
373 * percentage hasn't changed, then we skip out right 15725 * percentage hasn't changed, then we skip out right
374 * away. 15726 * away.
375 */ 15727 */
376 fixed_percent = (int) ((10 * percent) + 0.5); 15728 fixed_percent = (int) ((10 * percent) + 0.5);
377 if (ctx->progress_last_percent == fixed_percent) 15729 if (ctx->progress_last_percent == fixed_percent)
@@ -416,7 +15768,7 @@ int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent,
416 else 15768 else
417 fputs(" \r", stdout); 15769 fputs(" \r", stdout);
418 fputs(ctx->stop_meta, stdout); 15770 fputs(ctx->stop_meta, stdout);
419 15771
420 if (fixed_percent == 1000) 15772 if (fixed_percent == 1000)
421 e2fsck_clear_progbar(ctx); 15773 e2fsck_clear_progbar(ctx);
422 fflush(stdout); 15774 fflush(stdout);
@@ -432,7 +15784,7 @@ static int e2fsck_update_progress(e2fsck_t ctx, int pass,
432 15784
433 if (pass == 0) 15785 if (pass == 0)
434 return 0; 15786 return 0;
435 15787
436 if (ctx->progress_fd) { 15788 if (ctx->progress_fd) {
437 sprintf(buf, "%d %lu %lu\n", pass, cur, max); 15789 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
438 write(ctx->progress_fd, buf, strlen(buf)); 15790 write(ctx->progress_fd, buf, strlen(buf));
@@ -448,7 +15800,7 @@ static int e2fsck_update_progress(e2fsck_t ctx, int pass,
448 15800
449static void reserve_stdio_fds(void) 15801static void reserve_stdio_fds(void)
450{ 15802{
451 int fd; 15803 int fd;
452 15804
453 while (1) { 15805 while (1) {
454 fd = open("/dev/null", O_RDWR); 15806 fd = open("/dev/null", O_RDWR);
@@ -464,7 +15816,6 @@ static void reserve_stdio_fds(void)
464 close(fd); 15816 close(fd);
465} 15817}
466 15818
467#ifdef HAVE_SIGNAL_H
468static void signal_progress_on(int sig EXT2FS_ATTR((unused))) 15819static void signal_progress_on(int sig EXT2FS_ATTR((unused)))
469{ 15820{
470 e2fsck_t ctx = e2fsck_global_ctx; 15821 e2fsck_t ctx = e2fsck_global_ctx;
@@ -496,13 +15847,12 @@ static void signal_cancel(int sig EXT2FS_ATTR((unused)))
496 15847
497 ctx->flags |= E2F_FLAG_CANCEL; 15848 ctx->flags |= E2F_FLAG_CANCEL;
498} 15849}
499#endif
500 15850
501static void parse_extended_opts(e2fsck_t ctx, const char *opts) 15851static void parse_extended_opts(e2fsck_t ctx, const char *opts)
502{ 15852{
503 char *buf, *token, *next, *p, *arg; 15853 char *buf, *token, *next, *p, *arg;
504 int ea_ver; 15854 int ea_ver;
505 int extended_usage = 0; 15855 int extended_usage = 0;
506 15856
507 buf = string_copy(ctx, opts, 0); 15857 buf = string_copy(ctx, opts, 0);
508 for (token = buf; token && *token; token = next) { 15858 for (token = buf; token && *token; token = next) {
@@ -511,7 +15861,7 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
511 if (p) { 15861 if (p) {
512 *p = 0; 15862 *p = 0;
513 next = p+1; 15863 next = p+1;
514 } 15864 }
515 arg = strchr(token, '='); 15865 arg = strchr(token, '=');
516 if (arg) { 15866 if (arg) {
517 *arg = 0; 15867 *arg = 0;
@@ -542,22 +15892,20 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
542 "\tea_ver=<ea_version (1 or 2)\n\n")); 15892 "\tea_ver=<ea_version (1 or 2)\n\n"));
543 exit(1); 15893 exit(1);
544 } 15894 }
545} 15895}
546 15896
547 15897
548static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) 15898static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
549{ 15899{
550 int flush = 0; 15900 int flush = 0;
551 int c, fd; 15901 int c, fd;
552#ifdef MTRACE 15902#ifdef MTRACE
553 extern void *mallwatch; 15903 extern void *mallwatch;
554#endif 15904#endif
555 e2fsck_t ctx; 15905 e2fsck_t ctx;
556 errcode_t retval; 15906 errcode_t retval;
557#ifdef HAVE_SIGNAL_H 15907 struct sigaction sa;
558 struct sigaction sa; 15908 char *extended_opts = 0;
559#endif
560 char *extended_opts = 0;
561 15909
562 retval = e2fsck_allocate_context(&ctx); 15910 retval = e2fsck_allocate_context(&ctx);
563 if (retval) 15911 if (retval)
@@ -576,7 +15924,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
576 memset(bar, '=', sizeof(bar)-1); 15924 memset(bar, '=', sizeof(bar)-1);
577 memset(spaces, ' ', sizeof(spaces)-1); 15925 memset(spaces, ' ', sizeof(spaces)-1);
578 blkid_get_cache(&ctx->blkid, NULL); 15926 blkid_get_cache(&ctx->blkid, NULL);
579 15927
580 if (argc && *argv) 15928 if (argc && *argv)
581 ctx->program_name = *argv; 15929 ctx->program_name = *argv;
582 else 15930 else
@@ -610,7 +15958,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
610 case 'a': 15958 case 'a':
611 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) { 15959 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) {
612 conflict_opt: 15960 conflict_opt:
613 fatal_error(ctx, 15961 fatal_error(ctx,
614 _("Only one the options -p/-a, -n or -y may be specified.")); 15962 _("Only one the options -p/-a, -n or -y may be specified."));
615 } 15963 }
616 ctx->options |= E2F_OPT_PREEN; 15964 ctx->options |= E2F_OPT_PREEN;
@@ -716,17 +16064,17 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
716 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS)) 16064 !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
717 ctx->options |= E2F_OPT_READONLY; 16065 ctx->options |= E2F_OPT_READONLY;
718 ctx->io_options = strchr(argv[optind], '?'); 16066 ctx->io_options = strchr(argv[optind], '?');
719 if (ctx->io_options) 16067 if (ctx->io_options)
720 *ctx->io_options++ = 0; 16068 *ctx->io_options++ = 0;
721 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); 16069 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
722 if (!ctx->filesystem_name) { 16070 if (!ctx->filesystem_name) {
723 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), 16071 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
724 argv[optind]); 16072 argv[optind]);
725 fatal_error(ctx, 0); 16073 fatal_error(ctx, 0);
726 } 16074 }
727 if (extended_opts) 16075 if (extended_opts)
728 parse_extended_opts(ctx, extended_opts); 16076 parse_extended_opts(ctx, extended_opts);
729 16077
730 if (flush) { 16078 if (flush) {
731 fd = open(ctx->filesystem_name, O_RDONLY, 0); 16079 fd = open(ctx->filesystem_name, O_RDONLY, 0);
732 if (fd < 0) { 16080 if (fd < 0) {
@@ -757,7 +16105,6 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
757 "not be both used at the same time.\n")); 16105 "not be both used at the same time.\n"));
758 exit(FSCK_USAGE); 16106 exit(FSCK_USAGE);
759 } 16107 }
760#ifdef HAVE_SIGNAL_H
761 /* 16108 /*
762 * Set up signal action 16109 * Set up signal action
763 */ 16110 */
@@ -773,7 +16120,6 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
773 sigaction(SIGUSR1, &sa, 0); 16120 sigaction(SIGUSR1, &sa, 0);
774 sa.sa_handler = signal_progress_off; 16121 sa.sa_handler = signal_progress_off;
775 sigaction(SIGUSR2, &sa, 0); 16122 sigaction(SIGUSR2, &sa, 0);
776#endif
777 16123
778 /* Update our PATH to include /sbin if we need to run badblocks */ 16124 /* Update our PATH to include /sbin if we need to run badblocks */
779 if (cflag) { 16125 if (cflag) {
@@ -801,20 +16147,20 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
801 16147
802static const char *my_ver_string = E2FSPROGS_VERSION; 16148static const char *my_ver_string = E2FSPROGS_VERSION;
803static const char *my_ver_date = E2FSPROGS_DATE; 16149static const char *my_ver_date = E2FSPROGS_DATE;
804 16150
805int e2fsck_main (int argc, char *argv[]) 16151int e2fsck_main (int argc, char *argv[])
806{ 16152{
807 errcode_t retval = 0; 16153 errcode_t retval = 0;
808 int exit_value = FSCK_OK; 16154 int exit_value = FSCK_OK;
809 ext2_filsys fs = 0; 16155 ext2_filsys fs = 0;
810 io_manager io_ptr; 16156 io_manager io_ptr;
811 struct ext2_super_block *sb; 16157 struct ext2_super_block *sb;
812 const char *lib_ver_date; 16158 const char *lib_ver_date;
813 int my_ver, lib_ver; 16159 int my_ver, lib_ver;
814 e2fsck_t ctx; 16160 e2fsck_t ctx;
815 struct problem_context pctx; 16161 struct problem_context pctx;
816 int flags, run_result; 16162 int flags, run_result;
817 16163
818 clear_problem_context(&pctx); 16164 clear_problem_context(&pctx);
819#ifdef MTRACE 16165#ifdef MTRACE
820 mtrace(); 16166 mtrace();
@@ -835,7 +16181,7 @@ int e2fsck_main (int argc, char *argv[])
835 "out of date!\n")); 16181 "out of date!\n"));
836 show_version_only++; 16182 show_version_only++;
837 } 16183 }
838 16184
839 retval = PRS(argc, argv, &ctx); 16185 retval = PRS(argc, argv, &ctx);
840 if (retval) { 16186 if (retval) {
841 com_err("e2fsck", retval, 16187 com_err("e2fsck", retval,
@@ -843,7 +16189,7 @@ int e2fsck_main (int argc, char *argv[])
843 exit(FSCK_ERROR); 16189 exit(FSCK_ERROR);
844 } 16190 }
845 reserve_stdio_fds(); 16191 reserve_stdio_fds();
846 16192
847#ifdef RESOURCE_TRACK 16193#ifdef RESOURCE_TRACK
848 init_resource_track(&ctx->global_rtrack); 16194 init_resource_track(&ctx->global_rtrack);
849#endif 16195#endif
@@ -857,9 +16203,9 @@ int e2fsck_main (int argc, char *argv[])
857 error_message(EXT2_ET_BASE), lib_ver_date); 16203 error_message(EXT2_ET_BASE), lib_ver_date);
858 exit(FSCK_OK); 16204 exit(FSCK_OK);
859 } 16205 }
860 16206
861 check_mount(ctx); 16207 check_mount(ctx);
862 16208
863 if (!(ctx->options & E2F_OPT_PREEN) && 16209 if (!(ctx->options & E2F_OPT_PREEN) &&
864 !(ctx->options & E2F_OPT_NO) && 16210 !(ctx->options & E2F_OPT_NO) &&
865 !(ctx->options & E2F_OPT_YES)) { 16211 !(ctx->options & E2F_OPT_YES)) {
@@ -880,22 +16226,22 @@ restart:
880 flags |= EXT2_FLAG_RW; 16226 flags |= EXT2_FLAG_RW;
881 16227
882 if (ctx->superblock && ctx->blocksize) { 16228 if (ctx->superblock && ctx->blocksize) {
883 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, 16229 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
884 flags, ctx->superblock, ctx->blocksize, 16230 flags, ctx->superblock, ctx->blocksize,
885 io_ptr, &fs); 16231 io_ptr, &fs);
886 } else if (ctx->superblock) { 16232 } else if (ctx->superblock) {
887 int blocksize; 16233 int blocksize;
888 for (blocksize = EXT2_MIN_BLOCK_SIZE; 16234 for (blocksize = EXT2_MIN_BLOCK_SIZE;
889 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { 16235 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
890 retval = ext2fs_open2(ctx->filesystem_name, 16236 retval = ext2fs_open2(ctx->filesystem_name,
891 ctx->io_options, flags, 16237 ctx->io_options, flags,
892 ctx->superblock, blocksize, 16238 ctx->superblock, blocksize,
893 io_ptr, &fs); 16239 io_ptr, &fs);
894 if (!retval) 16240 if (!retval)
895 break; 16241 break;
896 } 16242 }
897 } else 16243 } else
898 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, 16244 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
899 flags, 0, 0, io_ptr, &fs); 16245 flags, 0, 0, io_ptr, &fs);
900 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && 16246 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
901 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) && 16247 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
@@ -1161,13 +16507,13 @@ restart:
1161 } 16507 }
1162 16508
1163 e2fsck_write_bitmaps(ctx); 16509 e2fsck_write_bitmaps(ctx);
1164 16510
1165 ext2fs_close(fs); 16511 ext2fs_close(fs);
1166 ctx->fs = NULL; 16512 ctx->fs = NULL;
1167 free(ctx->filesystem_name); 16513 free(ctx->filesystem_name);
1168 free(ctx->journal_name); 16514 free(ctx->journal_name);
1169 e2fsck_free_context(ctx); 16515 e2fsck_free_context(ctx);
1170 16516
1171#ifdef RESOURCE_TRACK 16517#ifdef RESOURCE_TRACK
1172 if (ctx->options & E2F_OPT_TIME) 16518 if (ctx->options & E2F_OPT_TIME)
1173 print_resource_track(NULL, &ctx->global_rtrack); 16519 print_resource_track(NULL, &ctx->global_rtrack);
diff --git a/e2fsprogs/e2fsck/badblocks.c b/e2fsprogs/e2fsck/badblocks.c
deleted file mode 100644
index 1ab76a091..000000000
--- a/e2fsprogs/e2fsck/badblocks.c
+++ /dev/null
@@ -1,135 +0,0 @@
1/*
2 * badblocks.c --- replace/append bad blocks to the bad block inode
3 *
4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
6 */
7
8#include <time.h>
9#ifdef HAVE_ERRNO_H
10#include <errno.h>
11#endif
12
13#include "e2fsck.h"
14
15static int check_bb_inode_blocks(ext2_filsys fs, blk_t *block_nr, int blockcnt,
16 void *priv_data);
17
18
19static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
20{
21 printf(_("Bad block %u out of range; ignored.\n"), blk);
22 return;
23}
24
25void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
26 int replace_bad_blocks)
27{
28 ext2_filsys fs = ctx->fs;
29 errcode_t retval;
30 badblocks_list bb_list = 0;
31 FILE *f;
32 char buf[1024];
33
34 e2fsck_read_bitmaps(ctx);
35
36 /*
37 * Make sure the bad block inode is sane. If there are any
38 * illegal blocks, clear them.
39 */
40 retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
41 check_bb_inode_blocks, 0);
42 if (retval) {
43 com_err("ext2fs_block_iterate", retval,
44 _("while sanity checking the bad blocks inode"));
45 goto fatal;
46 }
47
48 /*
49 * If we're appending to the bad blocks inode, read in the
50 * current bad blocks.
51 */
52 if (!replace_bad_blocks) {
53 retval = ext2fs_read_bb_inode(fs, &bb_list);
54 if (retval) {
55 com_err("ext2fs_read_bb_inode", retval,
56 _("while reading the bad blocks inode"));
57 goto fatal;
58 }
59 }
60
61 /*
62 * Now read in the bad blocks from the file; if
63 * bad_blocks_file is null, then try to run the badblocks
64 * command.
65 */
66 if (bad_blocks_file) {
67 f = fopen(bad_blocks_file, "r");
68 if (!f) {
69 com_err("read_bad_blocks_file", errno,
70 _("while trying to open %s"), bad_blocks_file);
71 goto fatal;
72 }
73 } else {
74 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize,
75 (ctx->options & E2F_OPT_PREEN) ? "" : "-s ",
76 (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "",
77 fs->device_name, fs->super->s_blocks_count);
78 f = popen(buf, "r");
79 if (!f) {
80 com_err("read_bad_blocks_file", errno,
81 _("while trying popen '%s'"), buf);
82 goto fatal;
83 }
84 }
85 retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
86 if (bad_blocks_file)
87 fclose(f);
88 else
89 pclose(f);
90 if (retval) {
91 com_err("ext2fs_read_bb_FILE", retval,
92 _("while reading in list of bad blocks from file"));
93 goto fatal;
94 }
95
96 /*
97 * Finally, update the bad blocks from the bad_block_map
98 */
99 retval = ext2fs_update_bb_inode(fs, bb_list);
100 if (retval) {
101 com_err("ext2fs_update_bb_inode", retval,
102 _("while updating bad block inode"));
103 goto fatal;
104 }
105
106 ext2fs_badblocks_list_free(bb_list);
107 return;
108
109fatal:
110 ctx->flags |= E2F_FLAG_ABORT;
111 return;
112
113}
114
115static int check_bb_inode_blocks(ext2_filsys fs,
116 blk_t *block_nr,
117 int blockcnt EXT2FS_ATTR((unused)),
118 void *priv_data EXT2FS_ATTR((unused)))
119{
120 if (!*block_nr)
121 return 0;
122
123 /*
124 * If the block number is outrageous, clear it and ignore it.
125 */
126 if (*block_nr >= fs->super->s_blocks_count ||
127 *block_nr < fs->super->s_first_data_block) {
128 printf(_("Warning illegal block %u found in bad block inode. Cleared.\n"), *block_nr);
129 *block_nr = 0;
130 return BLOCK_CHANGED;
131 }
132
133 return 0;
134}
135
diff --git a/e2fsprogs/e2fsck/dict.c b/e2fsprogs/e2fsck/dict.c
deleted file mode 100644
index b0809a76d..000000000
--- a/e2fsprogs/e2fsck/dict.c
+++ /dev/null
@@ -1,1529 +0,0 @@
1/*
2 * Dictionary Abstract Data Type
3 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
4 *
5 * Free Software License:
6 *
7 * All rights are reserved by the author, with the following exceptions:
8 * Permission is granted to freely reproduce and distribute this software,
9 * possibly in exchange for a fee, provided that this copyright notice appears
10 * intact. Permission is also granted to adapt this software to produce
11 * derivative works, as long as the modified versions carry this copyright
12 * notice and additional notices stating that the work has been modified.
13 * This source code may be translated into executable form and incorporated
14 * into proprietary software; there is no requirement for such software to
15 * contain a copyright notice related to this source.
16 *
17 * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $
18 * $Name: kazlib_1_20 $
19 */
20
21#ifdef __GNUC__
22#define EXT2FS_ATTR(x) __attribute__(x)
23#else
24#define EXT2FS_ATTR(x)
25#endif
26
27#include <stdlib.h>
28#include <stddef.h>
29#include <assert.h>
30#define DICT_IMPLEMENTATION
31#include "dict.h"
32
33#ifndef NDEBUG
34# define NDEBUG
35#endif
36
37/*
38 * These macros provide short convenient names for structure members,
39 * which are embellished with dict_ prefixes so that they are
40 * properly confined to the documented namespace. It's legal for a
41 * program which uses dict to define, for instance, a macro called ``parent''.
42 * Such a macro would interfere with the dnode_t struct definition.
43 * In general, highly portable and reusable C modules which expose their
44 * structures need to confine structure member names to well-defined spaces.
45 * The resulting identifiers aren't necessarily convenient to use, nor
46 * readable, in the implementation, however!
47 */
48
49#define left dict_left
50#define right dict_right
51#define parent dict_parent
52#define color dict_color
53#define key dict_key
54#define data dict_data
55
56#define nilnode dict_nilnode
57#define nodecount dict_nodecount
58#define maxcount dict_maxcount
59#define compare dict_compare
60#define allocnode dict_allocnode
61#define freenode dict_freenode
62#define context dict_context
63#define dupes dict_dupes
64
65#define dictptr dict_dictptr
66
67#define dict_root(D) ((D)->nilnode.left)
68#define dict_nil(D) (&(D)->nilnode)
69#define DICT_DEPTH_MAX 64
70
71static dnode_t *dnode_alloc(void *context);
72static void dnode_free(dnode_t *node, void *context);
73
74/*
75 * Perform a ``left rotation'' adjustment on the tree. The given node P and
76 * its right child C are rearranged so that the P instead becomes the left
77 * child of C. The left subtree of C is inherited as the new right subtree
78 * for P. The ordering of the keys within the tree is thus preserved.
79 */
80
81static void rotate_left(dnode_t *upper)
82{
83 dnode_t *lower, *lowleft, *upparent;
84
85 lower = upper->right;
86 upper->right = lowleft = lower->left;
87 lowleft->parent = upper;
88
89 lower->parent = upparent = upper->parent;
90
91 /* don't need to check for root node here because root->parent is
92 the sentinel nil node, and root->parent->left points back to root */
93
94 if (upper == upparent->left) {
95 upparent->left = lower;
96 } else {
97 assert (upper == upparent->right);
98 upparent->right = lower;
99 }
100
101 lower->left = upper;
102 upper->parent = lower;
103}
104
105/*
106 * This operation is the ``mirror'' image of rotate_left. It is
107 * the same procedure, but with left and right interchanged.
108 */
109
110static void rotate_right(dnode_t *upper)
111{
112 dnode_t *lower, *lowright, *upparent;
113
114 lower = upper->left;
115 upper->left = lowright = lower->right;
116 lowright->parent = upper;
117
118 lower->parent = upparent = upper->parent;
119
120 if (upper == upparent->right) {
121 upparent->right = lower;
122 } else {
123 assert (upper == upparent->left);
124 upparent->left = lower;
125 }
126
127 lower->right = upper;
128 upper->parent = lower;
129}
130
131/*
132 * Do a postorder traversal of the tree rooted at the specified
133 * node and free everything under it. Used by dict_free().
134 */
135
136static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
137{
138 if (node == nil)
139 return;
140 free_nodes(dict, node->left, nil);
141 free_nodes(dict, node->right, nil);
142 dict->freenode(node, dict->context);
143}
144
145/*
146 * This procedure performs a verification that the given subtree is a binary
147 * search tree. It performs an inorder traversal of the tree using the
148 * dict_next() successor function, verifying that the key of each node is
149 * strictly lower than that of its successor, if duplicates are not allowed,
150 * or lower or equal if duplicates are allowed. This function is used for
151 * debugging purposes.
152 */
153#ifndef NDEBUG
154static int verify_bintree(dict_t *dict)
155{
156 dnode_t *first, *next;
157
158 first = dict_first(dict);
159
160 if (dict->dupes) {
161 while (first && (next = dict_next(dict, first))) {
162 if (dict->compare(first->key, next->key) > 0)
163 return 0;
164 first = next;
165 }
166 } else {
167 while (first && (next = dict_next(dict, first))) {
168 if (dict->compare(first->key, next->key) >= 0)
169 return 0;
170 first = next;
171 }
172 }
173 return 1;
174}
175
176/*
177 * This function recursively verifies that the given binary subtree satisfies
178 * three of the red black properties. It checks that every red node has only
179 * black children. It makes sure that each node is either red or black. And it
180 * checks that every path has the same count of black nodes from root to leaf.
181 * It returns the blackheight of the given subtree; this allows blackheights to
182 * be computed recursively and compared for left and right siblings for
183 * mismatches. It does not check for every nil node being black, because there
184 * is only one sentinel nil node. The return value of this function is the
185 * black height of the subtree rooted at the node ``root'', or zero if the
186 * subtree is not red-black.
187 */
188
189static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
190{
191 unsigned height_left, height_right;
192
193 if (root != nil) {
194 height_left = verify_redblack(nil, root->left);
195 height_right = verify_redblack(nil, root->right);
196 if (height_left == 0 || height_right == 0)
197 return 0;
198 if (height_left != height_right)
199 return 0;
200 if (root->color == dnode_red) {
201 if (root->left->color != dnode_black)
202 return 0;
203 if (root->right->color != dnode_black)
204 return 0;
205 return height_left;
206 }
207 if (root->color != dnode_black)
208 return 0;
209 return height_left + 1;
210 }
211 return 1;
212}
213
214/*
215 * Compute the actual count of nodes by traversing the tree and
216 * return it. This could be compared against the stored count to
217 * detect a mismatch.
218 */
219
220static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
221{
222 if (root == nil)
223 return 0;
224 else
225 return 1 + verify_node_count(nil, root->left)
226 + verify_node_count(nil, root->right);
227}
228#endif
229
230/*
231 * Verify that the tree contains the given node. This is done by
232 * traversing all of the nodes and comparing their pointers to the
233 * given pointer. Returns 1 if the node is found, otherwise
234 * returns zero. It is intended for debugging purposes.
235 */
236
237static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
238{
239 if (root != nil) {
240 return root == node
241 || verify_dict_has_node(nil, root->left, node)
242 || verify_dict_has_node(nil, root->right, node);
243 }
244 return 0;
245}
246
247
248#ifdef E2FSCK_NOTUSED
249/*
250 * Dynamically allocate and initialize a dictionary object.
251 */
252
253dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
254{
255 dict_t *new = malloc(sizeof *new);
256
257 if (new) {
258 new->compare = comp;
259 new->allocnode = dnode_alloc;
260 new->freenode = dnode_free;
261 new->context = NULL;
262 new->nodecount = 0;
263 new->maxcount = maxcount;
264 new->nilnode.left = &new->nilnode;
265 new->nilnode.right = &new->nilnode;
266 new->nilnode.parent = &new->nilnode;
267 new->nilnode.color = dnode_black;
268 new->dupes = 0;
269 }
270 return new;
271}
272#endif /* E2FSCK_NOTUSED */
273
274/*
275 * Select a different set of node allocator routines.
276 */
277
278void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
279 dnode_free_t fr, void *context)
280{
281 assert (dict_count(dict) == 0);
282 assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
283
284 dict->allocnode = al ? al : dnode_alloc;
285 dict->freenode = fr ? fr : dnode_free;
286 dict->context = context;
287}
288
289#ifdef E2FSCK_NOTUSED
290/*
291 * Free a dynamically allocated dictionary object. Removing the nodes
292 * from the tree before deleting it is required.
293 */
294
295void dict_destroy(dict_t *dict)
296{
297 assert (dict_isempty(dict));
298 free(dict);
299}
300#endif
301
302/*
303 * Free all the nodes in the dictionary by using the dictionary's
304 * installed free routine. The dictionary is emptied.
305 */
306
307void dict_free_nodes(dict_t *dict)
308{
309 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
310 free_nodes(dict, root, nil);
311 dict->nodecount = 0;
312 dict->nilnode.left = &dict->nilnode;
313 dict->nilnode.right = &dict->nilnode;
314}
315
316#ifdef E2FSCK_NOTUSED
317/*
318 * Obsolescent function, equivalent to dict_free_nodes
319 */
320void dict_free(dict_t *dict)
321{
322#ifdef KAZLIB_OBSOLESCENT_DEBUG
323 assert ("call to obsolescent function dict_free()" && 0);
324#endif
325 dict_free_nodes(dict);
326}
327#endif
328
329/*
330 * Initialize a user-supplied dictionary object.
331 */
332
333dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
334{
335 dict->compare = comp;
336 dict->allocnode = dnode_alloc;
337 dict->freenode = dnode_free;
338 dict->context = NULL;
339 dict->nodecount = 0;
340 dict->maxcount = maxcount;
341 dict->nilnode.left = &dict->nilnode;
342 dict->nilnode.right = &dict->nilnode;
343 dict->nilnode.parent = &dict->nilnode;
344 dict->nilnode.color = dnode_black;
345 dict->dupes = 0;
346 return dict;
347}
348
349#ifdef E2FSCK_NOTUSED
350/*
351 * Initialize a dictionary in the likeness of another dictionary
352 */
353
354void dict_init_like(dict_t *dict, const dict_t *template)
355{
356 dict->compare = template->compare;
357 dict->allocnode = template->allocnode;
358 dict->freenode = template->freenode;
359 dict->context = template->context;
360 dict->nodecount = 0;
361 dict->maxcount = template->maxcount;
362 dict->nilnode.left = &dict->nilnode;
363 dict->nilnode.right = &dict->nilnode;
364 dict->nilnode.parent = &dict->nilnode;
365 dict->nilnode.color = dnode_black;
366 dict->dupes = template->dupes;
367
368 assert (dict_similar(dict, template));
369}
370
371/*
372 * Remove all nodes from the dictionary (without freeing them in any way).
373 */
374
375static void dict_clear(dict_t *dict)
376{
377 dict->nodecount = 0;
378 dict->nilnode.left = &dict->nilnode;
379 dict->nilnode.right = &dict->nilnode;
380 dict->nilnode.parent = &dict->nilnode;
381 assert (dict->nilnode.color == dnode_black);
382}
383
384
385/*
386 * Verify the integrity of the dictionary structure. This is provided for
387 * debugging purposes, and should be placed in assert statements. Just because
388 * this function succeeds doesn't mean that the tree is not corrupt. Certain
389 * corruptions in the tree may simply cause undefined behavior.
390 */
391
392int dict_verify(dict_t *dict)
393{
394#ifndef NDEBUG
395 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
396
397 /* check that the sentinel node and root node are black */
398 if (root->color != dnode_black)
399 return 0;
400 if (nil->color != dnode_black)
401 return 0;
402 if (nil->right != nil)
403 return 0;
404 /* nil->left is the root node; check that its parent pointer is nil */
405 if (nil->left->parent != nil)
406 return 0;
407 /* perform a weak test that the tree is a binary search tree */
408 if (!verify_bintree(dict))
409 return 0;
410 /* verify that the tree is a red-black tree */
411 if (!verify_redblack(nil, root))
412 return 0;
413 if (verify_node_count(nil, root) != dict_count(dict))
414 return 0;
415#endif
416 return 1;
417}
418
419/*
420 * Determine whether two dictionaries are similar: have the same comparison and
421 * allocator functions, and same status as to whether duplicates are allowed.
422 */
423
424int dict_similar(const dict_t *left, const dict_t *right)
425{
426 if (left->compare != right->compare)
427 return 0;
428
429 if (left->allocnode != right->allocnode)
430 return 0;
431
432 if (left->freenode != right->freenode)
433 return 0;
434
435 if (left->context != right->context)
436 return 0;
437
438 if (left->dupes != right->dupes)
439 return 0;
440
441 return 1;
442}
443#endif /* E2FSCK_NOTUSED */
444
445/*
446 * Locate a node in the dictionary having the given key.
447 * If the node is not found, a null a pointer is returned (rather than
448 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
449 * located node is returned.
450 */
451
452dnode_t *dict_lookup(dict_t *dict, const void *key)
453{
454 dnode_t *root = dict_root(dict);
455 dnode_t *nil = dict_nil(dict);
456 dnode_t *saved;
457 int result;
458
459 /* simple binary search adapted for trees that contain duplicate keys */
460
461 while (root != nil) {
462 result = dict->compare(key, root->key);
463 if (result < 0)
464 root = root->left;
465 else if (result > 0)
466 root = root->right;
467 else {
468 if (!dict->dupes) { /* no duplicates, return match */
469 return root;
470 } else { /* could be dupes, find leftmost one */
471 do {
472 saved = root;
473 root = root->left;
474 while (root != nil && dict->compare(key, root->key))
475 root = root->right;
476 } while (root != nil);
477 return saved;
478 }
479 }
480 }
481
482 return NULL;
483}
484
485#ifdef E2FSCK_NOTUSED
486/*
487 * Look for the node corresponding to the lowest key that is equal to or
488 * greater than the given key. If there is no such node, return null.
489 */
490
491dnode_t *dict_lower_bound(dict_t *dict, const void *key)
492{
493 dnode_t *root = dict_root(dict);
494 dnode_t *nil = dict_nil(dict);
495 dnode_t *tentative = 0;
496
497 while (root != nil) {
498 int result = dict->compare(key, root->key);
499
500 if (result > 0) {
501 root = root->right;
502 } else if (result < 0) {
503 tentative = root;
504 root = root->left;
505 } else {
506 if (!dict->dupes) {
507 return root;
508 } else {
509 tentative = root;
510 root = root->left;
511 }
512 }
513 }
514
515 return tentative;
516}
517
518/*
519 * Look for the node corresponding to the greatest key that is equal to or
520 * lower than the given key. If there is no such node, return null.
521 */
522
523dnode_t *dict_upper_bound(dict_t *dict, const void *key)
524{
525 dnode_t *root = dict_root(dict);
526 dnode_t *nil = dict_nil(dict);
527 dnode_t *tentative = 0;
528
529 while (root != nil) {
530 int result = dict->compare(key, root->key);
531
532 if (result < 0) {
533 root = root->left;
534 } else if (result > 0) {
535 tentative = root;
536 root = root->right;
537 } else {
538 if (!dict->dupes) {
539 return root;
540 } else {
541 tentative = root;
542 root = root->right;
543 }
544 }
545 }
546
547 return tentative;
548}
549#endif
550
551/*
552 * Insert a node into the dictionary. The node should have been
553 * initialized with a data field. All other fields are ignored.
554 * The behavior is undefined if the user attempts to insert into
555 * a dictionary that is already full (for which the dict_isfull()
556 * function returns true).
557 */
558
559void dict_insert(dict_t *dict, dnode_t *node, const void *key)
560{
561 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
562 dnode_t *parent = nil, *uncle, *grandpa;
563 int result = -1;
564
565 node->key = key;
566
567#ifndef NDEBUG
568 assert (!dict_isfull(dict));
569 assert (!dict_contains(dict, node));
570 assert (!dnode_is_in_a_dict(node));
571#endif
572
573 /* basic binary tree insert */
574
575 while (where != nil) {
576 parent = where;
577 result = dict->compare(key, where->key);
578 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
579 assert (dict->dupes || result != 0);
580 if (result < 0)
581 where = where->left;
582 else
583 where = where->right;
584 }
585
586 assert (where == nil);
587
588 if (result < 0)
589 parent->left = node;
590 else
591 parent->right = node;
592
593 node->parent = parent;
594 node->left = nil;
595 node->right = nil;
596
597 dict->nodecount++;
598
599 /* red black adjustments */
600
601 node->color = dnode_red;
602
603 while (parent->color == dnode_red) {
604 grandpa = parent->parent;
605 if (parent == grandpa->left) {
606 uncle = grandpa->right;
607 if (uncle->color == dnode_red) { /* red parent, red uncle */
608 parent->color = dnode_black;
609 uncle->color = dnode_black;
610 grandpa->color = dnode_red;
611 node = grandpa;
612 parent = grandpa->parent;
613 } else { /* red parent, black uncle */
614 if (node == parent->right) {
615 rotate_left(parent);
616 parent = node;
617 assert (grandpa == parent->parent);
618 /* rotation between parent and child preserves grandpa */
619 }
620 parent->color = dnode_black;
621 grandpa->color = dnode_red;
622 rotate_right(grandpa);
623 break;
624 }
625 } else { /* symmetric cases: parent == parent->parent->right */
626 uncle = grandpa->left;
627 if (uncle->color == dnode_red) {
628 parent->color = dnode_black;
629 uncle->color = dnode_black;
630 grandpa->color = dnode_red;
631 node = grandpa;
632 parent = grandpa->parent;
633 } else {
634 if (node == parent->left) {
635 rotate_right(parent);
636 parent = node;
637 assert (grandpa == parent->parent);
638 }
639 parent->color = dnode_black;
640 grandpa->color = dnode_red;
641 rotate_left(grandpa);
642 break;
643 }
644 }
645 }
646
647 dict_root(dict)->color = dnode_black;
648
649#ifdef E2FSCK_NOTUSED
650 assert (dict_verify(dict));
651#endif
652}
653
654#ifdef E2FSCK_NOTUSED
655/*
656 * Delete the given node from the dictionary. If the given node does not belong
657 * to the given dictionary, undefined behavior results. A pointer to the
658 * deleted node is returned.
659 */
660
661dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
662{
663 dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
664
665 /* basic deletion */
666
667 assert (!dict_isempty(dict));
668 assert (dict_contains(dict, delete));
669
670 /*
671 * If the node being deleted has two children, then we replace it with its
672 * successor (i.e. the leftmost node in the right subtree.) By doing this,
673 * we avoid the traditional algorithm under which the successor's key and
674 * value *only* move to the deleted node and the successor is spliced out
675 * from the tree. We cannot use this approach because the user may hold
676 * pointers to the successor, or nodes may be inextricably tied to some
677 * other structures by way of embedding, etc. So we must splice out the
678 * node we are given, not some other node, and must not move contents from
679 * one node to another behind the user's back.
680 */
681
682 if (delete->left != nil && delete->right != nil) {
683 dnode_t *next = dict_next(dict, delete);
684 dnode_t *nextparent = next->parent;
685 dnode_color_t nextcolor = next->color;
686
687 assert (next != nil);
688 assert (next->parent != nil);
689 assert (next->left == nil);
690
691 /*
692 * First, splice out the successor from the tree completely, by
693 * moving up its right child into its place.
694 */
695
696 child = next->right;
697 child->parent = nextparent;
698
699 if (nextparent->left == next) {
700 nextparent->left = child;
701 } else {
702 assert (nextparent->right == next);
703 nextparent->right = child;
704 }
705
706 /*
707 * Now that the successor has been extricated from the tree, install it
708 * in place of the node that we want deleted.
709 */
710
711 next->parent = delparent;
712 next->left = delete->left;
713 next->right = delete->right;
714 next->left->parent = next;
715 next->right->parent = next;
716 next->color = delete->color;
717 delete->color = nextcolor;
718
719 if (delparent->left == delete) {
720 delparent->left = next;
721 } else {
722 assert (delparent->right == delete);
723 delparent->right = next;
724 }
725
726 } else {
727 assert (delete != nil);
728 assert (delete->left == nil || delete->right == nil);
729
730 child = (delete->left != nil) ? delete->left : delete->right;
731
732 child->parent = delparent = delete->parent;
733
734 if (delete == delparent->left) {
735 delparent->left = child;
736 } else {
737 assert (delete == delparent->right);
738 delparent->right = child;
739 }
740 }
741
742 delete->parent = NULL;
743 delete->right = NULL;
744 delete->left = NULL;
745
746 dict->nodecount--;
747
748 assert (verify_bintree(dict));
749
750 /* red-black adjustments */
751
752 if (delete->color == dnode_black) {
753 dnode_t *parent, *sister;
754
755 dict_root(dict)->color = dnode_red;
756
757 while (child->color == dnode_black) {
758 parent = child->parent;
759 if (child == parent->left) {
760 sister = parent->right;
761 assert (sister != nil);
762 if (sister->color == dnode_red) {
763 sister->color = dnode_black;
764 parent->color = dnode_red;
765 rotate_left(parent);
766 sister = parent->right;
767 assert (sister != nil);
768 }
769 if (sister->left->color == dnode_black
770 && sister->right->color == dnode_black) {
771 sister->color = dnode_red;
772 child = parent;
773 } else {
774 if (sister->right->color == dnode_black) {
775 assert (sister->left->color == dnode_red);
776 sister->left->color = dnode_black;
777 sister->color = dnode_red;
778 rotate_right(sister);
779 sister = parent->right;
780 assert (sister != nil);
781 }
782 sister->color = parent->color;
783 sister->right->color = dnode_black;
784 parent->color = dnode_black;
785 rotate_left(parent);
786 break;
787 }
788 } else { /* symmetric case: child == child->parent->right */
789 assert (child == parent->right);
790 sister = parent->left;
791 assert (sister != nil);
792 if (sister->color == dnode_red) {
793 sister->color = dnode_black;
794 parent->color = dnode_red;
795 rotate_right(parent);
796 sister = parent->left;
797 assert (sister != nil);
798 }
799 if (sister->right->color == dnode_black
800 && sister->left->color == dnode_black) {
801 sister->color = dnode_red;
802 child = parent;
803 } else {
804 if (sister->left->color == dnode_black) {
805 assert (sister->right->color == dnode_red);
806 sister->right->color = dnode_black;
807 sister->color = dnode_red;
808 rotate_left(sister);
809 sister = parent->left;
810 assert (sister != nil);
811 }
812 sister->color = parent->color;
813 sister->left->color = dnode_black;
814 parent->color = dnode_black;
815 rotate_right(parent);
816 break;
817 }
818 }
819 }
820
821 child->color = dnode_black;
822 dict_root(dict)->color = dnode_black;
823 }
824
825#ifdef E2FSCK_NOTUSED
826 assert (dict_verify(dict));
827#endif
828
829 return delete;
830}
831#endif /* E2FSCK_NOTUSED */
832
833/*
834 * Allocate a node using the dictionary's allocator routine, give it
835 * the data item.
836 */
837
838int dict_alloc_insert(dict_t *dict, const void *key, void *data)
839{
840 dnode_t *node = dict->allocnode(dict->context);
841
842 if (node) {
843 dnode_init(node, data);
844 dict_insert(dict, node, key);
845 return 1;
846 }
847 return 0;
848}
849
850#ifdef E2FSCK_NOTUSED
851void dict_delete_free(dict_t *dict, dnode_t *node)
852{
853 dict_delete(dict, node);
854 dict->freenode(node, dict->context);
855}
856#endif
857
858/*
859 * Return the node with the lowest (leftmost) key. If the dictionary is empty
860 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
861 */
862
863dnode_t *dict_first(dict_t *dict)
864{
865 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
866
867 if (root != nil)
868 while ((left = root->left) != nil)
869 root = left;
870
871 return (root == nil) ? NULL : root;
872}
873
874/*
875 * Return the node with the highest (rightmost) key. If the dictionary is empty
876 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
877 */
878
879dnode_t *dict_last(dict_t *dict)
880{
881 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
882
883 if (root != nil)
884 while ((right = root->right) != nil)
885 root = right;
886
887 return (root == nil) ? NULL : root;
888}
889
890/*
891 * Return the given node's successor node---the node which has the
892 * next key in the the left to right ordering. If the node has
893 * no successor, a null pointer is returned rather than a pointer to
894 * the nil node.
895 */
896
897dnode_t *dict_next(dict_t *dict, dnode_t *curr)
898{
899 dnode_t *nil = dict_nil(dict), *parent, *left;
900
901 if (curr->right != nil) {
902 curr = curr->right;
903 while ((left = curr->left) != nil)
904 curr = left;
905 return curr;
906 }
907
908 parent = curr->parent;
909
910 while (parent != nil && curr == parent->right) {
911 curr = parent;
912 parent = curr->parent;
913 }
914
915 return (parent == nil) ? NULL : parent;
916}
917
918/*
919 * Return the given node's predecessor, in the key order.
920 * The nil sentinel node is returned if there is no predecessor.
921 */
922
923dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
924{
925 dnode_t *nil = dict_nil(dict), *parent, *right;
926
927 if (curr->left != nil) {
928 curr = curr->left;
929 while ((right = curr->right) != nil)
930 curr = right;
931 return curr;
932 }
933
934 parent = curr->parent;
935
936 while (parent != nil && curr == parent->left) {
937 curr = parent;
938 parent = curr->parent;
939 }
940
941 return (parent == nil) ? NULL : parent;
942}
943
944void dict_allow_dupes(dict_t *dict)
945{
946 dict->dupes = 1;
947}
948
949#undef dict_count
950#undef dict_isempty
951#undef dict_isfull
952#undef dnode_get
953#undef dnode_put
954#undef dnode_getkey
955
956dictcount_t dict_count(dict_t *dict)
957{
958 return dict->nodecount;
959}
960
961int dict_isempty(dict_t *dict)
962{
963 return dict->nodecount == 0;
964}
965
966int dict_isfull(dict_t *dict)
967{
968 return dict->nodecount == dict->maxcount;
969}
970
971int dict_contains(dict_t *dict, dnode_t *node)
972{
973 return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
974}
975
976static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused)))
977{
978 return malloc(sizeof *dnode_alloc(NULL));
979}
980
981static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused)))
982{
983 free(node);
984}
985
986dnode_t *dnode_create(void *data)
987{
988 dnode_t *new = malloc(sizeof *new);
989 if (new) {
990 new->data = data;
991 new->parent = NULL;
992 new->left = NULL;
993 new->right = NULL;
994 }
995 return new;
996}
997
998dnode_t *dnode_init(dnode_t *dnode, void *data)
999{
1000 dnode->data = data;
1001 dnode->parent = NULL;
1002 dnode->left = NULL;
1003 dnode->right = NULL;
1004 return dnode;
1005}
1006
1007void dnode_destroy(dnode_t *dnode)
1008{
1009#ifndef NDEBUG
1010 assert (!dnode_is_in_a_dict(dnode));
1011#endif
1012 free(dnode);
1013}
1014
1015void *dnode_get(dnode_t *dnode)
1016{
1017 return dnode->data;
1018}
1019
1020const void *dnode_getkey(dnode_t *dnode)
1021{
1022 return dnode->key;
1023}
1024
1025#ifdef E2FSCK_NOTUSED
1026void dnode_put(dnode_t *dnode, void *data)
1027{
1028 dnode->data = data;
1029}
1030
1031int dnode_is_in_a_dict(dnode_t *dnode)
1032{
1033 return (dnode->parent && dnode->left && dnode->right);
1034}
1035
1036void dict_process(dict_t *dict, void *context, dnode_process_t function)
1037{
1038 dnode_t *node = dict_first(dict), *next;
1039
1040 while (node != NULL) {
1041 /* check for callback function deleting */
1042 /* the next node from under us */
1043 assert (dict_contains(dict, node));
1044 next = dict_next(dict, node);
1045 function(dict, node, context);
1046 node = next;
1047 }
1048}
1049
1050static void load_begin_internal(dict_load_t *load, dict_t *dict)
1051{
1052 load->dictptr = dict;
1053 load->nilnode.left = &load->nilnode;
1054 load->nilnode.right = &load->nilnode;
1055}
1056
1057void dict_load_begin(dict_load_t *load, dict_t *dict)
1058{
1059 assert (dict_isempty(dict));
1060 load_begin_internal(load, dict);
1061}
1062
1063void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
1064{
1065 dict_t *dict = load->dictptr;
1066 dnode_t *nil = &load->nilnode;
1067
1068#ifndef NDEBUG
1069 assert (!dnode_is_in_a_dict(newnode));
1070 assert (dict->nodecount < dict->maxcount);
1071
1072 if (dict->nodecount > 0) {
1073 if (dict->dupes)
1074 assert (dict->compare(nil->left->key, key) <= 0);
1075 else
1076 assert (dict->compare(nil->left->key, key) < 0);
1077 }
1078#endif
1079
1080 newnode->key = key;
1081 nil->right->left = newnode;
1082 nil->right = newnode;
1083 newnode->left = nil;
1084 dict->nodecount++;
1085}
1086
1087void dict_load_end(dict_load_t *load)
1088{
1089 dict_t *dict = load->dictptr;
1090 dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1091 dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
1092 dnode_t *complete = 0;
1093 dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1094 dictcount_t botrowcount;
1095 unsigned baselevel = 0, level = 0, i;
1096
1097 assert (dnode_red == 0 && dnode_black == 1);
1098
1099 while (fullcount >= nodecount && fullcount)
1100 fullcount >>= 1;
1101
1102 botrowcount = nodecount - fullcount;
1103
1104 for (curr = loadnil->left; curr != loadnil; curr = next) {
1105 next = curr->left;
1106
1107 if (complete == NULL && botrowcount-- == 0) {
1108 assert (baselevel == 0);
1109 assert (level == 0);
1110 baselevel = level = 1;
1111 complete = tree[0];
1112
1113 if (complete != 0) {
1114 tree[0] = 0;
1115 complete->right = dictnil;
1116 while (tree[level] != 0) {
1117 tree[level]->right = complete;
1118 complete->parent = tree[level];
1119 complete = tree[level];
1120 tree[level++] = 0;
1121 }
1122 }
1123 }
1124
1125 if (complete == NULL) {
1126 curr->left = dictnil;
1127 curr->right = dictnil;
1128 curr->color = level % 2;
1129 complete = curr;
1130
1131 assert (level == baselevel);
1132 while (tree[level] != 0) {
1133 tree[level]->right = complete;
1134 complete->parent = tree[level];
1135 complete = tree[level];
1136 tree[level++] = 0;
1137 }
1138 } else {
1139 curr->left = complete;
1140 curr->color = (level + 1) % 2;
1141 complete->parent = curr;
1142 tree[level] = curr;
1143 complete = 0;
1144 level = baselevel;
1145 }
1146 }
1147
1148 if (complete == NULL)
1149 complete = dictnil;
1150
1151 for (i = 0; i < DICT_DEPTH_MAX; i++) {
1152 if (tree[i] != 0) {
1153 tree[i]->right = complete;
1154 complete->parent = tree[i];
1155 complete = tree[i];
1156 }
1157 }
1158
1159 dictnil->color = dnode_black;
1160 dictnil->right = dictnil;
1161 complete->parent = dictnil;
1162 complete->color = dnode_black;
1163 dict_root(dict) = complete;
1164
1165#ifdef E2FSCK_NOTUSED
1166 assert (dict_verify(dict));
1167#endif
1168}
1169
1170void dict_merge(dict_t *dest, dict_t *source)
1171{
1172 dict_load_t load;
1173 dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
1174
1175 assert (dict_similar(dest, source));
1176
1177 if (source == dest)
1178 return;
1179
1180 dest->nodecount = 0;
1181 load_begin_internal(&load, dest);
1182
1183 for (;;) {
1184 if (leftnode != NULL && rightnode != NULL) {
1185 if (dest->compare(leftnode->key, rightnode->key) < 0)
1186 goto copyleft;
1187 else
1188 goto copyright;
1189 } else if (leftnode != NULL) {
1190 goto copyleft;
1191 } else if (rightnode != NULL) {
1192 goto copyright;
1193 } else {
1194 assert (leftnode == NULL && rightnode == NULL);
1195 break;
1196 }
1197
1198 copyleft:
1199 {
1200 dnode_t *next = dict_next(dest, leftnode);
1201#ifndef NDEBUG
1202 leftnode->left = NULL; /* suppress assertion in dict_load_next */
1203#endif
1204 dict_load_next(&load, leftnode, leftnode->key);
1205 leftnode = next;
1206 continue;
1207 }
1208
1209 copyright:
1210 {
1211 dnode_t *next = dict_next(source, rightnode);
1212#ifndef NDEBUG
1213 rightnode->left = NULL;
1214#endif
1215 dict_load_next(&load, rightnode, rightnode->key);
1216 rightnode = next;
1217 continue;
1218 }
1219 }
1220
1221 dict_clear(source);
1222 dict_load_end(&load);
1223}
1224#endif /* E2FSCK_NOTUSED */
1225
1226#ifdef KAZLIB_TEST_MAIN
1227
1228#include <stdio.h>
1229#include <string.h>
1230#include <ctype.h>
1231#include <stdarg.h>
1232
1233typedef char input_t[256];
1234
1235static int tokenize(char *string, ...)
1236{
1237 char **tokptr;
1238 va_list arglist;
1239 int tokcount = 0;
1240
1241 va_start(arglist, string);
1242 tokptr = va_arg(arglist, char **);
1243 while (tokptr) {
1244 while (*string && isspace((unsigned char) *string))
1245 string++;
1246 if (!*string)
1247 break;
1248 *tokptr = string;
1249 while (*string && !isspace((unsigned char) *string))
1250 string++;
1251 tokptr = va_arg(arglist, char **);
1252 tokcount++;
1253 if (!*string)
1254 break;
1255 *string++ = 0;
1256 }
1257 va_end(arglist);
1258
1259 return tokcount;
1260}
1261
1262static int comparef(const void *key1, const void *key2)
1263{
1264 return strcmp(key1, key2);
1265}
1266
1267static char *dupstring(char *str)
1268{
1269 int sz = strlen(str) + 1;
1270 char *new = malloc(sz);
1271 if (new)
1272 memcpy(new, str, sz);
1273 return new;
1274}
1275
1276static dnode_t *new_node(void *c)
1277{
1278 static dnode_t few[5];
1279 static int count;
1280
1281 if (count < 5)
1282 return few + count++;
1283
1284 return NULL;
1285}
1286
1287static void del_node(dnode_t *n, void *c)
1288{
1289}
1290
1291static int prompt = 0;
1292
1293static void construct(dict_t *d)
1294{
1295 input_t in;
1296 int done = 0;
1297 dict_load_t dl;
1298 dnode_t *dn;
1299 char *tok1, *tok2, *val;
1300 const char *key;
1301 char *help =
1302 "p turn prompt on\n"
1303 "q finish construction\n"
1304 "a <key> <val> add new entry\n";
1305
1306 if (!dict_isempty(d))
1307 puts("warning: dictionary not empty!");
1308
1309 dict_load_begin(&dl, d);
1310
1311 while (!done) {
1312 if (prompt)
1313 putchar('>');
1314 fflush(stdout);
1315
1316 if (!fgets(in, sizeof(input_t), stdin))
1317 break;
1318
1319 switch (in[0]) {
1320 case '?':
1321 puts(help);
1322 break;
1323 case 'p':
1324 prompt = 1;
1325 break;
1326 case 'q':
1327 done = 1;
1328 break;
1329 case 'a':
1330 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1331 puts("what?");
1332 break;
1333 }
1334 key = dupstring(tok1);
1335 val = dupstring(tok2);
1336 dn = dnode_create(val);
1337
1338 if (!key || !val || !dn) {
1339 puts("out of memory");
1340 free((void *) key);
1341 free(val);
1342 if (dn)
1343 dnode_destroy(dn);
1344 }
1345
1346 dict_load_next(&dl, dn, key);
1347 break;
1348 default:
1349 putchar('?');
1350 putchar('\n');
1351 break;
1352 }
1353 }
1354
1355 dict_load_end(&dl);
1356}
1357
1358int main(void)
1359{
1360 input_t in;
1361 dict_t darray[10];
1362 dict_t *d = &darray[0];
1363 dnode_t *dn;
1364 int i;
1365 char *tok1, *tok2, *val;
1366 const char *key;
1367
1368 char *help =
1369 "a <key> <val> add value to dictionary\n"
1370 "d <key> delete value from dictionary\n"
1371 "l <key> lookup value in dictionary\n"
1372 "( <key> lookup lower bound\n"
1373 ") <key> lookup upper bound\n"
1374 "# <num> switch to alternate dictionary (0-9)\n"
1375 "j <num> <num> merge two dictionaries\n"
1376 "f free the whole dictionary\n"
1377 "k allow duplicate keys\n"
1378 "c show number of entries\n"
1379 "t dump whole dictionary in sort order\n"
1380 "m make dictionary out of sorted items\n"
1381 "p turn prompt on\n"
1382 "s switch to non-functioning allocator\n"
1383 "q quit";
1384
1385 for (i = 0; i < sizeof darray / sizeof *darray; i++)
1386 dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
1387
1388 for (;;) {
1389 if (prompt)
1390 putchar('>');
1391 fflush(stdout);
1392
1393 if (!fgets(in, sizeof(input_t), stdin))
1394 break;
1395
1396 switch(in[0]) {
1397 case '?':
1398 puts(help);
1399 break;
1400 case 'a':
1401 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1402 puts("what?");
1403 break;
1404 }
1405 key = dupstring(tok1);
1406 val = dupstring(tok2);
1407
1408 if (!key || !val) {
1409 puts("out of memory");
1410 free((void *) key);
1411 free(val);
1412 }
1413
1414 if (!dict_alloc_insert(d, key, val)) {
1415 puts("dict_alloc_insert failed");
1416 free((void *) key);
1417 free(val);
1418 break;
1419 }
1420 break;
1421 case 'd':
1422 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1423 puts("what?");
1424 break;
1425 }
1426 dn = dict_lookup(d, tok1);
1427 if (!dn) {
1428 puts("dict_lookup failed");
1429 break;
1430 }
1431 val = dnode_get(dn);
1432 key = dnode_getkey(dn);
1433 dict_delete_free(d, dn);
1434
1435 free(val);
1436 free((void *) key);
1437 break;
1438 case 'f':
1439 dict_free(d);
1440 break;
1441 case 'l':
1442 case '(':
1443 case ')':
1444 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1445 puts("what?");
1446 break;
1447 }
1448 dn = 0;
1449 switch (in[0]) {
1450 case 'l':
1451 dn = dict_lookup(d, tok1);
1452 break;
1453 case '(':
1454 dn = dict_lower_bound(d, tok1);
1455 break;
1456 case ')':
1457 dn = dict_upper_bound(d, tok1);
1458 break;
1459 }
1460 if (!dn) {
1461 puts("lookup failed");
1462 break;
1463 }
1464 val = dnode_get(dn);
1465 puts(val);
1466 break;
1467 case 'm':
1468 construct(d);
1469 break;
1470 case 'k':
1471 dict_allow_dupes(d);
1472 break;
1473 case 'c':
1474 printf("%lu\n", (unsigned long) dict_count(d));
1475 break;
1476 case 't':
1477 for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
1478 printf("%s\t%s\n", (char *) dnode_getkey(dn),
1479 (char *) dnode_get(dn));
1480 }
1481 break;
1482 case 'q':
1483 exit(0);
1484 break;
1485 case '\0':
1486 break;
1487 case 'p':
1488 prompt = 1;
1489 break;
1490 case 's':
1491 dict_set_allocator(d, new_node, del_node, NULL);
1492 break;
1493 case '#':
1494 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1495 puts("what?");
1496 break;
1497 } else {
1498 int dictnum = atoi(tok1);
1499 if (dictnum < 0 || dictnum > 9) {
1500 puts("invalid number");
1501 break;
1502 }
1503 d = &darray[dictnum];
1504 }
1505 break;
1506 case 'j':
1507 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1508 puts("what?");
1509 break;
1510 } else {
1511 int dict1 = atoi(tok1), dict2 = atoi(tok2);
1512 if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
1513 puts("invalid number");
1514 break;
1515 }
1516 dict_merge(&darray[dict1], &darray[dict2]);
1517 }
1518 break;
1519 default:
1520 putchar('?');
1521 putchar('\n');
1522 break;
1523 }
1524 }
1525
1526 return 0;
1527}
1528
1529#endif
diff --git a/e2fsprogs/e2fsck/dict.h b/e2fsprogs/e2fsck/dict.h
deleted file mode 100644
index 838079d6c..000000000
--- a/e2fsprogs/e2fsck/dict.h
+++ /dev/null
@@ -1,144 +0,0 @@
1/*
2 * Dictionary Abstract Data Type
3 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
4 *
5 * Free Software License:
6 *
7 * All rights are reserved by the author, with the following exceptions:
8 * Permission is granted to freely reproduce and distribute this software,
9 * possibly in exchange for a fee, provided that this copyright notice appears
10 * intact. Permission is also granted to adapt this software to produce
11 * derivative works, as long as the modified versions carry this copyright
12 * notice and additional notices stating that the work has been modified.
13 * This source code may be translated into executable form and incorporated
14 * into proprietary software; there is no requirement for such software to
15 * contain a copyright notice related to this source.
16 *
17 * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $
18 * $Name: kazlib_1_20 $
19 */
20
21#ifndef DICT_H
22#define DICT_H
23
24#include <limits.h>
25#ifdef KAZLIB_SIDEEFFECT_DEBUG
26#include "sfx.h"
27#endif
28
29/*
30 * Blurb for inclusion into C++ translation units
31 */
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37typedef unsigned long dictcount_t;
38#define DICTCOUNT_T_MAX ULONG_MAX
39
40/*
41 * The dictionary is implemented as a red-black tree
42 */
43
44typedef enum { dnode_red, dnode_black } dnode_color_t;
45
46typedef struct dnode_t {
47#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
48 struct dnode_t *dict_left;
49 struct dnode_t *dict_right;
50 struct dnode_t *dict_parent;
51 dnode_color_t dict_color;
52 const void *dict_key;
53 void *dict_data;
54#else
55 int dict_dummy;
56#endif
57} dnode_t;
58
59typedef int (*dict_comp_t)(const void *, const void *);
60typedef dnode_t *(*dnode_alloc_t)(void *);
61typedef void (*dnode_free_t)(dnode_t *, void *);
62
63typedef struct dict_t {
64#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
65 dnode_t dict_nilnode;
66 dictcount_t dict_nodecount;
67 dictcount_t dict_maxcount;
68 dict_comp_t dict_compare;
69 dnode_alloc_t dict_allocnode;
70 dnode_free_t dict_freenode;
71 void *dict_context;
72 int dict_dupes;
73#else
74 int dict_dummmy;
75#endif
76} dict_t;
77
78typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
79
80typedef struct dict_load_t {
81#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
82 dict_t *dict_dictptr;
83 dnode_t dict_nilnode;
84#else
85 int dict_dummmy;
86#endif
87} dict_load_t;
88
89extern dict_t *dict_create(dictcount_t, dict_comp_t);
90extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *);
91extern void dict_destroy(dict_t *);
92extern void dict_free_nodes(dict_t *);
93extern void dict_free(dict_t *);
94extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t);
95extern void dict_init_like(dict_t *, const dict_t *);
96extern int dict_verify(dict_t *);
97extern int dict_similar(const dict_t *, const dict_t *);
98extern dnode_t *dict_lookup(dict_t *, const void *);
99extern dnode_t *dict_lower_bound(dict_t *, const void *);
100extern dnode_t *dict_upper_bound(dict_t *, const void *);
101extern void dict_insert(dict_t *, dnode_t *, const void *);
102extern dnode_t *dict_delete(dict_t *, dnode_t *);
103extern int dict_alloc_insert(dict_t *, const void *, void *);
104extern void dict_delete_free(dict_t *, dnode_t *);
105extern dnode_t *dict_first(dict_t *);
106extern dnode_t *dict_last(dict_t *);
107extern dnode_t *dict_next(dict_t *, dnode_t *);
108extern dnode_t *dict_prev(dict_t *, dnode_t *);
109extern dictcount_t dict_count(dict_t *);
110extern int dict_isempty(dict_t *);
111extern int dict_isfull(dict_t *);
112extern int dict_contains(dict_t *, dnode_t *);
113extern void dict_allow_dupes(dict_t *);
114extern int dnode_is_in_a_dict(dnode_t *);
115extern dnode_t *dnode_create(void *);
116extern dnode_t *dnode_init(dnode_t *, void *);
117extern void dnode_destroy(dnode_t *);
118extern void *dnode_get(dnode_t *);
119extern const void *dnode_getkey(dnode_t *);
120extern void dnode_put(dnode_t *, void *);
121extern void dict_process(dict_t *, void *, dnode_process_t);
122extern void dict_load_begin(dict_load_t *, dict_t *);
123extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
124extern void dict_load_end(dict_load_t *);
125extern void dict_merge(dict_t *, dict_t *);
126
127#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
128#ifdef KAZLIB_SIDEEFFECT_DEBUG
129#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
130#else
131#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount)
132#endif
133#define dict_count(D) ((D)->dict_nodecount)
134#define dict_isempty(D) ((D)->dict_nodecount == 0)
135#define dnode_get(N) ((N)->dict_data)
136#define dnode_getkey(N) ((N)->dict_key)
137#define dnode_put(N, X) ((N)->dict_data = (X))
138#endif
139
140#ifdef __cplusplus
141}
142#endif
143
144#endif
diff --git a/e2fsprogs/e2fsck/dirinfo.c b/e2fsprogs/e2fsck/dirinfo.c
deleted file mode 100644
index 516c46135..000000000
--- a/e2fsprogs/e2fsck/dirinfo.c
+++ /dev/null
@@ -1,137 +0,0 @@
1/*
2 * dirinfo.c --- maintains the directory information table for e2fsck.
3 *
4 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8#include "e2fsck.h"
9
10/*
11 * This subroutine is called during pass1 to create a directory info
12 * entry. During pass1, the passed-in parent is 0; it will get filled
13 * in during pass2.
14 */
15void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
16{
17 struct dir_info *dir;
18 int i, j;
19 ext2_ino_t num_dirs;
20 errcode_t retval;
21 unsigned long old_size;
22
23#if 0
24 printf("add_dir_info for inode %lu...\n", ino);
25#endif
26 if (!ctx->dir_info) {
27 ctx->dir_info_count = 0;
28 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
29 if (retval)
30 num_dirs = 1024; /* Guess */
31 ctx->dir_info_size = num_dirs + 10;
32 ctx->dir_info = (struct dir_info *)
33 e2fsck_allocate_memory(ctx, ctx->dir_info_size
34 * sizeof (struct dir_info),
35 "directory map");
36 }
37
38 if (ctx->dir_info_count >= ctx->dir_info_size) {
39 old_size = ctx->dir_info_size * sizeof(struct dir_info);
40 ctx->dir_info_size += 10;
41 retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
42 sizeof(struct dir_info),
43 &ctx->dir_info);
44 if (retval) {
45 ctx->dir_info_size -= 10;
46 return;
47 }
48 }
49
50 /*
51 * Normally, add_dir_info is called with each inode in
52 * sequential order; but once in a while (like when pass 3
53 * needs to recreate the root directory or lost+found
54 * directory) it is called out of order. In those cases, we
55 * need to move the dir_info entries down to make room, since
56 * the dir_info array needs to be sorted by inode number for
57 * get_dir_info()'s sake.
58 */
59 if (ctx->dir_info_count &&
60 ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
61 for (i = ctx->dir_info_count-1; i > 0; i--)
62 if (ctx->dir_info[i-1].ino < ino)
63 break;
64 dir = &ctx->dir_info[i];
65 if (dir->ino != ino)
66 for (j = ctx->dir_info_count++; j > i; j--)
67 ctx->dir_info[j] = ctx->dir_info[j-1];
68 } else
69 dir = &ctx->dir_info[ctx->dir_info_count++];
70
71 dir->ino = ino;
72 dir->dotdot = parent;
73 dir->parent = parent;
74}
75
76/*
77 * get_dir_info() --- given an inode number, try to find the directory
78 * information entry for it.
79 */
80struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
81{
82 int low, high, mid;
83
84 low = 0;
85 high = ctx->dir_info_count-1;
86 if (!ctx->dir_info)
87 return 0;
88 if (ino == ctx->dir_info[low].ino)
89 return &ctx->dir_info[low];
90 if (ino == ctx->dir_info[high].ino)
91 return &ctx->dir_info[high];
92
93 while (low < high) {
94 mid = (low+high)/2;
95 if (mid == low || mid == high)
96 break;
97 if (ino == ctx->dir_info[mid].ino)
98 return &ctx->dir_info[mid];
99 if (ino < ctx->dir_info[mid].ino)
100 high = mid;
101 else
102 low = mid;
103 }
104 return 0;
105}
106
107/*
108 * Free the dir_info structure when it isn't needed any more.
109 */
110void e2fsck_free_dir_info(e2fsck_t ctx)
111{
112 if (ctx->dir_info) {
113 ext2fs_free_mem(&ctx->dir_info);
114 ctx->dir_info = 0;
115 }
116 ctx->dir_info_size = 0;
117 ctx->dir_info_count = 0;
118}
119
120/*
121 * Return the count of number of directories in the dir_info structure
122 */
123int e2fsck_get_num_dirinfo(e2fsck_t ctx)
124{
125 return ctx->dir_info_count;
126}
127
128/*
129 * A simple interator function
130 */
131struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
132{
133 if (*control >= ctx->dir_info_count)
134 return 0;
135
136 return(ctx->dir_info + (*control)++);
137}
diff --git a/e2fsprogs/e2fsck/dx_dirinfo.c b/e2fsprogs/e2fsck/dx_dirinfo.c
deleted file mode 100644
index 322f51679..000000000
--- a/e2fsprogs/e2fsck/dx_dirinfo.c
+++ /dev/null
@@ -1,150 +0,0 @@
1/*
2 * dirinfo.c --- maintains the directory information table for e2fsck.
3 *
4 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8#include "e2fsck.h"
9#ifdef ENABLE_HTREE
10
11/*
12 * This subroutine is called during pass1 to create a directory info
13 * entry. During pass1, the passed-in parent is 0; it will get filled
14 * in during pass2.
15 */
16void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
17{
18 struct dx_dir_info *dir;
19 int i, j;
20 errcode_t retval;
21 unsigned long old_size;
22
23#if 0
24 printf("add_dx_dir_info for inode %lu...\n", ino);
25#endif
26 if (!ctx->dx_dir_info) {
27 ctx->dx_dir_info_count = 0;
28 ctx->dx_dir_info_size = 100; /* Guess */
29 ctx->dx_dir_info = (struct dx_dir_info *)
30 e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
31 * sizeof (struct dx_dir_info),
32 "directory map");
33 }
34
35 if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
36 old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
37 ctx->dx_dir_info_size += 10;
38 retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
39 sizeof(struct dx_dir_info),
40 &ctx->dx_dir_info);
41 if (retval) {
42 ctx->dx_dir_info_size -= 10;
43 return;
44 }
45 }
46
47 /*
48 * Normally, add_dx_dir_info is called with each inode in
49 * sequential order; but once in a while (like when pass 3
50 * needs to recreate the root directory or lost+found
51 * directory) it is called out of order. In those cases, we
52 * need to move the dx_dir_info entries down to make room, since
53 * the dx_dir_info array needs to be sorted by inode number for
54 * get_dx_dir_info()'s sake.
55 */
56 if (ctx->dx_dir_info_count &&
57 ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
58 for (i = ctx->dx_dir_info_count-1; i > 0; i--)
59 if (ctx->dx_dir_info[i-1].ino < ino)
60 break;
61 dir = &ctx->dx_dir_info[i];
62 if (dir->ino != ino)
63 for (j = ctx->dx_dir_info_count++; j > i; j--)
64 ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
65 } else
66 dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
67
68 dir->ino = ino;
69 dir->numblocks = num_blocks;
70 dir->hashversion = 0;
71 dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
72 * sizeof (struct dx_dirblock_info),
73 "dx_block info array");
74
75}
76
77/*
78 * get_dx_dir_info() --- given an inode number, try to find the directory
79 * information entry for it.
80 */
81struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
82{
83 int low, high, mid;
84
85 low = 0;
86 high = ctx->dx_dir_info_count-1;
87 if (!ctx->dx_dir_info)
88 return 0;
89 if (ino == ctx->dx_dir_info[low].ino)
90 return &ctx->dx_dir_info[low];
91 if (ino == ctx->dx_dir_info[high].ino)
92 return &ctx->dx_dir_info[high];
93
94 while (low < high) {
95 mid = (low+high)/2;
96 if (mid == low || mid == high)
97 break;
98 if (ino == ctx->dx_dir_info[mid].ino)
99 return &ctx->dx_dir_info[mid];
100 if (ino < ctx->dx_dir_info[mid].ino)
101 high = mid;
102 else
103 low = mid;
104 }
105 return 0;
106}
107
108/*
109 * Free the dx_dir_info structure when it isn't needed any more.
110 */
111void e2fsck_free_dx_dir_info(e2fsck_t ctx)
112{
113 int i;
114 struct dx_dir_info *dir;
115
116 if (ctx->dx_dir_info) {
117 dir = ctx->dx_dir_info;
118 for (i=0; i < ctx->dx_dir_info_count; i++) {
119 if (dir->dx_block) {
120 ext2fs_free_mem(&dir->dx_block);
121 dir->dx_block = 0;
122 }
123 }
124 ext2fs_free_mem(&ctx->dx_dir_info);
125 ctx->dx_dir_info = 0;
126 }
127 ctx->dx_dir_info_size = 0;
128 ctx->dx_dir_info_count = 0;
129}
130
131/*
132 * Return the count of number of directories in the dx_dir_info structure
133 */
134int e2fsck_get_num_dx_dirinfo(e2fsck_t ctx)
135{
136 return ctx->dx_dir_info_count;
137}
138
139/*
140 * A simple interator function
141 */
142struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
143{
144 if (*control >= ctx->dx_dir_info_count)
145 return 0;
146
147 return(ctx->dx_dir_info + (*control)++);
148}
149
150#endif /* ENABLE_HTREE */
diff --git a/e2fsprogs/e2fsck/e2fsck.c b/e2fsprogs/e2fsck/e2fsck.c
deleted file mode 100644
index 2a84c5171..000000000
--- a/e2fsprogs/e2fsck/e2fsck.c
+++ /dev/null
@@ -1,202 +0,0 @@
1/*
2 * e2fsck.c - a consistency checker for the new extended file system.
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <errno.h>
13
14#include "e2fsck.h"
15#include "problem.h"
16
17/*
18 * This function allocates an e2fsck context
19 */
20errcode_t e2fsck_allocate_context(e2fsck_t *ret)
21{
22 e2fsck_t context;
23 errcode_t retval;
24
25 retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &context);
26 if (retval)
27 return retval;
28
29 memset(context, 0, sizeof(struct e2fsck_struct));
30
31 context->process_inode_size = 256;
32 context->ext_attr_ver = 2;
33
34 *ret = context;
35 return 0;
36}
37
38/*
39 * This function resets an e2fsck context; it is called when e2fsck
40 * needs to be restarted.
41 */
42errcode_t e2fsck_reset_context(e2fsck_t ctx)
43{
44 ctx->flags = 0;
45 ctx->lost_and_found = 0;
46 ctx->bad_lost_and_found = 0;
47 if (ctx->inode_used_map) {
48 ext2fs_free_inode_bitmap(ctx->inode_used_map);
49 ctx->inode_used_map = 0;
50 }
51 if (ctx->inode_dir_map) {
52 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
53 ctx->inode_dir_map = 0;
54 }
55 if (ctx->inode_reg_map) {
56 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
57 ctx->inode_reg_map = 0;
58 }
59 if (ctx->block_found_map) {
60 ext2fs_free_block_bitmap(ctx->block_found_map);
61 ctx->block_found_map = 0;
62 }
63 if (ctx->inode_link_info) {
64 ext2fs_free_icount(ctx->inode_link_info);
65 ctx->inode_link_info = 0;
66 }
67 if (ctx->journal_io) {
68 if (ctx->fs && ctx->fs->io != ctx->journal_io)
69 io_channel_close(ctx->journal_io);
70 ctx->journal_io = 0;
71 }
72 if (ctx->fs && ctx->fs->dblist) {
73 ext2fs_free_dblist(ctx->fs->dblist);
74 ctx->fs->dblist = 0;
75 }
76 e2fsck_free_dir_info(ctx);
77#ifdef ENABLE_HTREE
78 e2fsck_free_dx_dir_info(ctx);
79#endif
80 if (ctx->refcount) {
81 ea_refcount_free(ctx->refcount);
82 ctx->refcount = 0;
83 }
84 if (ctx->refcount_extra) {
85 ea_refcount_free(ctx->refcount_extra);
86 ctx->refcount_extra = 0;
87 }
88 if (ctx->block_dup_map) {
89 ext2fs_free_block_bitmap(ctx->block_dup_map);
90 ctx->block_dup_map = 0;
91 }
92 if (ctx->block_ea_map) {
93 ext2fs_free_block_bitmap(ctx->block_ea_map);
94 ctx->block_ea_map = 0;
95 }
96 if (ctx->inode_bb_map) {
97 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
98 ctx->inode_bb_map = 0;
99 }
100 if (ctx->inode_bad_map) {
101 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
102 ctx->inode_bad_map = 0;
103 }
104 if (ctx->inode_imagic_map) {
105 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
106 ctx->inode_imagic_map = 0;
107 }
108 if (ctx->dirs_to_hash) {
109 ext2fs_u32_list_free(ctx->dirs_to_hash);
110 ctx->dirs_to_hash = 0;
111 }
112
113 /*
114 * Clear the array of invalid meta-data flags
115 */
116 if (ctx->invalid_inode_bitmap_flag) {
117 ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag);
118 ctx->invalid_inode_bitmap_flag = 0;
119 }
120 if (ctx->invalid_block_bitmap_flag) {
121 ext2fs_free_mem(&ctx->invalid_block_bitmap_flag);
122 ctx->invalid_block_bitmap_flag = 0;
123 }
124 if (ctx->invalid_inode_table_flag) {
125 ext2fs_free_mem(&ctx->invalid_inode_table_flag);
126 ctx->invalid_inode_table_flag = 0;
127 }
128
129 /* Clear statistic counters */
130 ctx->fs_directory_count = 0;
131 ctx->fs_regular_count = 0;
132 ctx->fs_blockdev_count = 0;
133 ctx->fs_chardev_count = 0;
134 ctx->fs_links_count = 0;
135 ctx->fs_symlinks_count = 0;
136 ctx->fs_fast_symlinks_count = 0;
137 ctx->fs_fifo_count = 0;
138 ctx->fs_total_count = 0;
139 ctx->fs_badblocks_count = 0;
140 ctx->fs_sockets_count = 0;
141 ctx->fs_ind_count = 0;
142 ctx->fs_dind_count = 0;
143 ctx->fs_tind_count = 0;
144 ctx->fs_fragmented = 0;
145 ctx->large_files = 0;
146
147 /* Reset the superblock to the user's requested value */
148 ctx->superblock = ctx->use_superblock;
149
150 return 0;
151}
152
153void e2fsck_free_context(e2fsck_t ctx)
154{
155 if (!ctx)
156 return;
157
158 e2fsck_reset_context(ctx);
159 if (ctx->blkid)
160 blkid_put_cache(ctx->blkid);
161
162 ext2fs_free_mem(&ctx);
163}
164
165/*
166 * This function runs through the e2fsck passes and calls them all,
167 * returning restart, abort, or cancel as necessary...
168 */
169typedef void (*pass_t)(e2fsck_t ctx);
170
171pass_t e2fsck_passes[] = {
172 e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
173 e2fsck_pass5, 0 };
174
175#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
176
177int e2fsck_run(e2fsck_t ctx)
178{
179 int i;
180 pass_t e2fsck_pass;
181
182#ifdef HAVE_SETJMP_H
183 if (setjmp(ctx->abort_loc)) {
184 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
185 return (ctx->flags & E2F_FLAG_RUN_RETURN);
186 }
187 ctx->flags |= E2F_FLAG_SETJMP_OK;
188#endif
189
190 for (i=0; (e2fsck_pass = e2fsck_passes[i]); i++) {
191 if (ctx->flags & E2F_FLAG_RUN_RETURN)
192 break;
193 e2fsck_pass(ctx);
194 if (ctx->progress)
195 (void) (ctx->progress)(ctx, 0, 0, 0);
196 }
197 ctx->flags &= ~E2F_FLAG_SETJMP_OK;
198
199 if (ctx->flags & E2F_FLAG_RUN_RETURN)
200 return (ctx->flags & E2F_FLAG_RUN_RETURN);
201 return 0;
202}
diff --git a/e2fsprogs/e2fsck/e2fsck.h b/e2fsprogs/e2fsck/e2fsck.h
deleted file mode 100644
index 489903d7c..000000000
--- a/e2fsprogs/e2fsck/e2fsck.h
+++ /dev/null
@@ -1,446 +0,0 @@
1/*
2 * e2fsck.h
3 *
4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
6 *
7 */
8
9#include <stdio.h>
10#include <string.h>
11#ifdef HAVE_UNISTD_H
12#include <unistd.h>
13#endif
14#include <stdlib.h>
15#include <time.h>
16#ifdef HAVE_SYS_TYPES_H
17#include <sys/types.h>
18#endif
19#ifdef HAVE_SYS_TIME_H
20#include <sys/time.h>
21#endif
22#ifdef HAVE_SETJMP_H
23#include <setjmp.h>
24#endif
25
26#if EXT2_FLAT_INCLUDES
27#include "ext2_fs.h"
28#include "ext2fs.h"
29#include "blkid.h"
30#else
31#include "ext2fs/ext2_fs.h"
32#include "ext2fs/ext2fs.h"
33#include "blkid/blkid.h"
34#endif
35
36/*
37 * Exit codes used by fsck-type programs
38 */
39#define FSCK_OK 0 /* No errors */
40#define FSCK_NONDESTRUCT 1 /* File system errors corrected */
41#define FSCK_REBOOT 2 /* System should be rebooted */
42#define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */
43#define FSCK_ERROR 8 /* Operational error */
44#define FSCK_USAGE 16 /* Usage or syntax error */
45#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
46#define FSCK_LIBRARY 128 /* Shared library error */
47
48/*
49 * The last ext2fs revision level that this version of e2fsck is able to
50 * support
51 */
52#define E2FSCK_CURRENT_REV 1
53
54/*
55 * The directory information structure; stores directory information
56 * collected in earlier passes, to avoid disk i/o in fetching the
57 * directory information.
58 */
59struct dir_info {
60 ext2_ino_t ino; /* Inode number */
61 ext2_ino_t dotdot; /* Parent according to '..' */
62 ext2_ino_t parent; /* Parent according to treewalk */
63};
64
65
66/*
67 * The indexed directory information structure; stores information for
68 * directories which contain a hash tree index.
69 */
70struct dx_dir_info {
71 ext2_ino_t ino; /* Inode number */
72 int numblocks; /* number of blocks */
73 int hashversion;
74 short depth; /* depth of tree */
75 struct dx_dirblock_info *dx_block; /* Array of size numblocks */
76};
77
78#define DX_DIRBLOCK_ROOT 1
79#define DX_DIRBLOCK_LEAF 2
80#define DX_DIRBLOCK_NODE 3
81#define DX_DIRBLOCK_CORRUPT 4
82#define DX_DIRBLOCK_CLEARED 8
83
84struct dx_dirblock_info {
85 int type;
86 blk_t phys;
87 int flags;
88 blk_t parent;
89 ext2_dirhash_t min_hash;
90 ext2_dirhash_t max_hash;
91 ext2_dirhash_t node_min_hash;
92 ext2_dirhash_t node_max_hash;
93};
94
95#define DX_FLAG_REFERENCED 1
96#define DX_FLAG_DUP_REF 2
97#define DX_FLAG_FIRST 4
98#define DX_FLAG_LAST 8
99
100#ifdef RESOURCE_TRACK
101/*
102 * This structure is used for keeping track of how much resources have
103 * been used for a particular pass of e2fsck.
104 */
105struct resource_track {
106 struct timeval time_start;
107 struct timeval user_start;
108 struct timeval system_start;
109 void *brk_start;
110};
111#endif
112
113/*
114 * E2fsck options
115 */
116#define E2F_OPT_READONLY 0x0001
117#define E2F_OPT_PREEN 0x0002
118#define E2F_OPT_YES 0x0004
119#define E2F_OPT_NO 0x0008
120#define E2F_OPT_TIME 0x0010
121#define E2F_OPT_TIME2 0x0020
122#define E2F_OPT_CHECKBLOCKS 0x0040
123#define E2F_OPT_DEBUG 0x0080
124#define E2F_OPT_FORCE 0x0100
125#define E2F_OPT_WRITECHECK 0x0200
126#define E2F_OPT_COMPRESS_DIRS 0x0400
127
128/*
129 * E2fsck flags
130 */
131#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
132#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
133#define E2F_FLAG_SIGNAL_MASK 0x0003
134#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
135
136#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
137
138#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
139#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */
140#define E2F_FLAG_JOURNAL_INODE 0x0080 /* Create a new ext3 journal inode */
141#define E2F_FLAG_SB_SPECIFIED 0x0100 /* The superblock was explicitly
142 * specified by the user */
143#define E2F_FLAG_RESTARTED 0x0200 /* E2fsck has been restarted */
144#define E2F_FLAG_RESIZE_INODE 0x0400 /* Request to recreate resize inode */
145
146/*
147 * Defines for indicating the e2fsck pass number
148 */
149#define E2F_PASS_1 1
150#define E2F_PASS_2 2
151#define E2F_PASS_3 3
152#define E2F_PASS_4 4
153#define E2F_PASS_5 5
154#define E2F_PASS_1B 6
155
156/*
157 * Define the extended attribute refcount structure
158 */
159typedef struct ea_refcount *ext2_refcount_t;
160
161/*
162 * This is the global e2fsck structure.
163 */
164typedef struct e2fsck_struct *e2fsck_t;
165
166struct e2fsck_struct {
167 ext2_filsys fs;
168 const char *program_name;
169 char *filesystem_name;
170 char *device_name;
171 char *io_options;
172 int flags; /* E2fsck internal flags */
173 int options;
174 blk_t use_superblock; /* sb requested by user */
175 blk_t superblock; /* sb used to open fs */
176 int blocksize; /* blocksize */
177 blk_t num_blocks; /* Total number of blocks */
178 int mount_flags;
179 blkid_cache blkid; /* blkid cache */
180
181#ifdef HAVE_SETJMP_H
182 jmp_buf abort_loc;
183#endif
184 unsigned long abort_code;
185
186 int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
187 unsigned long max);
188
189 ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
190 ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
191 ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
192 ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
193 ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
194 ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
195
196 ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
197 ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
198 ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
199
200 /*
201 * Inode count arrays
202 */
203 ext2_icount_t inode_count;
204 ext2_icount_t inode_link_info;
205
206 ext2_refcount_t refcount;
207 ext2_refcount_t refcount_extra;
208
209 /*
210 * Array of flags indicating whether an inode bitmap, block
211 * bitmap, or inode table is invalid
212 */
213 int *invalid_inode_bitmap_flag;
214 int *invalid_block_bitmap_flag;
215 int *invalid_inode_table_flag;
216 int invalid_bitmaps; /* There are invalid bitmaps/itable */
217
218 /*
219 * Block buffer
220 */
221 char *block_buf;
222
223 /*
224 * For pass1_check_directory and pass1_get_blocks
225 */
226 ext2_ino_t stashed_ino;
227 struct ext2_inode *stashed_inode;
228
229 /*
230 * Location of the lost and found directory
231 */
232 ext2_ino_t lost_and_found;
233 int bad_lost_and_found;
234
235 /*
236 * Directory information
237 */
238 int dir_info_count;
239 int dir_info_size;
240 struct dir_info *dir_info;
241
242 /*
243 * Indexed directory information
244 */
245 int dx_dir_info_count;
246 int dx_dir_info_size;
247 struct dx_dir_info *dx_dir_info;
248
249 /*
250 * Directories to hash
251 */
252 ext2_u32_list dirs_to_hash;
253
254 /*
255 * Tuning parameters
256 */
257 int process_inode_size;
258 int inode_buffer_blocks;
259
260 /*
261 * ext3 journal support
262 */
263 io_channel journal_io;
264 char *journal_name;
265
266#ifdef RESOURCE_TRACK
267 /*
268 * For timing purposes
269 */
270 struct resource_track global_rtrack;
271#endif
272
273 /*
274 * How we display the progress update (for unix)
275 */
276 int progress_fd;
277 int progress_pos;
278 int progress_last_percent;
279 unsigned int progress_last_time;
280 int interactive; /* Are we connected directly to a tty? */
281 char start_meta[2], stop_meta[2];
282
283 /* File counts */
284 int fs_directory_count;
285 int fs_regular_count;
286 int fs_blockdev_count;
287 int fs_chardev_count;
288 int fs_links_count;
289 int fs_symlinks_count;
290 int fs_fast_symlinks_count;
291 int fs_fifo_count;
292 int fs_total_count;
293 int fs_badblocks_count;
294 int fs_sockets_count;
295 int fs_ind_count;
296 int fs_dind_count;
297 int fs_tind_count;
298 int fs_fragmented;
299 int large_files;
300 int fs_ext_attr_inodes;
301 int fs_ext_attr_blocks;
302
303 int ext_attr_ver;
304
305 /*
306 * For the use of callers of the e2fsck functions; not used by
307 * e2fsck functions themselves.
308 */
309 void *priv_data;
310};
311
312/* Used by the region allocation code */
313typedef __u32 region_addr_t;
314typedef struct region_struct *region_t;
315
316#ifndef HAVE_STRNLEN
317#define strnlen(str, x) e2fsck_strnlen((str),(x))
318extern int e2fsck_strnlen(const char * s, int count);
319#endif
320
321/*
322 * Procedure declarations
323 */
324
325extern void e2fsck_pass1(e2fsck_t ctx);
326extern void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
327extern void e2fsck_pass2(e2fsck_t ctx);
328extern void e2fsck_pass3(e2fsck_t ctx);
329extern void e2fsck_pass4(e2fsck_t ctx);
330extern void e2fsck_pass5(e2fsck_t ctx);
331
332/* e2fsck.c */
333extern errcode_t e2fsck_allocate_context(e2fsck_t *ret);
334extern errcode_t e2fsck_reset_context(e2fsck_t ctx);
335extern void e2fsck_free_context(e2fsck_t ctx);
336extern int e2fsck_run(e2fsck_t ctx);
337
338
339/* badblock.c */
340extern void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
341 int replace_bad_blocks);
342
343/* dirinfo.c */
344extern void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
345extern struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino);
346extern void e2fsck_free_dir_info(e2fsck_t ctx);
347extern int e2fsck_get_num_dirinfo(e2fsck_t ctx);
348extern struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control);
349
350/* dx_dirinfo.c */
351extern void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks);
352extern struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino);
353extern void e2fsck_free_dx_dir_info(e2fsck_t ctx);
354extern int e2fsck_get_num_dx_dirinfo(e2fsck_t ctx);
355extern struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control);
356
357/* ea_refcount.c */
358extern errcode_t ea_refcount_create(int size, ext2_refcount_t *ret);
359extern void ea_refcount_free(ext2_refcount_t refcount);
360extern errcode_t ea_refcount_fetch(ext2_refcount_t refcount, blk_t blk,
361 int *ret);
362extern errcode_t ea_refcount_increment(ext2_refcount_t refcount,
363 blk_t blk, int *ret);
364extern errcode_t ea_refcount_decrement(ext2_refcount_t refcount,
365 blk_t blk, int *ret);
366extern errcode_t ea_refcount_store(ext2_refcount_t refcount,
367 blk_t blk, int count);
368extern blk_t ext2fs_get_refcount_size(ext2_refcount_t refcount);
369extern void ea_refcount_intr_begin(ext2_refcount_t refcount);
370extern blk_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret);
371
372/* ehandler.c */
373extern const char *ehandler_operation(const char *op);
374extern void ehandler_init(io_channel channel);
375
376/* journal.c */
377extern int e2fsck_check_ext3_journal(e2fsck_t ctx);
378extern int e2fsck_run_ext3_journal(e2fsck_t ctx);
379extern void e2fsck_move_ext3_journal(e2fsck_t ctx);
380
381/* pass1.c */
382extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
383extern int e2fsck_pass1_check_device_inode(ext2_filsys fs,
384 struct ext2_inode *inode);
385extern int e2fsck_pass1_check_symlink(ext2_filsys fs,
386 struct ext2_inode *inode, char *buf);
387
388/* pass2.c */
389extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
390 ext2_ino_t ino, char *buf);
391
392/* pass3.c */
393extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
394extern errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
395 int num, int gauranteed_size);
396extern ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix);
397extern errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino,
398 int adj);
399
400
401/* region.c */
402extern region_t region_create(region_addr_t min, region_addr_t max);
403extern void region_free(region_t region);
404extern int region_allocate(region_t region, region_addr_t start, int n);
405
406/* rehash.c */
407errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
408void e2fsck_rehash_directories(e2fsck_t ctx);
409
410/* super.c */
411void check_super_block(e2fsck_t ctx);
412errcode_t e2fsck_get_device_size(e2fsck_t ctx);
413
414/* swapfs.c */
415void swap_filesys(e2fsck_t ctx);
416
417/* util.c */
418extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
419 const char *description);
420extern int ask(e2fsck_t ctx, const char * string, int def);
421extern int ask_yn(const char * string, int def);
422extern void e2fsck_read_bitmaps(e2fsck_t ctx);
423extern void e2fsck_write_bitmaps(e2fsck_t ctx);
424extern void preenhalt(e2fsck_t ctx);
425extern char *string_copy(e2fsck_t ctx, const char *str, int len);
426#ifdef RESOURCE_TRACK
427extern void print_resource_track(const char *desc,
428 struct resource_track *track);
429extern void init_resource_track(struct resource_track *track);
430#endif
431extern int inode_has_valid_blocks(struct ext2_inode *inode);
432extern void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
433 struct ext2_inode * inode, const char * proc);
434extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
435 struct ext2_inode * inode, const char * proc);
436#ifdef MTRACE
437extern void mtrace_print(char *mesg);
438#endif
439extern blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs,
440 const char *name, io_manager manager);
441extern int ext2_file_type(unsigned int mode);
442
443/* unix.c */
444extern void e2fsck_clear_progbar(e2fsck_t ctx);
445extern int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
446 float percent, unsigned int dpynum);
diff --git a/e2fsprogs/e2fsck/ea_refcount.c b/e2fsprogs/e2fsck/ea_refcount.c
deleted file mode 100644
index 6420c7280..000000000
--- a/e2fsprogs/e2fsck/ea_refcount.c
+++ /dev/null
@@ -1,479 +0,0 @@
1/*
2 * ea_refcount.c
3 *
4 * Copyright (C) 2001 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
6 */
7
8#if HAVE_UNISTD_H
9#include <unistd.h>
10#endif
11#include <string.h>
12#include <stdio.h>
13
14#include "e2fsck.h"
15
16/*
17 * The strategy we use for keeping track of EA refcounts is as
18 * follows. We keep a sorted array of first EA blocks and its
19 * reference counts. Once the refcount has dropped to zero, it is
20 * removed from the array to save memory space. Once the EA block is
21 * checked, its bit is set in the block_ea_map bitmap.
22 */
23struct ea_refcount_el {
24 blk_t ea_blk;
25 int ea_count;
26};
27
28struct ea_refcount {
29 blk_t count;
30 blk_t size;
31 blk_t cursor;
32 struct ea_refcount_el *list;
33};
34
35void ea_refcount_free(ext2_refcount_t refcount)
36{
37 if (!refcount)
38 return;
39
40 if (refcount->list)
41 ext2fs_free_mem(&refcount->list);
42 ext2fs_free_mem(&refcount);
43}
44
45errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
46{
47 ext2_refcount_t refcount;
48 errcode_t retval;
49 size_t bytes;
50
51 retval = ext2fs_get_mem(sizeof(struct ea_refcount), &refcount);
52 if (retval)
53 return retval;
54 memset(refcount, 0, sizeof(struct ea_refcount));
55
56 if (!size)
57 size = 500;
58 refcount->size = size;
59 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
60#ifdef DEBUG
61 printf("Refcount allocated %d entries, %d bytes.\n",
62 refcount->size, bytes);
63#endif
64 retval = ext2fs_get_mem(bytes, &refcount->list);
65 if (retval)
66 goto errout;
67 memset(refcount->list, 0, bytes);
68
69 refcount->count = 0;
70 refcount->cursor = 0;
71
72 *ret = refcount;
73 return 0;
74
75errout:
76 ea_refcount_free(refcount);
77 return(retval);
78}
79
80/*
81 * collapse_refcount() --- go through the refcount array, and get rid
82 * of any count == zero entries
83 */
84static void refcount_collapse(ext2_refcount_t refcount)
85{
86 unsigned int i, j;
87 struct ea_refcount_el *list;
88
89 list = refcount->list;
90 for (i = 0, j = 0; i < refcount->count; i++) {
91 if (list[i].ea_count) {
92 if (i != j)
93 list[j] = list[i];
94 j++;
95 }
96 }
97#if defined(DEBUG) || defined(TEST_PROGRAM)
98 printf("Refcount_collapse: size was %d, now %d\n",
99 refcount->count, j);
100#endif
101 refcount->count = j;
102}
103
104
105/*
106 * insert_refcount_el() --- Insert a new entry into the sorted list at a
107 * specified position.
108 */
109static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
110 blk_t blk, int pos)
111{
112 struct ea_refcount_el *el;
113 errcode_t retval;
114 blk_t new_size = 0;
115 int num;
116
117 if (refcount->count >= refcount->size) {
118 new_size = refcount->size + 100;
119#ifdef DEBUG
120 printf("Reallocating refcount %d entries...\n", new_size);
121#endif
122 retval = ext2fs_resize_mem((size_t) refcount->size *
123 sizeof(struct ea_refcount_el),
124 (size_t) new_size *
125 sizeof(struct ea_refcount_el),
126 &refcount->list);
127 if (retval)
128 return 0;
129 refcount->size = new_size;
130 }
131 num = (int) refcount->count - pos;
132 if (num < 0)
133 return 0; /* should never happen */
134 if (num) {
135 memmove(&refcount->list[pos+1], &refcount->list[pos],
136 sizeof(struct ea_refcount_el) * num);
137 }
138 refcount->count++;
139 el = &refcount->list[pos];
140 el->ea_count = 0;
141 el->ea_blk = blk;
142 return el;
143}
144
145
146/*
147 * get_refcount_el() --- given an block number, try to find refcount
148 * information in the sorted list. If the create flag is set,
149 * and we can't find an entry, create one in the sorted list.
150 */
151static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
152 blk_t blk, int create)
153{
154 float range;
155 int low, high, mid;
156 blk_t lowval, highval;
157
158 if (!refcount || !refcount->list)
159 return 0;
160retry:
161 low = 0;
162 high = (int) refcount->count-1;
163 if (create && ((refcount->count == 0) ||
164 (blk > refcount->list[high].ea_blk))) {
165 if (refcount->count >= refcount->size)
166 refcount_collapse(refcount);
167
168 return insert_refcount_el(refcount, blk,
169 (unsigned) refcount->count);
170 }
171 if (refcount->count == 0)
172 return 0;
173
174 if (refcount->cursor >= refcount->count)
175 refcount->cursor = 0;
176 if (blk == refcount->list[refcount->cursor].ea_blk)
177 return &refcount->list[refcount->cursor++];
178#ifdef DEBUG
179 printf("Non-cursor get_refcount_el: %u\n", blk);
180#endif
181 while (low <= high) {
182#if 0
183 mid = (low+high)/2;
184#else
185 if (low == high)
186 mid = low;
187 else {
188 /* Interpolate for efficiency */
189 lowval = refcount->list[low].ea_blk;
190 highval = refcount->list[high].ea_blk;
191
192 if (blk < lowval)
193 range = 0;
194 else if (blk > highval)
195 range = 1;
196 else
197 range = ((float) (blk - lowval)) /
198 (highval - lowval);
199 mid = low + ((int) (range * (high-low)));
200 }
201#endif
202 if (blk == refcount->list[mid].ea_blk) {
203 refcount->cursor = mid+1;
204 return &refcount->list[mid];
205 }
206 if (blk < refcount->list[mid].ea_blk)
207 high = mid-1;
208 else
209 low = mid+1;
210 }
211 /*
212 * If we need to create a new entry, it should be right at
213 * low (where high will be left at low-1).
214 */
215 if (create) {
216 if (refcount->count >= refcount->size) {
217 refcount_collapse(refcount);
218 if (refcount->count < refcount->size)
219 goto retry;
220 }
221 return insert_refcount_el(refcount, blk, low);
222 }
223 return 0;
224}
225
226errcode_t ea_refcount_fetch(ext2_refcount_t refcount, blk_t blk,
227 int *ret)
228{
229 struct ea_refcount_el *el;
230
231 el = get_refcount_el(refcount, blk, 0);
232 if (!el) {
233 *ret = 0;
234 return 0;
235 }
236 *ret = el->ea_count;
237 return 0;
238}
239
240errcode_t ea_refcount_increment(ext2_refcount_t refcount, blk_t blk, int *ret)
241{
242 struct ea_refcount_el *el;
243
244 el = get_refcount_el(refcount, blk, 1);
245 if (!el)
246 return EXT2_ET_NO_MEMORY;
247 el->ea_count++;
248
249 if (ret)
250 *ret = el->ea_count;
251 return 0;
252}
253
254errcode_t ea_refcount_decrement(ext2_refcount_t refcount, blk_t blk, int *ret)
255{
256 struct ea_refcount_el *el;
257
258 el = get_refcount_el(refcount, blk, 0);
259 if (!el || el->ea_count == 0)
260 return EXT2_ET_INVALID_ARGUMENT;
261
262 el->ea_count--;
263
264 if (ret)
265 *ret = el->ea_count;
266 return 0;
267}
268
269errcode_t ea_refcount_store(ext2_refcount_t refcount, blk_t blk, int count)
270{
271 struct ea_refcount_el *el;
272
273 /*
274 * Get the refcount element
275 */
276 el = get_refcount_el(refcount, blk, count ? 1 : 0);
277 if (!el)
278 return count ? EXT2_ET_NO_MEMORY : 0;
279 el->ea_count = count;
280 return 0;
281}
282
283blk_t ext2fs_get_refcount_size(ext2_refcount_t refcount)
284{
285 if (!refcount)
286 return 0;
287
288 return refcount->size;
289}
290
291void ea_refcount_intr_begin(ext2_refcount_t refcount)
292{
293 refcount->cursor = 0;
294}
295
296
297blk_t ea_refcount_intr_next(ext2_refcount_t refcount,
298 int *ret)
299{
300 struct ea_refcount_el *list;
301
302 while (1) {
303 if (refcount->cursor >= refcount->count)
304 return 0;
305 list = refcount->list;
306 if (list[refcount->cursor].ea_count) {
307 if (ret)
308 *ret = list[refcount->cursor].ea_count;
309 return list[refcount->cursor++].ea_blk;
310 }
311 refcount->cursor++;
312 }
313}
314
315
316#ifdef TEST_PROGRAM
317
318errcode_t ea_refcount_validate(ext2_refcount_t refcount, FILE *out)
319{
320 errcode_t ret = 0;
321 int i;
322 const char *bad = "bad refcount";
323
324 if (refcount->count > refcount->size) {
325 fprintf(out, "%s: count > size\n", bad);
326 return EXT2_ET_INVALID_ARGUMENT;
327 }
328 for (i=1; i < refcount->count; i++) {
329 if (refcount->list[i-1].ea_blk >= refcount->list[i].ea_blk) {
330 fprintf(out, "%s: list[%d].blk=%u, list[%d].blk=%u\n",
331 bad, i-1, refcount->list[i-1].ea_blk,
332 i, refcount->list[i].ea_blk);
333 ret = EXT2_ET_INVALID_ARGUMENT;
334 }
335 }
336 return ret;
337}
338
339#define BCODE_END 0
340#define BCODE_CREATE 1
341#define BCODE_FREE 2
342#define BCODE_STORE 3
343#define BCODE_INCR 4
344#define BCODE_DECR 5
345#define BCODE_FETCH 6
346#define BCODE_VALIDATE 7
347#define BCODE_LIST 8
348#define BCODE_COLLAPSE 9
349
350int bcode_program[] = {
351 BCODE_CREATE, 5,
352 BCODE_STORE, 3, 3,
353 BCODE_STORE, 4, 4,
354 BCODE_STORE, 1, 1,
355 BCODE_STORE, 8, 8,
356 BCODE_STORE, 2, 2,
357 BCODE_STORE, 4, 0,
358 BCODE_STORE, 2, 0,
359 BCODE_STORE, 6, 6,
360 BCODE_VALIDATE,
361 BCODE_STORE, 4, 4,
362 BCODE_STORE, 2, 2,
363 BCODE_FETCH, 1,
364 BCODE_FETCH, 2,
365 BCODE_INCR, 3,
366 BCODE_INCR, 3,
367 BCODE_DECR, 4,
368 BCODE_STORE, 4, 4,
369 BCODE_VALIDATE,
370 BCODE_STORE, 20, 20,
371 BCODE_STORE, 40, 40,
372 BCODE_STORE, 30, 30,
373 BCODE_STORE, 10, 10,
374 BCODE_DECR, 30,
375 BCODE_FETCH, 30,
376 BCODE_DECR, 2,
377 BCODE_DECR, 2,
378 BCODE_COLLAPSE,
379 BCODE_LIST,
380 BCODE_VALIDATE,
381 BCODE_FREE,
382 BCODE_END
383};
384
385int main(int argc, char **argv)
386{
387 int i = 0;
388 ext2_refcount_t refcount;
389 int size, arg;
390 blk_t blk;
391 errcode_t retval;
392
393 while (1) {
394 switch (bcode_program[i++]) {
395 case BCODE_END:
396 exit(0);
397 case BCODE_CREATE:
398 size = bcode_program[i++];
399 retval = ea_refcount_create(size, &refcount);
400 if (retval) {
401 com_err("ea_refcount_create",
402 retval, "");
403 exit(1);
404 } else
405 printf("Creating refcount with size %d\n",
406 size);
407 break;
408 case BCODE_FREE:
409 ea_refcount_free(refcount);
410 refcount = 0;
411 printf("Freeing refcount\n");
412 break;
413 case BCODE_STORE:
414 blk = (blk_t) bcode_program[i++];
415 arg = bcode_program[i++];
416 retval = ea_refcount_store(refcount, blk, arg);
417 printf("Storing blk %u with value %d\n", blk, arg);
418 if (retval)
419 com_err("ea_refcount_store", retval, "");
420 break;
421 case BCODE_FETCH:
422 blk = (blk_t) bcode_program[i++];
423 retval = ea_refcount_fetch(refcount, blk, &arg);
424 if (retval)
425 com_err("ea_refcount_fetch", retval, "");
426 else
427 printf("bcode_fetch(%u) returns %d\n",
428 blk, arg);
429 break;
430 case BCODE_INCR:
431 blk = (blk_t) bcode_program[i++];
432 retval = ea_refcount_increment(refcount, blk,
433 &arg);
434 if (retval)
435 com_err("ea_refcount_increment", retval,
436 "");
437 else
438 printf("bcode_increment(%u) returns %d\n",
439 blk, arg);
440 break;
441 case BCODE_DECR:
442 blk = (blk_t) bcode_program[i++];
443 retval = ea_refcount_decrement(refcount, blk,
444 &arg);
445 if (retval)
446 com_err("ea_refcount_decrement", retval,
447 "while decrementing blk %u", blk);
448 else
449 printf("bcode_decrement(%u) returns %d\n",
450 blk, arg);
451 break;
452 case BCODE_VALIDATE:
453 retval = ea_refcount_validate(refcount, stderr);
454 if (retval)
455 com_err("ea_refcount_validate",
456 retval, "");
457 else
458 printf("Refcount validation OK.\n");
459 break;
460 case BCODE_LIST:
461 ea_refcount_intr_begin(refcount);
462 while (1) {
463 blk = ea_refcount_intr_next(refcount,
464 &arg);
465 if (!blk)
466 break;
467 printf("\tblk=%u, count=%d\n", blk,
468 arg);
469 }
470 break;
471 case BCODE_COLLAPSE:
472 refcount_collapse(refcount);
473 break;
474 }
475
476 }
477}
478
479#endif
diff --git a/e2fsprogs/e2fsck/ehandler.c b/e2fsprogs/e2fsck/ehandler.c
deleted file mode 100644
index 16d6d4fa0..000000000
--- a/e2fsprogs/e2fsck/ehandler.c
+++ /dev/null
@@ -1,124 +0,0 @@
1/*
2 * ehandler.c --- handle bad block errors which come up during the
3 * course of an e2fsck session.
4 *
5 * Copyright (C) 1994 Theodore Ts'o. This file may be redistributed
6 * under the terms of the GNU Public License.
7 */
8
9#include <stdlib.h>
10#include <unistd.h>
11#include <string.h>
12#include <ctype.h>
13#include <termios.h>
14
15#include "e2fsck.h"
16
17#include <sys/time.h>
18#include <sys/resource.h>
19
20static const char *operation;
21
22static errcode_t e2fsck_handle_read_error(io_channel channel,
23 unsigned long block,
24 int count,
25 void *data,
26 size_t size EXT2FS_ATTR((unused)),
27 int actual EXT2FS_ATTR((unused)),
28 errcode_t error)
29{
30 int i;
31 char *p;
32 ext2_filsys fs = (ext2_filsys) channel->app_data;
33 e2fsck_t ctx;
34
35 ctx = (e2fsck_t) fs->priv_data;
36
37 /*
38 * If more than one block was read, try reading each block
39 * separately. We could use the actual bytes read to figure
40 * out where to start, but we don't bother.
41 */
42 if (count > 1) {
43 p = (char *) data;
44 for (i=0; i < count; i++, p += channel->block_size, block++) {
45 error = io_channel_read_blk(channel, block,
46 1, p);
47 if (error)
48 return error;
49 }
50 return 0;
51 }
52 if (operation)
53 printf(_("Error reading block %lu (%s) while %s. "), block,
54 error_message(error), operation);
55 else
56 printf(_("Error reading block %lu (%s). "), block,
57 error_message(error));
58 preenhalt(ctx);
59 if (ask(ctx, _("Ignore error"), 1)) {
60 if (ask(ctx, _("Force rewrite"), 1))
61 io_channel_write_blk(channel, block, 1, data);
62 return 0;
63 }
64
65 return error;
66}
67
68static errcode_t e2fsck_handle_write_error(io_channel channel,
69 unsigned long block,
70 int count,
71 const void *data,
72 size_t size EXT2FS_ATTR((unused)),
73 int actual EXT2FS_ATTR((unused)),
74 errcode_t error)
75{
76 int i;
77 const char *p;
78 ext2_filsys fs = (ext2_filsys) channel->app_data;
79 e2fsck_t ctx;
80
81 ctx = (e2fsck_t) fs->priv_data;
82
83 /*
84 * If more than one block was written, try writing each block
85 * separately. We could use the actual bytes read to figure
86 * out where to start, but we don't bother.
87 */
88 if (count > 1) {
89 p = (const char *) data;
90 for (i=0; i < count; i++, p += channel->block_size, block++) {
91 error = io_channel_write_blk(channel, block,
92 1, p);
93 if (error)
94 return error;
95 }
96 return 0;
97 }
98
99 if (operation)
100 printf(_("Error writing block %lu (%s) while %s. "), block,
101 error_message(error), operation);
102 else
103 printf(_("Error writing block %lu (%s). "), block,
104 error_message(error));
105 preenhalt(ctx);
106 if (ask(ctx, _("Ignore error"), 1))
107 return 0;
108
109 return error;
110}
111
112const char *ehandler_operation(const char *op)
113{
114 const char *ret = operation;
115
116 operation = op;
117 return ret;
118}
119
120void ehandler_init(io_channel channel)
121{
122 channel->read_error = e2fsck_handle_read_error;
123 channel->write_error = e2fsck_handle_write_error;
124}
diff --git a/e2fsprogs/e2fsck/jfs_user.h b/e2fsprogs/e2fsck/jfs_user.h
deleted file mode 100644
index c38def3e5..000000000
--- a/e2fsprogs/e2fsck/jfs_user.h
+++ /dev/null
@@ -1,120 +0,0 @@
1/*
2 * Compatibility header file for e2fsck which should be included
3 * instead of linux/jfs.h
4 *
5 * Copyright (C) 2000 Stephen C. Tweedie
6 *
7 * This file may be redistributed under the terms of the
8 * GNU General Public License version 2 or at your discretion
9 * any later version.
10 */
11
12/*
13 * Pull in the definition of the e2fsck context structure
14 */
15#include "e2fsck.h"
16
17struct buffer_head {
18 char b_data[8192];
19 e2fsck_t b_ctx;
20 io_channel b_io;
21 int b_size;
22 blk_t b_blocknr;
23 int b_dirty;
24 int b_uptodate;
25 int b_err;
26};
27
28struct inode {
29 e2fsck_t i_ctx;
30 ext2_ino_t i_ino;
31 struct ext2_inode i_ext2;
32};
33
34struct kdev_s {
35 e2fsck_t k_ctx;
36 int k_dev;
37};
38
39#define K_DEV_FS 1
40#define K_DEV_JOURNAL 2
41
42typedef struct kdev_s *kdev_t;
43
44#define lock_buffer(bh) do {} while(0)
45#define unlock_buffer(bh) do {} while(0)
46#define buffer_req(bh) 1
47#define do_readahead(journal, start) do {} while(0)
48
49extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
50
51typedef struct {
52 int object_length;
53} kmem_cache_t;
54
55#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length)
56#define kmem_cache_free(cache,obj) free(obj)
57#define kmem_cache_create(name,len,a,b,c,d) do_cache_create(len)
58#define kmem_cache_destroy(cache) do_cache_destroy(cache)
59#define kmalloc(len,flags) malloc(len)
60#define kfree(p) free(p)
61
62/*
63 * We use the standard libext2fs portability tricks for inline
64 * functions.
65 */
66extern kmem_cache_t * do_cache_create(int len);
67extern void do_cache_destroy(kmem_cache_t *cache);
68
69#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
70#ifdef E2FSCK_INCLUDE_INLINE_FUNCS
71#define _INLINE_ extern
72#else
73#ifdef __GNUC__
74#define _INLINE_ extern __inline__
75#else /* For Watcom C */
76#define _INLINE_ extern inline
77#endif
78#endif
79
80_INLINE_ kmem_cache_t * do_cache_create(int len)
81{
82 kmem_cache_t *new_cache;
83 new_cache = malloc(sizeof(*new_cache));
84 if (new_cache)
85 new_cache->object_length = len;
86 return new_cache;
87}
88
89_INLINE_ void do_cache_destroy(kmem_cache_t *cache)
90{
91 free(cache);
92}
93#undef _INLINE_
94#endif
95
96#define __init
97
98/*
99 * Now pull in the real linux/jfs.h definitions.
100 */
101#include <ext2fs/kernel-jbd.h>
102
103/*
104 * Kernel compatibility functions are defined in journal.c
105 */
106int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys);
107struct buffer_head *getblk(kdev_t ctx, blk_t blocknr, int blocksize);
108void sync_blockdev(kdev_t kdev);
109void ll_rw_block(int rw, int dummy, struct buffer_head *bh[]);
110void mark_buffer_dirty(struct buffer_head *bh);
111void mark_buffer_uptodate(struct buffer_head *bh, int val);
112void brelse(struct buffer_head *bh);
113int buffer_uptodate(struct buffer_head *bh);
114void wait_on_buffer(struct buffer_head *bh);
115
116/*
117 * Define newer 2.5 interfaces
118 */
119#define __getblk(dev, blocknr, blocksize) getblk(dev, blocknr, blocksize)
120#define set_buffer_uptodate(bh) mark_buffer_uptodate(bh, 1)
diff --git a/e2fsprogs/e2fsck/journal.c b/e2fsprogs/e2fsck/journal.c
deleted file mode 100644
index 14e774d50..000000000
--- a/e2fsprogs/e2fsck/journal.c
+++ /dev/null
@@ -1,960 +0,0 @@
1/*
2 * journal.c --- code for handling the "ext3" journal
3 *
4 * Copyright (C) 2000 Andreas Dilger
5 * Copyright (C) 2000 Theodore Ts'o
6 *
7 * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
8 * Copyright (C) 1999 Red Hat Software
9 *
10 * This file may be redistributed under the terms of the
11 * GNU General Public License version 2 or at your discretion
12 * any later version.
13 */
14
15#ifdef HAVE_SYS_MOUNT_H
16#include <sys/param.h>
17#include <sys/mount.h>
18#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
19#endif
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23
24#define E2FSCK_INCLUDE_INLINE_FUNCS
25#include "jfs_user.h"
26#include "problem.h"
27#include "uuid/uuid.h"
28
29#ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */
30static int bh_count = 0;
31#endif
32
33/*
34 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
35 * This creates a larger static binary, and a smaller binary using
36 * shared libraries. It's also probably slightly less CPU-efficient,
37 * which is why it's not on by default. But, it's a good way of
38 * testing the functions in inode_io.c and fileio.c.
39 */
40#undef USE_INODE_IO
41
42/* Kernel compatibility functions for handling the journal. These allow us
43 * to use the recovery.c file virtually unchanged from the kernel, so we
44 * don't have to do much to keep kernel and user recovery in sync.
45 */
46int journal_bmap(journal_t *journal, blk_t block, unsigned long *phys)
47{
48#ifdef USE_INODE_IO
49 *phys = block;
50 return 0;
51#else
52 struct inode *inode = journal->j_inode;
53 errcode_t retval;
54 blk_t pblk;
55
56 if (!inode) {
57 *phys = block;
58 return 0;
59 }
60
61 retval= ext2fs_bmap(inode->i_ctx->fs, inode->i_ino,
62 &inode->i_ext2, NULL, 0, block, &pblk);
63 *phys = pblk;
64 return (retval);
65#endif
66}
67
68struct buffer_head *getblk(kdev_t kdev, blk_t blocknr, int blocksize)
69{
70 struct buffer_head *bh;
71
72 bh = e2fsck_allocate_memory(kdev->k_ctx, sizeof(*bh), "block buffer");
73 if (!bh)
74 return NULL;
75
76 jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
77 (unsigned long) blocknr, blocksize, ++bh_count);
78
79 bh->b_ctx = kdev->k_ctx;
80 if (kdev->k_dev == K_DEV_FS)
81 bh->b_io = kdev->k_ctx->fs->io;
82 else
83 bh->b_io = kdev->k_ctx->journal_io;
84 bh->b_size = blocksize;
85 bh->b_blocknr = blocknr;
86
87 return bh;
88}
89
90void sync_blockdev(kdev_t kdev)
91{
92 io_channel io;
93
94 if (kdev->k_dev == K_DEV_FS)
95 io = kdev->k_ctx->fs->io;
96 else
97 io = kdev->k_ctx->journal_io;
98
99 io_channel_flush(io);
100}
101
102void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
103{
104 int retval;
105 struct buffer_head *bh;
106
107 for (; nr > 0; --nr) {
108 bh = *bhp++;
109 if (rw == READ && !bh->b_uptodate) {
110 jfs_debug(3, "reading block %lu/%p\n",
111 (unsigned long) bh->b_blocknr, (void *) bh);
112 retval = io_channel_read_blk(bh->b_io,
113 bh->b_blocknr,
114 1, bh->b_data);
115 if (retval) {
116 com_err(bh->b_ctx->device_name, retval,
117 "while reading block %lu\n",
118 (unsigned long) bh->b_blocknr);
119 bh->b_err = retval;
120 continue;
121 }
122 bh->b_uptodate = 1;
123 } else if (rw == WRITE && bh->b_dirty) {
124 jfs_debug(3, "writing block %lu/%p\n",
125 (unsigned long) bh->b_blocknr, (void *) bh);
126 retval = io_channel_write_blk(bh->b_io,
127 bh->b_blocknr,
128 1, bh->b_data);
129 if (retval) {
130 com_err(bh->b_ctx->device_name, retval,
131 "while writing block %lu\n",
132 (unsigned long) bh->b_blocknr);
133 bh->b_err = retval;
134 continue;
135 }
136 bh->b_dirty = 0;
137 bh->b_uptodate = 1;
138 } else {
139 jfs_debug(3, "no-op %s for block %lu\n",
140 rw == READ ? "read" : "write",
141 (unsigned long) bh->b_blocknr);
142 }
143 }
144}
145
146void mark_buffer_dirty(struct buffer_head *bh)
147{
148 bh->b_dirty = 1;
149}
150
151static void mark_buffer_clean(struct buffer_head * bh)
152{
153 bh->b_dirty = 0;
154}
155
156void brelse(struct buffer_head *bh)
157{
158 if (bh->b_dirty)
159 ll_rw_block(WRITE, 1, &bh);
160 jfs_debug(3, "freeing block %lu/%p (total %d)\n",
161 (unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
162 ext2fs_free_mem(&bh);
163}
164
165int buffer_uptodate(struct buffer_head *bh)
166{
167 return bh->b_uptodate;
168}
169
170void mark_buffer_uptodate(struct buffer_head *bh, int val)
171{
172 bh->b_uptodate = val;
173}
174
175void wait_on_buffer(struct buffer_head *bh)
176{
177 if (!bh->b_uptodate)
178 ll_rw_block(READ, 1, &bh);
179}
180
181
182static void e2fsck_clear_recover(e2fsck_t ctx, int error)
183{
184 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
185
186 /* if we had an error doing journal recovery, we need a full fsck */
187 if (error)
188 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
189 ext2fs_mark_super_dirty(ctx->fs);
190}
191
192static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
193{
194 struct ext2_super_block *sb = ctx->fs->super;
195 struct ext2_super_block jsuper;
196 struct problem_context pctx;
197 struct buffer_head *bh;
198 struct inode *j_inode = NULL;
199 struct kdev_s *dev_fs = NULL, *dev_journal;
200 const char *journal_name = 0;
201 journal_t *journal = NULL;
202 errcode_t retval = 0;
203 io_manager io_ptr = 0;
204 unsigned long start = 0;
205 blk_t blk;
206 int ext_journal = 0;
207 int tried_backup_jnl = 0;
208 int i;
209
210 clear_problem_context(&pctx);
211
212 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
213 if (!journal) {
214 return EXT2_ET_NO_MEMORY;
215 }
216
217 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
218 if (!dev_fs) {
219 retval = EXT2_ET_NO_MEMORY;
220 goto errout;
221 }
222 dev_journal = dev_fs+1;
223
224 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
225 dev_fs->k_dev = K_DEV_FS;
226 dev_journal->k_dev = K_DEV_JOURNAL;
227
228 journal->j_dev = dev_journal;
229 journal->j_fs_dev = dev_fs;
230 journal->j_inode = NULL;
231 journal->j_blocksize = ctx->fs->blocksize;
232
233 if (uuid_is_null(sb->s_journal_uuid)) {
234 if (!sb->s_journal_inum)
235 return EXT2_ET_BAD_INODE_NUM;
236 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
237 "journal inode");
238 if (!j_inode) {
239 retval = EXT2_ET_NO_MEMORY;
240 goto errout;
241 }
242
243 j_inode->i_ctx = ctx;
244 j_inode->i_ino = sb->s_journal_inum;
245
246 if ((retval = ext2fs_read_inode(ctx->fs,
247 sb->s_journal_inum,
248 &j_inode->i_ext2))) {
249 try_backup_journal:
250 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
251 tried_backup_jnl)
252 goto errout;
253 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
254 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
255 EXT2_N_BLOCKS*4);
256 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
257 j_inode->i_ext2.i_links_count = 1;
258 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
259 tried_backup_jnl++;
260 }
261 if (!j_inode->i_ext2.i_links_count ||
262 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
263 retval = EXT2_ET_NO_JOURNAL;
264 goto try_backup_journal;
265 }
266 if (j_inode->i_ext2.i_size / journal->j_blocksize <
267 JFS_MIN_JOURNAL_BLOCKS) {
268 retval = EXT2_ET_JOURNAL_TOO_SMALL;
269 goto try_backup_journal;
270 }
271 for (i=0; i < EXT2_N_BLOCKS; i++) {
272 blk = j_inode->i_ext2.i_block[i];
273 if (!blk) {
274 if (i < EXT2_NDIR_BLOCKS) {
275 retval = EXT2_ET_JOURNAL_TOO_SMALL;
276 goto try_backup_journal;
277 }
278 continue;
279 }
280 if (blk < sb->s_first_data_block ||
281 blk >= sb->s_blocks_count) {
282 retval = EXT2_ET_BAD_BLOCK_NUM;
283 goto try_backup_journal;
284 }
285 }
286 journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;
287
288#ifdef USE_INODE_IO
289 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
290 &j_inode->i_ext2,
291 &journal_name);
292 if (retval)
293 goto errout;
294
295 io_ptr = inode_io_manager;
296#else
297 journal->j_inode = j_inode;
298 ctx->journal_io = ctx->fs->io;
299 if ((retval = journal_bmap(journal, 0, &start)) != 0)
300 goto errout;
301#endif
302 } else {
303 ext_journal = 1;
304 if (!ctx->journal_name) {
305 char uuid[37];
306
307 uuid_unparse(sb->s_journal_uuid, uuid);
308 ctx->journal_name = blkid_get_devname(ctx->blkid,
309 "UUID", uuid);
310 if (!ctx->journal_name)
311 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
312 }
313 journal_name = ctx->journal_name;
314
315 if (!journal_name) {
316 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
317 return EXT2_ET_LOAD_EXT_JOURNAL;
318 }
319
320 jfs_debug(1, "Using journal file %s\n", journal_name);
321 io_ptr = unix_io_manager;
322 }
323
324#if 0
325 test_io_backing_manager = io_ptr;
326 io_ptr = test_io_manager;
327#endif
328#ifndef USE_INODE_IO
329 if (ext_journal)
330#endif
331 retval = io_ptr->open(journal_name, IO_FLAG_RW,
332 &ctx->journal_io);
333 if (retval)
334 goto errout;
335
336 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
337
338 if (ext_journal) {
339 if (ctx->fs->blocksize == 1024)
340 start = 1;
341 bh = getblk(dev_journal, start, ctx->fs->blocksize);
342 if (!bh) {
343 retval = EXT2_ET_NO_MEMORY;
344 goto errout;
345 }
346 ll_rw_block(READ, 1, &bh);
347 if ((retval = bh->b_err) != 0)
348 goto errout;
349 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
350 sizeof(jsuper));
351 brelse(bh);
352#ifdef EXT2FS_ENABLE_SWAPFS
353 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
354 ext2fs_swap_super(&jsuper);
355#endif
356 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
357 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
358 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
359 retval = EXT2_ET_LOAD_EXT_JOURNAL;
360 goto errout;
361 }
362 /* Make sure the journal UUID is correct */
363 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
364 sizeof(jsuper.s_uuid))) {
365 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
366 retval = EXT2_ET_LOAD_EXT_JOURNAL;
367 goto errout;
368 }
369
370 journal->j_maxlen = jsuper.s_blocks_count;
371 start++;
372 }
373
374 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
375 retval = EXT2_ET_NO_MEMORY;
376 goto errout;
377 }
378
379 journal->j_sb_buffer = bh;
380 journal->j_superblock = (journal_superblock_t *)bh->b_data;
381
382#ifdef USE_INODE_IO
383 if (j_inode)
384 ext2fs_free_mem(&j_inode);
385#endif
386
387 *ret_journal = journal;
388 return 0;
389
390errout:
391 if (dev_fs)
392 ext2fs_free_mem(&dev_fs);
393 if (j_inode)
394 ext2fs_free_mem(&j_inode);
395 if (journal)
396 ext2fs_free_mem(&journal);
397 return retval;
398
399}
400
401static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
402 struct problem_context *pctx)
403{
404 struct ext2_super_block *sb = ctx->fs->super;
405 int recover = ctx->fs->super->s_feature_incompat &
406 EXT3_FEATURE_INCOMPAT_RECOVER;
407 int has_journal = ctx->fs->super->s_feature_compat &
408 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
409
410 if (has_journal || sb->s_journal_inum) {
411 /* The journal inode is bogus, remove and force full fsck */
412 pctx->ino = sb->s_journal_inum;
413 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
414 if (has_journal && sb->s_journal_inum)
415 printf("*** ext3 journal has been deleted - "
416 "filesystem is now ext2 only ***\n\n");
417 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
418 sb->s_journal_inum = 0;
419 ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */
420 e2fsck_clear_recover(ctx, 1);
421 return 0;
422 }
423 return EXT2_ET_BAD_INODE_NUM;
424 } else if (recover) {
425 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
426 e2fsck_clear_recover(ctx, 1);
427 return 0;
428 }
429 return EXT2_ET_UNSUPP_FEATURE;
430 }
431 return 0;
432}
433
434#define V1_SB_SIZE 0x0024
435static void clear_v2_journal_fields(journal_t *journal)
436{
437 e2fsck_t ctx = journal->j_dev->k_ctx;
438 struct problem_context pctx;
439
440 clear_problem_context(&pctx);
441
442 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
443 return;
444
445 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
446 ctx->fs->blocksize-V1_SB_SIZE);
447 mark_buffer_dirty(journal->j_sb_buffer);
448}
449
450
451static errcode_t e2fsck_journal_load(journal_t *journal)
452{
453 e2fsck_t ctx = journal->j_dev->k_ctx;
454 journal_superblock_t *jsb;
455 struct buffer_head *jbh = journal->j_sb_buffer;
456 struct problem_context pctx;
457
458 clear_problem_context(&pctx);
459
460 ll_rw_block(READ, 1, &jbh);
461 if (jbh->b_err) {
462 com_err(ctx->device_name, jbh->b_err,
463 _("reading journal superblock\n"));
464 return jbh->b_err;
465 }
466
467 jsb = journal->j_superblock;
468 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
469 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
470 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
471
472 switch (ntohl(jsb->s_header.h_blocktype)) {
473 case JFS_SUPERBLOCK_V1:
474 journal->j_format_version = 1;
475 if (jsb->s_feature_compat ||
476 jsb->s_feature_incompat ||
477 jsb->s_feature_ro_compat ||
478 jsb->s_nr_users)
479 clear_v2_journal_fields(journal);
480 break;
481
482 case JFS_SUPERBLOCK_V2:
483 journal->j_format_version = 2;
484 if (ntohl(jsb->s_nr_users) > 1 &&
485 uuid_is_null(ctx->fs->super->s_journal_uuid))
486 clear_v2_journal_fields(journal);
487 if (ntohl(jsb->s_nr_users) > 1) {
488 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
489 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
490 }
491 break;
492
493 /*
494 * These should never appear in a journal super block, so if
495 * they do, the journal is badly corrupted.
496 */
497 case JFS_DESCRIPTOR_BLOCK:
498 case JFS_COMMIT_BLOCK:
499 case JFS_REVOKE_BLOCK:
500 return EXT2_ET_CORRUPT_SUPERBLOCK;
501
502 /* If we don't understand the superblock major type, but there
503 * is a magic number, then it is likely to be a new format we
504 * just don't understand, so leave it alone. */
505 default:
506 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
507 }
508
509 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
510 return EXT2_ET_UNSUPP_FEATURE;
511
512 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
513 return EXT2_ET_RO_UNSUPP_FEATURE;
514
515 /* We have now checked whether we know enough about the journal
516 * format to be able to proceed safely, so any other checks that
517 * fail we should attempt to recover from. */
518 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
519 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
520 _("%s: no valid journal superblock found\n"),
521 ctx->device_name);
522 return EXT2_ET_CORRUPT_SUPERBLOCK;
523 }
524
525 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
526 journal->j_maxlen = ntohl(jsb->s_maxlen);
527 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
528 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
529 _("%s: journal too short\n"),
530 ctx->device_name);
531 return EXT2_ET_CORRUPT_SUPERBLOCK;
532 }
533
534 journal->j_tail_sequence = ntohl(jsb->s_sequence);
535 journal->j_transaction_sequence = journal->j_tail_sequence;
536 journal->j_tail = ntohl(jsb->s_start);
537 journal->j_first = ntohl(jsb->s_first);
538 journal->j_last = ntohl(jsb->s_maxlen);
539
540 return 0;
541}
542
543static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
544 journal_t *journal)
545{
546 char *p;
547 union {
548 uuid_t uuid;
549 __u32 val[4];
550 } u;
551 __u32 new_seq = 0;
552 int i;
553
554 /* Leave a valid existing V1 superblock signature alone.
555 * Anything unrecognisable we overwrite with a new V2
556 * signature. */
557
558 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
559 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
560 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
561 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
562 }
563
564 /* Zero out everything else beyond the superblock header */
565
566 p = ((char *) jsb) + sizeof(journal_header_t);
567 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
568
569 jsb->s_blocksize = htonl(ctx->fs->blocksize);
570 jsb->s_maxlen = htonl(journal->j_maxlen);
571 jsb->s_first = htonl(1);
572
573 /* Initialize the journal sequence number so that there is "no"
574 * chance we will find old "valid" transactions in the journal.
575 * This avoids the need to zero the whole journal (slow to do,
576 * and risky when we are just recovering the filesystem).
577 */
578 uuid_generate(u.uuid);
579 for (i = 0; i < 4; i ++)
580 new_seq ^= u.val[i];
581 jsb->s_sequence = htonl(new_seq);
582
583 mark_buffer_dirty(journal->j_sb_buffer);
584 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
585}
586
587static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
588 journal_t *journal,
589 struct problem_context *pctx)
590{
591 struct ext2_super_block *sb = ctx->fs->super;
592 int recover = ctx->fs->super->s_feature_incompat &
593 EXT3_FEATURE_INCOMPAT_RECOVER;
594
595 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
596 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
597 e2fsck_journal_reset_super(ctx, journal->j_superblock,
598 journal);
599 journal->j_transaction_sequence = 1;
600 e2fsck_clear_recover(ctx, recover);
601 return 0;
602 }
603 return EXT2_ET_CORRUPT_SUPERBLOCK;
604 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
605 return EXT2_ET_CORRUPT_SUPERBLOCK;
606
607 return 0;
608}
609
610static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
611 int reset, int drop)
612{
613 journal_superblock_t *jsb;
614
615 if (drop)
616 mark_buffer_clean(journal->j_sb_buffer);
617 else if (!(ctx->options & E2F_OPT_READONLY)) {
618 jsb = journal->j_superblock;
619 jsb->s_sequence = htonl(journal->j_transaction_sequence);
620 if (reset)
621 jsb->s_start = 0; /* this marks the journal as empty */
622 mark_buffer_dirty(journal->j_sb_buffer);
623 }
624 brelse(journal->j_sb_buffer);
625
626 if (ctx->journal_io) {
627 if (ctx->fs && ctx->fs->io != ctx->journal_io)
628 io_channel_close(ctx->journal_io);
629 ctx->journal_io = 0;
630 }
631
632#ifndef USE_INODE_IO
633 if (journal->j_inode)
634 ext2fs_free_mem(&journal->j_inode);
635#endif
636 if (journal->j_fs_dev)
637 ext2fs_free_mem(&journal->j_fs_dev);
638 ext2fs_free_mem(&journal);
639}
640
641/*
642 * This function makes sure that the superblock fields regarding the
643 * journal are consistent.
644 */
645int e2fsck_check_ext3_journal(e2fsck_t ctx)
646{
647 struct ext2_super_block *sb = ctx->fs->super;
648 journal_t *journal;
649 int recover = ctx->fs->super->s_feature_incompat &
650 EXT3_FEATURE_INCOMPAT_RECOVER;
651 struct problem_context pctx;
652 problem_t problem;
653 int reset = 0, force_fsck = 0;
654 int retval;
655
656 /* If we don't have any journal features, don't do anything more */
657 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
658 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
659 uuid_is_null(sb->s_journal_uuid))
660 return 0;
661
662 clear_problem_context(&pctx);
663 pctx.num = sb->s_journal_inum;
664
665 retval = e2fsck_get_journal(ctx, &journal);
666 if (retval) {
667 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
668 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
669 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
670 (retval == EXT2_ET_NO_JOURNAL))
671 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
672 return retval;
673 }
674
675 retval = e2fsck_journal_load(journal);
676 if (retval) {
677 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
678 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
679 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
680 &pctx))) ||
681 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
682 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
683 &pctx))) ||
684 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
685 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
686 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
687 &pctx);
688 e2fsck_journal_release(ctx, journal, 0, 1);
689 return retval;
690 }
691
692 /*
693 * We want to make the flags consistent here. We will not leave with
694 * needs_recovery set but has_journal clear. We can't get in a loop
695 * with -y, -n, or -p, only if a user isn't making up their mind.
696 */
697no_has_journal:
698 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
699 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
700 pctx.str = "inode";
701 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
702 if (recover &&
703 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
704 goto no_has_journal;
705 /*
706 * Need a full fsck if we are releasing a
707 * journal stored on a reserved inode.
708 */
709 force_fsck = recover ||
710 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
711 /* Clear all of the journal fields */
712 sb->s_journal_inum = 0;
713 sb->s_journal_dev = 0;
714 memset(sb->s_journal_uuid, 0,
715 sizeof(sb->s_journal_uuid));
716 e2fsck_clear_recover(ctx, force_fsck);
717 } else if (!(ctx->options & E2F_OPT_READONLY)) {
718 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
719 ext2fs_mark_super_dirty(ctx->fs);
720 }
721 }
722
723 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
724 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
725 journal->j_superblock->s_start != 0) {
726 /* Print status information */
727 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
728 if (ctx->superblock)
729 problem = PR_0_JOURNAL_RUN_DEFAULT;
730 else
731 problem = PR_0_JOURNAL_RUN;
732 if (fix_problem(ctx, problem, &pctx)) {
733 ctx->options |= E2F_OPT_FORCE;
734 sb->s_feature_incompat |=
735 EXT3_FEATURE_INCOMPAT_RECOVER;
736 ext2fs_mark_super_dirty(ctx->fs);
737 } else if (fix_problem(ctx,
738 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
739 reset = 1;
740 sb->s_state &= ~EXT2_VALID_FS;
741 ext2fs_mark_super_dirty(ctx->fs);
742 }
743 /*
744 * If the user answers no to the above question, we
745 * ignore the fact that journal apparently has data;
746 * accidentally replaying over valid data would be far
747 * worse than skipping a questionable recovery.
748 *
749 * XXX should we abort with a fatal error here? What
750 * will the ext3 kernel code do if a filesystem with
751 * !NEEDS_RECOVERY but with a non-zero
752 * journal->j_superblock->s_start is mounted?
753 */
754 }
755
756 e2fsck_journal_release(ctx, journal, reset, 0);
757 return retval;
758}
759
760static errcode_t recover_ext3_journal(e2fsck_t ctx)
761{
762 journal_t *journal;
763 int retval;
764
765 journal_init_revoke_caches();
766 retval = e2fsck_get_journal(ctx, &journal);
767 if (retval)
768 return retval;
769
770 retval = e2fsck_journal_load(journal);
771 if (retval)
772 goto errout;
773
774 retval = journal_init_revoke(journal, 1024);
775 if (retval)
776 goto errout;
777
778 retval = -journal_recover(journal);
779 if (retval)
780 goto errout;
781
782 if (journal->j_superblock->s_errno) {
783 ctx->fs->super->s_state |= EXT2_ERROR_FS;
784 ext2fs_mark_super_dirty(ctx->fs);
785 journal->j_superblock->s_errno = 0;
786 mark_buffer_dirty(journal->j_sb_buffer);
787 }
788
789errout:
790 journal_destroy_revoke(journal);
791 journal_destroy_revoke_caches();
792 e2fsck_journal_release(ctx, journal, 1, 0);
793 return retval;
794}
795
796int e2fsck_run_ext3_journal(e2fsck_t ctx)
797{
798 io_manager io_ptr = ctx->fs->io->manager;
799 int blocksize = ctx->fs->blocksize;
800 errcode_t retval, recover_retval;
801
802 printf(_("%s: recovering journal\n"), ctx->device_name);
803 if (ctx->options & E2F_OPT_READONLY) {
804 printf(_("%s: won't do journal recovery while read-only\n"),
805 ctx->device_name);
806 return EXT2_ET_FILE_RO;
807 }
808
809 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
810 ext2fs_flush(ctx->fs); /* Force out any modifications */
811
812 recover_retval = recover_ext3_journal(ctx);
813
814 /*
815 * Reload the filesystem context to get up-to-date data from disk
816 * because journal recovery will change the filesystem under us.
817 */
818 ext2fs_close(ctx->fs);
819 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
820 ctx->superblock, blocksize, io_ptr,
821 &ctx->fs);
822
823 if (retval) {
824 com_err(ctx->program_name, retval,
825 _("while trying to re-open %s"),
826 ctx->device_name);
827 fatal_error(ctx, 0);
828 }
829 ctx->fs->priv_data = ctx;
830
831 /* Set the superblock flags */
832 e2fsck_clear_recover(ctx, recover_retval);
833 return recover_retval;
834}
835
836/*
837 * This function will move the journal inode from a visible file in
838 * the filesystem directory hierarchy to the reserved inode if necessary.
839 */
840static const char * const journal_names[] = {
841 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
842
843void e2fsck_move_ext3_journal(e2fsck_t ctx)
844{
845 struct ext2_super_block *sb = ctx->fs->super;
846 struct problem_context pctx;
847 struct ext2_inode inode;
848 ext2_filsys fs = ctx->fs;
849 ext2_ino_t ino;
850 errcode_t retval;
851 const char * const * cpp;
852 int group, mount_flags;
853
854 clear_problem_context(&pctx);
855
856 /*
857 * If the filesystem is opened read-only, or there is no
858 * journal, then do nothing.
859 */
860 if ((ctx->options & E2F_OPT_READONLY) ||
861 (sb->s_journal_inum == 0) ||
862 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
863 return;
864
865 /*
866 * Read in the journal inode
867 */
868 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
869 return;
870
871 /*
872 * If it's necessary to backup the journal inode, do so.
873 */
874 if ((sb->s_jnl_backup_type == 0) ||
875 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
876 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
877 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
878 memcpy(sb->s_jnl_blocks, inode.i_block,
879 EXT2_N_BLOCKS*4);
880 sb->s_jnl_blocks[16] = inode.i_size;
881 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
882 ext2fs_mark_super_dirty(fs);
883 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
884 }
885 }
886
887 /*
888 * If the journal is already the hidden inode, then do nothing
889 */
890 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
891 return;
892
893 /*
894 * The journal inode had better have only one link and not be readable.
895 */
896 if (inode.i_links_count != 1)
897 return;
898
899 /*
900 * If the filesystem is mounted, or we can't tell whether
901 * or not it's mounted, do nothing.
902 */
903 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
904 if (retval || (mount_flags & EXT2_MF_MOUNTED))
905 return;
906
907 /*
908 * If we can't find the name of the journal inode, then do
909 * nothing.
910 */
911 for (cpp = journal_names; *cpp; cpp++) {
912 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
913 strlen(*cpp), 0, &ino);
914 if ((retval == 0) && (ino == sb->s_journal_inum))
915 break;
916 }
917 if (*cpp == 0)
918 return;
919
920 /* We need the inode bitmap to be loaded */
921 retval = ext2fs_read_bitmaps(fs);
922 if (retval)
923 return;
924
925 pctx.str = *cpp;
926 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
927 return;
928
929 /*
930 * OK, we've done all the checks, let's actually move the
931 * journal inode. Errors at this point mean we need to force
932 * an ext2 filesystem check.
933 */
934 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
935 goto err_out;
936 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
937 goto err_out;
938 sb->s_journal_inum = EXT2_JOURNAL_INO;
939 ext2fs_mark_super_dirty(fs);
940 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
941 inode.i_links_count = 0;
942 inode.i_dtime = time(0);
943 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
944 goto err_out;
945
946 group = ext2fs_group_of_ino(fs, ino);
947 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
948 ext2fs_mark_ib_dirty(fs);
949 fs->group_desc[group].bg_free_inodes_count++;
950 fs->super->s_free_inodes_count++;
951 return;
952
953err_out:
954 pctx.errcode = retval;
955 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
956 fs->super->s_state &= ~EXT2_VALID_FS;
957 ext2fs_mark_super_dirty(fs);
958 return;
959}
960
diff --git a/e2fsprogs/e2fsck/message.c b/e2fsprogs/e2fsck/message.c
deleted file mode 100644
index b09ae8976..000000000
--- a/e2fsprogs/e2fsck/message.c
+++ /dev/null
@@ -1,466 +0,0 @@
1/*
2 * message.c --- print e2fsck messages (with compression)
3 *
4 * Copyright 1996, 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * print_e2fsck_message() prints a message to the user, using
12 * compression techniques and expansions of abbreviations.
13 *
14 * The following % expansions are supported:
15 *
16 * %b <blk> block number
17 * %B <blkcount> integer
18 * %c <blk2> block number
19 * %Di <dirent>->ino inode number
20 * %Dn <dirent>->name string
21 * %Dr <dirent>->rec_len
22 * %Dl <dirent>->name_len
23 * %Dt <dirent>->filetype
24 * %d <dir> inode number
25 * %g <group> integer
26 * %i <ino> inode number
27 * %Is <inode> -> i_size
28 * %IS <inode> -> i_extra_isize
29 * %Ib <inode> -> i_blocks
30 * %Il <inode> -> i_links_count
31 * %Im <inode> -> i_mode
32 * %IM <inode> -> i_mtime
33 * %IF <inode> -> i_faddr
34 * %If <inode> -> i_file_acl
35 * %Id <inode> -> i_dir_acl
36 * %Iu <inode> -> i_uid
37 * %Ig <inode> -> i_gid
38 * %j <ino2> inode number
39 * %m <com_err error message>
40 * %N <num>
41 * %p ext2fs_get_pathname of directory <ino>
42 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
43 * the containing directory. (If dirent is NULL
44 * then return the pathname of directory <ino2>)
45 * %q ext2fs_get_pathname of directory <dir>
46 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
47 * the containing directory.
48 * %s <str> miscellaneous string
49 * %S backup superblock
50 * %X <num> hexadecimal format
51 *
52 * The following '@' expansions are supported:
53 *
54 * @a extended attribute
55 * @A error allocating
56 * @b block
57 * @B bitmap
58 * @c compress
59 * @C conflicts with some other fs block
60 * @D deleted
61 * @d directory
62 * @e entry
63 * @E Entry '%Dn' in %p (%i)
64 * @f filesystem
65 * @F for @i %i (%Q) is
66 * @g group
67 * @h HTREE directory inode
68 * @i inode
69 * @I illegal
70 * @j journal
71 * @l lost+found
72 * @L is a link
73 * @o orphaned
74 * @p problem in
75 * @r root inode
76 * @s should be
77 * @S superblock
78 * @u unattached
79 * @v device
80 * @z zero-length
81 */
82
83#include <stdlib.h>
84#include <unistd.h>
85#include <string.h>
86#include <ctype.h>
87#include <termios.h>
88
89#include "e2fsck.h"
90
91#include "problem.h"
92
93#ifdef __GNUC__
94#define _INLINE_ __inline__
95#else
96#define _INLINE_
97#endif
98
99/*
100 * This structure defines the abbreviations used by the text strings
101 * below. The first character in the string is the index letter. An
102 * abbreviation of the form '@<i>' is expanded by looking up the index
103 * letter <i> in the table below.
104 */
105static const char *abbrevs[] = {
106 N_("aextended attribute"),
107 N_("Aerror allocating"),
108 N_("bblock"),
109 N_("Bbitmap"),
110 N_("ccompress"),
111 N_("Cconflicts with some other fs @b"),
112 N_("iinode"),
113 N_("Iillegal"),
114 N_("jjournal"),
115 N_("Ddeleted"),
116 N_("ddirectory"),
117 N_("eentry"),
118 N_("E@e '%Dn' in %p (%i)"),
119 N_("ffilesystem"),
120 N_("Ffor @i %i (%Q) is"),
121 N_("ggroup"),
122 N_("hHTREE @d @i"),
123 N_("llost+found"),
124 N_("Lis a link"),
125 N_("oorphaned"),
126 N_("pproblem in"),
127 N_("rroot @i"),
128 N_("sshould be"),
129 N_("Ssuper@b"),
130 N_("uunattached"),
131 N_("vdevice"),
132 N_("zzero-length"),
133 "@@",
134 0
135 };
136
137/*
138 * Give more user friendly names to the "special" inodes.
139 */
140#define num_special_inodes 11
141static const char *special_inode_name[] =
142{
143 N_("<The NULL inode>"), /* 0 */
144 N_("<The bad blocks inode>"), /* 1 */
145 "/", /* 2 */
146 N_("<The ACL index inode>"), /* 3 */
147 N_("<The ACL data inode>"), /* 4 */
148 N_("<The boot loader inode>"), /* 5 */
149 N_("<The undelete directory inode>"), /* 6 */
150 N_("<The group descriptor inode>"), /* 7 */
151 N_("<The journal inode>"), /* 8 */
152 N_("<Reserved inode 9>"), /* 9 */
153 N_("<Reserved inode 10>"), /* 10 */
154};
155
156/*
157 * This function does "safe" printing. It will convert non-printable
158 * ASCII characters using '^' and M- notation.
159 */
160static void safe_print(const char *cp, int len)
161{
162 unsigned char ch;
163
164 if (len < 0)
165 len = strlen(cp);
166
167 while (len--) {
168 ch = *cp++;
169 if (ch > 128) {
170 fputs("M-", stdout);
171 ch -= 128;
172 }
173 if ((ch < 32) || (ch == 0x7f)) {
174 fputc('^', stdout);
175 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
176 }
177 fputc(ch, stdout);
178 }
179}
180
181
182/*
183 * This function prints a pathname, using the ext2fs_get_pathname
184 * function
185 */
186static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
187{
188 errcode_t retval;
189 char *path;
190
191 if (!dir && (ino < num_special_inodes)) {
192 fputs(_(special_inode_name[ino]), stdout);
193 return;
194 }
195
196 retval = ext2fs_get_pathname(fs, dir, ino, &path);
197 if (retval)
198 fputs("???", stdout);
199 else {
200 safe_print(path, -1);
201 ext2fs_free_mem(&path);
202 }
203}
204
205/*
206 * This function handles the '@' expansion. We allow recursive
207 * expansion; an @ expression can contain further '@' and '%'
208 * expressions.
209 */
210static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
211 struct problem_context *pctx,
212 int *first)
213{
214 const char **cpp, *str;
215
216 /* Search for the abbreviation */
217 for (cpp = abbrevs; *cpp; cpp++) {
218 if (ch == *cpp[0])
219 break;
220 }
221 if (*cpp) {
222 str = _(*cpp) + 1;
223 if (*first && islower(*str)) {
224 *first = 0;
225 fputc(toupper(*str++), stdout);
226 }
227 print_e2fsck_message(ctx, str, pctx, *first);
228 } else
229 printf("@%c", ch);
230}
231
232/*
233 * This function expands '%IX' expressions
234 */
235static _INLINE_ void expand_inode_expression(char ch,
236 struct problem_context *ctx)
237{
238 struct ext2_inode *inode;
239 struct ext2_inode_large *large_inode;
240 char * time_str;
241 time_t t;
242 int do_gmt = -1;
243
244 if (!ctx || !ctx->inode)
245 goto no_inode;
246
247 inode = ctx->inode;
248 large_inode = (struct ext2_inode_large *) inode;
249
250 switch (ch) {
251 case 's':
252 if (LINUX_S_ISDIR(inode->i_mode))
253 printf("%u", inode->i_size);
254 else {
255#ifdef EXT2_NO_64_TYPE
256 if (inode->i_size_high)
257 printf("0x%x%08x", inode->i_size_high,
258 inode->i_size);
259 else
260 printf("%u", inode->i_size);
261#else
262 printf("%llu", (inode->i_size |
263 ((__u64) inode->i_size_high << 32)));
264#endif
265 }
266 break;
267 case 'S':
268 printf("%u", large_inode->i_extra_isize);
269 break;
270 case 'b':
271 printf("%u", inode->i_blocks);
272 break;
273 case 'l':
274 printf("%d", inode->i_links_count);
275 break;
276 case 'm':
277 printf("0%o", inode->i_mode);
278 break;
279 case 'M':
280 /* The diet libc doesn't respect the TZ environemnt variable */
281 if (do_gmt == -1) {
282 time_str = getenv("TZ");
283 if (!time_str)
284 time_str = "";
285 do_gmt = !strcmp(time_str, "GMT");
286 }
287 t = inode->i_mtime;
288 time_str = asctime(do_gmt ? gmtime(&t) : localtime(&t));
289 printf("%.24s", time_str);
290 break;
291 case 'F':
292 printf("%u", inode->i_faddr);
293 break;
294 case 'f':
295 printf("%u", inode->i_file_acl);
296 break;
297 case 'd':
298 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
299 inode->i_dir_acl : 0));
300 break;
301 case 'u':
302 printf("%d", (inode->i_uid |
303 (inode->osd2.linux2.l_i_uid_high << 16)));
304 break;
305 case 'g':
306 printf("%d", (inode->i_gid |
307 (inode->osd2.linux2.l_i_gid_high << 16)));
308 break;
309 default:
310 no_inode:
311 printf("%%I%c", ch);
312 break;
313 }
314}
315
316/*
317 * This function expands '%dX' expressions
318 */
319static _INLINE_ void expand_dirent_expression(char ch,
320 struct problem_context *ctx)
321{
322 struct ext2_dir_entry *dirent;
323 int len;
324
325 if (!ctx || !ctx->dirent)
326 goto no_dirent;
327
328 dirent = ctx->dirent;
329
330 switch (ch) {
331 case 'i':
332 printf("%u", dirent->inode);
333 break;
334 case 'n':
335 len = dirent->name_len & 0xFF;
336 if (len > EXT2_NAME_LEN)
337 len = EXT2_NAME_LEN;
338 if (len > dirent->rec_len)
339 len = dirent->rec_len;
340 safe_print(dirent->name, len);
341 break;
342 case 'r':
343 printf("%u", dirent->rec_len);
344 break;
345 case 'l':
346 printf("%u", dirent->name_len & 0xFF);
347 break;
348 case 't':
349 printf("%u", dirent->name_len >> 8);
350 break;
351 default:
352 no_dirent:
353 printf("%%D%c", ch);
354 break;
355 }
356}
357
358static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
359 struct problem_context *ctx)
360{
361 if (!ctx)
362 goto no_context;
363
364 switch (ch) {
365 case '%':
366 fputc('%', stdout);
367 break;
368 case 'b':
369 printf("%u", ctx->blk);
370 break;
371 case 'B':
372#ifdef EXT2_NO_64_TYPE
373 printf("%d", ctx->blkcount);
374#else
375 printf("%lld", ctx->blkcount);
376#endif
377 break;
378 case 'c':
379 printf("%u", ctx->blk2);
380 break;
381 case 'd':
382 printf("%u", ctx->dir);
383 break;
384 case 'g':
385 printf("%d", ctx->group);
386 break;
387 case 'i':
388 printf("%u", ctx->ino);
389 break;
390 case 'j':
391 printf("%u", ctx->ino2);
392 break;
393 case 'm':
394 printf("%s", error_message(ctx->errcode));
395 break;
396 case 'N':
397#ifdef EXT2_NO_64_TYPE
398 printf("%u", ctx->num);
399#else
400 printf("%llu", ctx->num);
401#endif
402 break;
403 case 'p':
404 print_pathname(fs, ctx->ino, 0);
405 break;
406 case 'P':
407 print_pathname(fs, ctx->ino2,
408 ctx->dirent ? ctx->dirent->inode : 0);
409 break;
410 case 'q':
411 print_pathname(fs, ctx->dir, 0);
412 break;
413 case 'Q':
414 print_pathname(fs, ctx->dir, ctx->ino);
415 break;
416 case 'S':
417 printf("%d", get_backup_sb(NULL, fs, NULL, NULL));
418 break;
419 case 's':
420 printf("%s", ctx->str ? ctx->str : "NULL");
421 break;
422 case 'X':
423#ifdef EXT2_NO_64_TYPE
424 printf("0x%x", ctx->num);
425#else
426 printf("0x%llx", ctx->num);
427#endif
428 break;
429 default:
430 no_context:
431 printf("%%%c", ch);
432 break;
433 }
434}
435
436void print_e2fsck_message(e2fsck_t ctx, const char *msg,
437 struct problem_context *pctx, int first)
438{
439 ext2_filsys fs = ctx->fs;
440 const char * cp;
441 int i;
442
443 e2fsck_clear_progbar(ctx);
444 for (cp = msg; *cp; cp++) {
445 if (cp[0] == '@') {
446 cp++;
447 expand_at_expression(ctx, *cp, pctx, &first);
448 } else if (cp[0] == '%' && cp[1] == 'I') {
449 cp += 2;
450 expand_inode_expression(*cp, pctx);
451 } else if (cp[0] == '%' && cp[1] == 'D') {
452 cp += 2;
453 expand_dirent_expression(*cp, pctx);
454 } else if ((cp[0] == '%')) {
455 cp++;
456 expand_percent_expression(fs, *cp, pctx);
457 } else {
458 for (i=0; cp[i]; i++)
459 if ((cp[i] == '@') || cp[i] == '%')
460 break;
461 printf("%.*s", i, cp);
462 cp += i-1;
463 }
464 first = 0;
465 }
466}
diff --git a/e2fsprogs/e2fsck/pass1.c b/e2fsprogs/e2fsck/pass1.c
deleted file mode 100644
index 8d01cae2b..000000000
--- a/e2fsprogs/e2fsck/pass1.c
+++ /dev/null
@@ -1,2122 +0,0 @@
1/*
2 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
12 * and applies the following tests to each inode:
13 *
14 * - The mode field of the inode must be legal.
15 * - The size and block count fields of the inode are correct.
16 * - A data block must not be used by another inode
17 *
18 * Pass 1 also gathers the collects the following information:
19 *
20 * - A bitmap of which inodes are in use. (inode_used_map)
21 * - A bitmap of which inodes are directories. (inode_dir_map)
22 * - A bitmap of which inodes are regular files. (inode_reg_map)
23 * - A bitmap of which inodes have bad fields. (inode_bad_map)
24 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
25 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
26 * - A bitmap of which blocks are in use. (block_found_map)
27 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
28 * - The data blocks of the directory inodes. (dir_map)
29 *
30 * Pass 1 is designed to stash away enough information so that the
31 * other passes should not need to read in the inode information
32 * during the normal course of a filesystem check. (Althogh if an
33 * inconsistency is detected, other passes may need to read in an
34 * inode to fix it.)
35 *
36 * Note that pass 1B will be invoked if there are any duplicate blocks
37 * found.
38 */
39
40#define _GNU_SOURCE 1 /* get strnlen() */
41#include <string.h>
42#include <time.h>
43#ifdef HAVE_ERRNO_H
44#include <errno.h>
45#endif
46
47#include "e2fsck.h"
48#include <ext2fs/ext2_ext_attr.h>
49
50#include "problem.h"
51
52#ifdef NO_INLINE_FUNCS
53#define _INLINE_
54#else
55#define _INLINE_ inline
56#endif
57
58static int process_block(ext2_filsys fs, blk_t *blocknr,
59 e2_blkcnt_t blockcnt, blk_t ref_blk,
60 int ref_offset, void *priv_data);
61static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
62 e2_blkcnt_t blockcnt, blk_t ref_blk,
63 int ref_offset, void *priv_data);
64static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
65 char *block_buf);
66static void mark_table_blocks(e2fsck_t ctx);
67static void alloc_bb_map(e2fsck_t ctx);
68static void alloc_imagic_map(e2fsck_t ctx);
69static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
70static void handle_fs_bad_blocks(e2fsck_t ctx);
71static void process_inodes(e2fsck_t ctx, char *block_buf);
72static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
73static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
74 dgrp_t group, void * priv_data);
75static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
76 char *block_buf, int adjust_sign);
77/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
78
79extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
80 struct ext2_inode * inode, int bufsize,
81 const char *proc);
82
83struct process_block_struct {
84 ext2_ino_t ino;
85 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
86 fragmented:1, compressed:1, bbcheck:1;
87 blk_t num_blocks;
88 blk_t max_blocks;
89 e2_blkcnt_t last_block;
90 int num_illegal_blocks;
91 blk_t previous_block;
92 struct ext2_inode *inode;
93 struct problem_context *pctx;
94 ext2fs_block_bitmap fs_meta_blocks;
95 e2fsck_t ctx;
96};
97
98struct process_inode_block {
99 ext2_ino_t ino;
100 struct ext2_inode inode;
101};
102
103struct scan_callback_struct {
104 e2fsck_t ctx;
105 char *block_buf;
106};
107
108/*
109 * For the inodes to process list.
110 */
111static struct process_inode_block *inodes_to_process;
112static int process_inode_count;
113
114static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
115 EXT2_MIN_BLOCK_LOG_SIZE + 1];
116
117/*
118 * Free all memory allocated by pass1 in preparation for restarting
119 * things.
120 */
121static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused)))
122{
123 ext2fs_free_mem(&inodes_to_process);
124 inodes_to_process = 0;
125}
126
127/*
128 * Check to make sure a device inode is real. Returns 1 if the device
129 * checks out, 0 if not.
130 *
131 * Note: this routine is now also used to check FIFO's and Sockets,
132 * since they have the same requirement; the i_block fields should be
133 * zero.
134 */
135int e2fsck_pass1_check_device_inode(ext2_filsys fs, struct ext2_inode *inode)
136{
137 int i;
138
139 /*
140 * If i_blocks is non-zero, or the index flag is set, then
141 * this is a bogus device/fifo/socket
142 */
143 if ((ext2fs_inode_data_blocks(fs, inode) != 0) ||
144 (inode->i_flags & EXT2_INDEX_FL))
145 return 0;
146
147 /*
148 * We should be able to do the test below all the time, but
149 * because the kernel doesn't forcibly clear the device
150 * inode's additional i_block fields, there are some rare
151 * occasions when a legitimate device inode will have non-zero
152 * additional i_block fields. So for now, we only complain
153 * when the immutable flag is set, which should never happen
154 * for devices. (And that's when the problem is caused, since
155 * you can't set or clear immutable flags for devices.) Once
156 * the kernel has been fixed we can change this...
157 */
158 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
159 for (i=4; i < EXT2_N_BLOCKS; i++)
160 if (inode->i_block[i])
161 return 0;
162 }
163 return 1;
164}
165
166/*
167 * Check to make sure a symlink inode is real. Returns 1 if the symlink
168 * checks out, 0 if not.
169 */
170int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode,
171 char *buf)
172{
173 unsigned int len;
174 int i;
175 blk_t blocks;
176
177 if ((inode->i_size_high || inode->i_size == 0) ||
178 (inode->i_flags & EXT2_INDEX_FL))
179 return 0;
180
181 blocks = ext2fs_inode_data_blocks(fs, inode);
182 if (blocks) {
183 if ((inode->i_size >= fs->blocksize) ||
184 (blocks != fs->blocksize >> 9) ||
185 (inode->i_block[0] < fs->super->s_first_data_block) ||
186 (inode->i_block[0] >= fs->super->s_blocks_count))
187 return 0;
188
189 for (i = 1; i < EXT2_N_BLOCKS; i++)
190 if (inode->i_block[i])
191 return 0;
192
193 if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf))
194 return 0;
195
196 len = strnlen(buf, fs->blocksize);
197 if (len == fs->blocksize)
198 return 0;
199 } else {
200 if (inode->i_size >= sizeof(inode->i_block))
201 return 0;
202
203 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
204 if (len == sizeof(inode->i_block))
205 return 0;
206 }
207 if (len != inode->i_size)
208 return 0;
209 return 1;
210}
211
212/*
213 * If the immutable (or append-only) flag is set on the inode, offer
214 * to clear it.
215 */
216#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
217static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
218{
219 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
220 return;
221
222 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
223 return;
224
225 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
226 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
227}
228
229/*
230 * If device, fifo or socket, check size is zero -- if not offer to
231 * clear it
232 */
233static void check_size(e2fsck_t ctx, struct problem_context *pctx)
234{
235 struct ext2_inode *inode = pctx->inode;
236
237 if ((inode->i_size == 0) && (inode->i_size_high == 0))
238 return;
239
240 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
241 return;
242
243 inode->i_size = 0;
244 inode->i_size_high = 0;
245 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
246}
247
248static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
249{
250 struct ext2_super_block *sb = ctx->fs->super;
251 struct ext2_inode_large *inode;
252 struct ext2_ext_attr_entry *entry;
253 char *start, *end;
254 int storage_size, remain, offs;
255 int problem = 0;
256
257 inode = (struct ext2_inode_large *) pctx->inode;
258 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
259 inode->i_extra_isize;
260 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
261 inode->i_extra_isize + sizeof(__u32);
262 end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
263 entry = (struct ext2_ext_attr_entry *) start;
264
265 /* scan all entry's headers first */
266
267 /* take finish entry 0UL into account */
268 remain = storage_size - sizeof(__u32);
269 offs = end - start;
270
271 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
272
273 /* header eats this space */
274 remain -= sizeof(struct ext2_ext_attr_entry);
275
276 /* is attribute name valid? */
277 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
278 pctx->num = entry->e_name_len;
279 problem = PR_1_ATTR_NAME_LEN;
280 goto fix;
281 }
282
283 /* attribute len eats this space */
284 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
285
286 /* check value size */
287 if (entry->e_value_size == 0 || entry->e_value_size > remain) {
288 pctx->num = entry->e_value_size;
289 problem = PR_1_ATTR_VALUE_SIZE;
290 goto fix;
291 }
292
293 /* check value placement */
294 if (entry->e_value_offs +
295 EXT2_XATTR_SIZE(entry->e_value_size) != offs) {
296 printf("(entry->e_value_offs + entry->e_value_size: %d, offs: %d)\n", entry->e_value_offs + entry->e_value_size, offs);
297 pctx->num = entry->e_value_offs;
298 problem = PR_1_ATTR_VALUE_OFFSET;
299 goto fix;
300 }
301
302 /* e_value_block must be 0 in inode's ea */
303 if (entry->e_value_block != 0) {
304 pctx->num = entry->e_value_block;
305 problem = PR_1_ATTR_VALUE_BLOCK;
306 goto fix;
307 }
308
309 /* e_hash must be 0 in inode's ea */
310 if (entry->e_hash != 0) {
311 pctx->num = entry->e_hash;
312 problem = PR_1_ATTR_HASH;
313 goto fix;
314 }
315
316 remain -= entry->e_value_size;
317 offs -= EXT2_XATTR_SIZE(entry->e_value_size);
318
319 entry = EXT2_EXT_ATTR_NEXT(entry);
320 }
321fix:
322 /*
323 * it seems like a corruption. it's very unlikely we could repair
324 * EA(s) in automatic fashion -bzzz
325 */
326#if 0
327 problem = PR_1_ATTR_HASH;
328#endif
329 if (problem == 0 || !fix_problem(ctx, problem, pctx))
330 return;
331
332 /* simple remove all possible EA(s) */
333 *((__u32 *)start) = 0UL;
334 e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *)inode,
335 EXT2_INODE_SIZE(sb), "pass1");
336}
337
338static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
339{
340 struct ext2_super_block *sb = ctx->fs->super;
341 struct ext2_inode_large *inode;
342 __u32 *eamagic;
343 int min, max;
344
345 inode = (struct ext2_inode_large *) pctx->inode;
346 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
347 /* this isn't large inode. so, nothing to check */
348 return;
349 }
350
351#if 0
352 printf("inode #%u, i_extra_size %d\n", pctx->ino,
353 inode->i_extra_isize);
354#endif
355 /* i_extra_isize must cover i_extra_isize + i_pad1 at least */
356 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1);
357 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
358 /*
359 * For now we will allow i_extra_isize to be 0, but really
360 * implementations should never allow i_extra_isize to be 0
361 */
362 if (inode->i_extra_isize &&
363 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
364 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
365 return;
366 inode->i_extra_isize = min;
367 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
368 EXT2_INODE_SIZE(sb), "pass1");
369 return;
370 }
371
372 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
373 inode->i_extra_isize);
374 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
375 /* it seems inode has an extended attribute(s) in body */
376 check_ea_in_inode(ctx, pctx);
377 }
378}
379
380void e2fsck_pass1(e2fsck_t ctx)
381{
382 int i;
383 __u64 max_sizes;
384 ext2_filsys fs = ctx->fs;
385 ext2_ino_t ino;
386 struct ext2_inode *inode;
387 ext2_inode_scan scan;
388 char *block_buf;
389#ifdef RESOURCE_TRACK
390 struct resource_track rtrack;
391#endif
392 unsigned char frag, fsize;
393 struct problem_context pctx;
394 struct scan_callback_struct scan_struct;
395 struct ext2_super_block *sb = ctx->fs->super;
396 int imagic_fs;
397 int busted_fs_time = 0;
398 int inode_size;
399
400#ifdef RESOURCE_TRACK
401 init_resource_track(&rtrack);
402#endif
403 clear_problem_context(&pctx);
404
405 if (!(ctx->options & E2F_OPT_PREEN))
406 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
407
408 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
409 !(ctx->options & E2F_OPT_NO)) {
410 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
411 ctx->dirs_to_hash = 0;
412 }
413
414#ifdef MTRACE
415 mtrace_print("Pass 1");
416#endif
417
418#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
419
420 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
421 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
422 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
423 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
424 max_sizes = (max_sizes * (1UL << i)) - 1;
425 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
426 }
427#undef EXT2_BPP
428
429 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
430
431 /*
432 * Allocate bitmaps structures
433 */
434 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"),
435 &ctx->inode_used_map);
436 if (pctx.errcode) {
437 pctx.num = 1;
438 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
439 ctx->flags |= E2F_FLAG_ABORT;
440 return;
441 }
442 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
443 _("directory inode map"), &ctx->inode_dir_map);
444 if (pctx.errcode) {
445 pctx.num = 2;
446 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
447 ctx->flags |= E2F_FLAG_ABORT;
448 return;
449 }
450 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
451 _("regular file inode map"), &ctx->inode_reg_map);
452 if (pctx.errcode) {
453 pctx.num = 6;
454 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
455 ctx->flags |= E2F_FLAG_ABORT;
456 return;
457 }
458 pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
459 &ctx->block_found_map);
460 if (pctx.errcode) {
461 pctx.num = 1;
462 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
463 ctx->flags |= E2F_FLAG_ABORT;
464 return;
465 }
466 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
467 &ctx->inode_link_info);
468 if (pctx.errcode) {
469 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
470 ctx->flags |= E2F_FLAG_ABORT;
471 return;
472 }
473 inode_size = EXT2_INODE_SIZE(fs->super);
474 inode = (struct ext2_inode *)
475 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
476
477 inodes_to_process = (struct process_inode_block *)
478 e2fsck_allocate_memory(ctx,
479 (ctx->process_inode_size *
480 sizeof(struct process_inode_block)),
481 "array of inodes to process");
482 process_inode_count = 0;
483
484 pctx.errcode = ext2fs_init_dblist(fs, 0);
485 if (pctx.errcode) {
486 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
487 ctx->flags |= E2F_FLAG_ABORT;
488 return;
489 }
490
491 /*
492 * If the last orphan field is set, clear it, since the pass1
493 * processing will automatically find and clear the orphans.
494 * In the future, we may want to try using the last_orphan
495 * linked list ourselves, but for now, we clear it so that the
496 * ext3 mount code won't get confused.
497 */
498 if (!(ctx->options & E2F_OPT_READONLY)) {
499 if (fs->super->s_last_orphan) {
500 fs->super->s_last_orphan = 0;
501 ext2fs_mark_super_dirty(fs);
502 }
503 }
504
505 mark_table_blocks(ctx);
506 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
507 "block interate buffer");
508 e2fsck_use_inode_shortcuts(ctx, 1);
509 ehandler_operation(_("doing inode scan"));
510 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
511 &scan);
512 if (pctx.errcode) {
513 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
514 ctx->flags |= E2F_FLAG_ABORT;
515 return;
516 }
517 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
518 ctx->stashed_inode = inode;
519 scan_struct.ctx = ctx;
520 scan_struct.block_buf = block_buf;
521 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
522 if (ctx->progress)
523 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
524 return;
525 if (fs->super->s_wtime < fs->super->s_inodes_count)
526 busted_fs_time = 1;
527
528 while (1) {
529 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
530 inode, inode_size);
531 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
532 return;
533 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
534 if (!ctx->inode_bb_map)
535 alloc_bb_map(ctx);
536 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
537 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
538 continue;
539 }
540 if (pctx.errcode) {
541 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
542 ctx->flags |= E2F_FLAG_ABORT;
543 return;
544 }
545 if (!ino)
546 break;
547 pctx.ino = ino;
548 pctx.inode = inode;
549 ctx->stashed_ino = ino;
550 if (inode->i_links_count) {
551 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
552 ino, inode->i_links_count);
553 if (pctx.errcode) {
554 pctx.num = inode->i_links_count;
555 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
556 ctx->flags |= E2F_FLAG_ABORT;
557 return;
558 }
559 }
560 if (ino == EXT2_BAD_INO) {
561 struct process_block_struct pb;
562
563 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
564 &pb.fs_meta_blocks);
565 if (pctx.errcode) {
566 pctx.num = 4;
567 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
568 ctx->flags |= E2F_FLAG_ABORT;
569 return;
570 }
571 pb.ino = EXT2_BAD_INO;
572 pb.num_blocks = pb.last_block = 0;
573 pb.num_illegal_blocks = 0;
574 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
575 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
576 pb.inode = inode;
577 pb.pctx = &pctx;
578 pb.ctx = ctx;
579 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
580 block_buf, process_bad_block, &pb);
581 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
582 if (pctx.errcode) {
583 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
584 ctx->flags |= E2F_FLAG_ABORT;
585 return;
586 }
587 if (pb.bbcheck)
588 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
589 ctx->flags |= E2F_FLAG_ABORT;
590 return;
591 }
592 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
593 clear_problem_context(&pctx);
594 continue;
595 } else if (ino == EXT2_ROOT_INO) {
596 /*
597 * Make sure the root inode is a directory; if
598 * not, offer to clear it. It will be
599 * regnerated in pass #3.
600 */
601 if (!LINUX_S_ISDIR(inode->i_mode)) {
602 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
603 inode->i_dtime = time(0);
604 inode->i_links_count = 0;
605 ext2fs_icount_store(ctx->inode_link_info,
606 ino, 0);
607 e2fsck_write_inode(ctx, ino, inode,
608 "pass1");
609 }
610
611 }
612 /*
613 * If dtime is set, offer to clear it. mke2fs
614 * version 0.2b created filesystems with the
615 * dtime field set for the root and lost+found
616 * directories. We won't worry about
617 * /lost+found, since that can be regenerated
618 * easily. But we will fix the root directory
619 * as a special case.
620 */
621 if (inode->i_dtime && inode->i_links_count) {
622 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
623 inode->i_dtime = 0;
624 e2fsck_write_inode(ctx, ino, inode,
625 "pass1");
626 }
627 }
628 } else if (ino == EXT2_JOURNAL_INO) {
629 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
630 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
631 if (!LINUX_S_ISREG(inode->i_mode) &&
632 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
633 &pctx)) {
634 inode->i_mode = LINUX_S_IFREG;
635 e2fsck_write_inode(ctx, ino, inode,
636 "pass1");
637 }
638 check_blocks(ctx, &pctx, block_buf);
639 continue;
640 }
641 if ((inode->i_links_count || inode->i_blocks ||
642 inode->i_blocks || inode->i_block[0]) &&
643 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
644 &pctx)) {
645 memset(inode, 0, inode_size);
646 ext2fs_icount_store(ctx->inode_link_info,
647 ino, 0);
648 e2fsck_write_inode_full(ctx, ino, inode,
649 inode_size, "pass1");
650 }
651 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
652 int problem = 0;
653
654 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
655 if (ino == EXT2_BOOT_LOADER_INO) {
656 if (LINUX_S_ISDIR(inode->i_mode))
657 problem = PR_1_RESERVED_BAD_MODE;
658 } else if (ino == EXT2_RESIZE_INO) {
659 if (inode->i_mode &&
660 !LINUX_S_ISREG(inode->i_mode))
661 problem = PR_1_RESERVED_BAD_MODE;
662 } else {
663 if (inode->i_mode != 0)
664 problem = PR_1_RESERVED_BAD_MODE;
665 }
666 if (problem) {
667 if (fix_problem(ctx, problem, &pctx)) {
668 inode->i_mode = 0;
669 e2fsck_write_inode(ctx, ino, inode,
670 "pass1");
671 }
672 }
673 check_blocks(ctx, &pctx, block_buf);
674 continue;
675 }
676 /*
677 * Check for inodes who might have been part of the
678 * orphaned list linked list. They should have gotten
679 * dealt with by now, unless the list had somehow been
680 * corrupted.
681 *
682 * FIXME: In the future, inodes which are still in use
683 * (and which are therefore) pending truncation should
684 * be handled specially. Right now we just clear the
685 * dtime field, and the normal e2fsck handling of
686 * inodes where i_size and the inode blocks are
687 * inconsistent is to fix i_size, instead of releasing
688 * the extra blocks. This won't catch the inodes that
689 * was at the end of the orphan list, but it's better
690 * than nothing. The right answer is that there
691 * shouldn't be any bugs in the orphan list handling. :-)
692 */
693 if (inode->i_dtime && !busted_fs_time &&
694 inode->i_dtime < ctx->fs->super->s_inodes_count) {
695 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
696 inode->i_dtime = inode->i_links_count ?
697 0 : time(0);
698 e2fsck_write_inode(ctx, ino, inode,
699 "pass1");
700 }
701 }
702
703 /*
704 * This code assumes that deleted inodes have
705 * i_links_count set to 0.
706 */
707 if (!inode->i_links_count) {
708 if (!inode->i_dtime && inode->i_mode) {
709 if (fix_problem(ctx,
710 PR_1_ZERO_DTIME, &pctx)) {
711 inode->i_dtime = time(0);
712 e2fsck_write_inode(ctx, ino, inode,
713 "pass1");
714 }
715 }
716 continue;
717 }
718 /*
719 * n.b. 0.3c ext2fs code didn't clear i_links_count for
720 * deleted files. Oops.
721 *
722 * Since all new ext2 implementations get this right,
723 * we now assume that the case of non-zero
724 * i_links_count and non-zero dtime means that we
725 * should keep the file, not delete it.
726 *
727 */
728 if (inode->i_dtime) {
729 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
730 inode->i_dtime = 0;
731 e2fsck_write_inode(ctx, ino, inode, "pass1");
732 }
733 }
734
735 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
736 switch (fs->super->s_creator_os) {
737 case EXT2_OS_LINUX:
738 frag = inode->osd2.linux2.l_i_frag;
739 fsize = inode->osd2.linux2.l_i_fsize;
740 break;
741 case EXT2_OS_HURD:
742 frag = inode->osd2.hurd2.h_i_frag;
743 fsize = inode->osd2.hurd2.h_i_fsize;
744 break;
745 case EXT2_OS_MASIX:
746 frag = inode->osd2.masix2.m_i_frag;
747 fsize = inode->osd2.masix2.m_i_fsize;
748 break;
749 default:
750 frag = fsize = 0;
751 }
752
753 if (inode->i_faddr || frag || fsize ||
754 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
755 mark_inode_bad(ctx, ino);
756 if (inode->i_flags & EXT2_IMAGIC_FL) {
757 if (imagic_fs) {
758 if (!ctx->inode_imagic_map)
759 alloc_imagic_map(ctx);
760 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
761 ino);
762 } else {
763 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
764 inode->i_flags &= ~EXT2_IMAGIC_FL;
765 e2fsck_write_inode(ctx, ino,
766 inode, "pass1");
767 }
768 }
769 }
770
771 check_inode_extra_space(ctx, &pctx);
772
773 if (LINUX_S_ISDIR(inode->i_mode)) {
774 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
775 e2fsck_add_dir_info(ctx, ino, 0);
776 ctx->fs_directory_count++;
777 } else if (LINUX_S_ISREG (inode->i_mode)) {
778 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
779 ctx->fs_regular_count++;
780 } else if (LINUX_S_ISCHR (inode->i_mode) &&
781 e2fsck_pass1_check_device_inode(fs, inode)) {
782 check_immutable(ctx, &pctx);
783 check_size(ctx, &pctx);
784 ctx->fs_chardev_count++;
785 } else if (LINUX_S_ISBLK (inode->i_mode) &&
786 e2fsck_pass1_check_device_inode(fs, inode)) {
787 check_immutable(ctx, &pctx);
788 check_size(ctx, &pctx);
789 ctx->fs_blockdev_count++;
790 } else if (LINUX_S_ISLNK (inode->i_mode) &&
791 e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
792 check_immutable(ctx, &pctx);
793 ctx->fs_symlinks_count++;
794 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
795 ctx->fs_fast_symlinks_count++;
796 check_blocks(ctx, &pctx, block_buf);
797 continue;
798 }
799 }
800 else if (LINUX_S_ISFIFO (inode->i_mode) &&
801 e2fsck_pass1_check_device_inode(fs, inode)) {
802 check_immutable(ctx, &pctx);
803 check_size(ctx, &pctx);
804 ctx->fs_fifo_count++;
805 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
806 e2fsck_pass1_check_device_inode(fs, inode)) {
807 check_immutable(ctx, &pctx);
808 check_size(ctx, &pctx);
809 ctx->fs_sockets_count++;
810 } else
811 mark_inode_bad(ctx, ino);
812 if (inode->i_block[EXT2_IND_BLOCK])
813 ctx->fs_ind_count++;
814 if (inode->i_block[EXT2_DIND_BLOCK])
815 ctx->fs_dind_count++;
816 if (inode->i_block[EXT2_TIND_BLOCK])
817 ctx->fs_tind_count++;
818 if (inode->i_block[EXT2_IND_BLOCK] ||
819 inode->i_block[EXT2_DIND_BLOCK] ||
820 inode->i_block[EXT2_TIND_BLOCK] ||
821 inode->i_file_acl) {
822 inodes_to_process[process_inode_count].ino = ino;
823 inodes_to_process[process_inode_count].inode = *inode;
824 process_inode_count++;
825 } else
826 check_blocks(ctx, &pctx, block_buf);
827
828 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
829 return;
830
831 if (process_inode_count >= ctx->process_inode_size) {
832 process_inodes(ctx, block_buf);
833
834 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
835 return;
836 }
837 }
838 process_inodes(ctx, block_buf);
839 ext2fs_close_inode_scan(scan);
840 ehandler_operation(0);
841
842 /*
843 * If any extended attribute blocks' reference counts need to
844 * be adjusted, either up (ctx->refcount_extra), or down
845 * (ctx->refcount), then fix them.
846 */
847 if (ctx->refcount) {
848 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
849 ea_refcount_free(ctx->refcount);
850 ctx->refcount = 0;
851 }
852 if (ctx->refcount_extra) {
853 adjust_extattr_refcount(ctx, ctx->refcount_extra,
854 block_buf, +1);
855 ea_refcount_free(ctx->refcount_extra);
856 ctx->refcount_extra = 0;
857 }
858
859 if (ctx->invalid_bitmaps)
860 handle_fs_bad_blocks(ctx);
861
862 /* We don't need the block_ea_map any more */
863 if (ctx->block_ea_map) {
864 ext2fs_free_block_bitmap(ctx->block_ea_map);
865 ctx->block_ea_map = 0;
866 }
867
868 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
869 ext2fs_block_bitmap save_bmap;
870
871 save_bmap = fs->block_map;
872 fs->block_map = ctx->block_found_map;
873 clear_problem_context(&pctx);
874 pctx.errcode = ext2fs_create_resize_inode(fs);
875 if (pctx.errcode) {
876 fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx);
877 /* Should never get here */
878 ctx->flags |= E2F_FLAG_ABORT;
879 return;
880 }
881 fs->block_map = save_bmap;
882 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
883 }
884
885 if (ctx->flags & E2F_FLAG_RESTART) {
886 /*
887 * Only the master copy of the superblock and block
888 * group descriptors are going to be written during a
889 * restart, so set the superblock to be used to be the
890 * master superblock.
891 */
892 ctx->use_superblock = 0;
893 unwind_pass1(fs);
894 goto endit;
895 }
896
897 if (ctx->block_dup_map) {
898 if (ctx->options & E2F_OPT_PREEN) {
899 clear_problem_context(&pctx);
900 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
901 }
902 e2fsck_pass1_dupblocks(ctx, block_buf);
903 }
904 ext2fs_free_mem(&inodes_to_process);
905endit:
906 e2fsck_use_inode_shortcuts(ctx, 0);
907
908 ext2fs_free_mem(&block_buf);
909 ext2fs_free_mem(&inode);
910
911#ifdef RESOURCE_TRACK
912 if (ctx->options & E2F_OPT_TIME2) {
913 e2fsck_clear_progbar(ctx);
914 print_resource_track(_("Pass 1"), &rtrack);
915 }
916#endif
917}
918
919/*
920 * When the inode_scan routines call this callback at the end of the
921 * glock group, call process_inodes.
922 */
923static errcode_t scan_callback(ext2_filsys fs,
924 ext2_inode_scan scan EXT2FS_ATTR((unused)),
925 dgrp_t group, void * priv_data)
926{
927 struct scan_callback_struct *scan_struct;
928 e2fsck_t ctx;
929
930 scan_struct = (struct scan_callback_struct *) priv_data;
931 ctx = scan_struct->ctx;
932
933 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
934
935 if (ctx->progress)
936 if ((ctx->progress)(ctx, 1, group+1,
937 ctx->fs->group_desc_count))
938 return EXT2_ET_CANCEL_REQUESTED;
939
940 return 0;
941}
942
943/*
944 * Process the inodes in the "inodes to process" list.
945 */
946static void process_inodes(e2fsck_t ctx, char *block_buf)
947{
948 int i;
949 struct ext2_inode *old_stashed_inode;
950 ext2_ino_t old_stashed_ino;
951 const char *old_operation;
952 char buf[80];
953 struct problem_context pctx;
954
955#if 0
956 printf("begin process_inodes: ");
957#endif
958 if (process_inode_count == 0)
959 return;
960 old_operation = ehandler_operation(0);
961 old_stashed_inode = ctx->stashed_inode;
962 old_stashed_ino = ctx->stashed_ino;
963 qsort(inodes_to_process, process_inode_count,
964 sizeof(struct process_inode_block), process_inode_cmp);
965 clear_problem_context(&pctx);
966 for (i=0; i < process_inode_count; i++) {
967 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
968 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
969
970#if 0
971 printf("%u ", pctx.ino);
972#endif
973 sprintf(buf, _("reading indirect blocks of inode %u"),
974 pctx.ino);
975 ehandler_operation(buf);
976 check_blocks(ctx, &pctx, block_buf);
977 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
978 break;
979 }
980 ctx->stashed_inode = old_stashed_inode;
981 ctx->stashed_ino = old_stashed_ino;
982 process_inode_count = 0;
983#if 0
984 printf("end process inodes\n");
985#endif
986 ehandler_operation(old_operation);
987}
988
989static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
990{
991 const struct process_inode_block *ib_a =
992 (const struct process_inode_block *) a;
993 const struct process_inode_block *ib_b =
994 (const struct process_inode_block *) b;
995 int ret;
996
997 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
998 ib_b->inode.i_block[EXT2_IND_BLOCK]);
999 if (ret == 0)
1000 ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl;
1001 return ret;
1002}
1003
1004/*
1005 * Mark an inode as being bad in some what
1006 */
1007static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
1008{
1009 struct problem_context pctx;
1010
1011 if (!ctx->inode_bad_map) {
1012 clear_problem_context(&pctx);
1013
1014 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
1015 _("bad inode map"), &ctx->inode_bad_map);
1016 if (pctx.errcode) {
1017 pctx.num = 3;
1018 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
1019 /* Should never get here */
1020 ctx->flags |= E2F_FLAG_ABORT;
1021 return;
1022 }
1023 }
1024 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
1025}
1026
1027
1028/*
1029 * This procedure will allocate the inode "bb" (badblock) map table
1030 */
1031static void alloc_bb_map(e2fsck_t ctx)
1032{
1033 struct problem_context pctx;
1034
1035 clear_problem_context(&pctx);
1036 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
1037 _("inode in bad block map"),
1038 &ctx->inode_bb_map);
1039 if (pctx.errcode) {
1040 pctx.num = 4;
1041 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
1042 /* Should never get here */
1043 ctx->flags |= E2F_FLAG_ABORT;
1044 return;
1045 }
1046}
1047
1048/*
1049 * This procedure will allocate the inode imagic table
1050 */
1051static void alloc_imagic_map(e2fsck_t ctx)
1052{
1053 struct problem_context pctx;
1054
1055 clear_problem_context(&pctx);
1056 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
1057 _("imagic inode map"),
1058 &ctx->inode_imagic_map);
1059 if (pctx.errcode) {
1060 pctx.num = 5;
1061 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
1062 /* Should never get here */
1063 ctx->flags |= E2F_FLAG_ABORT;
1064 return;
1065 }
1066}
1067
1068/*
1069 * Marks a block as in use, setting the dup_map if it's been set
1070 * already. Called by process_block and process_bad_block.
1071 *
1072 * WARNING: Assumes checks have already been done to make sure block
1073 * is valid. This is true in both process_block and process_bad_block.
1074 */
1075static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
1076{
1077 struct problem_context pctx;
1078
1079 clear_problem_context(&pctx);
1080
1081 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
1082 if (!ctx->block_dup_map) {
1083 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
1084 _("multiply claimed block map"),
1085 &ctx->block_dup_map);
1086 if (pctx.errcode) {
1087 pctx.num = 3;
1088 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
1089 &pctx);
1090 /* Should never get here */
1091 ctx->flags |= E2F_FLAG_ABORT;
1092 return;
1093 }
1094 }
1095 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
1096 } else {
1097 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
1098 }
1099}
1100
1101/*
1102 * Adjust the extended attribute block's reference counts at the end
1103 * of pass 1, either by subtracting out references for EA blocks that
1104 * are still referenced in ctx->refcount, or by adding references for
1105 * EA blocks that had extra references as accounted for in
1106 * ctx->refcount_extra.
1107 */
1108static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
1109 char *block_buf, int adjust_sign)
1110{
1111 struct ext2_ext_attr_header *header;
1112 struct problem_context pctx;
1113 ext2_filsys fs = ctx->fs;
1114 blk_t blk;
1115 __u32 should_be;
1116 int count;
1117
1118 clear_problem_context(&pctx);
1119
1120 ea_refcount_intr_begin(refcount);
1121 while (1) {
1122 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
1123 break;
1124 pctx.blk = blk;
1125 pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
1126 if (pctx.errcode) {
1127 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
1128 return;
1129 }
1130 header = (struct ext2_ext_attr_header *) block_buf;
1131 pctx.blkcount = header->h_refcount;
1132 should_be = header->h_refcount + adjust_sign * count;
1133 pctx.num = should_be;
1134 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
1135 header->h_refcount = should_be;
1136 pctx.errcode = ext2fs_write_ext_attr(fs, blk,
1137 block_buf);
1138 if (pctx.errcode) {
1139 fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx);
1140 continue;
1141 }
1142 }
1143 }
1144}
1145
1146/*
1147 * Handle processing the extended attribute blocks
1148 */
1149static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
1150 char *block_buf)
1151{
1152 ext2_filsys fs = ctx->fs;
1153 ext2_ino_t ino = pctx->ino;
1154 struct ext2_inode *inode = pctx->inode;
1155 blk_t blk;
1156 char * end;
1157 struct ext2_ext_attr_header *header;
1158 struct ext2_ext_attr_entry *entry;
1159 int count;
1160 region_t region;
1161
1162 blk = inode->i_file_acl;
1163 if (blk == 0)
1164 return 0;
1165
1166 /*
1167 * If the Extended attribute flag isn't set, then a non-zero
1168 * file acl means that the inode is corrupted.
1169 *
1170 * Or if the extended attribute block is an invalid block,
1171 * then the inode is also corrupted.
1172 */
1173 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
1174 (blk < fs->super->s_first_data_block) ||
1175 (blk >= fs->super->s_blocks_count)) {
1176 mark_inode_bad(ctx, ino);
1177 return 0;
1178 }
1179
1180 /* If ea bitmap hasn't been allocated, create it */
1181 if (!ctx->block_ea_map) {
1182 pctx->errcode = ext2fs_allocate_block_bitmap(fs,
1183 _("ext attr block map"),
1184 &ctx->block_ea_map);
1185 if (pctx->errcode) {
1186 pctx->num = 2;
1187 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
1188 ctx->flags |= E2F_FLAG_ABORT;
1189 return 0;
1190 }
1191 }
1192
1193 /* Create the EA refcount structure if necessary */
1194 if (!ctx->refcount) {
1195 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
1196 if (pctx->errcode) {
1197 pctx->num = 1;
1198 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
1199 ctx->flags |= E2F_FLAG_ABORT;
1200 return 0;
1201 }
1202 }
1203
1204#if 0
1205 /* Debugging text */
1206 printf("Inode %u has EA block %u\n", ino, blk);
1207#endif
1208
1209 /* Have we seen this EA block before? */
1210 if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) {
1211 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
1212 return 1;
1213 /* Ooops, this EA was referenced more than it stated */
1214 if (!ctx->refcount_extra) {
1215 pctx->errcode = ea_refcount_create(0,
1216 &ctx->refcount_extra);
1217 if (pctx->errcode) {
1218 pctx->num = 2;
1219 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
1220 ctx->flags |= E2F_FLAG_ABORT;
1221 return 0;
1222 }
1223 }
1224 ea_refcount_increment(ctx->refcount_extra, blk, 0);
1225 return 1;
1226 }
1227
1228 /*
1229 * OK, we haven't seen this EA block yet. So we need to
1230 * validate it
1231 */
1232 pctx->blk = blk;
1233 pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf);
1234 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
1235 goto clear_extattr;
1236 header = (struct ext2_ext_attr_header *) block_buf;
1237 pctx->blk = inode->i_file_acl;
1238 if (((ctx->ext_attr_ver == 1) &&
1239 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
1240 ((ctx->ext_attr_ver == 2) &&
1241 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
1242 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
1243 goto clear_extattr;
1244 }
1245
1246 if (header->h_blocks != 1) {
1247 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
1248 goto clear_extattr;
1249 }
1250
1251 region = region_create(0, fs->blocksize);
1252 if (!region) {
1253 fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
1254 ctx->flags |= E2F_FLAG_ABORT;
1255 return 0;
1256 }
1257 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
1258 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1259 goto clear_extattr;
1260 }
1261
1262 entry = (struct ext2_ext_attr_entry *)(header+1);
1263 end = block_buf + fs->blocksize;
1264 while ((char *)entry < end && *(__u32 *)entry) {
1265 if (region_allocate(region, (char *)entry - (char *)header,
1266 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
1267 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1268 goto clear_extattr;
1269 }
1270 if ((ctx->ext_attr_ver == 1 &&
1271 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
1272 (ctx->ext_attr_ver == 2 &&
1273 entry->e_name_index == 0)) {
1274 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
1275 goto clear_extattr;
1276 }
1277 if (entry->e_value_block != 0) {
1278 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
1279 goto clear_extattr;
1280 }
1281 if (entry->e_value_size &&
1282 region_allocate(region, entry->e_value_offs,
1283 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
1284 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1285 goto clear_extattr;
1286 }
1287 entry = EXT2_EXT_ATTR_NEXT(entry);
1288 }
1289 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
1290 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1291 goto clear_extattr;
1292 }
1293 region_free(region);
1294
1295 count = header->h_refcount - 1;
1296 if (count)
1297 ea_refcount_store(ctx->refcount, blk, count);
1298 mark_block_used(ctx, blk);
1299 ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk);
1300
1301 return 1;
1302
1303clear_extattr:
1304 inode->i_file_acl = 0;
1305 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
1306 return 0;
1307}
1308
1309/* Returns 1 if bad htree, 0 if OK */
1310static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
1311 ext2_ino_t ino EXT2FS_ATTR((unused)),
1312 struct ext2_inode *inode,
1313 char *block_buf)
1314{
1315 struct ext2_dx_root_info *root;
1316 ext2_filsys fs = ctx->fs;
1317 errcode_t retval;
1318 blk_t blk;
1319
1320 if ((!LINUX_S_ISDIR(inode->i_mode) &&
1321 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
1322 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
1323 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
1324 return 1;
1325
1326 blk = inode->i_block[0];
1327 if (((blk == 0) ||
1328 (blk < fs->super->s_first_data_block) ||
1329 (blk >= fs->super->s_blocks_count)) &&
1330 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
1331 return 1;
1332
1333 retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
1334 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
1335 return 1;
1336
1337 /* XXX should check that beginning matches a directory */
1338 root = (struct ext2_dx_root_info *) (block_buf + 24);
1339
1340 if ((root->reserved_zero || root->info_length < 8) &&
1341 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
1342 return 1;
1343
1344 pctx->num = root->hash_version;
1345 if ((root->hash_version != EXT2_HASH_LEGACY) &&
1346 (root->hash_version != EXT2_HASH_HALF_MD4) &&
1347 (root->hash_version != EXT2_HASH_TEA) &&
1348 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
1349 return 1;
1350
1351 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
1352 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
1353 return 1;
1354
1355 pctx->num = root->indirect_levels;
1356 if ((root->indirect_levels > 1) &&
1357 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
1358 return 1;
1359
1360 return 0;
1361}
1362
1363/*
1364 * This subroutine is called on each inode to account for all of the
1365 * blocks used by that inode.
1366 */
1367static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
1368 char *block_buf)
1369{
1370 ext2_filsys fs = ctx->fs;
1371 struct process_block_struct pb;
1372 ext2_ino_t ino = pctx->ino;
1373 struct ext2_inode *inode = pctx->inode;
1374 int bad_size = 0;
1375 int dirty_inode = 0;
1376 __u64 size;
1377
1378 pb.ino = ino;
1379 pb.num_blocks = 0;
1380 pb.last_block = -1;
1381 pb.num_illegal_blocks = 0;
1382 pb.suppress = 0; pb.clear = 0;
1383 pb.fragmented = 0;
1384 pb.compressed = 0;
1385 pb.previous_block = 0;
1386 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
1387 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
1388 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
1389 pb.inode = inode;
1390 pb.pctx = pctx;
1391 pb.ctx = ctx;
1392 pctx->ino = ino;
1393 pctx->errcode = 0;
1394
1395 if (inode->i_flags & EXT2_COMPRBLK_FL) {
1396 if (fs->super->s_feature_incompat &
1397 EXT2_FEATURE_INCOMPAT_COMPRESSION)
1398 pb.compressed = 1;
1399 else {
1400 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
1401 inode->i_flags &= ~EXT2_COMPRBLK_FL;
1402 dirty_inode++;
1403 }
1404 }
1405 }
1406
1407 if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
1408 pb.num_blocks++;
1409
1410 if (ext2fs_inode_has_valid_blocks(inode))
1411 pctx->errcode = ext2fs_block_iterate2(fs, ino,
1412 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
1413 block_buf, process_block, &pb);
1414 end_problem_latch(ctx, PR_LATCH_BLOCK);
1415 end_problem_latch(ctx, PR_LATCH_TOOBIG);
1416 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1417 goto out;
1418 if (pctx->errcode)
1419 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
1420
1421 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
1422 ctx->fs_fragmented++;
1423
1424 if (pb.clear) {
1425 inode->i_links_count = 0;
1426 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
1427 inode->i_dtime = time(0);
1428 dirty_inode++;
1429 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
1430 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
1431 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
1432 /*
1433 * The inode was probably partially accounted for
1434 * before processing was aborted, so we need to
1435 * restart the pass 1 scan.
1436 */
1437 ctx->flags |= E2F_FLAG_RESTART;
1438 goto out;
1439 }
1440
1441 if (inode->i_flags & EXT2_INDEX_FL) {
1442 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
1443 inode->i_flags &= ~EXT2_INDEX_FL;
1444 dirty_inode++;
1445 } else {
1446#ifdef ENABLE_HTREE
1447 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
1448#endif
1449 }
1450 }
1451 if (ctx->dirs_to_hash && pb.is_dir &&
1452 !(inode->i_flags & EXT2_INDEX_FL) &&
1453 ((inode->i_size / fs->blocksize) >= 3))
1454 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
1455
1456 if (!pb.num_blocks && pb.is_dir) {
1457 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
1458 inode->i_links_count = 0;
1459 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
1460 inode->i_dtime = time(0);
1461 dirty_inode++;
1462 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
1463 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
1464 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
1465 ctx->fs_directory_count--;
1466 goto out;
1467 }
1468 }
1469
1470 pb.num_blocks *= (fs->blocksize / 512);
1471#if 0
1472 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
1473 ino, inode->i_size, pb.last_block, inode->i_blocks,
1474 pb.num_blocks);
1475#endif
1476 if (pb.is_dir) {
1477 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
1478 if (nblock > (pb.last_block + 1))
1479 bad_size = 1;
1480 else if (nblock < (pb.last_block + 1)) {
1481 if (((pb.last_block + 1) - nblock) >
1482 fs->super->s_prealloc_dir_blocks)
1483 bad_size = 2;
1484 }
1485 } else {
1486 size = EXT2_I_SIZE(inode);
1487 if ((pb.last_block >= 0) &&
1488 (size < (__u64) pb.last_block * fs->blocksize))
1489 bad_size = 3;
1490 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
1491 bad_size = 4;
1492 }
1493 /* i_size for symlinks is checked elsewhere */
1494 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
1495 pctx->num = (pb.last_block+1) * fs->blocksize;
1496 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
1497 inode->i_size = pctx->num;
1498 if (!LINUX_S_ISDIR(inode->i_mode))
1499 inode->i_size_high = pctx->num >> 32;
1500 dirty_inode++;
1501 }
1502 pctx->num = 0;
1503 }
1504 if (LINUX_S_ISREG(inode->i_mode) &&
1505 (inode->i_size_high || inode->i_size & 0x80000000UL))
1506 ctx->large_files++;
1507 if (pb.num_blocks != inode->i_blocks) {
1508 pctx->num = pb.num_blocks;
1509 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
1510 inode->i_blocks = pb.num_blocks;
1511 dirty_inode++;
1512 }
1513 pctx->num = 0;
1514 }
1515out:
1516 if (dirty_inode)
1517 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
1518}
1519
1520#if 0
1521/*
1522 * Helper function called by process block when an illegal block is
1523 * found. It returns a description about why the block is illegal
1524 */
1525static char *describe_illegal_block(ext2_filsys fs, blk_t block)
1526{
1527 blk_t super;
1528 int i;
1529 static char problem[80];
1530
1531 super = fs->super->s_first_data_block;
1532 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
1533 if (block < super) {
1534 sprintf(problem, "< FIRSTBLOCK (%u)", super);
1535 return(problem);
1536 } else if (block >= fs->super->s_blocks_count) {
1537 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
1538 return(problem);
1539 }
1540 for (i = 0; i < fs->group_desc_count; i++) {
1541 if (block == super) {
1542 sprintf(problem, "is the superblock in group %d", i);
1543 break;
1544 }
1545 if (block > super &&
1546 block <= (super + fs->desc_blocks)) {
1547 sprintf(problem, "is in the group descriptors "
1548 "of group %d", i);
1549 break;
1550 }
1551 if (block == fs->group_desc[i].bg_block_bitmap) {
1552 sprintf(problem, "is the block bitmap of group %d", i);
1553 break;
1554 }
1555 if (block == fs->group_desc[i].bg_inode_bitmap) {
1556 sprintf(problem, "is the inode bitmap of group %d", i);
1557 break;
1558 }
1559 if (block >= fs->group_desc[i].bg_inode_table &&
1560 (block < fs->group_desc[i].bg_inode_table
1561 + fs->inode_blocks_per_group)) {
1562 sprintf(problem, "is in the inode table of group %d",
1563 i);
1564 break;
1565 }
1566 super += fs->super->s_blocks_per_group;
1567 }
1568 return(problem);
1569}
1570#endif
1571
1572/*
1573 * This is a helper function for check_blocks().
1574 */
1575static int process_block(ext2_filsys fs,
1576 blk_t *block_nr,
1577 e2_blkcnt_t blockcnt,
1578 blk_t ref_block EXT2FS_ATTR((unused)),
1579 int ref_offset EXT2FS_ATTR((unused)),
1580 void *priv_data)
1581{
1582 struct process_block_struct *p;
1583 struct problem_context *pctx;
1584 blk_t blk = *block_nr;
1585 int ret_code = 0;
1586 int problem = 0;
1587 e2fsck_t ctx;
1588
1589 p = (struct process_block_struct *) priv_data;
1590 pctx = p->pctx;
1591 ctx = p->ctx;
1592
1593 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
1594 /* todo: Check that the comprblk_fl is high, that the
1595 blkaddr pattern looks right (all non-holes up to
1596 first EXT2FS_COMPRESSED_BLKADDR, then all
1597 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
1598 that the feature_incompat bit is high, and that the
1599 inode is a regular file. If we're doing a "full
1600 check" (a concept introduced to e2fsck by e2compr,
1601 meaning that we look at data blocks as well as
1602 metadata) then call some library routine that
1603 checks the compressed data. I'll have to think
1604 about this, because one particularly important
1605 problem to be able to fix is to recalculate the
1606 cluster size if necessary. I think that perhaps
1607 we'd better do most/all e2compr-specific checks
1608 separately, after the non-e2compr checks. If not
1609 doing a full check, it may be useful to test that
1610 the personality is linux; e.g. if it isn't then
1611 perhaps this really is just an illegal block. */
1612 return 0;
1613 }
1614
1615 if (blk == 0) {
1616 if (p->is_dir == 0) {
1617 /*
1618 * Should never happen, since only directories
1619 * get called with BLOCK_FLAG_HOLE
1620 */
1621#if DEBUG_E2FSCK
1622 printf("process_block() called with blk == 0, "
1623 "blockcnt=%d, inode %lu???\n",
1624 blockcnt, p->ino);
1625#endif
1626 return 0;
1627 }
1628 if (blockcnt < 0)
1629 return 0;
1630 if (blockcnt * fs->blocksize < p->inode->i_size) {
1631#if 0
1632 printf("Missing block (#%d) in directory inode %lu!\n",
1633 blockcnt, p->ino);
1634#endif
1635 goto mark_dir;
1636 }
1637 return 0;
1638 }
1639
1640#if 0
1641 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
1642 blockcnt);
1643#endif
1644
1645 /*
1646 * Simplistic fragmentation check. We merely require that the
1647 * file be contiguous. (Which can never be true for really
1648 * big files that are greater than a block group.)
1649 */
1650 if (!HOLE_BLKADDR(p->previous_block)) {
1651 if (p->previous_block+1 != blk)
1652 p->fragmented = 1;
1653 }
1654 p->previous_block = blk;
1655
1656 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
1657 problem = PR_1_TOOBIG_DIR;
1658 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
1659 problem = PR_1_TOOBIG_REG;
1660 if (!p->is_dir && !p->is_reg && blockcnt > 0)
1661 problem = PR_1_TOOBIG_SYMLINK;
1662
1663 if (blk < fs->super->s_first_data_block ||
1664 blk >= fs->super->s_blocks_count)
1665 problem = PR_1_ILLEGAL_BLOCK_NUM;
1666
1667 if (problem) {
1668 p->num_illegal_blocks++;
1669 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
1670 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
1671 p->clear = 1;
1672 return BLOCK_ABORT;
1673 }
1674 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
1675 p->suppress = 1;
1676 set_latch_flags(PR_LATCH_BLOCK,
1677 PRL_SUPPRESS, 0);
1678 }
1679 }
1680 pctx->blk = blk;
1681 pctx->blkcount = blockcnt;
1682 if (fix_problem(ctx, problem, pctx)) {
1683 blk = *block_nr = 0;
1684 ret_code = BLOCK_CHANGED;
1685 goto mark_dir;
1686 } else
1687 return 0;
1688 }
1689
1690 if (p->ino == EXT2_RESIZE_INO) {
1691 /*
1692 * The resize inode has already be sanity checked
1693 * during pass #0 (the superblock checks). All we
1694 * have to do is mark the double indirect block as
1695 * being in use; all of the other blocks are handled
1696 * by mark_table_blocks()).
1697 */
1698 if (blockcnt == BLOCK_COUNT_DIND)
1699 mark_block_used(ctx, blk);
1700 } else
1701 mark_block_used(ctx, blk);
1702 p->num_blocks++;
1703 if (blockcnt >= 0)
1704 p->last_block = blockcnt;
1705mark_dir:
1706 if (p->is_dir && (blockcnt >= 0)) {
1707 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
1708 blk, blockcnt);
1709 if (pctx->errcode) {
1710 pctx->blk = blk;
1711 pctx->num = blockcnt;
1712 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
1713 /* Should never get here */
1714 ctx->flags |= E2F_FLAG_ABORT;
1715 return BLOCK_ABORT;
1716 }
1717 }
1718 return ret_code;
1719}
1720
1721static int process_bad_block(ext2_filsys fs,
1722 blk_t *block_nr,
1723 e2_blkcnt_t blockcnt,
1724 blk_t ref_block EXT2FS_ATTR((unused)),
1725 int ref_offset EXT2FS_ATTR((unused)),
1726 void *priv_data)
1727{
1728 struct process_block_struct *p;
1729 blk_t blk = *block_nr;
1730 blk_t first_block;
1731 dgrp_t i;
1732 struct problem_context *pctx;
1733 e2fsck_t ctx;
1734
1735 /*
1736 * Note: This function processes blocks for the bad blocks
1737 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
1738 */
1739
1740 if (!blk)
1741 return 0;
1742
1743 p = (struct process_block_struct *) priv_data;
1744 ctx = p->ctx;
1745 pctx = p->pctx;
1746
1747 pctx->ino = EXT2_BAD_INO;
1748 pctx->blk = blk;
1749 pctx->blkcount = blockcnt;
1750
1751 if ((blk < fs->super->s_first_data_block) ||
1752 (blk >= fs->super->s_blocks_count)) {
1753 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
1754 *block_nr = 0;
1755 return BLOCK_CHANGED;
1756 } else
1757 return 0;
1758 }
1759
1760 if (blockcnt < 0) {
1761 if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) {
1762 p->bbcheck = 1;
1763 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
1764 *block_nr = 0;
1765 return BLOCK_CHANGED;
1766 }
1767 } else if (ext2fs_test_block_bitmap(ctx->block_found_map,
1768 blk)) {
1769 p->bbcheck = 1;
1770 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
1771 pctx)) {
1772 *block_nr = 0;
1773 return BLOCK_CHANGED;
1774 }
1775 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1776 return BLOCK_ABORT;
1777 } else
1778 mark_block_used(ctx, blk);
1779 return 0;
1780 }
1781#if 0
1782 printf ("DEBUG: Marking %u as bad.\n", blk);
1783#endif
1784 ctx->fs_badblocks_count++;
1785 /*
1786 * If the block is not used, then mark it as used and return.
1787 * If it is already marked as found, this must mean that
1788 * there's an overlap between the filesystem table blocks
1789 * (bitmaps and inode table) and the bad block list.
1790 */
1791 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
1792 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
1793 return 0;
1794 }
1795 /*
1796 * Try to find the where the filesystem block was used...
1797 */
1798 first_block = fs->super->s_first_data_block;
1799
1800 for (i = 0; i < fs->group_desc_count; i++ ) {
1801 pctx->group = i;
1802 pctx->blk = blk;
1803 if (!ext2fs_bg_has_super(fs, i))
1804 goto skip_super;
1805 if (blk == first_block) {
1806 if (i == 0) {
1807 if (fix_problem(ctx,
1808 PR_1_BAD_PRIMARY_SUPERBLOCK,
1809 pctx)) {
1810 *block_nr = 0;
1811 return BLOCK_CHANGED;
1812 }
1813 return 0;
1814 }
1815 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
1816 return 0;
1817 }
1818 if ((blk > first_block) &&
1819 (blk <= first_block + fs->desc_blocks)) {
1820 if (i == 0) {
1821 pctx->blk = *block_nr;
1822 if (fix_problem(ctx,
1823 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
1824 *block_nr = 0;
1825 return BLOCK_CHANGED;
1826 }
1827 return 0;
1828 }
1829 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
1830 return 0;
1831 }
1832 skip_super:
1833 if (blk == fs->group_desc[i].bg_block_bitmap) {
1834 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
1835 ctx->invalid_block_bitmap_flag[i]++;
1836 ctx->invalid_bitmaps++;
1837 }
1838 return 0;
1839 }
1840 if (blk == fs->group_desc[i].bg_inode_bitmap) {
1841 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
1842 ctx->invalid_inode_bitmap_flag[i]++;
1843 ctx->invalid_bitmaps++;
1844 }
1845 return 0;
1846 }
1847 if ((blk >= fs->group_desc[i].bg_inode_table) &&
1848 (blk < (fs->group_desc[i].bg_inode_table +
1849 fs->inode_blocks_per_group))) {
1850 /*
1851 * If there are bad blocks in the inode table,
1852 * the inode scan code will try to do
1853 * something reasonable automatically.
1854 */
1855 return 0;
1856 }
1857 first_block += fs->super->s_blocks_per_group;
1858 }
1859 /*
1860 * If we've gotten to this point, then the only
1861 * possibility is that the bad block inode meta data
1862 * is using a bad block.
1863 */
1864 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
1865 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
1866 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
1867 p->bbcheck = 1;
1868 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
1869 *block_nr = 0;
1870 return BLOCK_CHANGED;
1871 }
1872 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1873 return BLOCK_ABORT;
1874 return 0;
1875 }
1876
1877 pctx->group = -1;
1878
1879 /* Warn user that the block wasn't claimed */
1880 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
1881
1882 return 0;
1883}
1884
1885static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
1886 const char *name, int num, blk_t *new_block)
1887{
1888 ext2_filsys fs = ctx->fs;
1889 blk_t old_block = *new_block;
1890 int i;
1891 char *buf;
1892 struct problem_context pctx;
1893
1894 clear_problem_context(&pctx);
1895
1896 pctx.group = group;
1897 pctx.blk = old_block;
1898 pctx.str = name;
1899
1900 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
1901 first_block + fs->super->s_blocks_per_group,
1902 num, ctx->block_found_map, new_block);
1903 if (pctx.errcode) {
1904 pctx.num = num;
1905 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
1906 ext2fs_unmark_valid(fs);
1907 return;
1908 }
1909 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
1910 if (pctx.errcode) {
1911 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
1912 ext2fs_unmark_valid(fs);
1913 return;
1914 }
1915 ext2fs_mark_super_dirty(fs);
1916 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
1917 pctx.blk2 = *new_block;
1918 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
1919 PR_1_RELOC_TO), &pctx);
1920 pctx.blk2 = 0;
1921 for (i = 0; i < num; i++) {
1922 pctx.blk = i;
1923 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
1924 if (old_block) {
1925 pctx.errcode = io_channel_read_blk(fs->io,
1926 old_block + i, 1, buf);
1927 if (pctx.errcode)
1928 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
1929 } else
1930 memset(buf, 0, fs->blocksize);
1931
1932 pctx.blk = (*new_block) + i;
1933 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
1934 1, buf);
1935 if (pctx.errcode)
1936 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
1937 }
1938 ext2fs_free_mem(&buf);
1939}
1940
1941/*
1942 * This routine gets called at the end of pass 1 if bad blocks are
1943 * detected in the superblock, group descriptors, inode_bitmaps, or
1944 * block bitmaps. At this point, all of the blocks have been mapped
1945 * out, so we can try to allocate new block(s) to replace the bad
1946 * blocks.
1947 */
1948static void handle_fs_bad_blocks(e2fsck_t ctx)
1949{
1950 ext2_filsys fs = ctx->fs;
1951 dgrp_t i;
1952 int first_block = fs->super->s_first_data_block;
1953
1954 for (i = 0; i < fs->group_desc_count; i++) {
1955 if (ctx->invalid_block_bitmap_flag[i]) {
1956 new_table_block(ctx, first_block, i, _("block bitmap"),
1957 1, &fs->group_desc[i].bg_block_bitmap);
1958 }
1959 if (ctx->invalid_inode_bitmap_flag[i]) {
1960 new_table_block(ctx, first_block, i, _("inode bitmap"),
1961 1, &fs->group_desc[i].bg_inode_bitmap);
1962 }
1963 if (ctx->invalid_inode_table_flag[i]) {
1964 new_table_block(ctx, first_block, i, _("inode table"),
1965 fs->inode_blocks_per_group,
1966 &fs->group_desc[i].bg_inode_table);
1967 ctx->flags |= E2F_FLAG_RESTART;
1968 }
1969 first_block += fs->super->s_blocks_per_group;
1970 }
1971 ctx->invalid_bitmaps = 0;
1972}
1973
1974/*
1975 * This routine marks all blocks which are used by the superblock,
1976 * group descriptors, inode bitmaps, and block bitmaps.
1977 */
1978static void mark_table_blocks(e2fsck_t ctx)
1979{
1980 ext2_filsys fs = ctx->fs;
1981 blk_t block, b;
1982 dgrp_t i;
1983 int j;
1984 struct problem_context pctx;
1985
1986 clear_problem_context(&pctx);
1987
1988 block = fs->super->s_first_data_block;
1989 for (i = 0; i < fs->group_desc_count; i++) {
1990 pctx.group = i;
1991
1992 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
1993
1994 /*
1995 * Mark the blocks used for the inode table
1996 */
1997 if (fs->group_desc[i].bg_inode_table) {
1998 for (j = 0, b = fs->group_desc[i].bg_inode_table;
1999 j < fs->inode_blocks_per_group;
2000 j++, b++) {
2001 if (ext2fs_test_block_bitmap(ctx->block_found_map,
2002 b)) {
2003 pctx.blk = b;
2004 if (fix_problem(ctx,
2005 PR_1_ITABLE_CONFLICT, &pctx)) {
2006 ctx->invalid_inode_table_flag[i]++;
2007 ctx->invalid_bitmaps++;
2008 }
2009 } else {
2010 ext2fs_mark_block_bitmap(ctx->block_found_map,
2011 b);
2012 }
2013 }
2014 }
2015
2016 /*
2017 * Mark block used for the block bitmap
2018 */
2019 if (fs->group_desc[i].bg_block_bitmap) {
2020 if (ext2fs_test_block_bitmap(ctx->block_found_map,
2021 fs->group_desc[i].bg_block_bitmap)) {
2022 pctx.blk = fs->group_desc[i].bg_block_bitmap;
2023 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
2024 ctx->invalid_block_bitmap_flag[i]++;
2025 ctx->invalid_bitmaps++;
2026 }
2027 } else {
2028 ext2fs_mark_block_bitmap(ctx->block_found_map,
2029 fs->group_desc[i].bg_block_bitmap);
2030 }
2031
2032 }
2033 /*
2034 * Mark block used for the inode bitmap
2035 */
2036 if (fs->group_desc[i].bg_inode_bitmap) {
2037 if (ext2fs_test_block_bitmap(ctx->block_found_map,
2038 fs->group_desc[i].bg_inode_bitmap)) {
2039 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
2040 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
2041 ctx->invalid_inode_bitmap_flag[i]++;
2042 ctx->invalid_bitmaps++;
2043 }
2044 } else {
2045 ext2fs_mark_block_bitmap(ctx->block_found_map,
2046 fs->group_desc[i].bg_inode_bitmap);
2047 }
2048 }
2049 block += fs->super->s_blocks_per_group;
2050 }
2051}
2052
2053/*
2054 * Thes subroutines short circuits ext2fs_get_blocks and
2055 * ext2fs_check_directory; we use them since we already have the inode
2056 * structure, so there's no point in letting the ext2fs library read
2057 * the inode again.
2058 */
2059static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
2060 blk_t *blocks)
2061{
2062 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
2063 int i;
2064
2065 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
2066 return EXT2_ET_CALLBACK_NOTHANDLED;
2067
2068 for (i=0; i < EXT2_N_BLOCKS; i++)
2069 blocks[i] = ctx->stashed_inode->i_block[i];
2070 return 0;
2071}
2072
2073static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
2074 struct ext2_inode *inode)
2075{
2076 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
2077
2078 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
2079 return EXT2_ET_CALLBACK_NOTHANDLED;
2080 *inode = *ctx->stashed_inode;
2081 return 0;
2082}
2083
2084static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
2085 struct ext2_inode *inode)
2086{
2087 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
2088
2089 if ((ino == ctx->stashed_ino) && ctx->stashed_inode)
2090 *ctx->stashed_inode = *inode;
2091 return EXT2_ET_CALLBACK_NOTHANDLED;
2092}
2093
2094static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
2095{
2096 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
2097
2098 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
2099 return EXT2_ET_CALLBACK_NOTHANDLED;
2100
2101 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
2102 return EXT2_ET_NO_DIRECTORY;
2103 return 0;
2104}
2105
2106void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
2107{
2108 ext2_filsys fs = ctx->fs;
2109
2110 if (bool) {
2111 fs->get_blocks = pass1_get_blocks;
2112 fs->check_directory = pass1_check_directory;
2113 fs->read_inode = pass1_read_inode;
2114 fs->write_inode = pass1_write_inode;
2115 ctx->stashed_ino = 0;
2116 } else {
2117 fs->get_blocks = 0;
2118 fs->check_directory = 0;
2119 fs->read_inode = 0;
2120 fs->write_inode = 0;
2121 }
2122}
diff --git a/e2fsprogs/e2fsck/pass1b.c b/e2fsprogs/e2fsck/pass1b.c
deleted file mode 100644
index ff63807b7..000000000
--- a/e2fsprogs/e2fsck/pass1b.c
+++ /dev/null
@@ -1,805 +0,0 @@
1/*
2 * pass1b.c --- Pass #1b of e2fsck
3 *
4 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are
5 * only invoked if pass 1 discovered blocks which are in use by more
6 * than one inode.
7 *
8 * Pass1B scans the data blocks of all the inodes again, generating a
9 * complete list of duplicate blocks and which inodes have claimed
10 * them.
11 *
12 * Pass1C does a tree-traversal of the filesystem, to determine the
13 * parent directories of these inodes. This step is necessary so that
14 * e2fsck can print out the pathnames of affected inodes.
15 *
16 * Pass1D is a reconciliation pass. For each inode with duplicate
17 * blocks, the user is prompted if s/he would like to clone the file
18 * (so that the file gets a fresh copy of the duplicated blocks) or
19 * simply to delete the file.
20 *
21 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
22 *
23 * %Begin-Header%
24 * This file may be redistributed under the terms of the GNU Public
25 * License.
26 * %End-Header%
27 *
28 */
29
30#include <time.h>
31#ifdef HAVE_ERRNO_H
32#include <errno.h>
33#endif
34
35#ifdef HAVE_INTTYPES_H
36#include <inttypes.h>
37#endif
38
39/* Needed for architectures where sizeof(int) != sizeof(void *) */
40#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
41#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr))
42
43#include "e2fsck.h"
44
45#include "problem.h"
46#include "dict.h"
47
48/* Define an extension to the ext2 library's block count information */
49#define BLOCK_COUNT_EXTATTR (-5)
50
51struct block_el {
52 blk_t block;
53 struct block_el *next;
54};
55
56struct inode_el {
57 ext2_ino_t inode;
58 struct inode_el *next;
59};
60
61struct dup_block {
62 int num_bad;
63 struct inode_el *inode_list;
64};
65
66/*
67 * This structure stores information about a particular inode which
68 * is sharing blocks with other inodes. This information is collected
69 * to display to the user, so that the user knows what files he or she
70 * is dealing with, when trying to decide how to resolve the conflict
71 * of multiply-claimed blocks.
72 */
73struct dup_inode {
74 ext2_ino_t dir;
75 int num_dupblocks;
76 struct ext2_inode inode;
77 struct block_el *block_list;
78};
79
80static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
81 e2_blkcnt_t blockcnt, blk_t ref_blk,
82 int ref_offset, void *priv_data);
83static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
84 struct dup_inode *dp, char *block_buf);
85static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
86 struct dup_inode *dp, char* block_buf);
87static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
88
89static void pass1b(e2fsck_t ctx, char *block_buf);
90static void pass1c(e2fsck_t ctx, char *block_buf);
91static void pass1d(e2fsck_t ctx, char *block_buf);
92
93static int dup_inode_count = 0;
94
95static dict_t blk_dict, ino_dict;
96
97static ext2fs_inode_bitmap inode_dup_map;
98
99static int dict_int_cmp(const void *a, const void *b)
100{
101 intptr_t ia, ib;
102
103 ia = (intptr_t)a;
104 ib = (intptr_t)b;
105
106 return (ia-ib);
107}
108
109/*
110 * Add a duplicate block record
111 */
112static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
113 struct ext2_inode *inode)
114{
115 dnode_t *n;
116 struct dup_block *db;
117 struct dup_inode *di;
118 struct block_el *blk_el;
119 struct inode_el *ino_el;
120
121 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
122 if (n)
123 db = (struct dup_block *) dnode_get(n);
124 else {
125 db = (struct dup_block *) e2fsck_allocate_memory(ctx,
126 sizeof(struct dup_block), "duplicate block header");
127 db->num_bad = 0;
128 db->inode_list = 0;
129 dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
130 }
131 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
132 sizeof(struct inode_el), "inode element");
133 ino_el->inode = ino;
134 ino_el->next = db->inode_list;
135 db->inode_list = ino_el;
136 db->num_bad++;
137
138 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
139 if (n)
140 di = (struct dup_inode *) dnode_get(n);
141 else {
142 di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
143 sizeof(struct dup_inode), "duplicate inode header");
144 di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
145 di->num_dupblocks = 0;
146 di->block_list = 0;
147 di->inode = *inode;
148 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
149 }
150 blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
151 sizeof(struct block_el), "block element");
152 blk_el->block = blk;
153 blk_el->next = di->block_list;
154 di->block_list = blk_el;
155 di->num_dupblocks++;
156}
157
158/*
159 * Free a duplicate inode record
160 */
161static void inode_dnode_free(dnode_t *node,
162 void *context EXT2FS_ATTR((unused)))
163{
164 struct dup_inode *di;
165 struct block_el *p, *next;
166
167 di = (struct dup_inode *) dnode_get(node);
168 for (p = di->block_list; p; p = next) {
169 next = p->next;
170 free(p);
171 }
172 free(node);
173}
174
175/*
176 * Free a duplicate block record
177 */
178static void block_dnode_free(dnode_t *node,
179 void *context EXT2FS_ATTR((unused)))
180{
181 struct dup_block *db;
182 struct inode_el *p, *next;
183
184 db = (struct dup_block *) dnode_get(node);
185 for (p = db->inode_list; p; p = next) {
186 next = p->next;
187 free(p);
188 }
189 free(node);
190}
191
192
193/*
194 * Main procedure for handling duplicate blocks
195 */
196void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
197{
198 ext2_filsys fs = ctx->fs;
199 struct problem_context pctx;
200
201 clear_problem_context(&pctx);
202
203 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
204 _("multiply claimed inode map"), &inode_dup_map);
205 if (pctx.errcode) {
206 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
207 ctx->flags |= E2F_FLAG_ABORT;
208 return;
209 }
210
211 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
212 dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
213 dict_set_allocator(&ino_dict, NULL, inode_dnode_free, NULL);
214 dict_set_allocator(&blk_dict, NULL, block_dnode_free, NULL);
215
216 pass1b(ctx, block_buf);
217 pass1c(ctx, block_buf);
218 pass1d(ctx, block_buf);
219
220 /*
221 * Time to free all of the accumulated data structures that we
222 * don't need anymore.
223 */
224 dict_free_nodes(&ino_dict);
225 dict_free_nodes(&blk_dict);
226}
227
228/*
229 * Scan the inodes looking for inodes that contain duplicate blocks.
230 */
231struct process_block_struct {
232 e2fsck_t ctx;
233 ext2_ino_t ino;
234 int dup_blocks;
235 struct ext2_inode *inode;
236 struct problem_context *pctx;
237};
238
239static void pass1b(e2fsck_t ctx, char *block_buf)
240{
241 ext2_filsys fs = ctx->fs;
242 ext2_ino_t ino;
243 struct ext2_inode inode;
244 ext2_inode_scan scan;
245 struct process_block_struct pb;
246 struct problem_context pctx;
247
248 clear_problem_context(&pctx);
249
250 if (!(ctx->options & E2F_OPT_PREEN))
251 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
252 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
253 &scan);
254 if (pctx.errcode) {
255 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
256 ctx->flags |= E2F_FLAG_ABORT;
257 return;
258 }
259 ctx->stashed_inode = &inode;
260 pb.ctx = ctx;
261 pb.pctx = &pctx;
262 pctx.str = "pass1b";
263 while (1) {
264 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
265 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
266 continue;
267 if (pctx.errcode) {
268 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
269 ctx->flags |= E2F_FLAG_ABORT;
270 return;
271 }
272 if (!ino)
273 break;
274 pctx.ino = ctx->stashed_ino = ino;
275 if ((ino != EXT2_BAD_INO) &&
276 !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
277 continue;
278
279 pb.ino = ino;
280 pb.dup_blocks = 0;
281 pb.inode = &inode;
282
283 if (ext2fs_inode_has_valid_blocks(&inode) ||
284 (ino == EXT2_BAD_INO))
285 pctx.errcode = ext2fs_block_iterate2(fs, ino,
286 0, block_buf, process_pass1b_block, &pb);
287 if (inode.i_file_acl)
288 process_pass1b_block(fs, &inode.i_file_acl,
289 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
290 if (pb.dup_blocks) {
291 end_problem_latch(ctx, PR_LATCH_DBLOCK);
292 if (ino >= EXT2_FIRST_INODE(fs->super) ||
293 ino == EXT2_ROOT_INO)
294 dup_inode_count++;
295 }
296 if (pctx.errcode)
297 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
298 }
299 ext2fs_close_inode_scan(scan);
300 e2fsck_use_inode_shortcuts(ctx, 0);
301}
302
303static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
304 blk_t *block_nr,
305 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
306 blk_t ref_blk EXT2FS_ATTR((unused)),
307 int ref_offset EXT2FS_ATTR((unused)),
308 void *priv_data)
309{
310 struct process_block_struct *p;
311 e2fsck_t ctx;
312
313 if (HOLE_BLKADDR(*block_nr))
314 return 0;
315 p = (struct process_block_struct *) priv_data;
316 ctx = p->ctx;
317
318 if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
319 return 0;
320
321 /* OK, this is a duplicate block */
322 if (p->ino != EXT2_BAD_INO) {
323 p->pctx->blk = *block_nr;
324 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
325 }
326 p->dup_blocks++;
327 ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
328
329 add_dupe(ctx, p->ino, *block_nr, p->inode);
330
331 return 0;
332}
333
334/*
335 * Pass 1c: Scan directories for inodes with duplicate blocks. This
336 * is used so that we can print pathnames when prompting the user for
337 * what to do.
338 */
339struct search_dir_struct {
340 int count;
341 ext2_ino_t first_inode;
342 ext2_ino_t max_inode;
343};
344
345static int search_dirent_proc(ext2_ino_t dir, int entry,
346 struct ext2_dir_entry *dirent,
347 int offset EXT2FS_ATTR((unused)),
348 int blocksize EXT2FS_ATTR((unused)),
349 char *buf EXT2FS_ATTR((unused)),
350 void *priv_data)
351{
352 struct search_dir_struct *sd;
353 struct dup_inode *p;
354 dnode_t *n;
355
356 sd = (struct search_dir_struct *) priv_data;
357
358 if (dirent->inode > sd->max_inode)
359 /* Should abort this inode, but not everything */
360 return 0;
361
362 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
363 !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
364 return 0;
365
366 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
367 if (!n)
368 return 0;
369 p = (struct dup_inode *) dnode_get(n);
370 p->dir = dir;
371 sd->count--;
372
373 return(sd->count ? 0 : DIRENT_ABORT);
374}
375
376
377static void pass1c(e2fsck_t ctx, char *block_buf)
378{
379 ext2_filsys fs = ctx->fs;
380 struct search_dir_struct sd;
381 struct problem_context pctx;
382
383 clear_problem_context(&pctx);
384
385 if (!(ctx->options & E2F_OPT_PREEN))
386 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
387
388 /*
389 * Search through all directories to translate inodes to names
390 * (by searching for the containing directory for that inode.)
391 */
392 sd.count = dup_inode_count;
393 sd.first_inode = EXT2_FIRST_INODE(fs->super);
394 sd.max_inode = fs->super->s_inodes_count;
395 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
396 search_dirent_proc, &sd);
397}
398
399static void pass1d(e2fsck_t ctx, char *block_buf)
400{
401 ext2_filsys fs = ctx->fs;
402 struct dup_inode *p, *t;
403 struct dup_block *q;
404 ext2_ino_t *shared, ino;
405 int shared_len;
406 int i;
407 int file_ok;
408 int meta_data = 0;
409 struct problem_context pctx;
410 dnode_t *n, *m;
411 struct block_el *s;
412 struct inode_el *r;
413
414 clear_problem_context(&pctx);
415
416 if (!(ctx->options & E2F_OPT_PREEN))
417 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
418 e2fsck_read_bitmaps(ctx);
419
420 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
421 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
422 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
423 sizeof(ext2_ino_t) * dict_count(&ino_dict),
424 "Shared inode list");
425 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
426 p = (struct dup_inode *) dnode_get(n);
427 shared_len = 0;
428 file_ok = 1;
429 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
430 if (ino == EXT2_BAD_INO)
431 continue;
432
433 /*
434 * Find all of the inodes which share blocks with this
435 * one. First we find all of the duplicate blocks
436 * belonging to this inode, and then search each block
437 * get the list of inodes, and merge them together.
438 */
439 for (s = p->block_list; s; s = s->next) {
440 m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
441 if (!m)
442 continue; /* Should never happen... */
443 q = (struct dup_block *) dnode_get(m);
444 if (q->num_bad > 1)
445 file_ok = 0;
446 if (check_if_fs_block(ctx, s->block)) {
447 file_ok = 0;
448 meta_data = 1;
449 }
450
451 /*
452 * Add all inodes used by this block to the
453 * shared[] --- which is a unique list, so
454 * if an inode is already in shared[], don't
455 * add it again.
456 */
457 for (r = q->inode_list; r; r = r->next) {
458 if (r->inode == ino)
459 continue;
460 for (i = 0; i < shared_len; i++)
461 if (shared[i] == r->inode)
462 break;
463 if (i == shared_len) {
464 shared[shared_len++] = r->inode;
465 }
466 }
467 }
468
469 /*
470 * Report the inode that we are working on
471 */
472 pctx.inode = &p->inode;
473 pctx.ino = ino;
474 pctx.dir = p->dir;
475 pctx.blkcount = p->num_dupblocks;
476 pctx.num = meta_data ? shared_len+1 : shared_len;
477 fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
478 pctx.blkcount = 0;
479 pctx.num = 0;
480
481 if (meta_data)
482 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
483
484 for (i = 0; i < shared_len; i++) {
485 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
486 if (!m)
487 continue; /* should never happen */
488 t = (struct dup_inode *) dnode_get(m);
489 /*
490 * Report the inode that we are sharing with
491 */
492 pctx.inode = &t->inode;
493 pctx.ino = shared[i];
494 pctx.dir = t->dir;
495 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
496 }
497 if (file_ok) {
498 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
499 continue;
500 }
501 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
502 pctx.errcode = clone_file(ctx, ino, p, block_buf);
503 if (pctx.errcode)
504 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
505 else
506 continue;
507 }
508 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
509 delete_file(ctx, ino, p, block_buf);
510 else
511 ext2fs_unmark_valid(fs);
512 }
513 ext2fs_free_mem(&shared);
514}
515
516/*
517 * Drop the refcount on the dup_block structure, and clear the entry
518 * in the block_dup_map if appropriate.
519 */
520static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
521{
522 p->num_bad--;
523 if (p->num_bad <= 0 ||
524 (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
525 ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
526}
527
528static int delete_file_block(ext2_filsys fs,
529 blk_t *block_nr,
530 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
531 blk_t ref_block EXT2FS_ATTR((unused)),
532 int ref_offset EXT2FS_ATTR((unused)),
533 void *priv_data)
534{
535 struct process_block_struct *pb;
536 struct dup_block *p;
537 dnode_t *n;
538 e2fsck_t ctx;
539
540 pb = (struct process_block_struct *) priv_data;
541 ctx = pb->ctx;
542
543 if (HOLE_BLKADDR(*block_nr))
544 return 0;
545
546 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
547 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
548 if (n) {
549 p = (struct dup_block *) dnode_get(n);
550 decrement_badcount(ctx, *block_nr, p);
551 } else
552 com_err("delete_file_block", 0,
553 _("internal error; can't find dup_blk for %d\n"),
554 *block_nr);
555 } else {
556 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
557 ext2fs_block_alloc_stats(fs, *block_nr, -1);
558 }
559
560 return 0;
561}
562
563static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
564 struct dup_inode *dp, char* block_buf)
565{
566 ext2_filsys fs = ctx->fs;
567 struct process_block_struct pb;
568 struct ext2_inode inode;
569 struct problem_context pctx;
570 unsigned int count;
571
572 clear_problem_context(&pctx);
573 pctx.ino = pb.ino = ino;
574 pb.dup_blocks = dp->num_dupblocks;
575 pb.ctx = ctx;
576 pctx.str = "delete_file";
577
578 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
579 if (ext2fs_inode_has_valid_blocks(&inode))
580 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
581 delete_file_block, &pb);
582 if (pctx.errcode)
583 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
584 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
585 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
586 if (ctx->inode_bad_map)
587 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
588 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
589
590 /* Inode may have changed by block_iterate, so reread it */
591 e2fsck_read_inode(ctx, ino, &inode, "delete_file");
592 inode.i_links_count = 0;
593 inode.i_dtime = time(0);
594 if (inode.i_file_acl &&
595 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
596 count = 1;
597 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
598 block_buf, -1, &count);
599 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
600 pctx.errcode = 0;
601 count = 1;
602 }
603 if (pctx.errcode) {
604 pctx.blk = inode.i_file_acl;
605 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
606 }
607 /*
608 * If the count is zero, then arrange to have the
609 * block deleted. If the block is in the block_dup_map,
610 * also call delete_file_block since it will take care
611 * of keeping the accounting straight.
612 */
613 if ((count == 0) ||
614 ext2fs_test_block_bitmap(ctx->block_dup_map,
615 inode.i_file_acl))
616 delete_file_block(fs, &inode.i_file_acl,
617 BLOCK_COUNT_EXTATTR, 0, 0, &pb);
618 }
619 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
620}
621
622struct clone_struct {
623 errcode_t errcode;
624 ext2_ino_t dir;
625 char *buf;
626 e2fsck_t ctx;
627};
628
629static int clone_file_block(ext2_filsys fs,
630 blk_t *block_nr,
631 e2_blkcnt_t blockcnt,
632 blk_t ref_block EXT2FS_ATTR((unused)),
633 int ref_offset EXT2FS_ATTR((unused)),
634 void *priv_data)
635{
636 struct dup_block *p;
637 blk_t new_block;
638 errcode_t retval;
639 struct clone_struct *cs = (struct clone_struct *) priv_data;
640 dnode_t *n;
641 e2fsck_t ctx;
642
643 ctx = cs->ctx;
644
645 if (HOLE_BLKADDR(*block_nr))
646 return 0;
647
648 if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
649 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
650 if (n) {
651 p = (struct dup_block *) dnode_get(n);
652 retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
653 &new_block);
654 if (retval) {
655 cs->errcode = retval;
656 return BLOCK_ABORT;
657 }
658 if (cs->dir && (blockcnt >= 0)) {
659 retval = ext2fs_set_dir_block(fs->dblist,
660 cs->dir, new_block, blockcnt);
661 if (retval) {
662 cs->errcode = retval;
663 return BLOCK_ABORT;
664 }
665 }
666#if 0
667 printf("Cloning block %u to %u\n", *block_nr,
668 new_block);
669#endif
670 retval = io_channel_read_blk(fs->io, *block_nr, 1,
671 cs->buf);
672 if (retval) {
673 cs->errcode = retval;
674 return BLOCK_ABORT;
675 }
676 retval = io_channel_write_blk(fs->io, new_block, 1,
677 cs->buf);
678 if (retval) {
679 cs->errcode = retval;
680 return BLOCK_ABORT;
681 }
682 decrement_badcount(ctx, *block_nr, p);
683 *block_nr = new_block;
684 ext2fs_mark_block_bitmap(ctx->block_found_map,
685 new_block);
686 ext2fs_mark_block_bitmap(fs->block_map, new_block);
687 return BLOCK_CHANGED;
688 } else
689 com_err("clone_file_block", 0,
690 _("internal error; can't find dup_blk for %d\n"),
691 *block_nr);
692 }
693 return 0;
694}
695
696static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
697 struct dup_inode *dp, char* block_buf)
698{
699 ext2_filsys fs = ctx->fs;
700 errcode_t retval;
701 struct clone_struct cs;
702 struct problem_context pctx;
703 blk_t blk;
704 dnode_t *n;
705 struct inode_el *ino_el;
706 struct dup_block *db;
707 struct dup_inode *di;
708
709 clear_problem_context(&pctx);
710 cs.errcode = 0;
711 cs.dir = 0;
712 cs.ctx = ctx;
713 retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
714 if (retval)
715 return retval;
716
717 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
718 cs.dir = ino;
719
720 pctx.ino = ino;
721 pctx.str = "clone_file";
722 if (ext2fs_inode_has_valid_blocks(&dp->inode))
723 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
724 clone_file_block, &cs);
725 ext2fs_mark_bb_dirty(fs);
726 if (pctx.errcode) {
727 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
728 retval = pctx.errcode;
729 goto errout;
730 }
731 if (cs.errcode) {
732 com_err("clone_file", cs.errcode,
733 _("returned from clone_file_block"));
734 retval = cs.errcode;
735 goto errout;
736 }
737 /* The inode may have changed on disk, so we have to re-read it */
738 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
739 blk = dp->inode.i_file_acl;
740 if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
741 BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
742 BLOCK_CHANGED)) {
743 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
744 /*
745 * If we cloned the EA block, find all other inodes
746 * which refered to that EA block, and modify
747 * them to point to the new EA block.
748 */
749 n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
750 db = (struct dup_block *) dnode_get(n);
751 for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
752 if (ino_el->inode == ino)
753 continue;
754 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
755 di = (struct dup_inode *) dnode_get(n);
756 if (di->inode.i_file_acl == blk) {
757 di->inode.i_file_acl = dp->inode.i_file_acl;
758 e2fsck_write_inode(ctx, ino_el->inode,
759 &di->inode, "clone file EA");
760 decrement_badcount(ctx, blk, db);
761 }
762 }
763 }
764 retval = 0;
765errout:
766 ext2fs_free_mem(&cs.buf);
767 return retval;
768}
769
770/*
771 * This routine returns 1 if a block overlaps with one of the superblocks,
772 * group descriptors, inode bitmaps, or block bitmaps.
773 */
774static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
775{
776 ext2_filsys fs = ctx->fs;
777 blk_t block;
778 dgrp_t i;
779
780 block = fs->super->s_first_data_block;
781 for (i = 0; i < fs->group_desc_count; i++) {
782
783 /* Check superblocks/block group descriptros */
784 if (ext2fs_bg_has_super(fs, i)) {
785 if (test_block >= block &&
786 (test_block <= block + fs->desc_blocks))
787 return 1;
788 }
789
790 /* Check the inode table */
791 if ((fs->group_desc[i].bg_inode_table) &&
792 (test_block >= fs->group_desc[i].bg_inode_table) &&
793 (test_block < (fs->group_desc[i].bg_inode_table +
794 fs->inode_blocks_per_group)))
795 return 1;
796
797 /* Check the bitmap blocks */
798 if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
799 (test_block == fs->group_desc[i].bg_inode_bitmap))
800 return 1;
801
802 block += fs->super->s_blocks_per_group;
803 }
804 return 0;
805}
diff --git a/e2fsprogs/e2fsck/pass2.c b/e2fsprogs/e2fsck/pass2.c
deleted file mode 100644
index 69599fffc..000000000
--- a/e2fsprogs/e2fsck/pass2.c
+++ /dev/null
@@ -1,1414 +0,0 @@
1/*
2 * pass2.c --- check directory structure
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * Pass 2 of e2fsck iterates through all active directory inodes, and
12 * applies to following tests to each directory entry in the directory
13 * blocks in the inodes:
14 *
15 * - The length of the directory entry (rec_len) should be at
16 * least 8 bytes, and no more than the remaining space
17 * left in the directory block.
18 * - The length of the name in the directory entry (name_len)
19 * should be less than (rec_len - 8).
20 * - The inode number in the directory entry should be within
21 * legal bounds.
22 * - The inode number should refer to a in-use inode.
23 * - The first entry should be '.', and its inode should be
24 * the inode of the directory.
25 * - The second entry should be '..'.
26 *
27 * To minimize disk seek time, the directory blocks are processed in
28 * sorted order of block numbers.
29 *
30 * Pass 2 also collects the following information:
31 * - The inode numbers of the subdirectories for each directory.
32 *
33 * Pass 2 relies on the following information from previous passes:
34 * - The directory information collected in pass 1.
35 * - The inode_used_map bitmap
36 * - The inode_bad_map bitmap
37 * - The inode_dir_map bitmap
38 *
39 * Pass 2 frees the following data structures
40 * - The inode_bad_map bitmap
41 * - The inode_reg_map bitmap
42 */
43
44#define _GNU_SOURCE 1 /* get strnlen() */
45#include <string.h>
46
47#include "e2fsck.h"
48#include "problem.h"
49#include "dict.h"
50
51#ifdef NO_INLINE_FUNCS
52#define _INLINE_
53#else
54#define _INLINE_ inline
55#endif
56
57/* #define DX_DEBUG */
58
59/*
60 * Keeps track of how many times an inode is referenced.
61 */
62static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
63static int check_dir_block(ext2_filsys fs,
64 struct ext2_db_entry *dir_blocks_info,
65 void *priv_data);
66static int allocate_dir_block(e2fsck_t ctx,
67 struct ext2_db_entry *dir_blocks_info,
68 char *buf, struct problem_context *pctx);
69static int update_dir_block(ext2_filsys fs,
70 blk_t *block_nr,
71 e2_blkcnt_t blockcnt,
72 blk_t ref_block,
73 int ref_offset,
74 void *priv_data);
75static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
76static int htree_depth(struct dx_dir_info *dx_dir,
77 struct dx_dirblock_info *dx_db);
78static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
79
80struct check_dir_struct {
81 char *buf;
82 struct problem_context pctx;
83 int count, max;
84 e2fsck_t ctx;
85};
86
87void e2fsck_pass2(e2fsck_t ctx)
88{
89 struct ext2_super_block *sb = ctx->fs->super;
90 struct problem_context pctx;
91 ext2_filsys fs = ctx->fs;
92 char *buf;
93#ifdef RESOURCE_TRACK
94 struct resource_track rtrack;
95#endif
96 struct dir_info *dir;
97 struct check_dir_struct cd;
98 struct dx_dir_info *dx_dir;
99 struct dx_dirblock_info *dx_db, *dx_parent;
100 int b;
101 int i, depth;
102 problem_t code;
103 int bad_dir;
104
105#ifdef RESOURCE_TRACK
106 init_resource_track(&rtrack);
107#endif
108
109 clear_problem_context(&cd.pctx);
110
111#ifdef MTRACE
112 mtrace_print("Pass 2");
113#endif
114
115 if (!(ctx->options & E2F_OPT_PREEN))
116 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
117
118 cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT,
119 0, ctx->inode_link_info,
120 &ctx->inode_count);
121 if (cd.pctx.errcode) {
122 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
123 ctx->flags |= E2F_FLAG_ABORT;
124 return;
125 }
126 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
127 "directory scan buffer");
128
129 /*
130 * Set up the parent pointer for the root directory, if
131 * present. (If the root directory is not present, we will
132 * create it in pass 3.)
133 */
134 dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO);
135 if (dir)
136 dir->parent = EXT2_ROOT_INO;
137
138 cd.buf = buf;
139 cd.ctx = ctx;
140 cd.count = 1;
141 cd.max = ext2fs_dblist_count(fs->dblist);
142
143 if (ctx->progress)
144 (void) (ctx->progress)(ctx, 2, 0, cd.max);
145
146 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
147 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
148
149 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
150 &cd);
151 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
152 return;
153 if (cd.pctx.errcode) {
154 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
155 ctx->flags |= E2F_FLAG_ABORT;
156 return;
157 }
158
159#ifdef ENABLE_HTREE
160 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
161 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
162 return;
163 if (dx_dir->numblocks == 0)
164 continue;
165 clear_problem_context(&pctx);
166 bad_dir = 0;
167 pctx.dir = dx_dir->ino;
168 dx_db = dx_dir->dx_block;
169 if (dx_db->flags & DX_FLAG_REFERENCED)
170 dx_db->flags |= DX_FLAG_DUP_REF;
171 else
172 dx_db->flags |= DX_FLAG_REFERENCED;
173 /*
174 * Find all of the first and last leaf blocks, and
175 * update their parent's min and max hash values
176 */
177 for (b=0, dx_db = dx_dir->dx_block;
178 b < dx_dir->numblocks;
179 b++, dx_db++) {
180 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
181 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
182 continue;
183 dx_parent = &dx_dir->dx_block[dx_db->parent];
184 /*
185 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
186 */
187 if (dx_db->flags & DX_FLAG_FIRST)
188 dx_parent->min_hash = dx_db->min_hash;
189 /*
190 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
191 */
192 if (dx_db->flags & DX_FLAG_LAST)
193 dx_parent->max_hash = dx_db->max_hash;
194 }
195
196 for (b=0, dx_db = dx_dir->dx_block;
197 b < dx_dir->numblocks;
198 b++, dx_db++) {
199 pctx.blkcount = b;
200 pctx.group = dx_db->parent;
201 code = 0;
202 if (!(dx_db->flags & DX_FLAG_FIRST) &&
203 (dx_db->min_hash < dx_db->node_min_hash)) {
204 pctx.blk = dx_db->min_hash;
205 pctx.blk2 = dx_db->node_min_hash;
206 code = PR_2_HTREE_MIN_HASH;
207 fix_problem(ctx, code, &pctx);
208 bad_dir++;
209 }
210 if (dx_db->type == DX_DIRBLOCK_LEAF) {
211 depth = htree_depth(dx_dir, dx_db);
212 if (depth != dx_dir->depth) {
213 code = PR_2_HTREE_BAD_DEPTH;
214 fix_problem(ctx, code, &pctx);
215 bad_dir++;
216 }
217 }
218 /*
219 * This test doesn't apply for the root block
220 * at block #0
221 */
222 if (b &&
223 (dx_db->max_hash > dx_db->node_max_hash)) {
224 pctx.blk = dx_db->max_hash;
225 pctx.blk2 = dx_db->node_max_hash;
226 code = PR_2_HTREE_MAX_HASH;
227 fix_problem(ctx, code, &pctx);
228 bad_dir++;
229 }
230 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
231 code = PR_2_HTREE_NOTREF;
232 fix_problem(ctx, code, &pctx);
233 bad_dir++;
234 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
235 code = PR_2_HTREE_DUPREF;
236 fix_problem(ctx, code, &pctx);
237 bad_dir++;
238 }
239 if (code == 0)
240 continue;
241 }
242 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
243 clear_htree(ctx, dx_dir->ino);
244 dx_dir->numblocks = 0;
245 }
246 }
247#endif
248 ext2fs_free_mem(&buf);
249 ext2fs_free_dblist(fs->dblist);
250
251 if (ctx->inode_bad_map) {
252 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
253 ctx->inode_bad_map = 0;
254 }
255 if (ctx->inode_reg_map) {
256 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
257 ctx->inode_reg_map = 0;
258 }
259
260 clear_problem_context(&pctx);
261 if (ctx->large_files) {
262 if (!(sb->s_feature_ro_compat &
263 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
264 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
265 sb->s_feature_ro_compat |=
266 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
267 ext2fs_mark_super_dirty(fs);
268 }
269 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
270 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
271 ext2fs_update_dynamic_rev(fs);
272 ext2fs_mark_super_dirty(fs);
273 }
274 } else if (!ctx->large_files &&
275 (sb->s_feature_ro_compat &
276 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
277 if (fs->flags & EXT2_FLAG_RW) {
278 sb->s_feature_ro_compat &=
279 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
280 ext2fs_mark_super_dirty(fs);
281 }
282 }
283
284#ifdef RESOURCE_TRACK
285 if (ctx->options & E2F_OPT_TIME2) {
286 e2fsck_clear_progbar(ctx);
287 print_resource_track(_("Pass 2"), &rtrack);
288 }
289#endif
290}
291
292#define MAX_DEPTH 32000
293static int htree_depth(struct dx_dir_info *dx_dir,
294 struct dx_dirblock_info *dx_db)
295{
296 int depth = 0;
297
298 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
299 dx_db = &dx_dir->dx_block[dx_db->parent];
300 depth++;
301 }
302 return depth;
303}
304
305static int dict_de_cmp(const void *a, const void *b)
306{
307 const struct ext2_dir_entry *de_a, *de_b;
308 int a_len, b_len;
309
310 de_a = (const struct ext2_dir_entry *) a;
311 a_len = de_a->name_len & 0xFF;
312 de_b = (const struct ext2_dir_entry *) b;
313 b_len = de_b->name_len & 0xFF;
314
315 if (a_len != b_len)
316 return (a_len - b_len);
317
318 return strncmp(de_a->name, de_b->name, a_len);
319}
320
321/*
322 * This is special sort function that makes sure that directory blocks
323 * with a dirblock of zero are sorted to the beginning of the list.
324 * This guarantees that the root node of the htree directories are
325 * processed first, so we know what hash version to use.
326 */
327static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
328{
329 const struct ext2_db_entry *db_a =
330 (const struct ext2_db_entry *) a;
331 const struct ext2_db_entry *db_b =
332 (const struct ext2_db_entry *) b;
333
334 if (db_a->blockcnt && !db_b->blockcnt)
335 return 1;
336
337 if (!db_a->blockcnt && db_b->blockcnt)
338 return -1;
339
340 if (db_a->blk != db_b->blk)
341 return (int) (db_a->blk - db_b->blk);
342
343 if (db_a->ino != db_b->ino)
344 return (int) (db_a->ino - db_b->ino);
345
346 return (int) (db_a->blockcnt - db_b->blockcnt);
347}
348
349
350/*
351 * Make sure the first entry in the directory is '.', and that the
352 * directory entry is sane.
353 */
354static int check_dot(e2fsck_t ctx,
355 struct ext2_dir_entry *dirent,
356 ext2_ino_t ino, struct problem_context *pctx)
357{
358 struct ext2_dir_entry *nextdir;
359 int status = 0;
360 int created = 0;
361 int new_len;
362 int problem = 0;
363
364 if (!dirent->inode)
365 problem = PR_2_MISSING_DOT;
366 else if (((dirent->name_len & 0xFF) != 1) ||
367 (dirent->name[0] != '.'))
368 problem = PR_2_1ST_NOT_DOT;
369 else if (dirent->name[1] != '\0')
370 problem = PR_2_DOT_NULL_TERM;
371
372 if (problem) {
373 if (fix_problem(ctx, problem, pctx)) {
374 if (dirent->rec_len < 12)
375 dirent->rec_len = 12;
376 dirent->inode = ino;
377 dirent->name_len = 1;
378 dirent->name[0] = '.';
379 dirent->name[1] = '\0';
380 status = 1;
381 created = 1;
382 }
383 }
384 if (dirent->inode != ino) {
385 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
386 dirent->inode = ino;
387 status = 1;
388 }
389 }
390 if (dirent->rec_len > 12) {
391 new_len = dirent->rec_len - 12;
392 if (new_len > 12) {
393 if (created ||
394 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
395 nextdir = (struct ext2_dir_entry *)
396 ((char *) dirent + 12);
397 dirent->rec_len = 12;
398 nextdir->rec_len = new_len;
399 nextdir->inode = 0;
400 nextdir->name_len = 0;
401 status = 1;
402 }
403 }
404 }
405 return status;
406}
407
408/*
409 * Make sure the second entry in the directory is '..', and that the
410 * directory entry is sane. We do not check the inode number of '..'
411 * here; this gets done in pass 3.
412 */
413static int check_dotdot(e2fsck_t ctx,
414 struct ext2_dir_entry *dirent,
415 struct dir_info *dir, struct problem_context *pctx)
416{
417 int problem = 0;
418
419 if (!dirent->inode)
420 problem = PR_2_MISSING_DOT_DOT;
421 else if (((dirent->name_len & 0xFF) != 2) ||
422 (dirent->name[0] != '.') ||
423 (dirent->name[1] != '.'))
424 problem = PR_2_2ND_NOT_DOT_DOT;
425 else if (dirent->name[2] != '\0')
426 problem = PR_2_DOT_DOT_NULL_TERM;
427
428 if (problem) {
429 if (fix_problem(ctx, problem, pctx)) {
430 if (dirent->rec_len < 12)
431 dirent->rec_len = 12;
432 /*
433 * Note: we don't have the parent inode just
434 * yet, so we will fill it in with the root
435 * inode. This will get fixed in pass 3.
436 */
437 dirent->inode = EXT2_ROOT_INO;
438 dirent->name_len = 2;
439 dirent->name[0] = '.';
440 dirent->name[1] = '.';
441 dirent->name[2] = '\0';
442 return 1;
443 }
444 return 0;
445 }
446 dir->dotdot = dirent->inode;
447 return 0;
448}
449
450/*
451 * Check to make sure a directory entry doesn't contain any illegal
452 * characters.
453 */
454static int check_name(e2fsck_t ctx,
455 struct ext2_dir_entry *dirent,
456 ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
457 struct problem_context *pctx)
458{
459 int i;
460 int fixup = -1;
461 int ret = 0;
462
463 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
464 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
465 if (fixup < 0) {
466 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
467 }
468 if (fixup) {
469 dirent->name[i] = '.';
470 ret = 1;
471 }
472 }
473 }
474 return ret;
475}
476
477/*
478 * Check the directory filetype (if present)
479 */
480static _INLINE_ int check_filetype(e2fsck_t ctx,
481 struct ext2_dir_entry *dirent,
482 ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
483 struct problem_context *pctx)
484{
485 int filetype = dirent->name_len >> 8;
486 int should_be = EXT2_FT_UNKNOWN;
487 struct ext2_inode inode;
488
489 if (!(ctx->fs->super->s_feature_incompat &
490 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
491 if (filetype == 0 ||
492 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
493 return 0;
494 dirent->name_len = dirent->name_len & 0xFF;
495 return 1;
496 }
497
498 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
499 should_be = EXT2_FT_DIR;
500 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
501 dirent->inode)) {
502 should_be = EXT2_FT_REG_FILE;
503 } else if (ctx->inode_bad_map &&
504 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
505 dirent->inode))
506 should_be = 0;
507 else {
508 e2fsck_read_inode(ctx, dirent->inode, &inode,
509 "check_filetype");
510 should_be = ext2_file_type(inode.i_mode);
511 }
512 if (filetype == should_be)
513 return 0;
514 pctx->num = should_be;
515
516 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
517 pctx) == 0)
518 return 0;
519
520 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
521 return 1;
522}
523
524#ifdef ENABLE_HTREE
525static void parse_int_node(ext2_filsys fs,
526 struct ext2_db_entry *db,
527 struct check_dir_struct *cd,
528 struct dx_dir_info *dx_dir,
529 char *block_buf)
530{
531 struct ext2_dx_root_info *root;
532 struct ext2_dx_entry *ent;
533 struct ext2_dx_countlimit *limit;
534 struct dx_dirblock_info *dx_db;
535 int i, expect_limit, count;
536 blk_t blk;
537 ext2_dirhash_t min_hash = 0xffffffff;
538 ext2_dirhash_t max_hash = 0;
539 ext2_dirhash_t hash = 0, prev_hash;
540
541 if (db->blockcnt == 0) {
542 root = (struct ext2_dx_root_info *) (block_buf + 24);
543
544#ifdef DX_DEBUG
545 printf("Root node dump:\n");
546 printf("\t Reserved zero: %d\n", root->reserved_zero);
547 printf("\t Hash Version: %d\n", root->hash_version);
548 printf("\t Info length: %d\n", root->info_length);
549 printf("\t Indirect levels: %d\n", root->indirect_levels);
550 printf("\t Flags: %d\n", root->unused_flags);
551#endif
552
553 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
554 } else {
555 ent = (struct ext2_dx_entry *) (block_buf+8);
556 }
557 limit = (struct ext2_dx_countlimit *) ent;
558
559#ifdef DX_DEBUG
560 printf("Number of entries (count): %d\n",
561 ext2fs_le16_to_cpu(limit->count));
562 printf("Number of entries (limit): %d\n",
563 ext2fs_le16_to_cpu(limit->limit));
564#endif
565
566 count = ext2fs_le16_to_cpu(limit->count);
567 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
568 sizeof(struct ext2_dx_entry);
569 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
570 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
571 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
572 goto clear_and_exit;
573 }
574 if (count > expect_limit) {
575 cd->pctx.num = count;
576 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
577 goto clear_and_exit;
578 count = expect_limit;
579 }
580
581 for (i=0; i < count; i++) {
582 prev_hash = hash;
583 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
584#ifdef DX_DEBUG
585 printf("Entry #%d: Hash 0x%08x, block %d\n", i,
586 hash, ext2fs_le32_to_cpu(ent[i].block));
587#endif
588 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
589 /* Check to make sure the block is valid */
590 if (blk > (blk_t) dx_dir->numblocks) {
591 cd->pctx.blk = blk;
592 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
593 &cd->pctx))
594 goto clear_and_exit;
595 }
596 if (hash < prev_hash &&
597 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
598 goto clear_and_exit;
599 dx_db = &dx_dir->dx_block[blk];
600 if (dx_db->flags & DX_FLAG_REFERENCED) {
601 dx_db->flags |= DX_FLAG_DUP_REF;
602 } else {
603 dx_db->flags |= DX_FLAG_REFERENCED;
604 dx_db->parent = db->blockcnt;
605 }
606 if (hash < min_hash)
607 min_hash = hash;
608 if (hash > max_hash)
609 max_hash = hash;
610 dx_db->node_min_hash = hash;
611 if ((i+1) < count)
612 dx_db->node_max_hash =
613 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
614 else {
615 dx_db->node_max_hash = 0xfffffffe;
616 dx_db->flags |= DX_FLAG_LAST;
617 }
618 if (i == 0)
619 dx_db->flags |= DX_FLAG_FIRST;
620 }
621#ifdef DX_DEBUG
622 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
623 db->blockcnt, min_hash, max_hash);
624#endif
625 dx_db = &dx_dir->dx_block[db->blockcnt];
626 dx_db->min_hash = min_hash;
627 dx_db->max_hash = max_hash;
628 return;
629
630clear_and_exit:
631 clear_htree(cd->ctx, cd->pctx.ino);
632 dx_dir->numblocks = 0;
633}
634#endif /* ENABLE_HTREE */
635
636/*
637 * Given a busted directory, try to salvage it somehow.
638 *
639 */
640static void salvage_directory(ext2_filsys fs,
641 struct ext2_dir_entry *dirent,
642 struct ext2_dir_entry *prev,
643 unsigned int *offset)
644{
645 char *cp = (char *) dirent;
646 int left = fs->blocksize - *offset - dirent->rec_len;
647 int name_len = dirent->name_len & 0xFF;
648
649 /*
650 * Special case of directory entry of size 8: copy what's left
651 * of the directory block up to cover up the invalid hole.
652 */
653 if ((left >= 12) && (dirent->rec_len == 8)) {
654 memmove(cp, cp+8, left);
655 memset(cp + left, 0, 8);
656 return;
657 }
658 /*
659 * If the directory entry overruns the end of the directory
660 * block, and the name is small enough to fit, then adjust the
661 * record length.
662 */
663 if ((left < 0) &&
664 (name_len + 8 <= dirent->rec_len + left) &&
665 dirent->inode <= fs->super->s_inodes_count &&
666 strnlen(dirent->name, name_len) == name_len) {
667 dirent->rec_len += left;
668 return;
669 }
670 /*
671 * If the directory entry is a multiple of four, so it is
672 * valid, let the previous directory entry absorb the invalid
673 * one.
674 */
675 if (prev && dirent->rec_len && (dirent->rec_len % 4) == 0) {
676 prev->rec_len += dirent->rec_len;
677 *offset += dirent->rec_len;
678 return;
679 }
680 /*
681 * Default salvage method --- kill all of the directory
682 * entries for the rest of the block. We will either try to
683 * absorb it into the previous directory entry, or create a
684 * new empty directory entry the rest of the directory block.
685 */
686 if (prev) {
687 prev->rec_len += fs->blocksize - *offset;
688 *offset = fs->blocksize;
689 } else {
690 dirent->rec_len = fs->blocksize - *offset;
691 dirent->name_len = 0;
692 dirent->inode = 0;
693 }
694}
695
696static int check_dir_block(ext2_filsys fs,
697 struct ext2_db_entry *db,
698 void *priv_data)
699{
700 struct dir_info *subdir, *dir;
701 struct dx_dir_info *dx_dir;
702#ifdef ENABLE_HTREE
703 struct dx_dirblock_info *dx_db = 0;
704#endif /* ENABLE_HTREE */
705 struct ext2_dir_entry *dirent, *prev;
706 ext2_dirhash_t hash;
707 unsigned int offset = 0;
708 int dir_modified = 0;
709 int dot_state;
710 blk_t block_nr = db->blk;
711 ext2_ino_t ino = db->ino;
712 __u16 links;
713 struct check_dir_struct *cd;
714 char *buf;
715 e2fsck_t ctx;
716 int problem;
717 struct ext2_dx_root_info *root;
718 struct ext2_dx_countlimit *limit;
719 static dict_t de_dict;
720 struct problem_context pctx;
721 int dups_found = 0;
722
723 cd = (struct check_dir_struct *) priv_data;
724 buf = cd->buf;
725 ctx = cd->ctx;
726
727 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
728 return DIRENT_ABORT;
729
730 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
731 return DIRENT_ABORT;
732
733 /*
734 * Make sure the inode is still in use (could have been
735 * deleted in the duplicate/bad blocks pass.
736 */
737 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
738 return 0;
739
740 cd->pctx.ino = ino;
741 cd->pctx.blk = block_nr;
742 cd->pctx.blkcount = db->blockcnt;
743 cd->pctx.ino2 = 0;
744 cd->pctx.dirent = 0;
745 cd->pctx.num = 0;
746
747 if (db->blk == 0) {
748 if (allocate_dir_block(ctx, db, buf, &cd->pctx))
749 return 0;
750 block_nr = db->blk;
751 }
752
753 if (db->blockcnt)
754 dot_state = 2;
755 else
756 dot_state = 0;
757
758 if (ctx->dirs_to_hash &&
759 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
760 dups_found++;
761
762#if 0
763 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
764 db->blockcnt, ino);
765#endif
766
767 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
768 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
769 cd->pctx.errcode = 0; /* We'll handle this ourselves */
770 if (cd->pctx.errcode) {
771 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
772 ctx->flags |= E2F_FLAG_ABORT;
773 return DIRENT_ABORT;
774 }
775 memset(buf, 0, fs->blocksize);
776 }
777#ifdef ENABLE_HTREE
778 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
779 if (dx_dir && dx_dir->numblocks) {
780 if (db->blockcnt >= dx_dir->numblocks) {
781 printf("XXX should never happen!!!\n");
782 abort();
783 }
784 dx_db = &dx_dir->dx_block[db->blockcnt];
785 dx_db->type = DX_DIRBLOCK_LEAF;
786 dx_db->phys = block_nr;
787 dx_db->min_hash = ~0;
788 dx_db->max_hash = 0;
789
790 dirent = (struct ext2_dir_entry *) buf;
791 limit = (struct ext2_dx_countlimit *) (buf+8);
792 if (db->blockcnt == 0) {
793 root = (struct ext2_dx_root_info *) (buf + 24);
794 dx_db->type = DX_DIRBLOCK_ROOT;
795 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
796 if ((root->reserved_zero ||
797 root->info_length < 8 ||
798 root->indirect_levels > 1) &&
799 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
800 clear_htree(ctx, ino);
801 dx_dir->numblocks = 0;
802 dx_db = 0;
803 }
804 dx_dir->hashversion = root->hash_version;
805 dx_dir->depth = root->indirect_levels + 1;
806 } else if ((dirent->inode == 0) &&
807 (dirent->rec_len == fs->blocksize) &&
808 (dirent->name_len == 0) &&
809 (ext2fs_le16_to_cpu(limit->limit) ==
810 ((fs->blocksize-8) /
811 sizeof(struct ext2_dx_entry))))
812 dx_db->type = DX_DIRBLOCK_NODE;
813 }
814#endif /* ENABLE_HTREE */
815
816 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
817 prev = 0;
818 do {
819 problem = 0;
820 dirent = (struct ext2_dir_entry *) (buf + offset);
821 cd->pctx.dirent = dirent;
822 cd->pctx.num = offset;
823 if (((offset + dirent->rec_len) > fs->blocksize) ||
824 (dirent->rec_len < 12) ||
825 ((dirent->rec_len % 4) != 0) ||
826 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
827 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
828 salvage_directory(fs, dirent, prev, &offset);
829 dir_modified++;
830 continue;
831 } else
832 goto abort_free_dict;
833 }
834 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
835 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
836 dirent->name_len = EXT2_NAME_LEN;
837 dir_modified++;
838 }
839 }
840
841 if (dot_state == 0) {
842 if (check_dot(ctx, dirent, ino, &cd->pctx))
843 dir_modified++;
844 } else if (dot_state == 1) {
845 dir = e2fsck_get_dir_info(ctx, ino);
846 if (!dir) {
847 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
848 goto abort_free_dict;
849 }
850 if (check_dotdot(ctx, dirent, dir, &cd->pctx))
851 dir_modified++;
852 } else if (dirent->inode == ino) {
853 problem = PR_2_LINK_DOT;
854 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
855 dirent->inode = 0;
856 dir_modified++;
857 goto next;
858 }
859 }
860 if (!dirent->inode)
861 goto next;
862
863 /*
864 * Make sure the inode listed is a legal one.
865 */
866 if (((dirent->inode != EXT2_ROOT_INO) &&
867 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
868 (dirent->inode > fs->super->s_inodes_count)) {
869 problem = PR_2_BAD_INO;
870 } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
871 dirent->inode))) {
872 /*
873 * If the inode is unused, offer to clear it.
874 */
875 problem = PR_2_UNUSED_INODE;
876 } else if (ctx->inode_bb_map &&
877 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
878 dirent->inode))) {
879 /*
880 * If the inode is in a bad block, offer to
881 * clear it.
882 */
883 problem = PR_2_BB_INODE;
884 } else if ((dot_state > 1) &&
885 ((dirent->name_len & 0xFF) == 1) &&
886 (dirent->name[0] == '.')) {
887 /*
888 * If there's a '.' entry in anything other
889 * than the first directory entry, it's a
890 * duplicate entry that should be removed.
891 */
892 problem = PR_2_DUP_DOT;
893 } else if ((dot_state > 1) &&
894 ((dirent->name_len & 0xFF) == 2) &&
895 (dirent->name[0] == '.') &&
896 (dirent->name[1] == '.')) {
897 /*
898 * If there's a '..' entry in anything other
899 * than the second directory entry, it's a
900 * duplicate entry that should be removed.
901 */
902 problem = PR_2_DUP_DOT_DOT;
903 } else if ((dot_state > 1) &&
904 (dirent->inode == EXT2_ROOT_INO)) {
905 /*
906 * Don't allow links to the root directory.
907 * We check this specially to make sure we
908 * catch this error case even if the root
909 * directory hasn't been created yet.
910 */
911 problem = PR_2_LINK_ROOT;
912 } else if ((dot_state > 1) &&
913 (dirent->name_len & 0xFF) == 0) {
914 /*
915 * Don't allow zero-length directory names.
916 */
917 problem = PR_2_NULL_NAME;
918 }
919
920 if (problem) {
921 if (fix_problem(ctx, problem, &cd->pctx)) {
922 dirent->inode = 0;
923 dir_modified++;
924 goto next;
925 } else {
926 ext2fs_unmark_valid(fs);
927 if (problem == PR_2_BAD_INO)
928 goto next;
929 }
930 }
931
932 /*
933 * If the inode was marked as having bad fields in
934 * pass1, process it and offer to fix/clear it.
935 * (We wait until now so that we can display the
936 * pathname to the user.)
937 */
938 if (ctx->inode_bad_map &&
939 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
940 dirent->inode)) {
941 if (e2fsck_process_bad_inode(ctx, ino,
942 dirent->inode,
943 buf + fs->blocksize)) {
944 dirent->inode = 0;
945 dir_modified++;
946 goto next;
947 }
948 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
949 return DIRENT_ABORT;
950 }
951
952 if (check_name(ctx, dirent, ino, &cd->pctx))
953 dir_modified++;
954
955 if (check_filetype(ctx, dirent, ino, &cd->pctx))
956 dir_modified++;
957
958#ifdef ENABLE_HTREE
959 if (dx_db) {
960 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
961 (dirent->name_len & 0xFF),
962 fs->super->s_hash_seed, &hash, 0);
963 if (hash < dx_db->min_hash)
964 dx_db->min_hash = hash;
965 if (hash > dx_db->max_hash)
966 dx_db->max_hash = hash;
967 }
968#endif
969
970 /*
971 * If this is a directory, then mark its parent in its
972 * dir_info structure. If the parent field is already
973 * filled in, then this directory has more than one
974 * hard link. We assume the first link is correct,
975 * and ask the user if he/she wants to clear this one.
976 */
977 if ((dot_state > 1) &&
978 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
979 dirent->inode))) {
980 subdir = e2fsck_get_dir_info(ctx, dirent->inode);
981 if (!subdir) {
982 cd->pctx.ino = dirent->inode;
983 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
984 goto abort_free_dict;
985 }
986 if (subdir->parent) {
987 cd->pctx.ino2 = subdir->parent;
988 if (fix_problem(ctx, PR_2_LINK_DIR,
989 &cd->pctx)) {
990 dirent->inode = 0;
991 dir_modified++;
992 goto next;
993 }
994 cd->pctx.ino2 = 0;
995 } else
996 subdir->parent = ino;
997 }
998
999 if (dups_found) {
1000 ;
1001 } else if (dict_lookup(&de_dict, dirent)) {
1002 clear_problem_context(&pctx);
1003 pctx.ino = ino;
1004 pctx.dirent = dirent;
1005 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
1006 if (!ctx->dirs_to_hash)
1007 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
1008 if (ctx->dirs_to_hash)
1009 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
1010 dups_found++;
1011 } else
1012 dict_alloc_insert(&de_dict, dirent, dirent);
1013
1014 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
1015 &links);
1016 if (links > 1)
1017 ctx->fs_links_count++;
1018 ctx->fs_total_count++;
1019 next:
1020 prev = dirent;
1021 offset += dirent->rec_len;
1022 dot_state++;
1023 } while (offset < fs->blocksize);
1024#if 0
1025 printf("\n");
1026#endif
1027#ifdef ENABLE_HTREE
1028 if (dx_db) {
1029#ifdef DX_DEBUG
1030 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
1031 db->blockcnt, dx_db->type,
1032 dx_db->min_hash, dx_db->max_hash);
1033#endif
1034 cd->pctx.dir = cd->pctx.ino;
1035 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
1036 (dx_db->type == DX_DIRBLOCK_NODE))
1037 parse_int_node(fs, db, cd, dx_dir, buf);
1038 }
1039#endif /* ENABLE_HTREE */
1040 if (offset != fs->blocksize) {
1041 cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
1042 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
1043 dirent->rec_len = cd->pctx.num;
1044 dir_modified++;
1045 }
1046 }
1047 if (dir_modified) {
1048 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
1049 if (cd->pctx.errcode) {
1050 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
1051 &cd->pctx))
1052 goto abort_free_dict;
1053 }
1054 ext2fs_mark_changed(fs);
1055 }
1056 dict_free_nodes(&de_dict);
1057 return 0;
1058abort_free_dict:
1059 dict_free_nodes(&de_dict);
1060 ctx->flags |= E2F_FLAG_ABORT;
1061 return DIRENT_ABORT;
1062}
1063
1064/*
1065 * This function is called to deallocate a block, and is an interator
1066 * functioned called by deallocate inode via ext2fs_iterate_block().
1067 */
1068static int deallocate_inode_block(ext2_filsys fs,
1069 blk_t *block_nr,
1070 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
1071 blk_t ref_block EXT2FS_ATTR((unused)),
1072 int ref_offset EXT2FS_ATTR((unused)),
1073 void *priv_data)
1074{
1075 e2fsck_t ctx = (e2fsck_t) priv_data;
1076
1077 if (HOLE_BLKADDR(*block_nr))
1078 return 0;
1079 if ((*block_nr < fs->super->s_first_data_block) ||
1080 (*block_nr >= fs->super->s_blocks_count))
1081 return 0;
1082 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
1083 ext2fs_block_alloc_stats(fs, *block_nr, -1);
1084 return 0;
1085}
1086
1087/*
1088 * This fuction deallocates an inode
1089 */
1090static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
1091{
1092 ext2_filsys fs = ctx->fs;
1093 struct ext2_inode inode;
1094 struct problem_context pctx;
1095 __u32 count;
1096
1097 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
1098 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
1099 inode.i_links_count = 0;
1100 inode.i_dtime = time(0);
1101 e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode");
1102 clear_problem_context(&pctx);
1103 pctx.ino = ino;
1104
1105 /*
1106 * Fix up the bitmaps...
1107 */
1108 e2fsck_read_bitmaps(ctx);
1109 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
1110 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
1111 if (ctx->inode_bad_map)
1112 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
1113 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
1114
1115 if (inode.i_file_acl &&
1116 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1117 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
1118 block_buf, -1, &count);
1119 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
1120 pctx.errcode = 0;
1121 count = 1;
1122 }
1123 if (pctx.errcode) {
1124 pctx.blk = inode.i_file_acl;
1125 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
1126 ctx->flags |= E2F_FLAG_ABORT;
1127 return;
1128 }
1129 if (count == 0) {
1130 ext2fs_unmark_block_bitmap(ctx->block_found_map,
1131 inode.i_file_acl);
1132 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
1133 }
1134 inode.i_file_acl = 0;
1135 }
1136
1137 if (!ext2fs_inode_has_valid_blocks(&inode))
1138 return;
1139
1140 if (LINUX_S_ISREG(inode.i_mode) &&
1141 (inode.i_size_high || inode.i_size & 0x80000000UL))
1142 ctx->large_files--;
1143
1144 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
1145 deallocate_inode_block, ctx);
1146 if (pctx.errcode) {
1147 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
1148 ctx->flags |= E2F_FLAG_ABORT;
1149 return;
1150 }
1151}
1152
1153/*
1154 * This fuction clears the htree flag on an inode
1155 */
1156static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
1157{
1158 struct ext2_inode inode;
1159
1160 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
1161 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
1162 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
1163 if (ctx->dirs_to_hash)
1164 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
1165}
1166
1167
1168extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
1169 ext2_ino_t ino, char *buf)
1170{
1171 ext2_filsys fs = ctx->fs;
1172 struct ext2_inode inode;
1173 int inode_modified = 0;
1174 int not_fixed = 0;
1175 unsigned char *frag, *fsize;
1176 struct problem_context pctx;
1177 int problem = 0;
1178
1179 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
1180
1181 clear_problem_context(&pctx);
1182 pctx.ino = ino;
1183 pctx.dir = dir;
1184 pctx.inode = &inode;
1185
1186 if (inode.i_file_acl &&
1187 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
1188 fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
1189 inode.i_file_acl = 0;
1190#ifdef EXT2FS_ENABLE_SWAPFS
1191 /*
1192 * This is a special kludge to deal with long symlinks
1193 * on big endian systems. i_blocks had already been
1194 * decremented earlier in pass 1, but since i_file_acl
1195 * hadn't yet been cleared, ext2fs_read_inode()
1196 * assumed that the file was short symlink and would
1197 * not have byte swapped i_block[0]. Hence, we have
1198 * to byte-swap it here.
1199 */
1200 if (LINUX_S_ISLNK(inode.i_mode) &&
1201 (fs->flags & EXT2_FLAG_SWAP_BYTES) &&
1202 (inode.i_blocks == fs->blocksize >> 9))
1203 inode.i_block[0] = ext2fs_swab32(inode.i_block[0]);
1204#endif
1205 inode_modified++;
1206 } else
1207 not_fixed++;
1208
1209 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
1210 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
1211 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
1212 !(LINUX_S_ISSOCK(inode.i_mode)))
1213 problem = PR_2_BAD_MODE;
1214 else if (LINUX_S_ISCHR(inode.i_mode)
1215 && !e2fsck_pass1_check_device_inode(fs, &inode))
1216 problem = PR_2_BAD_CHAR_DEV;
1217 else if (LINUX_S_ISBLK(inode.i_mode)
1218 && !e2fsck_pass1_check_device_inode(fs, &inode))
1219 problem = PR_2_BAD_BLOCK_DEV;
1220 else if (LINUX_S_ISFIFO(inode.i_mode)
1221 && !e2fsck_pass1_check_device_inode(fs, &inode))
1222 problem = PR_2_BAD_FIFO;
1223 else if (LINUX_S_ISSOCK(inode.i_mode)
1224 && !e2fsck_pass1_check_device_inode(fs, &inode))
1225 problem = PR_2_BAD_SOCKET;
1226 else if (LINUX_S_ISLNK(inode.i_mode)
1227 && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
1228 problem = PR_2_INVALID_SYMLINK;
1229 }
1230
1231 if (problem) {
1232 if (fix_problem(ctx, problem, &pctx)) {
1233 deallocate_inode(ctx, ino, 0);
1234 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
1235 return 0;
1236 return 1;
1237 } else
1238 not_fixed++;
1239 problem = 0;
1240 }
1241
1242 if (inode.i_faddr) {
1243 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
1244 inode.i_faddr = 0;
1245 inode_modified++;
1246 } else
1247 not_fixed++;
1248 }
1249
1250 switch (fs->super->s_creator_os) {
1251 case EXT2_OS_LINUX:
1252 frag = &inode.osd2.linux2.l_i_frag;
1253 fsize = &inode.osd2.linux2.l_i_fsize;
1254 break;
1255 case EXT2_OS_HURD:
1256 frag = &inode.osd2.hurd2.h_i_frag;
1257 fsize = &inode.osd2.hurd2.h_i_fsize;
1258 break;
1259 case EXT2_OS_MASIX:
1260 frag = &inode.osd2.masix2.m_i_frag;
1261 fsize = &inode.osd2.masix2.m_i_fsize;
1262 break;
1263 default:
1264 frag = fsize = 0;
1265 }
1266 if (frag && *frag) {
1267 pctx.num = *frag;
1268 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
1269 *frag = 0;
1270 inode_modified++;
1271 } else
1272 not_fixed++;
1273 pctx.num = 0;
1274 }
1275 if (fsize && *fsize) {
1276 pctx.num = *fsize;
1277 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
1278 *fsize = 0;
1279 inode_modified++;
1280 } else
1281 not_fixed++;
1282 pctx.num = 0;
1283 }
1284
1285 if (inode.i_file_acl &&
1286 ((inode.i_file_acl < fs->super->s_first_data_block) ||
1287 (inode.i_file_acl >= fs->super->s_blocks_count))) {
1288 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
1289 inode.i_file_acl = 0;
1290 inode_modified++;
1291 } else
1292 not_fixed++;
1293 }
1294 if (inode.i_dir_acl &&
1295 LINUX_S_ISDIR(inode.i_mode)) {
1296 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
1297 inode.i_dir_acl = 0;
1298 inode_modified++;
1299 } else
1300 not_fixed++;
1301 }
1302
1303 if (inode_modified)
1304 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
1305 if (!not_fixed)
1306 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
1307 return 0;
1308}
1309
1310
1311/*
1312 * allocate_dir_block --- this function allocates a new directory
1313 * block for a particular inode; this is done if a directory has
1314 * a "hole" in it, or if a directory has a illegal block number
1315 * that was zeroed out and now needs to be replaced.
1316 */
1317static int allocate_dir_block(e2fsck_t ctx,
1318 struct ext2_db_entry *db,
1319 char *buf EXT2FS_ATTR((unused)),
1320 struct problem_context *pctx)
1321{
1322 ext2_filsys fs = ctx->fs;
1323 blk_t blk;
1324 char *block;
1325 struct ext2_inode inode;
1326
1327 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
1328 return 1;
1329
1330 /*
1331 * Read the inode and block bitmaps in; we'll be messing with
1332 * them.
1333 */
1334 e2fsck_read_bitmaps(ctx);
1335
1336 /*
1337 * First, find a free block
1338 */
1339 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
1340 if (pctx->errcode) {
1341 pctx->str = "ext2fs_new_block";
1342 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1343 return 1;
1344 }
1345 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
1346 ext2fs_mark_block_bitmap(fs->block_map, blk);
1347 ext2fs_mark_bb_dirty(fs);
1348
1349 /*
1350 * Now let's create the actual data block for the inode
1351 */
1352 if (db->blockcnt)
1353 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
1354 else
1355 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
1356 EXT2_ROOT_INO, &block);
1357
1358 if (pctx->errcode) {
1359 pctx->str = "ext2fs_new_dir_block";
1360 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1361 return 1;
1362 }
1363
1364 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
1365 ext2fs_free_mem(&block);
1366 if (pctx->errcode) {
1367 pctx->str = "ext2fs_write_dir_block";
1368 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1369 return 1;
1370 }
1371
1372 /*
1373 * Update the inode block count
1374 */
1375 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
1376 inode.i_blocks += fs->blocksize / 512;
1377 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
1378 inode.i_size = (db->blockcnt+1) * fs->blocksize;
1379 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
1380
1381 /*
1382 * Finally, update the block pointers for the inode
1383 */
1384 db->blk = blk;
1385 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
1386 0, update_dir_block, db);
1387 if (pctx->errcode) {
1388 pctx->str = "ext2fs_block_iterate";
1389 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
1390 return 1;
1391 }
1392
1393 return 0;
1394}
1395
1396/*
1397 * This is a helper function for allocate_dir_block().
1398 */
1399static int update_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
1400 blk_t *block_nr,
1401 e2_blkcnt_t blockcnt,
1402 blk_t ref_block EXT2FS_ATTR((unused)),
1403 int ref_offset EXT2FS_ATTR((unused)),
1404 void *priv_data)
1405{
1406 struct ext2_db_entry *db;
1407
1408 db = (struct ext2_db_entry *) priv_data;
1409 if (db->blockcnt == (int) blockcnt) {
1410 *block_nr = db->blk;
1411 return BLOCK_CHANGED;
1412 }
1413 return 0;
1414}
diff --git a/e2fsprogs/e2fsck/pass3.c b/e2fsprogs/e2fsck/pass3.c
deleted file mode 100644
index a92c8904c..000000000
--- a/e2fsprogs/e2fsck/pass3.c
+++ /dev/null
@@ -1,804 +0,0 @@
1/*
2 * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * Pass #3 assures that all directories are connected to the
12 * filesystem tree, using the following algorithm:
13 *
14 * First, the root directory is checked to make sure it exists; if
15 * not, e2fsck will offer to create a new one. It is then marked as
16 * "done".
17 *
18 * Then, pass3 interates over all directory inodes; for each directory
19 * it attempts to trace up the filesystem tree, using dirinfo.parent
20 * until it reaches a directory which has been marked "done". If it
21 * can not do so, then the directory must be disconnected, and e2fsck
22 * will offer to reconnect it to /lost+found. While it is chasing
23 * parent pointers up the filesystem tree, if pass3 sees a directory
24 * twice, then it has detected a filesystem loop, and it will again
25 * offer to reconnect the directory to /lost+found in to break the
26 * filesystem loop.
27 *
28 * Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
29 * reconnect inodes to /lost+found; this subroutine is also used by
30 * pass 4. e2fsck_reconnect_file() calls get_lost_and_found(), which
31 * is responsible for creating /lost+found if it does not exist.
32 *
33 * Pass 3 frees the following data structures:
34 * - The dirinfo directory information cache.
35 */
36
37#ifdef HAVE_ERRNO_H
38#include <errno.h>
39#endif
40
41#include "e2fsck.h"
42#include "problem.h"
43
44static void check_root(e2fsck_t ctx);
45static int check_directory(e2fsck_t ctx, struct dir_info *dir,
46 struct problem_context *pctx);
47static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
48
49static ext2fs_inode_bitmap inode_loop_detect = 0;
50static ext2fs_inode_bitmap inode_done_map = 0;
51
52void e2fsck_pass3(e2fsck_t ctx)
53{
54 ext2_filsys fs = ctx->fs;
55 int i;
56#ifdef RESOURCE_TRACK
57 struct resource_track rtrack;
58#endif
59 struct problem_context pctx;
60 struct dir_info *dir;
61 unsigned long maxdirs, count;
62
63#ifdef RESOURCE_TRACK
64 init_resource_track(&rtrack);
65#endif
66
67 clear_problem_context(&pctx);
68
69#ifdef MTRACE
70 mtrace_print("Pass 3");
71#endif
72
73 if (!(ctx->options & E2F_OPT_PREEN))
74 fix_problem(ctx, PR_3_PASS_HEADER, &pctx);
75
76 /*
77 * Allocate some bitmaps to do loop detection.
78 */
79 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("inode done bitmap"),
80 &inode_done_map);
81 if (pctx.errcode) {
82 pctx.num = 2;
83 fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx);
84 ctx->flags |= E2F_FLAG_ABORT;
85 goto abort_exit;
86 }
87#ifdef RESOURCE_TRACK
88 if (ctx->options & E2F_OPT_TIME) {
89 e2fsck_clear_progbar(ctx);
90 print_resource_track(_("Peak memory"), &ctx->global_rtrack);
91 }
92#endif
93
94 check_root(ctx);
95 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
96 goto abort_exit;
97
98 ext2fs_mark_inode_bitmap(inode_done_map, EXT2_ROOT_INO);
99
100 maxdirs = e2fsck_get_num_dirinfo(ctx);
101 count = 1;
102
103 if (ctx->progress)
104 if ((ctx->progress)(ctx, 3, 0, maxdirs))
105 goto abort_exit;
106
107 for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) {
108 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
109 goto abort_exit;
110 if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs))
111 goto abort_exit;
112 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino))
113 if (check_directory(ctx, dir, &pctx))
114 goto abort_exit;
115 }
116
117 /*
118 * Force the creation of /lost+found if not present
119 */
120 if ((ctx->flags & E2F_OPT_READONLY) == 0)
121 e2fsck_get_lost_and_found(ctx, 1);
122
123 /*
124 * If there are any directories that need to be indexed or
125 * optimized, do it here.
126 */
127 e2fsck_rehash_directories(ctx);
128
129abort_exit:
130 e2fsck_free_dir_info(ctx);
131 if (inode_loop_detect) {
132 ext2fs_free_inode_bitmap(inode_loop_detect);
133 inode_loop_detect = 0;
134 }
135 if (inode_done_map) {
136 ext2fs_free_inode_bitmap(inode_done_map);
137 inode_done_map = 0;
138 }
139
140#ifdef RESOURCE_TRACK
141 if (ctx->options & E2F_OPT_TIME2) {
142 e2fsck_clear_progbar(ctx);
143 print_resource_track(_("Pass 3"), &rtrack);
144 }
145#endif
146}
147
148/*
149 * This makes sure the root inode is present; if not, we ask if the
150 * user wants us to create it. Not creating it is a fatal error.
151 */
152static void check_root(e2fsck_t ctx)
153{
154 ext2_filsys fs = ctx->fs;
155 blk_t blk;
156 struct ext2_inode inode;
157 char * block;
158 struct problem_context pctx;
159
160 clear_problem_context(&pctx);
161
162 if (ext2fs_test_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO)) {
163 /*
164 * If the root inode is not a directory, die here. The
165 * user must have answered 'no' in pass1 when we
166 * offered to clear it.
167 */
168 if (!(ext2fs_test_inode_bitmap(ctx->inode_dir_map,
169 EXT2_ROOT_INO))) {
170 fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx);
171 ctx->flags |= E2F_FLAG_ABORT;
172 }
173 return;
174 }
175
176 if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) {
177 fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx);
178 ctx->flags |= E2F_FLAG_ABORT;
179 return;
180 }
181
182 e2fsck_read_bitmaps(ctx);
183
184 /*
185 * First, find a free block
186 */
187 pctx.errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
188 if (pctx.errcode) {
189 pctx.str = "ext2fs_new_block";
190 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
191 ctx->flags |= E2F_FLAG_ABORT;
192 return;
193 }
194 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
195 ext2fs_mark_block_bitmap(fs->block_map, blk);
196 ext2fs_mark_bb_dirty(fs);
197
198 /*
199 * Now let's create the actual data block for the inode
200 */
201 pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
202 &block);
203 if (pctx.errcode) {
204 pctx.str = "ext2fs_new_dir_block";
205 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
206 ctx->flags |= E2F_FLAG_ABORT;
207 return;
208 }
209
210 pctx.errcode = ext2fs_write_dir_block(fs, blk, block);
211 if (pctx.errcode) {
212 pctx.str = "ext2fs_write_dir_block";
213 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
214 ctx->flags |= E2F_FLAG_ABORT;
215 return;
216 }
217 ext2fs_free_mem(&block);
218
219 /*
220 * Set up the inode structure
221 */
222 memset(&inode, 0, sizeof(inode));
223 inode.i_mode = 040755;
224 inode.i_size = fs->blocksize;
225 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
226 inode.i_links_count = 2;
227 inode.i_blocks = fs->blocksize / 512;
228 inode.i_block[0] = blk;
229
230 /*
231 * Write out the inode.
232 */
233 pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
234 if (pctx.errcode) {
235 pctx.str = "ext2fs_write_inode";
236 fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
237 ctx->flags |= E2F_FLAG_ABORT;
238 return;
239 }
240
241 /*
242 * Miscellaneous bookkeeping...
243 */
244 e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
245 ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2);
246 ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2);
247
248 ext2fs_mark_inode_bitmap(ctx->inode_used_map, EXT2_ROOT_INO);
249 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, EXT2_ROOT_INO);
250 ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_ROOT_INO);
251 ext2fs_mark_ib_dirty(fs);
252}
253
254/*
255 * This subroutine is responsible for making sure that a particular
256 * directory is connected to the root; if it isn't we trace it up as
257 * far as we can go, and then offer to connect the resulting parent to
258 * the lost+found. We have to do loop detection; if we ever discover
259 * a loop, we treat that as a disconnected directory and offer to
260 * reparent it to lost+found.
261 *
262 * However, loop detection is expensive, because for very large
263 * filesystems, the inode_loop_detect bitmap is huge, and clearing it
264 * is non-trivial. Loops in filesystems are also a rare error case,
265 * and we shouldn't optimize for error cases. So we try two passes of
266 * the algorithm. The first time, we ignore loop detection and merely
267 * increment a counter; if the counter exceeds some extreme threshold,
268 * then we try again with the loop detection bitmap enabled.
269 */
270static int check_directory(e2fsck_t ctx, struct dir_info *dir,
271 struct problem_context *pctx)
272{
273 ext2_filsys fs = ctx->fs;
274 struct dir_info *p = dir;
275 int loop_pass = 0, parent_count = 0;
276
277 if (!p)
278 return 0;
279
280 while (1) {
281 /*
282 * Mark this inode as being "done"; by the time we
283 * return from this function, the inode we either be
284 * verified as being connected to the directory tree,
285 * or we will have offered to reconnect this to
286 * lost+found.
287 *
288 * If it was marked done already, then we've reached a
289 * parent we've already checked.
290 */
291 if (ext2fs_mark_inode_bitmap(inode_done_map, p->ino))
292 break;
293
294 /*
295 * If this directory doesn't have a parent, or we've
296 * seen the parent once already, then offer to
297 * reparent it to lost+found
298 */
299 if (!p->parent ||
300 (loop_pass &&
301 (ext2fs_test_inode_bitmap(inode_loop_detect,
302 p->parent)))) {
303 pctx->ino = p->ino;
304 if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
305 if (e2fsck_reconnect_file(ctx, pctx->ino))
306 ext2fs_unmark_valid(fs);
307 else {
308 p = e2fsck_get_dir_info(ctx, pctx->ino);
309 p->parent = ctx->lost_and_found;
310 fix_dotdot(ctx, p, ctx->lost_and_found);
311 }
312 }
313 break;
314 }
315 p = e2fsck_get_dir_info(ctx, p->parent);
316 if (!p) {
317 fix_problem(ctx, PR_3_NO_DIRINFO, pctx);
318 return 0;
319 }
320 if (loop_pass) {
321 ext2fs_mark_inode_bitmap(inode_loop_detect,
322 p->ino);
323 } else if (parent_count++ > 2048) {
324 /*
325 * If we've run into a path depth that's
326 * greater than 2048, try again with the inode
327 * loop bitmap turned on and start from the
328 * top.
329 */
330 loop_pass = 1;
331 if (inode_loop_detect)
332 ext2fs_clear_inode_bitmap(inode_loop_detect);
333 else {
334 pctx->errcode = ext2fs_allocate_inode_bitmap(fs, _("inode loop detection bitmap"), &inode_loop_detect);
335 if (pctx->errcode) {
336 pctx->num = 1;
337 fix_problem(ctx,
338 PR_3_ALLOCATE_IBITMAP_ERROR, pctx);
339 ctx->flags |= E2F_FLAG_ABORT;
340 return -1;
341 }
342 }
343 p = dir;
344 }
345 }
346
347 /*
348 * Make sure that .. and the parent directory are the same;
349 * offer to fix it if not.
350 */
351 if (dir->parent != dir->dotdot) {
352 pctx->ino = dir->ino;
353 pctx->ino2 = dir->dotdot;
354 pctx->dir = dir->parent;
355 if (fix_problem(ctx, PR_3_BAD_DOT_DOT, pctx))
356 fix_dotdot(ctx, dir, dir->parent);
357 }
358 return 0;
359}
360
361/*
362 * This routine gets the lost_and_found inode, making it a directory
363 * if necessary
364 */
365ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
366{
367 ext2_filsys fs = ctx->fs;
368 ext2_ino_t ino;
369 blk_t blk;
370 errcode_t retval;
371 struct ext2_inode inode;
372 char * block;
373 static const char name[] = "lost+found";
374 struct problem_context pctx;
375 struct dir_info *dirinfo;
376
377 if (ctx->lost_and_found)
378 return ctx->lost_and_found;
379
380 clear_problem_context(&pctx);
381
382 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name,
383 sizeof(name)-1, 0, &ino);
384 if (retval && !fix)
385 return 0;
386 if (!retval) {
387 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino)) {
388 ctx->lost_and_found = ino;
389 return ino;
390 }
391
392 /* Lost+found isn't a directory! */
393 if (!fix)
394 return 0;
395 pctx.ino = ino;
396 if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
397 return 0;
398
399 /* OK, unlink the old /lost+found file. */
400 pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
401 if (pctx.errcode) {
402 pctx.str = "ext2fs_unlink";
403 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
404 return 0;
405 }
406 dirinfo = e2fsck_get_dir_info(ctx, ino);
407 if (dirinfo)
408 dirinfo->parent = 0;
409 e2fsck_adjust_inode_count(ctx, ino, -1);
410 } else if (retval != EXT2_ET_FILE_NOT_FOUND) {
411 pctx.errcode = retval;
412 fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx);
413 }
414 if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0))
415 return 0;
416
417 /*
418 * Read the inode and block bitmaps in; we'll be messing with
419 * them.
420 */
421 e2fsck_read_bitmaps(ctx);
422
423 /*
424 * First, find a free block
425 */
426 retval = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
427 if (retval) {
428 pctx.errcode = retval;
429 fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
430 return 0;
431 }
432 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
433 ext2fs_block_alloc_stats(fs, blk, +1);
434
435 /*
436 * Next find a free inode.
437 */
438 retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
439 ctx->inode_used_map, &ino);
440 if (retval) {
441 pctx.errcode = retval;
442 fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
443 return 0;
444 }
445 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
446 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
447 ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
448
449 /*
450 * Now let's create the actual data block for the inode
451 */
452 retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
453 if (retval) {
454 pctx.errcode = retval;
455 fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
456 return 0;
457 }
458
459 retval = ext2fs_write_dir_block(fs, blk, block);
460 ext2fs_free_mem(&block);
461 if (retval) {
462 pctx.errcode = retval;
463 fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
464 return 0;
465 }
466
467 /*
468 * Set up the inode structure
469 */
470 memset(&inode, 0, sizeof(inode));
471 inode.i_mode = 040700;
472 inode.i_size = fs->blocksize;
473 inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
474 inode.i_links_count = 2;
475 inode.i_blocks = fs->blocksize / 512;
476 inode.i_block[0] = blk;
477
478 /*
479 * Next, write out the inode.
480 */
481 pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
482 if (pctx.errcode) {
483 pctx.str = "ext2fs_write_inode";
484 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
485 return 0;
486 }
487 /*
488 * Finally, create the directory link
489 */
490 pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR);
491 if (pctx.errcode) {
492 pctx.str = "ext2fs_link";
493 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
494 return 0;
495 }
496
497 /*
498 * Miscellaneous bookkeeping that needs to be kept straight.
499 */
500 e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO);
501 e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1);
502 ext2fs_icount_store(ctx->inode_count, ino, 2);
503 ext2fs_icount_store(ctx->inode_link_info, ino, 2);
504 ctx->lost_and_found = ino;
505#if 0
506 printf("/lost+found created; inode #%lu\n", ino);
507#endif
508 return ino;
509}
510
511/*
512 * This routine will connect a file to lost+found
513 */
514int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
515{
516 ext2_filsys fs = ctx->fs;
517 errcode_t retval;
518 char name[80];
519 struct problem_context pctx;
520 struct ext2_inode inode;
521 int file_type = 0;
522
523 clear_problem_context(&pctx);
524 pctx.ino = ino;
525
526 if (!ctx->bad_lost_and_found && !ctx->lost_and_found) {
527 if (e2fsck_get_lost_and_found(ctx, 1) == 0)
528 ctx->bad_lost_and_found++;
529 }
530 if (ctx->bad_lost_and_found) {
531 fix_problem(ctx, PR_3_NO_LPF, &pctx);
532 return 1;
533 }
534
535 sprintf(name, "#%u", ino);
536 if (ext2fs_read_inode(fs, ino, &inode) == 0)
537 file_type = ext2_file_type(inode.i_mode);
538 retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type);
539 if (retval == EXT2_ET_DIR_NO_SPACE) {
540 if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
541 return 1;
542 retval = e2fsck_expand_directory(ctx, ctx->lost_and_found,
543 1, 0);
544 if (retval) {
545 pctx.errcode = retval;
546 fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
547 return 1;
548 }
549 retval = ext2fs_link(fs, ctx->lost_and_found, name,
550 ino, file_type);
551 }
552 if (retval) {
553 pctx.errcode = retval;
554 fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx);
555 return 1;
556 }
557 e2fsck_adjust_inode_count(ctx, ino, 1);
558
559 return 0;
560}
561
562/*
563 * Utility routine to adjust the inode counts on an inode.
564 */
565errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
566{
567 ext2_filsys fs = ctx->fs;
568 errcode_t retval;
569 struct ext2_inode inode;
570
571 if (!ino)
572 return 0;
573
574 retval = ext2fs_read_inode(fs, ino, &inode);
575 if (retval)
576 return retval;
577
578#if 0
579 printf("Adjusting link count for inode %lu by %d (from %d)\n", ino, adj,
580 inode.i_links_count);
581#endif
582
583 if (adj == 1) {
584 ext2fs_icount_increment(ctx->inode_count, ino, 0);
585 if (inode.i_links_count == (__u16) ~0)
586 return 0;
587 ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
588 inode.i_links_count++;
589 } else if (adj == -1) {
590 ext2fs_icount_decrement(ctx->inode_count, ino, 0);
591 if (inode.i_links_count == 0)
592 return 0;
593 ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
594 inode.i_links_count--;
595 }
596
597 retval = ext2fs_write_inode(fs, ino, &inode);
598 if (retval)
599 return retval;
600
601 return 0;
602}
603
604/*
605 * Fix parent --- this routine fixes up the parent of a directory.
606 */
607struct fix_dotdot_struct {
608 ext2_filsys fs;
609 ext2_ino_t parent;
610 int done;
611 e2fsck_t ctx;
612};
613
614static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
615 int offset EXT2FS_ATTR((unused)),
616 int blocksize EXT2FS_ATTR((unused)),
617 char *buf EXT2FS_ATTR((unused)),
618 void *priv_data)
619{
620 struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
621 errcode_t retval;
622 struct problem_context pctx;
623
624 if ((dirent->name_len & 0xFF) != 2)
625 return 0;
626 if (strncmp(dirent->name, "..", 2))
627 return 0;
628
629 clear_problem_context(&pctx);
630
631 retval = e2fsck_adjust_inode_count(fp->ctx, dirent->inode, -1);
632 if (retval) {
633 pctx.errcode = retval;
634 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
635 }
636 retval = e2fsck_adjust_inode_count(fp->ctx, fp->parent, 1);
637 if (retval) {
638 pctx.errcode = retval;
639 fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
640 }
641 dirent->inode = fp->parent;
642
643 fp->done++;
644 return DIRENT_ABORT | DIRENT_CHANGED;
645}
646
647static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
648{
649 ext2_filsys fs = ctx->fs;
650 errcode_t retval;
651 struct fix_dotdot_struct fp;
652 struct problem_context pctx;
653
654 fp.fs = fs;
655 fp.parent = parent;
656 fp.done = 0;
657 fp.ctx = ctx;
658
659#if 0
660 printf("Fixing '..' of inode %lu to be %lu...\n", dir->ino, parent);
661#endif
662
663 retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
664 0, fix_dotdot_proc, &fp);
665 if (retval || !fp.done) {
666 clear_problem_context(&pctx);
667 pctx.ino = dir->ino;
668 pctx.errcode = retval;
669 fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
670 PR_3_FIX_PARENT_NOFIND, &pctx);
671 ext2fs_unmark_valid(fs);
672 }
673 dir->dotdot = parent;
674
675 return;
676}
677
678/*
679 * These routines are responsible for expanding a /lost+found if it is
680 * too small.
681 */
682
683struct expand_dir_struct {
684 int num;
685 int guaranteed_size;
686 int newblocks;
687 int last_block;
688 errcode_t err;
689 e2fsck_t ctx;
690};
691
692static int expand_dir_proc(ext2_filsys fs,
693 blk_t *blocknr,
694 e2_blkcnt_t blockcnt,
695 blk_t ref_block EXT2FS_ATTR((unused)),
696 int ref_offset EXT2FS_ATTR((unused)),
697 void *priv_data)
698{
699 struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
700 blk_t new_blk;
701 static blk_t last_blk = 0;
702 char *block;
703 errcode_t retval;
704 e2fsck_t ctx;
705
706 ctx = es->ctx;
707
708 if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
709 return BLOCK_ABORT;
710
711 if (blockcnt > 0)
712 es->last_block = blockcnt;
713 if (*blocknr) {
714 last_blk = *blocknr;
715 return 0;
716 }
717 retval = ext2fs_new_block(fs, last_blk, ctx->block_found_map,
718 &new_blk);
719 if (retval) {
720 es->err = retval;
721 return BLOCK_ABORT;
722 }
723 if (blockcnt > 0) {
724 retval = ext2fs_new_dir_block(fs, 0, 0, &block);
725 if (retval) {
726 es->err = retval;
727 return BLOCK_ABORT;
728 }
729 es->num--;
730 retval = ext2fs_write_dir_block(fs, new_blk, block);
731 } else {
732 retval = ext2fs_get_mem(fs->blocksize, &block);
733 if (retval) {
734 es->err = retval;
735 return BLOCK_ABORT;
736 }
737 memset(block, 0, fs->blocksize);
738 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
739 }
740 if (retval) {
741 es->err = retval;
742 return BLOCK_ABORT;
743 }
744 ext2fs_free_mem(&block);
745 *blocknr = new_blk;
746 ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
747 ext2fs_block_alloc_stats(fs, new_blk, +1);
748 es->newblocks++;
749
750 if (es->num == 0)
751 return (BLOCK_CHANGED | BLOCK_ABORT);
752 else
753 return BLOCK_CHANGED;
754}
755
756errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
757 int num, int guaranteed_size)
758{
759 ext2_filsys fs = ctx->fs;
760 errcode_t retval;
761 struct expand_dir_struct es;
762 struct ext2_inode inode;
763
764 if (!(fs->flags & EXT2_FLAG_RW))
765 return EXT2_ET_RO_FILSYS;
766
767 /*
768 * Read the inode and block bitmaps in; we'll be messing with
769 * them.
770 */
771 e2fsck_read_bitmaps(ctx);
772
773 retval = ext2fs_check_directory(fs, dir);
774 if (retval)
775 return retval;
776
777 es.num = num;
778 es.guaranteed_size = guaranteed_size;
779 es.last_block = 0;
780 es.err = 0;
781 es.newblocks = 0;
782 es.ctx = ctx;
783
784 retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
785 0, expand_dir_proc, &es);
786
787 if (es.err)
788 return es.err;
789
790 /*
791 * Update the size and block count fields in the inode.
792 */
793 retval = ext2fs_read_inode(fs, dir, &inode);
794 if (retval)
795 return retval;
796
797 inode.i_size = (es.last_block + 1) * fs->blocksize;
798 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
799
800 e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
801
802 return 0;
803}
804
diff --git a/e2fsprogs/e2fsck/pass4.c b/e2fsprogs/e2fsck/pass4.c
deleted file mode 100644
index a9e49f178..000000000
--- a/e2fsprogs/e2fsck/pass4.c
+++ /dev/null
@@ -1,178 +0,0 @@
1/*
2 * pass4.c -- pass #4 of e2fsck: Check reference counts
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * Pass 4 frees the following data structures:
12 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
13 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
14 */
15
16#include "e2fsck.h"
17#include "problem.h"
18
19/*
20 * This routine is called when an inode is not connected to the
21 * directory tree.
22 *
23 * This subroutine returns 1 then the caller shouldn't bother with the
24 * rest of the pass 4 tests.
25 */
26static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i)
27{
28 ext2_filsys fs = ctx->fs;
29 struct ext2_inode inode;
30 struct problem_context pctx;
31
32 e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode");
33 clear_problem_context(&pctx);
34 pctx.ino = i;
35 pctx.inode = &inode;
36
37 /*
38 * Offer to delete any zero-length files that does not have
39 * blocks. If there is an EA block, it might have useful
40 * information, so we won't prompt to delete it, but let it be
41 * reconnected to lost+found.
42 */
43 if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) ||
44 LINUX_S_ISDIR(inode.i_mode))) {
45 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
46 ext2fs_icount_store(ctx->inode_link_info, i, 0);
47 inode.i_links_count = 0;
48 inode.i_dtime = time(0);
49 e2fsck_write_inode(ctx, i, &inode,
50 "disconnect_inode");
51 /*
52 * Fix up the bitmaps...
53 */
54 e2fsck_read_bitmaps(ctx);
55 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i);
56 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i);
57 ext2fs_inode_alloc_stats2(fs, i, -1,
58 LINUX_S_ISDIR(inode.i_mode));
59 return 0;
60 }
61 }
62
63 /*
64 * Prompt to reconnect.
65 */
66 if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
67 if (e2fsck_reconnect_file(ctx, i))
68 ext2fs_unmark_valid(fs);
69 } else {
70 /*
71 * If we don't attach the inode, then skip the
72 * i_links_test since there's no point in trying to
73 * force i_links_count to zero.
74 */
75 ext2fs_unmark_valid(fs);
76 return 1;
77 }
78 return 0;
79}
80
81
82void e2fsck_pass4(e2fsck_t ctx)
83{
84 ext2_filsys fs = ctx->fs;
85 ext2_ino_t i;
86 struct ext2_inode inode;
87#ifdef RESOURCE_TRACK
88 struct resource_track rtrack;
89#endif
90 struct problem_context pctx;
91 __u16 link_count, link_counted;
92 char *buf = 0;
93 int group, maxgroup;
94
95#ifdef RESOURCE_TRACK
96 init_resource_track(&rtrack);
97#endif
98
99#ifdef MTRACE
100 mtrace_print("Pass 4");
101#endif
102
103 clear_problem_context(&pctx);
104
105 if (!(ctx->options & E2F_OPT_PREEN))
106 fix_problem(ctx, PR_4_PASS_HEADER, &pctx);
107
108 group = 0;
109 maxgroup = fs->group_desc_count;
110 if (ctx->progress)
111 if ((ctx->progress)(ctx, 4, 0, maxgroup))
112 return;
113
114 for (i=1; i <= fs->super->s_inodes_count; i++) {
115 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
116 return;
117 if ((i % fs->super->s_inodes_per_group) == 0) {
118 group++;
119 if (ctx->progress)
120 if ((ctx->progress)(ctx, 4, group, maxgroup))
121 return;
122 }
123 if (i == EXT2_BAD_INO ||
124 (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
125 continue;
126 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) ||
127 (ctx->inode_imagic_map &&
128 ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) ||
129 (ctx->inode_bb_map &&
130 ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
131 continue;
132 ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
133 ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
134 if (link_counted == 0) {
135 if (!buf)
136 buf = e2fsck_allocate_memory(ctx,
137 fs->blocksize, "bad_inode buffer");
138 if (e2fsck_process_bad_inode(ctx, 0, i, buf))
139 continue;
140 if (disconnect_inode(ctx, i))
141 continue;
142 ext2fs_icount_fetch(ctx->inode_link_info, i,
143 &link_count);
144 ext2fs_icount_fetch(ctx->inode_count, i,
145 &link_counted);
146 }
147 if (link_counted != link_count) {
148 e2fsck_read_inode(ctx, i, &inode, "pass4");
149 pctx.ino = i;
150 pctx.inode = &inode;
151 if (link_count != inode.i_links_count) {
152 pctx.num = link_count;
153 fix_problem(ctx,
154 PR_4_INCONSISTENT_COUNT, &pctx);
155 }
156 pctx.num = link_counted;
157 if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
158 inode.i_links_count = link_counted;
159 e2fsck_write_inode(ctx, i, &inode, "pass4");
160 }
161 }
162 }
163 ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
164 ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
165 ext2fs_free_inode_bitmap(ctx->inode_bb_map);
166 ctx->inode_bb_map = 0;
167 ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
168 ctx->inode_imagic_map = 0;
169 if (buf)
170 ext2fs_free_mem(&buf);
171#ifdef RESOURCE_TRACK
172 if (ctx->options & E2F_OPT_TIME2) {
173 e2fsck_clear_progbar(ctx);
174 print_resource_track(_("Pass 4"), &rtrack);
175 }
176#endif
177}
178
diff --git a/e2fsprogs/e2fsck/pass5.c b/e2fsprogs/e2fsck/pass5.c
deleted file mode 100644
index e708fa41d..000000000
--- a/e2fsprogs/e2fsck/pass5.c
+++ /dev/null
@@ -1,547 +0,0 @@
1/*
2 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 */
12
13#include "e2fsck.h"
14#include "problem.h"
15
16static void check_block_bitmaps(e2fsck_t ctx);
17static void check_inode_bitmaps(e2fsck_t ctx);
18static void check_inode_end(e2fsck_t ctx);
19static void check_block_end(e2fsck_t ctx);
20
21void e2fsck_pass5(e2fsck_t ctx)
22{
23#ifdef RESOURCE_TRACK
24 struct resource_track rtrack;
25#endif
26 struct problem_context pctx;
27
28#ifdef MTRACE
29 mtrace_print("Pass 5");
30#endif
31
32#ifdef RESOURCE_TRACK
33 init_resource_track(&rtrack);
34#endif
35
36 clear_problem_context(&pctx);
37
38 if (!(ctx->options & E2F_OPT_PREEN))
39 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
40
41 if (ctx->progress)
42 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
43 return;
44
45 e2fsck_read_bitmaps(ctx);
46
47 check_block_bitmaps(ctx);
48 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
49 return;
50 check_inode_bitmaps(ctx);
51 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
52 return;
53 check_inode_end(ctx);
54 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
55 return;
56 check_block_end(ctx);
57 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
58 return;
59
60 ext2fs_free_inode_bitmap(ctx->inode_used_map);
61 ctx->inode_used_map = 0;
62 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
63 ctx->inode_dir_map = 0;
64 ext2fs_free_block_bitmap(ctx->block_found_map);
65 ctx->block_found_map = 0;
66
67#ifdef RESOURCE_TRACK
68 if (ctx->options & E2F_OPT_TIME2) {
69 e2fsck_clear_progbar(ctx);
70 print_resource_track(_("Pass 5"), &rtrack);
71 }
72#endif
73}
74
75#define NO_BLK ((blk_t) -1)
76
77static void print_bitmap_problem(e2fsck_t ctx, int problem,
78 struct problem_context *pctx)
79{
80 switch (problem) {
81 case PR_5_BLOCK_UNUSED:
82 if (pctx->blk == pctx->blk2)
83 pctx->blk2 = 0;
84 else
85 problem = PR_5_BLOCK_RANGE_UNUSED;
86 break;
87 case PR_5_BLOCK_USED:
88 if (pctx->blk == pctx->blk2)
89 pctx->blk2 = 0;
90 else
91 problem = PR_5_BLOCK_RANGE_USED;
92 break;
93 case PR_5_INODE_UNUSED:
94 if (pctx->ino == pctx->ino2)
95 pctx->ino2 = 0;
96 else
97 problem = PR_5_INODE_RANGE_UNUSED;
98 break;
99 case PR_5_INODE_USED:
100 if (pctx->ino == pctx->ino2)
101 pctx->ino2 = 0;
102 else
103 problem = PR_5_INODE_RANGE_USED;
104 break;
105 }
106 fix_problem(ctx, problem, pctx);
107 pctx->blk = pctx->blk2 = NO_BLK;
108 pctx->ino = pctx->ino2 = 0;
109}
110
111static void check_block_bitmaps(e2fsck_t ctx)
112{
113 ext2_filsys fs = ctx->fs;
114 blk_t i;
115 int *free_array;
116 int group = 0;
117 unsigned int blocks = 0;
118 unsigned int free_blocks = 0;
119 int group_free = 0;
120 int actual, bitmap;
121 struct problem_context pctx;
122 int problem, save_problem, fixit, had_problem;
123 errcode_t retval;
124
125 clear_problem_context(&pctx);
126 free_array = (int *) e2fsck_allocate_memory(ctx,
127 fs->group_desc_count * sizeof(int), "free block count array");
128
129 if ((fs->super->s_first_data_block <
130 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
131 (fs->super->s_blocks_count-1 >
132 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
133 pctx.num = 1;
134 pctx.blk = fs->super->s_first_data_block;
135 pctx.blk2 = fs->super->s_blocks_count -1;
136 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
137 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
138 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
139
140 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
141 return;
142 }
143
144 if ((fs->super->s_first_data_block <
145 ext2fs_get_block_bitmap_start(fs->block_map)) ||
146 (fs->super->s_blocks_count-1 >
147 ext2fs_get_block_bitmap_end(fs->block_map))) {
148 pctx.num = 2;
149 pctx.blk = fs->super->s_first_data_block;
150 pctx.blk2 = fs->super->s_blocks_count -1;
151 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
152 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
153 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
154
155 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
156 return;
157 }
158
159redo_counts:
160 had_problem = 0;
161 save_problem = 0;
162 pctx.blk = pctx.blk2 = NO_BLK;
163 for (i = fs->super->s_first_data_block;
164 i < fs->super->s_blocks_count;
165 i++) {
166 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
167 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
168
169 if (actual == bitmap)
170 goto do_counts;
171
172 if (!actual && bitmap) {
173 /*
174 * Block not used, but marked in use in the bitmap.
175 */
176 problem = PR_5_BLOCK_UNUSED;
177 } else {
178 /*
179 * Block used, but not marked in use in the bitmap.
180 */
181 problem = PR_5_BLOCK_USED;
182 }
183 if (pctx.blk == NO_BLK) {
184 pctx.blk = pctx.blk2 = i;
185 save_problem = problem;
186 } else {
187 if ((problem == save_problem) &&
188 (pctx.blk2 == i-1))
189 pctx.blk2++;
190 else {
191 print_bitmap_problem(ctx, save_problem, &pctx);
192 pctx.blk = pctx.blk2 = i;
193 save_problem = problem;
194 }
195 }
196 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
197 had_problem++;
198
199 do_counts:
200 if (!bitmap) {
201 group_free++;
202 free_blocks++;
203 }
204 blocks ++;
205 if ((blocks == fs->super->s_blocks_per_group) ||
206 (i == fs->super->s_blocks_count-1)) {
207 free_array[group] = group_free;
208 group ++;
209 blocks = 0;
210 group_free = 0;
211 if (ctx->progress)
212 if ((ctx->progress)(ctx, 5, group,
213 fs->group_desc_count*2))
214 return;
215 }
216 }
217 if (pctx.blk != NO_BLK)
218 print_bitmap_problem(ctx, save_problem, &pctx);
219 if (had_problem)
220 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
221 else
222 fixit = -1;
223 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
224
225 if (fixit == 1) {
226 ext2fs_free_block_bitmap(fs->block_map);
227 retval = ext2fs_copy_bitmap(ctx->block_found_map,
228 &fs->block_map);
229 if (retval) {
230 clear_problem_context(&pctx);
231 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
232 ctx->flags |= E2F_FLAG_ABORT;
233 return;
234 }
235 ext2fs_set_bitmap_padding(fs->block_map);
236 ext2fs_mark_bb_dirty(fs);
237
238 /* Redo the counts */
239 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
240 memset(free_array, 0, fs->group_desc_count * sizeof(int));
241 goto redo_counts;
242 } else if (fixit == 0)
243 ext2fs_unmark_valid(fs);
244
245 for (i = 0; i < fs->group_desc_count; i++) {
246 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
247 pctx.group = i;
248 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
249 pctx.blk2 = free_array[i];
250
251 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
252 &pctx)) {
253 fs->group_desc[i].bg_free_blocks_count =
254 free_array[i];
255 ext2fs_mark_super_dirty(fs);
256 } else
257 ext2fs_unmark_valid(fs);
258 }
259 }
260 if (free_blocks != fs->super->s_free_blocks_count) {
261 pctx.group = 0;
262 pctx.blk = fs->super->s_free_blocks_count;
263 pctx.blk2 = free_blocks;
264
265 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
266 fs->super->s_free_blocks_count = free_blocks;
267 ext2fs_mark_super_dirty(fs);
268 } else
269 ext2fs_unmark_valid(fs);
270 }
271 ext2fs_free_mem(&free_array);
272}
273
274static void check_inode_bitmaps(e2fsck_t ctx)
275{
276 ext2_filsys fs = ctx->fs;
277 ext2_ino_t i;
278 unsigned int free_inodes = 0;
279 int group_free = 0;
280 int dirs_count = 0;
281 int group = 0;
282 unsigned int inodes = 0;
283 int *free_array;
284 int *dir_array;
285 int actual, bitmap;
286 errcode_t retval;
287 struct problem_context pctx;
288 int problem, save_problem, fixit, had_problem;
289
290 clear_problem_context(&pctx);
291 free_array = (int *) e2fsck_allocate_memory(ctx,
292 fs->group_desc_count * sizeof(int), "free inode count array");
293
294 dir_array = (int *) e2fsck_allocate_memory(ctx,
295 fs->group_desc_count * sizeof(int), "directory count array");
296
297 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
298 (fs->super->s_inodes_count >
299 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
300 pctx.num = 3;
301 pctx.blk = 1;
302 pctx.blk2 = fs->super->s_inodes_count;
303 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
304 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
305 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
306
307 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
308 return;
309 }
310 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
311 (fs->super->s_inodes_count >
312 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
313 pctx.num = 4;
314 pctx.blk = 1;
315 pctx.blk2 = fs->super->s_inodes_count;
316 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
317 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
318 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
319
320 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
321 return;
322 }
323
324redo_counts:
325 had_problem = 0;
326 save_problem = 0;
327 pctx.ino = pctx.ino2 = 0;
328 for (i = 1; i <= fs->super->s_inodes_count; i++) {
329 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
330 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
331
332 if (actual == bitmap)
333 goto do_counts;
334
335 if (!actual && bitmap) {
336 /*
337 * Inode wasn't used, but marked in bitmap
338 */
339 problem = PR_5_INODE_UNUSED;
340 } else /* if (actual && !bitmap) */ {
341 /*
342 * Inode used, but not in bitmap
343 */
344 problem = PR_5_INODE_USED;
345 }
346 if (pctx.ino == 0) {
347 pctx.ino = pctx.ino2 = i;
348 save_problem = problem;
349 } else {
350 if ((problem == save_problem) &&
351 (pctx.ino2 == i-1))
352 pctx.ino2++;
353 else {
354 print_bitmap_problem(ctx, save_problem, &pctx);
355 pctx.ino = pctx.ino2 = i;
356 save_problem = problem;
357 }
358 }
359 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
360 had_problem++;
361
362do_counts:
363 if (!bitmap) {
364 group_free++;
365 free_inodes++;
366 } else {
367 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
368 dirs_count++;
369 }
370 inodes++;
371 if ((inodes == fs->super->s_inodes_per_group) ||
372 (i == fs->super->s_inodes_count)) {
373 free_array[group] = group_free;
374 dir_array[group] = dirs_count;
375 group ++;
376 inodes = 0;
377 group_free = 0;
378 dirs_count = 0;
379 if (ctx->progress)
380 if ((ctx->progress)(ctx, 5,
381 group + fs->group_desc_count,
382 fs->group_desc_count*2))
383 return;
384 }
385 }
386 if (pctx.ino)
387 print_bitmap_problem(ctx, save_problem, &pctx);
388
389 if (had_problem)
390 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
391 else
392 fixit = -1;
393 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
394
395 if (fixit == 1) {
396 ext2fs_free_inode_bitmap(fs->inode_map);
397 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
398 &fs->inode_map);
399 if (retval) {
400 clear_problem_context(&pctx);
401 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
402 ctx->flags |= E2F_FLAG_ABORT;
403 return;
404 }
405 ext2fs_set_bitmap_padding(fs->inode_map);
406 ext2fs_mark_ib_dirty(fs);
407
408 /* redo counts */
409 inodes = 0; free_inodes = 0; group_free = 0;
410 dirs_count = 0; group = 0;
411 memset(free_array, 0, fs->group_desc_count * sizeof(int));
412 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
413 goto redo_counts;
414 } else if (fixit == 0)
415 ext2fs_unmark_valid(fs);
416
417 for (i = 0; i < fs->group_desc_count; i++) {
418 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
419 pctx.group = i;
420 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
421 pctx.ino2 = free_array[i];
422 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
423 &pctx)) {
424 fs->group_desc[i].bg_free_inodes_count =
425 free_array[i];
426 ext2fs_mark_super_dirty(fs);
427 } else
428 ext2fs_unmark_valid(fs);
429 }
430 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
431 pctx.group = i;
432 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
433 pctx.ino2 = dir_array[i];
434
435 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
436 &pctx)) {
437 fs->group_desc[i].bg_used_dirs_count =
438 dir_array[i];
439 ext2fs_mark_super_dirty(fs);
440 } else
441 ext2fs_unmark_valid(fs);
442 }
443 }
444 if (free_inodes != fs->super->s_free_inodes_count) {
445 pctx.group = -1;
446 pctx.ino = fs->super->s_free_inodes_count;
447 pctx.ino2 = free_inodes;
448
449 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
450 fs->super->s_free_inodes_count = free_inodes;
451 ext2fs_mark_super_dirty(fs);
452 } else
453 ext2fs_unmark_valid(fs);
454 }
455 ext2fs_free_mem(&free_array);
456 ext2fs_free_mem(&dir_array);
457}
458
459static void check_inode_end(e2fsck_t ctx)
460{
461 ext2_filsys fs = ctx->fs;
462 ext2_ino_t end, save_inodes_count, i;
463 struct problem_context pctx;
464
465 clear_problem_context(&pctx);
466
467 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
468 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
469 &save_inodes_count);
470 if (pctx.errcode) {
471 pctx.num = 1;
472 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
473 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
474 return;
475 }
476 if (save_inodes_count == end)
477 return;
478
479 for (i = save_inodes_count + 1; i <= end; i++) {
480 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
481 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
482 for (i = save_inodes_count + 1; i <= end; i++)
483 ext2fs_mark_inode_bitmap(fs->inode_map,
484 i);
485 ext2fs_mark_ib_dirty(fs);
486 } else
487 ext2fs_unmark_valid(fs);
488 break;
489 }
490 }
491
492 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
493 save_inodes_count, 0);
494 if (pctx.errcode) {
495 pctx.num = 2;
496 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
497 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
498 return;
499 }
500}
501
502static void check_block_end(e2fsck_t ctx)
503{
504 ext2_filsys fs = ctx->fs;
505 blk_t end, save_blocks_count, i;
506 struct problem_context pctx;
507
508 clear_problem_context(&pctx);
509
510 end = fs->block_map->start +
511 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
512 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
513 &save_blocks_count);
514 if (pctx.errcode) {
515 pctx.num = 3;
516 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
517 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
518 return;
519 }
520 if (save_blocks_count == end)
521 return;
522
523 for (i = save_blocks_count + 1; i <= end; i++) {
524 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
525 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
526 for (i = save_blocks_count + 1; i <= end; i++)
527 ext2fs_mark_block_bitmap(fs->block_map,
528 i);
529 ext2fs_mark_bb_dirty(fs);
530 } else
531 ext2fs_unmark_valid(fs);
532 break;
533 }
534 }
535
536 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
537 save_blocks_count, 0);
538 if (pctx.errcode) {
539 pctx.num = 4;
540 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
541 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
542 return;
543 }
544}
545
546
547
diff --git a/e2fsprogs/e2fsck/problem.c b/e2fsprogs/e2fsck/problem.c
deleted file mode 100644
index 7be4d6245..000000000
--- a/e2fsprogs/e2fsck/problem.c
+++ /dev/null
@@ -1,1655 +0,0 @@
1/*
2 * problem.c --- report filesystem problems to the user
3 *
4 * Copyright 1996, 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <ctype.h>
16#include <termios.h>
17
18#include "e2fsck.h"
19
20#include "problem.h"
21#include "problemP.h"
22
23#define PROMPT_NONE 0
24#define PROMPT_FIX 1
25#define PROMPT_CLEAR 2
26#define PROMPT_RELOCATE 3
27#define PROMPT_ALLOCATE 4
28#define PROMPT_EXPAND 5
29#define PROMPT_CONNECT 6
30#define PROMPT_CREATE 7
31#define PROMPT_SALVAGE 8
32#define PROMPT_TRUNCATE 9
33#define PROMPT_CLEAR_INODE 10
34#define PROMPT_ABORT 11
35#define PROMPT_SPLIT 12
36#define PROMPT_CONTINUE 13
37#define PROMPT_CLONE 14
38#define PROMPT_DELETE 15
39#define PROMPT_SUPPRESS 16
40#define PROMPT_UNLINK 17
41#define PROMPT_CLEAR_HTREE 18
42#define PROMPT_RECREATE 19
43#define PROMPT_NULL 20
44
45/*
46 * These are the prompts which are used to ask the user if they want
47 * to fix a problem.
48 */
49static const char *prompt[] = {
50 N_("(no prompt)"), /* 0 */
51 N_("Fix"), /* 1 */
52 N_("Clear"), /* 2 */
53 N_("Relocate"), /* 3 */
54 N_("Allocate"), /* 4 */
55 N_("Expand"), /* 5 */
56 N_("Connect to /lost+found"), /* 6 */
57 N_("Create"), /* 7 */
58 N_("Salvage"), /* 8 */
59 N_("Truncate"), /* 9 */
60 N_("Clear inode"), /* 10 */
61 N_("Abort"), /* 11 */
62 N_("Split"), /* 12 */
63 N_("Continue"), /* 13 */
64 N_("Clone duplicate/bad blocks"), /* 14 */
65 N_("Delete file"), /* 15 */
66 N_("Suppress messages"),/* 16 */
67 N_("Unlink"), /* 17 */
68 N_("Clear HTree index"),/* 18 */
69 N_("Recreate"), /* 19 */
70 "", /* 20 */
71};
72
73/*
74 * These messages are printed when we are preen mode and we will be
75 * automatically fixing the problem.
76 */
77static const char *preen_msg[] = {
78 N_("(NONE)"), /* 0 */
79 N_("FIXED"), /* 1 */
80 N_("CLEARED"), /* 2 */
81 N_("RELOCATED"), /* 3 */
82 N_("ALLOCATED"), /* 4 */
83 N_("EXPANDED"), /* 5 */
84 N_("RECONNECTED"), /* 6 */
85 N_("CREATED"), /* 7 */
86 N_("SALVAGED"), /* 8 */
87 N_("TRUNCATED"), /* 9 */
88 N_("INODE CLEARED"), /* 10 */
89 N_("ABORTED"), /* 11 */
90 N_("SPLIT"), /* 12 */
91 N_("CONTINUING"), /* 13 */
92 N_("DUPLICATE/BAD BLOCKS CLONED"), /* 14 */
93 N_("FILE DELETED"), /* 15 */
94 N_("SUPPRESSED"), /* 16 */
95 N_("UNLINKED"), /* 17 */
96 N_("HTREE INDEX CLEARED"),/* 18 */
97 N_("WILL RECREATE"), /* 19 */
98 "", /* 20 */
99};
100
101static const struct e2fsck_problem problem_table[] = {
102
103 /* Pre-Pass 1 errors */
104
105 /* Block bitmap not in group */
106 { PR_0_BB_NOT_GROUP, N_("@b @B for @g %g is not in @g. (@b %b)\n"),
107 PROMPT_RELOCATE, PR_LATCH_RELOC },
108
109 /* Inode bitmap not in group */
110 { PR_0_IB_NOT_GROUP, N_("@i @B for @g %g is not in @g. (@b %b)\n"),
111 PROMPT_RELOCATE, PR_LATCH_RELOC },
112
113 /* Inode table not in group */
114 { PR_0_ITABLE_NOT_GROUP,
115 N_("@i table for @g %g is not in @g. (@b %b)\n"
116 "WARNING: SEVERE DATA LOSS POSSIBLE.\n"),
117 PROMPT_RELOCATE, PR_LATCH_RELOC },
118
119 /* Superblock corrupt */
120 { PR_0_SB_CORRUPT,
121 N_("\nThe @S could not be read or does not describe a correct ext2\n"
122 "@f. If the @v is valid and it really contains an ext2\n"
123 "@f (and not swap or ufs or something else), then the @S\n"
124 "is corrupt, and you might try running e2fsck with an alternate @S:\n"
125 " e2fsck -b %S <@v>\n\n"),
126 PROMPT_NONE, PR_FATAL },
127
128 /* Filesystem size is wrong */
129 { PR_0_FS_SIZE_WRONG,
130 N_("The @f size (according to the @S) is %b @bs\n"
131 "The physical size of the @v is %c @bs\n"
132 "Either the @S or the partition table is likely to be corrupt!\n"),
133 PROMPT_ABORT, 0 },
134
135 /* Fragments not supported */
136 { PR_0_NO_FRAGMENTS,
137 N_("@S @b_size = %b, fragsize = %c.\n"
138 "This version of e2fsck does not support fragment sizes different\n"
139 "from the @b size.\n"),
140 PROMPT_NONE, PR_FATAL },
141
142 /* Bad blocks_per_group */
143 { PR_0_BLOCKS_PER_GROUP,
144 N_("@S @bs_per_group = %b, should have been %c\n"),
145 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
146
147 /* Bad first_data_block */
148 { PR_0_FIRST_DATA_BLOCK,
149 N_("@S first_data_@b = %b, should have been %c\n"),
150 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
151
152 /* Adding UUID to filesystem */
153 { PR_0_ADD_UUID,
154 N_("@f did not have a UUID; generating one.\n\n"),
155 PROMPT_NONE, 0 },
156
157 /* Relocate hint */
158 { PR_0_RELOCATE_HINT,
159 N_("Note: if there is several inode or block bitmap blocks\n"
160 "which require relocation, or one part of the inode table\n"
161 "which must be moved, you may wish to try running e2fsck\n"
162 "with the '-b %S' option first. The problem may lie only\n"
163 "with the primary block group descriptor, and the backup\n"
164 "block group descriptor may be OK.\n\n"),
165 PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
166
167 /* Miscellaneous superblock corruption */
168 { PR_0_MISC_CORRUPT_SUPER,
169 N_("Corruption found in @S. (%s = %N).\n"),
170 PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
171
172 /* Error determing physical device size of filesystem */
173 { PR_0_GETSIZE_ERROR,
174 N_("Error determining size of the physical @v: %m\n"),
175 PROMPT_NONE, PR_FATAL },
176
177 /* Inode count in superblock is incorrect */
178 { PR_0_INODE_COUNT_WRONG,
179 N_("@i count in @S is %i, should be %j.\n"),
180 PROMPT_FIX, 0 },
181
182 { PR_0_HURD_CLEAR_FILETYPE,
183 N_("The Hurd does not support the filetype feature.\n"),
184 PROMPT_CLEAR, 0 },
185
186 /* Journal inode is invalid */
187 { PR_0_JOURNAL_BAD_INODE,
188 N_("@S has a bad ext3 @j (@i %i).\n"),
189 PROMPT_CLEAR, PR_PREEN_OK },
190
191 /* The external journal has (unsupported) multiple filesystems */
192 { PR_0_JOURNAL_UNSUPP_MULTIFS,
193 N_("External @j has multiple @f users (unsupported).\n"),
194 PROMPT_NONE, PR_FATAL },
195
196 /* Can't find external journal */
197 { PR_0_CANT_FIND_JOURNAL,
198 N_("Can't find external @j\n"),
199 PROMPT_NONE, PR_FATAL },
200
201 /* External journal has bad superblock */
202 { PR_0_EXT_JOURNAL_BAD_SUPER,
203 N_("External @j has bad @S\n"),
204 PROMPT_NONE, PR_FATAL },
205
206 /* Superblock has a bad journal UUID */
207 { PR_0_JOURNAL_BAD_UUID,
208 N_("External @j does not support this @f\n"),
209 PROMPT_NONE, PR_FATAL },
210
211 /* Journal has an unknown superblock type */
212 { PR_0_JOURNAL_UNSUPP_SUPER,
213 N_("Ext3 @j @S is unknown type %N (unsupported).\n"
214 "It is likely that your copy of e2fsck is old and/or doesn't "
215 "support this @j format.\n"
216 "It is also possible the @j @S is corrupt.\n"),
217 PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_SUPER },
218
219 /* Journal superblock is corrupt */
220 { PR_0_JOURNAL_BAD_SUPER,
221 N_("Ext3 @j @S is corrupt.\n"),
222 PROMPT_FIX, PR_PREEN_OK },
223
224 /* Superblock flag should be cleared */
225 { PR_0_JOURNAL_HAS_JOURNAL,
226 N_("@S doesn't have has_@j flag, but has ext3 @j %s.\n"),
227 PROMPT_CLEAR, PR_PREEN_OK },
228
229 /* Superblock flag is incorrect */
230 { PR_0_JOURNAL_RECOVER_SET,
231 N_("@S has ext3 needs_recovery flag set, but no @j.\n"),
232 PROMPT_CLEAR, PR_PREEN_OK },
233
234 /* Journal has data, but recovery flag is clear */
235 { PR_0_JOURNAL_RECOVERY_CLEAR,
236 N_("ext3 recovery flag clear, but @j has data.\n"),
237 PROMPT_NONE, 0 },
238
239 /* Ask if we should clear the journal */
240 { PR_0_JOURNAL_RESET_JOURNAL,
241 N_("Clear @j"),
242 PROMPT_NULL, PR_PREEN_NOMSG },
243
244 /* Ask if we should run the journal anyway */
245 { PR_0_JOURNAL_RUN,
246 N_("Run @j anyway"),
247 PROMPT_NULL, 0 },
248
249 /* Run the journal by default */
250 { PR_0_JOURNAL_RUN_DEFAULT,
251 N_("Recovery flag not set in backup @S, so running @j anyway.\n"),
252 PROMPT_NONE, 0 },
253
254 /* Clearing orphan inode */
255 { PR_0_ORPHAN_CLEAR_INODE,
256 N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
257 PROMPT_NONE, 0 },
258
259 /* Illegal block found in orphaned inode */
260 { PR_0_ORPHAN_ILLEGAL_BLOCK_NUM,
261 N_("@I @b #%B (%b) found in @o @i %i.\n"),
262 PROMPT_NONE, 0 },
263
264 /* Already cleared block found in orphaned inode */
265 { PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
266 N_("Already cleared @b #%B (%b) found in @o @i %i.\n"),
267 PROMPT_NONE, 0 },
268
269 /* Illegal orphan inode in superblock */
270 { PR_0_ORPHAN_ILLEGAL_HEAD_INODE,
271 N_("@I @o @i %i in @S.\n"),
272 PROMPT_NONE, 0 },
273
274 /* Illegal inode in orphaned inode list */
275 { PR_0_ORPHAN_ILLEGAL_INODE,
276 N_("@I @i %i in @o @i list.\n"),
277 PROMPT_NONE, 0 },
278
279 /* Filesystem revision is 0, but feature flags are set */
280 { PR_0_FS_REV_LEVEL,
281 "@f has feature flag(s) set, but is a revision 0 @f. ",
282 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
283
284 /* Journal superblock has an unknown read-only feature flag set */
285 { PR_0_JOURNAL_UNSUPP_ROCOMPAT,
286 N_("Ext3 @j @S has an unknown read-only feature flag set.\n"),
287 PROMPT_ABORT, 0 },
288
289 /* Journal superblock has an unknown incompatible feature flag set */
290 { PR_0_JOURNAL_UNSUPP_INCOMPAT,
291 N_("Ext3 @j @S has an unknown incompatible feature flag set.\n"),
292 PROMPT_ABORT, 0 },
293
294 /* Journal has unsupported version number */
295 { PR_0_JOURNAL_UNSUPP_VERSION,
296 N_("@j version not supported by this e2fsck.\n"),
297 PROMPT_ABORT, 0 },
298
299 /* Moving journal to hidden file */
300 { PR_0_MOVE_JOURNAL,
301 N_("Moving @j from /%s to hidden inode.\n\n"),
302 PROMPT_NONE, 0 },
303
304 /* Error moving journal to hidden file */
305 { PR_0_ERR_MOVE_JOURNAL,
306 N_("Error moving @j: %m\n\n"),
307 PROMPT_NONE, 0 },
308
309 /* Clearing V2 journal superblock */
310 { PR_0_CLEAR_V2_JOURNAL,
311 N_("Found invalid V2 @j @S fields (from V1 journal).\n"
312 "Clearing fields beyond the V1 @j @S...\n\n"),
313 PROMPT_NONE, 0 },
314
315 /* Backup journal inode blocks */
316 { PR_0_BACKUP_JNL,
317 N_("Backing up @j @i @b information.\n\n"),
318 PROMPT_NONE, 0 },
319
320 /* Reserved blocks w/o resize_inode */
321 { PR_0_NONZERO_RESERVED_GDT_BLOCKS,
322 N_("@f does not have resize_@i enabled, but s_reserved_gdt_@bs\n"
323 "is %N; @s zero. "),
324 PROMPT_FIX, 0 },
325
326 /* Resize_inode not enabled, but resize inode is non-zero */
327 { PR_0_CLEAR_RESIZE_INODE,
328 N_("Resize_@i not enabled, but the resize inode is non-zero. "),
329 PROMPT_CLEAR, 0 },
330
331 /* Resize inode invalid */
332 { PR_0_RESIZE_INODE_INVALID,
333 N_("Resize @i not valid. "),
334 PROMPT_RECREATE, 0 },
335
336 /* Pass 1 errors */
337
338 /* Pass 1: Checking inodes, blocks, and sizes */
339 { PR_1_PASS_HEADER,
340 N_("Pass 1: Checking @is, @bs, and sizes\n"),
341 PROMPT_NONE, 0 },
342
343 /* Root directory is not an inode */
344 { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "),
345 PROMPT_CLEAR, 0 },
346
347 /* Root directory has dtime set */
348 { PR_1_ROOT_DTIME,
349 N_("@r has dtime set (probably due to old mke2fs). "),
350 PROMPT_FIX, PR_PREEN_OK },
351
352 /* Reserved inode has bad mode */
353 { PR_1_RESERVED_BAD_MODE,
354 N_("Reserved @i %i %Q has bad mode. "),
355 PROMPT_CLEAR, PR_PREEN_OK },
356
357 /* Deleted inode has zero dtime */
358 { PR_1_ZERO_DTIME,
359 N_("@D @i %i has zero dtime. "),
360 PROMPT_FIX, PR_PREEN_OK },
361
362 /* Inode in use, but dtime set */
363 { PR_1_SET_DTIME,
364 N_("@i %i is in use, but has dtime set. "),
365 PROMPT_FIX, PR_PREEN_OK },
366
367 /* Zero-length directory */
368 { PR_1_ZERO_LENGTH_DIR,
369 N_("@i %i is a @z @d. "),
370 PROMPT_CLEAR, PR_PREEN_OK },
371
372 /* Block bitmap conflicts with some other fs block */
373 { PR_1_BB_CONFLICT,
374 N_("@g %g's @b @B at %b @C.\n"),
375 PROMPT_RELOCATE, 0 },
376
377 /* Inode bitmap conflicts with some other fs block */
378 { PR_1_IB_CONFLICT,
379 N_("@g %g's @i @B at %b @C.\n"),
380 PROMPT_RELOCATE, 0 },
381
382 /* Inode table conflicts with some other fs block */
383 { PR_1_ITABLE_CONFLICT,
384 N_("@g %g's @i table at %b @C.\n"),
385 PROMPT_RELOCATE, 0 },
386
387 /* Block bitmap is on a bad block */
388 { PR_1_BB_BAD_BLOCK,
389 N_("@g %g's @b @B (%b) is bad. "),
390 PROMPT_RELOCATE, 0 },
391
392 /* Inode bitmap is on a bad block */
393 { PR_1_IB_BAD_BLOCK,
394 N_("@g %g's @i @B (%b) is bad. "),
395 PROMPT_RELOCATE, 0 },
396
397 /* Inode has incorrect i_size */
398 { PR_1_BAD_I_SIZE,
399 N_("@i %i, i_size is %Is, @s %N. "),
400 PROMPT_FIX, PR_PREEN_OK },
401
402 /* Inode has incorrect i_blocks */
403 { PR_1_BAD_I_BLOCKS,
404 N_("@i %i, i_@bs is %Ib, @s %N. "),
405 PROMPT_FIX, PR_PREEN_OK },
406
407 /* Illegal blocknumber in inode */
408 { PR_1_ILLEGAL_BLOCK_NUM,
409 N_("@I @b #%B (%b) in @i %i. "),
410 PROMPT_CLEAR, PR_LATCH_BLOCK },
411
412 /* Block number overlaps fs metadata */
413 { PR_1_BLOCK_OVERLAPS_METADATA,
414 N_("@b #%B (%b) overlaps @f metadata in @i %i. "),
415 PROMPT_CLEAR, PR_LATCH_BLOCK },
416
417 /* Inode has illegal blocks (latch question) */
418 { PR_1_INODE_BLOCK_LATCH,
419 N_("@i %i has illegal @b(s). "),
420 PROMPT_CLEAR, 0 },
421
422 /* Too many bad blocks in inode */
423 { PR_1_TOO_MANY_BAD_BLOCKS,
424 N_("Too many illegal @bs in @i %i.\n"),
425 PROMPT_CLEAR_INODE, PR_NO_OK },
426
427 /* Illegal block number in bad block inode */
428 { PR_1_BB_ILLEGAL_BLOCK_NUM,
429 N_("@I @b #%B (%b) in bad @b @i. "),
430 PROMPT_CLEAR, PR_LATCH_BBLOCK },
431
432 /* Bad block inode has illegal blocks (latch question) */
433 { PR_1_INODE_BBLOCK_LATCH,
434 N_("Bad @b @i has illegal @b(s). "),
435 PROMPT_CLEAR, 0 },
436
437 /* Duplicate or bad blocks in use! */
438 { PR_1_DUP_BLOCKS_PREENSTOP,
439 N_("Duplicate or bad @b in use!\n"),
440 PROMPT_NONE, 0 },
441
442 /* Bad block used as bad block indirect block */
443 { PR_1_BBINODE_BAD_METABLOCK,
444 N_("Bad @b %b used as bad @b @i indirect @b. "),
445 PROMPT_CLEAR, PR_LATCH_BBLOCK },
446
447 /* Inconsistency can't be fixed prompt */
448 { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
449 N_("\nThe bad @b @i has probably been corrupted. You probably\n"
450 "should stop now and run ""e2fsck -c"" to scan for bad blocks\n"
451 "in the @f.\n"),
452 PROMPT_CONTINUE, PR_PREEN_NOMSG },
453
454 /* Bad primary block */
455 { PR_1_BAD_PRIMARY_BLOCK,
456 N_("\nIf the @b is really bad, the @f can not be fixed.\n"),
457 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
458
459 /* Bad primary block prompt */
460 { PR_1_BAD_PRIMARY_BLOCK_PROMPT,
461 N_("You can clear the this @b (and hope for the best) from the\n"
462 "bad @b list and hope that @b is really OK, but there are no\n"
463 "guarantees.\n\n"),
464 PROMPT_CLEAR, PR_PREEN_NOMSG },
465
466 /* Bad primary superblock */
467 { PR_1_BAD_PRIMARY_SUPERBLOCK,
468 N_("The primary @S (%b) is on the bad @b list.\n"),
469 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
470
471 /* Bad primary block group descriptors */
472 { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
473 N_("Block %b in the primary @g descriptors "
474 "is on the bad @b list\n"),
475 PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
476
477 /* Bad superblock in group */
478 { PR_1_BAD_SUPERBLOCK,
479 N_("Warning: Group %g's @S (%b) is bad.\n"),
480 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
481
482 /* Bad block group descriptors in group */
483 { PR_1_BAD_GROUP_DESCRIPTORS,
484 N_("Warning: Group %g's copy of the @g descriptors has a bad "
485 "@b (%b).\n"),
486 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
487
488 /* Block claimed for no reason */
489 { PR_1_PROGERR_CLAIMED_BLOCK,
490 N_("Programming error? @b #%b claimed for no reason in "
491 "process_bad_@b.\n"),
492 PROMPT_NONE, PR_PREEN_OK },
493
494 /* Error allocating blocks for relocating metadata */
495 { PR_1_RELOC_BLOCK_ALLOCATE,
496 N_("@A %N contiguous @b(s) in @b @g %g for %s: %m\n"),
497 PROMPT_NONE, PR_PREEN_OK },
498
499 /* Error allocating block buffer during relocation process */
500 { PR_1_RELOC_MEMORY_ALLOCATE,
501 N_("@A @b buffer for relocating %s\n"),
502 PROMPT_NONE, PR_PREEN_OK },
503
504 /* Relocating metadata group information from X to Y */
505 { PR_1_RELOC_FROM_TO,
506 N_("Relocating @g %g's %s from %b to %c...\n"),
507 PROMPT_NONE, PR_PREEN_OK },
508
509 /* Relocating metatdata group information to X */
510 { PR_1_RELOC_TO,
511 N_("Relocating @g %g's %s to %c...\n"), /* xgettext:no-c-format */
512 PROMPT_NONE, PR_PREEN_OK },
513
514 /* Block read error during relocation process */
515 { PR_1_RELOC_READ_ERR,
516 N_("Warning: could not read @b %b of %s: %m\n"),
517 PROMPT_NONE, PR_PREEN_OK },
518
519 /* Block write error during relocation process */
520 { PR_1_RELOC_WRITE_ERR,
521 N_("Warning: could not write @b %b for %s: %m\n"),
522 PROMPT_NONE, PR_PREEN_OK },
523
524 /* Error allocating inode bitmap */
525 { PR_1_ALLOCATE_IBITMAP_ERROR,
526 "@A @i @B (%N): %m\n",
527 PROMPT_NONE, PR_FATAL },
528
529 /* Error allocating block bitmap */
530 { PR_1_ALLOCATE_BBITMAP_ERROR,
531 "@A @b @B (%N): %m\n",
532 PROMPT_NONE, PR_FATAL },
533
534 /* Error allocating icount structure */
535 { PR_1_ALLOCATE_ICOUNT,
536 N_("@A icount link information: %m\n"),
537 PROMPT_NONE, PR_FATAL },
538
539 /* Error allocating dbcount */
540 { PR_1_ALLOCATE_DBCOUNT,
541 N_("@A @d @b array: %m\n"),
542 PROMPT_NONE, PR_FATAL },
543
544 /* Error while scanning inodes */
545 { PR_1_ISCAN_ERROR,
546 N_("Error while scanning @is (%i): %m\n"),
547 PROMPT_NONE, PR_FATAL },
548
549 /* Error while iterating over blocks */
550 { PR_1_BLOCK_ITERATE,
551 N_("Error while iterating over @bs in @i %i: %m\n"),
552 PROMPT_NONE, PR_FATAL },
553
554 /* Error while storing inode count information */
555 { PR_1_ICOUNT_STORE,
556 N_("Error storing @i count information (@i=%i, count=%N): %m\n"),
557 PROMPT_NONE, PR_FATAL },
558
559 /* Error while storing directory block information */
560 { PR_1_ADD_DBLOCK,
561 N_("Error storing @d @b information "
562 "(@i=%i, @b=%b, num=%N): %m\n"),
563 PROMPT_NONE, PR_FATAL },
564
565 /* Error while reading inode (for clearing) */
566 { PR_1_READ_INODE,
567 N_("Error reading @i %i: %m\n"),
568 PROMPT_NONE, PR_FATAL },
569
570 /* Suppress messages prompt */
571 { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
572
573 /* Imagic flag set on an inode when filesystem doesn't support it */
574 { PR_1_SET_IMAGIC,
575 N_("@i %i has imagic flag set. "),
576 PROMPT_CLEAR, 0 },
577
578 /* Immutable flag set on a device or socket inode */
579 { PR_1_SET_IMMUTABLE,
580 N_("Special (@v/socket/fifo/symlink) file (@i %i) has immutable\n"
581 "or append-only flag set. "),
582 PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
583
584 /* Compression flag set on an inode when filesystem doesn't support it */
585 { PR_1_COMPR_SET,
586 N_("@i %i has @cion flag set on @f without @cion support. "),
587 PROMPT_CLEAR, 0 },
588
589 /* Non-zero size for device, fifo or socket inode */
590 { PR_1_SET_NONZSIZE,
591 "Special (@v/socket/fifo) @i %i has non-zero size. ",
592 PROMPT_FIX, PR_PREEN_OK },
593
594 /* Filesystem revision is 0, but feature flags are set */
595 { PR_1_FS_REV_LEVEL,
596 "@f has feature flag(s) set, but is a revision 0 @f. ",
597 PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
598
599 /* Journal inode is not in use, but contains data */
600 { PR_1_JOURNAL_INODE_NOT_CLEAR,
601 "@j @i is not in use, but contains data. ",
602 PROMPT_CLEAR, PR_PREEN_OK },
603
604 /* Journal has bad mode */
605 { PR_1_JOURNAL_BAD_MODE,
606 N_("@j is not regular file. "),
607 PROMPT_FIX, PR_PREEN_OK },
608
609 /* Deal with inodes that were part of orphan linked list */
610 { PR_1_LOW_DTIME,
611 N_("@i %i was part of the orphaned @i list. "),
612 PROMPT_FIX, PR_LATCH_LOW_DTIME, 0 },
613
614 /* Deal with inodes that were part of corrupted orphan linked
615 list (latch question) */
616 { PR_1_ORPHAN_LIST_REFUGEES,
617 N_("@is that were part of a corrupted orphan linked list found. "),
618 PROMPT_FIX, 0 },
619
620 /* Error allocating refcount structure */
621 { PR_1_ALLOCATE_REFCOUNT,
622 "@A refcount structure (%N): %m\n",
623 PROMPT_NONE, PR_FATAL },
624
625 /* Error reading extended attribute block */
626 { PR_1_READ_EA_BLOCK,
627 N_("Error reading @a @b %b for @i %i. "),
628 PROMPT_CLEAR, 0 },
629
630 /* Invalid extended attribute block */
631 { PR_1_BAD_EA_BLOCK,
632 N_("@i %i has a bad @a @b %b. "),
633 PROMPT_CLEAR, 0 },
634
635 /* Error reading Extended Attribute block while fixing refcount */
636 { PR_1_EXTATTR_READ_ABORT,
637 N_("Error reading @a @b %b (%m). "),
638 PROMPT_ABORT, 0 },
639
640 /* Extended attribute reference count incorrect */
641 { PR_1_EXTATTR_REFCOUNT,
642 N_("@a @b %b has reference count %B, should be %N. "),
643 PROMPT_FIX, 0 },
644
645 /* Error writing Extended Attribute block while fixing refcount */
646 { PR_1_EXTATTR_WRITE,
647 N_("Error writing @a @b %b (%m). "),
648 PROMPT_ABORT, 0 },
649
650 /* Multiple EA blocks not supported */
651 { PR_1_EA_MULTI_BLOCK,
652 N_("@a @b %b has h_blocks > 1. "),
653 PROMPT_CLEAR, 0},
654
655 /* Error allocating EA region allocation structure */
656 { PR_1_EA_ALLOC_REGION,
657 N_("Error allocating @a @b %b. "),
658 PROMPT_ABORT, 0},
659
660 /* Error EA allocation collision */
661 { PR_1_EA_ALLOC_COLLISION,
662 N_("@a @b %b is corrupt (allocation collision). "),
663 PROMPT_CLEAR, 0},
664
665 /* Bad extended attribute name */
666 { PR_1_EA_BAD_NAME,
667 N_("@a @b %b is corrupt (invalid name). "),
668 PROMPT_CLEAR, 0},
669
670 /* Bad extended attribute value */
671 { PR_1_EA_BAD_VALUE,
672 N_("@a @b %b is corrupt (invalid value). "),
673 PROMPT_CLEAR, 0},
674
675 /* Inode too big (latch question) */
676 { PR_1_INODE_TOOBIG,
677 N_("@i %i is too big. "), PROMPT_TRUNCATE, 0 },
678
679 /* Directory too big */
680 { PR_1_TOOBIG_DIR,
681 N_("@b #%B (%b) causes @d to be too big. "),
682 PROMPT_CLEAR, PR_LATCH_TOOBIG },
683
684 /* Regular file too big */
685 { PR_1_TOOBIG_REG,
686 N_("@b #%B (%b) causes file to be too big. "),
687 PROMPT_CLEAR, PR_LATCH_TOOBIG },
688
689 /* Symlink too big */
690 { PR_1_TOOBIG_SYMLINK,
691 N_("@b #%B (%b) causes symlink to be too big. "),
692 PROMPT_CLEAR, PR_LATCH_TOOBIG },
693
694 /* INDEX_FL flag set on a non-HTREE filesystem */
695 { PR_1_HTREE_SET,
696 N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
697 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
698
699 /* INDEX_FL flag set on a non-directory */
700 { PR_1_HTREE_NODIR,
701 N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
702 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
703
704 /* Invalid root node in HTREE directory */
705 { PR_1_HTREE_BADROOT,
706 N_("@h %i has an invalid root node.\n"),
707 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
708
709 /* Unsupported hash version in HTREE directory */
710 { PR_1_HTREE_HASHV,
711 N_("@h %i has an unsupported hash version (%N)\n"),
712 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
713
714 /* Incompatible flag in HTREE root node */
715 { PR_1_HTREE_INCOMPAT,
716 N_("@h %i uses an incompatible htree root node flag.\n"),
717 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
718
719 /* HTREE too deep */
720 { PR_1_HTREE_DEPTH,
721 N_("@h %i has a tree depth (%N) which is too big\n"),
722 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
723
724 /* Bad block has indirect block that conflicts with filesystem block */
725 { PR_1_BB_FS_BLOCK,
726 N_("Bad @b @i has an indirect @b (%b) that conflicts with\n"
727 "@f metadata. "),
728 PROMPT_CLEAR, PR_LATCH_BBLOCK },
729
730 /* Resize inode failed */
731 { PR_1_RESIZE_INODE_CREATE,
732 N_("Resize @i (re)creation failed: %m."),
733 PROMPT_ABORT, 0 },
734
735 /* invalid inode->i_extra_isize */
736 { PR_1_EXTRA_ISIZE,
737 N_("@i %i has a extra size (%IS) which is invalid\n"),
738 PROMPT_FIX, PR_PREEN_OK },
739
740 /* invalid ea entry->e_name_len */
741 { PR_1_ATTR_NAME_LEN,
742 N_("@a in @i %i has a namelen (%N) which is invalid\n"),
743 PROMPT_CLEAR, PR_PREEN_OK },
744
745 /* invalid ea entry->e_value_size */
746 { PR_1_ATTR_VALUE_SIZE,
747 N_("@a in @i %i has a value size (%N) which is invalid\n"),
748 PROMPT_CLEAR, PR_PREEN_OK },
749
750 /* invalid ea entry->e_value_offs */
751 { PR_1_ATTR_VALUE_OFFSET,
752 N_("@a in @i %i has a value offset (%N) which is invalid\n"),
753 PROMPT_CLEAR, PR_PREEN_OK },
754
755 /* invalid ea entry->e_value_block */
756 { PR_1_ATTR_VALUE_BLOCK,
757 N_("@a in @i %i has a value block (%N) which is invalid (must be 0)\n"),
758 PROMPT_CLEAR, PR_PREEN_OK },
759
760 /* invalid ea entry->e_hash */
761 { PR_1_ATTR_HASH,
762 N_("@a in @i %i has a hash (%N) which is invalid (must be 0)\n"),
763 PROMPT_CLEAR, PR_PREEN_OK },
764
765 /* Pass 1b errors */
766
767 /* Pass 1B: Rescan for duplicate/bad blocks */
768 { PR_1B_PASS_HEADER,
769 N_("Duplicate @bs found... invoking duplicate @b passes.\n"
770 "Pass 1B: Rescan for duplicate/bad @bs\n"),
771 PROMPT_NONE, 0 },
772
773 /* Duplicate/bad block(s) header */
774 { PR_1B_DUP_BLOCK_HEADER,
775 N_("Duplicate/bad @b(s) in @i %i:"),
776 PROMPT_NONE, 0 },
777
778 /* Duplicate/bad block(s) in inode */
779 { PR_1B_DUP_BLOCK,
780 " %b",
781 PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
782
783 /* Duplicate/bad block(s) end */
784 { PR_1B_DUP_BLOCK_END,
785 "\n",
786 PROMPT_NONE, PR_PREEN_NOHDR },
787
788 /* Error while scanning inodes */
789 { PR_1B_ISCAN_ERROR,
790 N_("Error while scanning inodes (%i): %m\n"),
791 PROMPT_NONE, PR_FATAL },
792
793 /* Error allocating inode bitmap */
794 { PR_1B_ALLOCATE_IBITMAP_ERROR,
795 N_("@A @i @B (inode_dup_map): %m\n"),
796 PROMPT_NONE, PR_FATAL },
797
798 /* Error while iterating over blocks */
799 { PR_1B_BLOCK_ITERATE,
800 N_("Error while iterating over @bs in @i %i (%s): %m\n"),
801 PROMPT_NONE, 0 },
802
803 /* Error adjusting EA refcount */
804 { PR_1B_ADJ_EA_REFCOUNT,
805 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
806 PROMPT_NONE, 0 },
807
808
809 /* Pass 1C: Scan directories for inodes with dup blocks. */
810 { PR_1C_PASS_HEADER,
811 N_("Pass 1C: Scan directories for @is with dup @bs.\n"),
812 PROMPT_NONE, 0 },
813
814
815 /* Pass 1D: Reconciling duplicate blocks */
816 { PR_1D_PASS_HEADER,
817 N_("Pass 1D: Reconciling duplicate @bs\n"),
818 PROMPT_NONE, 0 },
819
820 /* File has duplicate blocks */
821 { PR_1D_DUP_FILE,
822 N_("File %Q (@i #%i, mod time %IM) \n"
823 " has %B duplicate @b(s), shared with %N file(s):\n"),
824 PROMPT_NONE, 0 },
825
826 /* List of files sharing duplicate blocks */
827 { PR_1D_DUP_FILE_LIST,
828 N_("\t%Q (@i #%i, mod time %IM)\n"),
829 PROMPT_NONE, 0 },
830
831 /* File sharing blocks with filesystem metadata */
832 { PR_1D_SHARE_METADATA,
833 N_("\t<@f metadata>\n"),
834 PROMPT_NONE, 0 },
835
836 /* Report of how many duplicate/bad inodes */
837 { PR_1D_NUM_DUP_INODES,
838 N_("(There are %N @is containing duplicate/bad @bs.)\n\n"),
839 PROMPT_NONE, 0 },
840
841 /* Duplicated blocks already reassigned or cloned. */
842 { PR_1D_DUP_BLOCKS_DEALT,
843 N_("Duplicated @bs already reassigned or cloned.\n\n"),
844 PROMPT_NONE, 0 },
845
846 /* Clone duplicate/bad blocks? */
847 { PR_1D_CLONE_QUESTION,
848 "", PROMPT_CLONE, PR_NO_OK },
849
850 /* Delete file? */
851 { PR_1D_DELETE_QUESTION,
852 "", PROMPT_DELETE, 0 },
853
854 /* Couldn't clone file (error) */
855 { PR_1D_CLONE_ERROR,
856 N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
857
858 /* Pass 2 errors */
859
860 /* Pass 2: Checking directory structure */
861 { PR_2_PASS_HEADER,
862 N_("Pass 2: Checking @d structure\n"),
863 PROMPT_NONE, 0 },
864
865 /* Bad inode number for '.' */
866 { PR_2_BAD_INODE_DOT,
867 N_("Bad @i number for '.' in @d @i %i.\n"),
868 PROMPT_FIX, 0 },
869
870 /* Directory entry has bad inode number */
871 { PR_2_BAD_INO,
872 N_("@E has bad @i #: %Di.\n"),
873 PROMPT_CLEAR, 0 },
874
875 /* Directory entry has deleted or unused inode */
876 { PR_2_UNUSED_INODE,
877 N_("@E has @D/unused @i %Di. "),
878 PROMPT_CLEAR, PR_PREEN_OK },
879
880 /* Directry entry is link to '.' */
881 { PR_2_LINK_DOT,
882 N_("@E @L to '.' "),
883 PROMPT_CLEAR, 0 },
884
885 /* Directory entry points to inode now located in a bad block */
886 { PR_2_BB_INODE,
887 N_("@E points to @i (%Di) located in a bad @b.\n"),
888 PROMPT_CLEAR, 0 },
889
890 /* Directory entry contains a link to a directory */
891 { PR_2_LINK_DIR,
892 N_("@E @L to @d %P (%Di).\n"),
893 PROMPT_CLEAR, 0 },
894
895 /* Directory entry contains a link to the root directry */
896 { PR_2_LINK_ROOT,
897 N_("@E @L to the @r.\n"),
898 PROMPT_CLEAR, 0 },
899
900 /* Directory entry has illegal characters in its name */
901 { PR_2_BAD_NAME,
902 N_("@E has illegal characters in its name.\n"),
903 PROMPT_FIX, 0 },
904
905 /* Missing '.' in directory inode */
906 { PR_2_MISSING_DOT,
907 N_("Missing '.' in @d @i %i.\n"),
908 PROMPT_FIX, 0 },
909
910 /* Missing '..' in directory inode */
911 { PR_2_MISSING_DOT_DOT,
912 N_("Missing '..' in @d @i %i.\n"),
913 PROMPT_FIX, 0 },
914
915 /* First entry in directory inode doesn't contain '.' */
916 { PR_2_1ST_NOT_DOT,
917 N_("First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n"),
918 PROMPT_FIX, 0 },
919
920 /* Second entry in directory inode doesn't contain '..' */
921 { PR_2_2ND_NOT_DOT_DOT,
922 N_("Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n"),
923 PROMPT_FIX, 0 },
924
925 /* i_faddr should be zero */
926 { PR_2_FADDR_ZERO,
927 N_("i_faddr @F %IF, @s zero.\n"),
928 PROMPT_CLEAR, 0 },
929
930 /* i_file_acl should be zero */
931 { PR_2_FILE_ACL_ZERO,
932 N_("i_file_acl @F %If, @s zero.\n"),
933 PROMPT_CLEAR, 0 },
934
935 /* i_dir_acl should be zero */
936 { PR_2_DIR_ACL_ZERO,
937 N_("i_dir_acl @F %Id, @s zero.\n"),
938 PROMPT_CLEAR, 0 },
939
940 /* i_frag should be zero */
941 { PR_2_FRAG_ZERO,
942 N_("i_frag @F %N, @s zero.\n"),
943 PROMPT_CLEAR, 0 },
944
945 /* i_fsize should be zero */
946 { PR_2_FSIZE_ZERO,
947 N_("i_fsize @F %N, @s zero.\n"),
948 PROMPT_CLEAR, 0 },
949
950 /* inode has bad mode */
951 { PR_2_BAD_MODE,
952 N_("@i %i (%Q) has a bad mode (%Im).\n"),
953 PROMPT_CLEAR, 0 },
954
955 /* directory corrupted */
956 { PR_2_DIR_CORRUPTED,
957 N_("@d @i %i, @b %B, offset %N: @d corrupted\n"),
958 PROMPT_SALVAGE, 0 },
959
960 /* filename too long */
961 { PR_2_FILENAME_LONG,
962 N_("@d @i %i, @b %B, offset %N: filename too long\n"),
963 PROMPT_TRUNCATE, 0 },
964
965 /* Directory inode has a missing block (hole) */
966 { PR_2_DIRECTORY_HOLE,
967 N_("@d @i %i has an unallocated @b #%B. "),
968 PROMPT_ALLOCATE, 0 },
969
970 /* '.' is not NULL terminated */
971 { PR_2_DOT_NULL_TERM,
972 N_("'.' @d @e in @d @i %i is not NULL terminated\n"),
973 PROMPT_FIX, 0 },
974
975 /* '..' is not NULL terminated */
976 { PR_2_DOT_DOT_NULL_TERM,
977 N_("'..' @d @e in @d @i %i is not NULL terminated\n"),
978 PROMPT_FIX, 0 },
979
980 /* Illegal character device inode */
981 { PR_2_BAD_CHAR_DEV,
982 N_("@i %i (%Q) is an @I character @v.\n"),
983 PROMPT_CLEAR, 0 },
984
985 /* Illegal block device inode */
986 { PR_2_BAD_BLOCK_DEV,
987 N_("@i %i (%Q) is an @I @b @v.\n"),
988 PROMPT_CLEAR, 0 },
989
990 /* Duplicate '.' entry */
991 { PR_2_DUP_DOT,
992 N_("@E is duplicate '.' @e.\n"),
993 PROMPT_FIX, 0 },
994
995 /* Duplicate '..' entry */
996 { PR_2_DUP_DOT_DOT,
997 N_("@E is duplicate '..' @e.\n"),
998 PROMPT_FIX, 0 },
999
1000 /* Internal error: couldn't find dir_info */
1001 { PR_2_NO_DIRINFO,
1002 N_("Internal error: couldn't find dir_info for %i.\n"),
1003 PROMPT_NONE, PR_FATAL },
1004
1005 /* Final rec_len is wrong */
1006 { PR_2_FINAL_RECLEN,
1007 N_("@E has rec_len of %Dr, should be %N.\n"),
1008 PROMPT_FIX, 0 },
1009
1010 /* Error allocating icount structure */
1011 { PR_2_ALLOCATE_ICOUNT,
1012 N_("@A icount structure: %m\n"),
1013 PROMPT_NONE, PR_FATAL },
1014
1015 /* Error iterating over directory blocks */
1016 { PR_2_DBLIST_ITERATE,
1017 N_("Error iterating over @d @bs: %m\n"),
1018 PROMPT_NONE, PR_FATAL },
1019
1020 /* Error reading directory block */
1021 { PR_2_READ_DIRBLOCK,
1022 N_("Error reading @d @b %b (@i %i): %m\n"),
1023 PROMPT_CONTINUE, 0 },
1024
1025 /* Error writing directory block */
1026 { PR_2_WRITE_DIRBLOCK,
1027 N_("Error writing @d @b %b (@i %i): %m\n"),
1028 PROMPT_CONTINUE, 0 },
1029
1030 /* Error allocating new directory block */
1031 { PR_2_ALLOC_DIRBOCK,
1032 N_("@A new @d @b for @i %i (%s): %m\n"),
1033 PROMPT_NONE, 0 },
1034
1035 /* Error deallocating inode */
1036 { PR_2_DEALLOC_INODE,
1037 N_("Error deallocating @i %i: %m\n"),
1038 PROMPT_NONE, PR_FATAL },
1039
1040 /* Directory entry for '.' is big. Split? */
1041 { PR_2_SPLIT_DOT,
1042 N_("@d @e for '.' is big. "),
1043 PROMPT_SPLIT, PR_NO_OK },
1044
1045 /* Illegal FIFO inode */
1046 { PR_2_BAD_FIFO,
1047 N_("@i %i (%Q) is an @I FIFO.\n"),
1048 PROMPT_CLEAR, 0 },
1049
1050 /* Illegal socket inode */
1051 { PR_2_BAD_SOCKET,
1052 N_("@i %i (%Q) is an @I socket.\n"),
1053 PROMPT_CLEAR, 0 },
1054
1055 /* Directory filetype not set */
1056 { PR_2_SET_FILETYPE,
1057 N_("Setting filetype for @E to %N.\n"),
1058 PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
1059
1060 /* Directory filetype incorrect */
1061 { PR_2_BAD_FILETYPE,
1062 N_("@E has an incorrect filetype (was %Dt, should be %N).\n"),
1063 PROMPT_FIX, 0 },
1064
1065 /* Directory filetype set on filesystem */
1066 { PR_2_CLEAR_FILETYPE,
1067 N_("@E has filetype set.\n"),
1068 PROMPT_CLEAR, PR_PREEN_OK },
1069
1070 /* Directory filename is null */
1071 { PR_2_NULL_NAME,
1072 N_("@E has a zero-length name.\n"),
1073 PROMPT_CLEAR, 0 },
1074
1075 /* Invalid symlink */
1076 { PR_2_INVALID_SYMLINK,
1077 N_("Symlink %Q (@i #%i) is invalid.\n"),
1078 PROMPT_CLEAR, 0 },
1079
1080 /* i_file_acl (extended attribute block) is bad */
1081 { PR_2_FILE_ACL_BAD,
1082 N_("@a @b @F invalid (%If).\n"),
1083 PROMPT_CLEAR, 0 },
1084
1085 /* Filesystem contains large files, but has no such flag in sb */
1086 { PR_2_FEATURE_LARGE_FILES,
1087 N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
1088 PROMPT_FIX, 0 },
1089
1090 /* Node in HTREE directory not referenced */
1091 { PR_2_HTREE_NOTREF,
1092 N_("@p @h %d: node (%B) not referenced\n"),
1093 PROMPT_NONE, 0 },
1094
1095 /* Node in HTREE directory referenced twice */
1096 { PR_2_HTREE_DUPREF,
1097 N_("@p @h %d: node (%B) referenced twice\n"),
1098 PROMPT_NONE, 0 },
1099
1100 /* Node in HTREE directory has bad min hash */
1101 { PR_2_HTREE_MIN_HASH,
1102 N_("@p @h %d: node (%B) has bad min hash\n"),
1103 PROMPT_NONE, 0 },
1104
1105 /* Node in HTREE directory has bad max hash */
1106 { PR_2_HTREE_MAX_HASH,
1107 N_("@p @h %d: node (%B) has bad max hash\n"),
1108 PROMPT_NONE, 0 },
1109
1110 /* Clear invalid HTREE directory */
1111 { PR_2_HTREE_CLEAR,
1112 N_("Invalid @h %d (%q). "), PROMPT_CLEAR, 0 },
1113
1114 /* Bad block in htree interior node */
1115 { PR_2_HTREE_BADBLK,
1116 N_("@p @h %d (%q): bad @b number %b.\n"),
1117 PROMPT_CLEAR_HTREE, 0 },
1118
1119 /* Error adjusting EA refcount */
1120 { PR_2_ADJ_EA_REFCOUNT,
1121 N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
1122 PROMPT_NONE, PR_FATAL },
1123
1124 /* Invalid HTREE root node */
1125 { PR_2_HTREE_BAD_ROOT,
1126 N_("@p @h %d: root node is invalid\n"),
1127 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
1128
1129 /* Invalid HTREE limit */
1130 { PR_2_HTREE_BAD_LIMIT,
1131 N_("@p @h %d: node (%B) has bad limit (%N)\n"),
1132 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
1133
1134 /* Invalid HTREE count */
1135 { PR_2_HTREE_BAD_COUNT,
1136 N_("@p @h %d: node (%B) has bad count (%N)\n"),
1137 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
1138
1139 /* HTREE interior node has out-of-order hashes in table */
1140 { PR_2_HTREE_HASH_ORDER,
1141 N_("@p @h %d: node (%B) has an unordered hash table\n"),
1142 PROMPT_CLEAR_HTREE, PR_PREEN_OK },
1143
1144 /* Node in HTREE directory has bad depth */
1145 { PR_2_HTREE_BAD_DEPTH,
1146 N_("@p @h %d: node (%B) has bad depth\n"),
1147 PROMPT_NONE, 0 },
1148
1149 /* Duplicate directory entry found */
1150 { PR_2_DUPLICATE_DIRENT,
1151 N_("Duplicate @E found. "),
1152 PROMPT_CLEAR, 0 },
1153
1154 /* Non-unique filename found */
1155 { PR_2_NON_UNIQUE_FILE, /* xgettext: no-c-format */
1156 N_("@E has a non-unique filename.\nRename to %s"),
1157 PROMPT_NULL, 0 },
1158
1159 /* Duplicate directory entry found */
1160 { PR_2_REPORT_DUP_DIRENT,
1161 N_("Duplicate @e '%Dn' found.\n\tMarking %p (%i) to be rebuilt.\n\n"),
1162 PROMPT_NONE, 0 },
1163
1164 /* Pass 3 errors */
1165
1166 /* Pass 3: Checking directory connectivity */
1167 { PR_3_PASS_HEADER,
1168 N_("Pass 3: Checking @d connectivity\n"),
1169 PROMPT_NONE, 0 },
1170
1171 /* Root inode not allocated */
1172 { PR_3_NO_ROOT_INODE,
1173 N_("@r not allocated. "),
1174 PROMPT_ALLOCATE, 0 },
1175
1176 /* No room in lost+found */
1177 { PR_3_EXPAND_LF_DIR,
1178 N_("No room in @l @d. "),
1179 PROMPT_EXPAND, 0 },
1180
1181 /* Unconnected directory inode */
1182 { PR_3_UNCONNECTED_DIR,
1183 N_("Unconnected @d @i %i (%p)\n"),
1184 PROMPT_CONNECT, 0 },
1185
1186 /* /lost+found not found */
1187 { PR_3_NO_LF_DIR,
1188 N_("/@l not found. "),
1189 PROMPT_CREATE, PR_PREEN_OK },
1190
1191 /* .. entry is incorrect */
1192 { PR_3_BAD_DOT_DOT,
1193 N_("'..' in %Q (%i) is %P (%j), @s %q (%d).\n"),
1194 PROMPT_FIX, 0 },
1195
1196 /* Bad or non-existent /lost+found. Cannot reconnect */
1197 { PR_3_NO_LPF,
1198 N_("Bad or non-existent /@l. Cannot reconnect.\n"),
1199 PROMPT_NONE, 0 },
1200
1201 /* Could not expand /lost+found */
1202 { PR_3_CANT_EXPAND_LPF,
1203 N_("Could not expand /@l: %m\n"),
1204 PROMPT_NONE, 0 },
1205
1206 /* Could not reconnect inode */
1207 { PR_3_CANT_RECONNECT,
1208 N_("Could not reconnect %i: %m\n"),
1209 PROMPT_NONE, 0 },
1210
1211 /* Error while trying to find /lost+found */
1212 { PR_3_ERR_FIND_LPF,
1213 N_("Error while trying to find /@l: %m\n"),
1214 PROMPT_NONE, 0 },
1215
1216 /* Error in ext2fs_new_block while creating /lost+found */
1217 { PR_3_ERR_LPF_NEW_BLOCK,
1218 N_("ext2fs_new_@b: %m while trying to create /@l @d\n"),
1219 PROMPT_NONE, 0 },
1220
1221 /* Error in ext2fs_new_inode while creating /lost+found */
1222 { PR_3_ERR_LPF_NEW_INODE,
1223 N_("ext2fs_new_@i: %m while trying to create /@l @d\n"),
1224 PROMPT_NONE, 0 },
1225
1226 /* Error in ext2fs_new_dir_block while creating /lost+found */
1227 { PR_3_ERR_LPF_NEW_DIR_BLOCK,
1228 N_("ext2fs_new_dir_@b: %m while creating new @d @b\n"),
1229 PROMPT_NONE, 0 },
1230
1231 /* Error while writing directory block for /lost+found */
1232 { PR_3_ERR_LPF_WRITE_BLOCK,
1233 N_("ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n"),
1234 PROMPT_NONE, 0 },
1235
1236 /* Error while adjusting inode count */
1237 { PR_3_ADJUST_INODE,
1238 N_("Error while adjusting @i count on @i %i\n"),
1239 PROMPT_NONE, 0 },
1240
1241 /* Couldn't fix parent directory -- error */
1242 { PR_3_FIX_PARENT_ERR,
1243 N_("Couldn't fix parent of @i %i: %m\n\n"),
1244 PROMPT_NONE, 0 },
1245
1246 /* Couldn't fix parent directory -- couldn't find it */
1247 { PR_3_FIX_PARENT_NOFIND,
1248 N_("Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n"),
1249 PROMPT_NONE, 0 },
1250
1251 /* Error allocating inode bitmap */
1252 { PR_3_ALLOCATE_IBITMAP_ERROR,
1253 N_("@A @i @B (%N): %m\n"),
1254 PROMPT_NONE, PR_FATAL },
1255
1256 /* Error creating root directory */
1257 { PR_3_CREATE_ROOT_ERROR,
1258 N_("Error creating root @d (%s): %m\n"),
1259 PROMPT_NONE, PR_FATAL },
1260
1261 /* Error creating lost and found directory */
1262 { PR_3_CREATE_LPF_ERROR,
1263 N_("Error creating /@l @d (%s): %m\n"),
1264 PROMPT_NONE, PR_FATAL },
1265
1266 /* Root inode is not directory; aborting */
1267 { PR_3_ROOT_NOT_DIR_ABORT,
1268 N_("@r is not a @d; aborting.\n"),
1269 PROMPT_NONE, PR_FATAL },
1270
1271 /* Cannot proceed without a root inode. */
1272 { PR_3_NO_ROOT_INODE_ABORT,
1273 N_("Cannot proceed without a @r.\n"),
1274 PROMPT_NONE, PR_FATAL },
1275
1276 /* Internal error: couldn't find dir_info */
1277 { PR_3_NO_DIRINFO,
1278 N_("Internal error: couldn't find dir_info for %i.\n"),
1279 PROMPT_NONE, PR_FATAL },
1280
1281 /* Lost+found not a directory */
1282 { PR_3_LPF_NOTDIR,
1283 N_("/@l is not a @d (ino=%i)\n"),
1284 PROMPT_UNLINK, 0 },
1285
1286 /* Pass 3A Directory Optimization */
1287
1288 /* Pass 3A: Optimizing directories */
1289 { PR_3A_PASS_HEADER,
1290 N_("Pass 3A: Optimizing directories\n"),
1291 PROMPT_NONE, PR_PREEN_NOMSG },
1292
1293 /* Error iterating over directories */
1294 { PR_3A_OPTIMIZE_ITER,
1295 N_("Failed to create dirs_to_hash iterator: %m"),
1296 PROMPT_NONE, 0 },
1297
1298 /* Error rehash directory */
1299 { PR_3A_OPTIMIZE_DIR_ERR,
1300 N_("Failed to optimize directory %q (%d): %m"),
1301 PROMPT_NONE, 0 },
1302
1303 /* Rehashing dir header */
1304 { PR_3A_OPTIMIZE_DIR_HEADER,
1305 N_("Optimizing directories: "),
1306 PROMPT_NONE, PR_MSG_ONLY },
1307
1308 /* Rehashing directory %d */
1309 { PR_3A_OPTIMIZE_DIR,
1310 " %d",
1311 PROMPT_NONE, PR_LATCH_OPTIMIZE_DIR | PR_PREEN_NOHDR},
1312
1313 /* Rehashing dir end */
1314 { PR_3A_OPTIMIZE_DIR_END,
1315 "\n",
1316 PROMPT_NONE, PR_PREEN_NOHDR },
1317
1318 /* Pass 4 errors */
1319
1320 /* Pass 4: Checking reference counts */
1321 { PR_4_PASS_HEADER,
1322 N_("Pass 4: Checking reference counts\n"),
1323 PROMPT_NONE, 0 },
1324
1325 /* Unattached zero-length inode */
1326 { PR_4_ZERO_LEN_INODE,
1327 "@u @z @i %i. ",
1328 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
1329
1330 /* Unattached inode */
1331 { PR_4_UNATTACHED_INODE,
1332 "@u @i %i\n",
1333 PROMPT_CONNECT, 0 },
1334
1335 /* Inode ref count wrong */
1336 { PR_4_BAD_REF_COUNT,
1337 N_("@i %i ref count is %Il, @s %N. "),
1338 PROMPT_FIX, PR_PREEN_OK },
1339
1340 { PR_4_INCONSISTENT_COUNT,
1341 N_("WARNING: PROGRAMMING BUG IN E2FSCK!\n"
1342 "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
1343 "@i_link_info[%i] is %N, @i.i_links_count is %Il. "
1344 "They should be the same!\n"),
1345 PROMPT_NONE, 0 },
1346
1347 /* Pass 5 errors */
1348
1349 /* Pass 5: Checking group summary information */
1350 { PR_5_PASS_HEADER,
1351 N_("Pass 5: Checking @g summary information\n"),
1352 PROMPT_NONE, 0 },
1353
1354 /* Padding at end of inode bitmap is not set. */
1355 { PR_5_INODE_BMAP_PADDING,
1356 N_("Padding at end of @i @B is not set. "),
1357 PROMPT_FIX, PR_PREEN_OK },
1358
1359 /* Padding at end of block bitmap is not set. */
1360 { PR_5_BLOCK_BMAP_PADDING,
1361 N_("Padding at end of @b @B is not set. "),
1362 PROMPT_FIX, PR_PREEN_OK },
1363
1364 /* Block bitmap differences header */
1365 { PR_5_BLOCK_BITMAP_HEADER,
1366 N_("@b @B differences: "),
1367 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
1368
1369 /* Block not used, but marked in bitmap */
1370 { PR_5_BLOCK_UNUSED,
1371 " -%b",
1372 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1373
1374 /* Block used, but not marked used in bitmap */
1375 { PR_5_BLOCK_USED,
1376 " +%b",
1377 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1378
1379 /* Block bitmap differences end */
1380 { PR_5_BLOCK_BITMAP_END,
1381 "\n",
1382 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1383
1384 /* Inode bitmap differences header */
1385 { PR_5_INODE_BITMAP_HEADER,
1386 N_("@i @B differences: "),
1387 PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
1388
1389 /* Inode not used, but marked in bitmap */
1390 { PR_5_INODE_UNUSED,
1391 " -%i",
1392 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1393
1394 /* Inode used, but not marked used in bitmap */
1395 { PR_5_INODE_USED,
1396 " +%i",
1397 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1398
1399 /* Inode bitmap differences end */
1400 { PR_5_INODE_BITMAP_END,
1401 "\n",
1402 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1403
1404 /* Free inodes count for group wrong */
1405 { PR_5_FREE_INODE_COUNT_GROUP,
1406 N_("Free @is count wrong for @g #%g (%i, counted=%j).\n"),
1407 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1408
1409 /* Directories count for group wrong */
1410 { PR_5_FREE_DIR_COUNT_GROUP,
1411 N_("Directories count wrong for @g #%g (%i, counted=%j).\n"),
1412 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1413
1414 /* Free inodes count wrong */
1415 { PR_5_FREE_INODE_COUNT,
1416 N_("Free @is count wrong (%i, counted=%j).\n"),
1417 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1418
1419 /* Free blocks count for group wrong */
1420 { PR_5_FREE_BLOCK_COUNT_GROUP,
1421 N_("Free @bs count wrong for @g #%g (%b, counted=%c).\n"),
1422 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1423
1424 /* Free blocks count wrong */
1425 { PR_5_FREE_BLOCK_COUNT,
1426 N_("Free @bs count wrong (%b, counted=%c).\n"),
1427 PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
1428
1429 /* Programming error: bitmap endpoints don't match */
1430 { PR_5_BMAP_ENDPOINTS,
1431 N_("PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
1432 "match calculated @B endpoints (%i, %j)\n"),
1433 PROMPT_NONE, PR_FATAL },
1434
1435 /* Internal error: fudging end of bitmap */
1436 { PR_5_FUDGE_BITMAP_ERROR,
1437 N_("Internal error: fudging end of bitmap (%N)\n"),
1438 PROMPT_NONE, PR_FATAL },
1439
1440 /* Error copying in replacement inode bitmap */
1441 { PR_5_COPY_IBITMAP_ERROR,
1442 "Error copying in replacement @i @B: %m\n",
1443 PROMPT_NONE, PR_FATAL },
1444
1445 /* Error copying in replacement block bitmap */
1446 { PR_5_COPY_BBITMAP_ERROR,
1447 "Error copying in replacement @b @B: %m\n",
1448 PROMPT_NONE, PR_FATAL },
1449
1450 /* Block range not used, but marked in bitmap */
1451 { PR_5_BLOCK_RANGE_UNUSED,
1452 " -(%b--%c)",
1453 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1454
1455 /* Block range used, but not marked used in bitmap */
1456 { PR_5_BLOCK_RANGE_USED,
1457 " +(%b--%c)",
1458 PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1459
1460 /* Inode range not used, but marked in bitmap */
1461 { PR_5_INODE_RANGE_UNUSED,
1462 " -(%i--%j)",
1463 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1464
1465 /* Inode range used, but not marked used in bitmap */
1466 { PR_5_INODE_RANGE_USED,
1467 " +(%i--%j)",
1468 PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
1469
1470 { 0 }
1471};
1472
1473/*
1474 * This is the latch flags register. It allows several problems to be
1475 * "latched" together. This means that the user has to answer but one
1476 * question for the set of problems, and all of the associated
1477 * problems will be either fixed or not fixed.
1478 */
1479static struct latch_descr pr_latch_info[] = {
1480 { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
1481 { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
1482 { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
1483 { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
1484 { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
1485 { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
1486 { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
1487 { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
1488 { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
1489 { -1, 0, 0 },
1490};
1491
1492static const struct e2fsck_problem *find_problem(problem_t code)
1493{
1494 int i;
1495
1496 for (i=0; problem_table[i].e2p_code; i++) {
1497 if (problem_table[i].e2p_code == code)
1498 return &problem_table[i];
1499 }
1500 return 0;
1501}
1502
1503static struct latch_descr *find_latch(int code)
1504{
1505 int i;
1506
1507 for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
1508 if (pr_latch_info[i].latch_code == code)
1509 return &pr_latch_info[i];
1510 }
1511 return 0;
1512}
1513
1514int end_problem_latch(e2fsck_t ctx, int mask)
1515{
1516 struct latch_descr *ldesc;
1517 struct problem_context pctx;
1518 int answer = -1;
1519
1520 ldesc = find_latch(mask);
1521 if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
1522 clear_problem_context(&pctx);
1523 answer = fix_problem(ctx, ldesc->end_message, &pctx);
1524 }
1525 ldesc->flags &= ~(PRL_VARIABLE);
1526 return answer;
1527}
1528
1529int set_latch_flags(int mask, int setflags, int clearflags)
1530{
1531 struct latch_descr *ldesc;
1532
1533 ldesc = find_latch(mask);
1534 if (!ldesc)
1535 return -1;
1536 ldesc->flags |= setflags;
1537 ldesc->flags &= ~clearflags;
1538 return 0;
1539}
1540
1541int get_latch_flags(int mask, int *value)
1542{
1543 struct latch_descr *ldesc;
1544
1545 ldesc = find_latch(mask);
1546 if (!ldesc)
1547 return -1;
1548 *value = ldesc->flags;
1549 return 0;
1550}
1551
1552void clear_problem_context(struct problem_context *ctx)
1553{
1554 memset(ctx, 0, sizeof(struct problem_context));
1555 ctx->blkcount = -1;
1556 ctx->group = -1;
1557}
1558
1559int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
1560{
1561 ext2_filsys fs = ctx->fs;
1562 const struct e2fsck_problem *ptr;
1563 struct latch_descr *ldesc = 0;
1564 const char *message;
1565 int def_yn, answer, ans;
1566 int print_answer = 0;
1567 int suppress = 0;
1568
1569 ptr = find_problem(code);
1570 if (!ptr) {
1571 printf(_("Unhandled error code (0x%x)!\n"), code);
1572 return 0;
1573 }
1574 def_yn = 1;
1575 if ((ptr->flags & PR_NO_DEFAULT) ||
1576 ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
1577 (ctx->options & E2F_OPT_NO))
1578 def_yn= 0;
1579
1580 /*
1581 * Do special latch processing. This is where we ask the
1582 * latch question, if it exists
1583 */
1584 if (ptr->flags & PR_LATCH_MASK) {
1585 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
1586 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
1587 ans = fix_problem(ctx, ldesc->question, pctx);
1588 if (ans == 1)
1589 ldesc->flags |= PRL_YES;
1590 if (ans == 0)
1591 ldesc->flags |= PRL_NO;
1592 ldesc->flags |= PRL_LATCHED;
1593 }
1594 if (ldesc->flags & PRL_SUPPRESS)
1595 suppress++;
1596 }
1597 if ((ptr->flags & PR_PREEN_NOMSG) &&
1598 (ctx->options & E2F_OPT_PREEN))
1599 suppress++;
1600 if ((ptr->flags & PR_NO_NOMSG) &&
1601 (ctx->options & E2F_OPT_NO))
1602 suppress++;
1603 if (!suppress) {
1604 message = ptr->e2p_description;
1605 if ((ctx->options & E2F_OPT_PREEN) &&
1606 !(ptr->flags & PR_PREEN_NOHDR)) {
1607 printf("%s: ", ctx->device_name ?
1608 ctx->device_name : ctx->filesystem_name);
1609 }
1610 if (*message)
1611 print_e2fsck_message(ctx, _(message), pctx, 1);
1612 }
1613 if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
1614 preenhalt(ctx);
1615
1616 if (ptr->flags & PR_FATAL)
1617 fatal_error(ctx, 0);
1618
1619 if (ptr->prompt == PROMPT_NONE) {
1620 if (ptr->flags & PR_NOCOLLATE)
1621 answer = -1;
1622 else
1623 answer = def_yn;
1624 } else {
1625 if (ctx->options & E2F_OPT_PREEN) {
1626 answer = def_yn;
1627 if (!(ptr->flags & PR_PREEN_NOMSG))
1628 print_answer = 1;
1629 } else if ((ptr->flags & PR_LATCH_MASK) &&
1630 (ldesc->flags & (PRL_YES | PRL_NO))) {
1631 if (!suppress)
1632 print_answer = 1;
1633 if (ldesc->flags & PRL_YES)
1634 answer = 1;
1635 else
1636 answer = 0;
1637 } else
1638 answer = ask(ctx, _(prompt[(int) ptr->prompt]), def_yn);
1639 if (!answer && !(ptr->flags & PR_NO_OK))
1640 ext2fs_unmark_valid(fs);
1641
1642 if (print_answer)
1643 printf("%s.\n", answer ?
1644 _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
1645
1646 }
1647
1648 if ((ptr->prompt == PROMPT_ABORT) && answer)
1649 fatal_error(ctx, 0);
1650
1651 if (ptr->flags & PR_AFTER_CODE)
1652 answer = fix_problem(ctx, ptr->second_code, pctx);
1653
1654 return answer;
1655}
diff --git a/e2fsprogs/e2fsck/problem.h b/e2fsprogs/e2fsck/problem.h
deleted file mode 100644
index 0e39a2935..000000000
--- a/e2fsprogs/e2fsck/problem.h
+++ /dev/null
@@ -1,897 +0,0 @@
1/*
2 * problem.h --- e2fsck problem error codes
3 *
4 * Copyright 1996 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12typedef __u32 problem_t;
13
14struct problem_context {
15 errcode_t errcode;
16 ext2_ino_t ino, ino2, dir;
17 struct ext2_inode *inode;
18 struct ext2_dir_entry *dirent;
19 blk_t blk, blk2;
20 e2_blkcnt_t blkcount;
21 int group;
22 __u64 num;
23 const char *str;
24};
25
26/*
27 * We define a set of "latch groups"; these are problems which are
28 * handled as a set. The user answers once for a particular latch
29 * group.
30 */
31#define PR_LATCH_MASK 0x0ff0 /* Latch mask */
32#define PR_LATCH_BLOCK 0x0010 /* Latch for illegal blocks (pass 1) */
33#define PR_LATCH_BBLOCK 0x0020 /* Latch for bad block inode blocks (pass 1) */
34#define PR_LATCH_IBITMAP 0x0030 /* Latch for pass 5 inode bitmap proc. */
35#define PR_LATCH_BBITMAP 0x0040 /* Latch for pass 5 inode bitmap proc. */
36#define PR_LATCH_RELOC 0x0050 /* Latch for superblock relocate hint */
37#define PR_LATCH_DBLOCK 0x0060 /* Latch for pass 1b dup block headers */
38#define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
39#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
40#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
41
42#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
43
44/*
45 * Latch group descriptor flags
46 */
47#define PRL_YES 0x0001 /* Answer yes */
48#define PRL_NO 0x0002 /* Answer no */
49#define PRL_LATCHED 0x0004 /* The latch group is latched */
50#define PRL_SUPPRESS 0x0008 /* Suppress all latch group questions */
51
52#define PRL_VARIABLE 0x000f /* All the flags that need to be reset */
53
54/*
55 * Pre-Pass 1 errors
56 */
57
58/* Block bitmap not in group */
59#define PR_0_BB_NOT_GROUP 0x000001
60
61/* Inode bitmap not in group */
62#define PR_0_IB_NOT_GROUP 0x000002
63
64/* Inode table not in group */
65#define PR_0_ITABLE_NOT_GROUP 0x000003
66
67/* Superblock corrupt */
68#define PR_0_SB_CORRUPT 0x000004
69
70/* Filesystem size is wrong */
71#define PR_0_FS_SIZE_WRONG 0x000005
72
73/* Fragments not supported */
74#define PR_0_NO_FRAGMENTS 0x000006
75
76/* Bad blocks_per_group */
77#define PR_0_BLOCKS_PER_GROUP 0x000007
78
79/* Bad first_data_block */
80#define PR_0_FIRST_DATA_BLOCK 0x000008
81
82/* Adding UUID to filesystem */
83#define PR_0_ADD_UUID 0x000009
84
85/* Relocate hint */
86#define PR_0_RELOCATE_HINT 0x00000A
87
88/* Miscellaneous superblock corruption */
89#define PR_0_MISC_CORRUPT_SUPER 0x00000B
90
91/* Error determing physical device size of filesystem */
92#define PR_0_GETSIZE_ERROR 0x00000C
93
94/* Inode count in the superblock incorrect */
95#define PR_0_INODE_COUNT_WRONG 0x00000D
96
97/* The Hurd does not support the filetype feature */
98#define PR_0_HURD_CLEAR_FILETYPE 0x00000E
99
100/* Journal inode is invalid */
101#define PR_0_JOURNAL_BAD_INODE 0x00000F
102
103/* The external journal has multiple filesystems (which we can't handle yet) */
104#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010
105
106/* Can't find external journal */
107#define PR_0_CANT_FIND_JOURNAL 0x000011
108
109/* External journal has bad superblock */
110#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012
111
112/* Superblock has a bad journal UUID */
113#define PR_0_JOURNAL_BAD_UUID 0x000013
114
115/* Journal has an unknown superblock type */
116#define PR_0_JOURNAL_UNSUPP_SUPER 0x000014
117
118/* Journal superblock is corrupt */
119#define PR_0_JOURNAL_BAD_SUPER 0x000015
120
121/* Journal superblock is corrupt */
122#define PR_0_JOURNAL_HAS_JOURNAL 0x000016
123
124/* Superblock has recovery flag set but no journal */
125#define PR_0_JOURNAL_RECOVER_SET 0x000017
126
127/* Journal has data, but recovery flag is clear */
128#define PR_0_JOURNAL_RECOVERY_CLEAR 0x000018
129
130/* Ask if we should clear the journal */
131#define PR_0_JOURNAL_RESET_JOURNAL 0x000019
132
133/* Filesystem revision is 0, but feature flags are set */
134#define PR_0_FS_REV_LEVEL 0x00001A
135
136/* Clearing orphan inode */
137#define PR_0_ORPHAN_CLEAR_INODE 0x000020
138
139/* Illegal block found in orphaned inode */
140#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021
141
142/* Already cleared block found in orphaned inode */
143#define PR_0_ORPHAN_ALREADY_CLEARED_BLOCK 0x000022
144
145/* Illegal orphan inode in superblock */
146#define PR_0_ORPHAN_ILLEGAL_HEAD_INODE 0x000023
147
148/* Illegal inode in orphaned inode list */
149#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024
150
151/* Journal has unsupported read-only feature - abort */
152#define PR_0_JOURNAL_UNSUPP_ROCOMPAT 0x000025
153
154/* Journal has unsupported incompatible feature - abort */
155#define PR_0_JOURNAL_UNSUPP_INCOMPAT 0x000026
156
157/* Journal has unsupported version number */
158#define PR_0_JOURNAL_UNSUPP_VERSION 0x000027
159
160/* Moving journal to hidden file */
161#define PR_0_MOVE_JOURNAL 0x000028
162
163/* Error moving journal */
164#define PR_0_ERR_MOVE_JOURNAL 0x000029
165
166/* Clearing V2 journal superblock */
167#define PR_0_CLEAR_V2_JOURNAL 0x00002A
168
169/* Run journal anyway */
170#define PR_0_JOURNAL_RUN 0x00002B
171
172/* Run journal anyway by default */
173#define PR_0_JOURNAL_RUN_DEFAULT 0x00002C
174
175/* Backup journal inode blocks */
176#define PR_0_BACKUP_JNL 0x00002D
177
178/* Reserved blocks w/o resize_inode */
179#define PR_0_NONZERO_RESERVED_GDT_BLOCKS 0x00002E
180
181/* Resize_inode not enabled, but resize inode is non-zero */
182#define PR_0_CLEAR_RESIZE_INODE 0x00002F
183
184/* Resize inode invalid */
185#define PR_0_RESIZE_INODE_INVALID 0x000030
186
187/*
188 * Pass 1 errors
189 */
190
191/* Pass 1: Checking inodes, blocks, and sizes */
192#define PR_1_PASS_HEADER 0x010000
193
194/* Root directory is not an inode */
195#define PR_1_ROOT_NO_DIR 0x010001
196
197/* Root directory has dtime set */
198#define PR_1_ROOT_DTIME 0x010002
199
200/* Reserved inode has bad mode */
201#define PR_1_RESERVED_BAD_MODE 0x010003
202
203/* Deleted inode has zero dtime */
204#define PR_1_ZERO_DTIME 0x010004
205
206/* Inode in use, but dtime set */
207#define PR_1_SET_DTIME 0x010005
208
209/* Zero-length directory */
210#define PR_1_ZERO_LENGTH_DIR 0x010006
211
212/* Block bitmap conflicts with some other fs block */
213#define PR_1_BB_CONFLICT 0x010007
214
215/* Inode bitmap conflicts with some other fs block */
216#define PR_1_IB_CONFLICT 0x010008
217
218/* Inode table conflicts with some other fs block */
219#define PR_1_ITABLE_CONFLICT 0x010009
220
221/* Block bitmap is on a bad block */
222#define PR_1_BB_BAD_BLOCK 0x01000A
223
224/* Inode bitmap is on a bad block */
225#define PR_1_IB_BAD_BLOCK 0x01000B
226
227/* Inode has incorrect i_size */
228#define PR_1_BAD_I_SIZE 0x01000C
229
230/* Inode has incorrect i_blocks */
231#define PR_1_BAD_I_BLOCKS 0x01000D
232
233/* Illegal block number in inode */
234#define PR_1_ILLEGAL_BLOCK_NUM 0x01000E
235
236/* Block number overlaps fs metadata */
237#define PR_1_BLOCK_OVERLAPS_METADATA 0x01000F
238
239/* Inode has illegal blocks (latch question) */
240#define PR_1_INODE_BLOCK_LATCH 0x010010
241
242/* Too many bad blocks in inode */
243#define PR_1_TOO_MANY_BAD_BLOCKS 0x010011
244
245/* Illegal block number in bad block inode */
246#define PR_1_BB_ILLEGAL_BLOCK_NUM 0x010012
247
248/* Bad block inode has illegal blocks (latch question) */
249#define PR_1_INODE_BBLOCK_LATCH 0x010013
250
251/* Duplicate or bad blocks in use! */
252#define PR_1_DUP_BLOCKS_PREENSTOP 0x010014
253
254/* Bad block used as bad block indirect block */
255#define PR_1_BBINODE_BAD_METABLOCK 0x010015
256
257/* Inconsistency can't be fixed prompt */
258#define PR_1_BBINODE_BAD_METABLOCK_PROMPT 0x010016
259
260/* Bad primary block */
261#define PR_1_BAD_PRIMARY_BLOCK 0x010017
262
263/* Bad primary block prompt */
264#define PR_1_BAD_PRIMARY_BLOCK_PROMPT 0x010018
265
266/* Bad primary superblock */
267#define PR_1_BAD_PRIMARY_SUPERBLOCK 0x010019
268
269/* Bad primary block group descriptors */
270#define PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR 0x01001A
271
272/* Bad superblock in group */
273#define PR_1_BAD_SUPERBLOCK 0x01001B
274
275/* Bad block group descriptors in group */
276#define PR_1_BAD_GROUP_DESCRIPTORS 0x01001C
277
278/* Block claimed for no reason */
279#define PR_1_PROGERR_CLAIMED_BLOCK 0x01001D
280
281/* Error allocating blocks for relocating metadata */
282#define PR_1_RELOC_BLOCK_ALLOCATE 0x01001E
283
284/* Error allocating block buffer during relocation process */
285#define PR_1_RELOC_MEMORY_ALLOCATE 0x01001F
286
287/* Relocating metadata group information from X to Y */
288#define PR_1_RELOC_FROM_TO 0x010020
289
290/* Relocating metatdata group information to X */
291#define PR_1_RELOC_TO 0x010021
292
293/* Block read error during relocation process */
294#define PR_1_RELOC_READ_ERR 0x010022
295
296/* Block write error during relocation process */
297#define PR_1_RELOC_WRITE_ERR 0x010023
298
299/* Error allocating inode bitmap */
300#define PR_1_ALLOCATE_IBITMAP_ERROR 0x010024
301
302/* Error allocating block bitmap */
303#define PR_1_ALLOCATE_BBITMAP_ERROR 0x010025
304
305/* Error allocating icount structure */
306#define PR_1_ALLOCATE_ICOUNT 0x010026
307
308/* Error allocating dbcount */
309#define PR_1_ALLOCATE_DBCOUNT 0x010027
310
311/* Error while scanning inodes */
312#define PR_1_ISCAN_ERROR 0x010028
313
314/* Error while iterating over blocks */
315#define PR_1_BLOCK_ITERATE 0x010029
316
317/* Error while storing inode count information */
318#define PR_1_ICOUNT_STORE 0x01002A
319
320/* Error while storing directory block information */
321#define PR_1_ADD_DBLOCK 0x01002B
322
323/* Error while reading inode (for clearing) */
324#define PR_1_READ_INODE 0x01002C
325
326/* Suppress messages prompt */
327#define PR_1_SUPPRESS_MESSAGES 0x01002D
328
329/* Imagic flag set on an inode when filesystem doesn't support it */
330#define PR_1_SET_IMAGIC 0x01002F
331
332/* Immutable flag set on a device or socket inode */
333#define PR_1_SET_IMMUTABLE 0x010030
334
335/* Compression flag set on a non-compressed filesystem */
336#define PR_1_COMPR_SET 0x010031
337
338/* Non-zero size on on device, fifo or socket inode */
339#define PR_1_SET_NONZSIZE 0x010032
340
341/* Filesystem revision is 0, but feature flags are set */
342#define PR_1_FS_REV_LEVEL 0x010033
343
344/* Journal inode not in use, needs clearing */
345#define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034
346
347/* Journal inode has wrong mode */
348#define PR_1_JOURNAL_BAD_MODE 0x010035
349
350/* Inode that was part of orphan linked list */
351#define PR_1_LOW_DTIME 0x010036
352
353/* Latch question which asks how to deal with low dtime inodes */
354#define PR_1_ORPHAN_LIST_REFUGEES 0x010037
355
356/* Error allocating refcount structure */
357#define PR_1_ALLOCATE_REFCOUNT 0x010038
358
359/* Error reading Extended Attribute block */
360#define PR_1_READ_EA_BLOCK 0x010039
361
362/* Invalid Extended Attribute block */
363#define PR_1_BAD_EA_BLOCK 0x01003A
364
365/* Error reading Extended Attribute block while fixing refcount -- abort */
366#define PR_1_EXTATTR_READ_ABORT 0x01003B
367
368/* Extended attribute reference count incorrect */
369#define PR_1_EXTATTR_REFCOUNT 0x01003C
370
371/* Error writing Extended Attribute block while fixing refcount */
372#define PR_1_EXTATTR_WRITE 0x01003D
373
374/* Multiple EA blocks not supported */
375#define PR_1_EA_MULTI_BLOCK 0x01003E
376
377/* Error allocating EA region allocation structure */
378#define PR_1_EA_ALLOC_REGION 0x01003F
379
380/* Error EA allocation collision */
381#define PR_1_EA_ALLOC_COLLISION 0x010040
382
383/* Bad extended attribute name */
384#define PR_1_EA_BAD_NAME 0x010041
385
386/* Bad extended attribute value */
387#define PR_1_EA_BAD_VALUE 0x010042
388
389/* Inode too big (latch question) */
390#define PR_1_INODE_TOOBIG 0x010043
391
392/* Directory too big */
393#define PR_1_TOOBIG_DIR 0x010044
394
395/* Regular file too big */
396#define PR_1_TOOBIG_REG 0x010045
397
398/* Symlink too big */
399#define PR_1_TOOBIG_SYMLINK 0x010046
400
401/* INDEX_FL flag set on a non-HTREE filesystem */
402#define PR_1_HTREE_SET 0x010047
403
404/* INDEX_FL flag set on a non-directory */
405#define PR_1_HTREE_NODIR 0x010048
406
407/* Invalid root node in HTREE directory */
408#define PR_1_HTREE_BADROOT 0x010049
409
410/* Unsupported hash version in HTREE directory */
411#define PR_1_HTREE_HASHV 0x01004A
412
413/* Incompatible flag in HTREE root node */
414#define PR_1_HTREE_INCOMPAT 0x01004B
415
416/* HTREE too deep */
417#define PR_1_HTREE_DEPTH 0x01004C
418
419/* Bad block has indirect block that conflicts with filesystem block */
420#define PR_1_BB_FS_BLOCK 0x01004D
421
422/* Resize inode failed */
423#define PR_1_RESIZE_INODE_CREATE 0x01004E
424
425/* inode->i_size is too long */
426#define PR_1_EXTRA_ISIZE 0x01004F
427
428/* attribute name is too long */
429#define PR_1_ATTR_NAME_LEN 0x010050
430
431/* wrong EA value offset */
432#define PR_1_ATTR_VALUE_OFFSET 0x010051
433
434/* wrong EA blocknumber */
435#define PR_1_ATTR_VALUE_BLOCK 0x010052
436
437/* wrong EA value size */
438#define PR_1_ATTR_VALUE_SIZE 0x010053
439
440/* wrong EA hash value */
441#define PR_1_ATTR_HASH 0x010054
442
443/*
444 * Pass 1b errors
445 */
446
447/* Pass 1B: Rescan for duplicate/bad blocks */
448#define PR_1B_PASS_HEADER 0x011000
449
450/* Duplicate/bad block(s) header */
451#define PR_1B_DUP_BLOCK_HEADER 0x011001
452
453/* Duplicate/bad block(s) in inode */
454#define PR_1B_DUP_BLOCK 0x011002
455
456/* Duplicate/bad block(s) end */
457#define PR_1B_DUP_BLOCK_END 0x011003
458
459/* Error while scanning inodes */
460#define PR_1B_ISCAN_ERROR 0x011004
461
462/* Error allocating inode bitmap */
463#define PR_1B_ALLOCATE_IBITMAP_ERROR 0x011005
464
465/* Error while iterating over blocks */
466#define PR_1B_BLOCK_ITERATE 0x0110006
467
468/* Error adjusting EA refcount */
469#define PR_1B_ADJ_EA_REFCOUNT 0x0110007
470
471
472/* Pass 1C: Scan directories for inodes with dup blocks. */
473#define PR_1C_PASS_HEADER 0x012000
474
475
476/* Pass 1D: Reconciling duplicate blocks */
477#define PR_1D_PASS_HEADER 0x013000
478
479/* File has duplicate blocks */
480#define PR_1D_DUP_FILE 0x013001
481
482/* List of files sharing duplicate blocks */
483#define PR_1D_DUP_FILE_LIST 0x013002
484
485/* File sharing blocks with filesystem metadata */
486#define PR_1D_SHARE_METADATA 0x013003
487
488/* Report of how many duplicate/bad inodes */
489#define PR_1D_NUM_DUP_INODES 0x013004
490
491/* Duplicated blocks already reassigned or cloned. */
492#define PR_1D_DUP_BLOCKS_DEALT 0x013005
493
494/* Clone duplicate/bad blocks? */
495#define PR_1D_CLONE_QUESTION 0x013006
496
497/* Delete file? */
498#define PR_1D_DELETE_QUESTION 0x013007
499
500/* Couldn't clone file (error) */
501#define PR_1D_CLONE_ERROR 0x013008
502
503/*
504 * Pass 2 errors
505 */
506
507/* Pass 2: Checking directory structure */
508#define PR_2_PASS_HEADER 0x020000
509
510/* Bad inode number for '.' */
511#define PR_2_BAD_INODE_DOT 0x020001
512
513/* Directory entry has bad inode number */
514#define PR_2_BAD_INO 0x020002
515
516/* Directory entry has deleted or unused inode */
517#define PR_2_UNUSED_INODE 0x020003
518
519/* Directry entry is link to '.' */
520#define PR_2_LINK_DOT 0x020004
521
522/* Directory entry points to inode now located in a bad block */
523#define PR_2_BB_INODE 0x020005
524
525/* Directory entry contains a link to a directory */
526#define PR_2_LINK_DIR 0x020006
527
528/* Directory entry contains a link to the root directry */
529#define PR_2_LINK_ROOT 0x020007
530
531/* Directory entry has illegal characters in its name */
532#define PR_2_BAD_NAME 0x020008
533
534/* Missing '.' in directory inode */
535#define PR_2_MISSING_DOT 0x020009
536
537/* Missing '..' in directory inode */
538#define PR_2_MISSING_DOT_DOT 0x02000A
539
540/* First entry in directory inode doesn't contain '.' */
541#define PR_2_1ST_NOT_DOT 0x02000B
542
543/* Second entry in directory inode doesn't contain '..' */
544#define PR_2_2ND_NOT_DOT_DOT 0x02000C
545
546/* i_faddr should be zero */
547#define PR_2_FADDR_ZERO 0x02000D
548
549/* i_file_acl should be zero */
550#define PR_2_FILE_ACL_ZERO 0x02000E
551
552/* i_dir_acl should be zero */
553#define PR_2_DIR_ACL_ZERO 0x02000F
554
555/* i_frag should be zero */
556#define PR_2_FRAG_ZERO 0x020010
557
558/* i_fsize should be zero */
559#define PR_2_FSIZE_ZERO 0x020011
560
561/* inode has bad mode */
562#define PR_2_BAD_MODE 0x020012
563
564/* directory corrupted */
565#define PR_2_DIR_CORRUPTED 0x020013
566
567/* filename too long */
568#define PR_2_FILENAME_LONG 0x020014
569
570/* Directory inode has a missing block (hole) */
571#define PR_2_DIRECTORY_HOLE 0x020015
572
573/* '.' is not NULL terminated */
574#define PR_2_DOT_NULL_TERM 0x020016
575
576/* '..' is not NULL terminated */
577#define PR_2_DOT_DOT_NULL_TERM 0x020017
578
579/* Illegal character device in inode */
580#define PR_2_BAD_CHAR_DEV 0x020018
581
582/* Illegal block device in inode */
583#define PR_2_BAD_BLOCK_DEV 0x020019
584
585/* Duplicate '.' entry */
586#define PR_2_DUP_DOT 0x02001A
587
588/* Duplicate '..' entry */
589#define PR_2_DUP_DOT_DOT 0x02001B
590
591/* Internal error: couldn't find dir_info */
592#define PR_2_NO_DIRINFO 0x02001C
593
594/* Final rec_len is wrong */
595#define PR_2_FINAL_RECLEN 0x02001D
596
597/* Error allocating icount structure */
598#define PR_2_ALLOCATE_ICOUNT 0x02001E
599
600/* Error iterating over directory blocks */
601#define PR_2_DBLIST_ITERATE 0x02001F
602
603/* Error reading directory block */
604#define PR_2_READ_DIRBLOCK 0x020020
605
606/* Error writing directory block */
607#define PR_2_WRITE_DIRBLOCK 0x020021
608
609/* Error allocating new directory block */
610#define PR_2_ALLOC_DIRBOCK 0x020022
611
612/* Error deallocating inode */
613#define PR_2_DEALLOC_INODE 0x020023
614
615/* Directory entry for '.' is big. Split? */
616#define PR_2_SPLIT_DOT 0x020024
617
618/* Illegal FIFO */
619#define PR_2_BAD_FIFO 0x020025
620
621/* Illegal socket */
622#define PR_2_BAD_SOCKET 0x020026
623
624/* Directory filetype not set */
625#define PR_2_SET_FILETYPE 0x020027
626
627/* Directory filetype incorrect */
628#define PR_2_BAD_FILETYPE 0x020028
629
630/* Directory filetype set when it shouldn't be */
631#define PR_2_CLEAR_FILETYPE 0x020029
632
633/* Directory filename can't be zero-length */
634#define PR_2_NULL_NAME 0x020030
635
636/* Invalid symlink */
637#define PR_2_INVALID_SYMLINK 0x020031
638
639/* i_file_acl (extended attribute) is bad */
640#define PR_2_FILE_ACL_BAD 0x020032
641
642/* Filesystem contains large files, but has no such flag in sb */
643#define PR_2_FEATURE_LARGE_FILES 0x020033
644
645/* Node in HTREE directory not referenced */
646#define PR_2_HTREE_NOTREF 0x020034
647
648/* Node in HTREE directory referenced twice */
649#define PR_2_HTREE_DUPREF 0x020035
650
651/* Node in HTREE directory has bad min hash */
652#define PR_2_HTREE_MIN_HASH 0x020036
653
654/* Node in HTREE directory has bad max hash */
655#define PR_2_HTREE_MAX_HASH 0x020037
656
657/* Clear invalid HTREE directory */
658#define PR_2_HTREE_CLEAR 0x020038
659
660/* Clear the htree flag forcibly */
661/* #define PR_2_HTREE_FCLR 0x020039 */
662
663/* Bad block in htree interior node */
664#define PR_2_HTREE_BADBLK 0x02003A
665
666/* Error adjusting EA refcount */
667#define PR_2_ADJ_EA_REFCOUNT 0x02003B
668
669/* Invalid HTREE root node */
670#define PR_2_HTREE_BAD_ROOT 0x02003C
671
672/* Invalid HTREE limit */
673#define PR_2_HTREE_BAD_LIMIT 0x02003D
674
675/* Invalid HTREE count */
676#define PR_2_HTREE_BAD_COUNT 0x02003E
677
678/* HTREE interior node has out-of-order hashes in table */
679#define PR_2_HTREE_HASH_ORDER 0x02003F
680
681/* Node in HTREE directory has bad depth */
682#define PR_2_HTREE_BAD_DEPTH 0x020040
683
684/* Duplicate directory entry found */
685#define PR_2_DUPLICATE_DIRENT 0x020041
686
687/* Non-unique filename found */
688#define PR_2_NON_UNIQUE_FILE 0x020042
689
690/* Duplicate directory entry found */
691#define PR_2_REPORT_DUP_DIRENT 0x020043
692
693/*
694 * Pass 3 errors
695 */
696
697/* Pass 3: Checking directory connectivity */
698#define PR_3_PASS_HEADER 0x030000
699
700/* Root inode not allocated */
701#define PR_3_NO_ROOT_INODE 0x030001
702
703/* No room in lost+found */
704#define PR_3_EXPAND_LF_DIR 0x030002
705
706/* Unconnected directory inode */
707#define PR_3_UNCONNECTED_DIR 0x030003
708
709/* /lost+found not found */
710#define PR_3_NO_LF_DIR 0x030004
711
712/* .. entry is incorrect */
713#define PR_3_BAD_DOT_DOT 0x030005
714
715/* Bad or non-existent /lost+found. Cannot reconnect */
716#define PR_3_NO_LPF 0x030006
717
718/* Could not expand /lost+found */
719#define PR_3_CANT_EXPAND_LPF 0x030007
720
721/* Could not reconnect inode */
722#define PR_3_CANT_RECONNECT 0x030008
723
724/* Error while trying to find /lost+found */
725#define PR_3_ERR_FIND_LPF 0x030009
726
727/* Error in ext2fs_new_block while creating /lost+found */
728#define PR_3_ERR_LPF_NEW_BLOCK 0x03000A
729
730/* Error in ext2fs_new_inode while creating /lost+found */
731#define PR_3_ERR_LPF_NEW_INODE 0x03000B
732
733/* Error in ext2fs_new_dir_block while creating /lost+found */
734#define PR_3_ERR_LPF_NEW_DIR_BLOCK 0x03000C
735
736/* Error while writing directory block for /lost+found */
737#define PR_3_ERR_LPF_WRITE_BLOCK 0x03000D
738
739/* Error while adjusting inode count */
740#define PR_3_ADJUST_INODE 0x03000E
741
742/* Couldn't fix parent directory -- error */
743#define PR_3_FIX_PARENT_ERR 0x03000F
744
745/* Couldn't fix parent directory -- couldn't find it */
746#define PR_3_FIX_PARENT_NOFIND 0x030010
747
748/* Error allocating inode bitmap */
749#define PR_3_ALLOCATE_IBITMAP_ERROR 0x030011
750
751/* Error creating root directory */
752#define PR_3_CREATE_ROOT_ERROR 0x030012
753
754/* Error creating lost and found directory */
755#define PR_3_CREATE_LPF_ERROR 0x030013
756
757/* Root inode is not directory; aborting */
758#define PR_3_ROOT_NOT_DIR_ABORT 0x030014
759
760/* Cannot proceed without a root inode. */
761#define PR_3_NO_ROOT_INODE_ABORT 0x030015
762
763/* Internal error: couldn't find dir_info */
764#define PR_3_NO_DIRINFO 0x030016
765
766/* Lost+found is not a directory */
767#define PR_3_LPF_NOTDIR 0x030017
768
769/*
770 * Pass 3a --- rehashing diretories
771 */
772/* Pass 3a: Reindexing directories */
773#define PR_3A_PASS_HEADER 0x031000
774
775/* Error iterating over directories */
776#define PR_3A_OPTIMIZE_ITER 0x031001
777
778/* Error rehash directory */
779#define PR_3A_OPTIMIZE_DIR_ERR 0x031002
780
781/* Rehashing dir header */
782#define PR_3A_OPTIMIZE_DIR_HEADER 0x031003
783
784/* Rehashing directory %d */
785#define PR_3A_OPTIMIZE_DIR 0x031004
786
787/* Rehashing dir end */
788#define PR_3A_OPTIMIZE_DIR_END 0x031005
789
790/*
791 * Pass 4 errors
792 */
793
794/* Pass 4: Checking reference counts */
795#define PR_4_PASS_HEADER 0x040000
796
797/* Unattached zero-length inode */
798#define PR_4_ZERO_LEN_INODE 0x040001
799
800/* Unattached inode */
801#define PR_4_UNATTACHED_INODE 0x040002
802
803/* Inode ref count wrong */
804#define PR_4_BAD_REF_COUNT 0x040003
805
806/* Inconsistent inode count information cached */
807#define PR_4_INCONSISTENT_COUNT 0x040004
808
809/*
810 * Pass 5 errors
811 */
812
813/* Pass 5: Checking group summary information */
814#define PR_5_PASS_HEADER 0x050000
815
816/* Padding at end of inode bitmap is not set. */
817#define PR_5_INODE_BMAP_PADDING 0x050001
818
819/* Padding at end of block bitmap is not set. */
820#define PR_5_BLOCK_BMAP_PADDING 0x050002
821
822/* Block bitmap differences header */
823#define PR_5_BLOCK_BITMAP_HEADER 0x050003
824
825/* Block not used, but marked in bitmap */
826#define PR_5_BLOCK_UNUSED 0x050004
827
828/* Block used, but not marked used in bitmap */
829#define PR_5_BLOCK_USED 0x050005
830
831/* Block bitmap differences end */
832#define PR_5_BLOCK_BITMAP_END 0x050006
833
834/* Inode bitmap differences header */
835#define PR_5_INODE_BITMAP_HEADER 0x050007
836
837/* Inode not used, but marked in bitmap */
838#define PR_5_INODE_UNUSED 0x050008
839
840/* Inode used, but not marked used in bitmap */
841#define PR_5_INODE_USED 0x050009
842
843/* Inode bitmap differences end */
844#define PR_5_INODE_BITMAP_END 0x05000A
845
846/* Free inodes count for group wrong */
847#define PR_5_FREE_INODE_COUNT_GROUP 0x05000B
848
849/* Directories count for group wrong */
850#define PR_5_FREE_DIR_COUNT_GROUP 0x05000C
851
852/* Free inodes count wrong */
853#define PR_5_FREE_INODE_COUNT 0x05000D
854
855/* Free blocks count for group wrong */
856#define PR_5_FREE_BLOCK_COUNT_GROUP 0x05000E
857
858/* Free blocks count wrong */
859#define PR_5_FREE_BLOCK_COUNT 0x05000F
860
861/* Programming error: bitmap endpoints don't match */
862#define PR_5_BMAP_ENDPOINTS 0x050010
863
864/* Internal error: fudging end of bitmap */
865#define PR_5_FUDGE_BITMAP_ERROR 0x050011
866
867/* Error copying in replacement inode bitmap */
868#define PR_5_COPY_IBITMAP_ERROR 0x050012
869
870/* Error copying in replacement block bitmap */
871#define PR_5_COPY_BBITMAP_ERROR 0x050013
872
873/* Block range not used, but marked in bitmap */
874#define PR_5_BLOCK_RANGE_UNUSED 0x050014
875
876/* Block range used, but not marked used in bitmap */
877#define PR_5_BLOCK_RANGE_USED 0x050015
878
879/* Inode range not used, but marked in bitmap */
880#define PR_5_INODE_RANGE_UNUSED 0x050016
881
882/* Inode rangeused, but not marked used in bitmap */
883#define PR_5_INODE_RANGE_USED 0x050017
884
885/*
886 * Function declarations
887 */
888int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx);
889int end_problem_latch(e2fsck_t ctx, int mask);
890int set_latch_flags(int mask, int setflags, int clearflags);
891int get_latch_flags(int mask, int *value);
892void clear_problem_context(struct problem_context *ctx);
893
894/* message.c */
895void print_e2fsck_message(e2fsck_t ctx, const char *msg,
896 struct problem_context *pctx, int first);
897
diff --git a/e2fsprogs/e2fsck/problemP.h b/e2fsprogs/e2fsck/problemP.h
deleted file mode 100644
index 329056b95..000000000
--- a/e2fsprogs/e2fsck/problemP.h
+++ /dev/null
@@ -1,42 +0,0 @@
1/*
2 * problemP.h --- Private header file for fix_problem()
3 *
4 * Copyright 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12struct e2fsck_problem {
13 problem_t e2p_code;
14 const char * e2p_description;
15 char prompt;
16 int flags;
17 problem_t second_code;
18};
19
20struct latch_descr {
21 int latch_code;
22 problem_t question;
23 problem_t end_message;
24 int flags;
25};
26
27#define PR_PREEN_OK 0x000001 /* Don't need to do preenhalt */
28#define PR_NO_OK 0x000002 /* If user answers no, don't make fs invalid */
29#define PR_NO_DEFAULT 0x000004 /* Default to no */
30#define PR_MSG_ONLY 0x000008 /* Print message only */
31
32/* Bit positions 0x000ff0 are reserved for the PR_LATCH flags */
33
34#define PR_FATAL 0x001000 /* Fatal error */
35#define PR_AFTER_CODE 0x002000 /* After asking the first question, */
36 /* ask another */
37#define PR_PREEN_NOMSG 0x004000 /* Don't print a message if we're preening */
38#define PR_NOCOLLATE 0x008000 /* Don't collate answers for this latch */
39#define PR_NO_NOMSG 0x010000 /* Don't print a message if e2fsck -n */
40#define PR_PREEN_NO 0x020000 /* Use No as an answer if preening */
41#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
42
diff --git a/e2fsprogs/e2fsck/recovery.c b/e2fsprogs/e2fsck/recovery.c
deleted file mode 100644
index edfa9bc83..000000000
--- a/e2fsprogs/e2fsck/recovery.c
+++ /dev/null
@@ -1,586 +0,0 @@
1/*
2 * linux/fs/recovery.c
3 *
4 * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
5 *
6 * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
7 *
8 * This file is part of the Linux kernel and is made available under
9 * the terms of the GNU General Public License, version 2, or at your
10 * option, any later version, incorporated herein by reference.
11 *
12 * Journal recovery routines for the generic filesystem journaling code;
13 * part of the ext2fs journaling system.
14 */
15
16#ifndef __KERNEL__
17#include "jfs_user.h"
18#else
19#include <linux/time.h>
20#include <linux/fs.h>
21#include <linux/jbd.h>
22#include <linux/errno.h>
23#include <linux/slab.h>
24#endif
25
26/*
27 * Maintain information about the progress of the recovery job, so that
28 * the different passes can carry information between them.
29 */
30struct recovery_info
31{
32 tid_t start_transaction;
33 tid_t end_transaction;
34
35 int nr_replays;
36 int nr_revokes;
37 int nr_revoke_hits;
38};
39
40enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
41static int do_one_pass(journal_t *journal,
42 struct recovery_info *info, enum passtype pass);
43static int scan_revoke_records(journal_t *, struct buffer_head *,
44 tid_t, struct recovery_info *);
45
46#ifdef __KERNEL__
47
48/* Release readahead buffers after use */
49void journal_brelse_array(struct buffer_head *b[], int n)
50{
51 while (--n >= 0)
52 brelse (b[n]);
53}
54
55
56/*
57 * When reading from the journal, we are going through the block device
58 * layer directly and so there is no readahead being done for us. We
59 * need to implement any readahead ourselves if we want it to happen at
60 * all. Recovery is basically one long sequential read, so make sure we
61 * do the IO in reasonably large chunks.
62 *
63 * This is not so critical that we need to be enormously clever about
64 * the readahead size, though. 128K is a purely arbitrary, good-enough
65 * fixed value.
66 */
67
68#define MAXBUF 8
69static int do_readahead(journal_t *journal, unsigned int start)
70{
71 int err;
72 unsigned int max, nbufs, next;
73 unsigned long blocknr;
74 struct buffer_head *bh;
75
76 struct buffer_head * bufs[MAXBUF];
77
78 /* Do up to 128K of readahead */
79 max = start + (128 * 1024 / journal->j_blocksize);
80 if (max > journal->j_maxlen)
81 max = journal->j_maxlen;
82
83 /* Do the readahead itself. We'll submit MAXBUF buffer_heads at
84 * a time to the block device IO layer. */
85
86 nbufs = 0;
87
88 for (next = start; next < max; next++) {
89 err = journal_bmap(journal, next, &blocknr);
90
91 if (err) {
92 printk (KERN_ERR "JBD: bad block at offset %u\n",
93 next);
94 goto failed;
95 }
96
97 bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
98 if (!bh) {
99 err = -ENOMEM;
100 goto failed;
101 }
102
103 if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
104 bufs[nbufs++] = bh;
105 if (nbufs == MAXBUF) {
106 ll_rw_block(READ, nbufs, bufs);
107 journal_brelse_array(bufs, nbufs);
108 nbufs = 0;
109 }
110 } else
111 brelse(bh);
112 }
113
114 if (nbufs)
115 ll_rw_block(READ, nbufs, bufs);
116 err = 0;
117
118failed:
119 if (nbufs)
120 journal_brelse_array(bufs, nbufs);
121 return err;
122}
123
124#endif /* __KERNEL__ */
125
126
127/*
128 * Read a block from the journal
129 */
130
131static int jread(struct buffer_head **bhp, journal_t *journal,
132 unsigned int offset)
133{
134 int err;
135 unsigned long blocknr;
136 struct buffer_head *bh;
137
138 *bhp = NULL;
139
140 J_ASSERT (offset < journal->j_maxlen);
141
142 err = journal_bmap(journal, offset, &blocknr);
143
144 if (err) {
145 printk (KERN_ERR "JBD: bad block at offset %u\n",
146 offset);
147 return err;
148 }
149
150 bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
151 if (!bh)
152 return -ENOMEM;
153
154 if (!buffer_uptodate(bh)) {
155 /* If this is a brand new buffer, start readahead.
156 Otherwise, we assume we are already reading it. */
157 if (!buffer_req(bh))
158 do_readahead(journal, offset);
159 wait_on_buffer(bh);
160 }
161
162 if (!buffer_uptodate(bh)) {
163 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
164 offset);
165 brelse(bh);
166 return -EIO;
167 }
168
169 *bhp = bh;
170 return 0;
171}
172
173
174/*
175 * Count the number of in-use tags in a journal descriptor block.
176 */
177
178static int count_tags(struct buffer_head *bh, int size)
179{
180 char * tagp;
181 journal_block_tag_t * tag;
182 int nr = 0;
183
184 tagp = &bh->b_data[sizeof(journal_header_t)];
185
186 while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
187 tag = (journal_block_tag_t *) tagp;
188
189 nr++;
190 tagp += sizeof(journal_block_tag_t);
191 if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
192 tagp += 16;
193
194 if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
195 break;
196 }
197
198 return nr;
199}
200
201
202/* Make sure we wrap around the log correctly! */
203#define wrap(journal, var) \
204do { \
205 if (var >= (journal)->j_last) \
206 var -= ((journal)->j_last - (journal)->j_first); \
207} while (0)
208
209/**
210 * int journal_recover(journal_t *journal) - recovers a on-disk journal
211 * @journal: the journal to recover
212 *
213 * The primary function for recovering the log contents when mounting a
214 * journaled device.
215 *
216 * Recovery is done in three passes. In the first pass, we look for the
217 * end of the log. In the second, we assemble the list of revoke
218 * blocks. In the third and final pass, we replay any un-revoked blocks
219 * in the log.
220 */
221int journal_recover(journal_t *journal)
222{
223 int err;
224 journal_superblock_t * sb;
225
226 struct recovery_info info;
227
228 memset(&info, 0, sizeof(info));
229 sb = journal->j_superblock;
230
231 /*
232 * The journal superblock's s_start field (the current log head)
233 * is always zero if, and only if, the journal was cleanly
234 * unmounted.
235 */
236
237 if (!sb->s_start) {
238 jbd_debug(1, "No recovery required, last transaction %d\n",
239 ntohl(sb->s_sequence));
240 journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
241 return 0;
242 }
243
244 err = do_one_pass(journal, &info, PASS_SCAN);
245 if (!err)
246 err = do_one_pass(journal, &info, PASS_REVOKE);
247 if (!err)
248 err = do_one_pass(journal, &info, PASS_REPLAY);
249
250 jbd_debug(0, "JBD: recovery, exit status %d, "
251 "recovered transactions %u to %u\n",
252 err, info.start_transaction, info.end_transaction);
253 jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
254 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
255
256 /* Restart the log at the next transaction ID, thus invalidating
257 * any existing commit records in the log. */
258 journal->j_transaction_sequence = ++info.end_transaction;
259
260 journal_clear_revoke(journal);
261 sync_blockdev(journal->j_fs_dev);
262 return err;
263}
264
265/**
266 * int journal_skip_recovery() - Start journal and wipe exiting records
267 * @journal: journal to startup
268 *
269 * Locate any valid recovery information from the journal and set up the
270 * journal structures in memory to ignore it (presumably because the
271 * caller has evidence that it is out of date).
272 * This function does'nt appear to be exorted..
273 *
274 * We perform one pass over the journal to allow us to tell the user how
275 * much recovery information is being erased, and to let us initialise
276 * the journal transaction sequence numbers to the next unused ID.
277 */
278int journal_skip_recovery(journal_t *journal)
279{
280 int err;
281 journal_superblock_t * sb;
282
283 struct recovery_info info;
284
285 memset (&info, 0, sizeof(info));
286 sb = journal->j_superblock;
287
288 err = do_one_pass(journal, &info, PASS_SCAN);
289
290 if (err) {
291 printk(KERN_ERR "JBD: error %d scanning journal\n", err);
292 ++journal->j_transaction_sequence;
293 } else {
294#ifdef __CONFIG_JBD_DEBUG__E2FS
295 int dropped = info.end_transaction - ntohl(sb->s_sequence);
296#endif
297 jbd_debug(0,
298 "JBD: ignoring %d transaction%s from the journal.\n",
299 dropped, (dropped == 1) ? "" : "s");
300 journal->j_transaction_sequence = ++info.end_transaction;
301 }
302
303 journal->j_tail = 0;
304 return err;
305}
306
307static int do_one_pass(journal_t *journal,
308 struct recovery_info *info, enum passtype pass)
309{
310 unsigned int first_commit_ID, next_commit_ID;
311 unsigned long next_log_block;
312 int err, success = 0;
313 journal_superblock_t * sb;
314 journal_header_t * tmp;
315 struct buffer_head * bh;
316 unsigned int sequence;
317 int blocktype;
318
319 /* Precompute the maximum metadata descriptors in a descriptor block */
320 int MAX_BLOCKS_PER_DESC;
321 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
322 / sizeof(journal_block_tag_t));
323
324 /*
325 * First thing is to establish what we expect to find in the log
326 * (in terms of transaction IDs), and where (in terms of log
327 * block offsets): query the superblock.
328 */
329
330 sb = journal->j_superblock;
331 next_commit_ID = ntohl(sb->s_sequence);
332 next_log_block = ntohl(sb->s_start);
333
334 first_commit_ID = next_commit_ID;
335 if (pass == PASS_SCAN)
336 info->start_transaction = first_commit_ID;
337
338 jbd_debug(1, "Starting recovery pass %d\n", pass);
339
340 /*
341 * Now we walk through the log, transaction by transaction,
342 * making sure that each transaction has a commit block in the
343 * expected place. Each complete transaction gets replayed back
344 * into the main filesystem.
345 */
346
347 while (1) {
348 int flags;
349 char * tagp;
350 journal_block_tag_t * tag;
351 struct buffer_head * obh;
352 struct buffer_head * nbh;
353
354 /* If we already know where to stop the log traversal,
355 * check right now that we haven't gone past the end of
356 * the log. */
357
358 if (pass != PASS_SCAN)
359 if (tid_geq(next_commit_ID, info->end_transaction))
360 break;
361
362 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
363 next_commit_ID, next_log_block, journal->j_last);
364
365 /* Skip over each chunk of the transaction looking
366 * either the next descriptor block or the final commit
367 * record. */
368
369 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
370 err = jread(&bh, journal, next_log_block);
371 if (err)
372 goto failed;
373
374 next_log_block++;
375 wrap(journal, next_log_block);
376
377 /* What kind of buffer is it?
378 *
379 * If it is a descriptor block, check that it has the
380 * expected sequence number. Otherwise, we're all done
381 * here. */
382
383 tmp = (journal_header_t *)bh->b_data;
384
385 if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
386 brelse(bh);
387 break;
388 }
389
390 blocktype = ntohl(tmp->h_blocktype);
391 sequence = ntohl(tmp->h_sequence);
392 jbd_debug(3, "Found magic %d, sequence %d\n",
393 blocktype, sequence);
394
395 if (sequence != next_commit_ID) {
396 brelse(bh);
397 break;
398 }
399
400 /* OK, we have a valid descriptor block which matches
401 * all of the sequence number checks. What are we going
402 * to do with it? That depends on the pass... */
403
404 switch(blocktype) {
405 case JFS_DESCRIPTOR_BLOCK:
406 /* If it is a valid descriptor block, replay it
407 * in pass REPLAY; otherwise, just skip over the
408 * blocks it describes. */
409 if (pass != PASS_REPLAY) {
410 next_log_block +=
411 count_tags(bh, journal->j_blocksize);
412 wrap(journal, next_log_block);
413 brelse(bh);
414 continue;
415 }
416
417 /* A descriptor block: we can now write all of
418 * the data blocks. Yay, useful work is finally
419 * getting done here! */
420
421 tagp = &bh->b_data[sizeof(journal_header_t)];
422 while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
423 <= journal->j_blocksize) {
424 unsigned long io_block;
425
426 tag = (journal_block_tag_t *) tagp;
427 flags = ntohl(tag->t_flags);
428
429 io_block = next_log_block++;
430 wrap(journal, next_log_block);
431 err = jread(&obh, journal, io_block);
432 if (err) {
433 /* Recover what we can, but
434 * report failure at the end. */
435 success = err;
436 printk (KERN_ERR
437 "JBD: IO error %d recovering "
438 "block %ld in log\n",
439 err, io_block);
440 } else {
441 unsigned long blocknr;
442
443 J_ASSERT(obh != NULL);
444 blocknr = ntohl(tag->t_blocknr);
445
446 /* If the block has been
447 * revoked, then we're all done
448 * here. */
449 if (journal_test_revoke
450 (journal, blocknr,
451 next_commit_ID)) {
452 brelse(obh);
453 ++info->nr_revoke_hits;
454 goto skip_write;
455 }
456
457 /* Find a buffer for the new
458 * data being restored */
459 nbh = __getblk(journal->j_fs_dev,
460 blocknr,
461 journal->j_blocksize);
462 if (nbh == NULL) {
463 printk(KERN_ERR
464 "JBD: Out of memory "
465 "during recovery.\n");
466 err = -ENOMEM;
467 brelse(bh);
468 brelse(obh);
469 goto failed;
470 }
471
472 lock_buffer(nbh);
473 memcpy(nbh->b_data, obh->b_data,
474 journal->j_blocksize);
475 if (flags & JFS_FLAG_ESCAPE) {
476 *((unsigned int *)bh->b_data) =
477 htonl(JFS_MAGIC_NUMBER);
478 }
479
480 BUFFER_TRACE(nbh, "marking dirty");
481 set_buffer_uptodate(nbh);
482 mark_buffer_dirty(nbh);
483 BUFFER_TRACE(nbh, "marking uptodate");
484 ++info->nr_replays;
485 /* ll_rw_block(WRITE, 1, &nbh); */
486 unlock_buffer(nbh);
487 brelse(obh);
488 brelse(nbh);
489 }
490
491 skip_write:
492 tagp += sizeof(journal_block_tag_t);
493 if (!(flags & JFS_FLAG_SAME_UUID))
494 tagp += 16;
495
496 if (flags & JFS_FLAG_LAST_TAG)
497 break;
498 }
499
500 brelse(bh);
501 continue;
502
503 case JFS_COMMIT_BLOCK:
504 /* Found an expected commit block: not much to
505 * do other than move on to the next sequence
506 * number. */
507 brelse(bh);
508 next_commit_ID++;
509 continue;
510
511 case JFS_REVOKE_BLOCK:
512 /* If we aren't in the REVOKE pass, then we can
513 * just skip over this block. */
514 if (pass != PASS_REVOKE) {
515 brelse(bh);
516 continue;
517 }
518
519 err = scan_revoke_records(journal, bh,
520 next_commit_ID, info);
521 brelse(bh);
522 if (err)
523 goto failed;
524 continue;
525
526 default:
527 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
528 blocktype);
529 goto done;
530 }
531 }
532
533 done:
534 /*
535 * We broke out of the log scan loop: either we came to the
536 * known end of the log or we found an unexpected block in the
537 * log. If the latter happened, then we know that the "current"
538 * transaction marks the end of the valid log.
539 */
540
541 if (pass == PASS_SCAN)
542 info->end_transaction = next_commit_ID;
543 else {
544 /* It's really bad news if different passes end up at
545 * different places (but possible due to IO errors). */
546 if (info->end_transaction != next_commit_ID) {
547 printk (KERN_ERR "JBD: recovery pass %d ended at "
548 "transaction %u, expected %u\n",
549 pass, next_commit_ID, info->end_transaction);
550 if (!success)
551 success = -EIO;
552 }
553 }
554
555 return success;
556
557 failed:
558 return err;
559}
560
561
562/* Scan a revoke record, marking all blocks mentioned as revoked. */
563
564static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
565 tid_t sequence, struct recovery_info *info)
566{
567 journal_revoke_header_t *header;
568 int offset, max;
569
570 header = (journal_revoke_header_t *) bh->b_data;
571 offset = sizeof(journal_revoke_header_t);
572 max = ntohl(header->r_count);
573
574 while (offset < max) {
575 unsigned long blocknr;
576 int err;
577
578 blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
579 offset += 4;
580 err = journal_set_revoke(journal, blocknr, sequence);
581 if (err)
582 return err;
583 ++info->nr_revokes;
584 }
585 return 0;
586}
diff --git a/e2fsprogs/e2fsck/region.c b/e2fsprogs/e2fsck/region.c
deleted file mode 100644
index 9ccb684a3..000000000
--- a/e2fsprogs/e2fsck/region.c
+++ /dev/null
@@ -1,204 +0,0 @@
1/*
2 * region.c --- code which manages allocations within a region.
3 *
4 * Copyright (C) 2001 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#if HAVE_UNISTD_H
13#include <unistd.h>
14#endif
15#include <string.h>
16
17#include "e2fsck.h"
18
19struct region_el {
20 region_addr_t start;
21 region_addr_t end;
22 struct region_el *next;
23};
24
25struct region_struct {
26 region_addr_t min;
27 region_addr_t max;
28 struct region_el *allocated;
29};
30
31region_t region_create(region_addr_t min, region_addr_t max)
32{
33 region_t region;
34
35 region = malloc(sizeof(struct region_struct));
36 if (!region)
37 return NULL;
38 memset(region, 0, sizeof(struct region_struct));
39 region->min = min;
40 region->max = max;
41 return region;
42}
43
44void region_free(region_t region)
45{
46 struct region_el *r, *next;
47
48 for (r = region->allocated; r; r = next) {
49 next = r->next;
50 free(r);
51 }
52 memset(region, 0, sizeof(struct region_struct));
53 free(region);
54}
55
56int region_allocate(region_t region, region_addr_t start, int n)
57{
58 struct region_el *r, *new_region, *prev, *next;
59 region_addr_t end;
60
61 end = start+n;
62 if ((start < region->min) || (end > region->max))
63 return -1;
64 if (n == 0)
65 return 1;
66
67 /*
68 * Search through the linked list. If we find that it
69 * conflicts witih something that's already allocated, return
70 * 1; if we can find an existing region which we can grow, do
71 * so. Otherwise, stop when we find the appropriate place
72 * insert a new region element into the linked list.
73 */
74 for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
75 if (((start >= r->start) && (start < r->end)) ||
76 ((end > r->start) && (end <= r->end)) ||
77 ((start <= r->start) && (end >= r->end)))
78 return 1;
79 if (end == r->start) {
80 r->start = start;
81 return 0;
82 }
83 if (start == r->end) {
84 if ((next = r->next)) {
85 if (end > next->start)
86 return 1;
87 if (end == next->start) {
88 r->end = next->end;
89 r->next = next->next;
90 free(next);
91 return 0;
92 }
93 }
94 r->end = end;
95 return 0;
96 }
97 if (start < r->start)
98 break;
99 }
100 /*
101 * Insert a new region element structure into the linked list
102 */
103 new_region = malloc(sizeof(struct region_el));
104 if (!new_region)
105 return -1;
106 new_region->start = start;
107 new_region->end = start + n;
108 new_region->next = r;
109 if (prev)
110 prev->next = new_region;
111 else
112 region->allocated = new_region;
113 return 0;
114}
115
116#ifdef TEST_PROGRAM
117#include <stdio.h>
118
119#define BCODE_END 0
120#define BCODE_CREATE 1
121#define BCODE_FREE 2
122#define BCODE_ALLOCATE 3
123#define BCODE_PRINT 4
124
125int bcode_program[] = {
126 BCODE_CREATE, 1, 1001,
127 BCODE_PRINT,
128 BCODE_ALLOCATE, 10, 10,
129 BCODE_ALLOCATE, 30, 10,
130 BCODE_PRINT,
131 BCODE_ALLOCATE, 1, 15,
132 BCODE_ALLOCATE, 15, 8,
133 BCODE_ALLOCATE, 1, 20,
134 BCODE_ALLOCATE, 1, 8,
135 BCODE_PRINT,
136 BCODE_ALLOCATE, 40, 10,
137 BCODE_PRINT,
138 BCODE_ALLOCATE, 22, 5,
139 BCODE_PRINT,
140 BCODE_ALLOCATE, 27, 3,
141 BCODE_PRINT,
142 BCODE_ALLOCATE, 20, 2,
143 BCODE_PRINT,
144 BCODE_ALLOCATE, 49, 1,
145 BCODE_ALLOCATE, 50, 5,
146 BCODE_ALLOCATE, 9, 2,
147 BCODE_ALLOCATE, 9, 1,
148 BCODE_PRINT,
149 BCODE_FREE,
150 BCODE_END
151};
152
153void region_print(region_t region, FILE *f)
154{
155 struct region_el *r;
156 int i = 0;
157
158 fprintf(f, "Printing region (min=%d. max=%d)\n\t", region->min,
159 region->max);
160 for (r = region->allocated; r; r = r->next) {
161 fprintf(f, "(%d, %d) ", r->start, r->end);
162 if (++i >= 8)
163 fprintf(f, "\n\t");
164 }
165 fprintf(f, "\n");
166}
167
168int main(int argc, char **argv)
169{
170 region_t r;
171 int pc = 0, ret;
172 region_addr_t start, end, len;
173
174
175 while (1) {
176 switch (bcode_program[pc++]) {
177 case BCODE_END:
178 exit(0);
179 case BCODE_CREATE:
180 start = bcode_program[pc++];
181 end = bcode_program[pc++];
182 printf("Creating region with args(%d, %d)\n",
183 start, end);
184 r = region_create(start, end);
185 if (!r) {
186 fprintf(stderr, "Couldn't create region.\n");
187 exit(1);
188 }
189 break;
190 case BCODE_ALLOCATE:
191 start = bcode_program[pc++];
192 end = bcode_program[pc++];
193 ret = region_allocate(r, start, end);
194 printf("Region_allocate(%d, %d) returns %d\n",
195 start, end, ret);
196 break;
197 case BCODE_PRINT:
198 region_print(r, stdout);
199 break;
200 }
201 }
202}
203
204#endif /* TEST_PROGRAM */
diff --git a/e2fsprogs/e2fsck/rehash.c b/e2fsprogs/e2fsck/rehash.c
deleted file mode 100644
index 727e08c2b..000000000
--- a/e2fsprogs/e2fsck/rehash.c
+++ /dev/null
@@ -1,840 +0,0 @@
1/*
2 * rehash.c --- rebuild hash tree directories
3 *
4 * Copyright (C) 2002 Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 * This algorithm is designed for simplicity of implementation and to
12 * pack the directory as much as possible. It however requires twice
13 * as much memory as the size of the directory. The maximum size
14 * directory supported using a 4k blocksize is roughly a gigabyte, and
15 * so there may very well be problems with machines that don't have
16 * virtual memory, and obscenely large directories.
17 *
18 * An alternate algorithm which is much more disk intensive could be
19 * written, and probably will need to be written in the future. The
20 * design goals of such an algorithm are: (a) use (roughly) constant
21 * amounts of memory, no matter how large the directory, (b) the
22 * directory must be safe at all times, even if e2fsck is interrupted
23 * in the middle, (c) we must use minimal amounts of extra disk
24 * blocks. This pretty much requires an incremental approach, where
25 * we are reading from one part of the directory, and inserting into
26 * the front half. So the algorithm will have to keep track of a
27 * moving block boundary between the new tree and the old tree, and
28 * files will need to be moved from the old directory and inserted
29 * into the new tree. If the new directory requires space which isn't
30 * yet available, blocks from the beginning part of the old directory
31 * may need to be moved to the end of the directory to make room for
32 * the new tree:
33 *
34 * --------------------------------------------------------
35 * | new tree | | old tree |
36 * --------------------------------------------------------
37 * ^ ptr ^ptr
38 * tail new head old
39 *
40 * This is going to be a pain in the tuckus to implement, and will
41 * require a lot more disk accesses. So I'm going to skip it for now;
42 * it's only really going to be an issue for really, really big
43 * filesystems (when we reach the level of tens of millions of files
44 * in a single directory). It will probably be easier to simply
45 * require that e2fsck use VM first.
46 */
47
48#include <string.h>
49#include <ctype.h>
50#include <errno.h>
51#include "e2fsck.h"
52#include "problem.h"
53
54struct fill_dir_struct {
55 char *buf;
56 struct ext2_inode *inode;
57 int err;
58 e2fsck_t ctx;
59 struct hash_entry *harray;
60 int max_array, num_array;
61 int dir_size;
62 int compress;
63 ino_t parent;
64};
65
66struct hash_entry {
67 ext2_dirhash_t hash;
68 ext2_dirhash_t minor_hash;
69 struct ext2_dir_entry *dir;
70};
71
72struct out_dir {
73 int num;
74 int max;
75 char *buf;
76 ext2_dirhash_t *hashes;
77};
78
79static int fill_dir_block(ext2_filsys fs,
80 blk_t *block_nr,
81 e2_blkcnt_t blockcnt,
82 blk_t ref_block EXT2FS_ATTR((unused)),
83 int ref_offset EXT2FS_ATTR((unused)),
84 void *priv_data)
85{
86 struct fill_dir_struct *fd = (struct fill_dir_struct *) priv_data;
87 struct hash_entry *new_array, *ent;
88 struct ext2_dir_entry *dirent;
89 char *dir;
90 unsigned int offset, dir_offset;
91
92 if (blockcnt < 0)
93 return 0;
94
95 offset = blockcnt * fs->blocksize;
96 if (offset + fs->blocksize > fd->inode->i_size) {
97 fd->err = EXT2_ET_DIR_CORRUPTED;
98 return BLOCK_ABORT;
99 }
100 dir = (fd->buf+offset);
101 if (HOLE_BLKADDR(*block_nr)) {
102 memset(dir, 0, fs->blocksize);
103 dirent = (struct ext2_dir_entry *) dir;
104 dirent->rec_len = fs->blocksize;
105 } else {
106 fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
107 if (fd->err)
108 return BLOCK_ABORT;
109 }
110 /* While the directory block is "hot", index it. */
111 dir_offset = 0;
112 while (dir_offset < fs->blocksize) {
113 dirent = (struct ext2_dir_entry *) (dir + dir_offset);
114 if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
115 (dirent->rec_len < 8) ||
116 ((dirent->rec_len % 4) != 0) ||
117 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
118 fd->err = EXT2_ET_DIR_CORRUPTED;
119 return BLOCK_ABORT;
120 }
121 dir_offset += dirent->rec_len;
122 if (dirent->inode == 0)
123 continue;
124 if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
125 (dirent->name[0] == '.'))
126 continue;
127 if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
128 (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
129 fd->parent = dirent->inode;
130 continue;
131 }
132 if (fd->num_array >= fd->max_array) {
133 new_array = realloc(fd->harray,
134 sizeof(struct hash_entry) * (fd->max_array+500));
135 if (!new_array) {
136 fd->err = ENOMEM;
137 return BLOCK_ABORT;
138 }
139 fd->harray = new_array;
140 fd->max_array += 500;
141 }
142 ent = fd->harray + fd->num_array++;
143 ent->dir = dirent;
144 fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
145 if (fd->compress)
146 ent->hash = ent->minor_hash = 0;
147 else {
148 fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
149 dirent->name,
150 dirent->name_len & 0xFF,
151 fs->super->s_hash_seed,
152 &ent->hash, &ent->minor_hash);
153 if (fd->err)
154 return BLOCK_ABORT;
155 }
156 }
157
158 return 0;
159}
160
161/* Used for sorting the hash entry */
162static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
163{
164 const struct hash_entry *he_a = (const struct hash_entry *) a;
165 const struct hash_entry *he_b = (const struct hash_entry *) b;
166 int ret;
167 int min_len;
168
169 min_len = he_a->dir->name_len;
170 if (min_len > he_b->dir->name_len)
171 min_len = he_b->dir->name_len;
172
173 ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
174 if (ret == 0) {
175 if (he_a->dir->name_len > he_b->dir->name_len)
176 ret = 1;
177 else if (he_a->dir->name_len < he_b->dir->name_len)
178 ret = -1;
179 else
180 ret = he_b->dir->inode - he_a->dir->inode;
181 }
182 return ret;
183}
184
185/* Used for sorting the hash entry */
186static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
187{
188 const struct hash_entry *he_a = (const struct hash_entry *) a;
189 const struct hash_entry *he_b = (const struct hash_entry *) b;
190 int ret;
191
192 if (he_a->hash > he_b->hash)
193 ret = 1;
194 else if (he_a->hash < he_b->hash)
195 ret = -1;
196 else {
197 if (he_a->minor_hash > he_b->minor_hash)
198 ret = 1;
199 else if (he_a->minor_hash < he_b->minor_hash)
200 ret = -1;
201 else
202 ret = name_cmp(a, b);
203 }
204 return ret;
205}
206
207static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir,
208 int blocks)
209{
210 void *new_mem;
211
212 if (outdir->max) {
213 new_mem = realloc(outdir->buf, blocks * fs->blocksize);
214 if (!new_mem)
215 return ENOMEM;
216 outdir->buf = new_mem;
217 new_mem = realloc(outdir->hashes,
218 blocks * sizeof(ext2_dirhash_t));
219 if (!new_mem)
220 return ENOMEM;
221 outdir->hashes = new_mem;
222 } else {
223 outdir->buf = malloc(blocks * fs->blocksize);
224 outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
225 outdir->num = 0;
226 }
227 outdir->max = blocks;
228 return 0;
229}
230
231static void free_out_dir(struct out_dir *outdir)
232{
233 if (outdir->buf)
234 free(outdir->buf);
235 if (outdir->hashes)
236 free(outdir->hashes);
237 outdir->max = 0;
238 outdir->num =0;
239}
240
241static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
242 char ** ret)
243{
244 errcode_t retval;
245
246 if (outdir->num >= outdir->max) {
247 retval = alloc_size_dir(fs, outdir, outdir->max + 50);
248 if (retval)
249 return retval;
250 }
251 *ret = outdir->buf + (outdir->num++ * fs->blocksize);
252 memset(*ret, 0, fs->blocksize);
253 return 0;
254}
255
256/*
257 * This function is used to make a unique filename. We do this by
258 * appending ~0, and then incrementing the number. However, we cannot
259 * expand the length of the filename beyond the padding available in
260 * the directory entry.
261 */
262static void mutate_name(char *str, __u16 *len)
263{
264 int i;
265 __u16 l = *len & 0xFF, h = *len & 0xff00;
266
267 /*
268 * First check to see if it looks the name has been mutated
269 * already
270 */
271 for (i = l-1; i > 0; i--) {
272 if (!isdigit(str[i]))
273 break;
274 }
275 if ((i == l-1) || (str[i] != '~')) {
276 if (((l-1) & 3) < 2)
277 l += 2;
278 else
279 l = (l+3) & ~3;
280 str[l-2] = '~';
281 str[l-1] = '0';
282 *len = l | h;
283 return;
284 }
285 for (i = l-1; i >= 0; i--) {
286 if (isdigit(str[i])) {
287 if (str[i] == '9')
288 str[i] = '0';
289 else {
290 str[i]++;
291 return;
292 }
293 continue;
294 }
295 if (i == 1) {
296 if (str[0] == 'z')
297 str[0] = 'A';
298 else if (str[0] == 'Z') {
299 str[0] = '~';
300 str[1] = '0';
301 } else
302 str[0]++;
303 } else if (i > 0) {
304 str[i] = '1';
305 str[i-1] = '~';
306 } else {
307 if (str[0] == '~')
308 str[0] = 'a';
309 else
310 str[0]++;
311 }
312 break;
313 }
314}
315
316static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
317 ext2_ino_t ino,
318 struct fill_dir_struct *fd)
319{
320 struct problem_context pctx;
321 struct hash_entry *ent, *prev;
322 int i, j;
323 int fixed = 0;
324 char new_name[256];
325 __u16 new_len;
326
327 clear_problem_context(&pctx);
328 pctx.ino = ino;
329
330 for (i=1; i < fd->num_array; i++) {
331 ent = fd->harray + i;
332 prev = ent - 1;
333 if (!ent->dir->inode ||
334 ((ent->dir->name_len & 0xFF) !=
335 (prev->dir->name_len & 0xFF)) ||
336 (strncmp(ent->dir->name, prev->dir->name,
337 ent->dir->name_len & 0xFF)))
338 continue;
339 pctx.dirent = ent->dir;
340 if ((ent->dir->inode == prev->dir->inode) &&
341 fix_problem(ctx, PR_2_DUPLICATE_DIRENT, &pctx)) {
342 e2fsck_adjust_inode_count(ctx, ent->dir->inode, -1);
343 ent->dir->inode = 0;
344 fixed++;
345 continue;
346 }
347 memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
348 new_len = ent->dir->name_len;
349 mutate_name(new_name, &new_len);
350 for (j=0; j < fd->num_array; j++) {
351 if ((i==j) ||
352 ((ent->dir->name_len & 0xFF) !=
353 (fd->harray[j].dir->name_len & 0xFF)) ||
354 (strncmp(new_name, fd->harray[j].dir->name,
355 new_len & 0xFF)))
356 continue;
357 mutate_name(new_name, &new_len);
358
359 j = -1;
360 }
361 new_name[new_len & 0xFF] = 0;
362 pctx.str = new_name;
363 if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
364 memcpy(ent->dir->name, new_name, new_len & 0xFF);
365 ent->dir->name_len = new_len;
366 ext2fs_dirhash(fs->super->s_def_hash_version,
367 ent->dir->name,
368 ent->dir->name_len & 0xFF,
369 fs->super->s_hash_seed,
370 &ent->hash, &ent->minor_hash);
371 fixed++;
372 }
373 }
374 return fixed;
375}
376
377
378static errcode_t copy_dir_entries(ext2_filsys fs,
379 struct fill_dir_struct *fd,
380 struct out_dir *outdir)
381{
382 errcode_t retval;
383 char *block_start;
384 struct hash_entry *ent;
385 struct ext2_dir_entry *dirent;
386 int i, rec_len, left;
387 ext2_dirhash_t prev_hash;
388 int offset;
389
390 outdir->max = 0;
391 retval = alloc_size_dir(fs, outdir,
392 (fd->dir_size / fs->blocksize) + 2);
393 if (retval)
394 return retval;
395 outdir->num = fd->compress ? 0 : 1;
396 offset = 0;
397 outdir->hashes[0] = 0;
398 prev_hash = 1;
399 if ((retval = get_next_block(fs, outdir, &block_start)))
400 return retval;
401 dirent = (struct ext2_dir_entry *) block_start;
402 left = fs->blocksize;
403 for (i=0; i < fd->num_array; i++) {
404 ent = fd->harray + i;
405 if (ent->dir->inode == 0)
406 continue;
407 rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
408 if (rec_len > left) {
409 if (left)
410 dirent->rec_len += left;
411 if ((retval = get_next_block(fs, outdir,
412 &block_start)))
413 return retval;
414 offset = 0;
415 }
416 left = fs->blocksize - offset;
417 dirent = (struct ext2_dir_entry *) (block_start + offset);
418 if (offset == 0) {
419 if (ent->hash == prev_hash)
420 outdir->hashes[outdir->num-1] = ent->hash | 1;
421 else
422 outdir->hashes[outdir->num-1] = ent->hash;
423 }
424 dirent->inode = ent->dir->inode;
425 dirent->name_len = ent->dir->name_len;
426 dirent->rec_len = rec_len;
427 memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
428 offset += rec_len;
429 left -= rec_len;
430 if (left < 12) {
431 dirent->rec_len += left;
432 offset += left;
433 left = 0;
434 }
435 prev_hash = ent->hash;
436 }
437 if (left)
438 dirent->rec_len += left;
439
440 return 0;
441}
442
443
444static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
445 ext2_ino_t ino, ext2_ino_t parent)
446{
447 struct ext2_dir_entry *dir;
448 struct ext2_dx_root_info *root;
449 struct ext2_dx_countlimit *limits;
450 int filetype = 0;
451
452 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
453 filetype = EXT2_FT_DIR << 8;
454
455 memset(buf, 0, fs->blocksize);
456 dir = (struct ext2_dir_entry *) buf;
457 dir->inode = ino;
458 dir->name[0] = '.';
459 dir->name_len = 1 | filetype;
460 dir->rec_len = 12;
461 dir = (struct ext2_dir_entry *) (buf + 12);
462 dir->inode = parent;
463 dir->name[0] = '.';
464 dir->name[1] = '.';
465 dir->name_len = 2 | filetype;
466 dir->rec_len = fs->blocksize - 12;
467
468 root = (struct ext2_dx_root_info *) (buf+24);
469 root->reserved_zero = 0;
470 root->hash_version = fs->super->s_def_hash_version;
471 root->info_length = 8;
472 root->indirect_levels = 0;
473 root->unused_flags = 0;
474
475 limits = (struct ext2_dx_countlimit *) (buf+32);
476 limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
477 limits->count = 0;
478
479 return root;
480}
481
482
483static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
484{
485 struct ext2_dir_entry *dir;
486 struct ext2_dx_countlimit *limits;
487
488 memset(buf, 0, fs->blocksize);
489 dir = (struct ext2_dir_entry *) buf;
490 dir->inode = 0;
491 dir->rec_len = fs->blocksize;
492
493 limits = (struct ext2_dx_countlimit *) (buf+8);
494 limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
495 limits->count = 0;
496
497 return (struct ext2_dx_entry *) limits;
498}
499
500/*
501 * This function takes the leaf nodes which have been written in
502 * outdir, and populates the root node and any necessary interior nodes.
503 */
504static errcode_t calculate_tree(ext2_filsys fs,
505 struct out_dir *outdir,
506 ext2_ino_t ino,
507 ext2_ino_t parent)
508{
509 struct ext2_dx_root_info *root_info;
510 struct ext2_dx_entry *root, *dx_ent = 0;
511 struct ext2_dx_countlimit *root_limit, *limit;
512 errcode_t retval;
513 char * block_start;
514 int i, c1, c2, nblks;
515 int limit_offset, root_offset;
516
517 root_info = set_root_node(fs, outdir->buf, ino, parent);
518 root_offset = limit_offset = ((char *) root_info - outdir->buf) +
519 root_info->info_length;
520 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
521 c1 = root_limit->limit;
522 nblks = outdir->num;
523
524 /* Write out the pointer blocks */
525 if (nblks-1 <= c1) {
526 /* Just write out the root block, and we're done */
527 root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
528 for (i=1; i < nblks; i++) {
529 root->block = ext2fs_cpu_to_le32(i);
530 if (i != 1)
531 root->hash =
532 ext2fs_cpu_to_le32(outdir->hashes[i]);
533 root++;
534 c1--;
535 }
536 } else {
537 c2 = 0;
538 limit = 0;
539 root_info->indirect_levels = 1;
540 for (i=1; i < nblks; i++) {
541 if (c1 == 0)
542 return ENOSPC;
543 if (c2 == 0) {
544 if (limit)
545 limit->limit = limit->count =
546 ext2fs_cpu_to_le16(limit->limit);
547 root = (struct ext2_dx_entry *)
548 (outdir->buf + root_offset);
549 root->block = ext2fs_cpu_to_le32(outdir->num);
550 if (i != 1)
551 root->hash =
552 ext2fs_cpu_to_le32(outdir->hashes[i]);
553 if ((retval = get_next_block(fs, outdir,
554 &block_start)))
555 return retval;
556 dx_ent = set_int_node(fs, block_start);
557 limit = (struct ext2_dx_countlimit *) dx_ent;
558 c2 = limit->limit;
559 root_offset += sizeof(struct ext2_dx_entry);
560 c1--;
561 }
562 dx_ent->block = ext2fs_cpu_to_le32(i);
563 if (c2 != limit->limit)
564 dx_ent->hash =
565 ext2fs_cpu_to_le32(outdir->hashes[i]);
566 dx_ent++;
567 c2--;
568 }
569 limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
570 limit->limit = ext2fs_cpu_to_le16(limit->limit);
571 }
572 root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
573 root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
574 root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
575
576 return 0;
577}
578
579struct write_dir_struct {
580 struct out_dir *outdir;
581 errcode_t err;
582 e2fsck_t ctx;
583 int cleared;
584};
585
586/*
587 * Helper function which writes out a directory block.
588 */
589static int write_dir_block(ext2_filsys fs,
590 blk_t *block_nr,
591 e2_blkcnt_t blockcnt,
592 blk_t ref_block EXT2FS_ATTR((unused)),
593 int ref_offset EXT2FS_ATTR((unused)),
594 void *priv_data)
595{
596 struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
597 blk_t blk;
598 char *dir;
599
600 if (*block_nr == 0)
601 return 0;
602 if (blockcnt >= wd->outdir->num) {
603 e2fsck_read_bitmaps(wd->ctx);
604 blk = *block_nr;
605 ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
606 ext2fs_block_alloc_stats(fs, blk, -1);
607 *block_nr = 0;
608 wd->cleared++;
609 return BLOCK_CHANGED;
610 }
611 if (blockcnt < 0)
612 return 0;
613
614 dir = wd->outdir->buf + (blockcnt * fs->blocksize);
615 wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
616 if (wd->err)
617 return BLOCK_ABORT;
618 return 0;
619}
620
621static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
622 struct out_dir *outdir,
623 ext2_ino_t ino, int compress)
624{
625 struct write_dir_struct wd;
626 errcode_t retval;
627 struct ext2_inode inode;
628
629 retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
630 if (retval)
631 return retval;
632
633 wd.outdir = outdir;
634 wd.err = 0;
635 wd.ctx = ctx;
636 wd.cleared = 0;
637
638 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
639 write_dir_block, &wd);
640 if (retval)
641 return retval;
642 if (wd.err)
643 return wd.err;
644
645 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
646 if (compress)
647 inode.i_flags &= ~EXT2_INDEX_FL;
648 else
649 inode.i_flags |= EXT2_INDEX_FL;
650 inode.i_size = outdir->num * fs->blocksize;
651 inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
652 e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
653
654 return 0;
655}
656
657errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
658{
659 ext2_filsys fs = ctx->fs;
660 errcode_t retval;
661 struct ext2_inode inode;
662 char *dir_buf = 0;
663 struct fill_dir_struct fd;
664 struct out_dir outdir;
665
666 outdir.max = outdir.num = 0;
667 outdir.buf = 0;
668 outdir.hashes = 0;
669 e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
670
671 retval = ENOMEM;
672 fd.harray = 0;
673 dir_buf = malloc(inode.i_size);
674 if (!dir_buf)
675 goto errout;
676
677 fd.max_array = inode.i_size / 32;
678 fd.num_array = 0;
679 fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
680 if (!fd.harray)
681 goto errout;
682
683 fd.ctx = ctx;
684 fd.buf = dir_buf;
685 fd.inode = &inode;
686 fd.err = 0;
687 fd.dir_size = 0;
688 fd.compress = 0;
689 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
690 (inode.i_size / fs->blocksize) < 2)
691 fd.compress = 1;
692 fd.parent = 0;
693
694 /* Read in the entire directory into memory */
695 retval = ext2fs_block_iterate2(fs, ino, 0, 0,
696 fill_dir_block, &fd);
697 if (fd.err) {
698 retval = fd.err;
699 goto errout;
700 }
701
702#if 0
703 printf("%d entries (%d bytes) found in inode %d\n",
704 fd.num_array, fd.dir_size, ino);
705#endif
706
707 /* Sort the list */
708resort:
709 if (fd.compress)
710 qsort(fd.harray+2, fd.num_array-2,
711 sizeof(struct hash_entry), name_cmp);
712 else
713 qsort(fd.harray, fd.num_array,
714 sizeof(struct hash_entry), hash_cmp);
715
716 /*
717 * Look for duplicates
718 */
719 if (duplicate_search_and_fix(ctx, fs, ino, &fd))
720 goto resort;
721
722 if (ctx->options & E2F_OPT_NO) {
723 retval = 0;
724 goto errout;
725 }
726
727 /*
728 * Copy the directory entries. In a htree directory these
729 * will become the leaf nodes.
730 */
731 retval = copy_dir_entries(fs, &fd, &outdir);
732 if (retval)
733 goto errout;
734
735 free(dir_buf); dir_buf = 0;
736
737 if (!fd.compress) {
738 /* Calculate the interior nodes */
739 retval = calculate_tree(fs, &outdir, ino, fd.parent);
740 if (retval)
741 goto errout;
742 }
743
744 retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
745 if (retval)
746 goto errout;
747
748errout:
749 if (dir_buf)
750 free(dir_buf);
751 if (fd.harray)
752 free(fd.harray);
753
754 free_out_dir(&outdir);
755 return retval;
756}
757
758void e2fsck_rehash_directories(e2fsck_t ctx)
759{
760 struct problem_context pctx;
761#ifdef RESOURCE_TRACK
762 struct resource_track rtrack;
763#endif
764 struct dir_info *dir;
765 ext2_u32_iterate iter;
766 ext2_ino_t ino;
767 errcode_t retval;
768 int i, cur, max, all_dirs, dir_index, first = 1;
769
770#ifdef RESOURCE_TRACK
771 init_resource_track(&rtrack);
772#endif
773
774 all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS;
775
776 if (!ctx->dirs_to_hash && !all_dirs)
777 return;
778
779 e2fsck_get_lost_and_found(ctx, 0);
780
781 clear_problem_context(&pctx);
782
783 dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX;
784 cur = 0;
785 if (all_dirs) {
786 i = 0;
787 max = e2fsck_get_num_dirinfo(ctx);
788 } else {
789 retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash,
790 &iter);
791 if (retval) {
792 pctx.errcode = retval;
793 fix_problem(ctx, PR_3A_OPTIMIZE_ITER, &pctx);
794 return;
795 }
796 max = ext2fs_u32_list_count(ctx->dirs_to_hash);
797 }
798 while (1) {
799 if (all_dirs) {
800 if ((dir = e2fsck_dir_info_iter(ctx, &i)) == 0)
801 break;
802 ino = dir->ino;
803 } else {
804 if (!ext2fs_u32_list_iterate(iter, &ino))
805 break;
806 }
807 if (ino == ctx->lost_and_found)
808 continue;
809 pctx.dir = ino;
810 if (first) {
811 fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
812 first = 0;
813 }
814#if 0
815 fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
816#endif
817 pctx.errcode = e2fsck_rehash_dir(ctx, ino);
818 if (pctx.errcode) {
819 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
820 fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
821 }
822 if (ctx->progress && !ctx->progress_fd)
823 e2fsck_simple_progress(ctx, "Rebuilding directory",
824 100.0 * (float) (++cur) / (float) max, ino);
825 }
826 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
827 if (!all_dirs)
828 ext2fs_u32_list_iterate_end(iter);
829
830 if (ctx->dirs_to_hash)
831 ext2fs_u32_list_free(ctx->dirs_to_hash);
832 ctx->dirs_to_hash = 0;
833
834#ifdef RESOURCE_TRACK
835 if (ctx->options & E2F_OPT_TIME2) {
836 e2fsck_clear_progbar(ctx);
837 print_resource_track("Pass 3A", &rtrack);
838 }
839#endif
840}
diff --git a/e2fsprogs/e2fsck/revoke.c b/e2fsprogs/e2fsck/revoke.c
deleted file mode 100644
index 388bf5b5d..000000000
--- a/e2fsprogs/e2fsck/revoke.c
+++ /dev/null
@@ -1,640 +0,0 @@
1/*
2 * linux/fs/revoke.c
3 *
4 * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
5 *
6 * Copyright 2000 Red Hat corp --- All Rights Reserved
7 *
8 * This file is part of the Linux kernel and is made available under
9 * the terms of the GNU General Public License, version 2, or at your
10 * option, any later version, incorporated herein by reference.
11 *
12 * Journal revoke routines for the generic filesystem journaling code;
13 * part of the ext2fs journaling system.
14 *
15 * Revoke is the mechanism used to prevent old log records for deleted
16 * metadata from being replayed on top of newer data using the same
17 * blocks. The revoke mechanism is used in two separate places:
18 *
19 * + Commit: during commit we write the entire list of the current
20 * transaction's revoked blocks to the journal
21 *
22 * + Recovery: during recovery we record the transaction ID of all
23 * revoked blocks. If there are multiple revoke records in the log
24 * for a single block, only the last one counts, and if there is a log
25 * entry for a block beyond the last revoke, then that log entry still
26 * gets replayed.
27 *
28 * We can get interactions between revokes and new log data within a
29 * single transaction:
30 *
31 * Block is revoked and then journaled:
32 * The desired end result is the journaling of the new block, so we
33 * cancel the revoke before the transaction commits.
34 *
35 * Block is journaled and then revoked:
36 * The revoke must take precedence over the write of the block, so we
37 * need either to cancel the journal entry or to write the revoke
38 * later in the log than the log block. In this case, we choose the
39 * latter: journaling a block cancels any revoke record for that block
40 * in the current transaction, so any revoke for that block in the
41 * transaction must have happened after the block was journaled and so
42 * the revoke must take precedence.
43 *
44 * Block is revoked and then written as data:
45 * The data write is allowed to succeed, but the revoke is _not_
46 * cancelled. We still need to prevent old log records from
47 * overwriting the new data. We don't even need to clear the revoke
48 * bit here.
49 *
50 * Revoke information on buffers is a tri-state value:
51 *
52 * RevokeValid clear: no cached revoke status, need to look it up
53 * RevokeValid set, Revoked clear:
54 * buffer has not been revoked, and cancel_revoke
55 * need do nothing.
56 * RevokeValid set, Revoked set:
57 * buffer has been revoked.
58 */
59
60#ifndef __KERNEL__
61#include "jfs_user.h"
62#else
63#include <linux/sched.h>
64#include <linux/fs.h>
65#include <linux/jbd.h>
66#include <linux/errno.h>
67#include <linux/slab.h>
68#include <linux/locks.h>
69#include <linux/list.h>
70#include <linux/smp_lock.h>
71#include <linux/init.h>
72#endif
73
74static kmem_cache_t *revoke_record_cache;
75static kmem_cache_t *revoke_table_cache;
76
77/* Each revoke record represents one single revoked block. During
78 journal replay, this involves recording the transaction ID of the
79 last transaction to revoke this block. */
80
81struct jbd_revoke_record_s
82{
83 struct list_head hash;
84 tid_t sequence; /* Used for recovery only */
85 unsigned long blocknr;
86};
87
88
89/* The revoke table is just a simple hash table of revoke records. */
90struct jbd_revoke_table_s
91{
92 /* It is conceivable that we might want a larger hash table
93 * for recovery. Must be a power of two. */
94 int hash_size;
95 int hash_shift;
96 struct list_head *hash_table;
97};
98
99
100#ifdef __KERNEL__
101static void write_one_revoke_record(journal_t *, transaction_t *,
102 struct journal_head **, int *,
103 struct jbd_revoke_record_s *);
104static void flush_descriptor(journal_t *, struct journal_head *, int);
105#endif
106
107/* Utility functions to maintain the revoke table */
108
109/* Borrowed from buffer.c: this is a tried and tested block hash function */
110static inline int hash(journal_t *journal, unsigned long block)
111{
112 struct jbd_revoke_table_s *table = journal->j_revoke;
113 int hash_shift = table->hash_shift;
114
115 return ((block << (hash_shift - 6)) ^
116 (block >> 13) ^
117 (block << (hash_shift - 12))) & (table->hash_size - 1);
118}
119
120static int insert_revoke_hash(journal_t *journal, unsigned long blocknr,
121 tid_t seq)
122{
123 struct list_head *hash_list;
124 struct jbd_revoke_record_s *record;
125
126#ifdef __KERNEL__
127repeat:
128#endif
129 record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS);
130 if (!record)
131 goto oom;
132
133 record->sequence = seq;
134 record->blocknr = blocknr;
135 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
136 list_add(&record->hash, hash_list);
137 return 0;
138
139oom:
140#ifdef __KERNEL__
141 if (!journal_oom_retry)
142 return -ENOMEM;
143 jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n");
144 current->policy |= SCHED_YIELD;
145 schedule();
146 goto repeat;
147#else
148 return -ENOMEM;
149#endif
150}
151
152/* Find a revoke record in the journal's hash table. */
153
154static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
155 unsigned long blocknr)
156{
157 struct list_head *hash_list;
158 struct jbd_revoke_record_s *record;
159
160 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
161
162 record = (struct jbd_revoke_record_s *) hash_list->next;
163 while (&(record->hash) != hash_list) {
164 if (record->blocknr == blocknr)
165 return record;
166 record = (struct jbd_revoke_record_s *) record->hash.next;
167 }
168 return NULL;
169}
170
171int __init journal_init_revoke_caches(void)
172{
173 revoke_record_cache = kmem_cache_create("revoke_record",
174 sizeof(struct jbd_revoke_record_s),
175 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
176 if (revoke_record_cache == 0)
177 return -ENOMEM;
178
179 revoke_table_cache = kmem_cache_create("revoke_table",
180 sizeof(struct jbd_revoke_table_s),
181 0, 0, NULL, NULL);
182 if (revoke_table_cache == 0) {
183 kmem_cache_destroy(revoke_record_cache);
184 revoke_record_cache = NULL;
185 return -ENOMEM;
186 }
187 return 0;
188}
189
190void journal_destroy_revoke_caches(void)
191{
192 kmem_cache_destroy(revoke_record_cache);
193 revoke_record_cache = 0;
194 kmem_cache_destroy(revoke_table_cache);
195 revoke_table_cache = 0;
196}
197
198/* Initialise the revoke table for a given journal to a given size. */
199
200int journal_init_revoke(journal_t *journal, int hash_size)
201{
202 int shift, tmp;
203
204 J_ASSERT (journal->j_revoke == NULL);
205
206 journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
207 if (!journal->j_revoke)
208 return -ENOMEM;
209
210 /* Check that the hash_size is a power of two */
211 J_ASSERT ((hash_size & (hash_size-1)) == 0);
212
213 journal->j_revoke->hash_size = hash_size;
214
215 shift = 0;
216 tmp = hash_size;
217 while((tmp >>= 1UL) != 0UL)
218 shift++;
219 journal->j_revoke->hash_shift = shift;
220
221 journal->j_revoke->hash_table =
222 kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
223 if (!journal->j_revoke->hash_table) {
224 kmem_cache_free(revoke_table_cache, journal->j_revoke);
225 journal->j_revoke = NULL;
226 return -ENOMEM;
227 }
228
229 for (tmp = 0; tmp < hash_size; tmp++)
230 INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
231
232 return 0;
233}
234
235/* Destoy a journal's revoke table. The table must already be empty! */
236
237void journal_destroy_revoke(journal_t *journal)
238{
239 struct jbd_revoke_table_s *table;
240 struct list_head *hash_list;
241 int i;
242
243 table = journal->j_revoke;
244 if (!table)
245 return;
246
247 for (i=0; i<table->hash_size; i++) {
248 hash_list = &table->hash_table[i];
249 J_ASSERT (list_empty(hash_list));
250 }
251
252 kfree(table->hash_table);
253 kmem_cache_free(revoke_table_cache, table);
254 journal->j_revoke = NULL;
255}
256
257
258#ifdef __KERNEL__
259
260/*
261 * journal_revoke: revoke a given buffer_head from the journal. This
262 * prevents the block from being replayed during recovery if we take a
263 * crash after this current transaction commits. Any subsequent
264 * metadata writes of the buffer in this transaction cancel the
265 * revoke.
266 *
267 * Note that this call may block --- it is up to the caller to make
268 * sure that there are no further calls to journal_write_metadata
269 * before the revoke is complete. In ext3, this implies calling the
270 * revoke before clearing the block bitmap when we are deleting
271 * metadata.
272 *
273 * Revoke performs a journal_forget on any buffer_head passed in as a
274 * parameter, but does _not_ forget the buffer_head if the bh was only
275 * found implicitly.
276 *
277 * bh_in may not be a journalled buffer - it may have come off
278 * the hash tables without an attached journal_head.
279 *
280 * If bh_in is non-zero, journal_revoke() will decrement its b_count
281 * by one.
282 */
283
284int journal_revoke(handle_t *handle, unsigned long blocknr,
285 struct buffer_head *bh_in)
286{
287 struct buffer_head *bh = NULL;
288 journal_t *journal;
289 kdev_t dev;
290 int err;
291
292 if (bh_in)
293 BUFFER_TRACE(bh_in, "enter");
294
295 journal = handle->h_transaction->t_journal;
296 if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){
297 J_ASSERT (!"Cannot set revoke feature!");
298 return -EINVAL;
299 }
300
301 dev = journal->j_fs_dev;
302 bh = bh_in;
303
304 if (!bh) {
305 bh = get_hash_table(dev, blocknr, journal->j_blocksize);
306 if (bh)
307 BUFFER_TRACE(bh, "found on hash");
308 }
309#ifdef JBD_EXPENSIVE_CHECKING
310 else {
311 struct buffer_head *bh2;
312
313 /* If there is a different buffer_head lying around in
314 * memory anywhere... */
315 bh2 = get_hash_table(dev, blocknr, journal->j_blocksize);
316 if (bh2) {
317 /* ... and it has RevokeValid status... */
318 if ((bh2 != bh) &&
319 test_bit(BH_RevokeValid, &bh2->b_state))
320 /* ...then it better be revoked too,
321 * since it's illegal to create a revoke
322 * record against a buffer_head which is
323 * not marked revoked --- that would
324 * risk missing a subsequent revoke
325 * cancel. */
326 J_ASSERT_BH(bh2, test_bit(BH_Revoked, &
327 bh2->b_state));
328 __brelse(bh2);
329 }
330 }
331#endif
332
333 /* We really ought not ever to revoke twice in a row without
334 first having the revoke cancelled: it's illegal to free a
335 block twice without allocating it in between! */
336 if (bh) {
337 J_ASSERT_BH(bh, !test_bit(BH_Revoked, &bh->b_state));
338 set_bit(BH_Revoked, &bh->b_state);
339 set_bit(BH_RevokeValid, &bh->b_state);
340 if (bh_in) {
341 BUFFER_TRACE(bh_in, "call journal_forget");
342 journal_forget(handle, bh_in);
343 } else {
344 BUFFER_TRACE(bh, "call brelse");
345 __brelse(bh);
346 }
347 }
348
349 lock_journal(journal);
350 jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in);
351 err = insert_revoke_hash(journal, blocknr,
352 handle->h_transaction->t_tid);
353 unlock_journal(journal);
354 BUFFER_TRACE(bh_in, "exit");
355 return err;
356}
357
358/*
359 * Cancel an outstanding revoke. For use only internally by the
360 * journaling code (called from journal_get_write_access).
361 *
362 * We trust the BH_Revoked bit on the buffer if the buffer is already
363 * being journaled: if there is no revoke pending on the buffer, then we
364 * don't do anything here.
365 *
366 * This would break if it were possible for a buffer to be revoked and
367 * discarded, and then reallocated within the same transaction. In such
368 * a case we would have lost the revoked bit, but when we arrived here
369 * the second time we would still have a pending revoke to cancel. So,
370 * do not trust the Revoked bit on buffers unless RevokeValid is also
371 * set.
372 *
373 * The caller must have the journal locked.
374 */
375int journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
376{
377 struct jbd_revoke_record_s *record;
378 journal_t *journal = handle->h_transaction->t_journal;
379 int need_cancel;
380 int did_revoke = 0; /* akpm: debug */
381 struct buffer_head *bh = jh2bh(jh);
382
383 jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
384
385 /* Is the existing Revoke bit valid? If so, we trust it, and
386 * only perform the full cancel if the revoke bit is set. If
387 * not, we can't trust the revoke bit, and we need to do the
388 * full search for a revoke record. */
389 if (test_and_set_bit(BH_RevokeValid, &bh->b_state))
390 need_cancel = (test_and_clear_bit(BH_Revoked, &bh->b_state));
391 else {
392 need_cancel = 1;
393 clear_bit(BH_Revoked, &bh->b_state);
394 }
395
396 if (need_cancel) {
397 record = find_revoke_record(journal, bh->b_blocknr);
398 if (record) {
399 jbd_debug(4, "cancelled existing revoke on "
400 "blocknr %lu\n", bh->b_blocknr);
401 list_del(&record->hash);
402 kmem_cache_free(revoke_record_cache, record);
403 did_revoke = 1;
404 }
405 }
406
407#ifdef JBD_EXPENSIVE_CHECKING
408 /* There better not be one left behind by now! */
409 record = find_revoke_record(journal, bh->b_blocknr);
410 J_ASSERT_JH(jh, record == NULL);
411#endif
412
413 /* Finally, have we just cleared revoke on an unhashed
414 * buffer_head? If so, we'd better make sure we clear the
415 * revoked status on any hashed alias too, otherwise the revoke
416 * state machine will get very upset later on. */
417 if (need_cancel && !bh->b_pprev) {
418 struct buffer_head *bh2;
419 bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
420 if (bh2) {
421 clear_bit(BH_Revoked, &bh2->b_state);
422 __brelse(bh2);
423 }
424 }
425
426 return did_revoke;
427}
428
429
430/*
431 * Write revoke records to the journal for all entries in the current
432 * revoke hash, deleting the entries as we go.
433 *
434 * Called with the journal lock held.
435 */
436
437void journal_write_revoke_records(journal_t *journal,
438 transaction_t *transaction)
439{
440 struct journal_head *descriptor;
441 struct jbd_revoke_record_s *record;
442 struct jbd_revoke_table_s *revoke;
443 struct list_head *hash_list;
444 int i, offset, count;
445
446 descriptor = NULL;
447 offset = 0;
448 count = 0;
449 revoke = journal->j_revoke;
450
451 for (i = 0; i < revoke->hash_size; i++) {
452 hash_list = &revoke->hash_table[i];
453
454 while (!list_empty(hash_list)) {
455 record = (struct jbd_revoke_record_s *)
456 hash_list->next;
457 write_one_revoke_record(journal, transaction,
458 &descriptor, &offset,
459 record);
460 count++;
461 list_del(&record->hash);
462 kmem_cache_free(revoke_record_cache, record);
463 }
464 }
465 if (descriptor)
466 flush_descriptor(journal, descriptor, offset);
467 jbd_debug(1, "Wrote %d revoke records\n", count);
468}
469
470/*
471 * Write out one revoke record. We need to create a new descriptor
472 * block if the old one is full or if we have not already created one.
473 */
474
475static void write_one_revoke_record(journal_t *journal,
476 transaction_t *transaction,
477 struct journal_head **descriptorp,
478 int *offsetp,
479 struct jbd_revoke_record_s *record)
480{
481 struct journal_head *descriptor;
482 int offset;
483 journal_header_t *header;
484
485 /* If we are already aborting, this all becomes a noop. We
486 still need to go round the loop in
487 journal_write_revoke_records in order to free all of the
488 revoke records: only the IO to the journal is omitted. */
489 if (is_journal_aborted(journal))
490 return;
491
492 descriptor = *descriptorp;
493 offset = *offsetp;
494
495 /* Make sure we have a descriptor with space left for the record */
496 if (descriptor) {
497 if (offset == journal->j_blocksize) {
498 flush_descriptor(journal, descriptor, offset);
499 descriptor = NULL;
500 }
501 }
502
503 if (!descriptor) {
504 descriptor = journal_get_descriptor_buffer(journal);
505 if (!descriptor)
506 return;
507 header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
508 header->h_magic = htonl(JFS_MAGIC_NUMBER);
509 header->h_blocktype = htonl(JFS_REVOKE_BLOCK);
510 header->h_sequence = htonl(transaction->t_tid);
511
512 /* Record it so that we can wait for IO completion later */
513 JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");
514 journal_file_buffer(descriptor, transaction, BJ_LogCtl);
515
516 offset = sizeof(journal_revoke_header_t);
517 *descriptorp = descriptor;
518 }
519
520 * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) =
521 htonl(record->blocknr);
522 offset += 4;
523 *offsetp = offset;
524}
525
526/*
527 * Flush a revoke descriptor out to the journal. If we are aborting,
528 * this is a noop; otherwise we are generating a buffer which needs to
529 * be waited for during commit, so it has to go onto the appropriate
530 * journal buffer list.
531 */
532
533static void flush_descriptor(journal_t *journal,
534 struct journal_head *descriptor,
535 int offset)
536{
537 journal_revoke_header_t *header;
538
539 if (is_journal_aborted(journal)) {
540 JBUFFER_TRACE(descriptor, "brelse");
541 __brelse(jh2bh(descriptor));
542 return;
543 }
544
545 header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data;
546 header->r_count = htonl(offset);
547 set_bit(BH_JWrite, &jh2bh(descriptor)->b_state);
548 {
549 struct buffer_head *bh = jh2bh(descriptor);
550 BUFFER_TRACE(bh, "write");
551 ll_rw_block (WRITE, 1, &bh);
552 }
553}
554
555#endif
556
557/*
558 * Revoke support for recovery.
559 *
560 * Recovery needs to be able to:
561 *
562 * record all revoke records, including the tid of the latest instance
563 * of each revoke in the journal
564 *
565 * check whether a given block in a given transaction should be replayed
566 * (ie. has not been revoked by a revoke record in that or a subsequent
567 * transaction)
568 *
569 * empty the revoke table after recovery.
570 */
571
572/*
573 * First, setting revoke records. We create a new revoke record for
574 * every block ever revoked in the log as we scan it for recovery, and
575 * we update the existing records if we find multiple revokes for a
576 * single block.
577 */
578
579int journal_set_revoke(journal_t *journal,
580 unsigned long blocknr,
581 tid_t sequence)
582{
583 struct jbd_revoke_record_s *record;
584
585 record = find_revoke_record(journal, blocknr);
586 if (record) {
587 /* If we have multiple occurences, only record the
588 * latest sequence number in the hashed record */
589 if (tid_gt(sequence, record->sequence))
590 record->sequence = sequence;
591 return 0;
592 }
593 return insert_revoke_hash(journal, blocknr, sequence);
594}
595
596/*
597 * Test revoke records. For a given block referenced in the log, has
598 * that block been revoked? A revoke record with a given transaction
599 * sequence number revokes all blocks in that transaction and earlier
600 * ones, but later transactions still need replayed.
601 */
602
603int journal_test_revoke(journal_t *journal,
604 unsigned long blocknr,
605 tid_t sequence)
606{
607 struct jbd_revoke_record_s *record;
608
609 record = find_revoke_record(journal, blocknr);
610 if (!record)
611 return 0;
612 if (tid_gt(sequence, record->sequence))
613 return 0;
614 return 1;
615}
616
617/*
618 * Finally, once recovery is over, we need to clear the revoke table so
619 * that it can be reused by the running filesystem.
620 */
621
622void journal_clear_revoke(journal_t *journal)
623{
624 int i;
625 struct list_head *hash_list;
626 struct jbd_revoke_record_s *record;
627 struct jbd_revoke_table_s *revoke_var;
628
629 revoke_var = journal->j_revoke;
630
631 for (i = 0; i < revoke_var->hash_size; i++) {
632 hash_list = &revoke_var->hash_table[i];
633 while (!list_empty(hash_list)) {
634 record = (struct jbd_revoke_record_s*) hash_list->next;
635 list_del(&record->hash);
636 kmem_cache_free(revoke_record_cache, record);
637 }
638 }
639}
640
diff --git a/e2fsprogs/e2fsck/super.c b/e2fsprogs/e2fsck/super.c
deleted file mode 100644
index 294cd80e4..000000000
--- a/e2fsprogs/e2fsck/super.c
+++ /dev/null
@@ -1,713 +0,0 @@
1/*
2 * e2fsck.c - superblock checks
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#ifdef HAVE_ERRNO_H
13#include <errno.h>
14#endif
15
16#ifndef EXT2_SKIP_UUID
17#include "uuid/uuid.h"
18#endif
19#include "e2fsck.h"
20#include "problem.h"
21
22#define MIN_CHECK 1
23#define MAX_CHECK 2
24
25static void check_super_value(e2fsck_t ctx, const char *descr,
26 unsigned long value, int flags,
27 unsigned long min_val, unsigned long max_val)
28{
29 struct problem_context pctx;
30
31 if (((flags & MIN_CHECK) && (value < min_val)) ||
32 ((flags & MAX_CHECK) && (value > max_val))) {
33 clear_problem_context(&pctx);
34 pctx.num = value;
35 pctx.str = descr;
36 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
37 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
38 }
39}
40
41/*
42 * This routine may get stubbed out in special compilations of the
43 * e2fsck code..
44 */
45#ifndef EXT2_SPECIAL_DEVICE_SIZE
46errcode_t e2fsck_get_device_size(e2fsck_t ctx)
47{
48 return (ext2fs_get_device_size(ctx->filesystem_name,
49 EXT2_BLOCK_SIZE(ctx->fs->super),
50 &ctx->num_blocks));
51}
52#endif
53
54/*
55 * helper function to release an inode
56 */
57struct process_block_struct {
58 e2fsck_t ctx;
59 char *buf;
60 struct problem_context *pctx;
61 int truncating;
62 int truncate_offset;
63 e2_blkcnt_t truncate_block;
64 int truncated_blocks;
65 int abort;
66 errcode_t errcode;
67};
68
69static int release_inode_block(ext2_filsys fs,
70 blk_t *block_nr,
71 e2_blkcnt_t blockcnt,
72 blk_t ref_blk EXT2FS_ATTR((unused)),
73 int ref_offset EXT2FS_ATTR((unused)),
74 void *priv_data)
75{
76 struct process_block_struct *pb;
77 e2fsck_t ctx;
78 struct problem_context *pctx;
79 blk_t blk = *block_nr;
80 int retval = 0;
81
82 pb = (struct process_block_struct *) priv_data;
83 ctx = pb->ctx;
84 pctx = pb->pctx;
85
86 pctx->blk = blk;
87 pctx->blkcount = blockcnt;
88
89 if (HOLE_BLKADDR(blk))
90 return 0;
91
92 if ((blk < fs->super->s_first_data_block) ||
93 (blk >= fs->super->s_blocks_count)) {
94 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
95 return_abort:
96 pb->abort = 1;
97 return BLOCK_ABORT;
98 }
99
100 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
101 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
102 goto return_abort;
103 }
104
105 /*
106 * If we are deleting an orphan, then we leave the fields alone.
107 * If we are truncating an orphan, then update the inode fields
108 * and clean up any partial block data.
109 */
110 if (pb->truncating) {
111 /*
112 * We only remove indirect blocks if they are
113 * completely empty.
114 */
115 if (blockcnt < 0) {
116 int i, limit;
117 blk_t *bp;
118
119 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
120 pb->buf);
121 if (pb->errcode)
122 goto return_abort;
123
124 limit = fs->blocksize >> 2;
125 for (i = 0, bp = (blk_t *) pb->buf;
126 i < limit; i++, bp++)
127 if (*bp)
128 return 0;
129 }
130 /*
131 * We don't remove direct blocks until we've reached
132 * the truncation block.
133 */
134 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
135 return 0;
136 /*
137 * If part of the last block needs truncating, we do
138 * it here.
139 */
140 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
141 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
142 pb->buf);
143 if (pb->errcode)
144 goto return_abort;
145 memset(pb->buf + pb->truncate_offset, 0,
146 fs->blocksize - pb->truncate_offset);
147 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
148 pb->buf);
149 if (pb->errcode)
150 goto return_abort;
151 }
152 pb->truncated_blocks++;
153 *block_nr = 0;
154 retval |= BLOCK_CHANGED;
155 }
156
157 ext2fs_block_alloc_stats(fs, blk, -1);
158 return retval;
159}
160
161/*
162 * This function releases an inode. Returns 1 if an inconsistency was
163 * found. If the inode has a link count, then it is being truncated and
164 * not deleted.
165 */
166static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
167 struct ext2_inode *inode, char *block_buf,
168 struct problem_context *pctx)
169{
170 struct process_block_struct pb;
171 ext2_filsys fs = ctx->fs;
172 errcode_t retval;
173 __u32 count;
174
175 if (!ext2fs_inode_has_valid_blocks(inode))
176 return 0;
177
178 pb.buf = block_buf + 3 * ctx->fs->blocksize;
179 pb.ctx = ctx;
180 pb.abort = 0;
181 pb.errcode = 0;
182 pb.pctx = pctx;
183 if (inode->i_links_count) {
184 pb.truncating = 1;
185 pb.truncate_block = (e2_blkcnt_t)
186 ((((long long)inode->i_size_high << 32) +
187 inode->i_size + fs->blocksize - 1) /
188 fs->blocksize);
189 pb.truncate_offset = inode->i_size % fs->blocksize;
190 } else {
191 pb.truncating = 0;
192 pb.truncate_block = 0;
193 pb.truncate_offset = 0;
194 }
195 pb.truncated_blocks = 0;
196 retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
197 block_buf, release_inode_block, &pb);
198 if (retval) {
199 com_err("release_inode_blocks", retval,
200 _("while calling ext2fs_block_iterate for inode %d"),
201 ino);
202 return 1;
203 }
204 if (pb.abort)
205 return 1;
206
207 /* Refresh the inode since ext2fs_block_iterate may have changed it */
208 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
209
210 if (pb.truncated_blocks)
211 inode->i_blocks -= pb.truncated_blocks *
212 (fs->blocksize / 512);
213
214 if (inode->i_file_acl) {
215 retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl,
216 block_buf, -1, &count);
217 if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
218 retval = 0;
219 count = 1;
220 }
221 if (retval) {
222 com_err("release_inode_blocks", retval,
223 _("while calling ext2fs_adjust_ea_refocunt for inode %d"),
224 ino);
225 return 1;
226 }
227 if (count == 0)
228 ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
229 inode->i_file_acl = 0;
230 }
231 return 0;
232}
233
234/*
235 * This function releases all of the orphan inodes. It returns 1 if
236 * it hit some error, and 0 on success.
237 */
238static int release_orphan_inodes(e2fsck_t ctx)
239{
240 ext2_filsys fs = ctx->fs;
241 ext2_ino_t ino, next_ino;
242 struct ext2_inode inode;
243 struct problem_context pctx;
244 char *block_buf;
245
246 if ((ino = fs->super->s_last_orphan) == 0)
247 return 0;
248
249 /*
250 * Win or lose, we won't be using the head of the orphan inode
251 * list again.
252 */
253 fs->super->s_last_orphan = 0;
254 ext2fs_mark_super_dirty(fs);
255
256 /*
257 * If the filesystem contains errors, don't run the orphan
258 * list, since the orphan list can't be trusted; and we're
259 * going to be running a full e2fsck run anyway...
260 */
261 if (fs->super->s_state & EXT2_ERROR_FS)
262 return 0;
263
264 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
265 (ino > fs->super->s_inodes_count)) {
266 clear_problem_context(&pctx);
267 pctx.ino = ino;
268 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
269 return 1;
270 }
271
272 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
273 "block iterate buffer");
274 e2fsck_read_bitmaps(ctx);
275
276 while (ino) {
277 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
278 clear_problem_context(&pctx);
279 pctx.ino = ino;
280 pctx.inode = &inode;
281 pctx.str = inode.i_links_count ? _("Truncating") :
282 _("Clearing");
283
284 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
285
286 next_ino = inode.i_dtime;
287 if (next_ino &&
288 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
289 (next_ino > fs->super->s_inodes_count))) {
290 pctx.ino = next_ino;
291 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
292 goto return_abort;
293 }
294
295 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
296 goto return_abort;
297
298 if (!inode.i_links_count) {
299 ext2fs_inode_alloc_stats2(fs, ino, -1,
300 LINUX_S_ISDIR(inode.i_mode));
301 inode.i_dtime = time(0);
302 } else {
303 inode.i_dtime = 0;
304 }
305 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
306 ino = next_ino;
307 }
308 ext2fs_free_mem(&block_buf);
309 return 0;
310return_abort:
311 ext2fs_free_mem(&block_buf);
312 return 1;
313}
314
315/*
316 * Check the resize inode to make sure it is sane. We check both for
317 * the case where on-line resizing is not enabled (in which case the
318 * resize inode should be cleared) as well as the case where on-line
319 * resizing is enabled.
320 */
321void check_resize_inode(e2fsck_t ctx)
322{
323 ext2_filsys fs = ctx->fs;
324 struct ext2_inode inode;
325 struct problem_context pctx;
326 int i, j, gdt_off, ind_off;
327 blk_t blk, pblk, expect;
328 __u32 *dind_buf = 0, *ind_buf;
329 errcode_t retval;
330
331 clear_problem_context(&pctx);
332
333 /*
334 * If the resize inode feature isn't set, then
335 * s_reserved_gdt_blocks must be zero.
336 */
337 if (!(fs->super->s_feature_compat &
338 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
339 if (fs->super->s_reserved_gdt_blocks) {
340 pctx.num = fs->super->s_reserved_gdt_blocks;
341 if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS,
342 &pctx)) {
343 fs->super->s_reserved_gdt_blocks = 0;
344 ext2fs_mark_super_dirty(fs);
345 }
346 }
347 }
348
349 /* Read the resizde inode */
350 pctx.ino = EXT2_RESIZE_INO;
351 retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
352 if (retval) {
353 if (fs->super->s_feature_compat &
354 EXT2_FEATURE_COMPAT_RESIZE_INODE)
355 ctx->flags |= E2F_FLAG_RESIZE_INODE;
356 return;
357 }
358
359 /*
360 * If the resize inode feature isn't set, check to make sure
361 * the resize inode is cleared; then we're done.
362 */
363 if (!(fs->super->s_feature_compat &
364 EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
365 for (i=0; i < EXT2_N_BLOCKS; i++) {
366 if (inode.i_block[i])
367 break;
368 }
369 if ((i < EXT2_N_BLOCKS) &&
370 fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) {
371 memset(&inode, 0, sizeof(inode));
372 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
373 "clear_resize");
374 }
375 return;
376 }
377
378 /*
379 * The resize inode feature is enabled; check to make sure the
380 * only block in use is the double indirect block
381 */
382 blk = inode.i_block[EXT2_DIND_BLOCK];
383 for (i=0; i < EXT2_N_BLOCKS; i++) {
384 if (i != EXT2_DIND_BLOCK && inode.i_block[i])
385 break;
386 }
387 if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count ||
388 !(inode.i_mode & LINUX_S_IFREG) ||
389 (blk < fs->super->s_first_data_block ||
390 blk >= fs->super->s_blocks_count)) {
391 resize_inode_invalid:
392 if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) {
393 memset(&inode, 0, sizeof(inode));
394 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode,
395 "clear_resize");
396 ctx->flags |= E2F_FLAG_RESIZE_INODE;
397 }
398 if (!(ctx->options & E2F_OPT_READONLY)) {
399 fs->super->s_state &= ~EXT2_VALID_FS;
400 ext2fs_mark_super_dirty(fs);
401 }
402 goto cleanup;
403 }
404 dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2,
405 "resize dind buffer");
406 ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize);
407
408 retval = ext2fs_read_ind_block(fs, blk, dind_buf);
409 if (retval)
410 goto resize_inode_invalid;
411
412 gdt_off = fs->desc_blocks;
413 pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks;
414 for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4;
415 i++, gdt_off++, pblk++) {
416 gdt_off %= fs->blocksize/4;
417 if (dind_buf[gdt_off] != pblk)
418 goto resize_inode_invalid;
419 retval = ext2fs_read_ind_block(fs, pblk, ind_buf);
420 if (retval)
421 goto resize_inode_invalid;
422 ind_off = 0;
423 for (j = 1; j < fs->group_desc_count; j++) {
424 if (!ext2fs_bg_has_super(fs, j))
425 continue;
426 expect = pblk + (j * fs->super->s_blocks_per_group);
427 if (ind_buf[ind_off] != expect)
428 goto resize_inode_invalid;
429 ind_off++;
430 }
431 }
432
433cleanup:
434 if (dind_buf)
435 ext2fs_free_mem(&dind_buf);
436
437 }
438
439void check_super_block(e2fsck_t ctx)
440{
441 ext2_filsys fs = ctx->fs;
442 blk_t first_block, last_block;
443 struct ext2_super_block *sb = fs->super;
444 struct ext2_group_desc *gd;
445 blk_t blocks_per_group = fs->super->s_blocks_per_group;
446 blk_t bpg_max;
447 int inodes_per_block;
448 int ipg_max;
449 int inode_size;
450 dgrp_t i;
451 blk_t should_be;
452 struct problem_context pctx;
453 __u32 free_blocks = 0, free_inodes = 0;
454
455 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
456 ipg_max = inodes_per_block * (blocks_per_group - 4);
457 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
458 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
459 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
460 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
461 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
462
463 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
464 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
465 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
466 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
467 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
468 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
469
470 clear_problem_context(&pctx);
471
472 /*
473 * Verify the super block constants...
474 */
475 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
476 MIN_CHECK, 1, 0);
477 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
478 MIN_CHECK, 1, 0);
479 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
480 MAX_CHECK, 0, sb->s_blocks_count);
481 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
482 MIN_CHECK | MAX_CHECK, 0,
483 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
484 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
485 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
486 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
487 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
488 bpg_max);
489 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
490 MIN_CHECK | MAX_CHECK, 8, bpg_max);
491 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
492 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
493 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
494 MAX_CHECK, 0, sb->s_blocks_count / 2);
495 check_super_value(ctx, "reserved_gdt_blocks",
496 sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
497 fs->blocksize/4);
498 inode_size = EXT2_INODE_SIZE(sb);
499 check_super_value(ctx, "inode_size",
500 inode_size, MIN_CHECK | MAX_CHECK,
501 EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
502 if (inode_size & (inode_size - 1)) {
503 pctx.num = inode_size;
504 pctx.str = "inode_size";
505 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
506 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
507 return;
508 }
509
510 if (!ctx->num_blocks) {
511 pctx.errcode = e2fsck_get_device_size(ctx);
512 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
513 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
514 ctx->flags |= E2F_FLAG_ABORT;
515 return;
516 }
517 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
518 (ctx->num_blocks < sb->s_blocks_count)) {
519 pctx.blk = sb->s_blocks_count;
520 pctx.blk2 = ctx->num_blocks;
521 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
522 ctx->flags |= E2F_FLAG_ABORT;
523 return;
524 }
525 }
526 }
527
528 if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) {
529 pctx.blk = EXT2_BLOCK_SIZE(sb);
530 pctx.blk2 = EXT2_FRAG_SIZE(sb);
531 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
532 ctx->flags |= E2F_FLAG_ABORT;
533 return;
534 }
535
536 should_be = sb->s_frags_per_group >>
537 (sb->s_log_block_size - sb->s_log_frag_size);
538 if (sb->s_blocks_per_group != should_be) {
539 pctx.blk = sb->s_blocks_per_group;
540 pctx.blk2 = should_be;
541 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
542 ctx->flags |= E2F_FLAG_ABORT;
543 return;
544 }
545
546 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
547 if (sb->s_first_data_block != should_be) {
548 pctx.blk = sb->s_first_data_block;
549 pctx.blk2 = should_be;
550 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
551 ctx->flags |= E2F_FLAG_ABORT;
552 return;
553 }
554
555 should_be = sb->s_inodes_per_group * fs->group_desc_count;
556 if (sb->s_inodes_count != should_be) {
557 pctx.ino = sb->s_inodes_count;
558 pctx.ino2 = should_be;
559 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
560 sb->s_inodes_count = should_be;
561 ext2fs_mark_super_dirty(fs);
562 }
563 }
564
565 /*
566 * Verify the group descriptors....
567 */
568 first_block = sb->s_first_data_block;
569 last_block = first_block + blocks_per_group;
570
571 for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
572 pctx.group = i;
573
574 if (i == fs->group_desc_count - 1)
575 last_block = sb->s_blocks_count;
576 if ((gd->bg_block_bitmap < first_block) ||
577 (gd->bg_block_bitmap >= last_block)) {
578 pctx.blk = gd->bg_block_bitmap;
579 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
580 gd->bg_block_bitmap = 0;
581 }
582 if (gd->bg_block_bitmap == 0) {
583 ctx->invalid_block_bitmap_flag[i]++;
584 ctx->invalid_bitmaps++;
585 }
586 if ((gd->bg_inode_bitmap < first_block) ||
587 (gd->bg_inode_bitmap >= last_block)) {
588 pctx.blk = gd->bg_inode_bitmap;
589 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
590 gd->bg_inode_bitmap = 0;
591 }
592 if (gd->bg_inode_bitmap == 0) {
593 ctx->invalid_inode_bitmap_flag[i]++;
594 ctx->invalid_bitmaps++;
595 }
596 if ((gd->bg_inode_table < first_block) ||
597 ((gd->bg_inode_table +
598 fs->inode_blocks_per_group - 1) >= last_block)) {
599 pctx.blk = gd->bg_inode_table;
600 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
601 gd->bg_inode_table = 0;
602 }
603 if (gd->bg_inode_table == 0) {
604 ctx->invalid_inode_table_flag[i]++;
605 ctx->invalid_bitmaps++;
606 }
607 free_blocks += gd->bg_free_blocks_count;
608 free_inodes += gd->bg_free_inodes_count;
609 first_block += sb->s_blocks_per_group;
610 last_block += sb->s_blocks_per_group;
611
612 if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) ||
613 (gd->bg_free_inodes_count > sb->s_inodes_per_group) ||
614 (gd->bg_used_dirs_count > sb->s_inodes_per_group))
615 ext2fs_unmark_valid(fs);
616
617 }
618
619 /*
620 * Update the global counts from the block group counts. This
621 * is needed for an experimental patch which eliminates
622 * locking the entire filesystem when allocating blocks or
623 * inodes; if the filesystem is not unmounted cleanly, the
624 * global counts may not be accurate.
625 */
626 if ((free_blocks != sb->s_free_blocks_count) ||
627 (free_inodes != sb->s_free_inodes_count)) {
628 if (ctx->options & E2F_OPT_READONLY)
629 ext2fs_unmark_valid(fs);
630 else {
631 sb->s_free_blocks_count = free_blocks;
632 sb->s_free_inodes_count = free_inodes;
633 ext2fs_mark_super_dirty(fs);
634 }
635 }
636
637 if ((sb->s_free_blocks_count > sb->s_blocks_count) ||
638 (sb->s_free_inodes_count > sb->s_inodes_count))
639 ext2fs_unmark_valid(fs);
640
641
642 /*
643 * If we have invalid bitmaps, set the error state of the
644 * filesystem.
645 */
646 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
647 sb->s_state &= ~EXT2_VALID_FS;
648 ext2fs_mark_super_dirty(fs);
649 }
650
651 clear_problem_context(&pctx);
652
653#ifndef EXT2_SKIP_UUID
654 /*
655 * If the UUID field isn't assigned, assign it.
656 */
657 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
658 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
659 uuid_generate(sb->s_uuid);
660 ext2fs_mark_super_dirty(fs);
661 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
662 }
663 }
664#endif
665
666 /*
667 * For the Hurd, check to see if the filetype option is set,
668 * since it doesn't support it.
669 */
670 if (!(ctx->options & E2F_OPT_READONLY) &&
671 fs->super->s_creator_os == EXT2_OS_HURD &&
672 (fs->super->s_feature_incompat &
673 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
674 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
675 fs->super->s_feature_incompat &=
676 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
677 ext2fs_mark_super_dirty(fs);
678
679 }
680 }
681
682 /*
683 * If we have any of the compatibility flags set, we need to have a
684 * revision 1 filesystem. Most kernels will not check the flags on
685 * a rev 0 filesystem and we may have corruption issues because of
686 * the incompatible changes to the filesystem.
687 */
688 if (!(ctx->options & E2F_OPT_READONLY) &&
689 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
690 (fs->super->s_feature_compat ||
691 fs->super->s_feature_ro_compat ||
692 fs->super->s_feature_incompat) &&
693 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
694 ext2fs_update_dynamic_rev(fs);
695 ext2fs_mark_super_dirty(fs);
696 }
697
698 check_resize_inode(ctx);
699
700 /*
701 * Clean up any orphan inodes, if present.
702 */
703 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
704 fs->super->s_state &= ~EXT2_VALID_FS;
705 ext2fs_mark_super_dirty(fs);
706 }
707
708 /*
709 * Move the ext3 journal file, if necessary.
710 */
711 e2fsck_move_ext3_journal(ctx);
712 return;
713}
diff --git a/e2fsprogs/e2fsck/swapfs.c b/e2fsprogs/e2fsck/swapfs.c
deleted file mode 100644
index a737b9624..000000000
--- a/e2fsprogs/e2fsck/swapfs.c
+++ /dev/null
@@ -1,268 +0,0 @@
1/*
2 * swapfs.c --- byte-swap an ext2 filesystem
3 *
4 * Copyright 1996, 1997 by Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 *
11 */
12
13#ifdef HAVE_ERRNO_H
14#include <errno.h>
15#endif
16#include "e2fsck.h"
17
18#ifdef ENABLE_SWAPFS
19
20struct swap_block_struct {
21 ext2_ino_t ino;
22 int isdir;
23 errcode_t errcode;
24 char *dir_buf;
25 struct ext2_inode *inode;
26};
27
28/*
29 * This is a helper function for block_iterate. We mark all of the
30 * indirect and direct blocks as changed, so that block_iterate will
31 * write them out.
32 */
33static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
34 void *priv_data)
35{
36 errcode_t retval;
37
38 struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
39
40 if (sb->isdir && (blockcnt >= 0) && *block_nr) {
41 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
42 if (retval) {
43 sb->errcode = retval;
44 return BLOCK_ABORT;
45 }
46 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
47 if (retval) {
48 sb->errcode = retval;
49 return BLOCK_ABORT;
50 }
51 }
52 if (blockcnt >= 0) {
53 if (blockcnt < EXT2_NDIR_BLOCKS)
54 return 0;
55 return BLOCK_CHANGED;
56 }
57 if (blockcnt == BLOCK_COUNT_IND) {
58 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
59 return 0;
60 return BLOCK_CHANGED;
61 }
62 if (blockcnt == BLOCK_COUNT_DIND) {
63 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
64 return 0;
65 return BLOCK_CHANGED;
66 }
67 if (blockcnt == BLOCK_COUNT_TIND) {
68 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
69 return 0;
70 return BLOCK_CHANGED;
71 }
72 return BLOCK_CHANGED;
73}
74
75/*
76 * This function is responsible for byte-swapping all of the indirect,
77 * block pointers. It is also responsible for byte-swapping directories.
78 */
79static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
80 struct ext2_inode *inode)
81{
82 errcode_t retval;
83 struct swap_block_struct sb;
84
85 sb.ino = ino;
86 sb.inode = inode;
87 sb.dir_buf = block_buf + ctx->fs->blocksize*3;
88 sb.errcode = 0;
89 sb.isdir = 0;
90 if (LINUX_S_ISDIR(inode->i_mode))
91 sb.isdir = 1;
92
93 retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
94 swap_block, &sb);
95 if (retval) {
96 com_err("swap_inode_blocks", retval,
97 _("while calling ext2fs_block_iterate"));
98 ctx->flags |= E2F_FLAG_ABORT;
99 return;
100 }
101 if (sb.errcode) {
102 com_err("swap_inode_blocks", sb.errcode,
103 _("while calling iterator function"));
104 ctx->flags |= E2F_FLAG_ABORT;
105 return;
106 }
107}
108
109static void swap_inodes(e2fsck_t ctx)
110{
111 ext2_filsys fs = ctx->fs;
112 dgrp_t group;
113 unsigned int i;
114 ext2_ino_t ino = 1;
115 char *buf, *block_buf;
116 errcode_t retval;
117 struct ext2_inode * inode;
118
119 e2fsck_use_inode_shortcuts(ctx, 1);
120
121 retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
122 &buf);
123 if (retval) {
124 com_err("swap_inodes", retval,
125 _("while allocating inode buffer"));
126 ctx->flags |= E2F_FLAG_ABORT;
127 return;
128 }
129 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
130 "block interate buffer");
131 for (group = 0; group < fs->group_desc_count; group++) {
132 retval = io_channel_read_blk(fs->io,
133 fs->group_desc[group].bg_inode_table,
134 fs->inode_blocks_per_group, buf);
135 if (retval) {
136 com_err("swap_inodes", retval,
137 _("while reading inode table (group %d)"),
138 group);
139 ctx->flags |= E2F_FLAG_ABORT;
140 return;
141 }
142 inode = (struct ext2_inode *) buf;
143 for (i=0; i < fs->super->s_inodes_per_group;
144 i++, ino++, inode++) {
145 ctx->stashed_ino = ino;
146 ctx->stashed_inode = inode;
147
148 if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
149 ext2fs_swap_inode(fs, inode, inode, 0);
150
151 /*
152 * Skip deleted files.
153 */
154 if (inode->i_links_count == 0)
155 continue;
156
157 if (LINUX_S_ISDIR(inode->i_mode) ||
158 ((inode->i_block[EXT2_IND_BLOCK] ||
159 inode->i_block[EXT2_DIND_BLOCK] ||
160 inode->i_block[EXT2_TIND_BLOCK]) &&
161 ext2fs_inode_has_valid_blocks(inode)))
162 swap_inode_blocks(ctx, ino, block_buf, inode);
163
164 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
165 return;
166
167 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
168 ext2fs_swap_inode(fs, inode, inode, 1);
169 }
170 retval = io_channel_write_blk(fs->io,
171 fs->group_desc[group].bg_inode_table,
172 fs->inode_blocks_per_group, buf);
173 if (retval) {
174 com_err("swap_inodes", retval,
175 _("while writing inode table (group %d)"),
176 group);
177 ctx->flags |= E2F_FLAG_ABORT;
178 return;
179 }
180 }
181 ext2fs_free_mem(&buf);
182 ext2fs_free_mem(&block_buf);
183 e2fsck_use_inode_shortcuts(ctx, 0);
184 ext2fs_flush_icache(fs);
185}
186
187#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
188/*
189 * On the PowerPC, the big-endian variant of the ext2 filesystem
190 * has its bitmaps stored as 32-bit words with bit 0 as the LSB
191 * of each word. Thus a bitmap with only bit 0 set would be, as
192 * a string of bytes, 00 00 00 01 00 ...
193 * To cope with this, we byte-reverse each word of a bitmap if
194 * we have a big-endian filesystem, that is, if we are *not*
195 * byte-swapping other word-sized numbers.
196 */
197#define EXT2_BIG_ENDIAN_BITMAPS
198#endif
199
200#ifdef EXT2_BIG_ENDIAN_BITMAPS
201static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
202{
203 __u32 *p = (__u32 *) bmap->bitmap;
204 int n, nbytes = (bmap->end - bmap->start + 7) / 8;
205
206 for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
207 *p = ext2fs_swab32(*p);
208}
209#endif
210
211
212void swap_filesys(e2fsck_t ctx)
213{
214 ext2_filsys fs = ctx->fs;
215#ifdef RESOURCE_TRACK
216 struct resource_track rtrack;
217
218 init_resource_track(&rtrack);
219#endif
220
221 if (!(ctx->options & E2F_OPT_PREEN))
222 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
223
224#ifdef MTRACE
225 mtrace_print("Byte swap");
226#endif
227
228 if (fs->super->s_mnt_count) {
229 fprintf(stderr, _("%s: the filesystem must be freshly "
230 "checked using fsck\n"
231 "and not mounted before trying to "
232 "byte-swap it.\n"), ctx->device_name);
233 ctx->flags |= E2F_FLAG_ABORT;
234 return;
235 }
236 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
237 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
238 EXT2_FLAG_SWAP_BYTES_WRITE);
239 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
240 } else {
241 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
242 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
243 }
244 swap_inodes(ctx);
245 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
246 return;
247 if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
248 fs->flags |= EXT2_FLAG_SWAP_BYTES;
249 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
250 EXT2_FLAG_SWAP_BYTES_WRITE);
251
252#ifdef EXT2_BIG_ENDIAN_BITMAPS
253 e2fsck_read_bitmaps(ctx);
254 ext2fs_swap_bitmap(fs->inode_map);
255 ext2fs_swap_bitmap(fs->block_map);
256 fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
257#endif
258 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
259 ext2fs_flush(fs);
260 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
261
262#ifdef RESOURCE_TRACK
263 if (ctx->options & E2F_OPT_TIME2)
264 print_resource_track(_("Byte swap"), &rtrack);
265#endif
266}
267
268#endif
diff --git a/e2fsprogs/e2fsck/util.c b/e2fsprogs/e2fsck/util.c
deleted file mode 100644
index 311156e23..000000000
--- a/e2fsprogs/e2fsck/util.c
+++ /dev/null
@@ -1,503 +0,0 @@
1/*
2 * util.c --- miscellaneous utilities
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <ctype.h>
16
17#ifdef HAVE_CONIO_H
18#undef HAVE_TERMIOS_H
19#include <conio.h>
20#define read_a_char() getch()
21#else
22#ifdef HAVE_TERMIOS_H
23#include <termios.h>
24#endif
25#include <stdio.h>
26#endif
27
28#ifdef HAVE_MALLOC_H
29#include <malloc.h>
30#endif
31
32#include "e2fsck.h"
33
34extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
35
36#include <sys/time.h>
37#include <sys/resource.h>
38
39#if 0
40void fatal_error(e2fsck_t ctx, const char *msg)
41{
42 if (msg)
43 fprintf (stderr, "e2fsck: %s\n", msg);
44 if (ctx->fs && ctx->fs->io) {
45 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
46 io_channel_flush(ctx->fs->io);
47 else
48 fprintf(stderr, "e2fsck: io manager magic bad!\n");
49 }
50 ctx->flags |= E2F_FLAG_ABORT;
51 if (ctx->flags & E2F_FLAG_SETJMP_OK)
52 longjmp(ctx->abort_loc, 1);
53 exit(FSCK_ERROR);
54}
55#endif
56
57void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
58 const char *description)
59{
60 void *ret;
61 char buf[256];
62
63#ifdef DEBUG_ALLOCATE_MEMORY
64 printf("Allocating %d bytes for %s...\n", size, description);
65#endif
66 ret = malloc(size);
67 if (!ret) {
68 sprintf(buf, "Can't allocate %s\n", description);
69 fatal_error(ctx, buf);
70 }
71 memset(ret, 0, size);
72 return ret;
73}
74
75char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
76 const char *str, int len)
77{
78 char *ret;
79
80 if (!str)
81 return NULL;
82 if (!len)
83 len = strlen(str);
84 ret = malloc(len+1);
85 if (ret) {
86 strncpy(ret, str, len);
87 ret[len] = 0;
88 }
89 return ret;
90}
91
92#ifndef HAVE_STRNLEN
93/*
94 * Incredibly, libc5 doesn't appear to have strnlen. So we have to
95 * provide our own.
96 */
97int e2fsck_strnlen(const char * s, int count)
98{
99 const char *cp = s;
100
101 while (count-- && *cp)
102 cp++;
103 return cp - s;
104}
105#endif
106
107#ifndef HAVE_CONIO_H
108static int read_a_char(void)
109{
110 char c;
111 int r;
112 int fail = 0;
113
114 while(1) {
115 if (e2fsck_global_ctx &&
116 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
117 return 3;
118 }
119 r = read(0, &c, 1);
120 if (r == 1)
121 return c;
122 if (fail++ > 100)
123 break;
124 }
125 return EOF;
126}
127#endif
128
129int ask_yn(const char * string, int def)
130{
131 int c;
132 const char *defstr;
133 const char *short_yes = _("yY");
134 const char *short_no = _("nN");
135
136#ifdef HAVE_TERMIOS_H
137 struct termios termios, tmp;
138
139 tcgetattr (0, &termios);
140 tmp = termios;
141 tmp.c_lflag &= ~(ICANON | ECHO);
142 tmp.c_cc[VMIN] = 1;
143 tmp.c_cc[VTIME] = 0;
144 tcsetattr (0, TCSANOW, &tmp);
145#endif
146
147 if (def == 1)
148 defstr = _(_("<y>"));
149 else if (def == 0)
150 defstr = _(_("<n>"));
151 else
152 defstr = _(" (y/n)");
153 printf("%s%s? ", string, defstr);
154 while (1) {
155 fflush (stdout);
156 if ((c = read_a_char()) == EOF)
157 break;
158 if (c == 3) {
159#ifdef HAVE_TERMIOS_H
160 tcsetattr (0, TCSANOW, &termios);
161#endif
162 if (e2fsck_global_ctx &&
163 e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
164 puts("\n");
165 longjmp(e2fsck_global_ctx->abort_loc, 1);
166 }
167 puts(_("cancelled!\n"));
168 return 0;
169 }
170 if (strchr(short_yes, (char) c)) {
171 def = 1;
172 break;
173 }
174 else if (strchr(short_no, (char) c)) {
175 def = 0;
176 break;
177 }
178 else if ((c == ' ' || c == '\n') && (def != -1))
179 break;
180 }
181 if (def)
182 puts(_("yes\n"));
183 else
184 puts (_("no\n"));
185#ifdef HAVE_TERMIOS_H
186 tcsetattr (0, TCSANOW, &termios);
187#endif
188 return def;
189}
190
191int ask (e2fsck_t ctx, const char * string, int def)
192{
193 if (ctx->options & E2F_OPT_NO) {
194 printf (_("%s? no\n\n"), string);
195 return 0;
196 }
197 if (ctx->options & E2F_OPT_YES) {
198 printf (_("%s? yes\n\n"), string);
199 return 1;
200 }
201 if (ctx->options & E2F_OPT_PREEN) {
202 printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
203 return def;
204 }
205 return ask_yn(string, def);
206}
207
208void e2fsck_read_bitmaps(e2fsck_t ctx)
209{
210 ext2_filsys fs = ctx->fs;
211 errcode_t retval;
212
213 if (ctx->invalid_bitmaps) {
214 com_err(ctx->program_name, 0,
215 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
216 ctx->device_name);
217 fatal_error(ctx, 0);
218 }
219
220 ehandler_operation(_("reading inode and block bitmaps"));
221 retval = ext2fs_read_bitmaps(fs);
222 ehandler_operation(0);
223 if (retval) {
224 com_err(ctx->program_name, retval,
225 _("while retrying to read bitmaps for %s"),
226 ctx->device_name);
227 fatal_error(ctx, 0);
228 }
229}
230
231void e2fsck_write_bitmaps(e2fsck_t ctx)
232{
233 ext2_filsys fs = ctx->fs;
234 errcode_t retval;
235
236 if (ext2fs_test_bb_dirty(fs)) {
237 ehandler_operation(_("writing block bitmaps"));
238 retval = ext2fs_write_block_bitmap(fs);
239 ehandler_operation(0);
240 if (retval) {
241 com_err(ctx->program_name, retval,
242 _("while retrying to write block bitmaps for %s"),
243 ctx->device_name);
244 fatal_error(ctx, 0);
245 }
246 }
247
248 if (ext2fs_test_ib_dirty(fs)) {
249 ehandler_operation(_("writing inode bitmaps"));
250 retval = ext2fs_write_inode_bitmap(fs);
251 ehandler_operation(0);
252 if (retval) {
253 com_err(ctx->program_name, retval,
254 _("while retrying to write inode bitmaps for %s"),
255 ctx->device_name);
256 fatal_error(ctx, 0);
257 }
258 }
259}
260
261void preenhalt(e2fsck_t ctx)
262{
263 ext2_filsys fs = ctx->fs;
264
265 if (!(ctx->options & E2F_OPT_PREEN))
266 return;
267 fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
268 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
269 ctx->device_name);
270 if (fs != NULL) {
271 fs->super->s_state |= EXT2_ERROR_FS;
272 ext2fs_mark_super_dirty(fs);
273 ext2fs_close(fs);
274 }
275 exit(FSCK_UNCORRECTED);
276}
277
278#ifdef RESOURCE_TRACK
279void init_resource_track(struct resource_track *track)
280{
281#ifdef HAVE_GETRUSAGE
282 struct rusage r;
283#endif
284
285 track->brk_start = sbrk(0);
286 gettimeofday(&track->time_start, 0);
287#ifdef HAVE_GETRUSAGE
288#ifdef sun
289 memset(&r, 0, sizeof(struct rusage));
290#endif
291 getrusage(RUSAGE_SELF, &r);
292 track->user_start = r.ru_utime;
293 track->system_start = r.ru_stime;
294#else
295 track->user_start.tv_sec = track->user_start.tv_usec = 0;
296 track->system_start.tv_sec = track->system_start.tv_usec = 0;
297#endif
298}
299
300#ifdef __GNUC__
301#define _INLINE_ __inline__
302#else
303#define _INLINE_
304#endif
305
306static _INLINE_ float timeval_subtract(struct timeval *tv1,
307 struct timeval *tv2)
308{
309 return ((tv1->tv_sec - tv2->tv_sec) +
310 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
311}
312
313void print_resource_track(const char *desc, struct resource_track *track)
314{
315#ifdef HAVE_GETRUSAGE
316 struct rusage r;
317#endif
318#ifdef HAVE_MALLINFO
319 struct mallinfo malloc_info;
320#endif
321 struct timeval time_end;
322
323 gettimeofday(&time_end, 0);
324
325 if (desc)
326 printf("%s: ", desc);
327
328#ifdef HAVE_MALLINFO
329#define kbytes(x) (((x) + 1023) / 1024)
330
331 malloc_info = mallinfo();
332 printf(_("Memory used: %dk/%dk (%dk/%dk), "),
333 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
334 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
335#else
336 printf(_("Memory used: %d, "),
337 (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
338#endif
339#ifdef HAVE_GETRUSAGE
340 getrusage(RUSAGE_SELF, &r);
341
342 printf(_("time: %5.2f/%5.2f/%5.2f\n"),
343 timeval_subtract(&time_end, &track->time_start),
344 timeval_subtract(&r.ru_utime, &track->user_start),
345 timeval_subtract(&r.ru_stime, &track->system_start));
346#else
347 printf(_("elapsed time: %6.3f\n"),
348 timeval_subtract(&time_end, &track->time_start));
349#endif
350}
351#endif /* RESOURCE_TRACK */
352
353void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
354 struct ext2_inode * inode, const char *proc)
355{
356 int retval;
357
358 retval = ext2fs_read_inode(ctx->fs, ino, inode);
359 if (retval) {
360 com_err("ext2fs_read_inode", retval,
361 _("while reading inode %ld in %s"), ino, proc);
362 fatal_error(ctx, 0);
363 }
364}
365
366extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
367 struct ext2_inode * inode, int bufsize,
368 const char *proc)
369{
370 int retval;
371
372 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
373 if (retval) {
374 com_err("ext2fs_write_inode", retval,
375 _("while writing inode %ld in %s"), ino, proc);
376 fatal_error(ctx, 0);
377 }
378}
379
380extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
381 struct ext2_inode * inode, const char *proc)
382{
383 int retval;
384
385 retval = ext2fs_write_inode(ctx->fs, ino, inode);
386 if (retval) {
387 com_err("ext2fs_write_inode", retval,
388 _("while writing inode %ld in %s"), ino, proc);
389 fatal_error(ctx, 0);
390 }
391}
392
393#ifdef MTRACE
394void mtrace_print(char *mesg)
395{
396 FILE *malloc_get_mallstream();
397 FILE *f = malloc_get_mallstream();
398
399 if (f)
400 fprintf(f, "============= %s\n", mesg);
401}
402#endif
403
404blk_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
405 io_manager manager)
406{
407 struct ext2_super_block *sb;
408 io_channel io = NULL;
409 void *buf = NULL;
410 int blocksize;
411 blk_t superblock, ret_sb = 8193;
412
413 if (fs && fs->super) {
414 ret_sb = (fs->super->s_blocks_per_group +
415 fs->super->s_first_data_block);
416 if (ctx) {
417 ctx->superblock = ret_sb;
418 ctx->blocksize = fs->blocksize;
419 }
420 return ret_sb;
421 }
422
423 if (ctx) {
424 if (ctx->blocksize) {
425 ret_sb = ctx->blocksize * 8;
426 if (ctx->blocksize == 1024)
427 ret_sb++;
428 ctx->superblock = ret_sb;
429 return ret_sb;
430 }
431 ctx->superblock = ret_sb;
432 ctx->blocksize = 1024;
433 }
434
435 if (!name || !manager)
436 goto cleanup;
437
438 if (manager->open(name, 0, &io) != 0)
439 goto cleanup;
440
441 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
442 goto cleanup;
443 sb = (struct ext2_super_block *) buf;
444
445 for (blocksize = EXT2_MIN_BLOCK_SIZE;
446 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
447 superblock = blocksize*8;
448 if (blocksize == 1024)
449 superblock++;
450 io_channel_set_blksize(io, blocksize);
451 if (io_channel_read_blk(io, superblock,
452 -SUPERBLOCK_SIZE, buf))
453 continue;
454#ifdef EXT2FS_ENABLE_SWAPFS
455 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
456 ext2fs_swap_super(sb);
457#endif
458 if (sb->s_magic == EXT2_SUPER_MAGIC) {
459 ret_sb = superblock;
460 if (ctx) {
461 ctx->superblock = superblock;
462 ctx->blocksize = blocksize;
463 }
464 break;
465 }
466 }
467
468cleanup:
469 if (io)
470 io_channel_close(io);
471 if (buf)
472 ext2fs_free_mem(&buf);
473 return (ret_sb);
474}
475
476/*
477 * Given a mode, return the ext2 file type
478 */
479int ext2_file_type(unsigned int mode)
480{
481 if (LINUX_S_ISREG(mode))
482 return EXT2_FT_REG_FILE;
483
484 if (LINUX_S_ISDIR(mode))
485 return EXT2_FT_DIR;
486
487 if (LINUX_S_ISCHR(mode))
488 return EXT2_FT_CHRDEV;
489
490 if (LINUX_S_ISBLK(mode))
491 return EXT2_FT_BLKDEV;
492
493 if (LINUX_S_ISLNK(mode))
494 return EXT2_FT_SYMLINK;
495
496 if (LINUX_S_ISFIFO(mode))
497 return EXT2_FT_FIFO;
498
499 if (LINUX_S_ISSOCK(mode))
500 return EXT2_FT_SOCK;
501
502 return 0;
503}