pass2.c revision 65f0aab98b20b5994a726ab90d355248bcddfffd
151125a21eafc29c925cac3655b46cfd8ef55f764Ted Kremenek/* 24241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * pass2.c --- check directory structure 34241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * 44241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o 54241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * 64241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * %Begin-Header% 74241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * This file may be redistributed under the terms of the GNU Public 84241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * License. 94241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * %End-Header% 1051125a21eafc29c925cac3655b46cfd8ef55f764Ted Kremenek * 1151125a21eafc29c925cac3655b46cfd8ef55f764Ted Kremenek * Pass 2 of e2fsck iterates through all active directory inodes, and 12b2213dc3dd8f58b611b91d2fce4834a767efcba7Jeffrey Yasskin * applies to following tests to each directory entry in the directory 13b2213dc3dd8f58b611b91d2fce4834a767efcba7Jeffrey Yasskin * blocks in the inodes: 14b2213dc3dd8f58b611b91d2fce4834a767efcba7Jeffrey Yasskin * 15b2213dc3dd8f58b611b91d2fce4834a767efcba7Jeffrey Yasskin * - The length of the directory entry (rec_len) should be at 164241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * least 8 bytes, and no more than the remaining space 174241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * left in the directory block. 184241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * - The length of the name in the directory entry (name_len) 195a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis * should be less than (rec_len - 8). 205a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis * - The inode number in the directory entry should be within 214241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * legal bounds. 224a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek * - The inode number should refer to a in-use inode. 231309f9a3b225ea846e5822691c39a77423125505Ted Kremenek * - The first entry should be '.', and its inode should be 2463bbe5312cd89ce0ceb684bff68c5baef636e93cTed Kremenek * the inode of the directory. 254241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * - The second entry should be '..'. 264241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * 27f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek * To minimize disk seek time, the directory blocks are processed in 284241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * sorted order of block numbers. 29ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenek * 304a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek * Pass 2 also collects the following information: 314a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek * - The inode numbers of the subdirectories for each directory. 3263bbe5312cd89ce0ceb684bff68c5baef636e93cTed Kremenek * 335fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek * Pass 2 relies on the following information from previous passes: 3418c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek * - The directory information collected in pass 1. 35626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek * - The inode_used_map bitmap 364241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * - The inode_bad_map bitmap 374241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * - The inode_dir_map bitmap 384a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek * 3911062b118476368fa5b294954713e5df97d8599fTed Kremenek * Pass 2 frees the following data structures 405a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis * - The inode_bad_map bitmap 419ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenek * - The inode_reg_map bitmap 425a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis */ 435fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek 4411062b118476368fa5b294954713e5df97d8599fTed Kremenek#define _GNU_SOURCE 1 /* get strnlen() */ 45cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek#include <string.h> 46cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek 47cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek#include "e2fsck.h" 48cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek#include "problem.h" 49cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek#include "dict.h" 501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 51bda1efd0daf6fca9f515c6ce38d1ed71a3cca5b7Zhongxing Xu#ifdef NO_INLINE_FUNCS 52bda1efd0daf6fca9f515c6ce38d1ed71a3cca5b7Zhongxing Xu#define _INLINE_ 53bda1efd0daf6fca9f515c6ce38d1ed71a3cca5b7Zhongxing Xu#else 54c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu#define _INLINE_ inline 5538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu#endif 56d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis 57a19f4af7a94835ce4693bfe12d6270754e79eb56Anna Zaks/* #define DX_DEBUG */ 58d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis 59d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis/* 60d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis * Keeps track of how many times an inode is referenced. 61e36de1fe51c39d9161915dd3dbef880954af6476Ted Kremenek */ 621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpstatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf); 631833d284346b9fa11aae4e6aa07381347c04745cJordan Rosestatic int check_dir_block(ext2_filsys fs, 641833d284346b9fa11aae4e6aa07381347c04745cJordan Rose struct ext2_db_entry *dir_blocks_info, 651833d284346b9fa11aae4e6aa07381347c04745cJordan Rose void *priv_data); 661833d284346b9fa11aae4e6aa07381347c04745cJordan Rosestatic int allocate_dir_block(e2fsck_t ctx, 671833d284346b9fa11aae4e6aa07381347c04745cJordan Rose struct ext2_db_entry *dir_blocks_info, 681833d284346b9fa11aae4e6aa07381347c04745cJordan Rose char *buf, struct problem_context *pctx); 691833d284346b9fa11aae4e6aa07381347c04745cJordan Rosestatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino); 701833d284346b9fa11aae4e6aa07381347c04745cJordan Rosestatic int htree_depth(struct dx_dir_info *dx_dir, 711833d284346b9fa11aae4e6aa07381347c04745cJordan Rose struct dx_dirblock_info *dx_db); 724c4cb527a44037d076da82ad9d12b4e655e64dbbTed Kremenekstatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b); 7346e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose 7446e778145c56cd9b42cb399795a294b29cb78b62Jordan Rosestruct check_dir_struct { 7546e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose char *buf; 761833d284346b9fa11aae4e6aa07381347c04745cJordan Rose struct problem_context pctx; 774c4cb527a44037d076da82ad9d12b4e655e64dbbTed Kremenek int count, max; 78d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek e2fsck_t ctx; 794c4cb527a44037d076da82ad9d12b4e655e64dbbTed Kremenek}; 8046e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose 8146e778145c56cd9b42cb399795a294b29cb78b62Jordan Rosevoid e2fsck_pass2(e2fsck_t ctx) 8246e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose{ 831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump struct ext2_super_block *sb = ctx->fs->super; 8446e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose struct problem_context pctx; 851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ext2_filsys fs = ctx->fs; 8646e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose char *buf; 871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump#ifdef RESOURCE_TRACK 885d5480380d7b7c3590a0283ddf239220e514e576Ted Kremenek struct resource_track rtrack; 891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump#endif 9046e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose struct check_dir_struct cd; 911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump struct dx_dir_info *dx_dir; 921833d284346b9fa11aae4e6aa07381347c04745cJordan Rose struct dx_dirblock_info *dx_db, *dx_parent; 931833d284346b9fa11aae4e6aa07381347c04745cJordan Rose int b; 941833d284346b9fa11aae4e6aa07381347c04745cJordan Rose int i, depth; 959c378f705405d37f49795d5e915989de774fe11fTed Kremenek problem_t code; 961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump int bad_dir; 971833d284346b9fa11aae4e6aa07381347c04745cJordan Rose 981833d284346b9fa11aae4e6aa07381347c04745cJordan Rose init_resource_track(&rtrack, ctx->fs->io); 991833d284346b9fa11aae4e6aa07381347c04745cJordan Rose clear_problem_context(&cd.pctx); 1001833d284346b9fa11aae4e6aa07381347c04745cJordan Rose 1011833d284346b9fa11aae4e6aa07381347c04745cJordan Rose#ifdef MTRACE 102d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek mtrace_print("Pass 2"); 103d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek#endif 1041833d284346b9fa11aae4e6aa07381347c04745cJordan Rose 105b38911f16b4943548db6a3695fc6ae23070b25d2Ted Kremenek if (!(ctx->options & E2F_OPT_PREEN)) 10646e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx); 107f24af5bc2e01ca8e7396ed997378a77fddfa521eTed Kremenek 1081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump e2fsck_setup_tdb_icount(ctx, EXT2_ICOUNT_OPT_INCREMENT, 1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump &ctx->inode_count); 1104a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (ctx->inode_count) 1114a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek cd.pctx.errcode = 0; 1124a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek else 1131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump cd.pctx.errcode = ext2fs_create_icount2(fs, 1144323a57627e796dcfdfdb7d47672dc09ed308edaTed Kremenek EXT2_ICOUNT_OPT_INCREMENT, 1158bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek 0, ctx->inode_link_info, 1161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump &ctx->inode_count); 1174a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (cd.pctx.errcode) { 1184c4cb527a44037d076da82ad9d12b4e655e64dbbTed Kremenek fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx); 1191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ctx->flags |= E2F_FLAG_ABORT; 1204a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek return; 1214c4cb527a44037d076da82ad9d12b4e655e64dbbTed Kremenek } 122c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize, 1234a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek "directory scan buffer"); 124c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu 1258bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek /* 1266800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks * Set up the parent pointer for the root directory, if 12746e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose * present. (If the root directory is not present, we will 12846e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose * create it in pass 3.) 129e40b69de464bc695afcaf7ef9602ad727d77b981Ted Kremenek */ 130e40b69de464bc695afcaf7ef9602ad727d77b981Ted Kremenek (void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); 131a5888f61be9f8d76e9b48a453dbced50523bd2e0Argyrios Kyrtzidis 132c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu cd.buf = buf; 1334a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek cd.ctx = ctx; 1340f9063c116b7c3b05d8042b5976463c2dae04861Ted Kremenek cd.count = 1; 135c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu cd.max = ext2fs_dblist_count(fs->dblist); 1361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (ctx->progress) 13825e695b2d574d919cc1bbddf3a2efe073d449b1cZhongxing Xu (void) (ctx->progress)(ctx, 2, 0, cd.max); 13925e695b2d574d919cc1bbddf3a2efe073d449b1cZhongxing Xu 140955cd444f445bcdbade1cdd3926254c8ee7890d8Anna Zaks if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) 141955cd444f445bcdbade1cdd3926254c8ee7890d8Anna Zaks ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp); 142955cd444f445bcdbade1cdd3926254c8ee7890d8Anna Zaks 143955cd444f445bcdbade1cdd3926254c8ee7890d8Anna Zaks cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block, 1445032ffe4259e7d436f2eb19e5a29fdae559e7c12Zhongxing Xu &cd); 1455032ffe4259e7d436f2eb19e5a29fdae559e7c12Zhongxing Xu if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) 1465032ffe4259e7d436f2eb19e5a29fdae559e7c12Zhongxing Xu return; 1475032ffe4259e7d436f2eb19e5a29fdae559e7c12Zhongxing Xu 148b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu if (ctx->flags & E2F_FLAG_RESTART_LATER) { 149b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu ctx->flags |= E2F_FLAG_RESTART; 150a5937bbfd19e61d651a58b0f0ffeef68457902a5Ted Kremenek return; 151a5937bbfd19e61d651a58b0f0ffeef68457902a5Ted Kremenek } 152a5937bbfd19e61d651a58b0f0ffeef68457902a5Ted Kremenek 153c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu if (cd.pctx.errcode) { 154c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); 1558bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ctx->flags |= E2F_FLAG_ABORT; 156b317f8f5ca8737a5bbad97a3f7566a2dbd2ed61bZhongxing Xu return; 15752c3196a89a26cebcf069dd140c3396b743b8e33Ted Kremenek } 15852c3196a89a26cebcf069dd140c3396b743b8e33Ted Kremenek 159c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu#ifdef ENABLE_HTREE 1601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { 1616800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1621831bd29572b6a7243da73d9606209190c0217deBenjamin Kramer return; 1636800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks if (dx_dir->numblocks == 0) 1645fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek continue; 165a5888f61be9f8d76e9b48a453dbced50523bd2e0Argyrios Kyrtzidis clear_problem_context(&pctx); 1666800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks bad_dir = 0; 1675fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek pctx.dir = dx_dir->ino; 168c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu dx_db = dx_dir->dx_block; 169c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu if (dx_db->flags & DX_FLAG_REFERENCED) 1706800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks dx_db->flags |= DX_FLAG_DUP_REF; 171c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu else 172c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu dx_db->flags |= DX_FLAG_REFERENCED; 1731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump /* 174c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu * Find all of the first and last leaf blocks, and 1759c378f705405d37f49795d5e915989de774fe11fTed Kremenek * update their parent's min and max hash values 176c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu */ 1774a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek for (b=0, dx_db = dx_dir->dx_block; 1784a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek b < dx_dir->numblocks; 1794a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek b++, dx_db++) { 1800e8a3c743b9b3e3039e329a1736122d3b5b5fed9Ted Kremenek if ((dx_db->type != DX_DIRBLOCK_LEAF) || 1811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST))) 182ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek continue; 1834a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek dx_parent = &dx_dir->dx_block[dx_db->parent]; 1845903a373db3d27794c90b25687e0dd6adb0e497dAnna Zaks /* 1855903a373db3d27794c90b25687e0dd6adb0e497dAnna Zaks * XXX Make sure dx_parent->min_hash > dx_db->min_hash 1865903a373db3d27794c90b25687e0dd6adb0e497dAnna Zaks */ 1875903a373db3d27794c90b25687e0dd6adb0e497dAnna Zaks if (dx_db->flags & DX_FLAG_FIRST) 1889c378f705405d37f49795d5e915989de774fe11fTed Kremenek dx_parent->min_hash = dx_db->min_hash; 18952c3196a89a26cebcf069dd140c3396b743b8e33Ted Kremenek /* 19052c3196a89a26cebcf069dd140c3396b743b8e33Ted Kremenek * XXX Make sure dx_parent->max_hash < dx_db->max_hash 1911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump */ 1929c378f705405d37f49795d5e915989de774fe11fTed Kremenek if (dx_db->flags & DX_FLAG_LAST) 19352c3196a89a26cebcf069dd140c3396b743b8e33Ted Kremenek dx_parent->max_hash = dx_db->max_hash; 19452c3196a89a26cebcf069dd140c3396b743b8e33Ted Kremenek } 1951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1964a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek for (b=0, dx_db = dx_dir->dx_block; 19746e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose b < dx_dir->numblocks; 1983148eb4a75f70f2636075c364d03104223f004d3Ted Kremenek b++, dx_db++) { 19946e778145c56cd9b42cb399795a294b29cb78b62Jordan Rose pctx.blkcount = b; 2003148eb4a75f70f2636075c364d03104223f004d3Ted Kremenek pctx.group = dx_db->parent; 2014a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek code = 0; 202c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu if (!(dx_db->flags & DX_FLAG_FIRST) && 203c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu (dx_db->min_hash < dx_db->node_min_hash)) { 2044a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek pctx.blk = dx_db->min_hash; 2054a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek pctx.blk2 = dx_db->node_min_hash; 2064a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek code = PR_2_HTREE_MIN_HASH; 2071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump fix_problem(ctx, code, &pctx); 2084a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek bad_dir++; 2094a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 2104a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (dx_db->type == DX_DIRBLOCK_LEAF) { 2114a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek depth = htree_depth(dx_dir, dx_db); 212c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu if (depth != dx_dir->depth) { 213c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu pctx.num = dx_dir->depth; 2144a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek code = PR_2_HTREE_BAD_DEPTH; 2154a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek fix_problem(ctx, code, &pctx); 2164a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek bad_dir++; 2174a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 2184a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 2194a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek /* 2204a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek * This test doesn't apply for the root block 221c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu * at block #0 222c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu */ 2231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (b && 224c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu (dx_db->max_hash > dx_db->node_max_hash)) { 2251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump pctx.blk = dx_db->max_hash; 226c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu pctx.blk2 = dx_db->node_max_hash; 227c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu code = PR_2_HTREE_MAX_HASH; 228c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu fix_problem(ctx, code, &pctx); 2299c378f705405d37f49795d5e915989de774fe11fTed Kremenek bad_dir++; 230c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu } 2311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (!(dx_db->flags & DX_FLAG_REFERENCED)) { 232c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu code = PR_2_HTREE_NOTREF; 233d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek fix_problem(ctx, code, &pctx); 234d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek bad_dir++; 235d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek } else if (dx_db->flags & DX_FLAG_DUP_REF) { 236d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek code = PR_2_HTREE_DUPREF; 237c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu fix_problem(ctx, code, &pctx); 238c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bad_dir++; 23938b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu } 24038b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu } 24199ba9e3bd70671f3441fb974895f226a83ce0e66David Blaikie if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) { 24238b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu clear_htree(ctx, dx_dir->ino); 2431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump dx_dir->numblocks = 0; 244c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu } 24538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu } 2469c378f705405d37f49795d5e915989de774fe11fTed Kremenek e2fsck_free_dx_dir_info(ctx); 2471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump#endif 2487177dee8aee4b432911c91f1b788963bec0cac9fDaniel Dunbar ext2fs_free_mem(&buf); 24938b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu ext2fs_free_dblist(fs->dblist); 2504a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 2514a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (ctx->inode_bad_map) { 25238b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu ext2fs_free_inode_bitmap(ctx->inode_bad_map); 2534241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek ctx->inode_bad_map = 0; 254d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis } 255e96de2dfde487211fb52f9139cdcae64d051a406Zhongxing Xu if (ctx->inode_reg_map) { 2564241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek ext2fs_free_inode_bitmap(ctx->inode_reg_map); 257626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek ctx->inode_reg_map = 0; 2581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 259626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek 2604241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek clear_problem_context(&pctx); 2614241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek if (ctx->large_files) { 2624241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek if (!(sb->s_feature_ro_compat & 263626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek EXT2_FEATURE_RO_COMPAT_LARGE_FILE) && 2644241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) { 265626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek sb->s_feature_ro_compat |= 266626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek EXT2_FEATURE_RO_COMPAT_LARGE_FILE; 267626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 26838b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu ext2fs_mark_super_dirty(fs); 26938b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu } 27038b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (sb->s_rev_level == EXT2_GOOD_OLD_REV && 27138b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) { 2725fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek ext2fs_update_dynamic_rev(fs); 2735fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek ext2fs_mark_super_dirty(fs); 2745fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek } 2751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 27639b4c6c98d391b25c376782cf92346aa88c96f7eTed Kremenek 27739b4c6c98d391b25c376782cf92346aa88c96f7eTed Kremenek print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io); 278d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek} 279d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek 2802ac58b7c09938bb28c51c7cd2deada609b75f94cTed Kremenek#define MAX_DEPTH 32000 281d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenekstatic int htree_depth(struct dx_dir_info *dx_dir, 282d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek struct dx_dirblock_info *dx_db) 283626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek{ 284d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek int depth = 0; 2854d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose 2864d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) { 2874d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose dx_db = &dx_dir->dx_block[dx_db->parent]; 2884d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose depth++; 2892ac58b7c09938bb28c51c7cd2deada609b75f94cTed Kremenek } 2902ac58b7c09938bb28c51c7cd2deada609b75f94cTed Kremenek return depth; 2914d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose} 2924241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek 29338b02b912e1a55c912f603c4369431264d36a381Zhongxing Xustatic int dict_de_cmp(const void *a, const void *b) 2946800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks{ 2956800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks const struct ext2_dir_entry *de_a, *de_b; 29638b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu int a_len, b_len; 2976800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks 29838b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu de_a = (const struct ext2_dir_entry *) a; 2998bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek a_len = de_a->name_len & 0xFF; 3006800ba622e4edf287801ac69c42c61e7e294b06bAnna Zaks de_b = (const struct ext2_dir_entry *) b; 30138b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu b_len = de_b->name_len & 0xFF; 3021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 30338b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (a_len != b_len) 304c77a55126fcad66fb086f8e100a494caa2496a2dZhongxing Xu return (a_len - b_len); 30538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu 3064a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek return strncmp(de_a->name, de_b->name, a_len); 3074241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek} 3089c378f705405d37f49795d5e915989de774fe11fTed Kremenek 309ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenek/* 310ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenek * This is special sort function that makes sure that directory blocks 311ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenek * with a dirblock of zero are sorted to the beginning of the list. 3124241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * This guarantees that the root node of the htree directories are 3134241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek * processed first, so we know what hash version to use. 3149c378f705405d37f49795d5e915989de774fe11fTed Kremenek */ 315ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenekstatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b) 316ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenek{ 317ede5a4ba111f0590879670b6cb07f4d6d0bd9075Ted Kremenek const struct ext2_db_entry *db_a = 31838b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu (const struct ext2_db_entry *) a; 3199d0064e802e81d0833e8ccab8978b17c0bac3625Ted Kremenek const struct ext2_db_entry *db_b = 3204a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek (const struct ext2_db_entry *) b; 321d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek 322d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek if (db_a->blockcnt && !db_b->blockcnt) 3234241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek return 1; 3244a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 3251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (!db_a->blockcnt && db_b->blockcnt) 32639b4c6c98d391b25c376782cf92346aa88c96f7eTed Kremenek return -1; 32739b4c6c98d391b25c376782cf92346aa88c96f7eTed Kremenek 328c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu if (db_a->blk != db_b->blk) 3294241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek return (int) (db_a->blk - db_b->blk); 33038b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu 33138b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (db_a->ino != db_b->ino) 332626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek return (int) (db_a->ino - db_b->ino); 333626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek 334626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek return (int) (db_a->blockcnt - db_b->blockcnt); 335626719bd2c09e27fe7c182724a812d27f59e3819Ted Kremenek} 33638b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu 33738b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu 3381eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump/* 33938b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu * Make sure the first entry in the directory is '.', and that the 3407ebde953bb050caa69f791fc1de449d435c6a36fTed Kremenek * directory entry is sane. 34138b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu */ 3421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpstatic int check_dot(e2fsck_t ctx, 34338b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu struct ext2_dir_entry *dirent, 3441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ext2_ino_t ino, struct problem_context *pctx) 34538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu{ 3461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump struct ext2_dir_entry *nextdir; 34738b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu unsigned int rec_len, new_len; 3481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump int status = 0; 34938b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu int created = 0; 3501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump int problem = 0; 35138b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu 3521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (!dirent->inode) 3531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump problem = PR_2_MISSING_DOT; 3544241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek else if (((dirent->name_len & 0xFF) != 1) || 35538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu (dirent->name[0] != '.')) 3561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump problem = PR_2_1ST_NOT_DOT; 35738b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu else if (dirent->name[1] != '\0') 3581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump problem = PR_2_DOT_NULL_TERM; 35938b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu 3601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); 36138b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (problem) { 36238b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (fix_problem(ctx, problem, pctx)) { 3635fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek if (rec_len < 12) 3645fe4d9deb543a19f557e3d85c5f33867af97cd96Ted Kremenek rec_len = dirent->rec_len = 12; 36538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu dirent->inode = ino; 36638b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu dirent->name_len = 1; 36738b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu dirent->name[0] = '.'; 368c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu dirent->name[1] = '\0'; 369fe9e543a2a363df7fcaa899367d3b2580b63b27cTed Kremenek status = 1; 37038b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu created = 1; 371cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek } 37238b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu } 37338b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (dirent->inode != ino) { 37438b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) { 37538b02b912e1a55c912f603c4369431264d36a381Zhongxing Xu dirent->inode = ino; 376d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek status = 1; 377d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek } 3782ac58b7c09938bb28c51c7cd2deada609b75f94cTed Kremenek } 3794d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose if (rec_len > 12) { 3804d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose new_len = rec_len - 12; 3814d9e497a2b1eab3b1214848216050c64fc3acfd6Jordan Rose if (new_len > 12) { 382d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek if (created || 383d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) { 384d767d81290288c030f3be0be1d3e62b9c8df51dcTed Kremenek nextdir = (struct ext2_dir_entry *) 3852ac58b7c09938bb28c51c7cd2deada609b75f94cTed Kremenek ((char *) dirent + 12); 386841c96a885789afea9d32d1d842033768c6d2b19Ted Kremenek dirent->rec_len = 12; 387841c96a885789afea9d32d1d842033768c6d2b19Ted Kremenek (void) ext2fs_set_rec_len(ctx->fs, new_len, 388841c96a885789afea9d32d1d842033768c6d2b19Ted Kremenek nextdir); 389841c96a885789afea9d32d1d842033768c6d2b19Ted Kremenek nextdir->inode = 0; 3904241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek nextdir->name_len = 0; 391cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek status = 1; 392f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek } 393c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu } 394f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek } 3951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return status; 396f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek} 3979c378f705405d37f49795d5e915989de774fe11fTed Kremenek 398c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu/* 399f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek * Make sure the second entry in the directory is '..', and that the 400f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek * directory entry is sane. We do not check the inode number of '..' 4011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * here; this gets done in pass 3. 402f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek */ 4031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpstatic int check_dotdot(e2fsck_t ctx, 4049c378f705405d37f49795d5e915989de774fe11fTed Kremenek struct ext2_dir_entry *dirent, 405c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu ext2_ino_t ino, struct problem_context *pctx) 406f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek{ 4071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump int rec_len, problem = 0; 408c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu 409c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu if (!dirent->inode) 410f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek problem = PR_2_MISSING_DOT_DOT; 411fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek else if (((dirent->name_len & 0xFF) != 2) || 412fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek (dirent->name[0] != '.') || 4131aae01a8308d2f8e31adab3f4d7ac35543aac680Anna Zaks (dirent->name[1] != '.')) 414fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek problem = PR_2_2ND_NOT_DOT_DOT; 415fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek else if (dirent->name[2] != '\0') 416fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek problem = PR_2_DOT_DOT_NULL_TERM; 4172d950b15b2b2b650b102ecf0c6b50b45e0cb6a8aAnna Zaks 418fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); 419fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek if (problem) { 420fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek if (fix_problem(ctx, problem, pctx)) { 421fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek if (rec_len < 12) 422fee96e043108b6e24e7d4c5464bf89ac970a7f81Ted Kremenek dirent->rec_len = 12; 4231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump /* 424f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek * Note: we don't have the parent inode just 425f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek * yet, so we will fill it in with the root 4261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * inode. This will get fixed in pass 3. 427f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek */ 428f6f5ef4aaa66b60270e84d1fe1292886369d2f38Ted Kremenek dirent->inode = EXT2_ROOT_INO; 4291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump dirent->name_len = 2; 4301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump dirent->name[0] = '.'; 4315a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis dirent->name[1] = '.'; 4325a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis dirent->name[2] = '\0'; 4334241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek return 1; 4344241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek } 4354a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek return 0; 4364a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 4374a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) { 4389ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenek fix_problem(ctx, PR_2_NO_DIRINFO, pctx); 4399ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenek return -1; 440c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu } 4414a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek return 0; 4421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump} 4434a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 4444a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek/* 4454a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek * Check to make sure a directory entry doesn't contain any illegal 4461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * characters. 4474a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek */ 4484a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenekstatic int check_name(e2fsck_t ctx, 4494a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek struct ext2_dir_entry *dirent, 4501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ext2_ino_t dir_ino EXT2FS_ATTR((unused)), 4514a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek struct problem_context *pctx) 4524a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek{ 4534a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek int i; 4541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump int fixup = -1; 4554a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek int ret = 0; 4564a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 4574a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek for ( i = 0; i < (dirent->name_len & 0xFF); i++) { 4581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (dirent->name[i] == '/' || dirent->name[i] == '\0') { 4594a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (fixup < 0) { 4604a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); 4614a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 4624a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (fixup) { 4631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump dirent->name[i] = '.'; 4649ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenek ret = 1; 4659ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenek } 466c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu } 4674a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 4681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return ret; 4694a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek} 4704a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 4714a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek/* 4721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump * Check the directory filetype (if present) 4734a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek */ 4744a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenekstatic _INLINE_ int check_filetype(e2fsck_t ctx, 4754a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek struct ext2_dir_entry *dirent, 4761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump ext2_ino_t dir_ino EXT2FS_ATTR((unused)), 4774a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek struct problem_context *pctx) 4784a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek{ 4794a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek int filetype = dirent->name_len >> 8; 4801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump int should_be = EXT2_FT_UNKNOWN; 4814a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek struct ext2_inode inode; 4824a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 4834a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (!(ctx->fs->super->s_feature_incompat & 4841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump EXT2_FEATURE_INCOMPAT_FILETYPE)) { 4854a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek if (filetype == 0 || 4864a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx)) 4874a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek return 0; 4884a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek dirent->name_len = dirent->name_len & 0xFF; 4891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return 1; 4904a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek } 4914a0f5f1646637fcf90eb236b5a46f40e5a5dd739Ted Kremenek 4924241b3d1ad87e9a593bbc6cdf0f49435d5aec235Ted Kremenek if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) { 493 should_be = EXT2_FT_DIR; 494 } else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map, 495 dirent->inode)) { 496 should_be = EXT2_FT_REG_FILE; 497 } else if (ctx->inode_bad_map && 498 ext2fs_test_inode_bitmap(ctx->inode_bad_map, 499 dirent->inode)) 500 should_be = 0; 501 else { 502 e2fsck_read_inode(ctx, dirent->inode, &inode, 503 "check_filetype"); 504 should_be = ext2_file_type(inode.i_mode); 505 } 506 if (filetype == should_be) 507 return 0; 508 pctx->num = should_be; 509 510 if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE, 511 pctx) == 0) 512 return 0; 513 514 dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8; 515 return 1; 516} 517 518#ifdef ENABLE_HTREE 519static void parse_int_node(ext2_filsys fs, 520 struct ext2_db_entry *db, 521 struct check_dir_struct *cd, 522 struct dx_dir_info *dx_dir, 523 char *block_buf) 524{ 525 struct ext2_dx_root_info *root; 526 struct ext2_dx_entry *ent; 527 struct ext2_dx_countlimit *limit; 528 struct dx_dirblock_info *dx_db; 529 int i, expect_limit, count; 530 blk_t blk; 531 ext2_dirhash_t min_hash = 0xffffffff; 532 ext2_dirhash_t max_hash = 0; 533 ext2_dirhash_t hash = 0, prev_hash; 534 535 if (db->blockcnt == 0) { 536 root = (struct ext2_dx_root_info *) (block_buf + 24); 537 538#ifdef DX_DEBUG 539 printf("Root node dump:\n"); 540 printf("\t Reserved zero: %u\n", root->reserved_zero); 541 printf("\t Hash Version: %d\n", root->hash_version); 542 printf("\t Info length: %d\n", root->info_length); 543 printf("\t Indirect levels: %d\n", root->indirect_levels); 544 printf("\t Flags: %d\n", root->unused_flags); 545#endif 546 547 ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length); 548 } else { 549 ent = (struct ext2_dx_entry *) (block_buf+8); 550 } 551 limit = (struct ext2_dx_countlimit *) ent; 552 553#ifdef DX_DEBUG 554 printf("Number of entries (count): %d\n", 555 ext2fs_le16_to_cpu(limit->count)); 556 printf("Number of entries (limit): %d\n", 557 ext2fs_le16_to_cpu(limit->limit)); 558#endif 559 560 count = ext2fs_le16_to_cpu(limit->count); 561 expect_limit = (fs->blocksize - ((char *) ent - block_buf)) / 562 sizeof(struct ext2_dx_entry); 563 if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) { 564 cd->pctx.num = ext2fs_le16_to_cpu(limit->limit); 565 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx)) 566 goto clear_and_exit; 567 } 568 if (count > expect_limit) { 569 cd->pctx.num = count; 570 if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx)) 571 goto clear_and_exit; 572 count = expect_limit; 573 } 574 575 for (i=0; i < count; i++) { 576 prev_hash = hash; 577 hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0; 578#ifdef DX_DEBUG 579 printf("Entry #%d: Hash 0x%08x, block %u\n", i, 580 hash, ext2fs_le32_to_cpu(ent[i].block)); 581#endif 582 blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff; 583 /* Check to make sure the block is valid */ 584 if (blk >= (blk_t) dx_dir->numblocks) { 585 cd->pctx.blk = blk; 586 if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK, 587 &cd->pctx)) 588 goto clear_and_exit; 589 continue; 590 } 591 if (hash < prev_hash && 592 fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx)) 593 goto clear_and_exit; 594 dx_db = &dx_dir->dx_block[blk]; 595 if (dx_db->flags & DX_FLAG_REFERENCED) { 596 dx_db->flags |= DX_FLAG_DUP_REF; 597 } else { 598 dx_db->flags |= DX_FLAG_REFERENCED; 599 dx_db->parent = db->blockcnt; 600 } 601 if (hash < min_hash) 602 min_hash = hash; 603 if (hash > max_hash) 604 max_hash = hash; 605 dx_db->node_min_hash = hash; 606 if ((i+1) < count) 607 dx_db->node_max_hash = 608 ext2fs_le32_to_cpu(ent[i+1].hash) & ~1; 609 else { 610 dx_db->node_max_hash = 0xfffffffe; 611 dx_db->flags |= DX_FLAG_LAST; 612 } 613 if (i == 0) 614 dx_db->flags |= DX_FLAG_FIRST; 615 } 616#ifdef DX_DEBUG 617 printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n", 618 db->blockcnt, min_hash, max_hash); 619#endif 620 dx_db = &dx_dir->dx_block[db->blockcnt]; 621 dx_db->min_hash = min_hash; 622 dx_db->max_hash = max_hash; 623 return; 624 625clear_and_exit: 626 clear_htree(cd->ctx, cd->pctx.ino); 627 dx_dir->numblocks = 0; 628} 629#endif /* ENABLE_HTREE */ 630 631/* 632 * Given a busted directory, try to salvage it somehow. 633 * 634 */ 635static void salvage_directory(ext2_filsys fs, 636 struct ext2_dir_entry *dirent, 637 struct ext2_dir_entry *prev, 638 unsigned int *offset) 639{ 640 char *cp = (char *) dirent; 641 int left; 642 unsigned int rec_len, prev_rec_len; 643 unsigned int name_len = dirent->name_len & 0xFF; 644 645 (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 646 left = fs->blocksize - *offset - rec_len; 647 648 /* 649 * Special case of directory entry of size 8: copy what's left 650 * of the directory block up to cover up the invalid hole. 651 */ 652 if ((left >= 12) && (rec_len == 8)) { 653 memmove(cp, cp+8, left); 654 memset(cp + left, 0, 8); 655 return; 656 } 657 /* 658 * If the directory entry overruns the end of the directory 659 * block, and the name is small enough to fit, then adjust the 660 * record length. 661 */ 662 if ((left < 0) && 663 ((int) rec_len + left > 8) && 664 (name_len + 8 <= (int) rec_len + left) && 665 dirent->inode <= fs->super->s_inodes_count && 666 strnlen(dirent->name, name_len) == name_len) { 667 (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent); 668 return; 669 } 670 /* 671 * If the record length of the directory entry is a multiple 672 * of four, and not too big, such that it is valid, let the 673 * previous directory entry absorb the invalid one. 674 */ 675 if (prev && rec_len && (rec_len % 4) == 0 && 676 (*offset + rec_len <= fs->blocksize)) { 677 (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); 678 prev_rec_len += rec_len; 679 (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); 680 *offset += rec_len; 681 return; 682 } 683 /* 684 * Default salvage method --- kill all of the directory 685 * entries for the rest of the block. We will either try to 686 * absorb it into the previous directory entry, or create a 687 * new empty directory entry the rest of the directory block. 688 */ 689 if (prev) { 690 (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); 691 prev_rec_len += fs->blocksize - *offset; 692 (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); 693 *offset = fs->blocksize; 694 } else { 695 rec_len = fs->blocksize - *offset; 696 (void) ext2fs_set_rec_len(fs, rec_len, dirent); 697 dirent->name_len = 0; 698 dirent->inode = 0; 699 } 700} 701 702static int check_dir_block(ext2_filsys fs, 703 struct ext2_db_entry *db, 704 void *priv_data) 705{ 706 struct dx_dir_info *dx_dir; 707#ifdef ENABLE_HTREE 708 struct dx_dirblock_info *dx_db = 0; 709#endif /* ENABLE_HTREE */ 710 struct ext2_dir_entry *dirent, *prev; 711 ext2_dirhash_t hash; 712 unsigned int offset = 0; 713 const char * old_op; 714 int dir_modified = 0; 715 int dot_state; 716 unsigned int rec_len; 717 blk_t block_nr = db->blk; 718 ext2_ino_t ino = db->ino; 719 ext2_ino_t subdir_parent; 720 __u16 links; 721 struct check_dir_struct *cd; 722 char *buf; 723 e2fsck_t ctx; 724 int problem; 725 struct ext2_dx_root_info *root; 726 struct ext2_dx_countlimit *limit; 727 static dict_t de_dict; 728 struct problem_context pctx; 729 int dups_found = 0; 730 int ret; 731 732 cd = (struct check_dir_struct *) priv_data; 733 buf = cd->buf; 734 ctx = cd->ctx; 735 736 if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) 737 return DIRENT_ABORT; 738 739 if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max)) 740 return DIRENT_ABORT; 741 742 /* 743 * Make sure the inode is still in use (could have been 744 * deleted in the duplicate/bad blocks pass. 745 */ 746 if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))) 747 return 0; 748 749 cd->pctx.ino = ino; 750 cd->pctx.blk = block_nr; 751 cd->pctx.blkcount = db->blockcnt; 752 cd->pctx.ino2 = 0; 753 cd->pctx.dirent = 0; 754 cd->pctx.num = 0; 755 756 if (db->blk == 0) { 757 if (allocate_dir_block(ctx, db, buf, &cd->pctx)) 758 return 0; 759 block_nr = db->blk; 760 } 761 762 if (db->blockcnt) 763 dot_state = 2; 764 else 765 dot_state = 0; 766 767 if (ctx->dirs_to_hash && 768 ext2fs_u32_list_test(ctx->dirs_to_hash, ino)) 769 dups_found++; 770 771#if 0 772 printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr, 773 db->blockcnt, ino); 774#endif 775 776 old_op = ehandler_operation(_("reading directory block")); 777 cd->pctx.errcode = ext2fs_read_dir_block(fs, block_nr, buf); 778 ehandler_operation(0); 779 if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED) 780 cd->pctx.errcode = 0; /* We'll handle this ourselves */ 781 if (cd->pctx.errcode) { 782 if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) { 783 ctx->flags |= E2F_FLAG_ABORT; 784 return DIRENT_ABORT; 785 } 786 memset(buf, 0, fs->blocksize); 787 } 788#ifdef ENABLE_HTREE 789 dx_dir = e2fsck_get_dx_dir_info(ctx, ino); 790 if (dx_dir && dx_dir->numblocks) { 791 if (db->blockcnt >= dx_dir->numblocks) { 792 if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK, 793 &pctx)) { 794 clear_htree(ctx, ino); 795 dx_dir->numblocks = 0; 796 dx_db = 0; 797 goto out_htree; 798 } 799 fatal_error(ctx, _("Can not continue.")); 800 } 801 dx_db = &dx_dir->dx_block[db->blockcnt]; 802 dx_db->type = DX_DIRBLOCK_LEAF; 803 dx_db->phys = block_nr; 804 dx_db->min_hash = ~0; 805 dx_db->max_hash = 0; 806 807 dirent = (struct ext2_dir_entry *) buf; 808 (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 809 limit = (struct ext2_dx_countlimit *) (buf+8); 810 if (db->blockcnt == 0) { 811 root = (struct ext2_dx_root_info *) (buf + 24); 812 dx_db->type = DX_DIRBLOCK_ROOT; 813 dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST; 814 if ((root->reserved_zero || 815 root->info_length < 8 || 816 root->indirect_levels > 1) && 817 fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) { 818 clear_htree(ctx, ino); 819 dx_dir->numblocks = 0; 820 dx_db = 0; 821 } 822 dx_dir->hashversion = root->hash_version; 823 if ((dx_dir->hashversion <= EXT2_HASH_TEA) && 824 (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)) 825 dx_dir->hashversion += 3; 826 dx_dir->depth = root->indirect_levels + 1; 827 } else if ((dirent->inode == 0) && 828 (rec_len == fs->blocksize) && 829 (dirent->name_len == 0) && 830 (ext2fs_le16_to_cpu(limit->limit) == 831 ((fs->blocksize-8) / 832 sizeof(struct ext2_dx_entry)))) 833 dx_db->type = DX_DIRBLOCK_NODE; 834 } 835out_htree: 836#endif /* ENABLE_HTREE */ 837 838 dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp); 839 prev = 0; 840 do { 841 int group; 842 ext2_ino_t first_unused_inode; 843 844 problem = 0; 845 dirent = (struct ext2_dir_entry *) (buf + offset); 846 (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 847 cd->pctx.dirent = dirent; 848 cd->pctx.num = offset; 849 if (((offset + rec_len) > fs->blocksize) || 850 (rec_len < 12) || 851 ((rec_len % 4) != 0) || 852 (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) { 853 if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { 854 salvage_directory(fs, dirent, prev, &offset); 855 dir_modified++; 856 continue; 857 } else 858 goto abort_free_dict; 859 } 860 if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) { 861 if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) { 862 dirent->name_len = EXT2_NAME_LEN; 863 dir_modified++; 864 } 865 } 866 867 if (dot_state == 0) { 868 if (check_dot(ctx, dirent, ino, &cd->pctx)) 869 dir_modified++; 870 } else if (dot_state == 1) { 871 ret = check_dotdot(ctx, dirent, ino, &cd->pctx); 872 if (ret < 0) 873 goto abort_free_dict; 874 if (ret) 875 dir_modified++; 876 } else if (dirent->inode == ino) { 877 problem = PR_2_LINK_DOT; 878 if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) { 879 dirent->inode = 0; 880 dir_modified++; 881 goto next; 882 } 883 } 884 if (!dirent->inode) 885 goto next; 886 887 /* 888 * Make sure the inode listed is a legal one. 889 */ 890 if (((dirent->inode != EXT2_ROOT_INO) && 891 (dirent->inode < EXT2_FIRST_INODE(fs->super))) || 892 (dirent->inode > fs->super->s_inodes_count)) { 893 problem = PR_2_BAD_INO; 894 } else if (ctx->inode_bb_map && 895 (ext2fs_test_inode_bitmap(ctx->inode_bb_map, 896 dirent->inode))) { 897 /* 898 * If the inode is in a bad block, offer to 899 * clear it. 900 */ 901 problem = PR_2_BB_INODE; 902 } else if ((dot_state > 1) && 903 ((dirent->name_len & 0xFF) == 1) && 904 (dirent->name[0] == '.')) { 905 /* 906 * If there's a '.' entry in anything other 907 * than the first directory entry, it's a 908 * duplicate entry that should be removed. 909 */ 910 problem = PR_2_DUP_DOT; 911 } else if ((dot_state > 1) && 912 ((dirent->name_len & 0xFF) == 2) && 913 (dirent->name[0] == '.') && 914 (dirent->name[1] == '.')) { 915 /* 916 * If there's a '..' entry in anything other 917 * than the second directory entry, it's a 918 * duplicate entry that should be removed. 919 */ 920 problem = PR_2_DUP_DOT_DOT; 921 } else if ((dot_state > 1) && 922 (dirent->inode == EXT2_ROOT_INO)) { 923 /* 924 * Don't allow links to the root directory. 925 * We check this specially to make sure we 926 * catch this error case even if the root 927 * directory hasn't been created yet. 928 */ 929 problem = PR_2_LINK_ROOT; 930 } else if ((dot_state > 1) && 931 (dirent->name_len & 0xFF) == 0) { 932 /* 933 * Don't allow zero-length directory names. 934 */ 935 problem = PR_2_NULL_NAME; 936 } 937 938 if (problem) { 939 if (fix_problem(ctx, problem, &cd->pctx)) { 940 dirent->inode = 0; 941 dir_modified++; 942 goto next; 943 } else { 944 ext2fs_unmark_valid(fs); 945 if (problem == PR_2_BAD_INO) 946 goto next; 947 } 948 } 949 950 /* 951 * If the inode was marked as having bad fields in 952 * pass1, process it and offer to fix/clear it. 953 * (We wait until now so that we can display the 954 * pathname to the user.) 955 */ 956 if (ctx->inode_bad_map && 957 ext2fs_test_inode_bitmap(ctx->inode_bad_map, 958 dirent->inode)) { 959 if (e2fsck_process_bad_inode(ctx, ino, 960 dirent->inode, 961 buf + fs->blocksize)) { 962 dirent->inode = 0; 963 dir_modified++; 964 goto next; 965 } 966 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 967 return DIRENT_ABORT; 968 } 969 970 group = ext2fs_group_of_ino(fs, dirent->inode); 971 first_unused_inode = group * fs->super->s_inodes_per_group + 972 1 + fs->super->s_inodes_per_group - 973 fs->group_desc[group].bg_itable_unused; 974 cd->pctx.group = group; 975 976 /* 977 * Check if the inode was missed out because 978 * _INODE_UNINIT flag was set or bg_itable_unused was 979 * incorrect. If so, clear the _INODE_UNINIT flag and 980 * restart e2fsck. In the future it would be nice if 981 * we could call a function in pass1.c that checks the 982 * newly visible inodes. 983 */ 984 if (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT) { 985 pctx.num = dirent->inode; 986 if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT, 987 &cd->pctx)){ 988 fs->group_desc[group].bg_flags &= 989 ~EXT2_BG_INODE_UNINIT; 990 ext2fs_mark_super_dirty(fs); 991 ctx->flags |= E2F_FLAG_RESTART_LATER; 992 } else { 993 ext2fs_unmark_valid(fs); 994 if (problem == PR_2_BAD_INO) 995 goto next; 996 } 997 } else if (dirent->inode >= first_unused_inode) { 998 pctx.num = dirent->inode; 999 if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){ 1000 fs->group_desc[group].bg_itable_unused = 0; 1001 ext2fs_mark_super_dirty(fs); 1002 ctx->flags |= E2F_FLAG_RESTART_LATER; 1003 } else { 1004 ext2fs_unmark_valid(fs); 1005 if (problem == PR_2_BAD_INO) 1006 goto next; 1007 } 1008 } 1009 1010 /* 1011 * Offer to clear unused inodes; if we are going to be 1012 * restarting the scan due to bg_itable_unused being 1013 * wrong, then don't clear any inodes to avoid zapping 1014 * inodes that were skipped during pass1 due to an 1015 * incorrect bg_itable_unused; we'll get any real 1016 * problems after we restart. 1017 */ 1018 if (!(ctx->flags & E2F_FLAG_RESTART_LATER) && 1019 !(ext2fs_test_inode_bitmap(ctx->inode_used_map, 1020 dirent->inode))) 1021 problem = PR_2_UNUSED_INODE; 1022 1023 if (problem) { 1024 if (fix_problem(ctx, problem, &cd->pctx)) { 1025 dirent->inode = 0; 1026 dir_modified++; 1027 goto next; 1028 } else { 1029 ext2fs_unmark_valid(fs); 1030 if (problem == PR_2_BAD_INO) 1031 goto next; 1032 } 1033 } 1034 1035 if (check_name(ctx, dirent, ino, &cd->pctx)) 1036 dir_modified++; 1037 1038 if (check_filetype(ctx, dirent, ino, &cd->pctx)) 1039 dir_modified++; 1040 1041#ifdef ENABLE_HTREE 1042 if (dx_db) { 1043 ext2fs_dirhash(dx_dir->hashversion, dirent->name, 1044 (dirent->name_len & 0xFF), 1045 fs->super->s_hash_seed, &hash, 0); 1046 if (hash < dx_db->min_hash) 1047 dx_db->min_hash = hash; 1048 if (hash > dx_db->max_hash) 1049 dx_db->max_hash = hash; 1050 } 1051#endif 1052 1053 /* 1054 * If this is a directory, then mark its parent in its 1055 * dir_info structure. If the parent field is already 1056 * filled in, then this directory has more than one 1057 * hard link. We assume the first link is correct, 1058 * and ask the user if he/she wants to clear this one. 1059 */ 1060 if ((dot_state > 1) && 1061 (ext2fs_test_inode_bitmap(ctx->inode_dir_map, 1062 dirent->inode))) { 1063 if (e2fsck_dir_info_get_parent(ctx, dirent->inode, 1064 &subdir_parent)) { 1065 cd->pctx.ino = dirent->inode; 1066 fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx); 1067 goto abort_free_dict; 1068 } 1069 if (subdir_parent) { 1070 cd->pctx.ino2 = subdir_parent; 1071 if (fix_problem(ctx, PR_2_LINK_DIR, 1072 &cd->pctx)) { 1073 dirent->inode = 0; 1074 dir_modified++; 1075 goto next; 1076 } 1077 cd->pctx.ino2 = 0; 1078 } else { 1079 (void) e2fsck_dir_info_set_parent(ctx, 1080 dirent->inode, ino); 1081 } 1082 } 1083 1084 if (dups_found) { 1085 ; 1086 } else if (dict_lookup(&de_dict, dirent)) { 1087 clear_problem_context(&pctx); 1088 pctx.ino = ino; 1089 pctx.dirent = dirent; 1090 fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx); 1091 if (!ctx->dirs_to_hash) 1092 ext2fs_u32_list_create(&ctx->dirs_to_hash, 50); 1093 if (ctx->dirs_to_hash) 1094 ext2fs_u32_list_add(ctx->dirs_to_hash, ino); 1095 dups_found++; 1096 } else 1097 dict_alloc_insert(&de_dict, dirent, dirent); 1098 1099 ext2fs_icount_increment(ctx->inode_count, dirent->inode, 1100 &links); 1101 if (links > 1) 1102 ctx->fs_links_count++; 1103 ctx->fs_total_count++; 1104 next: 1105 prev = dirent; 1106 if (dir_modified) 1107 (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 1108 offset += rec_len; 1109 dot_state++; 1110 } while (offset < fs->blocksize); 1111#if 0 1112 printf("\n"); 1113#endif 1114#ifdef ENABLE_HTREE 1115 if (dx_db) { 1116#ifdef DX_DEBUG 1117 printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n", 1118 db->blockcnt, dx_db->type, 1119 dx_db->min_hash, dx_db->max_hash); 1120#endif 1121 cd->pctx.dir = cd->pctx.ino; 1122 if ((dx_db->type == DX_DIRBLOCK_ROOT) || 1123 (dx_db->type == DX_DIRBLOCK_NODE)) 1124 parse_int_node(fs, db, cd, dx_dir, buf); 1125 } 1126#endif /* ENABLE_HTREE */ 1127 if (offset != fs->blocksize) { 1128 cd->pctx.num = rec_len - fs->blocksize + offset; 1129 if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) { 1130 dirent->rec_len = cd->pctx.num; 1131 dir_modified++; 1132 } 1133 } 1134 if (dir_modified) { 1135 cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf); 1136 if (cd->pctx.errcode) { 1137 if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK, 1138 &cd->pctx)) 1139 goto abort_free_dict; 1140 } 1141 ext2fs_mark_changed(fs); 1142 } 1143 dict_free_nodes(&de_dict); 1144 return 0; 1145abort_free_dict: 1146 ctx->flags |= E2F_FLAG_ABORT; 1147 dict_free_nodes(&de_dict); 1148 return DIRENT_ABORT; 1149} 1150 1151/* 1152 * This function is called to deallocate a block, and is an interator 1153 * functioned called by deallocate inode via ext2fs_iterate_block(). 1154 */ 1155static int deallocate_inode_block(ext2_filsys fs, 1156 blk_t *block_nr, 1157 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1158 blk_t ref_block EXT2FS_ATTR((unused)), 1159 int ref_offset EXT2FS_ATTR((unused)), 1160 void *priv_data) 1161{ 1162 e2fsck_t ctx = (e2fsck_t) priv_data; 1163 1164 if (HOLE_BLKADDR(*block_nr)) 1165 return 0; 1166 if ((*block_nr < fs->super->s_first_data_block) || 1167 (*block_nr >= fs->super->s_blocks_count)) 1168 return 0; 1169 ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); 1170 ext2fs_block_alloc_stats(fs, *block_nr, -1); 1171 return 0; 1172} 1173 1174/* 1175 * This fuction deallocates an inode 1176 */ 1177static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) 1178{ 1179 ext2_filsys fs = ctx->fs; 1180 struct ext2_inode inode; 1181 struct problem_context pctx; 1182 __u32 count; 1183 1184 e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); 1185 e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); 1186 clear_problem_context(&pctx); 1187 pctx.ino = ino; 1188 1189 /* 1190 * Fix up the bitmaps... 1191 */ 1192 e2fsck_read_bitmaps(ctx); 1193 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); 1194 1195 if (inode.i_file_acl && 1196 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { 1197 pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl, 1198 block_buf, -1, &count); 1199 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { 1200 pctx.errcode = 0; 1201 count = 1; 1202 } 1203 if (pctx.errcode) { 1204 pctx.blk = inode.i_file_acl; 1205 fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); 1206 ctx->flags |= E2F_FLAG_ABORT; 1207 return; 1208 } 1209 if (count == 0) { 1210 ext2fs_unmark_block_bitmap(ctx->block_found_map, 1211 inode.i_file_acl); 1212 ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1); 1213 } 1214 inode.i_file_acl = 0; 1215 } 1216 1217 if (!ext2fs_inode_has_valid_blocks(&inode)) 1218 return; 1219 1220 if (LINUX_S_ISREG(inode.i_mode) && 1221 (inode.i_size_high || inode.i_size & 0x80000000UL)) 1222 ctx->large_files--; 1223 1224 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, 1225 deallocate_inode_block, ctx); 1226 if (pctx.errcode) { 1227 fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); 1228 ctx->flags |= E2F_FLAG_ABORT; 1229 return; 1230 } 1231} 1232 1233/* 1234 * This fuction clears the htree flag on an inode 1235 */ 1236static void clear_htree(e2fsck_t ctx, ext2_ino_t ino) 1237{ 1238 struct ext2_inode inode; 1239 1240 e2fsck_read_inode(ctx, ino, &inode, "clear_htree"); 1241 inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL; 1242 e2fsck_write_inode(ctx, ino, &inode, "clear_htree"); 1243 if (ctx->dirs_to_hash) 1244 ext2fs_u32_list_add(ctx->dirs_to_hash, ino); 1245} 1246 1247 1248extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, 1249 ext2_ino_t ino, char *buf) 1250{ 1251 ext2_filsys fs = ctx->fs; 1252 struct ext2_inode inode; 1253 int inode_modified = 0; 1254 int not_fixed = 0; 1255 unsigned char *frag, *fsize; 1256 struct problem_context pctx; 1257 int problem = 0; 1258 1259 e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode"); 1260 1261 clear_problem_context(&pctx); 1262 pctx.ino = ino; 1263 pctx.dir = dir; 1264 pctx.inode = &inode; 1265 1266 if (inode.i_file_acl && 1267 !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { 1268 if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) { 1269 inode.i_file_acl = 0; 1270 inode_modified++; 1271 } else 1272 not_fixed++; 1273 } 1274 1275 if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) && 1276 !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) && 1277 !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) && 1278 !(LINUX_S_ISSOCK(inode.i_mode))) 1279 problem = PR_2_BAD_MODE; 1280 else if (LINUX_S_ISCHR(inode.i_mode) 1281 && !e2fsck_pass1_check_device_inode(fs, &inode)) 1282 problem = PR_2_BAD_CHAR_DEV; 1283 else if (LINUX_S_ISBLK(inode.i_mode) 1284 && !e2fsck_pass1_check_device_inode(fs, &inode)) 1285 problem = PR_2_BAD_BLOCK_DEV; 1286 else if (LINUX_S_ISFIFO(inode.i_mode) 1287 && !e2fsck_pass1_check_device_inode(fs, &inode)) 1288 problem = PR_2_BAD_FIFO; 1289 else if (LINUX_S_ISSOCK(inode.i_mode) 1290 && !e2fsck_pass1_check_device_inode(fs, &inode)) 1291 problem = PR_2_BAD_SOCKET; 1292 else if (LINUX_S_ISLNK(inode.i_mode) 1293 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) { 1294 problem = PR_2_INVALID_SYMLINK; 1295 } 1296 1297 if (problem) { 1298 if (fix_problem(ctx, problem, &pctx)) { 1299 deallocate_inode(ctx, ino, 0); 1300 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1301 return 0; 1302 return 1; 1303 } else 1304 not_fixed++; 1305 problem = 0; 1306 } 1307 1308 if (inode.i_faddr) { 1309 if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) { 1310 inode.i_faddr = 0; 1311 inode_modified++; 1312 } else 1313 not_fixed++; 1314 } 1315 1316 switch (fs->super->s_creator_os) { 1317 case EXT2_OS_HURD: 1318 frag = &inode.osd2.hurd2.h_i_frag; 1319 fsize = &inode.osd2.hurd2.h_i_fsize; 1320 break; 1321 default: 1322 frag = fsize = 0; 1323 } 1324 if (frag && *frag) { 1325 pctx.num = *frag; 1326 if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) { 1327 *frag = 0; 1328 inode_modified++; 1329 } else 1330 not_fixed++; 1331 pctx.num = 0; 1332 } 1333 if (fsize && *fsize) { 1334 pctx.num = *fsize; 1335 if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) { 1336 *fsize = 0; 1337 inode_modified++; 1338 } else 1339 not_fixed++; 1340 pctx.num = 0; 1341 } 1342 1343 if ((fs->super->s_creator_os == EXT2_OS_LINUX) && 1344 !(fs->super->s_feature_ro_compat & 1345 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && 1346 (inode.osd2.linux2.l_i_blocks_hi != 0)) { 1347 pctx.num = inode.osd2.linux2.l_i_blocks_hi; 1348 if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) { 1349 inode.osd2.linux2.l_i_blocks_hi = 0; 1350 inode_modified++; 1351 } 1352 } 1353 1354 if (!(fs->super->s_feature_incompat & 1355 EXT4_FEATURE_INCOMPAT_64BIT) && 1356 inode.osd2.linux2.l_i_file_acl_high != 0) { 1357 pctx.num = inode.osd2.linux2.l_i_file_acl_high; 1358 if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) { 1359 inode.osd2.linux2.l_i_file_acl_high = 0; 1360 inode_modified++; 1361 } else 1362 not_fixed++; 1363 } 1364 1365 if (inode.i_file_acl && 1366 ((inode.i_file_acl < fs->super->s_first_data_block) || 1367 (inode.i_file_acl >= fs->super->s_blocks_count))) { 1368 if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) { 1369 inode.i_file_acl = 0; 1370 inode_modified++; 1371 } else 1372 not_fixed++; 1373 } 1374 if (inode.i_dir_acl && 1375 LINUX_S_ISDIR(inode.i_mode)) { 1376 if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) { 1377 inode.i_dir_acl = 0; 1378 inode_modified++; 1379 } else 1380 not_fixed++; 1381 } 1382 1383 if (inode_modified) 1384 e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode"); 1385 if (!not_fixed && ctx->inode_bad_map) 1386 ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); 1387 return 0; 1388} 1389 1390 1391/* 1392 * allocate_dir_block --- this function allocates a new directory 1393 * block for a particular inode; this is done if a directory has 1394 * a "hole" in it, or if a directory has a illegal block number 1395 * that was zeroed out and now needs to be replaced. 1396 */ 1397static int allocate_dir_block(e2fsck_t ctx, 1398 struct ext2_db_entry *db, 1399 char *buf EXT2FS_ATTR((unused)), 1400 struct problem_context *pctx) 1401{ 1402 ext2_filsys fs = ctx->fs; 1403 blk_t blk; 1404 char *block; 1405 struct ext2_inode inode; 1406 1407 if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0) 1408 return 1; 1409 1410 /* 1411 * Read the inode and block bitmaps in; we'll be messing with 1412 * them. 1413 */ 1414 e2fsck_read_bitmaps(ctx); 1415 1416 /* 1417 * First, find a free block 1418 */ 1419 pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); 1420 if (pctx->errcode) { 1421 pctx->str = "ext2fs_new_block"; 1422 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 1423 return 1; 1424 } 1425 ext2fs_mark_block_bitmap(ctx->block_found_map, blk); 1426 ext2fs_mark_block_bitmap(fs->block_map, blk); 1427 ext2fs_mark_bb_dirty(fs); 1428 1429 /* 1430 * Now let's create the actual data block for the inode 1431 */ 1432 if (db->blockcnt) 1433 pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block); 1434 else 1435 pctx->errcode = ext2fs_new_dir_block(fs, db->ino, 1436 EXT2_ROOT_INO, &block); 1437 1438 if (pctx->errcode) { 1439 pctx->str = "ext2fs_new_dir_block"; 1440 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 1441 return 1; 1442 } 1443 1444 pctx->errcode = ext2fs_write_dir_block(fs, blk, block); 1445 ext2fs_free_mem(&block); 1446 if (pctx->errcode) { 1447 pctx->str = "ext2fs_write_dir_block"; 1448 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 1449 return 1; 1450 } 1451 1452 /* 1453 * Update the inode block count 1454 */ 1455 e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block"); 1456 ext2fs_iblk_add_blocks(fs, &inode, 1); 1457 if (inode.i_size < (db->blockcnt+1) * fs->blocksize) 1458 inode.i_size = (db->blockcnt+1) * fs->blocksize; 1459 e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block"); 1460 1461 /* 1462 * Finally, update the block pointers for the inode 1463 */ 1464 db->blk = blk; 1465 pctx->errcode = ext2fs_bmap(fs, db->ino, &inode, 0, BMAP_SET, 1466 db->blockcnt, &blk); 1467 if (pctx->errcode) { 1468 pctx->str = "ext2fs_block_iterate"; 1469 fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 1470 return 1; 1471 } 1472 1473 return 0; 1474} 1475