]>
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) | |
aa4115a4 | 22 | * - A bitmap of which inodes are regular files. (inode_reg_map) |
3839e657 | 23 | * - A bitmap of which inodes have bad fields. (inode_bad_map) |
21c84b71 | 24 | * - A bitmap of which inodes are in bad blocks. (inode_bb_map) |
aa4115a4 | 25 | * - A bitmap of which inodes are imagic inodes. (inode_imagic_map) |
3839e657 TT |
26 | * - A bitmap of which blocks are in use. (block_found_map) |
27 | * - A bitmap of which blocks are in use by two inodes (block_dup_map) | |
28 | * - The data blocks of the directory inodes. (dir_map) | |
29 | * | |
30 | * Pass 1 is designed to stash away enough information so that the | |
31 | * other passes should not need to read in the inode information | |
32 | * during the normal course of a filesystem check. (Althogh if an | |
33 | * inconsistency is detected, other passes may need to read in an | |
34 | * inode to fix it.) | |
35 | * | |
36 | * Note that pass 1B will be invoked if there are any duplicate blocks | |
37 | * found. | |
38 | */ | |
39 | ||
b969b1b8 | 40 | #define _GNU_SOURCE 1 /* get strnlen() */ |
3e699064 | 41 | #include <string.h> |
3839e657 | 42 | #include <time.h> |
50e1e10f TT |
43 | #ifdef HAVE_ERRNO_H |
44 | #include <errno.h> | |
45 | #endif | |
3839e657 | 46 | |
3839e657 | 47 | #include "e2fsck.h" |
342d847d TT |
48 | #include <ext2fs/ext2_ext_attr.h> |
49 | ||
21c84b71 | 50 | #include "problem.h" |
3839e657 | 51 | |
50e1e10f TT |
52 | #ifdef NO_INLINE_FUNCS |
53 | #define _INLINE_ | |
54 | #else | |
55 | #define _INLINE_ inline | |
56 | #endif | |
57 | ||
3839e657 | 58 | static int process_block(ext2_filsys fs, blk_t *blocknr, |
9d1bd3de | 59 | e2_blkcnt_t blockcnt, blk_t ref_blk, |
54dc7ca2 | 60 | int ref_offset, void *priv_data); |
3839e657 | 61 | static int process_bad_block(ext2_filsys fs, blk_t *block_nr, |
9d1bd3de | 62 | e2_blkcnt_t blockcnt, blk_t ref_blk, |
54dc7ca2 | 63 | int ref_offset, void *priv_data); |
1b6bf175 | 64 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 | 65 | char *block_buf); |
1b6bf175 | 66 | static void mark_table_blocks(e2fsck_t ctx); |
1b6bf175 | 67 | static void alloc_bb_map(e2fsck_t ctx); |
aa4115a4 | 68 | static void alloc_imagic_map(e2fsck_t ctx); |
fdbdea09 | 69 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino); |
1b6bf175 TT |
70 | static void handle_fs_bad_blocks(e2fsck_t ctx); |
71 | static void process_inodes(e2fsck_t ctx, char *block_buf); | |
4c77fe50 | 72 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); |
f3db3566 | 73 | static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, |
54dc7ca2 | 74 | dgrp_t group, void * priv_data); |
e8a3ee62 TT |
75 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
76 | char *block_buf, int adjust_sign); | |
21c84b71 | 77 | /* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */ |
3839e657 TT |
78 | |
79 | struct process_block_struct { | |
86c627ec | 80 | ext2_ino_t ino; |
83e692e8 | 81 | unsigned is_dir:1, is_reg:1, clear:1, suppress:1, |
000ba404 | 82 | fragmented:1, compressed:1, bbcheck:1; |
246501c6 | 83 | blk_t num_blocks; |
da307041 | 84 | blk_t max_blocks; |
9d1bd3de | 85 | e2_blkcnt_t last_block; |
246501c6 TT |
86 | int num_illegal_blocks; |
87 | blk_t previous_block; | |
f3db3566 | 88 | struct ext2_inode *inode; |
21c84b71 | 89 | struct problem_context *pctx; |
000ba404 | 90 | ext2fs_block_bitmap fs_meta_blocks; |
1b6bf175 | 91 | e2fsck_t ctx; |
3839e657 TT |
92 | }; |
93 | ||
94 | struct process_inode_block { | |
86c627ec | 95 | ext2_ino_t ino; |
3839e657 TT |
96 | struct ext2_inode inode; |
97 | }; | |
98 | ||
f8188fff TT |
99 | struct scan_callback_struct { |
100 | e2fsck_t ctx; | |
101 | char *block_buf; | |
102 | }; | |
103 | ||
3839e657 TT |
104 | /* |
105 | * For the inodes to process list. | |
106 | */ | |
107 | static struct process_inode_block *inodes_to_process; | |
108 | static int process_inode_count; | |
3839e657 | 109 | |
7823dd65 TT |
110 | static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE - |
111 | EXT2_MIN_BLOCK_LOG_SIZE + 1]; | |
246501c6 | 112 | |
f3db3566 TT |
113 | /* |
114 | * Free all memory allocated by pass1 in preparation for restarting | |
115 | * things. | |
116 | */ | |
54434927 | 117 | static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused))) |
f3db3566 | 118 | { |
c4e3d3f3 | 119 | ext2fs_free_mem(&inodes_to_process); |
08b21301 | 120 | inodes_to_process = 0; |
f3db3566 TT |
121 | } |
122 | ||
7cf73dcd TT |
123 | /* |
124 | * Check to make sure a device inode is real. Returns 1 if the device | |
125 | * checks out, 0 if not. | |
1dde43f0 TT |
126 | * |
127 | * Note: this routine is now also used to check FIFO's and Sockets, | |
128 | * since they have the same requirement; the i_block fields should be | |
129 | * zero. | |
7cf73dcd | 130 | */ |
f954ba01 TT |
131 | int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
132 | struct ext2_inode *inode) | |
7cf73dcd TT |
133 | { |
134 | int i; | |
135 | ||
a40ecbb1 | 136 | /* |
441ab1e0 TT |
137 | * If the index flag is set, then this is a bogus |
138 | * device/fifo/socket | |
a40ecbb1 | 139 | */ |
441ab1e0 | 140 | if (inode->i_flags & EXT2_INDEX_FL) |
53abed0a | 141 | return 0; |
bcf9c5d4 | 142 | |
7fdfabd3 TT |
143 | /* |
144 | * We should be able to do the test below all the time, but | |
145 | * because the kernel doesn't forcibly clear the device | |
146 | * inode's additional i_block fields, there are some rare | |
147 | * occasions when a legitimate device inode will have non-zero | |
148 | * additional i_block fields. So for now, we only complain | |
149 | * when the immutable flag is set, which should never happen | |
150 | * for devices. (And that's when the problem is caused, since | |
151 | * you can't set or clear immutable flags for devices.) Once | |
152 | * the kernel has been fixed we can change this... | |
153 | */ | |
01fbc701 | 154 | if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) { |
7fdfabd3 TT |
155 | for (i=4; i < EXT2_N_BLOCKS; i++) |
156 | if (inode->i_block[i]) | |
157 | return 0; | |
158 | } | |
7cf73dcd TT |
159 | return 1; |
160 | } | |
161 | ||
67052a8a AD |
162 | /* |
163 | * Check to make sure a symlink inode is real. Returns 1 if the symlink | |
164 | * checks out, 0 if not. | |
165 | */ | |
bcf9c5d4 TT |
166 | int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode, |
167 | char *buf) | |
67052a8a | 168 | { |
54434927 | 169 | unsigned int len; |
d007cb4c | 170 | int i; |
0684a4f3 | 171 | blk_t blocks; |
67052a8a | 172 | |
bcf9c5d4 TT |
173 | if ((inode->i_size_high || inode->i_size == 0) || |
174 | (inode->i_flags & EXT2_INDEX_FL)) | |
67052a8a AD |
175 | return 0; |
176 | ||
0684a4f3 TT |
177 | blocks = ext2fs_inode_data_blocks(fs, inode); |
178 | if (blocks) { | |
b94a052a | 179 | if ((inode->i_size >= fs->blocksize) || |
0684a4f3 | 180 | (blocks != fs->blocksize >> 9) || |
d007cb4c TT |
181 | (inode->i_block[0] < fs->super->s_first_data_block) || |
182 | (inode->i_block[0] >= fs->super->s_blocks_count)) | |
67052a8a AD |
183 | return 0; |
184 | ||
185 | for (i = 1; i < EXT2_N_BLOCKS; i++) | |
186 | if (inode->i_block[i]) | |
187 | return 0; | |
b94a052a | 188 | |
b94a052a AD |
189 | if (io_channel_read_blk(fs->io, inode->i_block[0], 1, buf)) |
190 | return 0; | |
191 | ||
192 | len = strnlen(buf, fs->blocksize); | |
193 | if (len == fs->blocksize) | |
194 | return 0; | |
67052a8a | 195 | } else { |
b94a052a | 196 | if (inode->i_size >= sizeof(inode->i_block)) |
67052a8a AD |
197 | return 0; |
198 | ||
b94a052a AD |
199 | len = strnlen((char *)inode->i_block, sizeof(inode->i_block)); |
200 | if (len == sizeof(inode->i_block)) | |
67052a8a AD |
201 | return 0; |
202 | } | |
b94a052a AD |
203 | if (len != inode->i_size) |
204 | return 0; | |
67052a8a AD |
205 | return 1; |
206 | } | |
207 | ||
6fdc7a32 | 208 | /* |
01fbc701 TT |
209 | * If the immutable (or append-only) flag is set on the inode, offer |
210 | * to clear it. | |
6fdc7a32 | 211 | */ |
bcf9c5d4 | 212 | #define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL) |
6fdc7a32 TT |
213 | static void check_immutable(e2fsck_t ctx, struct problem_context *pctx) |
214 | { | |
b94a052a | 215 | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) |
6fdc7a32 TT |
216 | return; |
217 | ||
218 | if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx)) | |
219 | return; | |
220 | ||
b94a052a | 221 | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; |
6fdc7a32 TT |
222 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
223 | } | |
224 | ||
d647a1ea TT |
225 | /* |
226 | * If device, fifo or socket, check size is zero -- if not offer to | |
227 | * clear it | |
228 | */ | |
229 | static void check_size(e2fsck_t ctx, struct problem_context *pctx) | |
230 | { | |
231 | struct ext2_inode *inode = pctx->inode; | |
232 | ||
85645a6f | 233 | if ((inode->i_size == 0) && (inode->i_size_high == 0)) |
d647a1ea TT |
234 | return; |
235 | ||
85645a6f | 236 | if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) |
d647a1ea TT |
237 | return; |
238 | ||
239 | inode->i_size = 0; | |
fdbdea09 | 240 | inode->i_size_high = 0; |
d647a1ea TT |
241 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
242 | } | |
243 | ||
cebe48a1 TT |
244 | static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx) |
245 | { | |
246 | struct ext2_super_block *sb = ctx->fs->super; | |
247 | struct ext2_inode_large *inode; | |
248 | struct ext2_ext_attr_entry *entry; | |
642935c0 | 249 | char *start, *end; |
1a8c2c4a | 250 | unsigned int storage_size, remain; |
cebe48a1 TT |
251 | int problem = 0; |
252 | ||
253 | inode = (struct ext2_inode_large *) pctx->inode; | |
254 | storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE - | |
255 | inode->i_extra_isize; | |
256 | start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + | |
257 | inode->i_extra_isize + sizeof(__u32); | |
258 | end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super); | |
259 | entry = (struct ext2_ext_attr_entry *) start; | |
260 | ||
261 | /* scan all entry's headers first */ | |
262 | ||
263 | /* take finish entry 0UL into account */ | |
264 | remain = storage_size - sizeof(__u32); | |
cebe48a1 TT |
265 | |
266 | while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { | |
267 | ||
268 | /* header eats this space */ | |
269 | remain -= sizeof(struct ext2_ext_attr_entry); | |
270 | ||
271 | /* is attribute name valid? */ | |
272 | if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) { | |
273 | pctx->num = entry->e_name_len; | |
274 | problem = PR_1_ATTR_NAME_LEN; | |
275 | goto fix; | |
276 | } | |
277 | ||
278 | /* attribute len eats this space */ | |
279 | remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); | |
280 | ||
281 | /* check value size */ | |
282 | if (entry->e_value_size == 0 || entry->e_value_size > remain) { | |
283 | pctx->num = entry->e_value_size; | |
284 | problem = PR_1_ATTR_VALUE_SIZE; | |
285 | goto fix; | |
286 | } | |
287 | ||
cebe48a1 TT |
288 | /* e_value_block must be 0 in inode's ea */ |
289 | if (entry->e_value_block != 0) { | |
290 | pctx->num = entry->e_value_block; | |
291 | problem = PR_1_ATTR_VALUE_BLOCK; | |
292 | goto fix; | |
293 | } | |
294 | ||
295 | /* e_hash must be 0 in inode's ea */ | |
296 | if (entry->e_hash != 0) { | |
297 | pctx->num = entry->e_hash; | |
298 | problem = PR_1_ATTR_HASH; | |
299 | goto fix; | |
300 | } | |
301 | ||
302 | remain -= entry->e_value_size; | |
cebe48a1 TT |
303 | |
304 | entry = EXT2_EXT_ATTR_NEXT(entry); | |
305 | } | |
306 | fix: | |
307 | /* | |
308 | * it seems like a corruption. it's very unlikely we could repair | |
309 | * EA(s) in automatic fashion -bzzz | |
310 | */ | |
311 | #if 0 | |
312 | problem = PR_1_ATTR_HASH; | |
313 | #endif | |
314 | if (problem == 0 || !fix_problem(ctx, problem, pctx)) | |
315 | return; | |
316 | ||
317 | /* simple remove all possible EA(s) */ | |
318 | *((__u32 *)start) = 0UL; | |
642935c0 | 319 | e2fsck_write_inode_full(ctx, pctx->ino, (struct ext2_inode *) inode, |
cebe48a1 TT |
320 | EXT2_INODE_SIZE(sb), "pass1"); |
321 | } | |
322 | ||
323 | static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) | |
324 | { | |
325 | struct ext2_super_block *sb = ctx->fs->super; | |
326 | struct ext2_inode_large *inode; | |
327 | __u32 *eamagic; | |
328 | int min, max; | |
329 | ||
330 | inode = (struct ext2_inode_large *) pctx->inode; | |
331 | if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) { | |
332 | /* this isn't large inode. so, nothing to check */ | |
333 | return; | |
334 | } | |
335 | ||
336 | #if 0 | |
337 | printf("inode #%u, i_extra_size %d\n", pctx->ino, | |
338 | inode->i_extra_isize); | |
339 | #endif | |
340 | /* i_extra_isize must cover i_extra_isize + i_pad1 at least */ | |
341 | min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1); | |
342 | max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; | |
343 | /* | |
344 | * For now we will allow i_extra_isize to be 0, but really | |
345 | * implementations should never allow i_extra_isize to be 0 | |
346 | */ | |
347 | if (inode->i_extra_isize && | |
348 | (inode->i_extra_isize < min || inode->i_extra_isize > max)) { | |
349 | if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx)) | |
350 | return; | |
351 | inode->i_extra_isize = min; | |
352 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, | |
353 | EXT2_INODE_SIZE(sb), "pass1"); | |
354 | return; | |
355 | } | |
356 | ||
357 | eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + | |
358 | inode->i_extra_isize); | |
359 | if (*eamagic == EXT2_EXT_ATTR_MAGIC) { | |
360 | /* it seems inode has an extended attribute(s) in body */ | |
361 | check_ea_in_inode(ctx, pctx); | |
362 | } | |
363 | } | |
6fdc7a32 | 364 | |
fbc3f901 TT |
365 | /* |
366 | * Check to see if the inode might really be a directory, despite i_mode | |
367 | * | |
368 | * This is a lot of complexity for something for which I'm not really | |
369 | * convinced happens frequently in the wild. If for any reason this | |
370 | * causes any problems, take this code out. | |
371 | * [tytso:20070331.0827EDT] | |
372 | */ | |
373 | static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, | |
374 | char *buf) | |
375 | { | |
376 | struct ext2_inode *inode = pctx->inode; | |
fbc3f901 | 377 | struct ext2_dir_entry *dirent; |
e94bc631 TT |
378 | const char *old_op; |
379 | errcode_t retval; | |
380 | blk_t blk; | |
381 | int i, not_device = 0; | |
fbc3f901 TT |
382 | |
383 | if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || | |
0eeb1549 | 384 | LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) |
fbc3f901 TT |
385 | return; |
386 | ||
0eeb1549 | 387 | for (i=0; i < EXT2_N_BLOCKS; i++) { |
fbc3f901 TT |
388 | blk = inode->i_block[i]; |
389 | if (!blk) | |
390 | continue; | |
391 | if (i >= 4) | |
392 | not_device++; | |
393 | ||
394 | if (blk < ctx->fs->super->s_first_data_block || | |
395 | blk >= ctx->fs->super->s_blocks_count || | |
396 | ext2fs_fast_test_block_bitmap(ctx->block_found_map, blk)) | |
397 | return; /* Invalid block, can't be dir */ | |
398 | } | |
399 | ||
400 | if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) && | |
401 | (inode->i_links_count == 1) && !not_device) | |
402 | return; | |
403 | ||
e94bc631 TT |
404 | old_op = ehandler_operation(_("reading directory block")); |
405 | retval = ext2fs_read_dir_block(ctx->fs, inode->i_block[0], buf); | |
406 | ehandler_operation(0); | |
407 | if (retval) | |
fbc3f901 TT |
408 | return; |
409 | ||
410 | dirent = (struct ext2_dir_entry *) buf; | |
411 | if (((dirent->name_len & 0xFF) != 1) || | |
412 | (dirent->name[0] != '.') || | |
413 | (dirent->inode != pctx->ino) || | |
414 | (dirent->rec_len < 12) || | |
415 | (dirent->rec_len % 4) || | |
416 | (dirent->rec_len >= ctx->fs->blocksize - 12)) | |
417 | return; | |
418 | ||
419 | dirent = (struct ext2_dir_entry *) (buf + dirent->rec_len); | |
420 | if (((dirent->name_len & 0xFF) != 2) || | |
421 | (dirent->name[0] != '.') || | |
422 | (dirent->name[1] != '.') || | |
423 | (dirent->rec_len < 12) || | |
424 | (dirent->rec_len % 4)) | |
425 | return; | |
426 | ||
427 | if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) { | |
428 | inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR; | |
429 | e2fsck_write_inode_full(ctx, pctx->ino, inode, | |
430 | EXT2_INODE_SIZE(ctx->fs->super), | |
431 | "check_is_really_dir"); | |
432 | } | |
433 | } | |
434 | ||
34b9f796 TT |
435 | extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags, |
436 | ext2_icount_t *ret) | |
437 | { | |
f954ba01 | 438 | unsigned int threshold; |
34b9f796 TT |
439 | ext2_ino_t num_dirs; |
440 | errcode_t retval; | |
f954ba01 TT |
441 | char *tdb_dir; |
442 | int enable; | |
34b9f796 TT |
443 | |
444 | *ret = 0; | |
445 | ||
446 | profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0, | |
447 | &tdb_dir); | |
f954ba01 TT |
448 | profile_get_uint(ctx->profile, "scratch_files", |
449 | "numdirs_threshold", 0, 0, &threshold); | |
34b9f796 TT |
450 | profile_get_boolean(ctx->profile, "scratch_files", |
451 | "icount", 0, 1, &enable); | |
452 | ||
453 | retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs); | |
454 | if (retval) | |
455 | num_dirs = 1024; /* Guess */ | |
456 | ||
457 | if (!enable || !tdb_dir || access(tdb_dir, W_OK) || | |
458 | (threshold && num_dirs <= threshold)) | |
459 | return; | |
460 | ||
461 | retval = ext2fs_create_icount_tdb(ctx->fs, tdb_dir, flags, ret); | |
462 | if (retval) | |
463 | *ret = 0; | |
464 | } | |
465 | ||
08b21301 | 466 | void e2fsck_pass1(e2fsck_t ctx) |
3839e657 | 467 | { |
9d1bd3de | 468 | int i; |
31e29a12 | 469 | __u64 max_sizes; |
1b6bf175 | 470 | ext2_filsys fs = ctx->fs; |
86c627ec | 471 | ext2_ino_t ino; |
cebe48a1 | 472 | struct ext2_inode *inode; |
3839e657 TT |
473 | ext2_inode_scan scan; |
474 | char *block_buf; | |
8bf191e8 | 475 | #ifdef RESOURCE_TRACK |
3839e657 | 476 | struct resource_track rtrack; |
8bf191e8 | 477 | #endif |
1e3472c5 | 478 | unsigned char frag, fsize; |
21c84b71 | 479 | struct problem_context pctx; |
f8188fff | 480 | struct scan_callback_struct scan_struct; |
5dd8f963 | 481 | struct ext2_super_block *sb = ctx->fs->super; |
e94bc631 | 482 | const char *old_op; |
6fdc7a32 | 483 | int imagic_fs; |
be93ef0c | 484 | int busted_fs_time = 0; |
cebe48a1 | 485 | int inode_size; |
3839e657 | 486 | |
8bf191e8 | 487 | #ifdef RESOURCE_TRACK |
3839e657 | 488 | init_resource_track(&rtrack); |
8bf191e8 | 489 | #endif |
1b6bf175 TT |
490 | clear_problem_context(&pctx); |
491 | ||
492 | if (!(ctx->options & E2F_OPT_PREEN)) | |
493 | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); | |
3839e657 | 494 | |
3214a453 TT |
495 | if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && |
496 | !(ctx->options & E2F_OPT_NO)) { | |
b7a00563 TT |
497 | if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) |
498 | ctx->dirs_to_hash = 0; | |
499 | } | |
500 | ||
3839e657 TT |
501 | #ifdef MTRACE |
502 | mtrace_print("Pass 1"); | |
503 | #endif | |
504 | ||
932a489c AD |
505 | #define EXT2_BPP(bits) (1ULL << ((bits) - 2)) |
506 | ||
507 | for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) { | |
508 | max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i); | |
509 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i); | |
510 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i); | |
511 | max_sizes = (max_sizes * (1UL << i)) - 1; | |
7823dd65 | 512 | ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes; |
9d1bd3de TT |
513 | } |
514 | #undef EXT2_BPP | |
6fdc7a32 | 515 | |
6fdc7a32 TT |
516 | imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES); |
517 | ||
3839e657 TT |
518 | /* |
519 | * Allocate bitmaps structures | |
520 | */ | |
0c4a0726 | 521 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"), |
1b6bf175 TT |
522 | &ctx->inode_used_map); |
523 | if (pctx.errcode) { | |
524 | pctx.num = 1; | |
525 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
526 | ctx->flags |= E2F_FLAG_ABORT; |
527 | return; | |
3839e657 | 528 | } |
0c4a0726 TT |
529 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
530 | _("directory inode map"), &ctx->inode_dir_map); | |
1b6bf175 TT |
531 | if (pctx.errcode) { |
532 | pctx.num = 2; | |
533 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
534 | ctx->flags |= E2F_FLAG_ABORT; |
535 | return; | |
3839e657 | 536 | } |
aa4115a4 | 537 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
0c4a0726 | 538 | _("regular file inode map"), &ctx->inode_reg_map); |
aa4115a4 TT |
539 | if (pctx.errcode) { |
540 | pctx.num = 6; | |
541 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
542 | ctx->flags |= E2F_FLAG_ABORT; | |
543 | return; | |
544 | } | |
0c4a0726 | 545 | pctx.errcode = ext2fs_allocate_block_bitmap(fs, _("in-use block map"), |
1b6bf175 TT |
546 | &ctx->block_found_map); |
547 | if (pctx.errcode) { | |
548 | pctx.num = 1; | |
549 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
08b21301 TT |
550 | ctx->flags |= E2F_FLAG_ABORT; |
551 | return; | |
3839e657 | 552 | } |
34b9f796 TT |
553 | e2fsck_setup_tdb_icount(ctx, 0, &ctx->inode_link_info); |
554 | if (!ctx->inode_link_info) | |
555 | pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, | |
556 | &ctx->inode_link_info); | |
1b6bf175 TT |
557 | if (pctx.errcode) { |
558 | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); | |
08b21301 TT |
559 | ctx->flags |= E2F_FLAG_ABORT; |
560 | return; | |
21c84b71 | 561 | } |
cebe48a1 TT |
562 | inode_size = EXT2_INODE_SIZE(fs->super); |
563 | inode = (struct ext2_inode *) | |
564 | e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); | |
565 | ||
54dc7ca2 TT |
566 | inodes_to_process = (struct process_inode_block *) |
567 | e2fsck_allocate_memory(ctx, | |
568 | (ctx->process_inode_size * | |
569 | sizeof(struct process_inode_block)), | |
570 | "array of inodes to process"); | |
3839e657 TT |
571 | process_inode_count = 0; |
572 | ||
1b6bf175 TT |
573 | pctx.errcode = ext2fs_init_dblist(fs, 0); |
574 | if (pctx.errcode) { | |
575 | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); | |
08b21301 | 576 | ctx->flags |= E2F_FLAG_ABORT; |
9d45b6ef | 577 | ext2fs_free_mem(&inode); |
08b21301 | 578 | return; |
21c84b71 | 579 | } |
3839e657 | 580 | |
9cbfb8d0 TT |
581 | /* |
582 | * If the last orphan field is set, clear it, since the pass1 | |
583 | * processing will automatically find and clear the orphans. | |
584 | * In the future, we may want to try using the last_orphan | |
585 | * linked list ourselves, but for now, we clear it so that the | |
586 | * ext3 mount code won't get confused. | |
587 | */ | |
588 | if (!(ctx->options & E2F_OPT_READONLY)) { | |
589 | if (fs->super->s_last_orphan) { | |
590 | fs->super->s_last_orphan = 0; | |
591 | ext2fs_mark_super_dirty(fs); | |
592 | } | |
593 | } | |
594 | ||
1b6bf175 | 595 | mark_table_blocks(ctx); |
54dc7ca2 TT |
596 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
597 | "block interate buffer"); | |
e72a9ba3 | 598 | e2fsck_use_inode_shortcuts(ctx, 1); |
e94bc631 | 599 | old_op = ehandler_operation(_("opening inode scan")); |
1b6bf175 TT |
600 | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
601 | &scan); | |
e94bc631 | 602 | ehandler_operation(old_op); |
1b6bf175 TT |
603 | if (pctx.errcode) { |
604 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 | 605 | ctx->flags |= E2F_FLAG_ABORT; |
9d45b6ef BB |
606 | ext2fs_free_mem(&block_buf); |
607 | ext2fs_free_mem(&inode); | |
08b21301 | 608 | return; |
3839e657 | 609 | } |
21c84b71 | 610 | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); |
cebe48a1 | 611 | ctx->stashed_inode = inode; |
f8188fff TT |
612 | scan_struct.ctx = ctx; |
613 | scan_struct.block_buf = block_buf; | |
614 | ext2fs_set_inode_callback(scan, scan_callback, &scan_struct); | |
615 | if (ctx->progress) | |
a02ce9df TT |
616 | if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count)) |
617 | return; | |
4147d9f0 TT |
618 | if ((fs->super->s_wtime < fs->super->s_inodes_count) || |
619 | (fs->super->s_mtime < fs->super->s_inodes_count)) | |
be93ef0c TT |
620 | busted_fs_time = 1; |
621 | ||
d237a78e | 622 | while (1) { |
e94bc631 | 623 | old_op = ehandler_operation(_("getting next inode from scan")); |
cebe48a1 TT |
624 | pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, |
625 | inode, inode_size); | |
e94bc631 | 626 | ehandler_operation(old_op); |
d237a78e TT |
627 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
628 | return; | |
629 | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { | |
630 | if (!ctx->inode_bb_map) | |
631 | alloc_bb_map(ctx); | |
632 | ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino); | |
633 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); | |
634 | continue; | |
635 | } | |
636 | if (pctx.errcode) { | |
637 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
638 | ctx->flags |= E2F_FLAG_ABORT; | |
639 | return; | |
640 | } | |
641 | if (!ino) | |
642 | break; | |
21c84b71 | 643 | pctx.ino = ino; |
cebe48a1 | 644 | pctx.inode = inode; |
1b6bf175 | 645 | ctx->stashed_ino = ino; |
cebe48a1 | 646 | if (inode->i_links_count) { |
1b6bf175 | 647 | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, |
cebe48a1 | 648 | ino, inode->i_links_count); |
1b6bf175 | 649 | if (pctx.errcode) { |
cebe48a1 | 650 | pctx.num = inode->i_links_count; |
1b6bf175 | 651 | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); |
08b21301 TT |
652 | ctx->flags |= E2F_FLAG_ABORT; |
653 | return; | |
1b6bf175 TT |
654 | } |
655 | } | |
3839e657 TT |
656 | if (ino == EXT2_BAD_INO) { |
657 | struct process_block_struct pb; | |
658 | ||
000ba404 TT |
659 | pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map, |
660 | &pb.fs_meta_blocks); | |
661 | if (pctx.errcode) { | |
662 | pctx.num = 4; | |
663 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
664 | ctx->flags |= E2F_FLAG_ABORT; | |
665 | return; | |
666 | } | |
3839e657 TT |
667 | pb.ino = EXT2_BAD_INO; |
668 | pb.num_blocks = pb.last_block = 0; | |
f3db3566 | 669 | pb.num_illegal_blocks = 0; |
21c84b71 | 670 | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
000ba404 | 671 | pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0; |
cebe48a1 | 672 | pb.inode = inode; |
21c84b71 | 673 | pb.pctx = &pctx; |
1b6bf175 TT |
674 | pb.ctx = ctx; |
675 | pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, | |
676 | block_buf, process_bad_block, &pb); | |
000ba404 | 677 | ext2fs_free_block_bitmap(pb.fs_meta_blocks); |
1b6bf175 TT |
678 | if (pctx.errcode) { |
679 | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); | |
08b21301 TT |
680 | ctx->flags |= E2F_FLAG_ABORT; |
681 | return; | |
1b6bf175 | 682 | } |
000ba404 TT |
683 | if (pb.bbcheck) |
684 | if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) { | |
685 | ctx->flags |= E2F_FLAG_ABORT; | |
686 | return; | |
687 | } | |
1b6bf175 | 688 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
21c84b71 | 689 | clear_problem_context(&pctx); |
d237a78e | 690 | continue; |
a9ca2016 | 691 | } else if (ino == EXT2_ROOT_INO) { |
3839e657 TT |
692 | /* |
693 | * Make sure the root inode is a directory; if | |
694 | * not, offer to clear it. It will be | |
695 | * regnerated in pass #3. | |
696 | */ | |
cebe48a1 | 697 | if (!LINUX_S_ISDIR(inode->i_mode)) { |
1b6bf175 | 698 | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) { |
1f3ad14a | 699 | inode->i_dtime = ctx->now; |
cebe48a1 | 700 | inode->i_links_count = 0; |
1b6bf175 | 701 | ext2fs_icount_store(ctx->inode_link_info, |
21c84b71 | 702 | ino, 0); |
cebe48a1 | 703 | e2fsck_write_inode(ctx, ino, inode, |
f3db3566 | 704 | "pass1"); |
21c84b71 | 705 | } |
b09a4b0c | 706 | |
3839e657 TT |
707 | } |
708 | /* | |
709 | * If dtime is set, offer to clear it. mke2fs | |
710 | * version 0.2b created filesystems with the | |
711 | * dtime field set for the root and lost+found | |
712 | * directories. We won't worry about | |
713 | * /lost+found, since that can be regenerated | |
714 | * easily. But we will fix the root directory | |
715 | * as a special case. | |
716 | */ | |
cebe48a1 | 717 | if (inode->i_dtime && inode->i_links_count) { |
1b6bf175 | 718 | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
cebe48a1 TT |
719 | inode->i_dtime = 0; |
720 | e2fsck_write_inode(ctx, ino, inode, | |
f3db3566 | 721 | "pass1"); |
21c84b71 | 722 | } |
3839e657 | 723 | } |
a9ca2016 | 724 | } else if (ino == EXT2_JOURNAL_INO) { |
f18996c8 TT |
725 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
726 | if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) { | |
cebe48a1 | 727 | if (!LINUX_S_ISREG(inode->i_mode) && |
a9ca2016 TT |
728 | fix_problem(ctx, PR_1_JOURNAL_BAD_MODE, |
729 | &pctx)) { | |
cebe48a1 TT |
730 | inode->i_mode = LINUX_S_IFREG; |
731 | e2fsck_write_inode(ctx, ino, inode, | |
a9ca2016 TT |
732 | "pass1"); |
733 | } | |
f18996c8 | 734 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 735 | continue; |
f18996c8 | 736 | } |
cebe48a1 TT |
737 | if ((inode->i_links_count || inode->i_blocks || |
738 | inode->i_blocks || inode->i_block[0]) && | |
a9ca2016 | 739 | fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, |
f18996c8 | 740 | &pctx)) { |
cebe48a1 | 741 | memset(inode, 0, inode_size); |
a9ca2016 TT |
742 | ext2fs_icount_store(ctx->inode_link_info, |
743 | ino, 0); | |
cebe48a1 TT |
744 | e2fsck_write_inode_full(ctx, ino, inode, |
745 | inode_size, "pass1"); | |
f18996c8 | 746 | } |
a9ca2016 | 747 | } else if (ino < EXT2_FIRST_INODE(fs->super)) { |
b09a4b0c TT |
748 | int problem = 0; |
749 | ||
1b6bf175 | 750 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
53ef44c4 | 751 | if (ino == EXT2_BOOT_LOADER_INO) { |
cebe48a1 | 752 | if (LINUX_S_ISDIR(inode->i_mode)) |
b09a4b0c | 753 | problem = PR_1_RESERVED_BAD_MODE; |
b1f204f7 | 754 | } else if (ino == EXT2_RESIZE_INO) { |
cebe48a1 TT |
755 | if (inode->i_mode && |
756 | !LINUX_S_ISREG(inode->i_mode)) | |
b1f204f7 | 757 | problem = PR_1_RESERVED_BAD_MODE; |
53ef44c4 | 758 | } else { |
cebe48a1 | 759 | if (inode->i_mode != 0) |
b09a4b0c | 760 | problem = PR_1_RESERVED_BAD_MODE; |
b09a4b0c TT |
761 | } |
762 | if (problem) { | |
763 | if (fix_problem(ctx, problem, &pctx)) { | |
cebe48a1 TT |
764 | inode->i_mode = 0; |
765 | e2fsck_write_inode(ctx, ino, inode, | |
50e1e10f | 766 | "pass1"); |
21c84b71 | 767 | } |
50e1e10f | 768 | } |
1b6bf175 | 769 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 770 | continue; |
3839e657 | 771 | } |
21afac09 TT |
772 | /* |
773 | * Check for inodes who might have been part of the | |
774 | * orphaned list linked list. They should have gotten | |
775 | * dealt with by now, unless the list had somehow been | |
776 | * corrupted. | |
777 | * | |
778 | * FIXME: In the future, inodes which are still in use | |
779 | * (and which are therefore) pending truncation should | |
780 | * be handled specially. Right now we just clear the | |
781 | * dtime field, and the normal e2fsck handling of | |
782 | * inodes where i_size and the inode blocks are | |
783 | * inconsistent is to fix i_size, instead of releasing | |
784 | * the extra blocks. This won't catch the inodes that | |
785 | * was at the end of the orphan list, but it's better | |
786 | * than nothing. The right answer is that there | |
787 | * shouldn't be any bugs in the orphan list handling. :-) | |
788 | */ | |
cebe48a1 TT |
789 | if (inode->i_dtime && !busted_fs_time && |
790 | inode->i_dtime < ctx->fs->super->s_inodes_count) { | |
21afac09 | 791 | if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { |
cebe48a1 | 792 | inode->i_dtime = inode->i_links_count ? |
1f3ad14a | 793 | 0 : ctx->now; |
cebe48a1 | 794 | e2fsck_write_inode(ctx, ino, inode, |
21afac09 TT |
795 | "pass1"); |
796 | } | |
797 | } | |
798 | ||
3839e657 TT |
799 | /* |
800 | * This code assumes that deleted inodes have | |
801 | * i_links_count set to 0. | |
802 | */ | |
cebe48a1 TT |
803 | if (!inode->i_links_count) { |
804 | if (!inode->i_dtime && inode->i_mode) { | |
1b6bf175 | 805 | if (fix_problem(ctx, |
21c84b71 | 806 | PR_1_ZERO_DTIME, &pctx)) { |
1f3ad14a | 807 | inode->i_dtime = ctx->now; |
cebe48a1 | 808 | e2fsck_write_inode(ctx, ino, inode, |
f3db3566 | 809 | "pass1"); |
21c84b71 | 810 | } |
3839e657 | 811 | } |
d237a78e | 812 | continue; |
3839e657 TT |
813 | } |
814 | /* | |
1e3472c5 | 815 | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
3839e657 | 816 | * deleted files. Oops. |
1e3472c5 TT |
817 | * |
818 | * Since all new ext2 implementations get this right, | |
819 | * we now assume that the case of non-zero | |
820 | * i_links_count and non-zero dtime means that we | |
821 | * should keep the file, not delete it. | |
3839e657 | 822 | * |
3839e657 | 823 | */ |
cebe48a1 | 824 | if (inode->i_dtime) { |
1b6bf175 | 825 | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
cebe48a1 TT |
826 | inode->i_dtime = 0; |
827 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
21c84b71 | 828 | } |
3839e657 TT |
829 | } |
830 | ||
1b6bf175 | 831 | ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino); |
1e3472c5 | 832 | switch (fs->super->s_creator_os) { |
1e3472c5 | 833 | case EXT2_OS_HURD: |
cebe48a1 TT |
834 | frag = inode->osd2.hurd2.h_i_frag; |
835 | fsize = inode->osd2.hurd2.h_i_fsize; | |
1e3472c5 TT |
836 | break; |
837 | case EXT2_OS_MASIX: | |
cebe48a1 TT |
838 | frag = inode->osd2.masix2.m_i_frag; |
839 | fsize = inode->osd2.masix2.m_i_fsize; | |
1e3472c5 TT |
840 | break; |
841 | default: | |
842 | frag = fsize = 0; | |
843 | } | |
844 | ||
cebe48a1 TT |
845 | if (inode->i_faddr || frag || fsize || |
846 | (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl)) | |
fdbdea09 | 847 | mark_inode_bad(ctx, ino); |
5d17119d TT |
848 | if ((fs->super->s_creator_os == EXT2_OS_LINUX) && |
849 | !(fs->super->s_feature_ro_compat & | |
850 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && | |
851 | (inode->osd2.linux2.l_i_blocks_hi != 0)) | |
852 | mark_inode_bad(ctx, ino); | |
cebe48a1 | 853 | if (inode->i_flags & EXT2_IMAGIC_FL) { |
6fdc7a32 TT |
854 | if (imagic_fs) { |
855 | if (!ctx->inode_imagic_map) | |
856 | alloc_imagic_map(ctx); | |
857 | ext2fs_mark_inode_bitmap(ctx->inode_imagic_map, | |
858 | ino); | |
859 | } else { | |
860 | if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) { | |
cebe48a1 | 861 | inode->i_flags &= ~EXT2_IMAGIC_FL; |
6fdc7a32 | 862 | e2fsck_write_inode(ctx, ino, |
cebe48a1 | 863 | inode, "pass1"); |
6fdc7a32 TT |
864 | } |
865 | } | |
aa4115a4 | 866 | } |
cebe48a1 TT |
867 | |
868 | check_inode_extra_space(ctx, &pctx); | |
fbc3f901 | 869 | check_is_really_dir(ctx, &pctx, block_buf); |
cebe48a1 TT |
870 | |
871 | if (LINUX_S_ISDIR(inode->i_mode)) { | |
1b6bf175 | 872 | ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino); |
08b21301 | 873 | e2fsck_add_dir_info(ctx, ino, 0); |
1b6bf175 | 874 | ctx->fs_directory_count++; |
cebe48a1 | 875 | } else if (LINUX_S_ISREG (inode->i_mode)) { |
aa4115a4 | 876 | ext2fs_mark_inode_bitmap(ctx->inode_reg_map, ino); |
1b6bf175 | 877 | ctx->fs_regular_count++; |
cebe48a1 TT |
878 | } else if (LINUX_S_ISCHR (inode->i_mode) && |
879 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 880 | check_immutable(ctx, &pctx); |
d647a1ea | 881 | check_size(ctx, &pctx); |
1b6bf175 | 882 | ctx->fs_chardev_count++; |
cebe48a1 TT |
883 | } else if (LINUX_S_ISBLK (inode->i_mode) && |
884 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 885 | check_immutable(ctx, &pctx); |
d647a1ea | 886 | check_size(ctx, &pctx); |
1b6bf175 | 887 | ctx->fs_blockdev_count++; |
cebe48a1 TT |
888 | } else if (LINUX_S_ISLNK (inode->i_mode) && |
889 | e2fsck_pass1_check_symlink(fs, inode, block_buf)) { | |
fd77b2c7 | 890 | check_immutable(ctx, &pctx); |
1b6bf175 | 891 | ctx->fs_symlinks_count++; |
cebe48a1 | 892 | if (ext2fs_inode_data_blocks(fs, inode) == 0) { |
1b6bf175 | 893 | ctx->fs_fast_symlinks_count++; |
0684a4f3 | 894 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 895 | continue; |
21c84b71 | 896 | } |
3839e657 | 897 | } |
cebe48a1 TT |
898 | else if (LINUX_S_ISFIFO (inode->i_mode) && |
899 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 900 | check_immutable(ctx, &pctx); |
d647a1ea | 901 | check_size(ctx, &pctx); |
1b6bf175 | 902 | ctx->fs_fifo_count++; |
cebe48a1 TT |
903 | } else if ((LINUX_S_ISSOCK (inode->i_mode)) && |
904 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 905 | check_immutable(ctx, &pctx); |
d647a1ea TT |
906 | check_size(ctx, &pctx); |
907 | ctx->fs_sockets_count++; | |
fdbdea09 TT |
908 | } else |
909 | mark_inode_bad(ctx, ino); | |
cebe48a1 | 910 | if (inode->i_block[EXT2_IND_BLOCK]) |
1b6bf175 | 911 | ctx->fs_ind_count++; |
cebe48a1 | 912 | if (inode->i_block[EXT2_DIND_BLOCK]) |
1b6bf175 | 913 | ctx->fs_dind_count++; |
cebe48a1 | 914 | if (inode->i_block[EXT2_TIND_BLOCK]) |
1b6bf175 | 915 | ctx->fs_tind_count++; |
cebe48a1 TT |
916 | if (inode->i_block[EXT2_IND_BLOCK] || |
917 | inode->i_block[EXT2_DIND_BLOCK] || | |
918 | inode->i_block[EXT2_TIND_BLOCK] || | |
919 | inode->i_file_acl) { | |
3839e657 | 920 | inodes_to_process[process_inode_count].ino = ino; |
cebe48a1 | 921 | inodes_to_process[process_inode_count].inode = *inode; |
3839e657 | 922 | process_inode_count++; |
f3db3566 | 923 | } else |
1b6bf175 | 924 | check_blocks(ctx, &pctx, block_buf); |
3839e657 | 925 | |
a02ce9df | 926 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
927 | return; |
928 | ||
929 | if (process_inode_count >= ctx->process_inode_size) { | |
1b6bf175 | 930 | process_inodes(ctx, block_buf); |
08b21301 | 931 | |
a02ce9df | 932 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
933 | return; |
934 | } | |
3839e657 | 935 | } |
1b6bf175 | 936 | process_inodes(ctx, block_buf); |
3839e657 | 937 | ext2fs_close_inode_scan(scan); |
3839e657 | 938 | |
e8a3ee62 TT |
939 | /* |
940 | * If any extended attribute blocks' reference counts need to | |
941 | * be adjusted, either up (ctx->refcount_extra), or down | |
942 | * (ctx->refcount), then fix them. | |
943 | */ | |
944 | if (ctx->refcount) { | |
945 | adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1); | |
946 | ea_refcount_free(ctx->refcount); | |
947 | ctx->refcount = 0; | |
948 | } | |
949 | if (ctx->refcount_extra) { | |
950 | adjust_extattr_refcount(ctx, ctx->refcount_extra, | |
951 | block_buf, +1); | |
952 | ea_refcount_free(ctx->refcount_extra); | |
953 | ctx->refcount_extra = 0; | |
954 | } | |
955 | ||
1b6bf175 TT |
956 | if (ctx->invalid_bitmaps) |
957 | handle_fs_bad_blocks(ctx); | |
f3db3566 | 958 | |
24ceb248 TT |
959 | /* We don't need the block_ea_map any more */ |
960 | if (ctx->block_ea_map) { | |
961 | ext2fs_free_block_bitmap(ctx->block_ea_map); | |
962 | ctx->block_ea_map = 0; | |
963 | } | |
964 | ||
c3ffaf83 TT |
965 | if (ctx->flags & E2F_FLAG_RESIZE_INODE) { |
966 | ext2fs_block_bitmap save_bmap; | |
c3ffaf83 TT |
967 | |
968 | save_bmap = fs->block_map; | |
969 | fs->block_map = ctx->block_found_map; | |
970 | clear_problem_context(&pctx); | |
971 | pctx.errcode = ext2fs_create_resize_inode(fs); | |
972 | if (pctx.errcode) { | |
973 | fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, &pctx); | |
974 | /* Should never get here */ | |
975 | ctx->flags |= E2F_FLAG_ABORT; | |
976 | return; | |
977 | } | |
1f3ad14a TT |
978 | e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, |
979 | "recreate inode"); | |
980 | inode->i_mtime = ctx->now; | |
981 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, | |
982 | "recreate inode"); | |
c3ffaf83 TT |
983 | fs->block_map = save_bmap; |
984 | ctx->flags &= ~E2F_FLAG_RESIZE_INODE; | |
985 | } | |
986 | ||
08b21301 | 987 | if (ctx->flags & E2F_FLAG_RESTART) { |
aa4115a4 TT |
988 | /* |
989 | * Only the master copy of the superblock and block | |
990 | * group descriptors are going to be written during a | |
991 | * restart, so set the superblock to be used to be the | |
992 | * master superblock. | |
993 | */ | |
994 | ctx->use_superblock = 0; | |
f3db3566 TT |
995 | unwind_pass1(fs); |
996 | goto endit; | |
997 | } | |
998 | ||
1b6bf175 TT |
999 | if (ctx->block_dup_map) { |
1000 | if (ctx->options & E2F_OPT_PREEN) { | |
1001 | clear_problem_context(&pctx); | |
1002 | fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); | |
3839e657 | 1003 | } |
08b21301 | 1004 | e2fsck_pass1_dupblocks(ctx, block_buf); |
3839e657 | 1005 | } |
c4e3d3f3 | 1006 | ext2fs_free_mem(&inodes_to_process); |
f3db3566 | 1007 | endit: |
e72a9ba3 | 1008 | e2fsck_use_inode_shortcuts(ctx, 0); |
1e3472c5 | 1009 | |
c4e3d3f3 | 1010 | ext2fs_free_mem(&block_buf); |
cebe48a1 | 1011 | ext2fs_free_mem(&inode); |
21c84b71 | 1012 | |
8bf191e8 | 1013 | #ifdef RESOURCE_TRACK |
5596defa TT |
1014 | if (ctx->options & E2F_OPT_TIME2) { |
1015 | e2fsck_clear_progbar(ctx); | |
0c4a0726 | 1016 | print_resource_track(_("Pass 1"), &rtrack); |
5596defa | 1017 | } |
8bf191e8 | 1018 | #endif |
3839e657 TT |
1019 | } |
1020 | ||
f3db3566 TT |
1021 | /* |
1022 | * When the inode_scan routines call this callback at the end of the | |
1023 | * glock group, call process_inodes. | |
1024 | */ | |
54434927 TT |
1025 | static errcode_t scan_callback(ext2_filsys fs, |
1026 | ext2_inode_scan scan EXT2FS_ATTR((unused)), | |
54dc7ca2 | 1027 | dgrp_t group, void * priv_data) |
f3db3566 | 1028 | { |
54dc7ca2 | 1029 | struct scan_callback_struct *scan_struct; |
f8188fff TT |
1030 | e2fsck_t ctx; |
1031 | ||
54dc7ca2 | 1032 | scan_struct = (struct scan_callback_struct *) priv_data; |
f8188fff TT |
1033 | ctx = scan_struct->ctx; |
1034 | ||
54dc7ca2 | 1035 | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
f8188fff TT |
1036 | |
1037 | if (ctx->progress) | |
a02ce9df TT |
1038 | if ((ctx->progress)(ctx, 1, group+1, |
1039 | ctx->fs->group_desc_count)) | |
1040 | return EXT2_ET_CANCEL_REQUESTED; | |
f8188fff | 1041 | |
f3db3566 TT |
1042 | return 0; |
1043 | } | |
1044 | ||
3839e657 TT |
1045 | /* |
1046 | * Process the inodes in the "inodes to process" list. | |
1047 | */ | |
1b6bf175 | 1048 | static void process_inodes(e2fsck_t ctx, char *block_buf) |
3839e657 TT |
1049 | { |
1050 | int i; | |
1051 | struct ext2_inode *old_stashed_inode; | |
86c627ec | 1052 | ext2_ino_t old_stashed_ino; |
3839e657 TT |
1053 | const char *old_operation; |
1054 | char buf[80]; | |
21c84b71 TT |
1055 | struct problem_context pctx; |
1056 | ||
3839e657 | 1057 | #if 0 |
f3db3566 | 1058 | printf("begin process_inodes: "); |
3839e657 | 1059 | #endif |
86a63e92 TT |
1060 | if (process_inode_count == 0) |
1061 | return; | |
3839e657 | 1062 | old_operation = ehandler_operation(0); |
1b6bf175 TT |
1063 | old_stashed_inode = ctx->stashed_inode; |
1064 | old_stashed_ino = ctx->stashed_ino; | |
3839e657 TT |
1065 | qsort(inodes_to_process, process_inode_count, |
1066 | sizeof(struct process_inode_block), process_inode_cmp); | |
21c84b71 | 1067 | clear_problem_context(&pctx); |
3839e657 | 1068 | for (i=0; i < process_inode_count; i++) { |
1b6bf175 TT |
1069 | pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; |
1070 | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; | |
21c84b71 | 1071 | |
3839e657 | 1072 | #if 0 |
21c84b71 | 1073 | printf("%u ", pctx.ino); |
3839e657 | 1074 | #endif |
86c627ec | 1075 | sprintf(buf, _("reading indirect blocks of inode %u"), |
0c4a0726 | 1076 | pctx.ino); |
3839e657 | 1077 | ehandler_operation(buf); |
1b6bf175 | 1078 | check_blocks(ctx, &pctx, block_buf); |
a02ce9df | 1079 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2df1f6aa | 1080 | break; |
3839e657 | 1081 | } |
1b6bf175 TT |
1082 | ctx->stashed_inode = old_stashed_inode; |
1083 | ctx->stashed_ino = old_stashed_ino; | |
3839e657 TT |
1084 | process_inode_count = 0; |
1085 | #if 0 | |
f3db3566 | 1086 | printf("end process inodes\n"); |
3839e657 TT |
1087 | #endif |
1088 | ehandler_operation(old_operation); | |
1089 | } | |
1090 | ||
4c77fe50 | 1091 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) |
3839e657 TT |
1092 | { |
1093 | const struct process_inode_block *ib_a = | |
1094 | (const struct process_inode_block *) a; | |
1095 | const struct process_inode_block *ib_b = | |
1096 | (const struct process_inode_block *) b; | |
b5acdb6a TT |
1097 | int ret; |
1098 | ||
1099 | ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] - | |
1100 | ib_b->inode.i_block[EXT2_IND_BLOCK]); | |
1101 | if (ret == 0) | |
1102 | ret = ib_a->inode.i_file_acl - ib_b->inode.i_file_acl; | |
1103 | return ret; | |
3839e657 TT |
1104 | } |
1105 | ||
3839e657 | 1106 | /* |
fdbdea09 | 1107 | * Mark an inode as being bad in some what |
3839e657 | 1108 | */ |
fdbdea09 | 1109 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino) |
3839e657 | 1110 | { |
1b6bf175 | 1111 | struct problem_context pctx; |
fdbdea09 TT |
1112 | |
1113 | if (!ctx->inode_bad_map) { | |
1114 | clear_problem_context(&pctx); | |
1b6bf175 | 1115 | |
fdbdea09 TT |
1116 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, |
1117 | _("bad inode map"), &ctx->inode_bad_map); | |
1118 | if (pctx.errcode) { | |
1119 | pctx.num = 3; | |
1120 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1121 | /* Should never get here */ | |
1122 | ctx->flags |= E2F_FLAG_ABORT; | |
1123 | return; | |
1124 | } | |
3839e657 | 1125 | } |
fdbdea09 | 1126 | ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino); |
3839e657 TT |
1127 | } |
1128 | ||
fdbdea09 | 1129 | |
21c84b71 TT |
1130 | /* |
1131 | * This procedure will allocate the inode "bb" (badblock) map table | |
1132 | */ | |
1b6bf175 | 1133 | static void alloc_bb_map(e2fsck_t ctx) |
21c84b71 | 1134 | { |
1b6bf175 | 1135 | struct problem_context pctx; |
21c84b71 | 1136 | |
1b6bf175 TT |
1137 | clear_problem_context(&pctx); |
1138 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, | |
0c4a0726 | 1139 | _("inode in bad block map"), |
1b6bf175 TT |
1140 | &ctx->inode_bb_map); |
1141 | if (pctx.errcode) { | |
1142 | pctx.num = 4; | |
1143 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
1144 | /* Should never get here */ |
1145 | ctx->flags |= E2F_FLAG_ABORT; | |
1146 | return; | |
21c84b71 TT |
1147 | } |
1148 | } | |
1149 | ||
aa4115a4 TT |
1150 | /* |
1151 | * This procedure will allocate the inode imagic table | |
1152 | */ | |
1153 | static void alloc_imagic_map(e2fsck_t ctx) | |
1154 | { | |
1155 | struct problem_context pctx; | |
1156 | ||
1157 | clear_problem_context(&pctx); | |
1158 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, | |
0c4a0726 | 1159 | _("imagic inode map"), |
aa4115a4 TT |
1160 | &ctx->inode_imagic_map); |
1161 | if (pctx.errcode) { | |
1162 | pctx.num = 5; | |
1163 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1164 | /* Should never get here */ | |
1165 | ctx->flags |= E2F_FLAG_ABORT; | |
1166 | return; | |
1167 | } | |
1168 | } | |
1169 | ||
3839e657 TT |
1170 | /* |
1171 | * Marks a block as in use, setting the dup_map if it's been set | |
1172 | * already. Called by process_block and process_bad_block. | |
50e1e10f TT |
1173 | * |
1174 | * WARNING: Assumes checks have already been done to make sure block | |
1175 | * is valid. This is true in both process_block and process_bad_block. | |
3839e657 | 1176 | */ |
1b6bf175 | 1177 | static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block) |
3839e657 | 1178 | { |
1b6bf175 TT |
1179 | struct problem_context pctx; |
1180 | ||
1181 | clear_problem_context(&pctx); | |
3839e657 | 1182 | |
1b6bf175 TT |
1183 | if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) { |
1184 | if (!ctx->block_dup_map) { | |
1185 | pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs, | |
0c4a0726 | 1186 | _("multiply claimed block map"), |
1b6bf175 TT |
1187 | &ctx->block_dup_map); |
1188 | if (pctx.errcode) { | |
1189 | pctx.num = 3; | |
1190 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, | |
1191 | &pctx); | |
08b21301 TT |
1192 | /* Should never get here */ |
1193 | ctx->flags |= E2F_FLAG_ABORT; | |
1194 | return; | |
3839e657 TT |
1195 | } |
1196 | } | |
1b6bf175 | 1197 | ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block); |
3839e657 | 1198 | } else { |
1b6bf175 | 1199 | ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block); |
3839e657 TT |
1200 | } |
1201 | } | |
1202 | ||
e8a3ee62 TT |
1203 | /* |
1204 | * Adjust the extended attribute block's reference counts at the end | |
1205 | * of pass 1, either by subtracting out references for EA blocks that | |
1206 | * are still referenced in ctx->refcount, or by adding references for | |
1207 | * EA blocks that had extra references as accounted for in | |
1208 | * ctx->refcount_extra. | |
1209 | */ | |
1210 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, | |
1211 | char *block_buf, int adjust_sign) | |
1212 | { | |
1213 | struct ext2_ext_attr_header *header; | |
1214 | struct problem_context pctx; | |
1215 | ext2_filsys fs = ctx->fs; | |
e8a3ee62 TT |
1216 | blk_t blk; |
1217 | __u32 should_be; | |
1218 | int count; | |
1219 | ||
1220 | clear_problem_context(&pctx); | |
1221 | ||
1222 | ea_refcount_intr_begin(refcount); | |
1223 | while (1) { | |
1224 | if ((blk = ea_refcount_intr_next(refcount, &count)) == 0) | |
1225 | break; | |
1226 | pctx.blk = blk; | |
1227 | pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf); | |
1228 | if (pctx.errcode) { | |
1229 | fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx); | |
1230 | return; | |
1231 | } | |
1232 | header = (struct ext2_ext_attr_header *) block_buf; | |
1233 | pctx.blkcount = header->h_refcount; | |
1234 | should_be = header->h_refcount + adjust_sign * count; | |
1235 | pctx.num = should_be; | |
1236 | if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) { | |
1237 | header->h_refcount = should_be; | |
1238 | pctx.errcode = ext2fs_write_ext_attr(fs, blk, | |
1239 | block_buf); | |
1240 | if (pctx.errcode) { | |
1241 | fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx); | |
1242 | continue; | |
1243 | } | |
1244 | } | |
1245 | } | |
1246 | } | |
1247 | ||
342d847d TT |
1248 | /* |
1249 | * Handle processing the extended attribute blocks | |
1250 | */ | |
1251 | static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, | |
1252 | char *block_buf) | |
1253 | { | |
1254 | ext2_filsys fs = ctx->fs; | |
1255 | ext2_ino_t ino = pctx->ino; | |
1256 | struct ext2_inode *inode = pctx->inode; | |
1257 | blk_t blk; | |
55fd07ed | 1258 | char * end; |
e8a3ee62 | 1259 | struct ext2_ext_attr_header *header; |
55fd07ed | 1260 | struct ext2_ext_attr_entry *entry; |
342d847d | 1261 | int count; |
86bc90f4 | 1262 | region_t region = 0; |
5469d767 | 1263 | |
342d847d TT |
1264 | blk = inode->i_file_acl; |
1265 | if (blk == 0) | |
1266 | return 0; | |
1267 | ||
1268 | /* | |
1269 | * If the Extended attribute flag isn't set, then a non-zero | |
1270 | * file acl means that the inode is corrupted. | |
1271 | * | |
1272 | * Or if the extended attribute block is an invalid block, | |
1273 | * then the inode is also corrupted. | |
1274 | */ | |
1275 | if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) || | |
1276 | (blk < fs->super->s_first_data_block) || | |
1277 | (blk >= fs->super->s_blocks_count)) { | |
1278 | mark_inode_bad(ctx, ino); | |
1279 | return 0; | |
1280 | } | |
1281 | ||
1282 | /* If ea bitmap hasn't been allocated, create it */ | |
1283 | if (!ctx->block_ea_map) { | |
1284 | pctx->errcode = ext2fs_allocate_block_bitmap(fs, | |
1285 | _("ext attr block map"), | |
1286 | &ctx->block_ea_map); | |
1287 | if (pctx->errcode) { | |
1288 | pctx->num = 2; | |
1289 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx); | |
1290 | ctx->flags |= E2F_FLAG_ABORT; | |
1291 | return 0; | |
1292 | } | |
1293 | } | |
1294 | ||
1295 | /* Create the EA refcount structure if necessary */ | |
1296 | if (!ctx->refcount) { | |
1297 | pctx->errcode = ea_refcount_create(0, &ctx->refcount); | |
1298 | if (pctx->errcode) { | |
1299 | pctx->num = 1; | |
1300 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
1301 | ctx->flags |= E2F_FLAG_ABORT; | |
1302 | return 0; | |
1303 | } | |
1304 | } | |
1305 | ||
b5acdb6a TT |
1306 | #if 0 |
1307 | /* Debugging text */ | |
1308 | printf("Inode %u has EA block %u\n", ino, blk); | |
1309 | #endif | |
1310 | ||
342d847d TT |
1311 | /* Have we seen this EA block before? */ |
1312 | if (ext2fs_fast_test_block_bitmap(ctx->block_ea_map, blk)) { | |
1313 | if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0) | |
1314 | return 1; | |
1315 | /* Ooops, this EA was referenced more than it stated */ | |
1316 | if (!ctx->refcount_extra) { | |
1317 | pctx->errcode = ea_refcount_create(0, | |
1318 | &ctx->refcount_extra); | |
1319 | if (pctx->errcode) { | |
1320 | pctx->num = 2; | |
1321 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
1322 | ctx->flags |= E2F_FLAG_ABORT; | |
55fd07ed | 1323 | return 0; |
342d847d TT |
1324 | } |
1325 | } | |
1326 | ea_refcount_increment(ctx->refcount_extra, blk, 0); | |
1327 | return 1; | |
1328 | } | |
5469d767 | 1329 | |
342d847d TT |
1330 | /* |
1331 | * OK, we haven't seen this EA block yet. So we need to | |
1332 | * validate it | |
1333 | */ | |
1334 | pctx->blk = blk; | |
1335 | pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf); | |
1336 | if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) | |
1337 | goto clear_extattr; | |
342d847d | 1338 | header = (struct ext2_ext_attr_header *) block_buf; |
55fd07ed | 1339 | pctx->blk = inode->i_file_acl; |
0684a4f3 TT |
1340 | if (((ctx->ext_attr_ver == 1) && |
1341 | (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) || | |
1342 | ((ctx->ext_attr_ver == 2) && | |
1343 | (header->h_magic != EXT2_EXT_ATTR_MAGIC))) { | |
1344 | if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx)) | |
1345 | goto clear_extattr; | |
1346 | } | |
0d63467d | 1347 | |
55fd07ed TT |
1348 | if (header->h_blocks != 1) { |
1349 | if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx)) | |
1350 | goto clear_extattr; | |
1351 | } | |
1352 | ||
1353 | region = region_create(0, fs->blocksize); | |
1354 | if (!region) { | |
1355 | fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx); | |
1356 | ctx->flags |= E2F_FLAG_ABORT; | |
1357 | return 0; | |
1358 | } | |
1359 | if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) { | |
1360 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
342d847d TT |
1361 | goto clear_extattr; |
1362 | } | |
5469d767 | 1363 | |
55fd07ed TT |
1364 | entry = (struct ext2_ext_attr_entry *)(header+1); |
1365 | end = block_buf + fs->blocksize; | |
1366 | while ((char *)entry < end && *(__u32 *)entry) { | |
1367 | if (region_allocate(region, (char *)entry - (char *)header, | |
1368 | EXT2_EXT_ATTR_LEN(entry->e_name_len))) { | |
1369 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
1370 | goto clear_extattr; | |
1371 | } | |
0684a4f3 | 1372 | if ((ctx->ext_attr_ver == 1 && |
0d63467d | 1373 | (entry->e_name_len == 0 || entry->e_name_index != 0)) || |
0684a4f3 | 1374 | (ctx->ext_attr_ver == 2 && |
0d63467d | 1375 | entry->e_name_index == 0)) { |
55fd07ed TT |
1376 | if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) |
1377 | goto clear_extattr; | |
1378 | } | |
1379 | if (entry->e_value_block != 0) { | |
1380 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
1381 | goto clear_extattr; | |
1382 | } | |
a34c6ffd AD |
1383 | if (entry->e_value_offs + entry->e_value_size > fs->blocksize) { |
1384 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
1385 | goto clear_extattr; | |
1386 | break; | |
1387 | } | |
14fe1c33 TT |
1388 | if (entry->e_value_size && |
1389 | region_allocate(region, entry->e_value_offs, | |
1390 | EXT2_EXT_ATTR_SIZE(entry->e_value_size))) { | |
55fd07ed TT |
1391 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
1392 | goto clear_extattr; | |
1393 | } | |
1394 | entry = EXT2_EXT_ATTR_NEXT(entry); | |
1395 | } | |
1396 | if (region_allocate(region, (char *)entry - (char *)header, 4)) { | |
1397 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
1398 | goto clear_extattr; | |
1399 | } | |
1400 | region_free(region); | |
342d847d TT |
1401 | |
1402 | count = header->h_refcount - 1; | |
1403 | if (count) | |
1404 | ea_refcount_store(ctx->refcount, blk, count); | |
1405 | mark_block_used(ctx, blk); | |
1406 | ext2fs_fast_mark_block_bitmap(ctx->block_ea_map, blk); | |
342d847d TT |
1407 | return 1; |
1408 | ||
1409 | clear_extattr: | |
5469d767 BB |
1410 | if (region) |
1411 | region_free(region); | |
342d847d TT |
1412 | inode->i_file_acl = 0; |
1413 | e2fsck_write_inode(ctx, ino, inode, "check_ext_attr"); | |
1414 | return 0; | |
1415 | } | |
1416 | ||
503f9e7f TT |
1417 | /* Returns 1 if bad htree, 0 if OK */ |
1418 | static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, | |
54434927 TT |
1419 | ext2_ino_t ino EXT2FS_ATTR((unused)), |
1420 | struct ext2_inode *inode, | |
503f9e7f TT |
1421 | char *block_buf) |
1422 | { | |
1423 | struct ext2_dx_root_info *root; | |
1424 | ext2_filsys fs = ctx->fs; | |
1425 | errcode_t retval; | |
1426 | blk_t blk; | |
1427 | ||
1428 | if ((!LINUX_S_ISDIR(inode->i_mode) && | |
1429 | fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) || | |
1430 | (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && | |
1431 | fix_problem(ctx, PR_1_HTREE_SET, pctx))) | |
1432 | return 1; | |
1433 | ||
1434 | blk = inode->i_block[0]; | |
1435 | if (((blk == 0) || | |
1436 | (blk < fs->super->s_first_data_block) || | |
1437 | (blk >= fs->super->s_blocks_count)) && | |
1438 | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) | |
1439 | return 1; | |
1440 | ||
1441 | retval = io_channel_read_blk(fs->io, blk, 1, block_buf); | |
1442 | if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) | |
1443 | return 1; | |
1444 | ||
1445 | /* XXX should check that beginning matches a directory */ | |
1446 | root = (struct ext2_dx_root_info *) (block_buf + 24); | |
1447 | ||
1448 | if ((root->reserved_zero || root->info_length < 8) && | |
1449 | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) | |
1450 | return 1; | |
1451 | ||
1452 | pctx->num = root->hash_version; | |
1453 | if ((root->hash_version != EXT2_HASH_LEGACY) && | |
1454 | (root->hash_version != EXT2_HASH_HALF_MD4) && | |
f044b4d8 | 1455 | (root->hash_version != EXT2_HASH_TEA) && |
503f9e7f TT |
1456 | fix_problem(ctx, PR_1_HTREE_HASHV, pctx)) |
1457 | return 1; | |
1458 | ||
1459 | if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) && | |
1460 | fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx)) | |
1461 | return 1; | |
1462 | ||
1463 | pctx->num = root->indirect_levels; | |
1464 | if ((root->indirect_levels > 1) && | |
1465 | fix_problem(ctx, PR_1_HTREE_DEPTH, pctx)) | |
1466 | return 1; | |
1467 | ||
1468 | return 0; | |
1469 | } | |
342d847d | 1470 | |
3839e657 TT |
1471 | /* |
1472 | * This subroutine is called on each inode to account for all of the | |
1473 | * blocks used by that inode. | |
1474 | */ | |
1b6bf175 | 1475 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 TT |
1476 | char *block_buf) |
1477 | { | |
1b6bf175 | 1478 | ext2_filsys fs = ctx->fs; |
3839e657 | 1479 | struct process_block_struct pb; |
86c627ec | 1480 | ext2_ino_t ino = pctx->ino; |
21c84b71 | 1481 | struct ext2_inode *inode = pctx->inode; |
246501c6 | 1482 | int bad_size = 0; |
503f9e7f | 1483 | int dirty_inode = 0; |
246501c6 | 1484 | __u64 size; |
3839e657 | 1485 | |
3839e657 | 1486 | pb.ino = ino; |
0684a4f3 TT |
1487 | pb.num_blocks = 0; |
1488 | pb.last_block = -1; | |
f3db3566 | 1489 | pb.num_illegal_blocks = 0; |
21c84b71 | 1490 | pb.suppress = 0; pb.clear = 0; |
74becf3c | 1491 | pb.fragmented = 0; |
1917875f | 1492 | pb.compressed = 0; |
74becf3c | 1493 | pb.previous_block = 0; |
b94a052a | 1494 | pb.is_dir = LINUX_S_ISDIR(inode->i_mode); |
da307041 TT |
1495 | pb.is_reg = LINUX_S_ISREG(inode->i_mode); |
1496 | pb.max_blocks = 1 << (31 - fs->super->s_log_block_size); | |
f3db3566 | 1497 | pb.inode = inode; |
21c84b71 | 1498 | pb.pctx = pctx; |
1b6bf175 TT |
1499 | pb.ctx = ctx; |
1500 | pctx->ino = ino; | |
0684a4f3 | 1501 | pctx->errcode = 0; |
1917875f TT |
1502 | |
1503 | if (inode->i_flags & EXT2_COMPRBLK_FL) { | |
f5ae75e5 TT |
1504 | if (fs->super->s_feature_incompat & |
1505 | EXT2_FEATURE_INCOMPAT_COMPRESSION) | |
1917875f TT |
1506 | pb.compressed = 1; |
1507 | else { | |
1508 | if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { | |
1509 | inode->i_flags &= ~EXT2_COMPRBLK_FL; | |
503f9e7f | 1510 | dirty_inode++; |
1917875f TT |
1511 | } |
1512 | } | |
1513 | } | |
1514 | ||
dc71f23e TT |
1515 | if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf)) |
1516 | pb.num_blocks++; | |
1517 | ||
0684a4f3 TT |
1518 | if (ext2fs_inode_has_valid_blocks(inode)) |
1519 | pctx->errcode = ext2fs_block_iterate2(fs, ino, | |
21c84b71 TT |
1520 | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
1521 | block_buf, process_block, &pb); | |
1b6bf175 | 1522 | end_problem_latch(ctx, PR_LATCH_BLOCK); |
da307041 | 1523 | end_problem_latch(ctx, PR_LATCH_TOOBIG); |
0684a4f3 TT |
1524 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
1525 | goto out; | |
1b6bf175 TT |
1526 | if (pctx->errcode) |
1527 | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); | |
3839e657 | 1528 | |
74becf3c | 1529 | if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) |
1b6bf175 | 1530 | ctx->fs_fragmented++; |
74becf3c | 1531 | |
f3db3566 | 1532 | if (pb.clear) { |
f3db3566 | 1533 | inode->i_links_count = 0; |
1b6bf175 | 1534 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
1f3ad14a | 1535 | inode->i_dtime = ctx->now; |
503f9e7f | 1536 | dirty_inode++; |
1b6bf175 | 1537 | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
aa4115a4 | 1538 | ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino); |
1b6bf175 | 1539 | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); |
f3db3566 TT |
1540 | /* |
1541 | * The inode was probably partially accounted for | |
1542 | * before processing was aborted, so we need to | |
1543 | * restart the pass 1 scan. | |
1544 | */ | |
08b21301 | 1545 | ctx->flags |= E2F_FLAG_RESTART; |
503f9e7f | 1546 | goto out; |
f3db3566 | 1547 | } |
8fdc9985 TT |
1548 | |
1549 | if (inode->i_flags & EXT2_INDEX_FL) { | |
503f9e7f TT |
1550 | if (handle_htree(ctx, pctx, ino, inode, block_buf)) { |
1551 | inode->i_flags &= ~EXT2_INDEX_FL; | |
1552 | dirty_inode++; | |
1553 | } else { | |
8fdc9985 TT |
1554 | #ifdef ENABLE_HTREE |
1555 | e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); | |
1556 | #endif | |
503f9e7f | 1557 | } |
8fdc9985 | 1558 | } |
b7a00563 TT |
1559 | if (ctx->dirs_to_hash && pb.is_dir && |
1560 | !(inode->i_flags & EXT2_INDEX_FL) && | |
1561 | ((inode->i_size / fs->blocksize) >= 3)) | |
1562 | ext2fs_u32_list_add(ctx->dirs_to_hash, ino); | |
1563 | ||
3839e657 | 1564 | if (!pb.num_blocks && pb.is_dir) { |
1b6bf175 | 1565 | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
3839e657 | 1566 | inode->i_links_count = 0; |
1b6bf175 | 1567 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
1f3ad14a | 1568 | inode->i_dtime = ctx->now; |
503f9e7f | 1569 | dirty_inode++; |
1b6bf175 | 1570 | ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); |
aa4115a4 | 1571 | ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino); |
1b6bf175 TT |
1572 | ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); |
1573 | ctx->fs_directory_count--; | |
0684a4f3 | 1574 | goto out; |
21c84b71 | 1575 | } |
3839e657 | 1576 | } |
0684a4f3 | 1577 | |
0684a4f3 TT |
1578 | pb.num_blocks *= (fs->blocksize / 512); |
1579 | #if 0 | |
1580 | printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n", | |
1581 | ino, inode->i_size, pb.last_block, inode->i_blocks, | |
1582 | pb.num_blocks); | |
1583 | #endif | |
246501c6 TT |
1584 | if (pb.is_dir) { |
1585 | int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); | |
da307041 | 1586 | if (nblock > (pb.last_block + 1)) |
246501c6 TT |
1587 | bad_size = 1; |
1588 | else if (nblock < (pb.last_block + 1)) { | |
246501c6 | 1589 | if (((pb.last_block + 1) - nblock) > |
5dd8f963 | 1590 | fs->super->s_prealloc_dir_blocks) |
9d1bd3de | 1591 | bad_size = 2; |
246501c6 TT |
1592 | } |
1593 | } else { | |
4f489285 | 1594 | size = EXT2_I_SIZE(inode); |
0684a4f3 | 1595 | if ((pb.last_block >= 0) && |
54434927 | 1596 | (size < (__u64) pb.last_block * fs->blocksize)) |
9d1bd3de | 1597 | bad_size = 3; |
246501c6 | 1598 | else if (size > ext2_max_sizes[fs->super->s_log_block_size]) |
9d1bd3de | 1599 | bad_size = 4; |
246501c6 | 1600 | } |
0684a4f3 TT |
1601 | /* i_size for symlinks is checked elsewhere */ |
1602 | if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) { | |
21c84b71 | 1603 | pctx->num = (pb.last_block+1) * fs->blocksize; |
1b6bf175 | 1604 | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
21c84b71 | 1605 | inode->i_size = pctx->num; |
0684a4f3 | 1606 | if (!LINUX_S_ISDIR(inode->i_mode)) |
246501c6 | 1607 | inode->i_size_high = pctx->num >> 32; |
503f9e7f | 1608 | dirty_inode++; |
21c84b71 TT |
1609 | } |
1610 | pctx->num = 0; | |
3839e657 | 1611 | } |
b94a052a AD |
1612 | if (LINUX_S_ISREG(inode->i_mode) && |
1613 | (inode->i_size_high || inode->i_size & 0x80000000UL)) | |
246501c6 | 1614 | ctx->large_files++; |
3839e657 | 1615 | if (pb.num_blocks != inode->i_blocks) { |
21c84b71 | 1616 | pctx->num = pb.num_blocks; |
1b6bf175 | 1617 | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
3839e657 | 1618 | inode->i_blocks = pb.num_blocks; |
503f9e7f | 1619 | dirty_inode++; |
21c84b71 TT |
1620 | } |
1621 | pctx->num = 0; | |
3839e657 | 1622 | } |
503f9e7f TT |
1623 | out: |
1624 | if (dirty_inode) | |
1625 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); | |
50e1e10f TT |
1626 | } |
1627 | ||
21c84b71 | 1628 | #if 0 |
50e1e10f TT |
1629 | /* |
1630 | * Helper function called by process block when an illegal block is | |
1631 | * found. It returns a description about why the block is illegal | |
1632 | */ | |
1633 | static char *describe_illegal_block(ext2_filsys fs, blk_t block) | |
1634 | { | |
1635 | blk_t super; | |
1636 | int i; | |
1637 | static char problem[80]; | |
1638 | ||
1639 | super = fs->super->s_first_data_block; | |
1640 | strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block"); | |
1641 | if (block < super) { | |
1642 | sprintf(problem, "< FIRSTBLOCK (%u)", super); | |
1643 | return(problem); | |
1644 | } else if (block >= fs->super->s_blocks_count) { | |
1645 | sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count); | |
1646 | return(problem); | |
1647 | } | |
1648 | for (i = 0; i < fs->group_desc_count; i++) { | |
1649 | if (block == super) { | |
1650 | sprintf(problem, "is the superblock in group %d", i); | |
1651 | break; | |
1652 | } | |
1653 | if (block > super && | |
1654 | block <= (super + fs->desc_blocks)) { | |
1655 | sprintf(problem, "is in the group descriptors " | |
1656 | "of group %d", i); | |
1657 | break; | |
1658 | } | |
1659 | if (block == fs->group_desc[i].bg_block_bitmap) { | |
1660 | sprintf(problem, "is the block bitmap of group %d", i); | |
1661 | break; | |
1662 | } | |
1663 | if (block == fs->group_desc[i].bg_inode_bitmap) { | |
1664 | sprintf(problem, "is the inode bitmap of group %d", i); | |
1665 | break; | |
1666 | } | |
1667 | if (block >= fs->group_desc[i].bg_inode_table && | |
1668 | (block < fs->group_desc[i].bg_inode_table | |
1669 | + fs->inode_blocks_per_group)) { | |
1670 | sprintf(problem, "is in the inode table of group %d", | |
1671 | i); | |
1672 | break; | |
1673 | } | |
1674 | super += fs->super->s_blocks_per_group; | |
1675 | } | |
1676 | return(problem); | |
1677 | } | |
21c84b71 | 1678 | #endif |
3839e657 TT |
1679 | |
1680 | /* | |
1681 | * This is a helper function for check_blocks(). | |
1682 | */ | |
53ef44c4 | 1683 | static int process_block(ext2_filsys fs, |
3839e657 | 1684 | blk_t *block_nr, |
9d1bd3de | 1685 | e2_blkcnt_t blockcnt, |
54434927 TT |
1686 | blk_t ref_block EXT2FS_ATTR((unused)), |
1687 | int ref_offset EXT2FS_ATTR((unused)), | |
54dc7ca2 | 1688 | void *priv_data) |
3839e657 TT |
1689 | { |
1690 | struct process_block_struct *p; | |
21c84b71 | 1691 | struct problem_context *pctx; |
3839e657 | 1692 | blk_t blk = *block_nr; |
50e1e10f | 1693 | int ret_code = 0; |
21c84b71 | 1694 | int problem = 0; |
1b6bf175 | 1695 | e2fsck_t ctx; |
3839e657 | 1696 | |
54dc7ca2 | 1697 | p = (struct process_block_struct *) priv_data; |
21c84b71 | 1698 | pctx = p->pctx; |
1b6bf175 | 1699 | ctx = p->ctx; |
3839e657 | 1700 | |
1917875f TT |
1701 | if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) { |
1702 | /* todo: Check that the comprblk_fl is high, that the | |
1703 | blkaddr pattern looks right (all non-holes up to | |
1704 | first EXT2FS_COMPRESSED_BLKADDR, then all | |
1705 | EXT2FS_COMPRESSED_BLKADDR up to end of cluster), | |
1706 | that the feature_incompat bit is high, and that the | |
1707 | inode is a regular file. If we're doing a "full | |
1708 | check" (a concept introduced to e2fsck by e2compr, | |
1709 | meaning that we look at data blocks as well as | |
1710 | metadata) then call some library routine that | |
1711 | checks the compressed data. I'll have to think | |
1712 | about this, because one particularly important | |
1713 | problem to be able to fix is to recalculate the | |
1714 | cluster size if necessary. I think that perhaps | |
1715 | we'd better do most/all e2compr-specific checks | |
1716 | separately, after the non-e2compr checks. If not | |
1717 | doing a full check, it may be useful to test that | |
1718 | the personality is linux; e.g. if it isn't then | |
1719 | perhaps this really is just an illegal block. */ | |
1720 | return 0; | |
1721 | } | |
b94a052a | 1722 | |
50e1e10f TT |
1723 | if (blk == 0) { |
1724 | if (p->is_dir == 0) { | |
1e3472c5 TT |
1725 | /* |
1726 | * Should never happen, since only directories | |
1727 | * get called with BLOCK_FLAG_HOLE | |
1728 | */ | |
1b6bf175 | 1729 | #if DEBUG_E2FSCK |
50e1e10f | 1730 | printf("process_block() called with blk == 0, " |
5c576477 TT |
1731 | "blockcnt=%d, inode %lu???\n", |
1732 | blockcnt, p->ino); | |
1b6bf175 | 1733 | #endif |
50e1e10f TT |
1734 | return 0; |
1735 | } | |
1736 | if (blockcnt < 0) | |
1737 | return 0; | |
1738 | if (blockcnt * fs->blocksize < p->inode->i_size) { | |
21c84b71 TT |
1739 | #if 0 |
1740 | printf("Missing block (#%d) in directory inode %lu!\n", | |
1741 | blockcnt, p->ino); | |
1742 | #endif | |
50e1e10f TT |
1743 | goto mark_dir; |
1744 | } | |
1745 | return 0; | |
1746 | } | |
1747 | ||
3839e657 | 1748 | #if 0 |
50e1e10f | 1749 | printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk, |
3839e657 | 1750 | blockcnt); |
50e1e10f | 1751 | #endif |
3839e657 | 1752 | |
74becf3c TT |
1753 | /* |
1754 | * Simplistic fragmentation check. We merely require that the | |
1755 | * file be contiguous. (Which can never be true for really | |
1756 | * big files that are greater than a block group.) | |
1757 | */ | |
1917875f | 1758 | if (!HOLE_BLKADDR(p->previous_block)) { |
74becf3c TT |
1759 | if (p->previous_block+1 != blk) |
1760 | p->fragmented = 1; | |
1761 | } | |
1762 | p->previous_block = blk; | |
503f9e7f | 1763 | |
8421fb67 | 1764 | if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size))) |
da307041 TT |
1765 | problem = PR_1_TOOBIG_DIR; |
1766 | if (p->is_reg && p->num_blocks+1 >= p->max_blocks) | |
1767 | problem = PR_1_TOOBIG_REG; | |
1768 | if (!p->is_dir && !p->is_reg && blockcnt > 0) | |
1769 | problem = PR_1_TOOBIG_SYMLINK; | |
1770 | ||
50e1e10f | 1771 | if (blk < fs->super->s_first_data_block || |
21c84b71 TT |
1772 | blk >= fs->super->s_blocks_count) |
1773 | problem = PR_1_ILLEGAL_BLOCK_NUM; | |
21c84b71 TT |
1774 | |
1775 | if (problem) { | |
f3db3566 | 1776 | p->num_illegal_blocks++; |
21c84b71 | 1777 | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
1b6bf175 | 1778 | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
f3db3566 TT |
1779 | p->clear = 1; |
1780 | return BLOCK_ABORT; | |
1781 | } | |
f8188fff | 1782 | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
f3db3566 | 1783 | p->suppress = 1; |
1b6bf175 TT |
1784 | set_latch_flags(PR_LATCH_BLOCK, |
1785 | PRL_SUPPRESS, 0); | |
f3db3566 TT |
1786 | } |
1787 | } | |
21c84b71 TT |
1788 | pctx->blk = blk; |
1789 | pctx->blkcount = blockcnt; | |
1b6bf175 | 1790 | if (fix_problem(ctx, problem, pctx)) { |
50e1e10f TT |
1791 | blk = *block_nr = 0; |
1792 | ret_code = BLOCK_CHANGED; | |
1793 | goto mark_dir; | |
21c84b71 | 1794 | } else |
3839e657 | 1795 | return 0; |
3839e657 TT |
1796 | } |
1797 | ||
d323f8fb | 1798 | if (p->ino == EXT2_RESIZE_INO) { |
c3ffaf83 TT |
1799 | /* |
1800 | * The resize inode has already be sanity checked | |
1801 | * during pass #0 (the superblock checks). All we | |
1802 | * have to do is mark the double indirect block as | |
1803 | * being in use; all of the other blocks are handled | |
1804 | * by mark_table_blocks()). | |
1805 | */ | |
1806 | if (blockcnt == BLOCK_COUNT_DIND) | |
d323f8fb TT |
1807 | mark_block_used(ctx, blk); |
1808 | } else | |
1809 | mark_block_used(ctx, blk); | |
50e1e10f | 1810 | p->num_blocks++; |
1e3472c5 TT |
1811 | if (blockcnt >= 0) |
1812 | p->last_block = blockcnt; | |
50e1e10f | 1813 | mark_dir: |
1e3472c5 | 1814 | if (p->is_dir && (blockcnt >= 0)) { |
1b6bf175 TT |
1815 | pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino, |
1816 | blk, blockcnt); | |
1817 | if (pctx->errcode) { | |
1818 | pctx->blk = blk; | |
1819 | pctx->num = blockcnt; | |
1820 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); | |
08b21301 TT |
1821 | /* Should never get here */ |
1822 | ctx->flags |= E2F_FLAG_ABORT; | |
1823 | return BLOCK_ABORT; | |
3839e657 | 1824 | } |
3839e657 | 1825 | } |
50e1e10f | 1826 | return ret_code; |
3839e657 TT |
1827 | } |
1828 | ||
53ef44c4 | 1829 | static int process_bad_block(ext2_filsys fs, |
3839e657 | 1830 | blk_t *block_nr, |
9d1bd3de | 1831 | e2_blkcnt_t blockcnt, |
54434927 TT |
1832 | blk_t ref_block EXT2FS_ATTR((unused)), |
1833 | int ref_offset EXT2FS_ATTR((unused)), | |
54dc7ca2 | 1834 | void *priv_data) |
3839e657 TT |
1835 | { |
1836 | struct process_block_struct *p; | |
3839e657 | 1837 | blk_t blk = *block_nr; |
54434927 TT |
1838 | blk_t first_block; |
1839 | dgrp_t i; | |
21c84b71 | 1840 | struct problem_context *pctx; |
1b6bf175 | 1841 | e2fsck_t ctx; |
21c84b71 | 1842 | |
1917875f TT |
1843 | /* |
1844 | * Note: This function processes blocks for the bad blocks | |
1845 | * inode, which is never compressed. So we don't use HOLE_BLKADDR(). | |
1846 | */ | |
1847 | ||
3839e657 TT |
1848 | if (!blk) |
1849 | return 0; | |
21c84b71 | 1850 | |
54dc7ca2 | 1851 | p = (struct process_block_struct *) priv_data; |
1b6bf175 | 1852 | ctx = p->ctx; |
21c84b71 TT |
1853 | pctx = p->pctx; |
1854 | ||
f8188fff | 1855 | pctx->ino = EXT2_BAD_INO; |
21c84b71 TT |
1856 | pctx->blk = blk; |
1857 | pctx->blkcount = blockcnt; | |
3839e657 TT |
1858 | |
1859 | if ((blk < fs->super->s_first_data_block) || | |
1860 | (blk >= fs->super->s_blocks_count)) { | |
1b6bf175 | 1861 | if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { |
3839e657 TT |
1862 | *block_nr = 0; |
1863 | return BLOCK_CHANGED; | |
21c84b71 | 1864 | } else |
3839e657 | 1865 | return 0; |
3839e657 TT |
1866 | } |
1867 | ||
1868 | if (blockcnt < 0) { | |
000ba404 TT |
1869 | if (ext2fs_test_block_bitmap(p->fs_meta_blocks, blk)) { |
1870 | p->bbcheck = 1; | |
1871 | if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) { | |
1872 | *block_nr = 0; | |
1873 | return BLOCK_CHANGED; | |
1874 | } | |
1875 | } else if (ext2fs_test_block_bitmap(ctx->block_found_map, | |
1876 | blk)) { | |
1877 | p->bbcheck = 1; | |
1878 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, | |
1879 | pctx)) { | |
1880 | *block_nr = 0; | |
1881 | return BLOCK_CHANGED; | |
1882 | } | |
a02ce9df | 1883 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
1884 | return BLOCK_ABORT; |
1885 | } else | |
1b6bf175 | 1886 | mark_block_used(ctx, blk); |
3839e657 TT |
1887 | return 0; |
1888 | } | |
1889 | #if 0 | |
50e1e10f | 1890 | printf ("DEBUG: Marking %u as bad.\n", blk); |
3839e657 | 1891 | #endif |
1b6bf175 | 1892 | ctx->fs_badblocks_count++; |
3839e657 TT |
1893 | /* |
1894 | * If the block is not used, then mark it as used and return. | |
1895 | * If it is already marked as found, this must mean that | |
1896 | * there's an overlap between the filesystem table blocks | |
1897 | * (bitmaps and inode table) and the bad block list. | |
1898 | */ | |
1b6bf175 TT |
1899 | if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) { |
1900 | ext2fs_mark_block_bitmap(ctx->block_found_map, blk); | |
3839e657 TT |
1901 | return 0; |
1902 | } | |
f3db3566 TT |
1903 | /* |
1904 | * Try to find the where the filesystem block was used... | |
1905 | */ | |
1906 | first_block = fs->super->s_first_data_block; | |
1907 | ||
1908 | for (i = 0; i < fs->group_desc_count; i++ ) { | |
21c84b71 | 1909 | pctx->group = i; |
1b6bf175 | 1910 | pctx->blk = blk; |
8039c480 TT |
1911 | if (!ext2fs_bg_has_super(fs, i)) |
1912 | goto skip_super; | |
f3db3566 TT |
1913 | if (blk == first_block) { |
1914 | if (i == 0) { | |
1b6bf175 TT |
1915 | if (fix_problem(ctx, |
1916 | PR_1_BAD_PRIMARY_SUPERBLOCK, | |
1917 | pctx)) { | |
1918 | *block_nr = 0; | |
50e1e10f | 1919 | return BLOCK_CHANGED; |
1b6bf175 | 1920 | } |
50e1e10f | 1921 | return 0; |
f3db3566 | 1922 | } |
1b6bf175 | 1923 | fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); |
f3db3566 TT |
1924 | return 0; |
1925 | } | |
1926 | if ((blk > first_block) && | |
1927 | (blk <= first_block + fs->desc_blocks)) { | |
1928 | if (i == 0) { | |
1b6bf175 TT |
1929 | pctx->blk = *block_nr; |
1930 | if (fix_problem(ctx, | |
1931 | PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { | |
1932 | *block_nr = 0; | |
50e1e10f | 1933 | return BLOCK_CHANGED; |
1b6bf175 | 1934 | } |
50e1e10f | 1935 | return 0; |
f3db3566 | 1936 | } |
1b6bf175 | 1937 | fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); |
f3db3566 | 1938 | return 0; |
3839e657 | 1939 | } |
8039c480 | 1940 | skip_super: |
f3db3566 | 1941 | if (blk == fs->group_desc[i].bg_block_bitmap) { |
1b6bf175 TT |
1942 | if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { |
1943 | ctx->invalid_block_bitmap_flag[i]++; | |
1944 | ctx->invalid_bitmaps++; | |
21c84b71 | 1945 | } |
f3db3566 TT |
1946 | return 0; |
1947 | } | |
1948 | if (blk == fs->group_desc[i].bg_inode_bitmap) { | |
1b6bf175 TT |
1949 | if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { |
1950 | ctx->invalid_inode_bitmap_flag[i]++; | |
1951 | ctx->invalid_bitmaps++; | |
21c84b71 | 1952 | } |
f3db3566 TT |
1953 | return 0; |
1954 | } | |
1955 | if ((blk >= fs->group_desc[i].bg_inode_table) && | |
1956 | (blk < (fs->group_desc[i].bg_inode_table + | |
1957 | fs->inode_blocks_per_group))) { | |
21c84b71 TT |
1958 | /* |
1959 | * If there are bad blocks in the inode table, | |
1960 | * the inode scan code will try to do | |
1961 | * something reasonable automatically. | |
1962 | */ | |
f3db3566 TT |
1963 | return 0; |
1964 | } | |
8039c480 | 1965 | first_block += fs->super->s_blocks_per_group; |
f3db3566 TT |
1966 | } |
1967 | /* | |
1968 | * If we've gotten to this point, then the only | |
1969 | * possibility is that the bad block inode meta data | |
1970 | * is using a bad block. | |
1971 | */ | |
1972 | if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) || | |
000ba404 TT |
1973 | (blk == p->inode->i_block[EXT2_DIND_BLOCK]) || |
1974 | (blk == p->inode->i_block[EXT2_TIND_BLOCK])) { | |
1975 | p->bbcheck = 1; | |
1976 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) { | |
1977 | *block_nr = 0; | |
1978 | return BLOCK_CHANGED; | |
1979 | } | |
a02ce9df | 1980 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 1981 | return BLOCK_ABORT; |
f3db3566 | 1982 | return 0; |
3839e657 | 1983 | } |
1b6bf175 TT |
1984 | |
1985 | pctx->group = -1; | |
1986 | ||
1987 | /* Warn user that the block wasn't claimed */ | |
1988 | fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx); | |
1989 | ||
f3db3566 | 1990 | return 0; |
3839e657 TT |
1991 | } |
1992 | ||
1b6bf175 | 1993 | static void new_table_block(e2fsck_t ctx, blk_t first_block, int group, |
3839e657 TT |
1994 | const char *name, int num, blk_t *new_block) |
1995 | { | |
1b6bf175 | 1996 | ext2_filsys fs = ctx->fs; |
3839e657 | 1997 | blk_t old_block = *new_block; |
abf23439 | 1998 | blk_t last_block; |
3839e657 TT |
1999 | int i; |
2000 | char *buf; | |
1b6bf175 TT |
2001 | struct problem_context pctx; |
2002 | ||
2003 | clear_problem_context(&pctx); | |
2004 | ||
2005 | pctx.group = group; | |
2006 | pctx.blk = old_block; | |
2007 | pctx.str = name; | |
2008 | ||
abf23439 ES |
2009 | last_block = ext2fs_group_last_block(fs, group); |
2010 | pctx.errcode = ext2fs_get_free_blocks(fs, first_block, last_block, | |
1b6bf175 TT |
2011 | num, ctx->block_found_map, new_block); |
2012 | if (pctx.errcode) { | |
2013 | pctx.num = num; | |
2014 | fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); | |
3839e657 TT |
2015 | ext2fs_unmark_valid(fs); |
2016 | return; | |
2017 | } | |
c4e3d3f3 | 2018 | pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf); |
08b21301 | 2019 | if (pctx.errcode) { |
1b6bf175 | 2020 | fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); |
3839e657 TT |
2021 | ext2fs_unmark_valid(fs); |
2022 | return; | |
2023 | } | |
2024 | ext2fs_mark_super_dirty(fs); | |
299d7424 | 2025 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
1b6bf175 TT |
2026 | pctx.blk2 = *new_block; |
2027 | fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO : | |
2028 | PR_1_RELOC_TO), &pctx); | |
2029 | pctx.blk2 = 0; | |
3839e657 | 2030 | for (i = 0; i < num; i++) { |
1b6bf175 TT |
2031 | pctx.blk = i; |
2032 | ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i); | |
f3db3566 | 2033 | if (old_block) { |
1b6bf175 TT |
2034 | pctx.errcode = io_channel_read_blk(fs->io, |
2035 | old_block + i, 1, buf); | |
2036 | if (pctx.errcode) | |
2037 | fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); | |
f3db3566 TT |
2038 | } else |
2039 | memset(buf, 0, fs->blocksize); | |
2040 | ||
1b6bf175 TT |
2041 | pctx.blk = (*new_block) + i; |
2042 | pctx.errcode = io_channel_write_blk(fs->io, pctx.blk, | |
3839e657 | 2043 | 1, buf); |
1b6bf175 TT |
2044 | if (pctx.errcode) |
2045 | fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); | |
3839e657 | 2046 | } |
c4e3d3f3 | 2047 | ext2fs_free_mem(&buf); |
3839e657 TT |
2048 | } |
2049 | ||
2050 | /* | |
f3db3566 TT |
2051 | * This routine gets called at the end of pass 1 if bad blocks are |
2052 | * detected in the superblock, group descriptors, inode_bitmaps, or | |
2053 | * block bitmaps. At this point, all of the blocks have been mapped | |
2054 | * out, so we can try to allocate new block(s) to replace the bad | |
2055 | * blocks. | |
3839e657 | 2056 | */ |
1b6bf175 | 2057 | static void handle_fs_bad_blocks(e2fsck_t ctx) |
3839e657 | 2058 | { |
1b6bf175 | 2059 | ext2_filsys fs = ctx->fs; |
54434927 | 2060 | dgrp_t i; |
d1b4b85c | 2061 | blk_t first_block; |
3839e657 TT |
2062 | |
2063 | for (i = 0; i < fs->group_desc_count; i++) { | |
abf23439 ES |
2064 | first_block = ext2fs_group_first_block(fs, i); |
2065 | ||
1b6bf175 | 2066 | if (ctx->invalid_block_bitmap_flag[i]) { |
0c4a0726 | 2067 | new_table_block(ctx, first_block, i, _("block bitmap"), |
1b6bf175 | 2068 | 1, &fs->group_desc[i].bg_block_bitmap); |
3839e657 | 2069 | } |
1b6bf175 | 2070 | if (ctx->invalid_inode_bitmap_flag[i]) { |
0c4a0726 | 2071 | new_table_block(ctx, first_block, i, _("inode bitmap"), |
1b6bf175 | 2072 | 1, &fs->group_desc[i].bg_inode_bitmap); |
3839e657 | 2073 | } |
1b6bf175 | 2074 | if (ctx->invalid_inode_table_flag[i]) { |
0c4a0726 | 2075 | new_table_block(ctx, first_block, i, _("inode table"), |
f3db3566 | 2076 | fs->inode_blocks_per_group, |
3839e657 | 2077 | &fs->group_desc[i].bg_inode_table); |
08b21301 | 2078 | ctx->flags |= E2F_FLAG_RESTART; |
3839e657 | 2079 | } |
3839e657 | 2080 | } |
1b6bf175 | 2081 | ctx->invalid_bitmaps = 0; |
3839e657 TT |
2082 | } |
2083 | ||
2084 | /* | |
2085 | * This routine marks all blocks which are used by the superblock, | |
2086 | * group descriptors, inode bitmaps, and block bitmaps. | |
2087 | */ | |
1b6bf175 | 2088 | static void mark_table_blocks(e2fsck_t ctx) |
3839e657 | 2089 | { |
1b6bf175 | 2090 | ext2_filsys fs = ctx->fs; |
62c6d140 | 2091 | blk_t b; |
54434927 TT |
2092 | dgrp_t i; |
2093 | int j; | |
21c84b71 TT |
2094 | struct problem_context pctx; |
2095 | ||
2096 | clear_problem_context(&pctx); | |
3839e657 | 2097 | |
3839e657 | 2098 | for (i = 0; i < fs->group_desc_count; i++) { |
21c84b71 | 2099 | pctx.group = i; |
da2e97f7 | 2100 | |
ef344e13 TT |
2101 | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map); |
2102 | ||
21c84b71 TT |
2103 | /* |
2104 | * Mark the blocks used for the inode table | |
2105 | */ | |
2106 | if (fs->group_desc[i].bg_inode_table) { | |
2107 | for (j = 0, b = fs->group_desc[i].bg_inode_table; | |
2108 | j < fs->inode_blocks_per_group; | |
2109 | j++, b++) { | |
1b6bf175 | 2110 | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
21c84b71 TT |
2111 | b)) { |
2112 | pctx.blk = b; | |
1b6bf175 | 2113 | if (fix_problem(ctx, |
21c84b71 | 2114 | PR_1_ITABLE_CONFLICT, &pctx)) { |
1b6bf175 TT |
2115 | ctx->invalid_inode_table_flag[i]++; |
2116 | ctx->invalid_bitmaps++; | |
21c84b71 TT |
2117 | } |
2118 | } else { | |
1b6bf175 | 2119 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
21c84b71 | 2120 | b); |
21c84b71 TT |
2121 | } |
2122 | } | |
2123 | } | |
2124 | ||
3839e657 TT |
2125 | /* |
2126 | * Mark block used for the block bitmap | |
2127 | */ | |
f3db3566 | 2128 | if (fs->group_desc[i].bg_block_bitmap) { |
1b6bf175 | 2129 | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
f3db3566 | 2130 | fs->group_desc[i].bg_block_bitmap)) { |
21c84b71 | 2131 | pctx.blk = fs->group_desc[i].bg_block_bitmap; |
1b6bf175 TT |
2132 | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
2133 | ctx->invalid_block_bitmap_flag[i]++; | |
2134 | ctx->invalid_bitmaps++; | |
f3db3566 | 2135 | } |
50e1e10f | 2136 | } else { |
1b6bf175 | 2137 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
f3db3566 | 2138 | fs->group_desc[i].bg_block_bitmap); |
50e1e10f TT |
2139 | } |
2140 | ||
f3db3566 | 2141 | } |
3839e657 TT |
2142 | /* |
2143 | * Mark block used for the inode bitmap | |
2144 | */ | |
f3db3566 | 2145 | if (fs->group_desc[i].bg_inode_bitmap) { |
1b6bf175 | 2146 | if (ext2fs_test_block_bitmap(ctx->block_found_map, |
f3db3566 | 2147 | fs->group_desc[i].bg_inode_bitmap)) { |
21c84b71 | 2148 | pctx.blk = fs->group_desc[i].bg_inode_bitmap; |
1b6bf175 TT |
2149 | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
2150 | ctx->invalid_inode_bitmap_flag[i]++; | |
2151 | ctx->invalid_bitmaps++; | |
21c84b71 | 2152 | } |
50e1e10f | 2153 | } else { |
1b6bf175 | 2154 | ext2fs_mark_block_bitmap(ctx->block_found_map, |
f3db3566 | 2155 | fs->group_desc[i].bg_inode_bitmap); |
50e1e10f | 2156 | } |
f3db3566 | 2157 | } |
3839e657 TT |
2158 | } |
2159 | } | |
2160 | ||
2161 | /* | |
e72a9ba3 | 2162 | * Thes subroutines short circuits ext2fs_get_blocks and |
3839e657 TT |
2163 | * ext2fs_check_directory; we use them since we already have the inode |
2164 | * structure, so there's no point in letting the ext2fs library read | |
2165 | * the inode again. | |
2166 | */ | |
86c627ec TT |
2167 | static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino, |
2168 | blk_t *blocks) | |
3839e657 | 2169 | { |
54dc7ca2 | 2170 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
3839e657 TT |
2171 | int i; |
2172 | ||
71d521c6 | 2173 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
521e3685 TT |
2174 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2175 | ||
2176 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
1b6bf175 | 2177 | blocks[i] = ctx->stashed_inode->i_block[i]; |
521e3685 | 2178 | return 0; |
3839e657 TT |
2179 | } |
2180 | ||
86c627ec | 2181 | static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino, |
e72a9ba3 | 2182 | struct ext2_inode *inode) |
1e3472c5 | 2183 | { |
54dc7ca2 | 2184 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2185 | |
71d521c6 | 2186 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1e3472c5 | 2187 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1b6bf175 | 2188 | *inode = *ctx->stashed_inode; |
1e3472c5 TT |
2189 | return 0; |
2190 | } | |
2191 | ||
86c627ec | 2192 | static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino, |
1e3472c5 TT |
2193 | struct ext2_inode *inode) |
2194 | { | |
54dc7ca2 | 2195 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2196 | |
27431595 TT |
2197 | if ((ino == ctx->stashed_ino) && ctx->stashed_inode && |
2198 | (inode != ctx->stashed_inode)) | |
1b6bf175 | 2199 | *ctx->stashed_inode = *inode; |
1e3472c5 TT |
2200 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2201 | } | |
2202 | ||
86c627ec | 2203 | static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino) |
3839e657 | 2204 | { |
54dc7ca2 | 2205 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2206 | |
71d521c6 | 2207 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1b6bf175 TT |
2208 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2209 | ||
2210 | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) | |
291c9049 | 2211 | return EXT2_ET_NO_DIRECTORY; |
1b6bf175 | 2212 | return 0; |
3839e657 | 2213 | } |
e72a9ba3 TT |
2214 | |
2215 | void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool) | |
2216 | { | |
2217 | ext2_filsys fs = ctx->fs; | |
2218 | ||
2219 | if (bool) { | |
2220 | fs->get_blocks = pass1_get_blocks; | |
2221 | fs->check_directory = pass1_check_directory; | |
2222 | fs->read_inode = pass1_read_inode; | |
2223 | fs->write_inode = pass1_write_inode; | |
2224 | ctx->stashed_ino = 0; | |
2225 | } else { | |
2226 | fs->get_blocks = 0; | |
2227 | fs->check_directory = 0; | |
2228 | fs->read_inode = 0; | |
2229 | fs->write_inode = 0; | |
2230 | } | |
2231 | } |