]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table | |
efc6f628 | 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% | |
efc6f628 | 10 | * |
3839e657 TT |
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 | ||
6dc64392 VAH |
58 | static int process_block(ext2_filsys fs, blk64_t *blocknr, |
59 | e2_blkcnt_t blockcnt, blk64_t ref_blk, | |
54dc7ca2 | 60 | int ref_offset, void *priv_data); |
6dc64392 VAH |
61 | static int process_bad_block(ext2_filsys fs, blk64_t *block_nr, |
62 | e2_blkcnt_t blockcnt, blk64_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); |
efc6f628 | 75 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
e8a3ee62 | 76 | char *block_buf, int adjust_sign); |
6dc64392 | 77 | /* static char *describe_illegal_block(ext2_filsys fs, blk64_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; |
65d71894 | 83 | blk64_t num_blocks; |
6dc64392 | 84 | blk64_t max_blocks; |
9d1bd3de | 85 | e2_blkcnt_t last_block; |
4dbe79bc | 86 | e2_blkcnt_t last_db_block; |
246501c6 | 87 | int num_illegal_blocks; |
6dc64392 | 88 | blk64_t previous_block; |
f3db3566 | 89 | struct ext2_inode *inode; |
21c84b71 | 90 | struct problem_context *pctx; |
000ba404 | 91 | ext2fs_block_bitmap fs_meta_blocks; |
1b6bf175 | 92 | e2fsck_t ctx; |
3839e657 TT |
93 | }; |
94 | ||
95 | struct process_inode_block { | |
86c627ec | 96 | ext2_ino_t ino; |
3839e657 TT |
97 | struct ext2_inode inode; |
98 | }; | |
99 | ||
f8188fff TT |
100 | struct scan_callback_struct { |
101 | e2fsck_t ctx; | |
102 | char *block_buf; | |
103 | }; | |
104 | ||
3839e657 TT |
105 | /* |
106 | * For the inodes to process list. | |
107 | */ | |
108 | static struct process_inode_block *inodes_to_process; | |
109 | static int process_inode_count; | |
3839e657 | 110 | |
7823dd65 TT |
111 | static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE - |
112 | EXT2_MIN_BLOCK_LOG_SIZE + 1]; | |
246501c6 | 113 | |
f3db3566 TT |
114 | /* |
115 | * Free all memory allocated by pass1 in preparation for restarting | |
116 | * things. | |
117 | */ | |
54434927 | 118 | static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused))) |
f3db3566 | 119 | { |
c4e3d3f3 | 120 | ext2fs_free_mem(&inodes_to_process); |
08b21301 | 121 | inodes_to_process = 0; |
f3db3566 TT |
122 | } |
123 | ||
7cf73dcd TT |
124 | /* |
125 | * Check to make sure a device inode is real. Returns 1 if the device | |
126 | * checks out, 0 if not. | |
1dde43f0 TT |
127 | * |
128 | * Note: this routine is now also used to check FIFO's and Sockets, | |
129 | * since they have the same requirement; the i_block fields should be | |
efc6f628 | 130 | * zero. |
7cf73dcd | 131 | */ |
efc6f628 | 132 | int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
f954ba01 | 133 | struct ext2_inode *inode) |
7cf73dcd TT |
134 | { |
135 | int i; | |
136 | ||
a40ecbb1 | 137 | /* |
441ab1e0 TT |
138 | * If the index flag is set, then this is a bogus |
139 | * device/fifo/socket | |
a40ecbb1 | 140 | */ |
441ab1e0 | 141 | if (inode->i_flags & EXT2_INDEX_FL) |
53abed0a | 142 | return 0; |
bcf9c5d4 | 143 | |
7fdfabd3 TT |
144 | /* |
145 | * We should be able to do the test below all the time, but | |
146 | * because the kernel doesn't forcibly clear the device | |
147 | * inode's additional i_block fields, there are some rare | |
148 | * occasions when a legitimate device inode will have non-zero | |
149 | * additional i_block fields. So for now, we only complain | |
150 | * when the immutable flag is set, which should never happen | |
151 | * for devices. (And that's when the problem is caused, since | |
152 | * you can't set or clear immutable flags for devices.) Once | |
153 | * the kernel has been fixed we can change this... | |
154 | */ | |
01fbc701 | 155 | if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) { |
efc6f628 | 156 | for (i=4; i < EXT2_N_BLOCKS; i++) |
7fdfabd3 TT |
157 | if (inode->i_block[i]) |
158 | return 0; | |
159 | } | |
7cf73dcd TT |
160 | return 1; |
161 | } | |
162 | ||
67052a8a AD |
163 | /* |
164 | * Check to make sure a symlink inode is real. Returns 1 if the symlink | |
165 | * checks out, 0 if not. | |
166 | */ | |
7cadc577 TT |
167 | int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, |
168 | struct ext2_inode *inode, char *buf) | |
67052a8a | 169 | { |
54434927 | 170 | unsigned int len; |
d007cb4c | 171 | int i; |
6dc64392 | 172 | blk64_t blocks; |
7cadc577 TT |
173 | ext2_extent_handle_t handle; |
174 | struct ext2_extent_info info; | |
175 | struct ext2fs_extent extent; | |
67052a8a | 176 | |
bcf9c5d4 TT |
177 | if ((inode->i_size_high || inode->i_size == 0) || |
178 | (inode->i_flags & EXT2_INDEX_FL)) | |
67052a8a AD |
179 | return 0; |
180 | ||
7cadc577 TT |
181 | if (inode->i_flags & EXT4_EXTENTS_FL) { |
182 | if (inode->i_size > fs->blocksize) | |
183 | return 0; | |
84b239ae | 184 | if (ext2fs_extent_open2(fs, ino, inode, &handle)) |
7cadc577 TT |
185 | return 0; |
186 | i = 0; | |
187 | if (ext2fs_extent_get_info(handle, &info) || | |
188 | (info.num_entries != 1) || | |
189 | (info.max_depth != 0)) | |
190 | goto exit_extent; | |
191 | if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent) || | |
192 | (extent.e_lblk != 0) || | |
193 | (extent.e_len != 1) || | |
194 | (extent.e_pblk < fs->super->s_first_data_block) || | |
4efbac6f | 195 | (extent.e_pblk >= ext2fs_blocks_count(fs->super))) |
7cadc577 TT |
196 | goto exit_extent; |
197 | i = 1; | |
198 | exit_extent: | |
199 | ext2fs_extent_free(handle); | |
200 | return i; | |
201 | } | |
202 | ||
6dc64392 | 203 | blocks = ext2fs_inode_data_blocks2(fs, inode); |
0684a4f3 | 204 | if (blocks) { |
b94a052a | 205 | if ((inode->i_size >= fs->blocksize) || |
0684a4f3 | 206 | (blocks != fs->blocksize >> 9) || |
d007cb4c | 207 | (inode->i_block[0] < fs->super->s_first_data_block) || |
4efbac6f | 208 | (inode->i_block[0] >= ext2fs_blocks_count(fs->super))) |
67052a8a AD |
209 | return 0; |
210 | ||
211 | for (i = 1; i < EXT2_N_BLOCKS; i++) | |
212 | if (inode->i_block[i]) | |
213 | return 0; | |
b94a052a | 214 | |
24a117ab | 215 | if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf)) |
b94a052a AD |
216 | return 0; |
217 | ||
218 | len = strnlen(buf, fs->blocksize); | |
219 | if (len == fs->blocksize) | |
220 | return 0; | |
67052a8a | 221 | } else { |
b94a052a | 222 | if (inode->i_size >= sizeof(inode->i_block)) |
67052a8a AD |
223 | return 0; |
224 | ||
b94a052a AD |
225 | len = strnlen((char *)inode->i_block, sizeof(inode->i_block)); |
226 | if (len == sizeof(inode->i_block)) | |
67052a8a AD |
227 | return 0; |
228 | } | |
b94a052a AD |
229 | if (len != inode->i_size) |
230 | return 0; | |
67052a8a AD |
231 | return 1; |
232 | } | |
233 | ||
6fdc7a32 | 234 | /* |
01fbc701 TT |
235 | * If the immutable (or append-only) flag is set on the inode, offer |
236 | * to clear it. | |
6fdc7a32 | 237 | */ |
bcf9c5d4 | 238 | #define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL) |
6fdc7a32 TT |
239 | static void check_immutable(e2fsck_t ctx, struct problem_context *pctx) |
240 | { | |
b94a052a | 241 | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) |
6fdc7a32 TT |
242 | return; |
243 | ||
244 | if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx)) | |
245 | return; | |
246 | ||
b94a052a | 247 | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; |
6fdc7a32 TT |
248 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
249 | } | |
250 | ||
d647a1ea TT |
251 | /* |
252 | * If device, fifo or socket, check size is zero -- if not offer to | |
253 | * clear it | |
254 | */ | |
255 | static void check_size(e2fsck_t ctx, struct problem_context *pctx) | |
256 | { | |
257 | struct ext2_inode *inode = pctx->inode; | |
efc6f628 | 258 | |
85645a6f | 259 | if ((inode->i_size == 0) && (inode->i_size_high == 0)) |
d647a1ea | 260 | return; |
efc6f628 | 261 | |
85645a6f | 262 | if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) |
d647a1ea | 263 | return; |
efc6f628 | 264 | |
d647a1ea | 265 | inode->i_size = 0; |
fdbdea09 | 266 | inode->i_size_high = 0; |
d647a1ea TT |
267 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
268 | } | |
efc6f628 | 269 | |
cebe48a1 TT |
270 | static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx) |
271 | { | |
272 | struct ext2_super_block *sb = ctx->fs->super; | |
273 | struct ext2_inode_large *inode; | |
274 | struct ext2_ext_attr_entry *entry; | |
642935c0 | 275 | char *start, *end; |
1a8c2c4a | 276 | unsigned int storage_size, remain; |
cebe48a1 TT |
277 | int problem = 0; |
278 | ||
279 | inode = (struct ext2_inode_large *) pctx->inode; | |
280 | storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE - | |
281 | inode->i_extra_isize; | |
282 | start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + | |
283 | inode->i_extra_isize + sizeof(__u32); | |
284 | end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super); | |
285 | entry = (struct ext2_ext_attr_entry *) start; | |
286 | ||
287 | /* scan all entry's headers first */ | |
288 | ||
289 | /* take finish entry 0UL into account */ | |
efc6f628 | 290 | remain = storage_size - sizeof(__u32); |
cebe48a1 TT |
291 | |
292 | while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { | |
fefaef39 | 293 | __u32 hash; |
cebe48a1 TT |
294 | |
295 | /* header eats this space */ | |
296 | remain -= sizeof(struct ext2_ext_attr_entry); | |
efc6f628 | 297 | |
cebe48a1 TT |
298 | /* is attribute name valid? */ |
299 | if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) { | |
300 | pctx->num = entry->e_name_len; | |
301 | problem = PR_1_ATTR_NAME_LEN; | |
302 | goto fix; | |
303 | } | |
304 | ||
305 | /* attribute len eats this space */ | |
306 | remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); | |
307 | ||
308 | /* check value size */ | |
309 | if (entry->e_value_size == 0 || entry->e_value_size > remain) { | |
310 | pctx->num = entry->e_value_size; | |
311 | problem = PR_1_ATTR_VALUE_SIZE; | |
312 | goto fix; | |
313 | } | |
314 | ||
cebe48a1 TT |
315 | /* e_value_block must be 0 in inode's ea */ |
316 | if (entry->e_value_block != 0) { | |
317 | pctx->num = entry->e_value_block; | |
318 | problem = PR_1_ATTR_VALUE_BLOCK; | |
319 | goto fix; | |
320 | } | |
fefaef39 AD |
321 | |
322 | hash = ext2fs_ext_attr_hash_entry(entry, | |
323 | start + entry->e_value_offs); | |
324 | ||
325 | /* e_hash may be 0 in older inode's ea */ | |
326 | if (entry->e_hash != 0 && entry->e_hash != hash) { | |
cebe48a1 TT |
327 | pctx->num = entry->e_hash; |
328 | problem = PR_1_ATTR_HASH; | |
329 | goto fix; | |
330 | } | |
331 | ||
332 | remain -= entry->e_value_size; | |
cebe48a1 TT |
333 | |
334 | entry = EXT2_EXT_ATTR_NEXT(entry); | |
335 | } | |
336 | fix: | |
337 | /* | |
338 | * it seems like a corruption. it's very unlikely we could repair | |
339 | * EA(s) in automatic fashion -bzzz | |
340 | */ | |
cebe48a1 TT |
341 | if (problem == 0 || !fix_problem(ctx, problem, pctx)) |
342 | return; | |
343 | ||
fefaef39 | 344 | /* simply remove all possible EA(s) */ |
cebe48a1 | 345 | *((__u32 *)start) = 0UL; |
da938f20 | 346 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, |
cebe48a1 TT |
347 | EXT2_INODE_SIZE(sb), "pass1"); |
348 | } | |
349 | ||
350 | static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) | |
351 | { | |
352 | struct ext2_super_block *sb = ctx->fs->super; | |
353 | struct ext2_inode_large *inode; | |
354 | __u32 *eamagic; | |
355 | int min, max; | |
356 | ||
357 | inode = (struct ext2_inode_large *) pctx->inode; | |
358 | if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) { | |
359 | /* this isn't large inode. so, nothing to check */ | |
360 | return; | |
361 | } | |
362 | ||
363 | #if 0 | |
364 | printf("inode #%u, i_extra_size %d\n", pctx->ino, | |
365 | inode->i_extra_isize); | |
efc6f628 | 366 | #endif |
cebe48a1 TT |
367 | /* i_extra_isize must cover i_extra_isize + i_pad1 at least */ |
368 | min = sizeof(inode->i_extra_isize) + sizeof(inode->i_pad1); | |
369 | max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; | |
efc6f628 | 370 | /* |
cebe48a1 TT |
371 | * For now we will allow i_extra_isize to be 0, but really |
372 | * implementations should never allow i_extra_isize to be 0 | |
373 | */ | |
374 | if (inode->i_extra_isize && | |
375 | (inode->i_extra_isize < min || inode->i_extra_isize > max)) { | |
376 | if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx)) | |
377 | return; | |
378 | inode->i_extra_isize = min; | |
379 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, | |
380 | EXT2_INODE_SIZE(sb), "pass1"); | |
381 | return; | |
382 | } | |
383 | ||
384 | eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + | |
385 | inode->i_extra_isize); | |
386 | if (*eamagic == EXT2_EXT_ATTR_MAGIC) { | |
387 | /* it seems inode has an extended attribute(s) in body */ | |
388 | check_ea_in_inode(ctx, pctx); | |
389 | } | |
390 | } | |
6fdc7a32 | 391 | |
efc6f628 | 392 | /* |
fbc3f901 TT |
393 | * Check to see if the inode might really be a directory, despite i_mode |
394 | * | |
395 | * This is a lot of complexity for something for which I'm not really | |
396 | * convinced happens frequently in the wild. If for any reason this | |
397 | * causes any problems, take this code out. | |
398 | * [tytso:20070331.0827EDT] | |
399 | */ | |
400 | static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, | |
401 | char *buf) | |
402 | { | |
403 | struct ext2_inode *inode = pctx->inode; | |
fbc3f901 | 404 | struct ext2_dir_entry *dirent; |
e94bc631 TT |
405 | const char *old_op; |
406 | errcode_t retval; | |
cf5301d7 | 407 | blk64_t blk; |
03fa6f8a | 408 | unsigned int i, rec_len, not_device = 0; |
1ec42a00 | 409 | int extent_fs; |
fbc3f901 | 410 | |
1ec42a00 ND |
411 | /* |
412 | * If the mode looks OK, we believe it. If the first block in | |
413 | * the i_block array is 0, this cannot be a directory. If the | |
414 | * inode is extent-mapped, it is still the case that the latter | |
415 | * cannot be 0 - the magic number in the extent header would make | |
416 | * it nonzero. | |
417 | */ | |
fbc3f901 | 418 | if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || |
0eeb1549 | 419 | LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) |
fbc3f901 TT |
420 | return; |
421 | ||
1ec42a00 ND |
422 | /* |
423 | * Check the block numbers in the i_block array for validity: | |
424 | * zero blocks are skipped (but the first one cannot be zero - | |
425 | * see above), other blocks are checked against the first and | |
426 | * max data blocks (from the the superblock) and against the | |
427 | * block bitmap. Any invalid block found means this cannot be | |
428 | * a directory. | |
429 | * | |
430 | * If there are non-zero blocks past the fourth entry, then | |
431 | * this cannot be a device file: we remember that for the next | |
432 | * check. | |
433 | * | |
434 | * For extent mapped files, we don't do any sanity checking: | |
435 | * just try to get the phys block of logical block 0 and run | |
436 | * with it. | |
437 | */ | |
438 | ||
cf5301d7 AD |
439 | extent_fs = (ctx->fs->super->s_feature_incompat & |
440 | EXT3_FEATURE_INCOMPAT_EXTENTS); | |
1ec42a00 ND |
441 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { |
442 | /* extent mapped */ | |
6dc64392 | 443 | if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0, |
1ec42a00 ND |
444 | &blk)) |
445 | return; | |
446 | /* device files are never extent mapped */ | |
447 | not_device++; | |
448 | } else { | |
449 | for (i=0; i < EXT2_N_BLOCKS; i++) { | |
450 | blk = inode->i_block[i]; | |
451 | if (!blk) | |
452 | continue; | |
453 | if (i >= 4) | |
454 | not_device++; | |
455 | ||
456 | if (blk < ctx->fs->super->s_first_data_block || | |
cc84d866 TT |
457 | blk >= ext2fs_blocks_count(ctx->fs->super) || |
458 | ext2fs_fast_test_block_bitmap2(ctx->block_found_map, | |
459 | blk)) | |
1ec42a00 ND |
460 | return; /* Invalid block, can't be dir */ |
461 | } | |
462 | blk = inode->i_block[0]; | |
fbc3f901 TT |
463 | } |
464 | ||
1ec42a00 ND |
465 | /* |
466 | * If the mode says this is a device file and the i_links_count field | |
467 | * is sane and we have not ruled it out as a device file previously, | |
468 | * we declare it a device file, not a directory. | |
469 | */ | |
efc6f628 | 470 | if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) && |
fbc3f901 TT |
471 | (inode->i_links_count == 1) && !not_device) |
472 | return; | |
473 | ||
1ec42a00 | 474 | /* read the first block */ |
e94bc631 | 475 | old_op = ehandler_operation(_("reading directory block")); |
6dc64392 | 476 | retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0); |
e94bc631 TT |
477 | ehandler_operation(0); |
478 | if (retval) | |
fbc3f901 TT |
479 | return; |
480 | ||
481 | dirent = (struct ext2_dir_entry *) buf; | |
8a480350 TT |
482 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
483 | if (retval) | |
484 | return; | |
fbc3f901 TT |
485 | if (((dirent->name_len & 0xFF) != 1) || |
486 | (dirent->name[0] != '.') || | |
487 | (dirent->inode != pctx->ino) || | |
5dd77dbe TT |
488 | (rec_len < 12) || |
489 | (rec_len % 4) || | |
490 | (rec_len >= ctx->fs->blocksize - 12)) | |
fbc3f901 TT |
491 | return; |
492 | ||
5dd77dbe | 493 | dirent = (struct ext2_dir_entry *) (buf + rec_len); |
8a480350 TT |
494 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
495 | if (retval) | |
496 | return; | |
fbc3f901 TT |
497 | if (((dirent->name_len & 0xFF) != 2) || |
498 | (dirent->name[0] != '.') || | |
499 | (dirent->name[1] != '.') || | |
5dd77dbe TT |
500 | (rec_len < 12) || |
501 | (rec_len % 4)) | |
fbc3f901 TT |
502 | return; |
503 | ||
504 | if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) { | |
505 | inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR; | |
efc6f628 TT |
506 | e2fsck_write_inode_full(ctx, pctx->ino, inode, |
507 | EXT2_INODE_SIZE(ctx->fs->super), | |
fbc3f901 TT |
508 | "check_is_really_dir"); |
509 | } | |
510 | } | |
511 | ||
efc6f628 | 512 | extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags, |
34b9f796 TT |
513 | ext2_icount_t *ret) |
514 | { | |
f954ba01 | 515 | unsigned int threshold; |
34b9f796 TT |
516 | ext2_ino_t num_dirs; |
517 | errcode_t retval; | |
f954ba01 TT |
518 | char *tdb_dir; |
519 | int enable; | |
34b9f796 TT |
520 | |
521 | *ret = 0; | |
522 | ||
523 | profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0, | |
524 | &tdb_dir); | |
f954ba01 TT |
525 | profile_get_uint(ctx->profile, "scratch_files", |
526 | "numdirs_threshold", 0, 0, &threshold); | |
34b9f796 TT |
527 | profile_get_boolean(ctx->profile, "scratch_files", |
528 | "icount", 0, 1, &enable); | |
529 | ||
530 | retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs); | |
531 | if (retval) | |
532 | num_dirs = 1024; /* Guess */ | |
533 | ||
534 | if (!enable || !tdb_dir || access(tdb_dir, W_OK) || | |
535 | (threshold && num_dirs <= threshold)) | |
536 | return; | |
537 | ||
538 | retval = ext2fs_create_icount_tdb(ctx->fs, tdb_dir, flags, ret); | |
539 | if (retval) | |
540 | *ret = 0; | |
541 | } | |
542 | ||
08b21301 | 543 | void e2fsck_pass1(e2fsck_t ctx) |
3839e657 | 544 | { |
9d1bd3de | 545 | int i; |
31e29a12 | 546 | __u64 max_sizes; |
1b6bf175 | 547 | ext2_filsys fs = ctx->fs; |
86c627ec | 548 | ext2_ino_t ino; |
cebe48a1 | 549 | struct ext2_inode *inode; |
3839e657 TT |
550 | ext2_inode_scan scan; |
551 | char *block_buf; | |
8bf191e8 | 552 | #ifdef RESOURCE_TRACK |
3839e657 | 553 | struct resource_track rtrack; |
8bf191e8 | 554 | #endif |
1e3472c5 | 555 | unsigned char frag, fsize; |
21c84b71 | 556 | struct problem_context pctx; |
f8188fff | 557 | struct scan_callback_struct scan_struct; |
5dd8f963 | 558 | struct ext2_super_block *sb = ctx->fs->super; |
e94bc631 | 559 | const char *old_op; |
15d482ba | 560 | int imagic_fs, extent_fs; |
be93ef0c | 561 | int busted_fs_time = 0; |
cebe48a1 | 562 | int inode_size; |
efc6f628 | 563 | |
6d96b00d | 564 | init_resource_track(&rtrack, ctx->fs->io); |
1b6bf175 TT |
565 | clear_problem_context(&pctx); |
566 | ||
567 | if (!(ctx->options & E2F_OPT_PREEN)) | |
568 | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); | |
3839e657 | 569 | |
3214a453 TT |
570 | if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && |
571 | !(ctx->options & E2F_OPT_NO)) { | |
b7a00563 TT |
572 | if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) |
573 | ctx->dirs_to_hash = 0; | |
574 | } | |
575 | ||
3839e657 TT |
576 | #ifdef MTRACE |
577 | mtrace_print("Pass 1"); | |
578 | #endif | |
579 | ||
932a489c AD |
580 | #define EXT2_BPP(bits) (1ULL << ((bits) - 2)) |
581 | ||
582 | for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) { | |
583 | max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i); | |
584 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i); | |
585 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i); | |
586 | max_sizes = (max_sizes * (1UL << i)) - 1; | |
7823dd65 | 587 | ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes; |
9d1bd3de TT |
588 | } |
589 | #undef EXT2_BPP | |
6fdc7a32 | 590 | |
6fdc7a32 | 591 | imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES); |
15d482ba | 592 | extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS); |
6fdc7a32 | 593 | |
3839e657 TT |
594 | /* |
595 | * Allocate bitmaps structures | |
596 | */ | |
0c4a0726 | 597 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, _("in-use inode map"), |
1b6bf175 TT |
598 | &ctx->inode_used_map); |
599 | if (pctx.errcode) { | |
600 | pctx.num = 1; | |
601 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
602 | ctx->flags |= E2F_FLAG_ABORT; |
603 | return; | |
3839e657 | 604 | } |
0c4a0726 TT |
605 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
606 | _("directory inode map"), &ctx->inode_dir_map); | |
1b6bf175 TT |
607 | if (pctx.errcode) { |
608 | pctx.num = 2; | |
609 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
610 | ctx->flags |= E2F_FLAG_ABORT; |
611 | return; | |
3839e657 | 612 | } |
aa4115a4 | 613 | pctx.errcode = ext2fs_allocate_inode_bitmap(fs, |
0c4a0726 | 614 | _("regular file inode map"), &ctx->inode_reg_map); |
aa4115a4 TT |
615 | if (pctx.errcode) { |
616 | pctx.num = 6; | |
617 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
618 | ctx->flags |= E2F_FLAG_ABORT; | |
619 | return; | |
620 | } | |
44fe08f1 TT |
621 | pctx.errcode = ext2fs_allocate_subcluster_bitmap(fs, |
622 | _("in-use block map"), | |
623 | &ctx->block_found_map); | |
1b6bf175 TT |
624 | if (pctx.errcode) { |
625 | pctx.num = 1; | |
626 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
08b21301 TT |
627 | ctx->flags |= E2F_FLAG_ABORT; |
628 | return; | |
3839e657 | 629 | } |
34b9f796 TT |
630 | e2fsck_setup_tdb_icount(ctx, 0, &ctx->inode_link_info); |
631 | if (!ctx->inode_link_info) | |
632 | pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, | |
633 | &ctx->inode_link_info); | |
1b6bf175 TT |
634 | if (pctx.errcode) { |
635 | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); | |
08b21301 TT |
636 | ctx->flags |= E2F_FLAG_ABORT; |
637 | return; | |
21c84b71 | 638 | } |
cebe48a1 TT |
639 | inode_size = EXT2_INODE_SIZE(fs->super); |
640 | inode = (struct ext2_inode *) | |
641 | e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); | |
642 | ||
54dc7ca2 TT |
643 | inodes_to_process = (struct process_inode_block *) |
644 | e2fsck_allocate_memory(ctx, | |
645 | (ctx->process_inode_size * | |
646 | sizeof(struct process_inode_block)), | |
647 | "array of inodes to process"); | |
3839e657 TT |
648 | process_inode_count = 0; |
649 | ||
1b6bf175 TT |
650 | pctx.errcode = ext2fs_init_dblist(fs, 0); |
651 | if (pctx.errcode) { | |
652 | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); | |
08b21301 | 653 | ctx->flags |= E2F_FLAG_ABORT; |
9d45b6ef | 654 | ext2fs_free_mem(&inode); |
08b21301 | 655 | return; |
21c84b71 | 656 | } |
3839e657 | 657 | |
9cbfb8d0 TT |
658 | /* |
659 | * If the last orphan field is set, clear it, since the pass1 | |
660 | * processing will automatically find and clear the orphans. | |
661 | * In the future, we may want to try using the last_orphan | |
662 | * linked list ourselves, but for now, we clear it so that the | |
663 | * ext3 mount code won't get confused. | |
664 | */ | |
665 | if (!(ctx->options & E2F_OPT_READONLY)) { | |
666 | if (fs->super->s_last_orphan) { | |
667 | fs->super->s_last_orphan = 0; | |
668 | ext2fs_mark_super_dirty(fs); | |
669 | } | |
670 | } | |
671 | ||
1b6bf175 | 672 | mark_table_blocks(ctx); |
44fe08f1 TT |
673 | pctx.errcode = ext2fs_convert_subcluster_bitmap(fs, |
674 | &ctx->block_found_map); | |
675 | if (pctx.errcode) { | |
676 | fix_problem(ctx, PR_1_CONVERT_SUBCLUSTER, &pctx); | |
677 | ctx->flags |= E2F_FLAG_ABORT; | |
678 | ext2fs_free_mem(&inode); | |
679 | return; | |
680 | } | |
54dc7ca2 TT |
681 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
682 | "block interate buffer"); | |
e72a9ba3 | 683 | e2fsck_use_inode_shortcuts(ctx, 1); |
e94bc631 | 684 | old_op = ehandler_operation(_("opening inode scan")); |
efc6f628 | 685 | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
1b6bf175 | 686 | &scan); |
e94bc631 | 687 | ehandler_operation(old_op); |
1b6bf175 TT |
688 | if (pctx.errcode) { |
689 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 | 690 | ctx->flags |= E2F_FLAG_ABORT; |
9d45b6ef BB |
691 | ext2fs_free_mem(&block_buf); |
692 | ext2fs_free_mem(&inode); | |
08b21301 | 693 | return; |
3839e657 | 694 | } |
21c84b71 | 695 | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); |
cebe48a1 | 696 | ctx->stashed_inode = inode; |
f8188fff TT |
697 | scan_struct.ctx = ctx; |
698 | scan_struct.block_buf = block_buf; | |
699 | ext2fs_set_inode_callback(scan, scan_callback, &scan_struct); | |
700 | if (ctx->progress) | |
a02ce9df TT |
701 | if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count)) |
702 | return; | |
4147d9f0 TT |
703 | if ((fs->super->s_wtime < fs->super->s_inodes_count) || |
704 | (fs->super->s_mtime < fs->super->s_inodes_count)) | |
be93ef0c TT |
705 | busted_fs_time = 1; |
706 | ||
d237a78e | 707 | while (1) { |
e94bc631 | 708 | old_op = ehandler_operation(_("getting next inode from scan")); |
efc6f628 | 709 | pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, |
cebe48a1 | 710 | inode, inode_size); |
e94bc631 | 711 | ehandler_operation(old_op); |
d237a78e TT |
712 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
713 | return; | |
714 | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { | |
715 | if (!ctx->inode_bb_map) | |
716 | alloc_bb_map(ctx); | |
c5d2f50d VAH |
717 | ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); |
718 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); | |
d237a78e TT |
719 | continue; |
720 | } | |
721 | if (pctx.errcode) { | |
722 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
723 | ctx->flags |= E2F_FLAG_ABORT; | |
724 | return; | |
725 | } | |
726 | if (!ino) | |
727 | break; | |
21c84b71 | 728 | pctx.ino = ino; |
cebe48a1 | 729 | pctx.inode = inode; |
1b6bf175 | 730 | ctx->stashed_ino = ino; |
cebe48a1 | 731 | if (inode->i_links_count) { |
efc6f628 | 732 | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, |
cebe48a1 | 733 | ino, inode->i_links_count); |
1b6bf175 | 734 | if (pctx.errcode) { |
cebe48a1 | 735 | pctx.num = inode->i_links_count; |
1b6bf175 | 736 | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); |
08b21301 TT |
737 | ctx->flags |= E2F_FLAG_ABORT; |
738 | return; | |
1b6bf175 TT |
739 | } |
740 | } | |
dfc870c7 ES |
741 | |
742 | /* | |
743 | * Test for incorrect extent flag settings. | |
744 | * | |
745 | * On big-endian machines we must be careful: | |
746 | * When the inode is read, the i_block array is not swapped | |
747 | * if the extent flag is set. Therefore if we are testing | |
748 | * for or fixing a wrongly-set flag, we must potentially | |
749 | * (un)swap before testing, or after fixing. | |
750 | */ | |
751 | ||
752 | /* | |
753 | * In this case the extents flag was set when read, so | |
754 | * extent_header_verify is ok. If the inode is cleared, | |
755 | * no need to swap... so no extra swapping here. | |
756 | */ | |
efc6f628 | 757 | if ((inode->i_flags & EXT4_EXTENTS_FL) && !extent_fs && |
15d482ba TT |
758 | (inode->i_links_count || (ino == EXT2_BAD_INO) || |
759 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO))) { | |
efc6f628 | 760 | if ((ext2fs_extent_header_verify(inode->i_block, |
15d482ba TT |
761 | sizeof(inode->i_block)) == 0) && |
762 | fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) { | |
763 | sb->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_EXTENTS; | |
764 | ext2fs_mark_super_dirty(fs); | |
765 | extent_fs = 1; | |
766 | } else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) { | |
767 | clear_inode: | |
768 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); | |
769 | if (ino == EXT2_BAD_INO) | |
c5d2f50d | 770 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, |
15d482ba TT |
771 | ino); |
772 | continue; | |
773 | } | |
774 | } | |
775 | ||
dfc870c7 ES |
776 | /* |
777 | * For big-endian machines: | |
778 | * If the inode didn't have the extents flag set when it | |
779 | * was read, then the i_blocks array was swapped. To test | |
780 | * as an extents header, we must swap it back first. | |
781 | * IF we then set the extents flag, the entire i_block | |
782 | * array must be un/re-swapped to make it proper extents data. | |
783 | */ | |
15d482ba TT |
784 | if (extent_fs && !(inode->i_flags & EXT4_EXTENTS_FL) && |
785 | (inode->i_links_count || (ino == EXT2_BAD_INO) || | |
786 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO)) && | |
787 | (LINUX_S_ISREG(inode->i_mode) || | |
dfc870c7 ES |
788 | LINUX_S_ISDIR(inode->i_mode))) { |
789 | void *ehp; | |
790 | #ifdef WORDS_BIGENDIAN | |
791 | __u32 tmp_block[EXT2_N_BLOCKS]; | |
792 | ||
793 | for (i = 0; i < EXT2_N_BLOCKS; i++) | |
794 | tmp_block[i] = ext2fs_swab32(inode->i_block[i]); | |
795 | ehp = tmp_block; | |
796 | #else | |
797 | ehp = inode->i_block; | |
798 | #endif | |
efc6f628 | 799 | if ((ext2fs_extent_header_verify(ehp, |
dfc870c7 ES |
800 | sizeof(inode->i_block)) == 0) && |
801 | (fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx))) { | |
15d482ba | 802 | inode->i_flags |= EXT4_EXTENTS_FL; |
dfc870c7 | 803 | #ifdef WORDS_BIGENDIAN |
efc6f628 | 804 | memcpy(inode->i_block, tmp_block, |
dfc870c7 ES |
805 | sizeof(inode->i_block)); |
806 | #endif | |
15d482ba TT |
807 | e2fsck_write_inode(ctx, ino, inode, "pass1"); |
808 | } | |
809 | } | |
810 | ||
3839e657 TT |
811 | if (ino == EXT2_BAD_INO) { |
812 | struct process_block_struct pb; | |
efc6f628 | 813 | |
000ba404 TT |
814 | pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map, |
815 | &pb.fs_meta_blocks); | |
816 | if (pctx.errcode) { | |
817 | pctx.num = 4; | |
818 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
819 | ctx->flags |= E2F_FLAG_ABORT; | |
820 | return; | |
821 | } | |
3839e657 TT |
822 | pb.ino = EXT2_BAD_INO; |
823 | pb.num_blocks = pb.last_block = 0; | |
4dbe79bc | 824 | pb.last_db_block = -1; |
f3db3566 | 825 | pb.num_illegal_blocks = 0; |
21c84b71 | 826 | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
000ba404 | 827 | pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0; |
cebe48a1 | 828 | pb.inode = inode; |
21c84b71 | 829 | pb.pctx = &pctx; |
1b6bf175 | 830 | pb.ctx = ctx; |
6dc64392 | 831 | pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, |
1b6bf175 | 832 | block_buf, process_bad_block, &pb); |
000ba404 | 833 | ext2fs_free_block_bitmap(pb.fs_meta_blocks); |
1b6bf175 TT |
834 | if (pctx.errcode) { |
835 | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); | |
08b21301 TT |
836 | ctx->flags |= E2F_FLAG_ABORT; |
837 | return; | |
1b6bf175 | 838 | } |
000ba404 TT |
839 | if (pb.bbcheck) |
840 | if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) { | |
841 | ctx->flags |= E2F_FLAG_ABORT; | |
842 | return; | |
843 | } | |
c5d2f50d | 844 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
21c84b71 | 845 | clear_problem_context(&pctx); |
d237a78e | 846 | continue; |
a9ca2016 | 847 | } else if (ino == EXT2_ROOT_INO) { |
3839e657 TT |
848 | /* |
849 | * Make sure the root inode is a directory; if | |
850 | * not, offer to clear it. It will be | |
851 | * regnerated in pass #3. | |
852 | */ | |
cebe48a1 | 853 | if (!LINUX_S_ISDIR(inode->i_mode)) { |
15d482ba TT |
854 | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) |
855 | goto clear_inode; | |
3839e657 TT |
856 | } |
857 | /* | |
858 | * If dtime is set, offer to clear it. mke2fs | |
859 | * version 0.2b created filesystems with the | |
860 | * dtime field set for the root and lost+found | |
861 | * directories. We won't worry about | |
862 | * /lost+found, since that can be regenerated | |
863 | * easily. But we will fix the root directory | |
864 | * as a special case. | |
865 | */ | |
cebe48a1 | 866 | if (inode->i_dtime && inode->i_links_count) { |
1b6bf175 | 867 | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
cebe48a1 TT |
868 | inode->i_dtime = 0; |
869 | e2fsck_write_inode(ctx, ino, inode, | |
f3db3566 | 870 | "pass1"); |
21c84b71 | 871 | } |
3839e657 | 872 | } |
a9ca2016 | 873 | } else if (ino == EXT2_JOURNAL_INO) { |
c5d2f50d | 874 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
f18996c8 | 875 | if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) { |
cebe48a1 | 876 | if (!LINUX_S_ISREG(inode->i_mode) && |
a9ca2016 TT |
877 | fix_problem(ctx, PR_1_JOURNAL_BAD_MODE, |
878 | &pctx)) { | |
cebe48a1 TT |
879 | inode->i_mode = LINUX_S_IFREG; |
880 | e2fsck_write_inode(ctx, ino, inode, | |
a9ca2016 TT |
881 | "pass1"); |
882 | } | |
f18996c8 | 883 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 884 | continue; |
f18996c8 | 885 | } |
6dc64392 | 886 | if ((inode->i_links_count || |
cebe48a1 | 887 | inode->i_blocks || inode->i_block[0]) && |
efc6f628 | 888 | fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, |
f18996c8 | 889 | &pctx)) { |
cebe48a1 | 890 | memset(inode, 0, inode_size); |
a9ca2016 TT |
891 | ext2fs_icount_store(ctx->inode_link_info, |
892 | ino, 0); | |
efc6f628 | 893 | e2fsck_write_inode_full(ctx, ino, inode, |
cebe48a1 | 894 | inode_size, "pass1"); |
f18996c8 | 895 | } |
a9ca2016 | 896 | } else if (ino < EXT2_FIRST_INODE(fs->super)) { |
b09a4b0c | 897 | int problem = 0; |
efc6f628 | 898 | |
c5d2f50d | 899 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
53ef44c4 | 900 | if (ino == EXT2_BOOT_LOADER_INO) { |
cebe48a1 | 901 | if (LINUX_S_ISDIR(inode->i_mode)) |
b09a4b0c | 902 | problem = PR_1_RESERVED_BAD_MODE; |
b1f204f7 | 903 | } else if (ino == EXT2_RESIZE_INO) { |
cebe48a1 TT |
904 | if (inode->i_mode && |
905 | !LINUX_S_ISREG(inode->i_mode)) | |
b1f204f7 | 906 | problem = PR_1_RESERVED_BAD_MODE; |
53ef44c4 | 907 | } else { |
cebe48a1 | 908 | if (inode->i_mode != 0) |
b09a4b0c | 909 | problem = PR_1_RESERVED_BAD_MODE; |
b09a4b0c TT |
910 | } |
911 | if (problem) { | |
912 | if (fix_problem(ctx, problem, &pctx)) { | |
cebe48a1 TT |
913 | inode->i_mode = 0; |
914 | e2fsck_write_inode(ctx, ino, inode, | |
50e1e10f | 915 | "pass1"); |
21c84b71 | 916 | } |
50e1e10f | 917 | } |
1b6bf175 | 918 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 919 | continue; |
3839e657 | 920 | } |
21afac09 TT |
921 | /* |
922 | * Check for inodes who might have been part of the | |
923 | * orphaned list linked list. They should have gotten | |
924 | * dealt with by now, unless the list had somehow been | |
925 | * corrupted. | |
efc6f628 | 926 | * |
21afac09 TT |
927 | * FIXME: In the future, inodes which are still in use |
928 | * (and which are therefore) pending truncation should | |
929 | * be handled specially. Right now we just clear the | |
930 | * dtime field, and the normal e2fsck handling of | |
931 | * inodes where i_size and the inode blocks are | |
932 | * inconsistent is to fix i_size, instead of releasing | |
933 | * the extra blocks. This won't catch the inodes that | |
934 | * was at the end of the orphan list, but it's better | |
935 | * than nothing. The right answer is that there | |
936 | * shouldn't be any bugs in the orphan list handling. :-) | |
937 | */ | |
cebe48a1 TT |
938 | if (inode->i_dtime && !busted_fs_time && |
939 | inode->i_dtime < ctx->fs->super->s_inodes_count) { | |
21afac09 | 940 | if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { |
cebe48a1 | 941 | inode->i_dtime = inode->i_links_count ? |
1f3ad14a | 942 | 0 : ctx->now; |
cebe48a1 | 943 | e2fsck_write_inode(ctx, ino, inode, |
21afac09 TT |
944 | "pass1"); |
945 | } | |
946 | } | |
efc6f628 | 947 | |
3839e657 TT |
948 | /* |
949 | * This code assumes that deleted inodes have | |
efc6f628 | 950 | * i_links_count set to 0. |
3839e657 | 951 | */ |
cebe48a1 TT |
952 | if (!inode->i_links_count) { |
953 | if (!inode->i_dtime && inode->i_mode) { | |
1b6bf175 | 954 | if (fix_problem(ctx, |
21c84b71 | 955 | PR_1_ZERO_DTIME, &pctx)) { |
1f3ad14a | 956 | inode->i_dtime = ctx->now; |
cebe48a1 | 957 | e2fsck_write_inode(ctx, ino, inode, |
f3db3566 | 958 | "pass1"); |
21c84b71 | 959 | } |
3839e657 | 960 | } |
d237a78e | 961 | continue; |
3839e657 TT |
962 | } |
963 | /* | |
1e3472c5 | 964 | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
3839e657 | 965 | * deleted files. Oops. |
1e3472c5 TT |
966 | * |
967 | * Since all new ext2 implementations get this right, | |
968 | * we now assume that the case of non-zero | |
969 | * i_links_count and non-zero dtime means that we | |
970 | * should keep the file, not delete it. | |
efc6f628 | 971 | * |
3839e657 | 972 | */ |
cebe48a1 | 973 | if (inode->i_dtime) { |
1b6bf175 | 974 | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
cebe48a1 TT |
975 | inode->i_dtime = 0; |
976 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
21c84b71 | 977 | } |
3839e657 | 978 | } |
efc6f628 | 979 | |
c5d2f50d | 980 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
1e3472c5 | 981 | switch (fs->super->s_creator_os) { |
1e3472c5 | 982 | case EXT2_OS_HURD: |
cebe48a1 TT |
983 | frag = inode->osd2.hurd2.h_i_frag; |
984 | fsize = inode->osd2.hurd2.h_i_fsize; | |
1e3472c5 | 985 | break; |
1e3472c5 TT |
986 | default: |
987 | frag = fsize = 0; | |
988 | } | |
efc6f628 | 989 | |
cebe48a1 TT |
990 | if (inode->i_faddr || frag || fsize || |
991 | (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl)) | |
fdbdea09 | 992 | mark_inode_bad(ctx, ino); |
911ec626 TT |
993 | if (!(fs->super->s_feature_incompat & |
994 | EXT4_FEATURE_INCOMPAT_64BIT) && | |
995 | inode->osd2.linux2.l_i_file_acl_high != 0) | |
996 | mark_inode_bad(ctx, ino); | |
5d17119d | 997 | if ((fs->super->s_creator_os == EXT2_OS_LINUX) && |
efc6f628 | 998 | !(fs->super->s_feature_ro_compat & |
5d17119d TT |
999 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && |
1000 | (inode->osd2.linux2.l_i_blocks_hi != 0)) | |
1001 | mark_inode_bad(ctx, ino); | |
cebe48a1 | 1002 | if (inode->i_flags & EXT2_IMAGIC_FL) { |
6fdc7a32 TT |
1003 | if (imagic_fs) { |
1004 | if (!ctx->inode_imagic_map) | |
1005 | alloc_imagic_map(ctx); | |
c5d2f50d | 1006 | ext2fs_mark_inode_bitmap2(ctx->inode_imagic_map, |
6fdc7a32 TT |
1007 | ino); |
1008 | } else { | |
1009 | if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) { | |
cebe48a1 | 1010 | inode->i_flags &= ~EXT2_IMAGIC_FL; |
6fdc7a32 | 1011 | e2fsck_write_inode(ctx, ino, |
cebe48a1 | 1012 | inode, "pass1"); |
6fdc7a32 TT |
1013 | } |
1014 | } | |
aa4115a4 | 1015 | } |
cebe48a1 TT |
1016 | |
1017 | check_inode_extra_space(ctx, &pctx); | |
fbc3f901 | 1018 | check_is_really_dir(ctx, &pctx, block_buf); |
cebe48a1 | 1019 | |
dfc870c7 ES |
1020 | /* |
1021 | * ext2fs_inode_has_valid_blocks does not actually look | |
1022 | * at i_block[] values, so not endian-sensitive here. | |
1023 | */ | |
cb23cad5 TT |
1024 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL) && |
1025 | LINUX_S_ISLNK(inode->i_mode) && | |
1026 | !ext2fs_inode_has_valid_blocks(inode) && | |
1027 | fix_problem(ctx, PR_1_FAST_SYMLINK_EXTENT_FL, &pctx)) { | |
1028 | inode->i_flags &= ~EXT4_EXTENTS_FL; | |
1029 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
1030 | } | |
1031 | ||
cebe48a1 | 1032 | if (LINUX_S_ISDIR(inode->i_mode)) { |
c5d2f50d | 1033 | ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); |
08b21301 | 1034 | e2fsck_add_dir_info(ctx, ino, 0); |
1b6bf175 | 1035 | ctx->fs_directory_count++; |
cebe48a1 | 1036 | } else if (LINUX_S_ISREG (inode->i_mode)) { |
c5d2f50d | 1037 | ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino); |
1b6bf175 | 1038 | ctx->fs_regular_count++; |
cebe48a1 TT |
1039 | } else if (LINUX_S_ISCHR (inode->i_mode) && |
1040 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1041 | check_immutable(ctx, &pctx); |
d647a1ea | 1042 | check_size(ctx, &pctx); |
1b6bf175 | 1043 | ctx->fs_chardev_count++; |
cebe48a1 TT |
1044 | } else if (LINUX_S_ISBLK (inode->i_mode) && |
1045 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1046 | check_immutable(ctx, &pctx); |
d647a1ea | 1047 | check_size(ctx, &pctx); |
1b6bf175 | 1048 | ctx->fs_blockdev_count++; |
cebe48a1 | 1049 | } else if (LINUX_S_ISLNK (inode->i_mode) && |
efc6f628 | 1050 | e2fsck_pass1_check_symlink(fs, ino, inode, |
7cadc577 | 1051 | block_buf)) { |
fd77b2c7 | 1052 | check_immutable(ctx, &pctx); |
1b6bf175 | 1053 | ctx->fs_symlinks_count++; |
cebe48a1 | 1054 | if (ext2fs_inode_data_blocks(fs, inode) == 0) { |
1b6bf175 | 1055 | ctx->fs_fast_symlinks_count++; |
0684a4f3 | 1056 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 1057 | continue; |
21c84b71 | 1058 | } |
3839e657 | 1059 | } |
cebe48a1 TT |
1060 | else if (LINUX_S_ISFIFO (inode->i_mode) && |
1061 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1062 | check_immutable(ctx, &pctx); |
d647a1ea | 1063 | check_size(ctx, &pctx); |
1b6bf175 | 1064 | ctx->fs_fifo_count++; |
cebe48a1 TT |
1065 | } else if ((LINUX_S_ISSOCK (inode->i_mode)) && |
1066 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1067 | check_immutable(ctx, &pctx); |
d647a1ea TT |
1068 | check_size(ctx, &pctx); |
1069 | ctx->fs_sockets_count++; | |
fdbdea09 TT |
1070 | } else |
1071 | mark_inode_bad(ctx, ino); | |
8da6d1a1 TT |
1072 | if (!(inode->i_flags & EXT4_EXTENTS_FL)) { |
1073 | if (inode->i_block[EXT2_IND_BLOCK]) | |
1074 | ctx->fs_ind_count++; | |
1075 | if (inode->i_block[EXT2_DIND_BLOCK]) | |
1076 | ctx->fs_dind_count++; | |
1077 | if (inode->i_block[EXT2_TIND_BLOCK]) | |
1078 | ctx->fs_tind_count++; | |
1079 | } | |
15d482ba TT |
1080 | if (!(inode->i_flags & EXT4_EXTENTS_FL) && |
1081 | (inode->i_block[EXT2_IND_BLOCK] || | |
1082 | inode->i_block[EXT2_DIND_BLOCK] || | |
1083 | inode->i_block[EXT2_TIND_BLOCK] || | |
a63745e8 | 1084 | ext2fs_file_acl_block(inode))) { |
3839e657 | 1085 | inodes_to_process[process_inode_count].ino = ino; |
cebe48a1 | 1086 | inodes_to_process[process_inode_count].inode = *inode; |
3839e657 | 1087 | process_inode_count++; |
f3db3566 | 1088 | } else |
1b6bf175 | 1089 | check_blocks(ctx, &pctx, block_buf); |
3839e657 | 1090 | |
a02ce9df | 1091 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
1092 | return; |
1093 | ||
1094 | if (process_inode_count >= ctx->process_inode_size) { | |
1b6bf175 | 1095 | process_inodes(ctx, block_buf); |
08b21301 | 1096 | |
a02ce9df | 1097 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
1098 | return; |
1099 | } | |
3839e657 | 1100 | } |
1b6bf175 | 1101 | process_inodes(ctx, block_buf); |
3839e657 | 1102 | ext2fs_close_inode_scan(scan); |
3839e657 | 1103 | |
e8a3ee62 TT |
1104 | /* |
1105 | * If any extended attribute blocks' reference counts need to | |
1106 | * be adjusted, either up (ctx->refcount_extra), or down | |
1107 | * (ctx->refcount), then fix them. | |
1108 | */ | |
1109 | if (ctx->refcount) { | |
1110 | adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1); | |
1111 | ea_refcount_free(ctx->refcount); | |
1112 | ctx->refcount = 0; | |
1113 | } | |
1114 | if (ctx->refcount_extra) { | |
1115 | adjust_extattr_refcount(ctx, ctx->refcount_extra, | |
1116 | block_buf, +1); | |
1117 | ea_refcount_free(ctx->refcount_extra); | |
1118 | ctx->refcount_extra = 0; | |
1119 | } | |
efc6f628 | 1120 | |
1b6bf175 TT |
1121 | if (ctx->invalid_bitmaps) |
1122 | handle_fs_bad_blocks(ctx); | |
f3db3566 | 1123 | |
24ceb248 TT |
1124 | /* We don't need the block_ea_map any more */ |
1125 | if (ctx->block_ea_map) { | |
1126 | ext2fs_free_block_bitmap(ctx->block_ea_map); | |
1127 | ctx->block_ea_map = 0; | |
1128 | } | |
1129 | ||
c3ffaf83 TT |
1130 | if (ctx->flags & E2F_FLAG_RESIZE_INODE) { |
1131 | ext2fs_block_bitmap save_bmap; | |
c3ffaf83 TT |
1132 | |
1133 | save_bmap = fs->block_map; | |
1134 | fs->block_map = ctx->block_found_map; | |
1135 | clear_problem_context(&pctx); | |
1136 | pctx.errcode = ext2fs_create_resize_inode(fs); | |
1137 | if (pctx.errcode) { | |
a6217f5a TT |
1138 | if (!fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, |
1139 | &pctx)) { | |
1140 | ctx->flags |= E2F_FLAG_ABORT; | |
1141 | return; | |
1142 | } | |
1143 | pctx.errcode = 0; | |
1144 | } | |
1145 | if (!pctx.errcode) { | |
1146 | e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, | |
1147 | "recreate inode"); | |
1148 | inode->i_mtime = ctx->now; | |
1149 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, | |
1150 | "recreate inode"); | |
c3ffaf83 TT |
1151 | } |
1152 | fs->block_map = save_bmap; | |
1153 | ctx->flags &= ~E2F_FLAG_RESIZE_INODE; | |
1154 | } | |
efc6f628 | 1155 | |
08b21301 | 1156 | if (ctx->flags & E2F_FLAG_RESTART) { |
aa4115a4 TT |
1157 | /* |
1158 | * Only the master copy of the superblock and block | |
1159 | * group descriptors are going to be written during a | |
1160 | * restart, so set the superblock to be used to be the | |
1161 | * master superblock. | |
1162 | */ | |
1163 | ctx->use_superblock = 0; | |
f3db3566 TT |
1164 | unwind_pass1(fs); |
1165 | goto endit; | |
1166 | } | |
1167 | ||
1b6bf175 TT |
1168 | if (ctx->block_dup_map) { |
1169 | if (ctx->options & E2F_OPT_PREEN) { | |
1170 | clear_problem_context(&pctx); | |
1171 | fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); | |
3839e657 | 1172 | } |
08b21301 | 1173 | e2fsck_pass1_dupblocks(ctx, block_buf); |
3839e657 | 1174 | } |
c4e3d3f3 | 1175 | ext2fs_free_mem(&inodes_to_process); |
f3db3566 | 1176 | endit: |
e72a9ba3 | 1177 | e2fsck_use_inode_shortcuts(ctx, 0); |
efc6f628 | 1178 | |
c4e3d3f3 | 1179 | ext2fs_free_mem(&block_buf); |
cebe48a1 | 1180 | ext2fs_free_mem(&inode); |
21c84b71 | 1181 | |
9facd076 | 1182 | print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io); |
3839e657 TT |
1183 | } |
1184 | ||
f3db3566 TT |
1185 | /* |
1186 | * When the inode_scan routines call this callback at the end of the | |
1187 | * glock group, call process_inodes. | |
1188 | */ | |
efc6f628 | 1189 | static errcode_t scan_callback(ext2_filsys fs, |
54434927 | 1190 | ext2_inode_scan scan EXT2FS_ATTR((unused)), |
54dc7ca2 | 1191 | dgrp_t group, void * priv_data) |
f3db3566 | 1192 | { |
54dc7ca2 | 1193 | struct scan_callback_struct *scan_struct; |
f8188fff TT |
1194 | e2fsck_t ctx; |
1195 | ||
54dc7ca2 | 1196 | scan_struct = (struct scan_callback_struct *) priv_data; |
f8188fff | 1197 | ctx = scan_struct->ctx; |
efc6f628 | 1198 | |
54dc7ca2 | 1199 | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
f8188fff TT |
1200 | |
1201 | if (ctx->progress) | |
a02ce9df TT |
1202 | if ((ctx->progress)(ctx, 1, group+1, |
1203 | ctx->fs->group_desc_count)) | |
1204 | return EXT2_ET_CANCEL_REQUESTED; | |
f8188fff | 1205 | |
f3db3566 TT |
1206 | return 0; |
1207 | } | |
1208 | ||
3839e657 TT |
1209 | /* |
1210 | * Process the inodes in the "inodes to process" list. | |
1211 | */ | |
1b6bf175 | 1212 | static void process_inodes(e2fsck_t ctx, char *block_buf) |
3839e657 TT |
1213 | { |
1214 | int i; | |
1215 | struct ext2_inode *old_stashed_inode; | |
86c627ec | 1216 | ext2_ino_t old_stashed_ino; |
3839e657 TT |
1217 | const char *old_operation; |
1218 | char buf[80]; | |
21c84b71 | 1219 | struct problem_context pctx; |
efc6f628 | 1220 | |
3839e657 | 1221 | #if 0 |
f3db3566 | 1222 | printf("begin process_inodes: "); |
3839e657 | 1223 | #endif |
86a63e92 TT |
1224 | if (process_inode_count == 0) |
1225 | return; | |
3839e657 | 1226 | old_operation = ehandler_operation(0); |
1b6bf175 TT |
1227 | old_stashed_inode = ctx->stashed_inode; |
1228 | old_stashed_ino = ctx->stashed_ino; | |
3839e657 TT |
1229 | qsort(inodes_to_process, process_inode_count, |
1230 | sizeof(struct process_inode_block), process_inode_cmp); | |
21c84b71 | 1231 | clear_problem_context(&pctx); |
3839e657 | 1232 | for (i=0; i < process_inode_count; i++) { |
1b6bf175 TT |
1233 | pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; |
1234 | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; | |
efc6f628 | 1235 | |
3839e657 | 1236 | #if 0 |
21c84b71 | 1237 | printf("%u ", pctx.ino); |
3839e657 | 1238 | #endif |
86c627ec | 1239 | sprintf(buf, _("reading indirect blocks of inode %u"), |
0c4a0726 | 1240 | pctx.ino); |
3839e657 | 1241 | ehandler_operation(buf); |
1b6bf175 | 1242 | check_blocks(ctx, &pctx, block_buf); |
a02ce9df | 1243 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2df1f6aa | 1244 | break; |
3839e657 | 1245 | } |
1b6bf175 TT |
1246 | ctx->stashed_inode = old_stashed_inode; |
1247 | ctx->stashed_ino = old_stashed_ino; | |
3839e657 TT |
1248 | process_inode_count = 0; |
1249 | #if 0 | |
f3db3566 | 1250 | printf("end process inodes\n"); |
3839e657 TT |
1251 | #endif |
1252 | ehandler_operation(old_operation); | |
1253 | } | |
1254 | ||
4c77fe50 | 1255 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) |
3839e657 TT |
1256 | { |
1257 | const struct process_inode_block *ib_a = | |
1258 | (const struct process_inode_block *) a; | |
1259 | const struct process_inode_block *ib_b = | |
1260 | (const struct process_inode_block *) b; | |
b5acdb6a | 1261 | int ret; |
efc6f628 | 1262 | |
b5acdb6a TT |
1263 | ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] - |
1264 | ib_b->inode.i_block[EXT2_IND_BLOCK]); | |
1265 | if (ret == 0) | |
a63745e8 VAH |
1266 | ret = ext2fs_file_acl_block(&(ib_a->inode)) - |
1267 | ext2fs_file_acl_block(&ib_b->inode); | |
0eeec8ac TT |
1268 | if (ret == 0) |
1269 | ret = ib_a->ino - ib_b->ino; | |
b5acdb6a | 1270 | return ret; |
3839e657 TT |
1271 | } |
1272 | ||
3839e657 | 1273 | /* |
fdbdea09 | 1274 | * Mark an inode as being bad in some what |
3839e657 | 1275 | */ |
fdbdea09 | 1276 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino) |
3839e657 | 1277 | { |
1b6bf175 | 1278 | struct problem_context pctx; |
fdbdea09 TT |
1279 | |
1280 | if (!ctx->inode_bad_map) { | |
1281 | clear_problem_context(&pctx); | |
efc6f628 | 1282 | |
fdbdea09 TT |
1283 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, |
1284 | _("bad inode map"), &ctx->inode_bad_map); | |
1285 | if (pctx.errcode) { | |
1286 | pctx.num = 3; | |
1287 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1288 | /* Should never get here */ | |
1289 | ctx->flags |= E2F_FLAG_ABORT; | |
1290 | return; | |
1291 | } | |
3839e657 | 1292 | } |
c5d2f50d | 1293 | ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino); |
3839e657 TT |
1294 | } |
1295 | ||
fdbdea09 | 1296 | |
21c84b71 TT |
1297 | /* |
1298 | * This procedure will allocate the inode "bb" (badblock) map table | |
1299 | */ | |
1b6bf175 | 1300 | static void alloc_bb_map(e2fsck_t ctx) |
21c84b71 | 1301 | { |
1b6bf175 | 1302 | struct problem_context pctx; |
efc6f628 | 1303 | |
1b6bf175 TT |
1304 | clear_problem_context(&pctx); |
1305 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, | |
0c4a0726 | 1306 | _("inode in bad block map"), |
1b6bf175 TT |
1307 | &ctx->inode_bb_map); |
1308 | if (pctx.errcode) { | |
1309 | pctx.num = 4; | |
1310 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
1311 | /* Should never get here */ |
1312 | ctx->flags |= E2F_FLAG_ABORT; | |
1313 | return; | |
21c84b71 TT |
1314 | } |
1315 | } | |
1316 | ||
aa4115a4 TT |
1317 | /* |
1318 | * This procedure will allocate the inode imagic table | |
1319 | */ | |
1320 | static void alloc_imagic_map(e2fsck_t ctx) | |
1321 | { | |
1322 | struct problem_context pctx; | |
efc6f628 | 1323 | |
aa4115a4 TT |
1324 | clear_problem_context(&pctx); |
1325 | pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, | |
0c4a0726 | 1326 | _("imagic inode map"), |
aa4115a4 TT |
1327 | &ctx->inode_imagic_map); |
1328 | if (pctx.errcode) { | |
1329 | pctx.num = 5; | |
1330 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1331 | /* Should never get here */ | |
1332 | ctx->flags |= E2F_FLAG_ABORT; | |
1333 | return; | |
1334 | } | |
1335 | } | |
1336 | ||
3839e657 TT |
1337 | /* |
1338 | * Marks a block as in use, setting the dup_map if it's been set | |
1339 | * already. Called by process_block and process_bad_block. | |
50e1e10f TT |
1340 | * |
1341 | * WARNING: Assumes checks have already been done to make sure block | |
1342 | * is valid. This is true in both process_block and process_bad_block. | |
3839e657 | 1343 | */ |
6dc64392 | 1344 | static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block) |
3839e657 | 1345 | { |
1b6bf175 | 1346 | struct problem_context pctx; |
efc6f628 | 1347 | |
1b6bf175 | 1348 | clear_problem_context(&pctx); |
efc6f628 | 1349 | |
c5d2f50d | 1350 | if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) { |
1b6bf175 TT |
1351 | if (!ctx->block_dup_map) { |
1352 | pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs, | |
0c4a0726 | 1353 | _("multiply claimed block map"), |
1b6bf175 TT |
1354 | &ctx->block_dup_map); |
1355 | if (pctx.errcode) { | |
1356 | pctx.num = 3; | |
efc6f628 | 1357 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, |
1b6bf175 | 1358 | &pctx); |
08b21301 TT |
1359 | /* Should never get here */ |
1360 | ctx->flags |= E2F_FLAG_ABORT; | |
1361 | return; | |
3839e657 TT |
1362 | } |
1363 | } | |
c5d2f50d | 1364 | ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block); |
3839e657 | 1365 | } else { |
c5d2f50d | 1366 | ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block); |
3839e657 TT |
1367 | } |
1368 | } | |
1369 | ||
e8a3ee62 TT |
1370 | /* |
1371 | * Adjust the extended attribute block's reference counts at the end | |
1372 | * of pass 1, either by subtracting out references for EA blocks that | |
1373 | * are still referenced in ctx->refcount, or by adding references for | |
1374 | * EA blocks that had extra references as accounted for in | |
1375 | * ctx->refcount_extra. | |
1376 | */ | |
efc6f628 | 1377 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
e8a3ee62 TT |
1378 | char *block_buf, int adjust_sign) |
1379 | { | |
1380 | struct ext2_ext_attr_header *header; | |
1381 | struct problem_context pctx; | |
1382 | ext2_filsys fs = ctx->fs; | |
6dc64392 | 1383 | blk64_t blk; |
e8a3ee62 TT |
1384 | __u32 should_be; |
1385 | int count; | |
1386 | ||
1387 | clear_problem_context(&pctx); | |
efc6f628 | 1388 | |
e8a3ee62 TT |
1389 | ea_refcount_intr_begin(refcount); |
1390 | while (1) { | |
1391 | if ((blk = ea_refcount_intr_next(refcount, &count)) == 0) | |
1392 | break; | |
1393 | pctx.blk = blk; | |
6dc64392 | 1394 | pctx.errcode = ext2fs_read_ext_attr2(fs, blk, block_buf); |
e8a3ee62 TT |
1395 | if (pctx.errcode) { |
1396 | fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx); | |
1397 | return; | |
1398 | } | |
1399 | header = (struct ext2_ext_attr_header *) block_buf; | |
1400 | pctx.blkcount = header->h_refcount; | |
1401 | should_be = header->h_refcount + adjust_sign * count; | |
1402 | pctx.num = should_be; | |
1403 | if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) { | |
1404 | header->h_refcount = should_be; | |
6dc64392 | 1405 | pctx.errcode = ext2fs_write_ext_attr2(fs, blk, |
e8a3ee62 TT |
1406 | block_buf); |
1407 | if (pctx.errcode) { | |
a6217f5a TT |
1408 | fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT, |
1409 | &pctx); | |
e8a3ee62 TT |
1410 | continue; |
1411 | } | |
1412 | } | |
1413 | } | |
1414 | } | |
1415 | ||
342d847d TT |
1416 | /* |
1417 | * Handle processing the extended attribute blocks | |
1418 | */ | |
1419 | static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, | |
1420 | char *block_buf) | |
1421 | { | |
1422 | ext2_filsys fs = ctx->fs; | |
1423 | ext2_ino_t ino = pctx->ino; | |
1424 | struct ext2_inode *inode = pctx->inode; | |
6dc64392 | 1425 | blk64_t blk; |
55fd07ed | 1426 | char * end; |
e8a3ee62 | 1427 | struct ext2_ext_attr_header *header; |
55fd07ed | 1428 | struct ext2_ext_attr_entry *entry; |
342d847d | 1429 | int count; |
86bc90f4 | 1430 | region_t region = 0; |
5469d767 | 1431 | |
a63745e8 | 1432 | blk = ext2fs_file_acl_block(inode); |
342d847d TT |
1433 | if (blk == 0) |
1434 | return 0; | |
1435 | ||
1436 | /* | |
1437 | * If the Extended attribute flag isn't set, then a non-zero | |
1438 | * file acl means that the inode is corrupted. | |
1439 | * | |
1440 | * Or if the extended attribute block is an invalid block, | |
1441 | * then the inode is also corrupted. | |
1442 | */ | |
1443 | if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) || | |
1444 | (blk < fs->super->s_first_data_block) || | |
4efbac6f | 1445 | (blk >= ext2fs_blocks_count(fs->super))) { |
342d847d TT |
1446 | mark_inode_bad(ctx, ino); |
1447 | return 0; | |
1448 | } | |
1449 | ||
1450 | /* If ea bitmap hasn't been allocated, create it */ | |
1451 | if (!ctx->block_ea_map) { | |
1452 | pctx->errcode = ext2fs_allocate_block_bitmap(fs, | |
1453 | _("ext attr block map"), | |
1454 | &ctx->block_ea_map); | |
1455 | if (pctx->errcode) { | |
1456 | pctx->num = 2; | |
1457 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx); | |
1458 | ctx->flags |= E2F_FLAG_ABORT; | |
1459 | return 0; | |
1460 | } | |
1461 | } | |
1462 | ||
1463 | /* Create the EA refcount structure if necessary */ | |
1464 | if (!ctx->refcount) { | |
1465 | pctx->errcode = ea_refcount_create(0, &ctx->refcount); | |
1466 | if (pctx->errcode) { | |
1467 | pctx->num = 1; | |
1468 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
1469 | ctx->flags |= E2F_FLAG_ABORT; | |
1470 | return 0; | |
1471 | } | |
1472 | } | |
1473 | ||
b5acdb6a TT |
1474 | #if 0 |
1475 | /* Debugging text */ | |
1476 | printf("Inode %u has EA block %u\n", ino, blk); | |
1477 | #endif | |
1478 | ||
342d847d | 1479 | /* Have we seen this EA block before? */ |
c5d2f50d | 1480 | if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) { |
342d847d TT |
1481 | if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0) |
1482 | return 1; | |
1483 | /* Ooops, this EA was referenced more than it stated */ | |
1484 | if (!ctx->refcount_extra) { | |
1485 | pctx->errcode = ea_refcount_create(0, | |
1486 | &ctx->refcount_extra); | |
1487 | if (pctx->errcode) { | |
1488 | pctx->num = 2; | |
1489 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
1490 | ctx->flags |= E2F_FLAG_ABORT; | |
55fd07ed | 1491 | return 0; |
342d847d TT |
1492 | } |
1493 | } | |
1494 | ea_refcount_increment(ctx->refcount_extra, blk, 0); | |
1495 | return 1; | |
1496 | } | |
5469d767 | 1497 | |
342d847d TT |
1498 | /* |
1499 | * OK, we haven't seen this EA block yet. So we need to | |
1500 | * validate it | |
1501 | */ | |
1502 | pctx->blk = blk; | |
6dc64392 | 1503 | pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf); |
342d847d TT |
1504 | if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) |
1505 | goto clear_extattr; | |
342d847d | 1506 | header = (struct ext2_ext_attr_header *) block_buf; |
a63745e8 | 1507 | pctx->blk = ext2fs_file_acl_block(inode); |
0684a4f3 TT |
1508 | if (((ctx->ext_attr_ver == 1) && |
1509 | (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) || | |
1510 | ((ctx->ext_attr_ver == 2) && | |
1511 | (header->h_magic != EXT2_EXT_ATTR_MAGIC))) { | |
1512 | if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx)) | |
1513 | goto clear_extattr; | |
1514 | } | |
0d63467d | 1515 | |
55fd07ed TT |
1516 | if (header->h_blocks != 1) { |
1517 | if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx)) | |
1518 | goto clear_extattr; | |
1519 | } | |
1520 | ||
1521 | region = region_create(0, fs->blocksize); | |
1522 | if (!region) { | |
a6217f5a | 1523 | fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx); |
55fd07ed TT |
1524 | ctx->flags |= E2F_FLAG_ABORT; |
1525 | return 0; | |
1526 | } | |
1527 | if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) { | |
1528 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
342d847d TT |
1529 | goto clear_extattr; |
1530 | } | |
5469d767 | 1531 | |
55fd07ed TT |
1532 | entry = (struct ext2_ext_attr_entry *)(header+1); |
1533 | end = block_buf + fs->blocksize; | |
1534 | while ((char *)entry < end && *(__u32 *)entry) { | |
fefaef39 AD |
1535 | __u32 hash; |
1536 | ||
55fd07ed TT |
1537 | if (region_allocate(region, (char *)entry - (char *)header, |
1538 | EXT2_EXT_ATTR_LEN(entry->e_name_len))) { | |
1539 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
1540 | goto clear_extattr; | |
fefaef39 | 1541 | break; |
55fd07ed | 1542 | } |
0684a4f3 | 1543 | if ((ctx->ext_attr_ver == 1 && |
0d63467d | 1544 | (entry->e_name_len == 0 || entry->e_name_index != 0)) || |
0684a4f3 | 1545 | (ctx->ext_attr_ver == 2 && |
0d63467d | 1546 | entry->e_name_index == 0)) { |
55fd07ed TT |
1547 | if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) |
1548 | goto clear_extattr; | |
fefaef39 | 1549 | break; |
55fd07ed TT |
1550 | } |
1551 | if (entry->e_value_block != 0) { | |
1552 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
1553 | goto clear_extattr; | |
1554 | } | |
a34c6ffd AD |
1555 | if (entry->e_value_offs + entry->e_value_size > fs->blocksize) { |
1556 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
1557 | goto clear_extattr; | |
1558 | break; | |
1559 | } | |
14fe1c33 TT |
1560 | if (entry->e_value_size && |
1561 | region_allocate(region, entry->e_value_offs, | |
1562 | EXT2_EXT_ATTR_SIZE(entry->e_value_size))) { | |
55fd07ed TT |
1563 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
1564 | goto clear_extattr; | |
1565 | } | |
fefaef39 AD |
1566 | |
1567 | hash = ext2fs_ext_attr_hash_entry(entry, block_buf + | |
1568 | entry->e_value_offs); | |
1569 | ||
1570 | if (entry->e_hash != hash) { | |
1571 | pctx->num = entry->e_hash; | |
1572 | if (fix_problem(ctx, PR_1_ATTR_HASH, pctx)) | |
1573 | goto clear_extattr; | |
1574 | entry->e_hash = hash; | |
1575 | } | |
1576 | ||
55fd07ed TT |
1577 | entry = EXT2_EXT_ATTR_NEXT(entry); |
1578 | } | |
1579 | if (region_allocate(region, (char *)entry - (char *)header, 4)) { | |
1580 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
1581 | goto clear_extattr; | |
1582 | } | |
1583 | region_free(region); | |
342d847d TT |
1584 | |
1585 | count = header->h_refcount - 1; | |
1586 | if (count) | |
1587 | ea_refcount_store(ctx->refcount, blk, count); | |
1588 | mark_block_used(ctx, blk); | |
c5d2f50d | 1589 | ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk); |
342d847d TT |
1590 | return 1; |
1591 | ||
1592 | clear_extattr: | |
5469d767 BB |
1593 | if (region) |
1594 | region_free(region); | |
a63745e8 | 1595 | ext2fs_file_acl_block_set(inode, 0); |
342d847d TT |
1596 | e2fsck_write_inode(ctx, ino, inode, "check_ext_attr"); |
1597 | return 0; | |
1598 | } | |
1599 | ||
503f9e7f TT |
1600 | /* Returns 1 if bad htree, 0 if OK */ |
1601 | static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, | |
15d482ba | 1602 | ext2_ino_t ino, struct ext2_inode *inode, |
503f9e7f TT |
1603 | char *block_buf) |
1604 | { | |
1605 | struct ext2_dx_root_info *root; | |
1606 | ext2_filsys fs = ctx->fs; | |
1607 | errcode_t retval; | |
6dc64392 | 1608 | blk64_t blk; |
503f9e7f TT |
1609 | |
1610 | if ((!LINUX_S_ISDIR(inode->i_mode) && | |
1611 | fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) || | |
1612 | (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && | |
1613 | fix_problem(ctx, PR_1_HTREE_SET, pctx))) | |
1614 | return 1; | |
1615 | ||
6dc64392 | 1616 | pctx->errcode = ext2fs_bmap2(fs, ino, inode, 0, 0, 0, 0, &blk); |
15d482ba TT |
1617 | |
1618 | if ((pctx->errcode) || | |
1619 | (blk == 0) || | |
1620 | (blk < fs->super->s_first_data_block) || | |
4efbac6f | 1621 | (blk >= ext2fs_blocks_count(fs->super))) { |
15d482ba TT |
1622 | if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
1623 | return 1; | |
1624 | else | |
1625 | return 0; | |
1626 | } | |
503f9e7f | 1627 | |
24a117ab | 1628 | retval = io_channel_read_blk64(fs->io, blk, 1, block_buf); |
503f9e7f TT |
1629 | if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
1630 | return 1; | |
efc6f628 | 1631 | |
503f9e7f TT |
1632 | /* XXX should check that beginning matches a directory */ |
1633 | root = (struct ext2_dx_root_info *) (block_buf + 24); | |
1634 | ||
1635 | if ((root->reserved_zero || root->info_length < 8) && | |
1636 | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) | |
1637 | return 1; | |
1638 | ||
1639 | pctx->num = root->hash_version; | |
1640 | if ((root->hash_version != EXT2_HASH_LEGACY) && | |
1641 | (root->hash_version != EXT2_HASH_HALF_MD4) && | |
f044b4d8 | 1642 | (root->hash_version != EXT2_HASH_TEA) && |
503f9e7f TT |
1643 | fix_problem(ctx, PR_1_HTREE_HASHV, pctx)) |
1644 | return 1; | |
efc6f628 | 1645 | |
503f9e7f TT |
1646 | if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) && |
1647 | fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx)) | |
1648 | return 1; | |
1649 | ||
1650 | pctx->num = root->indirect_levels; | |
1651 | if ((root->indirect_levels > 1) && | |
1652 | fix_problem(ctx, PR_1_HTREE_DEPTH, pctx)) | |
1653 | return 1; | |
efc6f628 | 1654 | |
503f9e7f TT |
1655 | return 0; |
1656 | } | |
342d847d | 1657 | |
e3df15ab TT |
1658 | void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, |
1659 | struct ext2_inode *inode, int restart_flag, | |
1660 | const char *source) | |
1661 | { | |
15d482ba | 1662 | inode->i_flags = 0; |
e3df15ab TT |
1663 | inode->i_links_count = 0; |
1664 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); | |
1665 | inode->i_dtime = ctx->now; | |
1666 | ||
c5d2f50d VAH |
1667 | ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); |
1668 | ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); | |
e3df15ab | 1669 | if (ctx->inode_reg_map) |
c5d2f50d | 1670 | ext2fs_unmark_inode_bitmap2(ctx->inode_reg_map, ino); |
e3df15ab | 1671 | if (ctx->inode_bad_map) |
c5d2f50d | 1672 | ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); |
e3df15ab TT |
1673 | |
1674 | /* | |
1675 | * If the inode was partially accounted for before processing | |
1676 | * was aborted, we need to restart the pass 1 scan. | |
1677 | */ | |
1678 | ctx->flags |= restart_flag; | |
1679 | ||
1680 | e2fsck_write_inode(ctx, ino, inode, source); | |
1681 | } | |
1682 | ||
15d482ba | 1683 | static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, |
d5a8f9a9 TT |
1684 | struct process_block_struct *pb, |
1685 | blk64_t start_block, | |
15d482ba TT |
1686 | ext2_extent_handle_t ehandle) |
1687 | { | |
1688 | struct ext2fs_extent extent; | |
6dc64392 | 1689 | blk64_t blk; |
15d482ba | 1690 | e2_blkcnt_t blockcnt; |
2acad6b4 | 1691 | unsigned int i; |
15d482ba TT |
1692 | int is_dir, is_leaf; |
1693 | errcode_t problem; | |
11de9261 | 1694 | struct ext2_extent_info info; |
15d482ba | 1695 | |
11de9261 TT |
1696 | pctx->errcode = ext2fs_extent_get_info(ehandle, &info); |
1697 | if (pctx->errcode) | |
1698 | return; | |
15d482ba TT |
1699 | |
1700 | pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB, | |
1701 | &extent); | |
11de9261 | 1702 | while (!pctx->errcode && info.num_entries-- > 0) { |
15d482ba TT |
1703 | is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF; |
1704 | is_dir = LINUX_S_ISDIR(pctx->inode->i_mode); | |
1705 | ||
1706 | problem = 0; | |
e6238d37 TT |
1707 | if (extent.e_pblk == 0 || |
1708 | extent.e_pblk < ctx->fs->super->s_first_data_block || | |
4efbac6f | 1709 | extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super)) |
15d482ba | 1710 | problem = PR_1_EXTENT_BAD_START_BLK; |
d5a8f9a9 TT |
1711 | else if (extent.e_lblk < start_block) |
1712 | problem = PR_1_OUT_OF_ORDER_EXTENTS; | |
7a1eac2f ES |
1713 | else if (is_leaf && |
1714 | (extent.e_pblk + extent.e_len) > | |
4efbac6f | 1715 | ext2fs_blocks_count(ctx->fs->super)) |
15d482ba TT |
1716 | problem = PR_1_EXTENT_ENDS_BEYOND; |
1717 | ||
1718 | if (problem) { | |
7518c176 | 1719 | report_problem: |
15d482ba TT |
1720 | pctx->blk = extent.e_pblk; |
1721 | pctx->blk2 = extent.e_lblk; | |
1722 | pctx->num = extent.e_len; | |
1723 | if (fix_problem(ctx, problem, pctx)) { | |
19f433a5 | 1724 | e2fsck_read_bitmaps(ctx); |
15d482ba TT |
1725 | pctx->errcode = |
1726 | ext2fs_extent_delete(ehandle, 0); | |
1727 | if (pctx->errcode) { | |
7518c176 | 1728 | pctx->str = "ext2fs_extent_delete"; |
15d482ba TT |
1729 | return; |
1730 | } | |
73e5abcf TT |
1731 | pctx->errcode = ext2fs_extent_get(ehandle, |
1732 | EXT2_EXTENT_CURRENT, | |
1733 | &extent); | |
1734 | if (pctx->errcode == EXT2_ET_NO_CURRENT_NODE) { | |
1735 | pctx->errcode = 0; | |
1736 | break; | |
1737 | } | |
1738 | continue; | |
15d482ba TT |
1739 | } |
1740 | goto next; | |
1741 | } | |
1742 | ||
1743 | if (!is_leaf) { | |
7518c176 | 1744 | blk = extent.e_pblk; |
15d482ba TT |
1745 | pctx->errcode = ext2fs_extent_get(ehandle, |
1746 | EXT2_EXTENT_DOWN, &extent); | |
1747 | if (pctx->errcode) { | |
7518c176 TT |
1748 | pctx->str = "EXT2_EXTENT_DOWN"; |
1749 | problem = PR_1_EXTENT_HEADER_INVALID; | |
1750 | if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD) | |
1751 | goto report_problem; | |
1752 | return; | |
15d482ba | 1753 | } |
d5a8f9a9 | 1754 | scan_extent_node(ctx, pctx, pb, extent.e_lblk, ehandle); |
7518c176 TT |
1755 | if (pctx->errcode) |
1756 | return; | |
15d482ba TT |
1757 | pctx->errcode = ext2fs_extent_get(ehandle, |
1758 | EXT2_EXTENT_UP, &extent); | |
1759 | if (pctx->errcode) { | |
7518c176 TT |
1760 | pctx->str = "EXT2_EXTENT_UP"; |
1761 | return; | |
15d482ba | 1762 | } |
7518c176 TT |
1763 | mark_block_used(ctx, blk); |
1764 | pb->num_blocks++; | |
15d482ba TT |
1765 | goto next; |
1766 | } | |
1767 | ||
63b5e354 TT |
1768 | if ((pb->previous_block != 0) && |
1769 | (pb->previous_block+1 != extent.e_pblk)) { | |
100d4701 TT |
1770 | if (ctx->options & E2F_OPT_FRAGCHECK) { |
1771 | char type = '?'; | |
1772 | ||
1773 | if (pb->is_dir) | |
1774 | type = 'd'; | |
1775 | else if (pb->is_reg) | |
1776 | type = 'f'; | |
1777 | ||
1778 | printf(("%6lu(%c): expecting %6lu " | |
1779 | "actual extent " | |
63b5e354 | 1780 | "phys %6lu log %lu len %lu\n"), |
100d4701 | 1781 | (unsigned long) pctx->ino, type, |
63b5e354 TT |
1782 | (unsigned long) pb->previous_block+1, |
1783 | (unsigned long) extent.e_pblk, | |
1784 | (unsigned long) extent.e_lblk, | |
1785 | (unsigned long) extent.e_len); | |
100d4701 | 1786 | } |
63b5e354 TT |
1787 | pb->fragmented = 1; |
1788 | } | |
4607ef7d | 1789 | while (is_dir && ++pb->last_db_block < extent.e_lblk) { |
6dc64392 VAH |
1790 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, |
1791 | pb->ino, 0, | |
1792 | pb->last_db_block); | |
4607ef7d TT |
1793 | if (pctx->errcode) { |
1794 | pctx->blk = 0; | |
1795 | pctx->num = pb->last_db_block; | |
1796 | goto failed_add_dir_block; | |
1797 | } | |
1798 | } | |
15d482ba TT |
1799 | for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0; |
1800 | i < extent.e_len; | |
1801 | blk++, blockcnt++, i++) { | |
44fe08f1 TT |
1802 | if (!(ctx->fs->cluster_ratio_bits && |
1803 | pb->previous_block && | |
1804 | (EXT2FS_B2C(ctx->fs, blk) == | |
1805 | EXT2FS_B2C(ctx->fs, pb->previous_block)) && | |
1806 | (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) == | |
b2e6c86d | 1807 | (blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) { |
44fe08f1 | 1808 | mark_block_used(ctx, blk); |
b2e6c86d TT |
1809 | pb->num_blocks++; |
1810 | } | |
44fe08f1 TT |
1811 | |
1812 | pb->previous_block = blk; | |
15d482ba TT |
1813 | |
1814 | if (is_dir) { | |
6dc64392 | 1815 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pctx->ino, blk, blockcnt); |
15d482ba TT |
1816 | if (pctx->errcode) { |
1817 | pctx->blk = blk; | |
1818 | pctx->num = blockcnt; | |
4607ef7d | 1819 | failed_add_dir_block: |
15d482ba TT |
1820 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
1821 | /* Should never get here */ | |
1822 | ctx->flags |= E2F_FLAG_ABORT; | |
1823 | return; | |
1824 | } | |
1825 | } | |
1826 | } | |
4607ef7d TT |
1827 | if (is_dir && extent.e_len > 0) |
1828 | pb->last_db_block = blockcnt - 1; | |
63b5e354 | 1829 | pb->previous_block = extent.e_pblk + extent.e_len - 1; |
d9af85b5 | 1830 | start_block = pb->last_block = extent.e_lblk + extent.e_len - 1; |
15d482ba TT |
1831 | next: |
1832 | pctx->errcode = ext2fs_extent_get(ehandle, | |
1833 | EXT2_EXTENT_NEXT_SIB, | |
1834 | &extent); | |
1835 | } | |
1836 | if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT) | |
1837 | pctx->errcode = 0; | |
1838 | } | |
1839 | ||
1840 | static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, | |
2acad6b4 | 1841 | struct process_block_struct *pb) |
15d482ba | 1842 | { |
8da6d1a1 | 1843 | struct ext2_extent_info info; |
15d482ba TT |
1844 | struct ext2_inode *inode = pctx->inode; |
1845 | ext2_extent_handle_t ehandle; | |
1846 | ext2_filsys fs = ctx->fs; | |
1847 | ext2_ino_t ino = pctx->ino; | |
8da6d1a1 | 1848 | errcode_t retval; |
15d482ba | 1849 | |
84b239ae | 1850 | pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle); |
0a68b181 TT |
1851 | if (pctx->errcode) { |
1852 | if (fix_problem(ctx, PR_1_READ_EXTENT, pctx)) | |
1853 | e2fsck_clear_inode(ctx, ino, inode, 0, | |
1854 | "check_blocks_extents"); | |
15d482ba TT |
1855 | pctx->errcode = 0; |
1856 | return; | |
1857 | } | |
1858 | ||
8da6d1a1 TT |
1859 | retval = ext2fs_extent_get_info(ehandle, &info); |
1860 | if (retval == 0) { | |
1861 | if (info.max_depth >= MAX_EXTENT_DEPTH_COUNT) | |
1862 | info.max_depth = MAX_EXTENT_DEPTH_COUNT-1; | |
1863 | ctx->extent_depth_count[info.max_depth]++; | |
1864 | } | |
1865 | ||
d5a8f9a9 | 1866 | scan_extent_node(ctx, pctx, pb, 0, ehandle); |
7518c176 TT |
1867 | if (pctx->errcode && |
1868 | fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) { | |
1869 | pb->num_blocks = 0; | |
1870 | inode->i_blocks = 0; | |
1871 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, | |
1872 | "check_blocks_extents"); | |
1873 | pctx->errcode = 0; | |
1874 | } | |
15d482ba TT |
1875 | ext2fs_extent_free(ehandle); |
1876 | } | |
1877 | ||
3839e657 TT |
1878 | /* |
1879 | * This subroutine is called on each inode to account for all of the | |
1880 | * blocks used by that inode. | |
1881 | */ | |
1b6bf175 | 1882 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 TT |
1883 | char *block_buf) |
1884 | { | |
1b6bf175 | 1885 | ext2_filsys fs = ctx->fs; |
3839e657 | 1886 | struct process_block_struct pb; |
86c627ec | 1887 | ext2_ino_t ino = pctx->ino; |
21c84b71 | 1888 | struct ext2_inode *inode = pctx->inode; |
246501c6 | 1889 | int bad_size = 0; |
503f9e7f | 1890 | int dirty_inode = 0; |
7c1e090c | 1891 | int extent_fs; |
246501c6 | 1892 | __u64 size; |
efc6f628 | 1893 | |
3839e657 | 1894 | pb.ino = ino; |
0684a4f3 TT |
1895 | pb.num_blocks = 0; |
1896 | pb.last_block = -1; | |
4dbe79bc | 1897 | pb.last_db_block = -1; |
f3db3566 | 1898 | pb.num_illegal_blocks = 0; |
21c84b71 | 1899 | pb.suppress = 0; pb.clear = 0; |
74becf3c | 1900 | pb.fragmented = 0; |
1917875f | 1901 | pb.compressed = 0; |
74becf3c | 1902 | pb.previous_block = 0; |
b94a052a | 1903 | pb.is_dir = LINUX_S_ISDIR(inode->i_mode); |
da307041 TT |
1904 | pb.is_reg = LINUX_S_ISREG(inode->i_mode); |
1905 | pb.max_blocks = 1 << (31 - fs->super->s_log_block_size); | |
f3db3566 | 1906 | pb.inode = inode; |
21c84b71 | 1907 | pb.pctx = pctx; |
1b6bf175 TT |
1908 | pb.ctx = ctx; |
1909 | pctx->ino = ino; | |
0684a4f3 | 1910 | pctx->errcode = 0; |
1917875f | 1911 | |
7c1e090c ES |
1912 | extent_fs = (ctx->fs->super->s_feature_incompat & |
1913 | EXT3_FEATURE_INCOMPAT_EXTENTS); | |
1914 | ||
1917875f | 1915 | if (inode->i_flags & EXT2_COMPRBLK_FL) { |
f5ae75e5 TT |
1916 | if (fs->super->s_feature_incompat & |
1917 | EXT2_FEATURE_INCOMPAT_COMPRESSION) | |
1917875f TT |
1918 | pb.compressed = 1; |
1919 | else { | |
1920 | if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { | |
1921 | inode->i_flags &= ~EXT2_COMPRBLK_FL; | |
503f9e7f | 1922 | dirty_inode++; |
1917875f TT |
1923 | } |
1924 | } | |
1925 | } | |
1926 | ||
a63745e8 VAH |
1927 | if (ext2fs_file_acl_block(inode) && |
1928 | check_ext_attr(ctx, pctx, block_buf)) { | |
fefaef39 AD |
1929 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
1930 | goto out; | |
dc71f23e | 1931 | pb.num_blocks++; |
fefaef39 | 1932 | } |
dc71f23e | 1933 | |
15d482ba | 1934 | if (ext2fs_inode_has_valid_blocks(inode)) { |
7c1e090c | 1935 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) |
2acad6b4 | 1936 | check_blocks_extents(ctx, pctx, &pb); |
15d482ba | 1937 | else |
6dc64392 | 1938 | pctx->errcode = ext2fs_block_iterate3(fs, ino, |
15d482ba TT |
1939 | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
1940 | block_buf, process_block, &pb); | |
1941 | } | |
1b6bf175 | 1942 | end_problem_latch(ctx, PR_LATCH_BLOCK); |
da307041 | 1943 | end_problem_latch(ctx, PR_LATCH_TOOBIG); |
0684a4f3 TT |
1944 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
1945 | goto out; | |
1b6bf175 TT |
1946 | if (pctx->errcode) |
1947 | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); | |
3839e657 | 1948 | |
ce44d8ca TT |
1949 | if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) { |
1950 | if (LINUX_S_ISDIR(inode->i_mode)) | |
1951 | ctx->fs_fragmented_dir++; | |
1952 | else | |
1953 | ctx->fs_fragmented++; | |
1954 | } | |
74becf3c | 1955 | |
f3db3566 | 1956 | if (pb.clear) { |
e3df15ab TT |
1957 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, |
1958 | "check_blocks"); | |
1959 | return; | |
f3db3566 | 1960 | } |
efc6f628 | 1961 | |
8fdc9985 | 1962 | if (inode->i_flags & EXT2_INDEX_FL) { |
503f9e7f TT |
1963 | if (handle_htree(ctx, pctx, ino, inode, block_buf)) { |
1964 | inode->i_flags &= ~EXT2_INDEX_FL; | |
1965 | dirty_inode++; | |
1966 | } else { | |
8fdc9985 TT |
1967 | #ifdef ENABLE_HTREE |
1968 | e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); | |
1969 | #endif | |
503f9e7f | 1970 | } |
8fdc9985 | 1971 | } |
efc6f628 | 1972 | |
3839e657 | 1973 | if (!pb.num_blocks && pb.is_dir) { |
1b6bf175 | 1974 | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
e3df15ab | 1975 | e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks"); |
1b6bf175 | 1976 | ctx->fs_directory_count--; |
e3df15ab | 1977 | return; |
21c84b71 | 1978 | } |
3839e657 | 1979 | } |
0684a4f3 | 1980 | |
1ca1059f TT |
1981 | if (!(fs->super->s_feature_ro_compat & |
1982 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || | |
1983 | !(inode->i_flags & EXT4_HUGE_FILE_FL)) | |
1984 | pb.num_blocks *= (fs->blocksize / 512); | |
b2e6c86d | 1985 | pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs); |
0684a4f3 | 1986 | #if 0 |
b2e6c86d | 1987 | printf("inode %u, i_size = %u, last_block = %lld, i_blocks=%llu, num_blocks = %llu\n", |
6dc64392 | 1988 | ino, inode->i_size, pb.last_block, ext2fs_inode_i_blocks(fs, inode), |
0684a4f3 TT |
1989 | pb.num_blocks); |
1990 | #endif | |
246501c6 TT |
1991 | if (pb.is_dir) { |
1992 | int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); | |
efc6f628 | 1993 | if (inode->i_size & (fs->blocksize - 1)) |
2cd12338 TT |
1994 | bad_size = 5; |
1995 | else if (nblock > (pb.last_block + 1)) | |
246501c6 TT |
1996 | bad_size = 1; |
1997 | else if (nblock < (pb.last_block + 1)) { | |
246501c6 | 1998 | if (((pb.last_block + 1) - nblock) > |
5dd8f963 | 1999 | fs->super->s_prealloc_dir_blocks) |
9d1bd3de | 2000 | bad_size = 2; |
246501c6 TT |
2001 | } |
2002 | } else { | |
9f0288d3 TT |
2003 | e2_blkcnt_t blkpg = ctx->blocks_per_page; |
2004 | ||
4f489285 | 2005 | size = EXT2_I_SIZE(inode); |
0684a4f3 | 2006 | if ((pb.last_block >= 0) && |
9f0288d3 TT |
2007 | /* allow allocated blocks to end of PAGE_SIZE */ |
2008 | (size < (__u64)pb.last_block * fs->blocksize) && | |
2009 | (pb.last_block / blkpg * blkpg != pb.last_block || | |
4ffafee2 ES |
2010 | size < (__u64)(pb.last_block & ~(blkpg-1)) *fs->blocksize) && |
2011 | !(inode->i_flags & EXT4_EOFBLOCKS_FL)) | |
9d1bd3de | 2012 | bad_size = 3; |
7c1e090c ES |
2013 | else if (!(extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
2014 | size > ext2_max_sizes[fs->super->s_log_block_size]) | |
2015 | /* too big for a direct/indirect-mapped file */ | |
9d1bd3de | 2016 | bad_size = 4; |
7c1e090c | 2017 | else if ((extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
3ec7be43 | 2018 | size > |
03fa6f8a | 2019 | ((1ULL << (32 + EXT2_BLOCK_SIZE_BITS(fs->super))) - 1)) |
7c1e090c ES |
2020 | /* too big for an extent-based file - 32bit ee_block */ |
2021 | bad_size = 6; | |
2291fbb0 TT |
2022 | |
2023 | /* | |
2024 | * Check to see if the EOFBLOCKS flag is set where it | |
2025 | * doesn't need to be. | |
2026 | */ | |
2027 | if ((inode->i_flags & EXT4_EOFBLOCKS_FL) && | |
ae2272f8 | 2028 | (size >= (((__u64)pb.last_block + 1) * fs->blocksize))) { |
2291fbb0 TT |
2029 | pctx->blkcount = pb.last_block; |
2030 | if (fix_problem(ctx, PR_1_EOFBLOCKS_FL_SET, pctx)) { | |
2031 | inode->i_flags &= ~EXT4_EOFBLOCKS_FL; | |
2032 | dirty_inode++; | |
2033 | } | |
2034 | } | |
246501c6 | 2035 | } |
0684a4f3 TT |
2036 | /* i_size for symlinks is checked elsewhere */ |
2037 | if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) { | |
21c84b71 | 2038 | pctx->num = (pb.last_block+1) * fs->blocksize; |
3ec7be43 | 2039 | pctx->group = bad_size; |
1b6bf175 | 2040 | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
21c84b71 | 2041 | inode->i_size = pctx->num; |
0684a4f3 | 2042 | if (!LINUX_S_ISDIR(inode->i_mode)) |
246501c6 | 2043 | inode->i_size_high = pctx->num >> 32; |
503f9e7f | 2044 | dirty_inode++; |
21c84b71 TT |
2045 | } |
2046 | pctx->num = 0; | |
3839e657 | 2047 | } |
b94a052a AD |
2048 | if (LINUX_S_ISREG(inode->i_mode) && |
2049 | (inode->i_size_high || inode->i_size & 0x80000000UL)) | |
246501c6 | 2050 | ctx->large_files++; |
8a8f3654 | 2051 | if ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) || |
1ca1059f TT |
2052 | ((fs->super->s_feature_ro_compat & |
2053 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && | |
2054 | (inode->i_flags & EXT4_HUGE_FILE_FL) && | |
2055 | (inode->osd2.linux2.l_i_blocks_hi != 0))) { | |
21c84b71 | 2056 | pctx->num = pb.num_blocks; |
1b6bf175 | 2057 | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
3839e657 | 2058 | inode->i_blocks = pb.num_blocks; |
b70506bf | 2059 | inode->osd2.linux2.l_i_blocks_hi = pb.num_blocks >> 32; |
503f9e7f | 2060 | dirty_inode++; |
21c84b71 TT |
2061 | } |
2062 | pctx->num = 0; | |
3839e657 | 2063 | } |
a49249d2 TT |
2064 | |
2065 | if (ctx->dirs_to_hash && pb.is_dir && | |
2066 | !(inode->i_flags & EXT2_INDEX_FL) && | |
2067 | ((inode->i_size / fs->blocksize) >= 3)) | |
2068 | ext2fs_u32_list_add(ctx->dirs_to_hash, ino); | |
2069 | ||
503f9e7f TT |
2070 | out: |
2071 | if (dirty_inode) | |
2072 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); | |
50e1e10f TT |
2073 | } |
2074 | ||
21c84b71 | 2075 | #if 0 |
50e1e10f TT |
2076 | /* |
2077 | * Helper function called by process block when an illegal block is | |
2078 | * found. It returns a description about why the block is illegal | |
2079 | */ | |
6dc64392 | 2080 | static char *describe_illegal_block(ext2_filsys fs, blk64_t block) |
50e1e10f | 2081 | { |
6dc64392 | 2082 | blk64_t super; |
50e1e10f TT |
2083 | int i; |
2084 | static char problem[80]; | |
2085 | ||
2086 | super = fs->super->s_first_data_block; | |
2087 | strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block"); | |
2088 | if (block < super) { | |
2089 | sprintf(problem, "< FIRSTBLOCK (%u)", super); | |
2090 | return(problem); | |
4efbac6f VAH |
2091 | } else if (block >= ext2fs_blocks_count(fs->super)) { |
2092 | sprintf(problem, "> BLOCKS (%u)", ext2fs_blocks_count(fs->super)); | |
50e1e10f TT |
2093 | return(problem); |
2094 | } | |
2095 | for (i = 0; i < fs->group_desc_count; i++) { | |
2096 | if (block == super) { | |
2097 | sprintf(problem, "is the superblock in group %d", i); | |
2098 | break; | |
2099 | } | |
2100 | if (block > super && | |
2101 | block <= (super + fs->desc_blocks)) { | |
2102 | sprintf(problem, "is in the group descriptors " | |
2103 | "of group %d", i); | |
2104 | break; | |
2105 | } | |
d7cca6b0 | 2106 | if (block == ext2fs_block_bitmap_loc(fs, i)) { |
50e1e10f TT |
2107 | sprintf(problem, "is the block bitmap of group %d", i); |
2108 | break; | |
2109 | } | |
d7cca6b0 | 2110 | if (block == ext2fs_inode_bitmap_loc(fs, i)) { |
50e1e10f TT |
2111 | sprintf(problem, "is the inode bitmap of group %d", i); |
2112 | break; | |
2113 | } | |
d7cca6b0 VAH |
2114 | if (block >= ext2fs_inode_table_loc(fs, i) && |
2115 | (block < ext2fs_inode_table_loc(fs, i) | |
50e1e10f TT |
2116 | + fs->inode_blocks_per_group)) { |
2117 | sprintf(problem, "is in the inode table of group %d", | |
2118 | i); | |
2119 | break; | |
2120 | } | |
2121 | super += fs->super->s_blocks_per_group; | |
2122 | } | |
2123 | return(problem); | |
2124 | } | |
21c84b71 | 2125 | #endif |
3839e657 TT |
2126 | |
2127 | /* | |
2128 | * This is a helper function for check_blocks(). | |
2129 | */ | |
53ef44c4 | 2130 | static int process_block(ext2_filsys fs, |
6dc64392 | 2131 | blk64_t *block_nr, |
9d1bd3de | 2132 | e2_blkcnt_t blockcnt, |
6dc64392 | 2133 | blk64_t ref_block EXT2FS_ATTR((unused)), |
54434927 | 2134 | int ref_offset EXT2FS_ATTR((unused)), |
54dc7ca2 | 2135 | void *priv_data) |
3839e657 TT |
2136 | { |
2137 | struct process_block_struct *p; | |
21c84b71 | 2138 | struct problem_context *pctx; |
6dc64392 | 2139 | blk64_t blk = *block_nr; |
50e1e10f | 2140 | int ret_code = 0; |
21c84b71 | 2141 | int problem = 0; |
1b6bf175 | 2142 | e2fsck_t ctx; |
3839e657 | 2143 | |
54dc7ca2 | 2144 | p = (struct process_block_struct *) priv_data; |
21c84b71 | 2145 | pctx = p->pctx; |
1b6bf175 | 2146 | ctx = p->ctx; |
3839e657 | 2147 | |
1917875f TT |
2148 | if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) { |
2149 | /* todo: Check that the comprblk_fl is high, that the | |
2150 | blkaddr pattern looks right (all non-holes up to | |
2151 | first EXT2FS_COMPRESSED_BLKADDR, then all | |
2152 | EXT2FS_COMPRESSED_BLKADDR up to end of cluster), | |
2153 | that the feature_incompat bit is high, and that the | |
2154 | inode is a regular file. If we're doing a "full | |
2155 | check" (a concept introduced to e2fsck by e2compr, | |
2156 | meaning that we look at data blocks as well as | |
2157 | metadata) then call some library routine that | |
2158 | checks the compressed data. I'll have to think | |
2159 | about this, because one particularly important | |
2160 | problem to be able to fix is to recalculate the | |
2161 | cluster size if necessary. I think that perhaps | |
2162 | we'd better do most/all e2compr-specific checks | |
2163 | separately, after the non-e2compr checks. If not | |
2164 | doing a full check, it may be useful to test that | |
2165 | the personality is linux; e.g. if it isn't then | |
2166 | perhaps this really is just an illegal block. */ | |
2167 | return 0; | |
2168 | } | |
b94a052a | 2169 | |
4dbe79bc | 2170 | if (blk == 0) |
50e1e10f | 2171 | return 0; |
50e1e10f | 2172 | |
3839e657 | 2173 | #if 0 |
50e1e10f | 2174 | printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk, |
3839e657 | 2175 | blockcnt); |
50e1e10f | 2176 | #endif |
efc6f628 | 2177 | |
74becf3c TT |
2178 | /* |
2179 | * Simplistic fragmentation check. We merely require that the | |
2180 | * file be contiguous. (Which can never be true for really | |
2181 | * big files that are greater than a block group.) | |
2182 | */ | |
63b5e354 TT |
2183 | if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) { |
2184 | if (p->previous_block+1 != blk) { | |
100d4701 TT |
2185 | if (ctx->options & E2F_OPT_FRAGCHECK) { |
2186 | char type = '?'; | |
2187 | ||
2188 | if (p->is_dir) | |
2189 | type = 'd'; | |
2190 | else if (p->is_reg) | |
2191 | type = 'f'; | |
2192 | ||
2193 | printf(_("%6lu(%c): expecting %6lu " | |
2194 | "got phys %6lu (blkcnt %lld)\n"), | |
2195 | (unsigned long) pctx->ino, type, | |
63b5e354 TT |
2196 | (unsigned long) p->previous_block+1, |
2197 | (unsigned long) blk, | |
f4e2c991 | 2198 | blockcnt); |
100d4701 | 2199 | } |
74becf3c | 2200 | p->fragmented = 1; |
63b5e354 | 2201 | } |
74becf3c TT |
2202 | } |
2203 | p->previous_block = blk; | |
503f9e7f | 2204 | |
8421fb67 | 2205 | if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size))) |
da307041 TT |
2206 | problem = PR_1_TOOBIG_DIR; |
2207 | if (p->is_reg && p->num_blocks+1 >= p->max_blocks) | |
2208 | problem = PR_1_TOOBIG_REG; | |
2209 | if (!p->is_dir && !p->is_reg && blockcnt > 0) | |
2210 | problem = PR_1_TOOBIG_SYMLINK; | |
efc6f628 | 2211 | |
50e1e10f | 2212 | if (blk < fs->super->s_first_data_block || |
4efbac6f | 2213 | blk >= ext2fs_blocks_count(fs->super)) |
21c84b71 | 2214 | problem = PR_1_ILLEGAL_BLOCK_NUM; |
21c84b71 TT |
2215 | |
2216 | if (problem) { | |
f3db3566 | 2217 | p->num_illegal_blocks++; |
21c84b71 | 2218 | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
1b6bf175 | 2219 | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
f3db3566 TT |
2220 | p->clear = 1; |
2221 | return BLOCK_ABORT; | |
2222 | } | |
f8188fff | 2223 | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
f3db3566 | 2224 | p->suppress = 1; |
1b6bf175 TT |
2225 | set_latch_flags(PR_LATCH_BLOCK, |
2226 | PRL_SUPPRESS, 0); | |
f3db3566 TT |
2227 | } |
2228 | } | |
21c84b71 TT |
2229 | pctx->blk = blk; |
2230 | pctx->blkcount = blockcnt; | |
1b6bf175 | 2231 | if (fix_problem(ctx, problem, pctx)) { |
50e1e10f TT |
2232 | blk = *block_nr = 0; |
2233 | ret_code = BLOCK_CHANGED; | |
2234 | goto mark_dir; | |
21c84b71 | 2235 | } else |
3839e657 | 2236 | return 0; |
3839e657 TT |
2237 | } |
2238 | ||
d323f8fb | 2239 | if (p->ino == EXT2_RESIZE_INO) { |
efc6f628 | 2240 | /* |
c3ffaf83 TT |
2241 | * The resize inode has already be sanity checked |
2242 | * during pass #0 (the superblock checks). All we | |
2243 | * have to do is mark the double indirect block as | |
2244 | * being in use; all of the other blocks are handled | |
2245 | * by mark_table_blocks()). | |
2246 | */ | |
2247 | if (blockcnt == BLOCK_COUNT_DIND) | |
d323f8fb TT |
2248 | mark_block_used(ctx, blk); |
2249 | } else | |
2250 | mark_block_used(ctx, blk); | |
50e1e10f | 2251 | p->num_blocks++; |
1e3472c5 TT |
2252 | if (blockcnt >= 0) |
2253 | p->last_block = blockcnt; | |
50e1e10f | 2254 | mark_dir: |
1e3472c5 | 2255 | if (p->is_dir && (blockcnt >= 0)) { |
4dbe79bc | 2256 | while (++p->last_db_block < blockcnt) { |
6dc64392 VAH |
2257 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, |
2258 | p->ino, 0, | |
2259 | p->last_db_block); | |
4dbe79bc TT |
2260 | if (pctx->errcode) { |
2261 | pctx->blk = 0; | |
2262 | pctx->num = p->last_db_block; | |
2263 | goto failed_add_dir_block; | |
2264 | } | |
2265 | } | |
6dc64392 VAH |
2266 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino, |
2267 | blk, blockcnt); | |
1b6bf175 TT |
2268 | if (pctx->errcode) { |
2269 | pctx->blk = blk; | |
2270 | pctx->num = blockcnt; | |
4dbe79bc | 2271 | failed_add_dir_block: |
1b6bf175 | 2272 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
08b21301 TT |
2273 | /* Should never get here */ |
2274 | ctx->flags |= E2F_FLAG_ABORT; | |
2275 | return BLOCK_ABORT; | |
3839e657 | 2276 | } |
3839e657 | 2277 | } |
50e1e10f | 2278 | return ret_code; |
3839e657 TT |
2279 | } |
2280 | ||
53ef44c4 | 2281 | static int process_bad_block(ext2_filsys fs, |
6dc64392 | 2282 | blk64_t *block_nr, |
9d1bd3de | 2283 | e2_blkcnt_t blockcnt, |
6dc64392 | 2284 | blk64_t ref_block EXT2FS_ATTR((unused)), |
54434927 | 2285 | int ref_offset EXT2FS_ATTR((unused)), |
54dc7ca2 | 2286 | void *priv_data) |
3839e657 TT |
2287 | { |
2288 | struct process_block_struct *p; | |
6dc64392 VAH |
2289 | blk64_t blk = *block_nr; |
2290 | blk64_t first_block; | |
54434927 | 2291 | dgrp_t i; |
21c84b71 | 2292 | struct problem_context *pctx; |
1b6bf175 | 2293 | e2fsck_t ctx; |
21c84b71 | 2294 | |
1917875f TT |
2295 | /* |
2296 | * Note: This function processes blocks for the bad blocks | |
2297 | * inode, which is never compressed. So we don't use HOLE_BLKADDR(). | |
2298 | */ | |
2299 | ||
3839e657 TT |
2300 | if (!blk) |
2301 | return 0; | |
efc6f628 | 2302 | |
54dc7ca2 | 2303 | p = (struct process_block_struct *) priv_data; |
1b6bf175 | 2304 | ctx = p->ctx; |
21c84b71 | 2305 | pctx = p->pctx; |
efc6f628 | 2306 | |
f8188fff | 2307 | pctx->ino = EXT2_BAD_INO; |
21c84b71 TT |
2308 | pctx->blk = blk; |
2309 | pctx->blkcount = blockcnt; | |
3839e657 TT |
2310 | |
2311 | if ((blk < fs->super->s_first_data_block) || | |
4efbac6f | 2312 | (blk >= ext2fs_blocks_count(fs->super))) { |
1b6bf175 | 2313 | if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { |
3839e657 TT |
2314 | *block_nr = 0; |
2315 | return BLOCK_CHANGED; | |
21c84b71 | 2316 | } else |
3839e657 | 2317 | return 0; |
3839e657 TT |
2318 | } |
2319 | ||
2320 | if (blockcnt < 0) { | |
c5d2f50d | 2321 | if (ext2fs_test_block_bitmap2(p->fs_meta_blocks, blk)) { |
000ba404 TT |
2322 | p->bbcheck = 1; |
2323 | if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) { | |
2324 | *block_nr = 0; | |
2325 | return BLOCK_CHANGED; | |
2326 | } | |
c5d2f50d | 2327 | } else if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
000ba404 TT |
2328 | blk)) { |
2329 | p->bbcheck = 1; | |
efc6f628 | 2330 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, |
000ba404 TT |
2331 | pctx)) { |
2332 | *block_nr = 0; | |
2333 | return BLOCK_CHANGED; | |
2334 | } | |
a02ce9df | 2335 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
2336 | return BLOCK_ABORT; |
2337 | } else | |
1b6bf175 | 2338 | mark_block_used(ctx, blk); |
3839e657 TT |
2339 | return 0; |
2340 | } | |
efc6f628 | 2341 | #if 0 |
50e1e10f | 2342 | printf ("DEBUG: Marking %u as bad.\n", blk); |
3839e657 | 2343 | #endif |
1b6bf175 | 2344 | ctx->fs_badblocks_count++; |
3839e657 TT |
2345 | /* |
2346 | * If the block is not used, then mark it as used and return. | |
2347 | * If it is already marked as found, this must mean that | |
2348 | * there's an overlap between the filesystem table blocks | |
2349 | * (bitmaps and inode table) and the bad block list. | |
2350 | */ | |
c5d2f50d VAH |
2351 | if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) { |
2352 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); | |
3839e657 TT |
2353 | return 0; |
2354 | } | |
f3db3566 TT |
2355 | /* |
2356 | * Try to find the where the filesystem block was used... | |
2357 | */ | |
2358 | first_block = fs->super->s_first_data_block; | |
efc6f628 | 2359 | |
f3db3566 | 2360 | for (i = 0; i < fs->group_desc_count; i++ ) { |
21c84b71 | 2361 | pctx->group = i; |
1b6bf175 | 2362 | pctx->blk = blk; |
8039c480 TT |
2363 | if (!ext2fs_bg_has_super(fs, i)) |
2364 | goto skip_super; | |
f3db3566 TT |
2365 | if (blk == first_block) { |
2366 | if (i == 0) { | |
1b6bf175 TT |
2367 | if (fix_problem(ctx, |
2368 | PR_1_BAD_PRIMARY_SUPERBLOCK, | |
2369 | pctx)) { | |
2370 | *block_nr = 0; | |
50e1e10f | 2371 | return BLOCK_CHANGED; |
1b6bf175 | 2372 | } |
50e1e10f | 2373 | return 0; |
f3db3566 | 2374 | } |
1b6bf175 | 2375 | fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); |
f3db3566 TT |
2376 | return 0; |
2377 | } | |
2378 | if ((blk > first_block) && | |
2379 | (blk <= first_block + fs->desc_blocks)) { | |
2380 | if (i == 0) { | |
1b6bf175 TT |
2381 | pctx->blk = *block_nr; |
2382 | if (fix_problem(ctx, | |
2383 | PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { | |
2384 | *block_nr = 0; | |
50e1e10f | 2385 | return BLOCK_CHANGED; |
1b6bf175 | 2386 | } |
50e1e10f | 2387 | return 0; |
f3db3566 | 2388 | } |
1b6bf175 | 2389 | fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); |
f3db3566 | 2390 | return 0; |
3839e657 | 2391 | } |
8039c480 | 2392 | skip_super: |
d7cca6b0 | 2393 | if (blk == ext2fs_block_bitmap_loc(fs, i)) { |
1b6bf175 TT |
2394 | if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { |
2395 | ctx->invalid_block_bitmap_flag[i]++; | |
2396 | ctx->invalid_bitmaps++; | |
21c84b71 | 2397 | } |
f3db3566 TT |
2398 | return 0; |
2399 | } | |
d7cca6b0 | 2400 | if (blk == ext2fs_inode_bitmap_loc(fs, i)) { |
1b6bf175 TT |
2401 | if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { |
2402 | ctx->invalid_inode_bitmap_flag[i]++; | |
2403 | ctx->invalid_bitmaps++; | |
21c84b71 | 2404 | } |
f3db3566 TT |
2405 | return 0; |
2406 | } | |
d7cca6b0 VAH |
2407 | if ((blk >= ext2fs_inode_table_loc(fs, i)) && |
2408 | (blk < (ext2fs_inode_table_loc(fs, i) + | |
f3db3566 | 2409 | fs->inode_blocks_per_group))) { |
21c84b71 TT |
2410 | /* |
2411 | * If there are bad blocks in the inode table, | |
2412 | * the inode scan code will try to do | |
2413 | * something reasonable automatically. | |
2414 | */ | |
f3db3566 TT |
2415 | return 0; |
2416 | } | |
8039c480 | 2417 | first_block += fs->super->s_blocks_per_group; |
f3db3566 TT |
2418 | } |
2419 | /* | |
2420 | * If we've gotten to this point, then the only | |
2421 | * possibility is that the bad block inode meta data | |
2422 | * is using a bad block. | |
2423 | */ | |
2424 | if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) || | |
000ba404 TT |
2425 | (blk == p->inode->i_block[EXT2_DIND_BLOCK]) || |
2426 | (blk == p->inode->i_block[EXT2_TIND_BLOCK])) { | |
2427 | p->bbcheck = 1; | |
2428 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) { | |
2429 | *block_nr = 0; | |
2430 | return BLOCK_CHANGED; | |
2431 | } | |
a02ce9df | 2432 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 2433 | return BLOCK_ABORT; |
f3db3566 | 2434 | return 0; |
3839e657 | 2435 | } |
1b6bf175 TT |
2436 | |
2437 | pctx->group = -1; | |
2438 | ||
2439 | /* Warn user that the block wasn't claimed */ | |
2440 | fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx); | |
2441 | ||
f3db3566 | 2442 | return 0; |
3839e657 TT |
2443 | } |
2444 | ||
efc6f628 | 2445 | static void new_table_block(e2fsck_t ctx, blk_t first_block, int group, |
c5d2f50d | 2446 | const char *name, int num, blk64_t *new_block) |
3839e657 | 2447 | { |
1b6bf175 | 2448 | ext2_filsys fs = ctx->fs; |
617446e4 | 2449 | dgrp_t last_grp; |
c5d2f50d VAH |
2450 | blk64_t old_block = *new_block; |
2451 | blk64_t last_block; | |
617446e4 | 2452 | int i, is_flexbg, flexbg, flexbg_size; |
3839e657 | 2453 | char *buf; |
1b6bf175 TT |
2454 | struct problem_context pctx; |
2455 | ||
2456 | clear_problem_context(&pctx); | |
2457 | ||
2458 | pctx.group = group; | |
2459 | pctx.blk = old_block; | |
2460 | pctx.str = name; | |
2461 | ||
617446e4 TT |
2462 | /* |
2463 | * For flex_bg filesystems, first try to allocate the metadata | |
2464 | * within the flex_bg, and if that fails then try finding the | |
2465 | * space anywhere in the filesystem. | |
2466 | */ | |
2467 | is_flexbg = EXT2_HAS_INCOMPAT_FEATURE(fs->super, | |
2468 | EXT4_FEATURE_INCOMPAT_FLEX_BG); | |
2469 | if (is_flexbg) { | |
2470 | flexbg_size = 1 << fs->super->s_log_groups_per_flex; | |
2471 | flexbg = group / flexbg_size; | |
b49f78fe TT |
2472 | first_block = ext2fs_group_first_block2(fs, |
2473 | flexbg_size * flexbg); | |
617446e4 TT |
2474 | last_grp = group | (flexbg_size - 1); |
2475 | if (last_grp > fs->group_desc_count) | |
2476 | last_grp = fs->group_desc_count; | |
b49f78fe | 2477 | last_block = ext2fs_group_last_block2(fs, last_grp); |
617446e4 | 2478 | } else |
b49f78fe | 2479 | last_block = ext2fs_group_last_block2(fs, group); |
c5d2f50d VAH |
2480 | pctx.errcode = ext2fs_get_free_blocks2(fs, first_block, last_block, |
2481 | num, ctx->block_found_map, | |
2482 | new_block); | |
617446e4 | 2483 | if (is_flexbg && (pctx.errcode == EXT2_ET_BLOCK_ALLOC_FAIL)) |
c5d2f50d | 2484 | pctx.errcode = ext2fs_get_free_blocks2(fs, |
617446e4 | 2485 | fs->super->s_first_data_block, |
4efbac6f | 2486 | ext2fs_blocks_count(fs->super), |
617446e4 | 2487 | num, ctx->block_found_map, new_block); |
1b6bf175 TT |
2488 | if (pctx.errcode) { |
2489 | pctx.num = num; | |
2490 | fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); | |
3839e657 | 2491 | ext2fs_unmark_valid(fs); |
617446e4 | 2492 | ctx->flags |= E2F_FLAG_ABORT; |
3839e657 TT |
2493 | return; |
2494 | } | |
c4e3d3f3 | 2495 | pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf); |
08b21301 | 2496 | if (pctx.errcode) { |
1b6bf175 | 2497 | fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); |
3839e657 | 2498 | ext2fs_unmark_valid(fs); |
617446e4 | 2499 | ctx->flags |= E2F_FLAG_ABORT; |
3839e657 TT |
2500 | return; |
2501 | } | |
2502 | ext2fs_mark_super_dirty(fs); | |
299d7424 | 2503 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
1b6bf175 TT |
2504 | pctx.blk2 = *new_block; |
2505 | fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO : | |
2506 | PR_1_RELOC_TO), &pctx); | |
2507 | pctx.blk2 = 0; | |
3839e657 | 2508 | for (i = 0; i < num; i++) { |
1b6bf175 | 2509 | pctx.blk = i; |
c5d2f50d | 2510 | ext2fs_mark_block_bitmap2(ctx->block_found_map, (*new_block)+i); |
f3db3566 | 2511 | if (old_block) { |
24a117ab | 2512 | pctx.errcode = io_channel_read_blk64(fs->io, |
1b6bf175 TT |
2513 | old_block + i, 1, buf); |
2514 | if (pctx.errcode) | |
2515 | fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); | |
f3db3566 TT |
2516 | } else |
2517 | memset(buf, 0, fs->blocksize); | |
2518 | ||
1b6bf175 | 2519 | pctx.blk = (*new_block) + i; |
24a117ab | 2520 | pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, |
3839e657 | 2521 | 1, buf); |
1b6bf175 TT |
2522 | if (pctx.errcode) |
2523 | fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); | |
3839e657 | 2524 | } |
c4e3d3f3 | 2525 | ext2fs_free_mem(&buf); |
3839e657 TT |
2526 | } |
2527 | ||
2528 | /* | |
f3db3566 TT |
2529 | * This routine gets called at the end of pass 1 if bad blocks are |
2530 | * detected in the superblock, group descriptors, inode_bitmaps, or | |
2531 | * block bitmaps. At this point, all of the blocks have been mapped | |
2532 | * out, so we can try to allocate new block(s) to replace the bad | |
2533 | * blocks. | |
3839e657 | 2534 | */ |
1b6bf175 | 2535 | static void handle_fs_bad_blocks(e2fsck_t ctx) |
3839e657 | 2536 | { |
1b6bf175 | 2537 | ext2_filsys fs = ctx->fs; |
54434927 | 2538 | dgrp_t i; |
c5d2f50d VAH |
2539 | blk64_t first_block; |
2540 | blk64_t new_blk; | |
3839e657 TT |
2541 | |
2542 | for (i = 0; i < fs->group_desc_count; i++) { | |
b49f78fe | 2543 | first_block = ext2fs_group_first_block2(fs, i); |
abf23439 | 2544 | |
1b6bf175 | 2545 | if (ctx->invalid_block_bitmap_flag[i]) { |
c5d2f50d | 2546 | new_blk = ext2fs_block_bitmap_loc(fs, i); |
0c4a0726 | 2547 | new_table_block(ctx, first_block, i, _("block bitmap"), |
c5d2f50d VAH |
2548 | 1, &new_blk); |
2549 | ext2fs_block_bitmap_loc_set(fs, i, new_blk); | |
3839e657 | 2550 | } |
1b6bf175 | 2551 | if (ctx->invalid_inode_bitmap_flag[i]) { |
c5d2f50d | 2552 | new_blk = ext2fs_inode_bitmap_loc(fs, i); |
0c4a0726 | 2553 | new_table_block(ctx, first_block, i, _("inode bitmap"), |
c5d2f50d VAH |
2554 | 1, &new_blk); |
2555 | ext2fs_inode_bitmap_loc_set(fs, i, new_blk); | |
3839e657 | 2556 | } |
1b6bf175 | 2557 | if (ctx->invalid_inode_table_flag[i]) { |
c5d2f50d | 2558 | new_blk = ext2fs_inode_table_loc(fs, i); |
0c4a0726 | 2559 | new_table_block(ctx, first_block, i, _("inode table"), |
efc6f628 | 2560 | fs->inode_blocks_per_group, |
c5d2f50d VAH |
2561 | &new_blk); |
2562 | ext2fs_inode_table_loc_set(fs, i, new_blk); | |
08b21301 | 2563 | ctx->flags |= E2F_FLAG_RESTART; |
3839e657 | 2564 | } |
3839e657 | 2565 | } |
1b6bf175 | 2566 | ctx->invalid_bitmaps = 0; |
3839e657 TT |
2567 | } |
2568 | ||
2569 | /* | |
2570 | * This routine marks all blocks which are used by the superblock, | |
2571 | * group descriptors, inode bitmaps, and block bitmaps. | |
2572 | */ | |
1b6bf175 | 2573 | static void mark_table_blocks(e2fsck_t ctx) |
3839e657 | 2574 | { |
1b6bf175 | 2575 | ext2_filsys fs = ctx->fs; |
6dc64392 | 2576 | blk64_t b; |
54434927 TT |
2577 | dgrp_t i; |
2578 | int j; | |
21c84b71 | 2579 | struct problem_context pctx; |
efc6f628 | 2580 | |
21c84b71 | 2581 | clear_problem_context(&pctx); |
efc6f628 | 2582 | |
3839e657 | 2583 | for (i = 0; i < fs->group_desc_count; i++) { |
21c84b71 | 2584 | pctx.group = i; |
da2e97f7 | 2585 | |
ef344e13 TT |
2586 | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map); |
2587 | ||
21c84b71 TT |
2588 | /* |
2589 | * Mark the blocks used for the inode table | |
2590 | */ | |
d7cca6b0 VAH |
2591 | if (ext2fs_inode_table_loc(fs, i)) { |
2592 | for (j = 0, b = ext2fs_inode_table_loc(fs, i); | |
21c84b71 TT |
2593 | j < fs->inode_blocks_per_group; |
2594 | j++, b++) { | |
c5d2f50d | 2595 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
21c84b71 TT |
2596 | b)) { |
2597 | pctx.blk = b; | |
9a7fe4bd TT |
2598 | if (!ctx->invalid_inode_table_flag[i] && |
2599 | fix_problem(ctx, | |
21c84b71 | 2600 | PR_1_ITABLE_CONFLICT, &pctx)) { |
1b6bf175 TT |
2601 | ctx->invalid_inode_table_flag[i]++; |
2602 | ctx->invalid_bitmaps++; | |
21c84b71 TT |
2603 | } |
2604 | } else { | |
c5d2f50d | 2605 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
21c84b71 | 2606 | b); |
21c84b71 TT |
2607 | } |
2608 | } | |
2609 | } | |
efc6f628 | 2610 | |
3839e657 | 2611 | /* |
efc6f628 | 2612 | * Mark block used for the block bitmap |
3839e657 | 2613 | */ |
d7cca6b0 | 2614 | if (ext2fs_block_bitmap_loc(fs, i)) { |
c5d2f50d | 2615 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
d7cca6b0 VAH |
2616 | ext2fs_block_bitmap_loc(fs, i))) { |
2617 | pctx.blk = ext2fs_block_bitmap_loc(fs, i); | |
1b6bf175 TT |
2618 | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
2619 | ctx->invalid_block_bitmap_flag[i]++; | |
2620 | ctx->invalid_bitmaps++; | |
f3db3566 | 2621 | } |
50e1e10f | 2622 | } else { |
c5d2f50d | 2623 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
d7cca6b0 | 2624 | ext2fs_block_bitmap_loc(fs, i)); |
50e1e10f | 2625 | } |
efc6f628 | 2626 | |
f3db3566 | 2627 | } |
3839e657 | 2628 | /* |
efc6f628 | 2629 | * Mark block used for the inode bitmap |
3839e657 | 2630 | */ |
d7cca6b0 | 2631 | if (ext2fs_inode_bitmap_loc(fs, i)) { |
c5d2f50d | 2632 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
d7cca6b0 VAH |
2633 | ext2fs_inode_bitmap_loc(fs, i))) { |
2634 | pctx.blk = ext2fs_inode_bitmap_loc(fs, i); | |
1b6bf175 TT |
2635 | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
2636 | ctx->invalid_inode_bitmap_flag[i]++; | |
2637 | ctx->invalid_bitmaps++; | |
efc6f628 | 2638 | } |
50e1e10f | 2639 | } else { |
c5d2f50d | 2640 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
d7cca6b0 | 2641 | ext2fs_inode_bitmap_loc(fs, i)); |
50e1e10f | 2642 | } |
f3db3566 | 2643 | } |
3839e657 TT |
2644 | } |
2645 | } | |
efc6f628 | 2646 | |
3839e657 | 2647 | /* |
e72a9ba3 | 2648 | * Thes subroutines short circuits ext2fs_get_blocks and |
3839e657 TT |
2649 | * ext2fs_check_directory; we use them since we already have the inode |
2650 | * structure, so there's no point in letting the ext2fs library read | |
2651 | * the inode again. | |
2652 | */ | |
86c627ec TT |
2653 | static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino, |
2654 | blk_t *blocks) | |
3839e657 | 2655 | { |
54dc7ca2 | 2656 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
3839e657 | 2657 | int i; |
efc6f628 | 2658 | |
71d521c6 | 2659 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
521e3685 TT |
2660 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2661 | ||
2662 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
1b6bf175 | 2663 | blocks[i] = ctx->stashed_inode->i_block[i]; |
521e3685 | 2664 | return 0; |
3839e657 TT |
2665 | } |
2666 | ||
86c627ec | 2667 | static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino, |
e72a9ba3 | 2668 | struct ext2_inode *inode) |
1e3472c5 | 2669 | { |
54dc7ca2 | 2670 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2671 | |
71d521c6 | 2672 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1e3472c5 | 2673 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1b6bf175 | 2674 | *inode = *ctx->stashed_inode; |
1e3472c5 TT |
2675 | return 0; |
2676 | } | |
2677 | ||
86c627ec | 2678 | static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino, |
1e3472c5 TT |
2679 | struct ext2_inode *inode) |
2680 | { | |
54dc7ca2 | 2681 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2682 | |
27431595 TT |
2683 | if ((ino == ctx->stashed_ino) && ctx->stashed_inode && |
2684 | (inode != ctx->stashed_inode)) | |
1b6bf175 | 2685 | *ctx->stashed_inode = *inode; |
1e3472c5 TT |
2686 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2687 | } | |
2688 | ||
86c627ec | 2689 | static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino) |
3839e657 | 2690 | { |
54dc7ca2 | 2691 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2692 | |
71d521c6 | 2693 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1b6bf175 TT |
2694 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2695 | ||
2696 | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) | |
291c9049 | 2697 | return EXT2_ET_NO_DIRECTORY; |
1b6bf175 | 2698 | return 0; |
3839e657 | 2699 | } |
e72a9ba3 | 2700 | |
16bd349e TT |
2701 | static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal, |
2702 | blk64_t *ret) | |
2703 | { | |
2704 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
2705 | errcode_t retval; | |
c5d2f50d | 2706 | blk64_t new_block; |
16bd349e TT |
2707 | |
2708 | if (ctx->block_found_map) { | |
28843200 TT |
2709 | retval = ext2fs_new_block2(fs, goal, ctx->block_found_map, |
2710 | &new_block); | |
16bd349e TT |
2711 | if (retval) |
2712 | return retval; | |
8a2cbe2c | 2713 | if (fs->block_map) { |
2d07b3ad | 2714 | ext2fs_mark_block_bitmap2(fs->block_map, new_block); |
8a2cbe2c TT |
2715 | ext2fs_mark_bb_dirty(fs); |
2716 | } | |
16bd349e TT |
2717 | } else { |
2718 | if (!fs->block_map) { | |
2719 | retval = ext2fs_read_block_bitmap(fs); | |
2720 | if (retval) | |
2721 | return retval; | |
2722 | } | |
2723 | ||
28843200 | 2724 | retval = ext2fs_new_block2(fs, goal, 0, &new_block); |
16bd349e TT |
2725 | if (retval) |
2726 | return retval; | |
2727 | } | |
efc6f628 | 2728 | |
16bd349e TT |
2729 | *ret = new_block; |
2730 | return (0); | |
2731 | } | |
2732 | ||
2733 | static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse) | |
2734 | { | |
2735 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
2736 | ||
2737 | if (ctx->block_found_map) { | |
2738 | if (inuse > 0) | |
28843200 | 2739 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); |
16bd349e | 2740 | else |
28843200 | 2741 | ext2fs_unmark_block_bitmap2(ctx->block_found_map, blk); |
16bd349e TT |
2742 | } |
2743 | } | |
2744 | ||
e72a9ba3 TT |
2745 | void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool) |
2746 | { | |
2747 | ext2_filsys fs = ctx->fs; | |
2748 | ||
2749 | if (bool) { | |
2750 | fs->get_blocks = pass1_get_blocks; | |
2751 | fs->check_directory = pass1_check_directory; | |
2752 | fs->read_inode = pass1_read_inode; | |
2753 | fs->write_inode = pass1_write_inode; | |
2754 | ctx->stashed_ino = 0; | |
16bd349e TT |
2755 | ext2fs_set_alloc_block_callback(fs, e2fsck_get_alloc_block, |
2756 | 0); | |
2757 | ext2fs_set_block_alloc_stats_callback(fs, | |
2758 | e2fsck_block_alloc_stats, | |
2759 | 0); | |
e72a9ba3 TT |
2760 | } else { |
2761 | fs->get_blocks = 0; | |
2762 | fs->check_directory = 0; | |
2763 | fs->read_inode = 0; | |
2764 | fs->write_inode = 0; | |
2765 | } | |
2766 | } |