]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/pass2.c
e2fsck: add resource tracking for passes 1[b-d]
[thirdparty/e2fsprogs.git] / e2fsck / pass2.c
CommitLineData
3839e657
TT
1/*
2 * pass2.c --- check directory structure
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 2 of e2fsck iterates through all active directory inodes, and
12 * applies to following tests to each directory entry in the directory
13 * blocks in the inodes:
14 *
15 * - The length of the directory entry (rec_len) should be at
16 * least 8 bytes, and no more than the remaining space
17 * left in the directory block.
18 * - The length of the name in the directory entry (name_len)
efc6f628 19 * should be less than (rec_len - 8).
3839e657
TT
20 * - The inode number in the directory entry should be within
21 * legal bounds.
22 * - The inode number should refer to a in-use inode.
23 * - The first entry should be '.', and its inode should be
24 * the inode of the directory.
25 * - The second entry should be '..'.
26 *
27 * To minimize disk seek time, the directory blocks are processed in
28 * sorted order of block numbers.
29 *
30 * Pass 2 also collects the following information:
31 * - The inode numbers of the subdirectories for each directory.
32 *
33 * Pass 2 relies on the following information from previous passes:
34 * - The directory information collected in pass 1.
35 * - The inode_used_map bitmap
36 * - The inode_bad_map bitmap
37 * - The inode_dir_map bitmap
3839e657
TT
38 *
39 * Pass 2 frees the following data structures
40 * - The inode_bad_map bitmap
aa4115a4 41 * - The inode_reg_map bitmap
3839e657
TT
42 */
43
b969b1b8 44#define _GNU_SOURCE 1 /* get strnlen() */
48e6e813
TT
45#include <string.h>
46
3839e657 47#include "e2fsck.h"
21c84b71 48#include "problem.h"
0926668d 49#include "dict.h"
3839e657 50
aa4115a4
TT
51#ifdef NO_INLINE_FUNCS
52#define _INLINE_
53#else
54#define _INLINE_ inline
55#endif
56
ad4fa466 57/* #define DX_DEBUG */
8fdc9985 58
3839e657
TT
59/*
60 * Keeps track of how many times an inode is referenced.
61 */
4035f40b 62static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
3839e657 63static int check_dir_block(ext2_filsys fs,
21c84b71 64 struct ext2_db_entry *dir_blocks_info,
54dc7ca2 65 void *priv_data);
1b6bf175 66static int allocate_dir_block(e2fsck_t ctx,
21c84b71
TT
67 struct ext2_db_entry *dir_blocks_info,
68 char *buf, struct problem_context *pctx);
50e1e10f
TT
69static int update_dir_block(ext2_filsys fs,
70 blk_t *block_nr,
133a56dc 71 e2_blkcnt_t blockcnt,
4035f40b 72 blk_t ref_block,
efc6f628 73 int ref_offset,
4035f40b 74 void *priv_data);
8fdc9985 75static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
ad4fa466
TT
76static int htree_depth(struct dx_dir_info *dx_dir,
77 struct dx_dirblock_info *dx_db);
ea1959f0 78static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
3839e657 79
21c84b71
TT
80struct check_dir_struct {
81 char *buf;
82 struct problem_context pctx;
f8188fff 83 int count, max;
1b6bf175 84 e2fsck_t ctx;
efc6f628 85};
21c84b71 86
08b21301 87void e2fsck_pass2(e2fsck_t ctx)
3839e657 88{
a4742691
TT
89 struct ext2_super_block *sb = ctx->fs->super;
90 struct problem_context pctx;
91 ext2_filsys fs = ctx->fs;
92 char *buf;
8bf191e8 93#ifdef RESOURCE_TRACK
3839e657 94 struct resource_track rtrack;
8bf191e8 95#endif
21c84b71 96 struct check_dir_struct cd;
8fdc9985
TT
97 struct dx_dir_info *dx_dir;
98 struct dx_dirblock_info *dx_db, *dx_parent;
54434927 99 int b;
ad4fa466 100 int i, depth;
8fdc9985
TT
101 problem_t code;
102 int bad_dir;
103
8bf191e8 104#ifdef RESOURCE_TRACK
6d96b00d 105 init_resource_track(&rtrack, ctx->fs->io);
8bf191e8 106#endif
3839e657 107
1b6bf175
TT
108 clear_problem_context(&cd.pctx);
109
3839e657
TT
110#ifdef MTRACE
111 mtrace_print("Pass 2");
112#endif
113
1b6bf175
TT
114 if (!(ctx->options & E2F_OPT_PREEN))
115 fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
116
efc6f628 117 e2fsck_setup_tdb_icount(ctx, EXT2_ICOUNT_OPT_INCREMENT,
34b9f796
TT
118 &ctx->inode_count);
119 if (ctx->inode_count)
120 cd.pctx.errcode = 0;
efc6f628
TT
121 else
122 cd.pctx.errcode = ext2fs_create_icount2(fs,
34b9f796 123 EXT2_ICOUNT_OPT_INCREMENT,
1b6bf175
TT
124 0, ctx->inode_link_info,
125 &ctx->inode_count);
126 if (cd.pctx.errcode) {
127 fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx);
08b21301
TT
128 ctx->flags |= E2F_FLAG_ABORT;
129 return;
21c84b71 130 }
bcf9c5d4 131 buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize,
54dc7ca2 132 "directory scan buffer");
3839e657 133
21c84b71
TT
134 /*
135 * Set up the parent pointer for the root directory, if
136 * present. (If the root directory is not present, we will
137 * create it in pass 3.)
138 */
28db82a8 139 (void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
21c84b71
TT
140
141 cd.buf = buf;
1b6bf175 142 cd.ctx = ctx;
f75c28de 143 cd.count = 1;
f8188fff 144 cd.max = ext2fs_dblist_count(fs->dblist);
f75c28de
TT
145
146 if (ctx->progress)
147 (void) (ctx->progress)(ctx, 2, 0, cd.max);
ea1959f0
TT
148
149 if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
150 ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
efc6f628 151
1b6bf175
TT
152 cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
153 &cd);
49a7360b 154 if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
08b21301 155 return;
6267ee49
AD
156
157 if (ctx->flags & E2F_FLAG_RESTART_LATER) {
158 ctx->flags |= E2F_FLAG_RESTART;
159 return;
160 }
161
1b6bf175
TT
162 if (cd.pctx.errcode) {
163 fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
08b21301
TT
164 ctx->flags |= E2F_FLAG_ABORT;
165 return;
7ac02a5e 166 }
8fdc9985
TT
167
168#ifdef ENABLE_HTREE
169 for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
4cae0452
TT
170 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
171 return;
62acaa1d 172 if (dx_dir->numblocks == 0)
8fdc9985
TT
173 continue;
174 clear_problem_context(&pctx);
175 bad_dir = 0;
176 pctx.dir = dx_dir->ino;
177 dx_db = dx_dir->dx_block;
178 if (dx_db->flags & DX_FLAG_REFERENCED)
179 dx_db->flags |= DX_FLAG_DUP_REF;
180 else
181 dx_db->flags |= DX_FLAG_REFERENCED;
182 /*
183 * Find all of the first and last leaf blocks, and
184 * update their parent's min and max hash values
185 */
186 for (b=0, dx_db = dx_dir->dx_block;
187 b < dx_dir->numblocks;
188 b++, dx_db++) {
189 if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
190 !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
191 continue;
192 dx_parent = &dx_dir->dx_block[dx_db->parent];
193 /*
194 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
195 */
196 if (dx_db->flags & DX_FLAG_FIRST)
197 dx_parent->min_hash = dx_db->min_hash;
198 /*
199 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
200 */
201 if (dx_db->flags & DX_FLAG_LAST)
202 dx_parent->max_hash = dx_db->max_hash;
203 }
efc6f628 204
8fdc9985
TT
205 for (b=0, dx_db = dx_dir->dx_block;
206 b < dx_dir->numblocks;
207 b++, dx_db++) {
208 pctx.blkcount = b;
209 pctx.group = dx_db->parent;
210 code = 0;
211 if (!(dx_db->flags & DX_FLAG_FIRST) &&
212 (dx_db->min_hash < dx_db->node_min_hash)) {
213 pctx.blk = dx_db->min_hash;
214 pctx.blk2 = dx_db->node_min_hash;
215 code = PR_2_HTREE_MIN_HASH;
216 fix_problem(ctx, code, &pctx);
217 bad_dir++;
218 }
ad4fa466
TT
219 if (dx_db->type == DX_DIRBLOCK_LEAF) {
220 depth = htree_depth(dx_dir, dx_db);
221 if (depth != dx_dir->depth) {
e5e12db9 222 pctx.num = dx_dir->depth;
ad4fa466
TT
223 code = PR_2_HTREE_BAD_DEPTH;
224 fix_problem(ctx, code, &pctx);
225 bad_dir++;
226 }
227 }
8fdc9985 228 /*
efc6f628 229 * This test doesn't apply for the root block
8fdc9985
TT
230 * at block #0
231 */
232 if (b &&
233 (dx_db->max_hash > dx_db->node_max_hash)) {
234 pctx.blk = dx_db->max_hash;
235 pctx.blk2 = dx_db->node_max_hash;
236 code = PR_2_HTREE_MAX_HASH;
237 fix_problem(ctx, code, &pctx);
503f9e7f 238 bad_dir++;
8fdc9985
TT
239 }
240 if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
241 code = PR_2_HTREE_NOTREF;
242 fix_problem(ctx, code, &pctx);
243 bad_dir++;
244 } else if (dx_db->flags & DX_FLAG_DUP_REF) {
245 code = PR_2_HTREE_DUPREF;
246 fix_problem(ctx, code, &pctx);
247 bad_dir++;
248 }
249 if (code == 0)
250 continue;
251 }
252 if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
253 clear_htree(ctx, dx_dir->ino);
62acaa1d 254 dx_dir->numblocks = 0;
8fdc9985 255 }
8fdc9985
TT
256 }
257#endif
c4e3d3f3 258 ext2fs_free_mem(&buf);
21c84b71
TT
259 ext2fs_free_dblist(fs->dblist);
260
1b6bf175
TT
261 if (ctx->inode_bad_map) {
262 ext2fs_free_inode_bitmap(ctx->inode_bad_map);
263 ctx->inode_bad_map = 0;
3839e657 264 }
aa4115a4
TT
265 if (ctx->inode_reg_map) {
266 ext2fs_free_inode_bitmap(ctx->inode_reg_map);
267 ctx->inode_reg_map = 0;
268 }
a4742691
TT
269
270 clear_problem_context(&pctx);
271 if (ctx->large_files) {
272 if (!(sb->s_feature_ro_compat &
273 EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
274 fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
275 sb->s_feature_ro_compat |=
276 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
0cfce7f7 277 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
a4742691
TT
278 ext2fs_mark_super_dirty(fs);
279 }
280 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
281 fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
282 ext2fs_update_dynamic_rev(fs);
283 ext2fs_mark_super_dirty(fs);
284 }
a4742691 285 }
efc6f628 286
8bf191e8 287#ifdef RESOURCE_TRACK
5596defa
TT
288 if (ctx->options & E2F_OPT_TIME2) {
289 e2fsck_clear_progbar(ctx);
6d96b00d 290 print_resource_track(_("Pass 2"), &rtrack, fs->io);
5596defa 291 }
8bf191e8 292#endif
3839e657
TT
293}
294
ad4fa466
TT
295#define MAX_DEPTH 32000
296static int htree_depth(struct dx_dir_info *dx_dir,
297 struct dx_dirblock_info *dx_db)
298{
299 int depth = 0;
300
301 while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) {
302 dx_db = &dx_dir->dx_block[dx_db->parent];
303 depth++;
304 }
305 return depth;
306}
307
0926668d
TT
308static int dict_de_cmp(const void *a, const void *b)
309{
520ead37 310 const struct ext2_dir_entry *de_a, *de_b;
0926668d
TT
311 int a_len, b_len;
312
520ead37 313 de_a = (const struct ext2_dir_entry *) a;
0926668d 314 a_len = de_a->name_len & 0xFF;
520ead37 315 de_b = (const struct ext2_dir_entry *) b;
0926668d
TT
316 b_len = de_b->name_len & 0xFF;
317
318 if (a_len != b_len)
319 return (a_len - b_len);
320
321 return strncmp(de_a->name, de_b->name, a_len);
322}
ad4fa466 323
ea1959f0
TT
324/*
325 * This is special sort function that makes sure that directory blocks
326 * with a dirblock of zero are sorted to the beginning of the list.
327 * This guarantees that the root node of the htree directories are
328 * processed first, so we know what hash version to use.
329 */
330static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
331{
332 const struct ext2_db_entry *db_a =
333 (const struct ext2_db_entry *) a;
334 const struct ext2_db_entry *db_b =
335 (const struct ext2_db_entry *) b;
336
337 if (db_a->blockcnt && !db_b->blockcnt)
338 return 1;
339
340 if (!db_a->blockcnt && db_b->blockcnt)
341 return -1;
efc6f628 342
ea1959f0
TT
343 if (db_a->blk != db_b->blk)
344 return (int) (db_a->blk - db_b->blk);
efc6f628 345
ea1959f0
TT
346 if (db_a->ino != db_b->ino)
347 return (int) (db_a->ino - db_b->ino);
348
349 return (int) (db_a->blockcnt - db_b->blockcnt);
350}
351
352
3839e657
TT
353/*
354 * Make sure the first entry in the directory is '.', and that the
355 * directory entry is sane.
356 */
1b6bf175 357static int check_dot(e2fsck_t ctx,
3839e657 358 struct ext2_dir_entry *dirent,
86c627ec 359 ext2_ino_t ino, struct problem_context *pctx)
3839e657
TT
360{
361 struct ext2_dir_entry *nextdir;
362 int status = 0;
363 int created = 0;
5dd77dbe 364 int rec_len, new_len;
21c84b71 365 int problem = 0;
efc6f628 366
21c84b71
TT
367 if (!dirent->inode)
368 problem = PR_2_MISSING_DOT;
b6f79831 369 else if (((dirent->name_len & 0xFF) != 1) ||
21c84b71
TT
370 (dirent->name[0] != '.'))
371 problem = PR_2_1ST_NOT_DOT;
372 else if (dirent->name[1] != '\0')
373 problem = PR_2_DOT_NULL_TERM;
5dd77dbe
TT
374
375 rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
376 dirent->rec_len : 65536;
21c84b71 377 if (problem) {
1b6bf175 378 if (fix_problem(ctx, problem, pctx)) {
5dd77dbe
TT
379 if (rec_len < 12)
380 rec_len = dirent->rec_len = 12;
3839e657
TT
381 dirent->inode = ino;
382 dirent->name_len = 1;
383 dirent->name[0] = '.';
21c84b71 384 dirent->name[1] = '\0';
3839e657
TT
385 status = 1;
386 created = 1;
3839e657
TT
387 }
388 }
3839e657 389 if (dirent->inode != ino) {
1b6bf175 390 if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) {
3839e657
TT
391 dirent->inode = ino;
392 status = 1;
21c84b71 393 }
3839e657 394 }
5dd77dbe
TT
395 if (rec_len > 12) {
396 new_len = rec_len - 12;
3839e657 397 if (new_len > 12) {
3839e657 398 if (created ||
f8188fff 399 fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
3839e657
TT
400 nextdir = (struct ext2_dir_entry *)
401 ((char *) dirent + 12);
402 dirent->rec_len = 12;
403 nextdir->rec_len = new_len;
404 nextdir->inode = 0;
405 nextdir->name_len = 0;
406 status = 1;
407 }
408 }
409 }
410 return status;
411}
412
413/*
414 * Make sure the second entry in the directory is '..', and that the
415 * directory entry is sane. We do not check the inode number of '..'
416 * here; this gets done in pass 3.
417 */
1b6bf175 418static int check_dotdot(e2fsck_t ctx,
3839e657 419 struct ext2_dir_entry *dirent,
28db82a8 420 ext2_ino_t ino, struct problem_context *pctx)
3839e657 421{
5dd77dbe 422 int rec_len, problem = 0;
efc6f628 423
21c84b71
TT
424 if (!dirent->inode)
425 problem = PR_2_MISSING_DOT_DOT;
b6f79831 426 else if (((dirent->name_len & 0xFF) != 2) ||
21c84b71
TT
427 (dirent->name[0] != '.') ||
428 (dirent->name[1] != '.'))
429 problem = PR_2_2ND_NOT_DOT_DOT;
430 else if (dirent->name[2] != '\0')
431 problem = PR_2_DOT_DOT_NULL_TERM;
432
5dd77dbe
TT
433 rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
434 dirent->rec_len : 65536;
21c84b71 435 if (problem) {
1b6bf175 436 if (fix_problem(ctx, problem, pctx)) {
5dd77dbe 437 if (rec_len < 12)
21c84b71 438 dirent->rec_len = 12;
3839e657
TT
439 /*
440 * Note: we don't have the parent inode just
441 * yet, so we will fill it in with the root
442 * inode. This will get fixed in pass 3.
443 */
444 dirent->inode = EXT2_ROOT_INO;
445 dirent->name_len = 2;
446 dirent->name[0] = '.';
447 dirent->name[1] = '.';
21c84b71 448 dirent->name[2] = '\0';
3839e657 449 return 1;
efc6f628 450 }
3839e657
TT
451 return 0;
452 }
28db82a8
TT
453 if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) {
454 fix_problem(ctx, PR_2_NO_DIRINFO, pctx);
455 return -1;
456 }
3839e657
TT
457 return 0;
458}
459
460/*
461 * Check to make sure a directory entry doesn't contain any illegal
462 * characters.
463 */
1b6bf175 464static int check_name(e2fsck_t ctx,
3839e657 465 struct ext2_dir_entry *dirent,
efc6f628 466 ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
54434927 467 struct problem_context *pctx)
3839e657
TT
468{
469 int i;
470 int fixup = -1;
3839e657 471 int ret = 0;
efc6f628 472
b6f79831 473 for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
3839e657
TT
474 if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
475 if (fixup < 0) {
1b6bf175 476 fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
3839e657
TT
477 }
478 if (fixup) {
479 dirent->name[i] = '.';
480 ret = 1;
21c84b71 481 }
3839e657
TT
482 }
483 }
484 return ret;
485}
486
aa4115a4
TT
487/*
488 * Check the directory filetype (if present)
489 */
490static _INLINE_ int check_filetype(e2fsck_t ctx,
54434927
TT
491 struct ext2_dir_entry *dirent,
492 ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
493 struct problem_context *pctx)
aa4115a4
TT
494{
495 int filetype = dirent->name_len >> 8;
496 int should_be = EXT2_FT_UNKNOWN;
497 struct ext2_inode inode;
498
499 if (!(ctx->fs->super->s_feature_incompat &
7847c1d4
TT
500 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
501 if (filetype == 0 ||
502 !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
503 return 0;
504 dirent->name_len = dirent->name_len & 0xFF;
505 return 1;
506 }
aa4115a4
TT
507
508 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
509 should_be = EXT2_FT_DIR;
510 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
511 dirent->inode)) {
512 should_be = EXT2_FT_REG_FILE;
513 } else if (ctx->inode_bad_map &&
514 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
515 dirent->inode))
516 should_be = 0;
517 else {
518 e2fsck_read_inode(ctx, dirent->inode, &inode,
519 "check_filetype");
6fdc7a32 520 should_be = ext2_file_type(inode.i_mode);
aa4115a4
TT
521 }
522 if (filetype == should_be)
523 return 0;
524 pctx->num = should_be;
525
526 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE,
527 pctx) == 0)
528 return 0;
efc6f628 529
aa4115a4
TT
530 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
531 return 1;
532}
533
8fdc9985
TT
534#ifdef ENABLE_HTREE
535static void parse_int_node(ext2_filsys fs,
536 struct ext2_db_entry *db,
537 struct check_dir_struct *cd,
538 struct dx_dir_info *dx_dir,
539 char *block_buf)
540{
541 struct ext2_dx_root_info *root;
542 struct ext2_dx_entry *ent;
543 struct ext2_dx_countlimit *limit;
544 struct dx_dirblock_info *dx_db;
ad4fa466 545 int i, expect_limit, count;
8fdc9985
TT
546 blk_t blk;
547 ext2_dirhash_t min_hash = 0xffffffff;
548 ext2_dirhash_t max_hash = 0;
ad4fa466 549 ext2_dirhash_t hash = 0, prev_hash;
8fdc9985
TT
550
551 if (db->blockcnt == 0) {
552 root = (struct ext2_dx_root_info *) (block_buf + 24);
efc6f628 553
8fdc9985
TT
554#ifdef DX_DEBUG
555 printf("Root node dump:\n");
8deb80a5 556 printf("\t Reserved zero: %u\n", root->reserved_zero);
8fdc9985
TT
557 printf("\t Hash Version: %d\n", root->hash_version);
558 printf("\t Info length: %d\n", root->info_length);
559 printf("\t Indirect levels: %d\n", root->indirect_levels);
560 printf("\t Flags: %d\n", root->unused_flags);
561#endif
562
563 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
564 } else {
565 ent = (struct ext2_dx_entry *) (block_buf+8);
566 }
567 limit = (struct ext2_dx_countlimit *) ent;
568
569#ifdef DX_DEBUG
efc6f628 570 printf("Number of entries (count): %d\n",
8132d840 571 ext2fs_le16_to_cpu(limit->count));
efc6f628 572 printf("Number of entries (limit): %d\n",
8132d840 573 ext2fs_le16_to_cpu(limit->limit));
8fdc9985
TT
574#endif
575
8132d840 576 count = ext2fs_le16_to_cpu(limit->count);
ad4fa466
TT
577 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
578 sizeof(struct ext2_dx_entry);
8132d840
TT
579 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
580 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
ad4fa466
TT
581 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
582 goto clear_and_exit;
583 }
8132d840
TT
584 if (count > expect_limit) {
585 cd->pctx.num = count;
ad4fa466
TT
586 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx))
587 goto clear_and_exit;
588 count = expect_limit;
589 }
efc6f628 590
ad4fa466
TT
591 for (i=0; i < count; i++) {
592 prev_hash = hash;
8132d840 593 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0;
8fdc9985 594#ifdef DX_DEBUG
8deb80a5 595 printf("Entry #%d: Hash 0x%08x, block %u\n", i,
8132d840 596 hash, ext2fs_le32_to_cpu(ent[i].block));
8fdc9985 597#endif
8132d840 598 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff;
8fdc9985 599 /* Check to make sure the block is valid */
977ac873 600 if (blk >= (blk_t) dx_dir->numblocks) {
b7a00563 601 cd->pctx.blk = blk;
8fdc9985 602 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
ad4fa466
TT
603 &cd->pctx))
604 goto clear_and_exit;
977ac873 605 continue;
8fdc9985 606 }
ad4fa466
TT
607 if (hash < prev_hash &&
608 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx))
609 goto clear_and_exit;
8fdc9985
TT
610 dx_db = &dx_dir->dx_block[blk];
611 if (dx_db->flags & DX_FLAG_REFERENCED) {
612 dx_db->flags |= DX_FLAG_DUP_REF;
613 } else {
614 dx_db->flags |= DX_FLAG_REFERENCED;
615 dx_db->parent = db->blockcnt;
616 }
617 if (hash < min_hash)
618 min_hash = hash;
619 if (hash > max_hash)
620 max_hash = hash;
621 dx_db->node_min_hash = hash;
8132d840 622 if ((i+1) < count)
efc6f628 623 dx_db->node_max_hash =
8132d840 624 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1;
8fdc9985
TT
625 else {
626 dx_db->node_max_hash = 0xfffffffe;
627 dx_db->flags |= DX_FLAG_LAST;
628 }
629 if (i == 0)
630 dx_db->flags |= DX_FLAG_FIRST;
631 }
632#ifdef DX_DEBUG
633 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
634 db->blockcnt, min_hash, max_hash);
635#endif
636 dx_db = &dx_dir->dx_block[db->blockcnt];
637 dx_db->min_hash = min_hash;
638 dx_db->max_hash = max_hash;
ad4fa466
TT
639 return;
640
641clear_and_exit:
642 clear_htree(cd->ctx, cd->pctx.ino);
643 dx_dir->numblocks = 0;
8fdc9985
TT
644}
645#endif /* ENABLE_HTREE */
aa4115a4 646
e70ae99e
TT
647/*
648 * Given a busted directory, try to salvage it somehow.
efc6f628 649 *
e70ae99e 650 */
ad4fa466 651static void salvage_directory(ext2_filsys fs,
e70ae99e
TT
652 struct ext2_dir_entry *dirent,
653 struct ext2_dir_entry *prev,
54434927 654 unsigned int *offset)
e70ae99e
TT
655{
656 char *cp = (char *) dirent;
5dd77dbe 657 int left, rec_len;
642935c0 658 unsigned int name_len = dirent->name_len & 0xFF;
e70ae99e 659
5dd77dbe
TT
660 rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
661 dirent->rec_len : 65536;
662 left = fs->blocksize - *offset - rec_len;
663
e70ae99e
TT
664 /*
665 * Special case of directory entry of size 8: copy what's left
666 * of the directory block up to cover up the invalid hole.
667 */
5dd77dbe 668 if ((left >= 12) && (rec_len == 8)) {
e70ae99e
TT
669 memmove(cp, cp+8, left);
670 memset(cp + left, 0, 8);
ad4fa466
TT
671 return;
672 }
673 /*
674 * If the directory entry overruns the end of the directory
675 * block, and the name is small enough to fit, then adjust the
676 * record length.
677 */
678 if ((left < 0) &&
5dd77dbe 679 (name_len + 8 <= rec_len + (unsigned) left) &&
ad4fa466
TT
680 dirent->inode <= fs->super->s_inodes_count &&
681 strnlen(dirent->name, name_len) == name_len) {
682 dirent->rec_len += left;
683 return;
e70ae99e
TT
684 }
685 /*
575307cc
KS
686 * If the record length of the directory entry is a multiple
687 * of four, and not too big, such that it is valid, let the
688 * previous directory entry absorb the invalid one.
e70ae99e 689 */
5dd77dbe
TT
690 if (prev && rec_len && (rec_len % 4) == 0 &&
691 (*offset + rec_len <= fs->blocksize)) {
692 prev->rec_len += rec_len;
693 *offset += rec_len;
ad4fa466 694 return;
e70ae99e
TT
695 }
696 /*
697 * Default salvage method --- kill all of the directory
698 * entries for the rest of the block. We will either try to
699 * absorb it into the previous directory entry, or create a
700 * new empty directory entry the rest of the directory block.
701 */
702 if (prev) {
ad4fa466
TT
703 prev->rec_len += fs->blocksize - *offset;
704 *offset = fs->blocksize;
e70ae99e 705 } else {
ad4fa466 706 dirent->rec_len = fs->blocksize - *offset;
e70ae99e
TT
707 dirent->name_len = 0;
708 dirent->inode = 0;
e70ae99e 709 }
e70ae99e
TT
710}
711
3839e657 712static int check_dir_block(ext2_filsys fs,
21c84b71 713 struct ext2_db_entry *db,
54dc7ca2 714 void *priv_data)
3839e657 715{
8fdc9985
TT
716 struct dx_dir_info *dx_dir;
717#ifdef ENABLE_HTREE
718 struct dx_dirblock_info *dx_db = 0;
719#endif /* ENABLE_HTREE */
e70ae99e 720 struct ext2_dir_entry *dirent, *prev;
8fdc9985 721 ext2_dirhash_t hash;
54434927 722 unsigned int offset = 0;
e94bc631 723 const char * old_op;
3839e657 724 int dir_modified = 0;
21c84b71 725 int dot_state;
03fa6f8a 726 unsigned int rec_len;
3839e657 727 blk_t block_nr = db->blk;
86c627ec 728 ext2_ino_t ino = db->ino;
28db82a8 729 ext2_ino_t subdir_parent;
21c84b71 730 __u16 links;
54dc7ca2 731 struct check_dir_struct *cd;
1b6bf175
TT
732 char *buf;
733 e2fsck_t ctx;
734 int problem;
ea1959f0 735 struct ext2_dx_root_info *root;
e8254bfd 736 struct ext2_dx_countlimit *limit;
0926668d
TT
737 static dict_t de_dict;
738 struct problem_context pctx;
739 int dups_found = 0;
28db82a8 740 int ret;
1b6bf175 741
54dc7ca2 742 cd = (struct check_dir_struct *) priv_data;
1b6bf175
TT
743 buf = cd->buf;
744 ctx = cd->ctx;
f8188fff 745
49a7360b 746 if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
4cae0452 747 return DIRENT_ABORT;
efc6f628 748
4cae0452
TT
749 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
750 return DIRENT_ABORT;
efc6f628 751
3839e657 752 /*
efc6f628 753 * Make sure the inode is still in use (could have been
3839e657
TT
754 * deleted in the duplicate/bad blocks pass.
755 */
efc6f628 756 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino)))
3839e657 757 return 0;
50e1e10f 758
21c84b71
TT
759 cd->pctx.ino = ino;
760 cd->pctx.blk = block_nr;
761 cd->pctx.blkcount = db->blockcnt;
762 cd->pctx.ino2 = 0;
763 cd->pctx.dirent = 0;
764 cd->pctx.num = 0;
765
50e1e10f 766 if (db->blk == 0) {
1b6bf175 767 if (allocate_dir_block(ctx, db, buf, &cd->pctx))
50e1e10f
TT
768 return 0;
769 block_nr = db->blk;
770 }
efc6f628 771
3839e657
TT
772 if (db->blockcnt)
773 dot_state = 2;
774 else
775 dot_state = 0;
776
0926668d
TT
777 if (ctx->dirs_to_hash &&
778 ext2fs_u32_list_test(ctx->dirs_to_hash, ino))
779 dups_found++;
780
3839e657 781#if 0
f3db3566 782 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr,
3839e657
TT
783 db->blockcnt, ino);
784#endif
efc6f628 785
e94bc631 786 old_op = ehandler_operation(_("reading directory block"));
1b6bf175 787 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf);
e94bc631 788 ehandler_operation(0);
b9852cd8
TT
789 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
790 cd->pctx.errcode = 0; /* We'll handle this ourselves */
1b6bf175 791 if (cd->pctx.errcode) {
08b21301
TT
792 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
793 ctx->flags |= E2F_FLAG_ABORT;
794 return DIRENT_ABORT;
795 }
1b6bf175 796 memset(buf, 0, fs->blocksize);
3839e657 797 }
8fdc9985
TT
798#ifdef ENABLE_HTREE
799 dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
62acaa1d 800 if (dx_dir && dx_dir->numblocks) {
8fdc9985 801 if (db->blockcnt >= dx_dir->numblocks) {
efc6f628 802 if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK,
d45edec0
TT
803 &pctx)) {
804 clear_htree(ctx, ino);
805 dx_dir->numblocks = 0;
806 dx_db = 0;
807 goto out_htree;
808 }
809 fatal_error(ctx, _("Can not continue."));
8fdc9985
TT
810 }
811 dx_db = &dx_dir->dx_block[db->blockcnt];
812 dx_db->type = DX_DIRBLOCK_LEAF;
813 dx_db->phys = block_nr;
814 dx_db->min_hash = ~0;
815 dx_db->max_hash = 0;
efc6f628 816
8fdc9985 817 dirent = (struct ext2_dir_entry *) buf;
5dd77dbe
TT
818 rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
819 dirent->rec_len : 65536;
e8254bfd 820 limit = (struct ext2_dx_countlimit *) (buf+8);
8fdc9985 821 if (db->blockcnt == 0) {
ea1959f0 822 root = (struct ext2_dx_root_info *) (buf + 24);
8fdc9985
TT
823 dx_db->type = DX_DIRBLOCK_ROOT;
824 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
ea1959f0
TT
825 if ((root->reserved_zero ||
826 root->info_length < 8 ||
827 root->indirect_levels > 1) &&
828 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
829 clear_htree(ctx, ino);
830 dx_dir->numblocks = 0;
831 dx_db = 0;
f77704e4 832 }
ea1959f0 833 dx_dir->hashversion = root->hash_version;
f77704e4
TT
834 if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
835 (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
836 dx_dir->hashversion += 3;
ad4fa466 837 dx_dir->depth = root->indirect_levels + 1;
8fdc9985 838 } else if ((dirent->inode == 0) &&
5dd77dbe 839 (rec_len == fs->blocksize) &&
e8254bfd 840 (dirent->name_len == 0) &&
efc6f628
TT
841 (ext2fs_le16_to_cpu(limit->limit) ==
842 ((fs->blocksize-8) /
8132d840 843 sizeof(struct ext2_dx_entry))))
8fdc9985
TT
844 dx_db->type = DX_DIRBLOCK_NODE;
845 }
d45edec0 846out_htree:
8fdc9985 847#endif /* ENABLE_HTREE */
3839e657 848
0926668d 849 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
e70ae99e 850 prev = 0;
3839e657 851 do {
49a7360b
JS
852 int group;
853 ext2_ino_t first_unused_inode;
854
1b6bf175 855 problem = 0;
3839e657 856 dirent = (struct ext2_dir_entry *) (buf + offset);
5dd77dbe
TT
857 rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
858 dirent->rec_len : 65536;
21c84b71
TT
859 cd->pctx.dirent = dirent;
860 cd->pctx.num = offset;
5dd77dbe
TT
861 if (((offset + rec_len) > fs->blocksize) ||
862 (rec_len < 12) ||
863 ((rec_len % 4) != 0) ||
03fa6f8a 864 (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
1b6bf175 865 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
ad4fa466 866 salvage_directory(fs, dirent, prev, &offset);
3839e657 867 dir_modified++;
e70ae99e 868 continue;
21c84b71 869 } else
0926668d 870 goto abort_free_dict;
3839e657 871 }
b6f79831 872 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) {
1b6bf175 873 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) {
50e1e10f
TT
874 dirent->name_len = EXT2_NAME_LEN;
875 dir_modified++;
876 }
50e1e10f
TT
877 }
878
e70ae99e 879 if (dot_state == 0) {
1b6bf175 880 if (check_dot(ctx, dirent, ino, &cd->pctx))
3839e657 881 dir_modified++;
e70ae99e 882 } else if (dot_state == 1) {
28db82a8
TT
883 ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
884 if (ret < 0)
0926668d 885 goto abort_free_dict;
28db82a8 886 if (ret)
3839e657
TT
887 dir_modified++;
888 } else if (dirent->inode == ino) {
1b6bf175
TT
889 problem = PR_2_LINK_DOT;
890 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) {
3839e657
TT
891 dirent->inode = 0;
892 dir_modified++;
21c84b71 893 goto next;
3839e657
TT
894 }
895 }
efc6f628 896 if (!dirent->inode)
3839e657 897 goto next;
efc6f628 898
3839e657
TT
899 /*
900 * Make sure the inode listed is a legal one.
efc6f628 901 */
3839e657 902 if (((dirent->inode != EXT2_ROOT_INO) &&
7f88b043 903 (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
3839e657 904 (dirent->inode > fs->super->s_inodes_count)) {
1b6bf175 905 problem = PR_2_BAD_INO;
1b6bf175
TT
906 } else if (ctx->inode_bb_map &&
907 (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
908 dirent->inode))) {
909 /*
910 * If the inode is in a bad block, offer to
911 * clear it.
912 */
913 problem = PR_2_BB_INODE;
e70ae99e 914 } else if ((dot_state > 1) &&
b6f79831 915 ((dirent->name_len & 0xFF) == 1) &&
1b6bf175
TT
916 (dirent->name[0] == '.')) {
917 /*
918 * If there's a '.' entry in anything other
919 * than the first directory entry, it's a
920 * duplicate entry that should be removed.
921 */
922 problem = PR_2_DUP_DOT;
e70ae99e 923 } else if ((dot_state > 1) &&
b6f79831 924 ((dirent->name_len & 0xFF) == 2) &&
efc6f628 925 (dirent->name[0] == '.') &&
1b6bf175
TT
926 (dirent->name[1] == '.')) {
927 /*
928 * If there's a '..' entry in anything other
929 * than the second directory entry, it's a
930 * duplicate entry that should be removed.
931 */
932 problem = PR_2_DUP_DOT_DOT;
e70ae99e 933 } else if ((dot_state > 1) &&
1b6bf175
TT
934 (dirent->inode == EXT2_ROOT_INO)) {
935 /*
936 * Don't allow links to the root directory.
937 * We check this specially to make sure we
938 * catch this error case even if the root
939 * directory hasn't been created yet.
940 */
941 problem = PR_2_LINK_ROOT;
e70ae99e 942 } else if ((dot_state > 1) &&
c40db6d5
TT
943 (dirent->name_len & 0xFF) == 0) {
944 /*
945 * Don't allow zero-length directory names.
946 */
947 problem = PR_2_NULL_NAME;
21c84b71
TT
948 }
949
1b6bf175
TT
950 if (problem) {
951 if (fix_problem(ctx, problem, &cd->pctx)) {
21c84b71
TT
952 dirent->inode = 0;
953 dir_modified++;
954 goto next;
1b6bf175
TT
955 } else {
956 ext2fs_unmark_valid(fs);
957 if (problem == PR_2_BAD_INO)
958 goto next;
21c84b71 959 }
3839e657
TT
960 }
961
962 /*
963 * If the inode was marked as having bad fields in
964 * pass1, process it and offer to fix/clear it.
965 * (We wait until now so that we can display the
966 * pathname to the user.)
967 */
1b6bf175
TT
968 if (ctx->inode_bad_map &&
969 ext2fs_test_inode_bitmap(ctx->inode_bad_map,
3839e657 970 dirent->inode)) {
e72a9ba3 971 if (e2fsck_process_bad_inode(ctx, ino,
bcf9c5d4
TT
972 dirent->inode,
973 buf + fs->blocksize)) {
3839e657
TT
974 dirent->inode = 0;
975 dir_modified++;
976 goto next;
977 }
a02ce9df 978 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
08b21301 979 return DIRENT_ABORT;
3839e657
TT
980 }
981
49a7360b
JS
982 group = ext2fs_group_of_ino(fs, dirent->inode);
983 first_unused_inode = group * fs->super->s_inodes_per_group +
984 1 + fs->super->s_inodes_per_group -
985 fs->group_desc[group].bg_itable_unused;
986 cd->pctx.group = group;
987
988 /*
42e89ce7
TT
989 * Check if the inode was missed out because
990 * _INODE_UNINIT flag was set or bg_itable_unused was
991 * incorrect. If so, clear the _INODE_UNINIT flag and
992 * restart e2fsck. In the future it would be nice if
993 * we could call a function in pass1.c that checks the
994 * newly visible inodes.
49a7360b
JS
995 */
996 if (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT) {
6267ee49 997 pctx.num = dirent->inode;
49a7360b
JS
998 if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
999 &cd->pctx)){
1000 fs->group_desc[group].bg_flags &=
1001 ~EXT2_BG_INODE_UNINIT;
42e89ce7 1002 ext2fs_mark_super_dirty(fs);
6267ee49 1003 ctx->flags |= E2F_FLAG_RESTART_LATER;
49a7360b
JS
1004 } else {
1005 ext2fs_unmark_valid(fs);
1006 if (problem == PR_2_BAD_INO)
1007 goto next;
1008 }
1009 } else if (dirent->inode >= first_unused_inode) {
6267ee49 1010 pctx.num = dirent->inode;
49a7360b
JS
1011 if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
1012 fs->group_desc[group].bg_itable_unused = 0;
49a7360b 1013 ext2fs_mark_super_dirty(fs);
6267ee49 1014 ctx->flags |= E2F_FLAG_RESTART_LATER;
49a7360b
JS
1015 } else {
1016 ext2fs_unmark_valid(fs);
1017 if (problem == PR_2_BAD_INO)
1018 goto next;
1019 }
1020 }
1021
1022 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
1023 dirent->inode))) {
1024 /*
1025 * If the inode is unused, offer to clear it.
1026 */
1027 problem = PR_2_UNUSED_INODE;
1028 }
1029
1030 if (problem) {
1031 if (fix_problem(ctx, problem, &cd->pctx)) {
1032 dirent->inode = 0;
1033 dir_modified++;
1034 goto next;
1035 } else {
1036 ext2fs_unmark_valid(fs);
1037 if (problem == PR_2_BAD_INO)
1038 goto next;
1039 }
1040 }
1041
1b6bf175
TT
1042 if (check_name(ctx, dirent, ino, &cd->pctx))
1043 dir_modified++;
1044
aa4115a4
TT
1045 if (check_filetype(ctx, dirent, ino, &cd->pctx))
1046 dir_modified++;
1047
8fdc9985
TT
1048#ifdef ENABLE_HTREE
1049 if (dx_db) {
1050 ext2fs_dirhash(dx_dir->hashversion, dirent->name,
503f9e7f
TT
1051 (dirent->name_len & 0xFF),
1052 fs->super->s_hash_seed, &hash, 0);
8fdc9985
TT
1053 if (hash < dx_db->min_hash)
1054 dx_db->min_hash = hash;
1055 if (hash > dx_db->max_hash)
1056 dx_db->max_hash = hash;
1057 }
1058#endif
1059
3839e657
TT
1060 /*
1061 * If this is a directory, then mark its parent in its
1062 * dir_info structure. If the parent field is already
1063 * filled in, then this directory has more than one
1064 * hard link. We assume the first link is correct,
1065 * and ask the user if he/she wants to clear this one.
1066 */
e70ae99e 1067 if ((dot_state > 1) &&
1b6bf175 1068 (ext2fs_test_inode_bitmap(ctx->inode_dir_map,
3839e657 1069 dirent->inode))) {
28db82a8
TT
1070 if (e2fsck_dir_info_get_parent(ctx, dirent->inode,
1071 &subdir_parent)) {
1b6bf175
TT
1072 cd->pctx.ino = dirent->inode;
1073 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx);
0926668d 1074 goto abort_free_dict;
3839e657 1075 }
28db82a8
TT
1076 if (subdir_parent) {
1077 cd->pctx.ino2 = subdir_parent;
1b6bf175 1078 if (fix_problem(ctx, PR_2_LINK_DIR,
21c84b71 1079 &cd->pctx)) {
3839e657
TT
1080 dirent->inode = 0;
1081 dir_modified++;
1082 goto next;
21c84b71
TT
1083 }
1084 cd->pctx.ino2 = 0;
28db82a8 1085 } else {
efc6f628 1086 (void) e2fsck_dir_info_set_parent(ctx,
28db82a8
TT
1087 dirent->inode, ino);
1088 }
3839e657 1089 }
0926668d
TT
1090
1091 if (dups_found) {
1092 ;
1093 } else if (dict_lookup(&de_dict, dirent)) {
1094 clear_problem_context(&pctx);
1095 pctx.ino = ino;
1096 pctx.dirent = dirent;
1097 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
1098 if (!ctx->dirs_to_hash)
1099 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
1100 if (ctx->dirs_to_hash)
1101 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
1102 dups_found++;
1103 } else
1104 dict_alloc_insert(&de_dict, dirent, dirent);
efc6f628 1105
1b6bf175
TT
1106 ext2fs_icount_increment(ctx->inode_count, dirent->inode,
1107 &links);
21c84b71 1108 if (links > 1)
1b6bf175
TT
1109 ctx->fs_links_count++;
1110 ctx->fs_total_count++;
3839e657 1111 next:
e70ae99e 1112 prev = dirent;
5dd77dbe
TT
1113 if (dir_modified)
1114 rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
1115 dirent->rec_len : 65536;
1116 offset += rec_len;
e70ae99e 1117 dot_state++;
3839e657
TT
1118 } while (offset < fs->blocksize);
1119#if 0
1120 printf("\n");
1121#endif
8fdc9985
TT
1122#ifdef ENABLE_HTREE
1123 if (dx_db) {
1124#ifdef DX_DEBUG
1125 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
1126 db->blockcnt, dx_db->type,
1127 dx_db->min_hash, dx_db->max_hash);
1128#endif
b7a00563 1129 cd->pctx.dir = cd->pctx.ino;
8fdc9985
TT
1130 if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
1131 (dx_db->type == DX_DIRBLOCK_NODE))
1132 parse_int_node(fs, db, cd, dx_dir, buf);
1133 }
1134#endif /* ENABLE_HTREE */
3839e657 1135 if (offset != fs->blocksize) {
5dd77dbe 1136 cd->pctx.num = rec_len - fs->blocksize + offset;
1b6bf175
TT
1137 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
1138 dirent->rec_len = cd->pctx.num;
1139 dir_modified++;
1140 }
3839e657
TT
1141 }
1142 if (dir_modified) {
1b6bf175
TT
1143 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
1144 if (cd->pctx.errcode) {
08b21301 1145 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
0926668d
TT
1146 &cd->pctx))
1147 goto abort_free_dict;
3839e657
TT
1148 }
1149 ext2fs_mark_changed(fs);
1150 }
0926668d 1151 dict_free_nodes(&de_dict);
3839e657 1152 return 0;
0926668d 1153abort_free_dict:
0926668d 1154 ctx->flags |= E2F_FLAG_ABORT;
49a7360b 1155 dict_free_nodes(&de_dict);
0926668d 1156 return DIRENT_ABORT;
3839e657
TT
1157}
1158
1159/*
1160 * This function is called to deallocate a block, and is an interator
1161 * functioned called by deallocate inode via ext2fs_iterate_block().
1162 */
1163static int deallocate_inode_block(ext2_filsys fs,
133a56dc 1164 blk_t *block_nr,
54434927
TT
1165 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
1166 blk_t ref_block EXT2FS_ATTR((unused)),
1167 int ref_offset EXT2FS_ATTR((unused)),
133a56dc 1168 void *priv_data)
3839e657 1169{
54dc7ca2 1170 e2fsck_t ctx = (e2fsck_t) priv_data;
efc6f628 1171
1917875f 1172 if (HOLE_BLKADDR(*block_nr))
3839e657 1173 return 0;
1ba7a2f2
TT
1174 if ((*block_nr < fs->super->s_first_data_block) ||
1175 (*block_nr >= fs->super->s_blocks_count))
1176 return 0;
1b6bf175 1177 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
0684a4f3 1178 ext2fs_block_alloc_stats(fs, *block_nr, -1);
3839e657
TT
1179 return 0;
1180}
efc6f628 1181
3839e657
TT
1182/*
1183 * This fuction deallocates an inode
1184 */
4035f40b 1185static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
3839e657 1186{
1b6bf175 1187 ext2_filsys fs = ctx->fs;
3839e657 1188 struct ext2_inode inode;
1b6bf175 1189 struct problem_context pctx;
0684a4f3 1190 __u32 count;
efc6f628 1191
08b21301 1192 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
e3df15ab 1193 e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
1b6bf175
TT
1194 clear_problem_context(&pctx);
1195 pctx.ino = ino;
f3db3566 1196
3839e657
TT
1197 /*
1198 * Fix up the bitmaps...
1199 */
f8188fff 1200 e2fsck_read_bitmaps(ctx);
0684a4f3
TT
1201 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
1202
1203 if (inode.i_file_acl &&
1204 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1205 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
1206 block_buf, -1, &count);
1207 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
1208 pctx.errcode = 0;
1209 count = 1;
1210 }
1211 if (pctx.errcode) {
1212 pctx.blk = inode.i_file_acl;
1213 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
1214 ctx->flags |= E2F_FLAG_ABORT;
1215 return;
1216 }
1217 if (count == 0) {
1218 ext2fs_unmark_block_bitmap(ctx->block_found_map,
1219 inode.i_file_acl);
1220 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1);
1221 }
1222 inode.i_file_acl = 0;
1223 }
3839e657 1224
21c84b71 1225 if (!ext2fs_inode_has_valid_blocks(&inode))
3839e657 1226 return;
a4742691 1227
b94a052a 1228 if (LINUX_S_ISREG(inode.i_mode) &&
a4742691
TT
1229 (inode.i_size_high || inode.i_size & 0x80000000UL))
1230 ctx->large_files--;
1231
133a56dc 1232 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
1b6bf175
TT
1233 deallocate_inode_block, ctx);
1234 if (pctx.errcode) {
1235 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
08b21301
TT
1236 ctx->flags |= E2F_FLAG_ABORT;
1237 return;
1b6bf175 1238 }
3839e657
TT
1239}
1240
8fdc9985
TT
1241/*
1242 * This fuction clears the htree flag on an inode
1243 */
1244static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
1245{
1246 struct ext2_inode inode;
efc6f628 1247
8fdc9985
TT
1248 e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
1249 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
1250 e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
b7a00563
TT
1251 if (ctx->dirs_to_hash)
1252 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
8fdc9985
TT
1253}
1254
1255
86c627ec 1256extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
bcf9c5d4 1257 ext2_ino_t ino, char *buf)
3839e657 1258{
1b6bf175 1259 ext2_filsys fs = ctx->fs;
3839e657 1260 struct ext2_inode inode;
3839e657 1261 int inode_modified = 0;
6c313fd4 1262 int not_fixed = 0;
1e3472c5 1263 unsigned char *frag, *fsize;
21c84b71 1264 struct problem_context pctx;
08b21301 1265 int problem = 0;
3839e657 1266
08b21301 1267 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
21c84b71
TT
1268
1269 clear_problem_context(&pctx);
1270 pctx.ino = ino;
1271 pctx.dir = dir;
1272 pctx.inode = &inode;
1273
6c313fd4 1274 if (inode.i_file_acl &&
f76344fb
TT
1275 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
1276 if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
1277 inode.i_file_acl = 0;
f76344fb
TT
1278 inode_modified++;
1279 } else
1280 not_fixed++;
1281 }
6c313fd4 1282
50e1e10f
TT
1283 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
1284 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
1285 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
08b21301
TT
1286 !(LINUX_S_ISSOCK(inode.i_mode)))
1287 problem = PR_2_BAD_MODE;
fdbdea09 1288 else if (LINUX_S_ISCHR(inode.i_mode)
0684a4f3 1289 && !e2fsck_pass1_check_device_inode(fs, &inode))
08b21301 1290 problem = PR_2_BAD_CHAR_DEV;
fdbdea09 1291 else if (LINUX_S_ISBLK(inode.i_mode)
0684a4f3 1292 && !e2fsck_pass1_check_device_inode(fs, &inode))
08b21301 1293 problem = PR_2_BAD_BLOCK_DEV;
fdbdea09 1294 else if (LINUX_S_ISFIFO(inode.i_mode)
0684a4f3 1295 && !e2fsck_pass1_check_device_inode(fs, &inode))
1dde43f0 1296 problem = PR_2_BAD_FIFO;
fdbdea09 1297 else if (LINUX_S_ISSOCK(inode.i_mode)
0684a4f3 1298 && !e2fsck_pass1_check_device_inode(fs, &inode))
1dde43f0 1299 problem = PR_2_BAD_SOCKET;
fdbdea09 1300 else if (LINUX_S_ISLNK(inode.i_mode)
7cadc577 1301 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
bcf9c5d4 1302 problem = PR_2_INVALID_SYMLINK;
67052a8a 1303 }
1dde43f0 1304
08b21301
TT
1305 if (problem) {
1306 if (fix_problem(ctx, problem, &pctx)) {
1b6bf175 1307 deallocate_inode(ctx, ino, 0);
a02ce9df 1308 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
08b21301 1309 return 0;
7cf73dcd 1310 return 1;
6c313fd4
TT
1311 } else
1312 not_fixed++;
08b21301 1313 problem = 0;
7cf73dcd 1314 }
efc6f628 1315
6c313fd4
TT
1316 if (inode.i_faddr) {
1317 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
1318 inode.i_faddr = 0;
1319 inode_modified++;
1320 } else
1321 not_fixed++;
3839e657 1322 }
1e3472c5
TT
1323
1324 switch (fs->super->s_creator_os) {
1e3472c5
TT
1325 case EXT2_OS_HURD:
1326 frag = &inode.osd2.hurd2.h_i_frag;
1327 fsize = &inode.osd2.hurd2.h_i_fsize;
1328 break;
1e3472c5
TT
1329 default:
1330 frag = fsize = 0;
1331 }
21c84b71
TT
1332 if (frag && *frag) {
1333 pctx.num = *frag;
1b6bf175 1334 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
21c84b71
TT
1335 *frag = 0;
1336 inode_modified++;
7e0282c5
TT
1337 } else
1338 not_fixed++;
21c84b71
TT
1339 pctx.num = 0;
1340 }
1341 if (fsize && *fsize) {
1342 pctx.num = *fsize;
1b6bf175 1343 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
21c84b71
TT
1344 *fsize = 0;
1345 inode_modified++;
6c313fd4
TT
1346 } else
1347 not_fixed++;
21c84b71
TT
1348 pctx.num = 0;
1349 }
1350
5d17119d 1351 if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
efc6f628 1352 !(fs->super->s_feature_ro_compat &
5d17119d
TT
1353 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
1354 (inode.osd2.linux2.l_i_blocks_hi != 0)) {
1355 pctx.num = inode.osd2.linux2.l_i_blocks_hi;
1356 if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
1357 inode.osd2.linux2.l_i_blocks_hi = 0;
1358 inode_modified++;
1359 }
1360 }
1361
911ec626
TT
1362 if (!(fs->super->s_feature_incompat &
1363 EXT4_FEATURE_INCOMPAT_64BIT) &&
1364 inode.osd2.linux2.l_i_file_acl_high != 0) {
1365 pctx.num = inode.osd2.linux2.l_i_file_acl_high;
1366 if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {
1367 inode.osd2.linux2.l_i_file_acl_high = 0;
1368 inode_modified++;
1369 } else
1370 not_fixed++;
1371 }
1372
342d847d
TT
1373 if (inode.i_file_acl &&
1374 ((inode.i_file_acl < fs->super->s_first_data_block) ||
6c313fd4
TT
1375 (inode.i_file_acl >= fs->super->s_blocks_count))) {
1376 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
1377 inode.i_file_acl = 0;
1378 inode_modified++;
1379 } else
1380 not_fixed++;
342d847d 1381 }
21c84b71 1382 if (inode.i_dir_acl &&
6c313fd4
TT
1383 LINUX_S_ISDIR(inode.i_mode)) {
1384 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
1385 inode.i_dir_acl = 0;
1386 inode_modified++;
1387 } else
1388 not_fixed++;
21c84b71 1389 }
6c313fd4 1390
f3db3566 1391 if (inode_modified)
08b21301 1392 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
f76344fb 1393 if (!not_fixed && ctx->inode_bad_map)
6c313fd4 1394 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
3839e657
TT
1395 return 0;
1396}
1397
50e1e10f
TT
1398
1399/*
1400 * allocate_dir_block --- this function allocates a new directory
1401 * block for a particular inode; this is done if a directory has
1402 * a "hole" in it, or if a directory has a illegal block number
1403 * that was zeroed out and now needs to be replaced.
1404 */
1b6bf175 1405static int allocate_dir_block(e2fsck_t ctx,
21c84b71 1406 struct ext2_db_entry *db,
efc6f628 1407 char *buf EXT2FS_ATTR((unused)),
54434927 1408 struct problem_context *pctx)
50e1e10f 1409{
1b6bf175 1410 ext2_filsys fs = ctx->fs;
50e1e10f
TT
1411 blk_t blk;
1412 char *block;
1413 struct ext2_inode inode;
50e1e10f 1414
1b6bf175 1415 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0)
50e1e10f
TT
1416 return 1;
1417
1418 /*
1419 * Read the inode and block bitmaps in; we'll be messing with
1420 * them.
1421 */
f8188fff 1422 e2fsck_read_bitmaps(ctx);
efc6f628 1423
50e1e10f
TT
1424 /*
1425 * First, find a free block
1426 */
1b6bf175
TT
1427 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk);
1428 if (pctx->errcode) {
1429 pctx->str = "ext2fs_new_block";
1430 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
50e1e10f
TT
1431 return 1;
1432 }
1b6bf175 1433 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
50e1e10f
TT
1434 ext2fs_mark_block_bitmap(fs->block_map, blk);
1435 ext2fs_mark_bb_dirty(fs);
1436
1437 /*
1438 * Now let's create the actual data block for the inode
1439 */
1440 if (db->blockcnt)
1b6bf175 1441 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block);
50e1e10f 1442 else
1b6bf175
TT
1443 pctx->errcode = ext2fs_new_dir_block(fs, db->ino,
1444 EXT2_ROOT_INO, &block);
50e1e10f 1445
1b6bf175
TT
1446 if (pctx->errcode) {
1447 pctx->str = "ext2fs_new_dir_block";
1448 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
50e1e10f
TT
1449 return 1;
1450 }
1451
1b6bf175 1452 pctx->errcode = ext2fs_write_dir_block(fs, blk, block);
c4e3d3f3 1453 ext2fs_free_mem(&block);
1b6bf175
TT
1454 if (pctx->errcode) {
1455 pctx->str = "ext2fs_write_dir_block";
1456 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
50e1e10f
TT
1457 return 1;
1458 }
1459
1460 /*
1461 * Update the inode block count
1462 */
08b21301 1463 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block");
1ca1059f 1464 ext2fs_iblk_add_blocks(fs, &inode, 1);
50e1e10f
TT
1465 if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
1466 inode.i_size = (db->blockcnt+1) * fs->blocksize;
08b21301 1467 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block");
50e1e10f
TT
1468
1469 /*
1470 * Finally, update the block pointers for the inode
1471 */
1472 db->blk = blk;
133a56dc 1473 pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE,
50e1e10f 1474 0, update_dir_block, db);
1b6bf175
TT
1475 if (pctx->errcode) {
1476 pctx->str = "ext2fs_block_iterate";
1477 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx);
50e1e10f
TT
1478 return 1;
1479 }
1480
1481 return 0;
1482}
1483
1484/*
1485 * This is a helper function for allocate_dir_block().
1486 */
54434927 1487static int update_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
50e1e10f 1488 blk_t *block_nr,
133a56dc 1489 e2_blkcnt_t blockcnt,
54434927 1490 blk_t ref_block EXT2FS_ATTR((unused)),
efc6f628 1491 int ref_offset EXT2FS_ATTR((unused)),
54dc7ca2 1492 void *priv_data)
50e1e10f 1493{
54dc7ca2 1494 struct ext2_db_entry *db;
50e1e10f 1495
54dc7ca2 1496 db = (struct ext2_db_entry *) priv_data;
133a56dc 1497 if (db->blockcnt == (int) blockcnt) {
50e1e10f
TT
1498 *block_nr = db->blk;
1499 return BLOCK_CHANGED;
1500 }
1501 return 0;
1502}