]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table | |
3 | * | |
21c84b71 TT |
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% | |
3839e657 TT |
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 have bad fields. (inode_bad_map) | |
21c84b71 | 23 | * - A bitmap of which inodes are in bad blocks. (inode_bb_map) |
3839e657 TT |
24 | * - A bitmap of which blocks are in use. (block_found_map) |
25 | * - A bitmap of which blocks are in use by two inodes (block_dup_map) | |
26 | * - The data blocks of the directory inodes. (dir_map) | |
27 | * | |
28 | * Pass 1 is designed to stash away enough information so that the | |
29 | * other passes should not need to read in the inode information | |
30 | * during the normal course of a filesystem check. (Althogh if an | |
31 | * inconsistency is detected, other passes may need to read in an | |
32 | * inode to fix it.) | |
33 | * | |
34 | * Note that pass 1B will be invoked if there are any duplicate blocks | |
35 | * found. | |
36 | */ | |
37 | ||
38 | #include <time.h> | |
50e1e10f TT |
39 | #ifdef HAVE_ERRNO_H |
40 | #include <errno.h> | |
41 | #endif | |
3839e657 | 42 | |
3839e657 | 43 | #include "e2fsck.h" |
21c84b71 | 44 | #include "problem.h" |
3839e657 | 45 | |
50e1e10f TT |
46 | #ifdef NO_INLINE_FUNCS |
47 | #define _INLINE_ | |
48 | #else | |
49 | #define _INLINE_ inline | |
50 | #endif | |
51 | ||
3839e657 | 52 | static int process_block(ext2_filsys fs, blk_t *blocknr, |
9d1bd3de | 53 | e2_blkcnt_t blockcnt, blk_t ref_blk, |
54dc7ca2 | 54 | int ref_offset, void *priv_data); |
3839e657 | 55 | static int process_bad_block(ext2_filsys fs, blk_t *block_nr, |
9d1bd3de | 56 | e2_blkcnt_t blockcnt, blk_t ref_blk, |
54dc7ca2 | 57 | int ref_offset, void *priv_data); |
1b6bf175 | 58 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 | 59 | char *block_buf); |
1b6bf175 TT |
60 | static void mark_table_blocks(e2fsck_t ctx); |
61 | static void alloc_bad_map(e2fsck_t ctx); | |
62 | static void alloc_bb_map(e2fsck_t ctx); | |
63 | static void handle_fs_bad_blocks(e2fsck_t ctx); | |
64 | static void process_inodes(e2fsck_t ctx, char *block_buf); | |
4c77fe50 | 65 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); |
f3db3566 | 66 | static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, |
54dc7ca2 | 67 | dgrp_t group, void * priv_data); |
21c84b71 | 68 | /* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */ |
3839e657 TT |
69 | |
70 | struct process_block_struct { | |
246501c6 TT |
71 | ino_t ino; |
72 | int is_dir:1, clear:1, suppress:1, fragmented:1; | |
73 | blk_t num_blocks; | |
9d1bd3de | 74 | e2_blkcnt_t last_block; |
246501c6 TT |
75 | int num_illegal_blocks; |
76 | blk_t previous_block; | |
f3db3566 | 77 | struct ext2_inode *inode; |
21c84b71 | 78 | struct problem_context *pctx; |
1b6bf175 | 79 | e2fsck_t ctx; |
3839e657 TT |
80 | }; |
81 | ||
82 | struct process_inode_block { | |
83 | ino_t ino; | |
84 | struct ext2_inode inode; | |
85 | }; | |
86 | ||
f8188fff TT |
87 | struct scan_callback_struct { |
88 | e2fsck_t ctx; | |
89 | char *block_buf; | |
90 | }; | |
91 | ||
3839e657 TT |
92 | /* |
93 | * For the inodes to process list. | |
94 | */ | |
95 | static struct process_inode_block *inodes_to_process; | |
96 | static int process_inode_count; | |
3839e657 | 97 | |
9d1bd3de | 98 | static __u64 ext2_max_sizes[4]; |
246501c6 | 99 | |
f3db3566 TT |
100 | /* |
101 | * Free all memory allocated by pass1 in preparation for restarting | |
102 | * things. | |
103 | */ | |
104 | static void unwind_pass1(ext2_filsys fs) | |
105 | { | |
08b21301 TT |
106 | ext2fs_free_mem((void **) &inodes_to_process); |
107 | inodes_to_process = 0; | |
f3db3566 TT |
108 | } |
109 | ||
7cf73dcd TT |
110 | /* |
111 | * Check to make sure a device inode is real. Returns 1 if the device | |
112 | * checks out, 0 if not. | |
1dde43f0 TT |
113 | * |
114 | * Note: this routine is now also used to check FIFO's and Sockets, | |
115 | * since they have the same requirement; the i_block fields should be | |
116 | * zero. | |
7cf73dcd TT |
117 | */ |
118 | int e2fsck_pass1_check_device_inode(struct ext2_inode *inode) | |
119 | { | |
120 | int i; | |
121 | ||
7fdfabd3 TT |
122 | /* |
123 | * We should be able to do the test below all the time, but | |
124 | * because the kernel doesn't forcibly clear the device | |
125 | * inode's additional i_block fields, there are some rare | |
126 | * occasions when a legitimate device inode will have non-zero | |
127 | * additional i_block fields. So for now, we only complain | |
128 | * when the immutable flag is set, which should never happen | |
129 | * for devices. (And that's when the problem is caused, since | |
130 | * you can't set or clear immutable flags for devices.) Once | |
131 | * the kernel has been fixed we can change this... | |
132 | */ | |
133 | if (inode->i_flags & EXT2_IMMUTABLE_FL) { | |
134 | for (i=4; i < EXT2_N_BLOCKS; i++) | |
135 | if (inode->i_block[i]) | |
136 | return 0; | |
137 | } | |
7cf73dcd TT |
138 | return 1; |
139 | } | |
140 | ||
08b21301 | 141 | void e2fsck_pass1(e2fsck_t ctx) |
3839e657 | 142 | { |
9d1bd3de TT |
143 | int i; |
144 | __u64 max_sizes; | |
1b6bf175 | 145 | ext2_filsys fs = ctx->fs; |
3839e657 TT |
146 | ino_t ino; |
147 | struct ext2_inode inode; | |
148 | ext2_inode_scan scan; | |
149 | char *block_buf; | |
8bf191e8 | 150 | #ifdef RESOURCE_TRACK |
3839e657 | 151 | struct resource_track rtrack; |
8bf191e8 | 152 | #endif |
1e3472c5 | 153 | unsigned char frag, fsize; |
21c84b71 | 154 | struct problem_context pctx; |
f8188fff | 155 | struct scan_callback_struct scan_struct; |
874b4d26 | 156 | struct ext2fs_sb *sb; |
3839e657 | 157 | |
8bf191e8 | 158 | #ifdef RESOURCE_TRACK |
3839e657 | 159 | init_resource_track(&rtrack); |
8bf191e8 | 160 | #endif |
1b6bf175 TT |
161 | clear_problem_context(&pctx); |
162 | ||
163 | if (!(ctx->options & E2F_OPT_PREEN)) | |
164 | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); | |
3839e657 TT |
165 | |
166 | #ifdef MTRACE | |
167 | mtrace_print("Pass 1"); | |
168 | #endif | |
169 | ||
9d1bd3de TT |
170 | #define EXT2_BPP(bits) (1UL << ((bits) - 2)) |
171 | ||
172 | for (i=0; i < 4; i++) { | |
173 | max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(10+i); | |
174 | max_sizes = max_sizes + EXT2_BPP(10+i) * EXT2_BPP(10+i); | |
175 | max_sizes = (max_sizes + | |
176 | (__u64) EXT2_BPP(10+i) * EXT2_BPP(10+i) * | |
177 | EXT2_BPP(10+i)); | |
178 | max_sizes = (max_sizes * (1UL << (10+i))) - 1; | |
179 | ext2_max_sizes[i] = max_sizes; | |
180 | } | |
181 | #undef EXT2_BPP | |
182 | ||
3839e657 TT |
183 | /* |
184 | * Allocate bitmaps structures | |
185 | */ | |
1b6bf175 TT |
186 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "in-use inode map", |
187 | &ctx->inode_used_map); | |
188 | if (pctx.errcode) { | |
189 | pctx.num = 1; | |
190 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
191 | ctx->flags |= E2F_FLAG_ABORT; |
192 | return; | |
3839e657 | 193 | } |
1b6bf175 TT |
194 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "directory inode map", |
195 | &ctx->inode_dir_map); | |
196 | if (pctx.errcode) { | |
197 | pctx.num = 2; | |
198 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
199 | ctx->flags |= E2F_FLAG_ABORT; |
200 | return; | |
3839e657 | 201 | } |
1b6bf175 TT |
202 | pctx.errcode = ext2fs_allocate_block_bitmap(fs, "in-use block map", |
203 | &ctx->block_found_map); | |
204 | if (pctx.errcode) { | |
205 | pctx.num = 1; | |
206 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
08b21301 TT |
207 | ctx->flags |= E2F_FLAG_ABORT; |
208 | return; | |
3839e657 | 209 | } |
1b6bf175 TT |
210 | pctx.errcode = ext2fs_allocate_block_bitmap(fs, "illegal block map", |
211 | &ctx->block_illegal_map); | |
212 | if (pctx.errcode) { | |
213 | pctx.num = 2; | |
214 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
08b21301 TT |
215 | ctx->flags |= E2F_FLAG_ABORT; |
216 | return; | |
50e1e10f | 217 | } |
1b6bf175 TT |
218 | pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, |
219 | &ctx->inode_link_info); | |
220 | if (pctx.errcode) { | |
221 | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); | |
08b21301 TT |
222 | ctx->flags |= E2F_FLAG_ABORT; |
223 | return; | |
21c84b71 | 224 | } |
54dc7ca2 TT |
225 | inodes_to_process = (struct process_inode_block *) |
226 | e2fsck_allocate_memory(ctx, | |
227 | (ctx->process_inode_size * | |
228 | sizeof(struct process_inode_block)), | |
229 | "array of inodes to process"); | |
3839e657 TT |
230 | process_inode_count = 0; |
231 | ||
1b6bf175 TT |
232 | pctx.errcode = ext2fs_init_dblist(fs, 0); |
233 | if (pctx.errcode) { | |
234 | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); | |
08b21301 TT |
235 | ctx->flags |= E2F_FLAG_ABORT; |
236 | return; | |
21c84b71 | 237 | } |
3839e657 | 238 | |
1b6bf175 | 239 | mark_table_blocks(ctx); |
54dc7ca2 TT |
240 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
241 | "block interate buffer"); | |
3839e657 TT |
242 | fs->get_blocks = pass1_get_blocks; |
243 | fs->check_directory = pass1_check_directory; | |
1e3472c5 TT |
244 | fs->read_inode = pass1_read_inode; |
245 | fs->write_inode = pass1_write_inode; | |
3839e657 | 246 | ehandler_operation("doing inode scan"); |
1b6bf175 TT |
247 | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
248 | &scan); | |
249 | if (pctx.errcode) { | |
250 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 TT |
251 | ctx->flags |= E2F_FLAG_ABORT; |
252 | return; | |
3839e657 | 253 | } |
21c84b71 | 254 | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); |
1b6bf175 TT |
255 | pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); |
256 | if (pctx.errcode) { | |
257 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 TT |
258 | ctx->flags |= E2F_FLAG_ABORT; |
259 | return; | |
3839e657 | 260 | } |
1b6bf175 | 261 | ctx->stashed_inode = &inode; |
f8188fff TT |
262 | scan_struct.ctx = ctx; |
263 | scan_struct.block_buf = block_buf; | |
264 | ext2fs_set_inode_callback(scan, scan_callback, &scan_struct); | |
265 | if (ctx->progress) | |
a02ce9df TT |
266 | if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count)) |
267 | return; | |
3839e657 | 268 | while (ino) { |
21c84b71 TT |
269 | pctx.ino = ino; |
270 | pctx.inode = &inode; | |
1b6bf175 TT |
271 | ctx->stashed_ino = ino; |
272 | if (inode.i_links_count) { | |
273 | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, | |
274 | ino, inode.i_links_count); | |
275 | if (pctx.errcode) { | |
276 | pctx.num = inode.i_links_count; | |
277 | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); | |
08b21301 TT |
278 | ctx->flags |= E2F_FLAG_ABORT; |
279 | return; | |
1b6bf175 TT |
280 | } |
281 | } | |
3839e657 TT |
282 | if (ino == EXT2_BAD_INO) { |
283 | struct process_block_struct pb; | |
284 | ||
285 | pb.ino = EXT2_BAD_INO; | |
286 | pb.num_blocks = pb.last_block = 0; | |
f3db3566 | 287 | pb.num_illegal_blocks = 0; |
21c84b71 | 288 | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
74becf3c | 289 | pb.fragmented = 0; |
f3db3566 | 290 | pb.inode = &inode; |
21c84b71 | 291 | pb.pctx = &pctx; |
1b6bf175 TT |
292 | pb.ctx = ctx; |
293 | pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, | |
294 | block_buf, process_bad_block, &pb); | |
295 | if (pctx.errcode) { | |
296 | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); | |
08b21301 TT |
297 | ctx->flags |= E2F_FLAG_ABORT; |
298 | return; | |
1b6bf175 TT |
299 | } |
300 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); | |
21c84b71 | 301 | clear_problem_context(&pctx); |
3839e657 TT |
302 | goto next; |
303 | } | |
304 | if (ino == EXT2_ROOT_INO) { | |
305 | /* | |
306 | * Make sure the root inode is a directory; if | |
307 | * not, offer to clear it. It will be | |
308 | * regnerated in pass #3. | |
309 | */ | |
50e1e10f | 310 | if (!LINUX_S_ISDIR(inode.i_mode)) { |
1b6bf175 | 311 | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) { |
3839e657 TT |
312 | inode.i_dtime = time(0); |
313 | inode.i_links_count = 0; | |
1b6bf175 | 314 | ext2fs_icount_store(ctx->inode_link_info, |
21c84b71 | 315 | ino, 0); |
08b21301 | 316 | e2fsck_write_inode(ctx, ino, &inode, |
f3db3566 | 317 | "pass1"); |
21c84b71 | 318 | } |
3839e657 TT |
319 | } |
320 | /* | |
321 | * If dtime is set, offer to clear it. mke2fs | |
322 | * version 0.2b created filesystems with the | |
323 | * dtime field set for the root and lost+found | |
324 | * directories. We won't worry about | |
325 | * /lost+found, since that can be regenerated | |
326 | * easily. But we will fix the root directory | |
327 | * as a special case. | |
328 | */ | |
329 | if (inode.i_dtime && inode.i_links_count) { | |
1b6bf175 | 330 | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
3839e657 | 331 | inode.i_dtime = 0; |
08b21301 | 332 | e2fsck_write_inode(ctx, ino, &inode, |
f3db3566 | 333 | "pass1"); |
21c84b71 | 334 | } |
3839e657 TT |
335 | } |
336 | } | |
7f88b043 TT |
337 | if ((ino != EXT2_ROOT_INO) && |
338 | (ino < EXT2_FIRST_INODE(fs->super))) { | |
1b6bf175 | 339 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
9d1bd3de TT |
340 | if (((ino == EXT2_BOOT_LOADER_INO) && |
341 | LINUX_S_ISDIR(inode.i_mode)) || | |
342 | ((ino != EXT2_BOOT_LOADER_INO) && | |
343 | (inode.i_mode != 0))) { | |
1b6bf175 | 344 | if (fix_problem(ctx, |
21c84b71 | 345 | PR_1_RESERVED_BAD_MODE, &pctx)) { |
50e1e10f | 346 | inode.i_mode = 0; |
08b21301 | 347 | e2fsck_write_inode(ctx, ino, &inode, |
50e1e10f | 348 | "pass1"); |
21c84b71 | 349 | } |
50e1e10f | 350 | } |
1b6bf175 | 351 | check_blocks(ctx, &pctx, block_buf); |
3839e657 TT |
352 | goto next; |
353 | } | |
354 | /* | |
355 | * This code assumes that deleted inodes have | |
356 | * i_links_count set to 0. | |
357 | */ | |
358 | if (!inode.i_links_count) { | |
359 | if (!inode.i_dtime && inode.i_mode) { | |
1b6bf175 | 360 | if (fix_problem(ctx, |
21c84b71 | 361 | PR_1_ZERO_DTIME, &pctx)) { |
3839e657 | 362 | inode.i_dtime = time(0); |
08b21301 | 363 | e2fsck_write_inode(ctx, ino, &inode, |
f3db3566 | 364 | "pass1"); |
21c84b71 | 365 | } |
3839e657 TT |
366 | } |
367 | goto next; | |
368 | } | |
369 | /* | |
1e3472c5 | 370 | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
3839e657 | 371 | * deleted files. Oops. |
1e3472c5 TT |
372 | * |
373 | * Since all new ext2 implementations get this right, | |
374 | * we now assume that the case of non-zero | |
375 | * i_links_count and non-zero dtime means that we | |
376 | * should keep the file, not delete it. | |
3839e657 | 377 | * |
3839e657 TT |
378 | */ |
379 | if (inode.i_dtime) { | |
1b6bf175 | 380 | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
1e3472c5 | 381 | inode.i_dtime = 0; |
08b21301 | 382 | e2fsck_write_inode(ctx, ino, &inode, "pass1"); |
21c84b71 | 383 | } |
3839e657 TT |
384 | } |
385 | ||
1b6bf175 | 386 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
1e3472c5 TT |
387 | switch (fs->super->s_creator_os) { |
388 | case EXT2_OS_LINUX: | |
389 | frag = inode.osd2.linux2.l_i_frag; | |
390 | fsize = inode.osd2.linux2.l_i_fsize; | |
391 | break; | |
392 | case EXT2_OS_HURD: | |
393 | frag = inode.osd2.hurd2.h_i_frag; | |
394 | fsize = inode.osd2.hurd2.h_i_fsize; | |
395 | break; | |
396 | case EXT2_OS_MASIX: | |
397 | frag = inode.osd2.masix2.m_i_frag; | |
398 | fsize = inode.osd2.masix2.m_i_fsize; | |
399 | break; | |
400 | default: | |
401 | frag = fsize = 0; | |
402 | } | |
403 | ||
404 | if (inode.i_faddr || frag || fsize | |
246501c6 TT |
405 | || inode.i_file_acl || |
406 | (LINUX_S_ISDIR(inode.i_mode) && inode.i_dir_acl)) { | |
1b6bf175 TT |
407 | if (!ctx->inode_bad_map) |
408 | alloc_bad_map(ctx); | |
409 | ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); | |
3839e657 TT |
410 | } |
411 | ||
50e1e10f | 412 | if (LINUX_S_ISDIR(inode.i_mode)) { |
1b6bf175 | 413 | ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); |
08b21301 | 414 | e2fsck_add_dir_info(ctx, ino, 0); |
1b6bf175 | 415 | ctx->fs_directory_count++; |
50e1e10f | 416 | } else if (LINUX_S_ISREG (inode.i_mode)) |
1b6bf175 | 417 | ctx->fs_regular_count++; |
7cf73dcd TT |
418 | else if (LINUX_S_ISCHR (inode.i_mode) && |
419 | e2fsck_pass1_check_device_inode(&inode)) | |
1b6bf175 | 420 | ctx->fs_chardev_count++; |
7cf73dcd TT |
421 | else if (LINUX_S_ISBLK (inode.i_mode) && |
422 | e2fsck_pass1_check_device_inode(&inode)) | |
1b6bf175 | 423 | ctx->fs_blockdev_count++; |
50e1e10f | 424 | else if (LINUX_S_ISLNK (inode.i_mode)) { |
1b6bf175 | 425 | ctx->fs_symlinks_count++; |
21c84b71 | 426 | if (!inode.i_blocks) { |
1b6bf175 | 427 | ctx->fs_fast_symlinks_count++; |
21c84b71 TT |
428 | goto next; |
429 | } | |
3839e657 | 430 | } |
1dde43f0 TT |
431 | else if (LINUX_S_ISFIFO (inode.i_mode) && |
432 | e2fsck_pass1_check_device_inode(&inode)) | |
1b6bf175 | 433 | ctx->fs_fifo_count++; |
1dde43f0 TT |
434 | else if ((LINUX_S_ISSOCK (inode.i_mode)) && |
435 | e2fsck_pass1_check_device_inode(&inode)) | |
1b6bf175 | 436 | ctx->fs_sockets_count++; |
3839e657 | 437 | else { |
1b6bf175 TT |
438 | if (!ctx->inode_bad_map) |
439 | alloc_bad_map(ctx); | |
440 | ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); | |
3839e657 | 441 | } |
50e1e10f | 442 | if (inode.i_block[EXT2_IND_BLOCK]) |
1b6bf175 | 443 | ctx->fs_ind_count++; |
50e1e10f | 444 | if (inode.i_block[EXT2_DIND_BLOCK]) |
1b6bf175 | 445 | ctx->fs_dind_count++; |
50e1e10f | 446 | if (inode.i_block[EXT2_TIND_BLOCK]) |
1b6bf175 | 447 | ctx->fs_tind_count++; |
3839e657 TT |
448 | if (inode.i_block[EXT2_IND_BLOCK] || |
449 | inode.i_block[EXT2_DIND_BLOCK] || | |
450 | inode.i_block[EXT2_TIND_BLOCK]) { | |
451 | inodes_to_process[process_inode_count].ino = ino; | |
452 | inodes_to_process[process_inode_count].inode = inode; | |
453 | process_inode_count++; | |
f3db3566 | 454 | } else |
1b6bf175 | 455 | check_blocks(ctx, &pctx, block_buf); |
3839e657 | 456 | |
a02ce9df | 457 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
458 | return; |
459 | ||
460 | if (process_inode_count >= ctx->process_inode_size) { | |
1b6bf175 | 461 | process_inodes(ctx, block_buf); |
08b21301 | 462 | |
a02ce9df | 463 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
464 | return; |
465 | } | |
3839e657 | 466 | next: |
1b6bf175 | 467 | pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); |
2df1f6aa TT |
468 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
469 | return; | |
1b6bf175 TT |
470 | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { |
471 | if (!ctx->inode_bb_map) | |
472 | alloc_bb_map(ctx); | |
473 | ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino); | |
474 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); | |
21c84b71 TT |
475 | goto next; |
476 | } | |
1b6bf175 TT |
477 | if (pctx.errcode) { |
478 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 TT |
479 | ctx->flags |= E2F_FLAG_ABORT; |
480 | return; | |
3839e657 TT |
481 | } |
482 | } | |
1b6bf175 | 483 | process_inodes(ctx, block_buf); |
3839e657 TT |
484 | ext2fs_close_inode_scan(scan); |
485 | ehandler_operation(0); | |
486 | ||
1b6bf175 TT |
487 | if (ctx->invalid_bitmaps) |
488 | handle_fs_bad_blocks(ctx); | |
f3db3566 | 489 | |
08b21301 | 490 | if (ctx->flags & E2F_FLAG_RESTART) { |
f3db3566 TT |
491 | unwind_pass1(fs); |
492 | goto endit; | |
493 | } | |
494 | ||
1b6bf175 TT |
495 | if (ctx->block_dup_map) { |
496 | if (ctx->options & E2F_OPT_PREEN) { | |
497 | clear_problem_context(&pctx); | |
498 | fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); | |
3839e657 | 499 | } |
08b21301 | 500 | e2fsck_pass1_dupblocks(ctx, block_buf); |
3839e657 | 501 | } |
08b21301 | 502 | ext2fs_free_mem((void **) &inodes_to_process); |
f3db3566 | 503 | endit: |
1e3472c5 TT |
504 | fs->get_blocks = 0; |
505 | fs->check_directory = 0; | |
506 | fs->read_inode = 0; | |
507 | fs->write_inode = 0; | |
508 | ||
08b21301 | 509 | ext2fs_free_mem((void **) &block_buf); |
1b6bf175 TT |
510 | ext2fs_free_block_bitmap(ctx->block_illegal_map); |
511 | ctx->block_illegal_map = 0; | |
21c84b71 | 512 | |
874b4d26 | 513 | sb = (struct ext2fs_sb *) fs->super; |
246501c6 | 514 | if (ctx->large_files && |
874b4d26 | 515 | !(sb->s_feature_ro_compat & |
246501c6 TT |
516 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { |
517 | if (fix_problem(ctx, PR_1_FEATURE_LARGE_FILES, &pctx)) { | |
874b4d26 | 518 | sb->s_feature_ro_compat |= |
246501c6 TT |
519 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE; |
520 | ext2fs_mark_super_dirty(fs); | |
521 | } | |
522 | } else if (!ctx->large_files && | |
874b4d26 | 523 | (sb->s_feature_ro_compat & |
246501c6 TT |
524 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { |
525 | if (fs->flags & EXT2_FLAG_RW) { | |
874b4d26 | 526 | sb->s_feature_ro_compat &= |
246501c6 TT |
527 | ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE; |
528 | ext2fs_mark_super_dirty(fs); | |
529 | } | |
530 | } | |
531 | ||
8bf191e8 | 532 | #ifdef RESOURCE_TRACK |
1b6bf175 TT |
533 | if (ctx->options & E2F_OPT_TIME2) |
534 | print_resource_track("Pass 1", &rtrack); | |
8bf191e8 | 535 | #endif |
3839e657 TT |
536 | } |
537 | ||
f3db3566 TT |
538 | /* |
539 | * When the inode_scan routines call this callback at the end of the | |
540 | * glock group, call process_inodes. | |
541 | */ | |
542 | static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, | |
54dc7ca2 | 543 | dgrp_t group, void * priv_data) |
f3db3566 | 544 | { |
54dc7ca2 | 545 | struct scan_callback_struct *scan_struct; |
f8188fff TT |
546 | e2fsck_t ctx; |
547 | ||
54dc7ca2 | 548 | scan_struct = (struct scan_callback_struct *) priv_data; |
f8188fff TT |
549 | ctx = scan_struct->ctx; |
550 | ||
54dc7ca2 | 551 | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
f8188fff TT |
552 | |
553 | if (ctx->progress) | |
a02ce9df TT |
554 | if ((ctx->progress)(ctx, 1, group+1, |
555 | ctx->fs->group_desc_count)) | |
556 | return EXT2_ET_CANCEL_REQUESTED; | |
f8188fff | 557 | |
f3db3566 TT |
558 | return 0; |
559 | } | |
560 | ||
3839e657 TT |
561 | /* |
562 | * Process the inodes in the "inodes to process" list. | |
563 | */ | |
1b6bf175 | 564 | static void process_inodes(e2fsck_t ctx, char *block_buf) |
3839e657 TT |
565 | { |
566 | int i; | |
567 | struct ext2_inode *old_stashed_inode; | |
21c84b71 | 568 | ino_t old_stashed_ino; |
3839e657 TT |
569 | const char *old_operation; |
570 | char buf[80]; | |
21c84b71 TT |
571 | struct problem_context pctx; |
572 | ||
3839e657 | 573 | #if 0 |
f3db3566 | 574 | printf("begin process_inodes: "); |
3839e657 TT |
575 | #endif |
576 | old_operation = ehandler_operation(0); | |
1b6bf175 TT |
577 | old_stashed_inode = ctx->stashed_inode; |
578 | old_stashed_ino = ctx->stashed_ino; | |
3839e657 TT |
579 | qsort(inodes_to_process, process_inode_count, |
580 | sizeof(struct process_inode_block), process_inode_cmp); | |
21c84b71 | 581 | clear_problem_context(&pctx); |
3839e657 | 582 | for (i=0; i < process_inode_count; i++) { |
1b6bf175 TT |
583 | pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; |
584 | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; | |
21c84b71 | 585 | |
3839e657 | 586 | #if 0 |
21c84b71 | 587 | printf("%u ", pctx.ino); |
3839e657 | 588 | #endif |
21c84b71 | 589 | sprintf(buf, "reading indirect blocks of inode %lu", pctx.ino); |
3839e657 | 590 | ehandler_operation(buf); |
1b6bf175 | 591 | check_blocks(ctx, &pctx, block_buf); |
a02ce9df | 592 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2df1f6aa | 593 | break; |
3839e657 | 594 | } |
1b6bf175 TT |
595 | ctx->stashed_inode = old_stashed_inode; |
596 | ctx->stashed_ino = old_stashed_ino; | |
3839e657 TT |
597 | process_inode_count = 0; |
598 | #if 0 | |
f3db3566 | 599 | printf("end process inodes\n"); |
3839e657 TT |
600 | #endif |
601 | ehandler_operation(old_operation); | |
602 | } | |
603 | ||
4c77fe50 | 604 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) |
3839e657 TT |
605 | { |
606 | const struct process_inode_block *ib_a = | |
607 | (const struct process_inode_block *) a; | |
608 | const struct process_inode_block *ib_b = | |
609 | (const struct process_inode_block *) b; | |
610 | ||
611 | return (ib_a->inode.i_block[EXT2_IND_BLOCK] - | |
612 | ib_b->inode.i_block[EXT2_IND_BLOCK]); | |
613 | } | |
614 | ||
3839e657 TT |
615 | /* |
616 | * This procedure will allocate the inode bad map table | |
617 | */ | |
1b6bf175 | 618 | static void alloc_bad_map(e2fsck_t ctx) |
3839e657 | 619 | { |
1b6bf175 TT |
620 | struct problem_context pctx; |
621 | ||
622 | clear_problem_context(&pctx); | |
3839e657 | 623 | |
1b6bf175 TT |
624 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, "bad inode map", |
625 | &ctx->inode_bad_map); | |
626 | if (pctx.errcode) { | |
627 | pctx.num = 3; | |
628 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
629 | /* Should never get here */ |
630 | ctx->flags |= E2F_FLAG_ABORT; | |
631 | return; | |
3839e657 TT |
632 | } |
633 | } | |
634 | ||
21c84b71 TT |
635 | /* |
636 | * This procedure will allocate the inode "bb" (badblock) map table | |
637 | */ | |
1b6bf175 | 638 | static void alloc_bb_map(e2fsck_t ctx) |
21c84b71 | 639 | { |
1b6bf175 | 640 | struct problem_context pctx; |
21c84b71 | 641 | |
1b6bf175 TT |
642 | clear_problem_context(&pctx); |
643 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, | |
644 | "inode in bad block map", | |
645 | &ctx->inode_bb_map); | |
646 | if (pctx.errcode) { | |
647 | pctx.num = 4; | |
648 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
649 | /* Should never get here */ |
650 | ctx->flags |= E2F_FLAG_ABORT; | |
651 | return; | |
21c84b71 TT |
652 | } |
653 | } | |
654 | ||
3839e657 TT |
655 | /* |
656 | * Marks a block as in use, setting the dup_map if it's been set | |
657 | * already. Called by process_block and process_bad_block. | |
50e1e10f TT |
658 | * |
659 | * WARNING: Assumes checks have already been done to make sure block | |
660 | * is valid. This is true in both process_block and process_bad_block. | |
3839e657 | 661 | */ |
1b6bf175 | 662 | static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block) |
3839e657 | 663 | { |
1b6bf175 TT |
664 | struct problem_context pctx; |
665 | ||
666 | clear_problem_context(&pctx); | |
3839e657 | 667 | |
1b6bf175 TT |
668 | if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) { |
669 | if (!ctx->block_dup_map) { | |
670 | pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs, | |
671 | "multiply claimed block map", | |
672 | &ctx->block_dup_map); | |
673 | if (pctx.errcode) { | |
674 | pctx.num = 3; | |
675 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, | |
676 | &pctx); | |
08b21301 TT |
677 | /* Should never get here */ |
678 | ctx->flags |= E2F_FLAG_ABORT; | |
679 | return; | |
3839e657 TT |
680 | } |
681 | } | |
1b6bf175 | 682 | ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block); |
3839e657 | 683 | } else { |
1b6bf175 | 684 | ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block); |
3839e657 TT |
685 | } |
686 | } | |
687 | ||
688 | /* | |
689 | * This subroutine is called on each inode to account for all of the | |
690 | * blocks used by that inode. | |
691 | */ | |
1b6bf175 | 692 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 TT |
693 | char *block_buf) |
694 | { | |
1b6bf175 | 695 | ext2_filsys fs = ctx->fs; |
3839e657 | 696 | struct process_block_struct pb; |
21c84b71 TT |
697 | ino_t ino = pctx->ino; |
698 | struct ext2_inode *inode = pctx->inode; | |
246501c6 TT |
699 | int bad_size = 0; |
700 | __u64 size; | |
701 | struct ext2fs_sb *sb; | |
3839e657 | 702 | |
21c84b71 | 703 | if (!ext2fs_inode_has_valid_blocks(pctx->inode)) |
3839e657 TT |
704 | return; |
705 | ||
706 | pb.ino = ino; | |
707 | pb.num_blocks = pb.last_block = 0; | |
f3db3566 | 708 | pb.num_illegal_blocks = 0; |
21c84b71 | 709 | pb.suppress = 0; pb.clear = 0; |
74becf3c TT |
710 | pb.fragmented = 0; |
711 | pb.previous_block = 0; | |
21c84b71 | 712 | pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode); |
f3db3566 | 713 | pb.inode = inode; |
21c84b71 | 714 | pb.pctx = pctx; |
1b6bf175 TT |
715 | pb.ctx = ctx; |
716 | pctx->ino = ino; | |
717 | pctx->errcode = ext2fs_block_iterate2(fs, ino, | |
21c84b71 TT |
718 | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
719 | block_buf, process_block, &pb); | |
a02ce9df | 720 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 721 | return; |
1b6bf175 TT |
722 | end_problem_latch(ctx, PR_LATCH_BLOCK); |
723 | if (pctx->errcode) | |
724 | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); | |
3839e657 | 725 | |
74becf3c | 726 | if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) |
1b6bf175 | 727 | ctx->fs_fragmented++; |
74becf3c | 728 | |
f3db3566 | 729 | if (pb.clear) { |
08b21301 | 730 | e2fsck_read_inode(ctx, ino, inode, "check_blocks"); |
f3db3566 | 731 | inode->i_links_count = 0; |
1b6bf175 | 732 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
f3db3566 | 733 | inode->i_dtime = time(0); |
08b21301 | 734 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); |
1b6bf175 TT |
735 | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
736 | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); | |
f3db3566 TT |
737 | /* |
738 | * The inode was probably partially accounted for | |
739 | * before processing was aborted, so we need to | |
740 | * restart the pass 1 scan. | |
741 | */ | |
08b21301 | 742 | ctx->flags |= E2F_FLAG_RESTART; |
f3db3566 TT |
743 | return; |
744 | } | |
745 | ||
3839e657 TT |
746 | pb.num_blocks *= (fs->blocksize / 512); |
747 | #if 0 | |
246501c6 | 748 | printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n", |
3839e657 TT |
749 | ino, inode->i_size, pb.last_block, inode->i_blocks, |
750 | pb.num_blocks); | |
751 | #endif | |
752 | if (!pb.num_blocks && pb.is_dir) { | |
1b6bf175 | 753 | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
3839e657 | 754 | inode->i_links_count = 0; |
1b6bf175 | 755 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
3839e657 | 756 | inode->i_dtime = time(0); |
08b21301 | 757 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); |
1b6bf175 TT |
758 | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
759 | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); | |
760 | ctx->fs_directory_count--; | |
50e1e10f | 761 | pb.is_dir = 0; |
21c84b71 | 762 | } |
3839e657 | 763 | } |
246501c6 TT |
764 | if (pb.is_dir) { |
765 | int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); | |
766 | if ((nblock > (pb.last_block + 1)) || | |
767 | ((inode->i_size & (fs->blocksize-1)) != 0)) | |
768 | bad_size = 1; | |
769 | else if (nblock < (pb.last_block + 1)) { | |
770 | sb = (struct ext2fs_sb *) fs->super; | |
771 | if (((pb.last_block + 1) - nblock) > | |
772 | sb->s_prealloc_dir_blocks) | |
9d1bd3de | 773 | bad_size = 2; |
246501c6 TT |
774 | } |
775 | } else { | |
776 | size = inode->i_size + ((__u64) inode->i_size_high << 32); | |
777 | if ((size < pb.last_block * fs->blocksize)) | |
9d1bd3de | 778 | bad_size = 3; |
246501c6 | 779 | else if (size > ext2_max_sizes[fs->super->s_log_block_size]) |
9d1bd3de | 780 | bad_size = 4; |
246501c6 TT |
781 | } |
782 | if (bad_size) { | |
21c84b71 | 783 | pctx->num = (pb.last_block+1) * fs->blocksize; |
1b6bf175 | 784 | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
21c84b71 | 785 | inode->i_size = pctx->num; |
246501c6 TT |
786 | if (!pb.is_dir) |
787 | inode->i_size_high = pctx->num >> 32; | |
08b21301 | 788 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); |
21c84b71 TT |
789 | } |
790 | pctx->num = 0; | |
3839e657 | 791 | } |
246501c6 TT |
792 | if (!pb.is_dir && inode->i_size_high) |
793 | ctx->large_files++; | |
3839e657 | 794 | if (pb.num_blocks != inode->i_blocks) { |
21c84b71 | 795 | pctx->num = pb.num_blocks; |
1b6bf175 | 796 | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
3839e657 | 797 | inode->i_blocks = pb.num_blocks; |
08b21301 | 798 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); |
21c84b71 TT |
799 | } |
800 | pctx->num = 0; | |
3839e657 | 801 | } |
50e1e10f TT |
802 | } |
803 | ||
21c84b71 | 804 | #if 0 |
50e1e10f TT |
805 | /* |
806 | * Helper function called by process block when an illegal block is | |
807 | * found. It returns a description about why the block is illegal | |
808 | */ | |
809 | static char *describe_illegal_block(ext2_filsys fs, blk_t block) | |
810 | { | |
811 | blk_t super; | |
812 | int i; | |
813 | static char problem[80]; | |
814 | ||
815 | super = fs->super->s_first_data_block; | |
816 | strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block"); | |
817 | if (block < super) { | |
818 | sprintf(problem, "< FIRSTBLOCK (%u)", super); | |
819 | return(problem); | |
820 | } else if (block >= fs->super->s_blocks_count) { | |
821 | sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count); | |
822 | return(problem); | |
823 | } | |
824 | for (i = 0; i < fs->group_desc_count; i++) { | |
825 | if (block == super) { | |
826 | sprintf(problem, "is the superblock in group %d", i); | |
827 | break; | |
828 | } | |
829 | if (block > super && | |
830 | block <= (super + fs->desc_blocks)) { | |
831 | sprintf(problem, "is in the group descriptors " | |
832 | "of group %d", i); | |
833 | break; | |
834 | } | |
835 | if (block == fs->group_desc[i].bg_block_bitmap) { | |
836 | sprintf(problem, "is the block bitmap of group %d", i); | |
837 | break; | |
838 | } | |
839 | if (block == fs->group_desc[i].bg_inode_bitmap) { | |
840 | sprintf(problem, "is the inode bitmap of group %d", i); | |
841 | break; | |
842 | } | |
843 | if (block >= fs->group_desc[i].bg_inode_table && | |
844 | (block < fs->group_desc[i].bg_inode_table | |
845 | + fs->inode_blocks_per_group)) { | |
846 | sprintf(problem, "is in the inode table of group %d", | |
847 | i); | |
848 | break; | |
849 | } | |
850 | super += fs->super->s_blocks_per_group; | |
851 | } | |
852 | return(problem); | |
853 | } | |
21c84b71 | 854 | #endif |
3839e657 TT |
855 | |
856 | /* | |
857 | * This is a helper function for check_blocks(). | |
858 | */ | |
859 | int process_block(ext2_filsys fs, | |
860 | blk_t *block_nr, | |
9d1bd3de | 861 | e2_blkcnt_t blockcnt, |
21c84b71 TT |
862 | blk_t ref_block, |
863 | int ref_offset, | |
54dc7ca2 | 864 | void *priv_data) |
3839e657 TT |
865 | { |
866 | struct process_block_struct *p; | |
21c84b71 | 867 | struct problem_context *pctx; |
3839e657 | 868 | blk_t blk = *block_nr; |
50e1e10f | 869 | int ret_code = 0; |
21c84b71 | 870 | int problem = 0; |
1b6bf175 | 871 | e2fsck_t ctx; |
3839e657 | 872 | |
54dc7ca2 | 873 | p = (struct process_block_struct *) priv_data; |
21c84b71 | 874 | pctx = p->pctx; |
1b6bf175 | 875 | ctx = p->ctx; |
3839e657 | 876 | |
50e1e10f TT |
877 | if (blk == 0) { |
878 | if (p->is_dir == 0) { | |
1e3472c5 TT |
879 | /* |
880 | * Should never happen, since only directories | |
881 | * get called with BLOCK_FLAG_HOLE | |
882 | */ | |
1b6bf175 | 883 | #if DEBUG_E2FSCK |
50e1e10f | 884 | printf("process_block() called with blk == 0, " |
5c576477 TT |
885 | "blockcnt=%d, inode %lu???\n", |
886 | blockcnt, p->ino); | |
1b6bf175 | 887 | #endif |
50e1e10f TT |
888 | return 0; |
889 | } | |
890 | if (blockcnt < 0) | |
891 | return 0; | |
892 | if (blockcnt * fs->blocksize < p->inode->i_size) { | |
21c84b71 TT |
893 | #if 0 |
894 | printf("Missing block (#%d) in directory inode %lu!\n", | |
895 | blockcnt, p->ino); | |
896 | #endif | |
50e1e10f TT |
897 | goto mark_dir; |
898 | } | |
899 | return 0; | |
900 | } | |
901 | ||
3839e657 | 902 | #if 0 |
50e1e10f | 903 | printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk, |
3839e657 | 904 | blockcnt); |
50e1e10f | 905 | #endif |
3839e657 | 906 | |
74becf3c TT |
907 | /* |
908 | * Simplistic fragmentation check. We merely require that the | |
909 | * file be contiguous. (Which can never be true for really | |
910 | * big files that are greater than a block group.) | |
911 | */ | |
912 | if (p->previous_block) { | |
913 | if (p->previous_block+1 != blk) | |
914 | p->fragmented = 1; | |
915 | } | |
916 | p->previous_block = blk; | |
917 | ||
50e1e10f | 918 | if (blk < fs->super->s_first_data_block || |
21c84b71 TT |
919 | blk >= fs->super->s_blocks_count) |
920 | problem = PR_1_ILLEGAL_BLOCK_NUM; | |
521e3685 TT |
921 | #if 0 |
922 | else | |
923 | if (ext2fs_test_block_bitmap(block_illegal_map, blk)) | |
924 | problem = PR_1_BLOCK_OVERLAPS_METADATA; | |
925 | #endif | |
21c84b71 TT |
926 | |
927 | if (problem) { | |
f3db3566 | 928 | p->num_illegal_blocks++; |
21c84b71 | 929 | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
1b6bf175 | 930 | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
f3db3566 TT |
931 | p->clear = 1; |
932 | return BLOCK_ABORT; | |
933 | } | |
f8188fff | 934 | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
f3db3566 | 935 | p->suppress = 1; |
1b6bf175 TT |
936 | set_latch_flags(PR_LATCH_BLOCK, |
937 | PRL_SUPPRESS, 0); | |
f3db3566 TT |
938 | } |
939 | } | |
21c84b71 TT |
940 | pctx->blk = blk; |
941 | pctx->blkcount = blockcnt; | |
1b6bf175 | 942 | if (fix_problem(ctx, problem, pctx)) { |
50e1e10f TT |
943 | blk = *block_nr = 0; |
944 | ret_code = BLOCK_CHANGED; | |
945 | goto mark_dir; | |
21c84b71 | 946 | } else |
3839e657 | 947 | return 0; |
21c84b71 TT |
948 | pctx->blk = 0; |
949 | pctx->blkcount = -1; | |
3839e657 TT |
950 | } |
951 | ||
1b6bf175 | 952 | mark_block_used(ctx, blk); |
50e1e10f | 953 | p->num_blocks++; |
1e3472c5 TT |
954 | if (blockcnt >= 0) |
955 | p->last_block = blockcnt; | |
50e1e10f | 956 | mark_dir: |
1e3472c5 | 957 | if (p->is_dir && (blockcnt >= 0)) { |
1b6bf175 TT |
958 | pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino, |
959 | blk, blockcnt); | |
960 | if (pctx->errcode) { | |
961 | pctx->blk = blk; | |
962 | pctx->num = blockcnt; | |
963 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); | |
08b21301 TT |
964 | /* Should never get here */ |
965 | ctx->flags |= E2F_FLAG_ABORT; | |
966 | return BLOCK_ABORT; | |
3839e657 | 967 | } |
3839e657 | 968 | } |
50e1e10f | 969 | return ret_code; |
3839e657 TT |
970 | } |
971 | ||
1b6bf175 | 972 | static void bad_block_indirect(e2fsck_t ctx, blk_t blk) |
f3db3566 | 973 | { |
1b6bf175 | 974 | struct problem_context pctx; |
f3db3566 | 975 | |
1b6bf175 TT |
976 | clear_problem_context(&pctx); |
977 | /* | |
978 | * Prompt to see if we should continue or not. | |
979 | */ | |
980 | if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, &pctx)) | |
08b21301 | 981 | ctx->flags |= E2F_FLAG_ABORT; |
50e1e10f TT |
982 | } |
983 | ||
3839e657 TT |
984 | int process_bad_block(ext2_filsys fs, |
985 | blk_t *block_nr, | |
9d1bd3de | 986 | e2_blkcnt_t blockcnt, |
21c84b71 TT |
987 | blk_t ref_block, |
988 | int ref_offset, | |
54dc7ca2 | 989 | void *priv_data) |
3839e657 TT |
990 | { |
991 | struct process_block_struct *p; | |
3839e657 | 992 | blk_t blk = *block_nr; |
f3db3566 TT |
993 | int first_block; |
994 | int i; | |
21c84b71 | 995 | struct problem_context *pctx; |
1b6bf175 | 996 | e2fsck_t ctx; |
21c84b71 | 997 | |
3839e657 TT |
998 | if (!blk) |
999 | return 0; | |
21c84b71 | 1000 | |
54dc7ca2 | 1001 | p = (struct process_block_struct *) priv_data; |
1b6bf175 | 1002 | ctx = p->ctx; |
21c84b71 TT |
1003 | pctx = p->pctx; |
1004 | ||
f8188fff | 1005 | pctx->ino = EXT2_BAD_INO; |
21c84b71 TT |
1006 | pctx->blk = blk; |
1007 | pctx->blkcount = blockcnt; | |
3839e657 TT |
1008 | |
1009 | if ((blk < fs->super->s_first_data_block) || | |
1010 | (blk >= fs->super->s_blocks_count)) { | |
1b6bf175 | 1011 | if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { |
3839e657 TT |
1012 | *block_nr = 0; |
1013 | return BLOCK_CHANGED; | |
21c84b71 | 1014 | } else |
3839e657 | 1015 | return 0; |
3839e657 TT |
1016 | } |
1017 | ||
1018 | if (blockcnt < 0) { | |
08b21301 | 1019 | if (ext2fs_test_block_bitmap(ctx->block_found_map, blk)) { |
1b6bf175 | 1020 | bad_block_indirect(ctx, blk); |
a02ce9df | 1021 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
1022 | return BLOCK_ABORT; |
1023 | } else | |
1b6bf175 | 1024 | mark_block_used(ctx, blk); |
3839e657 TT |
1025 | return 0; |
1026 | } | |
1027 | #if 0 | |
50e1e10f | 1028 | printf ("DEBUG: Marking %u as bad.\n", blk); |
3839e657 | 1029 | #endif |
1b6bf175 | 1030 | ctx->fs_badblocks_count++; |
3839e657 TT |
1031 | /* |
1032 | * If the block is not used, then mark it as used and return. | |
1033 | * If it is already marked as found, this must mean that | |
1034 | * there's an overlap between the filesystem table blocks | |
1035 | * (bitmaps and inode table) and the bad block list. | |
1036 | */ | |
1b6bf175 TT |
1037 | if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) { |
1038 | ext2fs_mark_block_bitmap(ctx->block_found_map, blk); | |
3839e657 TT |
1039 | return 0; |
1040 | } | |
f3db3566 TT |
1041 | /* |
1042 | * Try to find the where the filesystem block was used... | |
1043 | */ | |
1044 | first_block = fs->super->s_first_data_block; | |
1045 | ||
1046 | for (i = 0; i < fs->group_desc_count; i++ ) { | |
21c84b71 | 1047 | pctx->group = i; |
1b6bf175 | 1048 | pctx->blk = blk; |
8039c480 TT |
1049 | if (!ext2fs_bg_has_super(fs, i)) |
1050 | goto skip_super; | |
f3db3566 TT |
1051 | if (blk == first_block) { |
1052 | if (i == 0) { | |
1b6bf175 TT |
1053 | if (fix_problem(ctx, |
1054 | PR_1_BAD_PRIMARY_SUPERBLOCK, | |
1055 | pctx)) { | |
1056 | *block_nr = 0; | |
50e1e10f | 1057 | return BLOCK_CHANGED; |
1b6bf175 | 1058 | } |
50e1e10f | 1059 | return 0; |
f3db3566 | 1060 | } |
1b6bf175 | 1061 | fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); |
f3db3566 TT |
1062 | return 0; |
1063 | } | |
1064 | if ((blk > first_block) && | |
1065 | (blk <= first_block + fs->desc_blocks)) { | |
1066 | if (i == 0) { | |
1b6bf175 TT |
1067 | pctx->blk = *block_nr; |
1068 | if (fix_problem(ctx, | |
1069 | PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { | |
1070 | *block_nr = 0; | |
50e1e10f | 1071 | return BLOCK_CHANGED; |
1b6bf175 | 1072 | } |
50e1e10f | 1073 | return 0; |
f3db3566 | 1074 | } |
1b6bf175 | 1075 | fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); |
f3db3566 | 1076 | return 0; |
3839e657 | 1077 | } |
8039c480 | 1078 | skip_super: |
f3db3566 | 1079 | if (blk == fs->group_desc[i].bg_block_bitmap) { |
1b6bf175 TT |
1080 | if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { |
1081 | ctx->invalid_block_bitmap_flag[i]++; | |
1082 | ctx->invalid_bitmaps++; | |
21c84b71 | 1083 | } |
f3db3566 TT |
1084 | return 0; |
1085 | } | |
1086 | if (blk == fs->group_desc[i].bg_inode_bitmap) { | |
1b6bf175 TT |
1087 | if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { |
1088 | ctx->invalid_inode_bitmap_flag[i]++; | |
1089 | ctx->invalid_bitmaps++; | |
21c84b71 | 1090 | } |
f3db3566 TT |
1091 | return 0; |
1092 | } | |
1093 | if ((blk >= fs->group_desc[i].bg_inode_table) && | |
1094 | (blk < (fs->group_desc[i].bg_inode_table + | |
1095 | fs->inode_blocks_per_group))) { | |
21c84b71 TT |
1096 | /* |
1097 | * If there are bad blocks in the inode table, | |
1098 | * the inode scan code will try to do | |
1099 | * something reasonable automatically. | |
1100 | */ | |
f3db3566 TT |
1101 | return 0; |
1102 | } | |
8039c480 | 1103 | first_block += fs->super->s_blocks_per_group; |
f3db3566 TT |
1104 | } |
1105 | /* | |
1106 | * If we've gotten to this point, then the only | |
1107 | * possibility is that the bad block inode meta data | |
1108 | * is using a bad block. | |
1109 | */ | |
1110 | if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) || | |
1111 | p->inode->i_block[EXT2_DIND_BLOCK]) { | |
1b6bf175 | 1112 | bad_block_indirect(ctx, blk); |
a02ce9df | 1113 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 1114 | return BLOCK_ABORT; |
f3db3566 | 1115 | return 0; |
3839e657 | 1116 | } |
1b6bf175 TT |
1117 | |
1118 | pctx->group = -1; | |
1119 | ||
1120 | /* Warn user that the block wasn't claimed */ | |
1121 | fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx); | |
1122 | ||
f3db3566 | 1123 | return 0; |
3839e657 TT |
1124 | } |
1125 | ||
1b6bf175 | 1126 | static void new_table_block(e2fsck_t ctx, blk_t first_block, int group, |
3839e657 TT |
1127 | const char *name, int num, blk_t *new_block) |
1128 | { | |
1b6bf175 | 1129 | ext2_filsys fs = ctx->fs; |
3839e657 TT |
1130 | blk_t old_block = *new_block; |
1131 | int i; | |
1132 | char *buf; | |
1b6bf175 TT |
1133 | struct problem_context pctx; |
1134 | ||
1135 | clear_problem_context(&pctx); | |
1136 | ||
1137 | pctx.group = group; | |
1138 | pctx.blk = old_block; | |
1139 | pctx.str = name; | |
1140 | ||
1141 | pctx.errcode = ext2fs_get_free_blocks(fs, first_block, | |
3839e657 | 1142 | first_block + fs->super->s_blocks_per_group, |
1b6bf175 TT |
1143 | num, ctx->block_found_map, new_block); |
1144 | if (pctx.errcode) { | |
1145 | pctx.num = num; | |
1146 | fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); | |
3839e657 TT |
1147 | ext2fs_unmark_valid(fs); |
1148 | return; | |
1149 | } | |
08b21301 TT |
1150 | pctx.errcode = ext2fs_get_mem(fs->blocksize, (void **) &buf); |
1151 | if (pctx.errcode) { | |
1b6bf175 | 1152 | fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); |
3839e657 TT |
1153 | ext2fs_unmark_valid(fs); |
1154 | return; | |
1155 | } | |
1156 | ext2fs_mark_super_dirty(fs); | |
1b6bf175 TT |
1157 | pctx.blk2 = *new_block; |
1158 | fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO : | |
1159 | PR_1_RELOC_TO), &pctx); | |
1160 | pctx.blk2 = 0; | |
3839e657 | 1161 | for (i = 0; i < num; i++) { |
1b6bf175 TT |
1162 | pctx.blk = i; |
1163 | ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i); | |
f3db3566 | 1164 | if (old_block) { |
1b6bf175 TT |
1165 | pctx.errcode = io_channel_read_blk(fs->io, |
1166 | old_block + i, 1, buf); | |
1167 | if (pctx.errcode) | |
1168 | fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); | |
f3db3566 TT |
1169 | } else |
1170 | memset(buf, 0, fs->blocksize); | |
1171 | ||
1b6bf175 TT |
1172 | pctx.blk = (*new_block) + i; |
1173 | pctx.errcode = io_channel_write_blk(fs->io, pctx.blk, | |
3839e657 | 1174 | 1, buf); |
1b6bf175 TT |
1175 | if (pctx.errcode) |
1176 | fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); | |
3839e657 | 1177 | } |
08b21301 | 1178 | ext2fs_free_mem((void **) &buf); |
3839e657 TT |
1179 | } |
1180 | ||
1181 | /* | |
f3db3566 TT |
1182 | * This routine gets called at the end of pass 1 if bad blocks are |
1183 | * detected in the superblock, group descriptors, inode_bitmaps, or | |
1184 | * block bitmaps. At this point, all of the blocks have been mapped | |
1185 | * out, so we can try to allocate new block(s) to replace the bad | |
1186 | * blocks. | |
3839e657 | 1187 | */ |
1b6bf175 | 1188 | static void handle_fs_bad_blocks(e2fsck_t ctx) |
3839e657 | 1189 | { |
1b6bf175 | 1190 | ext2_filsys fs = ctx->fs; |
f3db3566 TT |
1191 | int i; |
1192 | int first_block = fs->super->s_first_data_block; | |
3839e657 TT |
1193 | |
1194 | for (i = 0; i < fs->group_desc_count; i++) { | |
1b6bf175 TT |
1195 | if (ctx->invalid_block_bitmap_flag[i]) { |
1196 | new_table_block(ctx, first_block, i, "block bitmap", | |
1197 | 1, &fs->group_desc[i].bg_block_bitmap); | |
3839e657 | 1198 | } |
1b6bf175 TT |
1199 | if (ctx->invalid_inode_bitmap_flag[i]) { |
1200 | new_table_block(ctx, first_block, i, "inode bitmap", | |
1201 | 1, &fs->group_desc[i].bg_inode_bitmap); | |
3839e657 | 1202 | } |
1b6bf175 TT |
1203 | if (ctx->invalid_inode_table_flag[i]) { |
1204 | new_table_block(ctx, first_block, i, "inode table", | |
f3db3566 | 1205 | fs->inode_blocks_per_group, |
3839e657 | 1206 | &fs->group_desc[i].bg_inode_table); |
08b21301 | 1207 | ctx->flags |= E2F_FLAG_RESTART; |
3839e657 | 1208 | } |
3839e657 TT |
1209 | first_block += fs->super->s_blocks_per_group; |
1210 | } | |
1b6bf175 | 1211 | ctx->invalid_bitmaps = 0; |
3839e657 TT |
1212 | } |
1213 | ||
1214 | /* | |
1215 | * This routine marks all blocks which are used by the superblock, | |
1216 | * group descriptors, inode bitmaps, and block bitmaps. | |
1217 | */ | |
1b6bf175 | 1218 | static void mark_table_blocks(e2fsck_t ctx) |
3839e657 | 1219 | { |
1b6bf175 | 1220 | ext2_filsys fs = ctx->fs; |
f3db3566 | 1221 | blk_t block, b; |
3839e657 | 1222 | int i,j; |
21c84b71 TT |
1223 | struct problem_context pctx; |
1224 | ||
1225 | clear_problem_context(&pctx); | |
3839e657 TT |
1226 | |
1227 | block = fs->super->s_first_data_block; | |
1228 | for (i = 0; i < fs->group_desc_count; i++) { | |
21c84b71 | 1229 | pctx.group = i; |
da2e97f7 TT |
1230 | |
1231 | if (ext2fs_bg_has_super(fs, i)) { | |
1232 | /* | |
1233 | * Mark this group's copy of the superblock | |
1234 | */ | |
1b6bf175 TT |
1235 | ext2fs_mark_block_bitmap(ctx->block_found_map, block); |
1236 | ext2fs_mark_block_bitmap(ctx->block_illegal_map, | |
1237 | block); | |
da2e97f7 TT |
1238 | |
1239 | /* | |
1240 | * Mark this group's copy of the descriptors | |
1241 | */ | |
1242 | for (j = 0; j < fs->desc_blocks; j++) { | |
1b6bf175 | 1243 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
da2e97f7 | 1244 | block + j + 1); |
1b6bf175 | 1245 | ext2fs_mark_block_bitmap(ctx->block_illegal_map, |
da2e97f7 TT |
1246 | block + j + 1); |
1247 | } | |
1248 | } | |
1249 | ||
21c84b71 TT |
1250 | /* |
1251 | * Mark the blocks used for the inode table | |
1252 | */ | |
1253 | if (fs->group_desc[i].bg_inode_table) { | |
1254 | for (j = 0, b = fs->group_desc[i].bg_inode_table; | |
1255 | j < fs->inode_blocks_per_group; | |
1256 | j++, b++) { | |
1b6bf175 | 1257 | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
21c84b71 TT |
1258 | b)) { |
1259 | pctx.blk = b; | |
1b6bf175 | 1260 | if (fix_problem(ctx, |
21c84b71 | 1261 | PR_1_ITABLE_CONFLICT, &pctx)) { |
1b6bf175 TT |
1262 | ctx->invalid_inode_table_flag[i]++; |
1263 | ctx->invalid_bitmaps++; | |
21c84b71 TT |
1264 | } |
1265 | } else { | |
1b6bf175 | 1266 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
21c84b71 | 1267 | b); |
1b6bf175 | 1268 | ext2fs_mark_block_bitmap(ctx->block_illegal_map, |
21c84b71 TT |
1269 | b); |
1270 | } | |
1271 | } | |
1272 | } | |
1273 | ||
3839e657 TT |
1274 | /* |
1275 | * Mark block used for the block bitmap | |
1276 | */ | |
f3db3566 | 1277 | if (fs->group_desc[i].bg_block_bitmap) { |
1b6bf175 | 1278 | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
f3db3566 | 1279 | fs->group_desc[i].bg_block_bitmap)) { |
21c84b71 | 1280 | pctx.blk = fs->group_desc[i].bg_block_bitmap; |
1b6bf175 TT |
1281 | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
1282 | ctx->invalid_block_bitmap_flag[i]++; | |
1283 | ctx->invalid_bitmaps++; | |
f3db3566 | 1284 | } |
50e1e10f | 1285 | } else { |
1b6bf175 | 1286 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
f3db3566 | 1287 | fs->group_desc[i].bg_block_bitmap); |
1b6bf175 | 1288 | ext2fs_mark_block_bitmap(ctx->block_illegal_map, |
50e1e10f TT |
1289 | fs->group_desc[i].bg_block_bitmap); |
1290 | } | |
1291 | ||
f3db3566 | 1292 | } |
3839e657 TT |
1293 | /* |
1294 | * Mark block used for the inode bitmap | |
1295 | */ | |
f3db3566 | 1296 | if (fs->group_desc[i].bg_inode_bitmap) { |
1b6bf175 | 1297 | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
f3db3566 | 1298 | fs->group_desc[i].bg_inode_bitmap)) { |
21c84b71 | 1299 | pctx.blk = fs->group_desc[i].bg_inode_bitmap; |
1b6bf175 TT |
1300 | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
1301 | ctx->invalid_inode_bitmap_flag[i]++; | |
1302 | ctx->invalid_bitmaps++; | |
21c84b71 | 1303 | } |
50e1e10f | 1304 | } else { |
1b6bf175 | 1305 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
f3db3566 | 1306 | fs->group_desc[i].bg_inode_bitmap); |
1b6bf175 | 1307 | ext2fs_mark_block_bitmap(ctx->block_illegal_map, |
50e1e10f TT |
1308 | fs->group_desc[i].bg_inode_bitmap); |
1309 | } | |
f3db3566 | 1310 | } |
3839e657 TT |
1311 | block += fs->super->s_blocks_per_group; |
1312 | } | |
1313 | } | |
1314 | ||
1315 | /* | |
1316 | * This subroutines short circuits ext2fs_get_blocks and | |
1317 | * ext2fs_check_directory; we use them since we already have the inode | |
1318 | * structure, so there's no point in letting the ext2fs library read | |
1319 | * the inode again. | |
1320 | */ | |
1e3472c5 | 1321 | errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks) |
3839e657 | 1322 | { |
54dc7ca2 | 1323 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
3839e657 TT |
1324 | int i; |
1325 | ||
1b6bf175 | 1326 | if (ino != ctx->stashed_ino) |
521e3685 TT |
1327 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1328 | ||
1329 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
1b6bf175 | 1330 | blocks[i] = ctx->stashed_inode->i_block[i]; |
521e3685 | 1331 | return 0; |
3839e657 TT |
1332 | } |
1333 | ||
1e3472c5 TT |
1334 | errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode) |
1335 | { | |
54dc7ca2 | 1336 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 TT |
1337 | |
1338 | if (ino != ctx->stashed_ino) | |
1e3472c5 | 1339 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1b6bf175 | 1340 | *inode = *ctx->stashed_inode; |
1e3472c5 TT |
1341 | return 0; |
1342 | } | |
1343 | ||
1344 | errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino, | |
1345 | struct ext2_inode *inode) | |
1346 | { | |
54dc7ca2 | 1347 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 TT |
1348 | |
1349 | if (ino == ctx->stashed_ino) | |
1350 | *ctx->stashed_inode = *inode; | |
1e3472c5 TT |
1351 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1352 | } | |
1353 | ||
1354 | errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino) | |
3839e657 | 1355 | { |
54dc7ca2 | 1356 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 TT |
1357 | |
1358 | if (ino != ctx->stashed_ino) | |
1359 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
1360 | ||
1361 | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) | |
291c9049 | 1362 | return EXT2_ET_NO_DIRECTORY; |
1b6bf175 | 1363 | return 0; |
3839e657 | 1364 | } |