blob: cf821ee1d06e36acdb663deac4ba275549ff036f [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
3 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * 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%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 *
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)
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000022 * - A bitmap of which inodes are regular files. (inode_reg_map)
Theodore Ts'o3839e651997-04-26 13:21:57 +000023 * - A bitmap of which inodes have bad fields. (inode_bad_map)
Theodore Ts'o21c84b71997-04-29 16:15:03 +000024 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000025 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
Theodore Ts'o3839e651997-04-26 13:21:57 +000026 * - 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#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000041#ifdef HAVE_ERRNO_H
42#include <errno.h>
43#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000044
Theodore Ts'o3839e651997-04-26 13:21:57 +000045#include "e2fsck.h"
Theodore Ts'o21c84b71997-04-29 16:15:03 +000046#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000047
Theodore Ts'o50e1e101997-04-26 13:58:21 +000048#ifdef NO_INLINE_FUNCS
49#define _INLINE_
50#else
51#define _INLINE_ inline
52#endif
53
Theodore Ts'o3839e651997-04-26 13:21:57 +000054static int process_block(ext2_filsys fs, blk_t *blocknr,
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +000055 e2_blkcnt_t blockcnt, blk_t ref_blk,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000056 int ref_offset, void *priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +000057static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +000058 e2_blkcnt_t blockcnt, blk_t ref_blk,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000059 int ref_offset, void *priv_data);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000060static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +000061 char *block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000062static void mark_table_blocks(e2fsck_t ctx);
63static void alloc_bad_map(e2fsck_t ctx);
64static void alloc_bb_map(e2fsck_t ctx);
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000065static void alloc_imagic_map(e2fsck_t ctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000066static void handle_fs_bad_blocks(e2fsck_t ctx);
67static void process_inodes(e2fsck_t ctx, char *block_buf);
Theodore Ts'o4c77fe51998-04-30 17:35:59 +000068static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
Theodore Ts'of3db3561997-04-26 13:34:30 +000069static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000070 dgrp_t group, void * priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000071/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
Theodore Ts'o3839e651997-04-26 13:21:57 +000072
73struct process_block_struct {
Theodore Ts'o246501c1998-03-24 16:22:38 +000074 ino_t ino;
75 int is_dir:1, clear:1, suppress:1, fragmented:1;
76 blk_t num_blocks;
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +000077 e2_blkcnt_t last_block;
Theodore Ts'o246501c1998-03-24 16:22:38 +000078 int num_illegal_blocks;
79 blk_t previous_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +000080 struct ext2_inode *inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000081 struct problem_context *pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000082 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +000083};
84
85struct process_inode_block {
86 ino_t ino;
87 struct ext2_inode inode;
88};
89
Theodore Ts'of8188ff1997-11-14 05:23:04 +000090struct scan_callback_struct {
91 e2fsck_t ctx;
92 char *block_buf;
93};
94
Theodore Ts'o3839e651997-04-26 13:21:57 +000095/*
Theodore Ts'o3839e651997-04-26 13:21:57 +000096 * For the inodes to process list.
97 */
98static struct process_inode_block *inodes_to_process;
99static int process_inode_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000100
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000101static __u64 ext2_max_sizes[4];
Theodore Ts'o246501c1998-03-24 16:22:38 +0000102
Theodore Ts'o3839e651997-04-26 13:21:57 +0000103/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000104 * Free all memory allocated by pass1 in preparation for restarting
105 * things.
106 */
107static void unwind_pass1(ext2_filsys fs)
108{
Theodore Ts'o08b21301997-11-03 19:42:40 +0000109 ext2fs_free_mem((void **) &inodes_to_process);
110 inodes_to_process = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000111}
112
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000113/*
114 * Check to make sure a device inode is real. Returns 1 if the device
115 * checks out, 0 if not.
Theodore Ts'o1dde43f1998-11-14 04:18:28 +0000116 *
117 * Note: this routine is now also used to check FIFO's and Sockets,
118 * since they have the same requirement; the i_block fields should be
119 * zero.
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000120 */
121int e2fsck_pass1_check_device_inode(struct ext2_inode *inode)
122{
123 int i;
124
Theodore Ts'o7fdfabd1997-11-24 11:51:17 +0000125 /*
126 * We should be able to do the test below all the time, but
127 * because the kernel doesn't forcibly clear the device
128 * inode's additional i_block fields, there are some rare
129 * occasions when a legitimate device inode will have non-zero
130 * additional i_block fields. So for now, we only complain
131 * when the immutable flag is set, which should never happen
132 * for devices. (And that's when the problem is caused, since
133 * you can't set or clear immutable flags for devices.) Once
134 * the kernel has been fixed we can change this...
135 */
136 if (inode->i_flags & EXT2_IMMUTABLE_FL) {
137 for (i=4; i < EXT2_N_BLOCKS; i++)
138 if (inode->i_block[i])
139 return 0;
140 }
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000141 return 1;
142}
143
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000144/*
145 * If the immutable flag is set on the inode, offer to clear it.
146 */
147static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
148{
149 if (!(pctx->inode->i_flags & EXT2_IMMUTABLE_FL))
150 return;
151
152 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
153 return;
154
155 pctx->inode->i_flags &= ~EXT2_IMMUTABLE_FL;
156 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
157}
158
159
Theodore Ts'o08b21301997-11-03 19:42:40 +0000160void e2fsck_pass1(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000161{
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000162 int i;
163 __u64 max_sizes;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000164 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000165 ino_t ino;
166 struct ext2_inode inode;
167 ext2_inode_scan scan;
168 char *block_buf;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000169#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000170 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000171#endif
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000172 unsigned char frag, fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000173 struct problem_context pctx;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000174 struct scan_callback_struct scan_struct;
Theodore Ts'o874b4d21998-07-06 14:33:12 +0000175 struct ext2fs_sb *sb;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000176 int imagic_fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000177
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000178#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000179 init_resource_track(&rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000180#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000181 clear_problem_context(&pctx);
182
183 if (!(ctx->options & E2F_OPT_PREEN))
184 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000185
186#ifdef MTRACE
187 mtrace_print("Pass 1");
188#endif
189
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000190#define EXT2_BPP(bits) (1UL << ((bits) - 2))
191
192 for (i=0; i < 4; i++) {
193 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(10+i);
194 max_sizes = max_sizes + EXT2_BPP(10+i) * EXT2_BPP(10+i);
195 max_sizes = (max_sizes +
196 (__u64) EXT2_BPP(10+i) * EXT2_BPP(10+i) *
197 EXT2_BPP(10+i));
198 max_sizes = (max_sizes * (1UL << (10+i))) - 1;
199 ext2_max_sizes[i] = max_sizes;
200 }
201#undef EXT2_BPP
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000202
203 sb = (struct ext2fs_sb *) fs->super;
204 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
205
Theodore Ts'o3839e651997-04-26 13:21:57 +0000206 /*
207 * Allocate bitmaps structures
208 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000209 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "in-use inode map",
210 &ctx->inode_used_map);
211 if (pctx.errcode) {
212 pctx.num = 1;
213 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000214 ctx->flags |= E2F_FLAG_ABORT;
215 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000216 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000217 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "directory inode map",
218 &ctx->inode_dir_map);
219 if (pctx.errcode) {
220 pctx.num = 2;
221 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000222 ctx->flags |= E2F_FLAG_ABORT;
223 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000224 }
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000225 pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
226 "regular file inode map",
227 &ctx->inode_reg_map);
228 if (pctx.errcode) {
229 pctx.num = 6;
230 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
231 ctx->flags |= E2F_FLAG_ABORT;
232 return;
233 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000234 pctx.errcode = ext2fs_allocate_block_bitmap(fs, "in-use block map",
235 &ctx->block_found_map);
236 if (pctx.errcode) {
237 pctx.num = 1;
238 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000239 ctx->flags |= E2F_FLAG_ABORT;
240 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000241 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000242 pctx.errcode = ext2fs_allocate_block_bitmap(fs, "illegal block map",
243 &ctx->block_illegal_map);
244 if (pctx.errcode) {
245 pctx.num = 2;
246 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000247 ctx->flags |= E2F_FLAG_ABORT;
248 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000249 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000250 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
251 &ctx->inode_link_info);
252 if (pctx.errcode) {
253 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000254 ctx->flags |= E2F_FLAG_ABORT;
255 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000256 }
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000257 inodes_to_process = (struct process_inode_block *)
258 e2fsck_allocate_memory(ctx,
259 (ctx->process_inode_size *
260 sizeof(struct process_inode_block)),
261 "array of inodes to process");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000262 process_inode_count = 0;
263
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000264 pctx.errcode = ext2fs_init_dblist(fs, 0);
265 if (pctx.errcode) {
266 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000267 ctx->flags |= E2F_FLAG_ABORT;
268 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000269 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000270
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000271 mark_table_blocks(ctx);
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000272 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
273 "block interate buffer");
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +0000274 e2fsck_use_inode_shortcuts(ctx, 1);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000275 ehandler_operation("doing inode scan");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000276 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
277 &scan);
278 if (pctx.errcode) {
279 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000280 ctx->flags |= E2F_FLAG_ABORT;
281 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000282 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000283 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000284 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
285 if (pctx.errcode) {
286 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000287 ctx->flags |= E2F_FLAG_ABORT;
288 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000289 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000290 ctx->stashed_inode = &inode;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000291 scan_struct.ctx = ctx;
292 scan_struct.block_buf = block_buf;
293 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
294 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000295 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
296 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000297 while (ino) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000298 pctx.ino = ino;
299 pctx.inode = &inode;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000300 ctx->stashed_ino = ino;
301 if (inode.i_links_count) {
302 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
303 ino, inode.i_links_count);
304 if (pctx.errcode) {
305 pctx.num = inode.i_links_count;
306 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000307 ctx->flags |= E2F_FLAG_ABORT;
308 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000309 }
310 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000311 if (ino == EXT2_BAD_INO) {
312 struct process_block_struct pb;
313
314 pb.ino = EXT2_BAD_INO;
315 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000316 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000317 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000318 pb.fragmented = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000319 pb.inode = &inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000320 pb.pctx = &pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000321 pb.ctx = ctx;
322 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
323 block_buf, process_bad_block, &pb);
324 if (pctx.errcode) {
325 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000326 ctx->flags |= E2F_FLAG_ABORT;
327 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000328 }
329 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000330 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000331 goto next;
332 }
333 if (ino == EXT2_ROOT_INO) {
334 /*
335 * Make sure the root inode is a directory; if
336 * not, offer to clear it. It will be
337 * regnerated in pass #3.
338 */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000339 if (!LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000340 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000341 inode.i_dtime = time(0);
342 inode.i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000343 ext2fs_icount_store(ctx->inode_link_info,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000344 ino, 0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000345 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000346 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000347 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000348 }
349 /*
350 * If dtime is set, offer to clear it. mke2fs
351 * version 0.2b created filesystems with the
352 * dtime field set for the root and lost+found
353 * directories. We won't worry about
354 * /lost+found, since that can be regenerated
355 * easily. But we will fix the root directory
356 * as a special case.
357 */
358 if (inode.i_dtime && inode.i_links_count) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000359 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000360 inode.i_dtime = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000361 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000362 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000363 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000364 }
365 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000366 if ((ino != EXT2_ROOT_INO) &&
367 (ino < EXT2_FIRST_INODE(fs->super))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000368 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000369 if (((ino == EXT2_BOOT_LOADER_INO) &&
370 LINUX_S_ISDIR(inode.i_mode)) ||
371 ((ino != EXT2_BOOT_LOADER_INO) &&
372 (inode.i_mode != 0))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000373 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000374 PR_1_RESERVED_BAD_MODE, &pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000375 inode.i_mode = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000376 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000377 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000378 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000379 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000380 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000381 goto next;
382 }
383 /*
384 * This code assumes that deleted inodes have
385 * i_links_count set to 0.
386 */
387 if (!inode.i_links_count) {
388 if (!inode.i_dtime && inode.i_mode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000389 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000390 PR_1_ZERO_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000391 inode.i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000392 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000393 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000394 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000395 }
396 goto next;
397 }
398 /*
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000399 * n.b. 0.3c ext2fs code didn't clear i_links_count for
Theodore Ts'o3839e651997-04-26 13:21:57 +0000400 * deleted files. Oops.
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000401 *
402 * Since all new ext2 implementations get this right,
403 * we now assume that the case of non-zero
404 * i_links_count and non-zero dtime means that we
405 * should keep the file, not delete it.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000406 *
Theodore Ts'o3839e651997-04-26 13:21:57 +0000407 */
408 if (inode.i_dtime) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000409 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000410 inode.i_dtime = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000411 e2fsck_write_inode(ctx, ino, &inode, "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000412 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000413 }
414
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000415 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000416 switch (fs->super->s_creator_os) {
417 case EXT2_OS_LINUX:
418 frag = inode.osd2.linux2.l_i_frag;
419 fsize = inode.osd2.linux2.l_i_fsize;
420 break;
421 case EXT2_OS_HURD:
422 frag = inode.osd2.hurd2.h_i_frag;
423 fsize = inode.osd2.hurd2.h_i_fsize;
424 break;
425 case EXT2_OS_MASIX:
426 frag = inode.osd2.masix2.m_i_frag;
427 fsize = inode.osd2.masix2.m_i_fsize;
428 break;
429 default:
430 frag = fsize = 0;
431 }
432
433 if (inode.i_faddr || frag || fsize
Theodore Ts'o246501c1998-03-24 16:22:38 +0000434 || inode.i_file_acl ||
435 (LINUX_S_ISDIR(inode.i_mode) && inode.i_dir_acl)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000436 if (!ctx->inode_bad_map)
437 alloc_bad_map(ctx);
438 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000439 }
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000440 if (inode.i_flags & EXT2_IMAGIC_FL) {
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000441 if (imagic_fs) {
442 if (!ctx->inode_imagic_map)
443 alloc_imagic_map(ctx);
444 ext2fs_mark_inode_bitmap(ctx->inode_imagic_map,
445 ino);
446 } else {
447 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
448 inode.i_flags &= ~EXT2_IMAGIC_FL;
449 e2fsck_write_inode(ctx, ino,
450 &inode, "pass1");
451 }
452 }
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000453 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000454
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000455 if (LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000456 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000457 e2fsck_add_dir_info(ctx, ino, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000458 ctx->fs_directory_count++;
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000459 } else if (LINUX_S_ISREG (inode.i_mode)) {
460 ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000461 ctx->fs_regular_count++;
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000462 } else if (LINUX_S_ISCHR (inode.i_mode) &&
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000463 e2fsck_pass1_check_device_inode(&inode)) {
464 check_immutable(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000465 ctx->fs_chardev_count++;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000466 } else if (LINUX_S_ISBLK (inode.i_mode) &&
467 e2fsck_pass1_check_device_inode(&inode)) {
468 check_immutable(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000469 ctx->fs_blockdev_count++;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000470 } else if (LINUX_S_ISLNK (inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000471 ctx->fs_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000472 if (!inode.i_blocks) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000473 ctx->fs_fast_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000474 goto next;
475 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000476 }
Theodore Ts'o1dde43f1998-11-14 04:18:28 +0000477 else if (LINUX_S_ISFIFO (inode.i_mode) &&
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000478 e2fsck_pass1_check_device_inode(&inode)) {
479 check_immutable(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000480 ctx->fs_fifo_count++;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000481 } else if ((LINUX_S_ISSOCK (inode.i_mode)) &&
482 e2fsck_pass1_check_device_inode(&inode)) {
483 check_immutable(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000484 ctx->fs_sockets_count++;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000485 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000486 if (!ctx->inode_bad_map)
487 alloc_bad_map(ctx);
488 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000489 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000490 if (inode.i_block[EXT2_IND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000491 ctx->fs_ind_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000492 if (inode.i_block[EXT2_DIND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000493 ctx->fs_dind_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000494 if (inode.i_block[EXT2_TIND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000495 ctx->fs_tind_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000496 if (inode.i_block[EXT2_IND_BLOCK] ||
497 inode.i_block[EXT2_DIND_BLOCK] ||
498 inode.i_block[EXT2_TIND_BLOCK]) {
499 inodes_to_process[process_inode_count].ino = ino;
500 inodes_to_process[process_inode_count].inode = inode;
501 process_inode_count++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000502 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000503 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000504
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000505 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000506 return;
507
508 if (process_inode_count >= ctx->process_inode_size) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000509 process_inodes(ctx, block_buf);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000510
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000511 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000512 return;
513 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000514 next:
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000515 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
Theodore Ts'o2df1f6a1998-02-27 05:03:48 +0000516 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
517 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000518 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
519 if (!ctx->inode_bb_map)
520 alloc_bb_map(ctx);
521 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
522 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000523 goto next;
524 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000525 if (pctx.errcode) {
526 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000527 ctx->flags |= E2F_FLAG_ABORT;
528 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000529 }
530 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000531 process_inodes(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000532 ext2fs_close_inode_scan(scan);
533 ehandler_operation(0);
534
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000535 if (ctx->invalid_bitmaps)
536 handle_fs_bad_blocks(ctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000537
Theodore Ts'o08b21301997-11-03 19:42:40 +0000538 if (ctx->flags & E2F_FLAG_RESTART) {
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000539 /*
540 * Only the master copy of the superblock and block
541 * group descriptors are going to be written during a
542 * restart, so set the superblock to be used to be the
543 * master superblock.
544 */
545 ctx->use_superblock = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000546 unwind_pass1(fs);
547 goto endit;
548 }
549
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000550 if (ctx->block_dup_map) {
551 if (ctx->options & E2F_OPT_PREEN) {
552 clear_problem_context(&pctx);
553 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000554 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000555 e2fsck_pass1_dupblocks(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000556 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000557 ext2fs_free_mem((void **) &inodes_to_process);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000558endit:
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +0000559 e2fsck_use_inode_shortcuts(ctx, 0);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000560
Theodore Ts'o08b21301997-11-03 19:42:40 +0000561 ext2fs_free_mem((void **) &block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000562 ext2fs_free_block_bitmap(ctx->block_illegal_map);
563 ctx->block_illegal_map = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000564
Theodore Ts'o246501c1998-03-24 16:22:38 +0000565 if (ctx->large_files &&
Theodore Ts'o874b4d21998-07-06 14:33:12 +0000566 !(sb->s_feature_ro_compat &
Theodore Ts'o246501c1998-03-24 16:22:38 +0000567 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
568 if (fix_problem(ctx, PR_1_FEATURE_LARGE_FILES, &pctx)) {
Theodore Ts'o874b4d21998-07-06 14:33:12 +0000569 sb->s_feature_ro_compat |=
Theodore Ts'o246501c1998-03-24 16:22:38 +0000570 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
571 ext2fs_mark_super_dirty(fs);
572 }
573 } else if (!ctx->large_files &&
Theodore Ts'o874b4d21998-07-06 14:33:12 +0000574 (sb->s_feature_ro_compat &
Theodore Ts'o246501c1998-03-24 16:22:38 +0000575 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
576 if (fs->flags & EXT2_FLAG_RW) {
Theodore Ts'o874b4d21998-07-06 14:33:12 +0000577 sb->s_feature_ro_compat &=
Theodore Ts'o246501c1998-03-24 16:22:38 +0000578 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
579 ext2fs_mark_super_dirty(fs);
580 }
581 }
582
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000583#ifdef RESOURCE_TRACK
Theodore Ts'o5596def1999-07-19 15:27:37 +0000584 if (ctx->options & E2F_OPT_TIME2) {
585 e2fsck_clear_progbar(ctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000586 print_resource_track("Pass 1", &rtrack);
Theodore Ts'o5596def1999-07-19 15:27:37 +0000587 }
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000588#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000589}
590
591/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000592 * When the inode_scan routines call this callback at the end of the
593 * glock group, call process_inodes.
594 */
595static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000596 dgrp_t group, void * priv_data)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000597{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000598 struct scan_callback_struct *scan_struct;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000599 e2fsck_t ctx;
600
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000601 scan_struct = (struct scan_callback_struct *) priv_data;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000602 ctx = scan_struct->ctx;
603
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000604 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000605
606 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000607 if ((ctx->progress)(ctx, 1, group+1,
608 ctx->fs->group_desc_count))
609 return EXT2_ET_CANCEL_REQUESTED;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000610
Theodore Ts'of3db3561997-04-26 13:34:30 +0000611 return 0;
612}
613
614/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000615 * Process the inodes in the "inodes to process" list.
616 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000617static void process_inodes(e2fsck_t ctx, char *block_buf)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000618{
619 int i;
620 struct ext2_inode *old_stashed_inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000621 ino_t old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000622 const char *old_operation;
623 char buf[80];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000624 struct problem_context pctx;
625
Theodore Ts'o3839e651997-04-26 13:21:57 +0000626#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000627 printf("begin process_inodes: ");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000628#endif
629 old_operation = ehandler_operation(0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000630 old_stashed_inode = ctx->stashed_inode;
631 old_stashed_ino = ctx->stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000632 qsort(inodes_to_process, process_inode_count,
633 sizeof(struct process_inode_block), process_inode_cmp);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000634 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000635 for (i=0; i < process_inode_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000636 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
637 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000638
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000639#if 0
640 printf("%u ", pctx.ino);
641#endif
642 sprintf(buf, "reading indirect blocks of inode %lu", pctx.ino);
643 ehandler_operation(buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000644 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000645 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o2df1f6a1998-02-27 05:03:48 +0000646 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000647 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000648 ctx->stashed_inode = old_stashed_inode;
649 ctx->stashed_ino = old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000650 process_inode_count = 0;
651#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000652 printf("end process inodes\n");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000653#endif
654 ehandler_operation(old_operation);
655}
656
Theodore Ts'o4c77fe51998-04-30 17:35:59 +0000657static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000658{
659 const struct process_inode_block *ib_a =
660 (const struct process_inode_block *) a;
661 const struct process_inode_block *ib_b =
662 (const struct process_inode_block *) b;
663
664 return (ib_a->inode.i_block[EXT2_IND_BLOCK] -
665 ib_b->inode.i_block[EXT2_IND_BLOCK]);
666}
667
Theodore Ts'o3839e651997-04-26 13:21:57 +0000668/*
669 * This procedure will allocate the inode bad map table
670 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000671static void alloc_bad_map(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000672{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000673 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000674
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000675 clear_problem_context(&pctx);
676
677 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, "bad inode map",
678 &ctx->inode_bad_map);
679 if (pctx.errcode) {
680 pctx.num = 3;
681 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000682 /* Should never get here */
683 ctx->flags |= E2F_FLAG_ABORT;
684 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000685 }
686}
687
688/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000689 * This procedure will allocate the inode "bb" (badblock) map table
690 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000691static void alloc_bb_map(e2fsck_t ctx)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000692{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000693 struct problem_context pctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000694
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000695 clear_problem_context(&pctx);
696 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
697 "inode in bad block map",
698 &ctx->inode_bb_map);
699 if (pctx.errcode) {
700 pctx.num = 4;
701 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000702 /* Should never get here */
703 ctx->flags |= E2F_FLAG_ABORT;
704 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000705 }
706}
707
708/*
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000709 * This procedure will allocate the inode imagic table
710 */
711static void alloc_imagic_map(e2fsck_t ctx)
712{
713 struct problem_context pctx;
714
715 clear_problem_context(&pctx);
716 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
717 "imagic inode map",
718 &ctx->inode_imagic_map);
719 if (pctx.errcode) {
720 pctx.num = 5;
721 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
722 /* Should never get here */
723 ctx->flags |= E2F_FLAG_ABORT;
724 return;
725 }
726}
727
728/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000729 * Marks a block as in use, setting the dup_map if it's been set
730 * already. Called by process_block and process_bad_block.
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000731 *
732 * WARNING: Assumes checks have already been done to make sure block
733 * is valid. This is true in both process_block and process_bad_block.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000734 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000735static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000736{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000737 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000738
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000739 clear_problem_context(&pctx);
740
741 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
742 if (!ctx->block_dup_map) {
743 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
744 "multiply claimed block map",
745 &ctx->block_dup_map);
746 if (pctx.errcode) {
747 pctx.num = 3;
748 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
749 &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000750 /* Should never get here */
751 ctx->flags |= E2F_FLAG_ABORT;
752 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000753 }
754 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000755 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000756 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000757 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000758 }
759}
760
761/*
762 * This subroutine is called on each inode to account for all of the
763 * blocks used by that inode.
764 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000765static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000766 char *block_buf)
767{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000768 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000769 struct process_block_struct pb;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000770 ino_t ino = pctx->ino;
771 struct ext2_inode *inode = pctx->inode;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000772 int bad_size = 0;
773 __u64 size;
774 struct ext2fs_sb *sb;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000775
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000776 if (!ext2fs_inode_has_valid_blocks(pctx->inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000777 return;
778
779 pb.ino = ino;
780 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000781 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000782 pb.suppress = 0; pb.clear = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000783 pb.fragmented = 0;
784 pb.previous_block = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000785 pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000786 pb.inode = inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000787 pb.pctx = pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000788 pb.ctx = ctx;
789 pctx->ino = ino;
790 pctx->errcode = ext2fs_block_iterate2(fs, ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000791 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
792 block_buf, process_block, &pb);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000793 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000794 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000795 end_problem_latch(ctx, PR_LATCH_BLOCK);
796 if (pctx->errcode)
797 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000798
Theodore Ts'o74becf31997-04-26 14:37:06 +0000799 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000800 ctx->fs_fragmented++;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000801
Theodore Ts'of3db3561997-04-26 13:34:30 +0000802 if (pb.clear) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000803 e2fsck_read_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000804 inode->i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000805 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000806 inode->i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000807 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000808 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000809 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000810 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000811 /*
812 * The inode was probably partially accounted for
813 * before processing was aborted, so we need to
814 * restart the pass 1 scan.
815 */
Theodore Ts'o08b21301997-11-03 19:42:40 +0000816 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000817 return;
818 }
819
Theodore Ts'o3839e651997-04-26 13:21:57 +0000820 pb.num_blocks *= (fs->blocksize / 512);
821#if 0
Theodore Ts'o246501c1998-03-24 16:22:38 +0000822 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000823 ino, inode->i_size, pb.last_block, inode->i_blocks,
824 pb.num_blocks);
825#endif
826 if (!pb.num_blocks && pb.is_dir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000827 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000828 inode->i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000829 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000830 inode->i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000831 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000832 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000833 ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000834 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
835 ctx->fs_directory_count--;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000836 pb.is_dir = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000837 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000838 }
Theodore Ts'o246501c1998-03-24 16:22:38 +0000839 if (pb.is_dir) {
840 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
841 if ((nblock > (pb.last_block + 1)) ||
842 ((inode->i_size & (fs->blocksize-1)) != 0))
843 bad_size = 1;
844 else if (nblock < (pb.last_block + 1)) {
845 sb = (struct ext2fs_sb *) fs->super;
846 if (((pb.last_block + 1) - nblock) >
847 sb->s_prealloc_dir_blocks)
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000848 bad_size = 2;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000849 }
850 } else {
851 size = inode->i_size + ((__u64) inode->i_size_high << 32);
852 if ((size < pb.last_block * fs->blocksize))
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000853 bad_size = 3;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000854 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000855 bad_size = 4;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000856 }
857 if (bad_size) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000858 pctx->num = (pb.last_block+1) * fs->blocksize;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000859 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000860 inode->i_size = pctx->num;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000861 if (!pb.is_dir)
862 inode->i_size_high = pctx->num >> 32;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000863 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000864 }
865 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000866 }
Theodore Ts'o246501c1998-03-24 16:22:38 +0000867 if (!pb.is_dir && inode->i_size_high)
868 ctx->large_files++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000869 if (pb.num_blocks != inode->i_blocks) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000870 pctx->num = pb.num_blocks;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000871 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000872 inode->i_blocks = pb.num_blocks;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000873 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000874 }
875 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000876 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000877}
878
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000879#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000880/*
881 * Helper function called by process block when an illegal block is
882 * found. It returns a description about why the block is illegal
883 */
884static char *describe_illegal_block(ext2_filsys fs, blk_t block)
885{
886 blk_t super;
887 int i;
888 static char problem[80];
889
890 super = fs->super->s_first_data_block;
891 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
892 if (block < super) {
893 sprintf(problem, "< FIRSTBLOCK (%u)", super);
894 return(problem);
895 } else if (block >= fs->super->s_blocks_count) {
896 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
897 return(problem);
898 }
899 for (i = 0; i < fs->group_desc_count; i++) {
900 if (block == super) {
901 sprintf(problem, "is the superblock in group %d", i);
902 break;
903 }
904 if (block > super &&
905 block <= (super + fs->desc_blocks)) {
906 sprintf(problem, "is in the group descriptors "
907 "of group %d", i);
908 break;
909 }
910 if (block == fs->group_desc[i].bg_block_bitmap) {
911 sprintf(problem, "is the block bitmap of group %d", i);
912 break;
913 }
914 if (block == fs->group_desc[i].bg_inode_bitmap) {
915 sprintf(problem, "is the inode bitmap of group %d", i);
916 break;
917 }
918 if (block >= fs->group_desc[i].bg_inode_table &&
919 (block < fs->group_desc[i].bg_inode_table
920 + fs->inode_blocks_per_group)) {
921 sprintf(problem, "is in the inode table of group %d",
922 i);
923 break;
924 }
925 super += fs->super->s_blocks_per_group;
926 }
927 return(problem);
928}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000929#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000930
931/*
932 * This is a helper function for check_blocks().
933 */
934int process_block(ext2_filsys fs,
935 blk_t *block_nr,
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000936 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000937 blk_t ref_block,
938 int ref_offset,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000939 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000940{
941 struct process_block_struct *p;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000942 struct problem_context *pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000943 blk_t blk = *block_nr;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000944 int ret_code = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000945 int problem = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000946 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000947
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000948 p = (struct process_block_struct *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000949 pctx = p->pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000950 ctx = p->ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000951
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000952 if (blk == 0) {
953 if (p->is_dir == 0) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000954 /*
955 * Should never happen, since only directories
956 * get called with BLOCK_FLAG_HOLE
957 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000958#if DEBUG_E2FSCK
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000959 printf("process_block() called with blk == 0, "
Theodore Ts'o5c576471997-04-29 15:29:49 +0000960 "blockcnt=%d, inode %lu???\n",
961 blockcnt, p->ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000962#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000963 return 0;
964 }
965 if (blockcnt < 0)
966 return 0;
967 if (blockcnt * fs->blocksize < p->inode->i_size) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000968#if 0
969 printf("Missing block (#%d) in directory inode %lu!\n",
970 blockcnt, p->ino);
971#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000972 goto mark_dir;
973 }
974 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000975 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000976
977#if 0
978 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
979 blockcnt);
980#endif
981
Theodore Ts'o74becf31997-04-26 14:37:06 +0000982 /*
983 * Simplistic fragmentation check. We merely require that the
984 * file be contiguous. (Which can never be true for really
985 * big files that are greater than a block group.)
986 */
987 if (p->previous_block) {
988 if (p->previous_block+1 != blk)
989 p->fragmented = 1;
990 }
991 p->previous_block = blk;
992
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000993 if (blk < fs->super->s_first_data_block ||
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000994 blk >= fs->super->s_blocks_count)
995 problem = PR_1_ILLEGAL_BLOCK_NUM;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000996#if 0
997 else
998 if (ext2fs_test_block_bitmap(block_illegal_map, blk))
999 problem = PR_1_BLOCK_OVERLAPS_METADATA;
1000#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001001
1002 if (problem) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001003 p->num_illegal_blocks++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001004 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001005 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001006 p->clear = 1;
1007 return BLOCK_ABORT;
1008 }
Theodore Ts'of8188ff1997-11-14 05:23:04 +00001009 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001010 p->suppress = 1;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001011 set_latch_flags(PR_LATCH_BLOCK,
1012 PRL_SUPPRESS, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001013 }
1014 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001015 pctx->blk = blk;
1016 pctx->blkcount = blockcnt;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001017 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001018 blk = *block_nr = 0;
1019 ret_code = BLOCK_CHANGED;
1020 goto mark_dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001021 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +00001022 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001023 pctx->blk = 0;
1024 pctx->blkcount = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001025 }
1026
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001027 mark_block_used(ctx, blk);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001028 p->num_blocks++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001029 if (blockcnt >= 0)
1030 p->last_block = blockcnt;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001031mark_dir:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001032 if (p->is_dir && (blockcnt >= 0)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001033 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
1034 blk, blockcnt);
1035 if (pctx->errcode) {
1036 pctx->blk = blk;
1037 pctx->num = blockcnt;
1038 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001039 /* Should never get here */
1040 ctx->flags |= E2F_FLAG_ABORT;
1041 return BLOCK_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001042 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001043 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001044 return ret_code;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001045}
1046
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001047static void bad_block_indirect(e2fsck_t ctx, blk_t blk)
Theodore Ts'of3db3561997-04-26 13:34:30 +00001048{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001049 struct problem_context pctx;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001050
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001051 clear_problem_context(&pctx);
1052 /*
1053 * Prompt to see if we should continue or not.
1054 */
1055 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, &pctx))
Theodore Ts'o08b21301997-11-03 19:42:40 +00001056 ctx->flags |= E2F_FLAG_ABORT;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001057}
1058
Theodore Ts'o3839e651997-04-26 13:21:57 +00001059int process_bad_block(ext2_filsys fs,
1060 blk_t *block_nr,
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +00001061 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001062 blk_t ref_block,
1063 int ref_offset,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001064 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001065{
1066 struct process_block_struct *p;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001067 blk_t blk = *block_nr;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001068 int first_block;
1069 int i;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001070 struct problem_context *pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001071 e2fsck_t ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001072
Theodore Ts'o3839e651997-04-26 13:21:57 +00001073 if (!blk)
1074 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001075
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001076 p = (struct process_block_struct *) priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001077 ctx = p->ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001078 pctx = p->pctx;
1079
Theodore Ts'of8188ff1997-11-14 05:23:04 +00001080 pctx->ino = EXT2_BAD_INO;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001081 pctx->blk = blk;
1082 pctx->blkcount = blockcnt;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001083
1084 if ((blk < fs->super->s_first_data_block) ||
1085 (blk >= fs->super->s_blocks_count)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001086 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00001087 *block_nr = 0;
1088 return BLOCK_CHANGED;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001089 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +00001090 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001091 }
1092
1093 if (blockcnt < 0) {
Theodore Ts'o08b21301997-11-03 19:42:40 +00001094 if (ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001095 bad_block_indirect(ctx, blk);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001096 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001097 return BLOCK_ABORT;
1098 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001099 mark_block_used(ctx, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001100 return 0;
1101 }
1102#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001103 printf ("DEBUG: Marking %u as bad.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001104#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001105 ctx->fs_badblocks_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001106 /*
1107 * If the block is not used, then mark it as used and return.
1108 * If it is already marked as found, this must mean that
1109 * there's an overlap between the filesystem table blocks
1110 * (bitmaps and inode table) and the bad block list.
1111 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001112 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
1113 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001114 return 0;
1115 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001116 /*
1117 * Try to find the where the filesystem block was used...
1118 */
1119 first_block = fs->super->s_first_data_block;
1120
1121 for (i = 0; i < fs->group_desc_count; i++ ) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001122 pctx->group = i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001123 pctx->blk = blk;
Theodore Ts'o8039c481997-11-19 21:39:13 +00001124 if (!ext2fs_bg_has_super(fs, i))
1125 goto skip_super;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001126 if (blk == first_block) {
1127 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001128 if (fix_problem(ctx,
1129 PR_1_BAD_PRIMARY_SUPERBLOCK,
1130 pctx)) {
1131 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001132 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001133 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001134 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001135 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001136 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001137 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001138 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001139 if ((blk > first_block) &&
1140 (blk <= first_block + fs->desc_blocks)) {
1141 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001142 pctx->blk = *block_nr;
1143 if (fix_problem(ctx,
1144 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
1145 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001146 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001147 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001148 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001149 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001150 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001151 return 0;
1152 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00001153 skip_super:
Theodore Ts'of3db3561997-04-26 13:34:30 +00001154 if (blk == fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001155 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
1156 ctx->invalid_block_bitmap_flag[i]++;
1157 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001158 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001159 return 0;
1160 }
1161 if (blk == fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001162 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
1163 ctx->invalid_inode_bitmap_flag[i]++;
1164 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001165 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001166 return 0;
1167 }
1168 if ((blk >= fs->group_desc[i].bg_inode_table) &&
1169 (blk < (fs->group_desc[i].bg_inode_table +
1170 fs->inode_blocks_per_group))) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001171 /*
1172 * If there are bad blocks in the inode table,
1173 * the inode scan code will try to do
1174 * something reasonable automatically.
1175 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001176 return 0;
1177 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00001178 first_block += fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001179 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001180 /*
1181 * If we've gotten to this point, then the only
1182 * possibility is that the bad block inode meta data
1183 * is using a bad block.
1184 */
1185 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
1186 p->inode->i_block[EXT2_DIND_BLOCK]) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001187 bad_block_indirect(ctx, blk);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001188 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001189 return BLOCK_ABORT;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001190 return 0;
1191 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001192
1193 pctx->group = -1;
1194
1195 /* Warn user that the block wasn't claimed */
1196 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
1197
Theodore Ts'o3839e651997-04-26 13:21:57 +00001198 return 0;
1199}
1200
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001201static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001202 const char *name, int num, blk_t *new_block)
1203{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001204 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001205 blk_t old_block = *new_block;
1206 int i;
1207 char *buf;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001208 struct problem_context pctx;
1209
1210 clear_problem_context(&pctx);
1211
1212 pctx.group = group;
1213 pctx.blk = old_block;
1214 pctx.str = name;
1215
1216 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001217 first_block + fs->super->s_blocks_per_group,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001218 num, ctx->block_found_map, new_block);
1219 if (pctx.errcode) {
1220 pctx.num = num;
1221 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001222 ext2fs_unmark_valid(fs);
1223 return;
1224 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001225 pctx.errcode = ext2fs_get_mem(fs->blocksize, (void **) &buf);
1226 if (pctx.errcode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001227 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001228 ext2fs_unmark_valid(fs);
1229 return;
1230 }
1231 ext2fs_mark_super_dirty(fs);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001232 pctx.blk2 = *new_block;
1233 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
1234 PR_1_RELOC_TO), &pctx);
1235 pctx.blk2 = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001236 for (i = 0; i < num; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001237 pctx.blk = i;
1238 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001239 if (old_block) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001240 pctx.errcode = io_channel_read_blk(fs->io,
1241 old_block + i, 1, buf);
1242 if (pctx.errcode)
1243 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001244 } else
1245 memset(buf, 0, fs->blocksize);
1246
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001247 pctx.blk = (*new_block) + i;
1248 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001249 1, buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001250 if (pctx.errcode)
1251 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001252 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001253 ext2fs_free_mem((void **) &buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001254}
1255
1256/*
Theodore Ts'of3db3561997-04-26 13:34:30 +00001257 * This routine gets called at the end of pass 1 if bad blocks are
1258 * detected in the superblock, group descriptors, inode_bitmaps, or
1259 * block bitmaps. At this point, all of the blocks have been mapped
1260 * out, so we can try to allocate new block(s) to replace the bad
1261 * blocks.
Theodore Ts'o3839e651997-04-26 13:21:57 +00001262 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001263static void handle_fs_bad_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001264{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001265 ext2_filsys fs = ctx->fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001266 int i;
1267 int first_block = fs->super->s_first_data_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001268
1269 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001270 if (ctx->invalid_block_bitmap_flag[i]) {
1271 new_table_block(ctx, first_block, i, "block bitmap",
1272 1, &fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001273 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001274 if (ctx->invalid_inode_bitmap_flag[i]) {
1275 new_table_block(ctx, first_block, i, "inode bitmap",
1276 1, &fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001277 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001278 if (ctx->invalid_inode_table_flag[i]) {
1279 new_table_block(ctx, first_block, i, "inode table",
Theodore Ts'of3db3561997-04-26 13:34:30 +00001280 fs->inode_blocks_per_group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001281 &fs->group_desc[i].bg_inode_table);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001282 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001283 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001284 first_block += fs->super->s_blocks_per_group;
1285 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001286 ctx->invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001287}
1288
1289/*
1290 * This routine marks all blocks which are used by the superblock,
1291 * group descriptors, inode bitmaps, and block bitmaps.
1292 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001293static void mark_table_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001294{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001295 ext2_filsys fs = ctx->fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001296 blk_t block, b;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001297 int i,j;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001298 struct problem_context pctx;
1299
1300 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001301
1302 block = fs->super->s_first_data_block;
1303 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001304 pctx.group = i;
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001305
1306 if (ext2fs_bg_has_super(fs, i)) {
1307 /*
1308 * Mark this group's copy of the superblock
1309 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001310 ext2fs_mark_block_bitmap(ctx->block_found_map, block);
1311 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
1312 block);
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001313
1314 /*
1315 * Mark this group's copy of the descriptors
1316 */
1317 for (j = 0; j < fs->desc_blocks; j++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001318 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001319 block + j + 1);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001320 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001321 block + j + 1);
1322 }
1323 }
1324
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001325 /*
1326 * Mark the blocks used for the inode table
1327 */
1328 if (fs->group_desc[i].bg_inode_table) {
1329 for (j = 0, b = fs->group_desc[i].bg_inode_table;
1330 j < fs->inode_blocks_per_group;
1331 j++, b++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001332 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001333 b)) {
1334 pctx.blk = b;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001335 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001336 PR_1_ITABLE_CONFLICT, &pctx)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001337 ctx->invalid_inode_table_flag[i]++;
1338 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001339 }
1340 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001341 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001342 b);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001343 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001344 b);
1345 }
1346 }
1347 }
1348
Theodore Ts'o3839e651997-04-26 13:21:57 +00001349 /*
1350 * Mark block used for the block bitmap
1351 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001352 if (fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001353 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001354 fs->group_desc[i].bg_block_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001355 pctx.blk = fs->group_desc[i].bg_block_bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001356 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
1357 ctx->invalid_block_bitmap_flag[i]++;
1358 ctx->invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001359 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001360 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001361 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001362 fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001363 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001364 fs->group_desc[i].bg_block_bitmap);
1365 }
1366
Theodore Ts'of3db3561997-04-26 13:34:30 +00001367 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001368 /*
1369 * Mark block used for the inode bitmap
1370 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001371 if (fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001372 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001373 fs->group_desc[i].bg_inode_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001374 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001375 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
1376 ctx->invalid_inode_bitmap_flag[i]++;
1377 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001378 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001379 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001380 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001381 fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001382 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001383 fs->group_desc[i].bg_inode_bitmap);
1384 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001385 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001386 block += fs->super->s_blocks_per_group;
1387 }
1388}
1389
1390/*
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001391 * Thes subroutines short circuits ext2fs_get_blocks and
Theodore Ts'o3839e651997-04-26 13:21:57 +00001392 * ext2fs_check_directory; we use them since we already have the inode
1393 * structure, so there's no point in letting the ext2fs library read
1394 * the inode again.
1395 */
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001396static errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001397{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001398 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001399 int i;
1400
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001401 if (ino != ctx->stashed_ino)
Theodore Ts'o521e3681997-04-29 17:48:10 +00001402 return EXT2_ET_CALLBACK_NOTHANDLED;
1403
1404 for (i=0; i < EXT2_N_BLOCKS; i++)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001405 blocks[i] = ctx->stashed_inode->i_block[i];
Theodore Ts'o521e3681997-04-29 17:48:10 +00001406 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001407}
1408
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001409static errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino,
1410 struct ext2_inode *inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001411{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001412 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001413
1414 if (ino != ctx->stashed_ino)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001415 return EXT2_ET_CALLBACK_NOTHANDLED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001416 *inode = *ctx->stashed_inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001417 return 0;
1418}
1419
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001420static errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001421 struct ext2_inode *inode)
1422{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001423 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001424
1425 if (ino == ctx->stashed_ino)
1426 *ctx->stashed_inode = *inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001427 return EXT2_ET_CALLBACK_NOTHANDLED;
1428}
1429
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001430static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001431{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001432 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001433
1434 if (ino != ctx->stashed_ino)
1435 return EXT2_ET_CALLBACK_NOTHANDLED;
1436
1437 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
Theodore Ts'o291c9041997-10-31 06:17:08 +00001438 return EXT2_ET_NO_DIRECTORY;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001439 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001440}
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001441
1442void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
1443{
1444 ext2_filsys fs = ctx->fs;
1445
1446 if (bool) {
1447 fs->get_blocks = pass1_get_blocks;
1448 fs->check_directory = pass1_check_directory;
1449 fs->read_inode = pass1_read_inode;
1450 fs->write_inode = pass1_write_inode;
1451 ctx->stashed_ino = 0;
1452 } else {
1453 fs->get_blocks = 0;
1454 fs->check_directory = 0;
1455 fs->read_inode = 0;
1456 fs->write_inode = 0;
1457 }
1458}
1459
1460