13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass2.c --- check directory structure 3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o 521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * 621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header% 721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public 821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License. 921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header% 10efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 of e2fsck iterates through all active directory inodes, and 123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * applies to following tests to each directory entry in the directory 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * blocks in the inodes: 143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The length of the directory entry (rec_len) should be at 163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * least 8 bytes, and no more than the remaining space 173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * left in the directory block. 183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The length of the name in the directory entry (name_len) 19efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * should be less than (rec_len - 8). 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode number in the directory entry should be within 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * legal bounds. 223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode number should refer to a in-use inode. 233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The first entry should be '.', and its inode should be 243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * the inode of the directory. 253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The second entry should be '..'. 263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * To minimize disk seek time, the directory blocks are processed in 283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * sorted order of block numbers. 293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 also collects the following information: 313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode numbers of the subdirectories for each directory. 323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 relies on the following information from previous passes: 343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The directory information collected in pass 1. 353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode_used_map bitmap 363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode_bad_map bitmap 373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode_dir_map bitmap 383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Pass 2 frees the following data structures 403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * - The inode_bad_map bitmap 41aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * - The inode_reg_map bitmap 423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 44b969b1b8a5c13992cadb026114731958644540d8Matthias Andree#define _GNU_SOURCE 1 /* get strnlen() */ 45d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h" 4648e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o#include <string.h> 4748e6e81362f264aee4f3945c14928efaf71a06c9Theodore Ts'o 483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "e2fsck.h" 4921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "problem.h" 503dca12fb62448f52663c859a089244d9cf37c5e3Theodore Ts'o#include "support/dict.h" 513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 52aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#ifdef NO_INLINE_FUNCS 53aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_ 54aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#else 55aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#define _INLINE_ inline 56aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o#endif 57aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 58ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o/* #define DX_DEBUG */ 598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Keeps track of how many times an inode is referenced. 623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 634035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf); 64a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wongstatic int check_dir_block2(ext2_filsys fs, 65a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong struct ext2_db_entry2 *dir_blocks_info, 66a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong void *priv_data); 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs, 686dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson struct ext2_db_entry2 *dir_blocks_info, 6954dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o void *priv_data); 701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx, 716dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson struct ext2_db_entry2 *dir_blocks_info, 7221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o char *buf, struct problem_context *pctx); 738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino); 74ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir, 75ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o struct dx_dirblock_info *dx_db); 76ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b); 773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ostruct check_dir_struct { 7921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o char *buf; 8021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct problem_context pctx; 81f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o int count, max; 821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o e2fsck_t ctx; 83a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong unsigned long long list_offset; 84a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong unsigned long long ra_entries; 85a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong unsigned long long next_ra_off; 86efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o}; 8721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 8808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'ovoid e2fsck_pass2(e2fsck_t ctx) 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 90a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o struct ext2_super_block *sb = ctx->fs->super; 91a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o struct problem_context pctx; 92a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o ext2_filsys fs = ctx->fs; 93a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o char *buf; 948bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#ifdef RESOURCE_TRACK 953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct resource_track rtrack; 968bf191e8660939687ef35c013066d2082cb16722Theodore Ts'o#endif 9721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct check_dir_struct cd; 988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct dx_dir_info *dx_dir; 998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct dx_dirblock_info *dx_db, *dx_parent; 100544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int b; 101ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o int i, depth; 1028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o problem_t code; 1038fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o int bad_dir; 104a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong int (*check_dir_func)(ext2_filsys fs, 105a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong struct ext2_db_entry2 *dir_blocks_info, 106a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong void *priv_data); 1078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 1086d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o init_resource_track(&rtrack, ctx->fs->io); 1091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&cd.pctx); 1101b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#ifdef MTRACE 1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o mtrace_print("Pass 2"); 1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (!(ctx->options & E2F_OPT_PREEN)) 1161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx); 1171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 118749f07121d9c98c317987a87f44c458745f39f15Theodore Ts'o cd.pctx.errcode = e2fsck_setup_icount(ctx, "inode_count", 119749f07121d9c98c317987a87f44c458745f39f15Theodore Ts'o EXT2_ICOUNT_OPT_INCREMENT, 120749f07121d9c98c317987a87f44c458745f39f15Theodore Ts'o ctx->inode_link_info, &ctx->inode_count); 1211b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (cd.pctx.errcode) { 1221b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx); 12308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 12408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 12521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 126bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize, 12754dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o "directory scan buffer"); 1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 12921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o /* 13021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Set up the parent pointer for the root directory, if 13121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * present. (If the root directory is not present, we will 13221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * create it in pass 3.) 13321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o */ 13428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o (void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); 13521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 13621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd.buf = buf; 1371b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o cd.ctx = ctx; 138f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o cd.count = 1; 1396dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson cd.max = ext2fs_dblist_count2(fs->dblist); 140a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd.list_offset = 0; 141a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize; 142a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd.next_ra_off = 0; 143f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 144f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (ctx->progress) 145f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o (void) (ctx->progress)(ctx, 2, 0, cd.max); 146ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o 14786f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (ext2fs_has_feature_dir_index(fs->super)) 1486dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp); 149efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 150a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block; 151a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func, 1526dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson &cd); 1536267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger if (ctx->flags & E2F_FLAG_RESTART_LATER) { 1546267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger ctx->flags |= E2F_FLAG_RESTART; 155db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger ctx->flags &= ~E2F_FLAG_RESTART_LATER; 1566267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger } 1576267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger 158db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger if (ctx->flags & E2F_FLAG_RUN_RETURN) 159db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger return; 160db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger 1611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (cd.pctx.errcode) { 1621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); 16308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 16408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 1657ac02a5ebddcc6187c893eedc80d92777b399575Theodore Ts'o } 1668fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 1678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { 1684cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1694cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o return; 170d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong if (e2fsck_dir_will_be_rehashed(ctx, dx_dir->ino) || 171d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong dx_dir->numblocks == 0) 1728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o continue; 1738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o clear_problem_context(&pctx); 1748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o bad_dir = 0; 1758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.dir = dx_dir->ino; 1768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db = dx_dir->dx_block; 1778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (dx_db->flags & DX_FLAG_REFERENCED) 1788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_DUP_REF; 1798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o else 1808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_REFERENCED; 1818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o /* 1828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * Find all of the first and last leaf blocks, and 1838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * update their parent's min and max hash values 1848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */ 1858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o for (b=0, dx_db = dx_dir->dx_block; 1868fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o b < dx_dir->numblocks; 1878fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o b++, dx_db++) { 1888fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if ((dx_db->type != DX_DIRBLOCK_LEAF) || 1898fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST))) 1908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o continue; 1918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_parent = &dx_dir->dx_block[dx_db->parent]; 1928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o /* 1938fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * XXX Make sure dx_parent->min_hash > dx_db->min_hash 1948fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */ 1958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (dx_db->flags & DX_FLAG_FIRST) 1968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_parent->min_hash = dx_db->min_hash; 1978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o /* 1988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * XXX Make sure dx_parent->max_hash < dx_db->max_hash 1998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */ 2008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (dx_db->flags & DX_FLAG_LAST) 2018fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_parent->max_hash = dx_db->max_hash; 2028fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 203efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 2048fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o for (b=0, dx_db = dx_dir->dx_block; 2058fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o b < dx_dir->numblocks; 2068fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o b++, dx_db++) { 2078fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.blkcount = b; 2088fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.group = dx_db->parent; 2098fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o code = 0; 2108fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (!(dx_db->flags & DX_FLAG_FIRST) && 2118fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o (dx_db->min_hash < dx_db->node_min_hash)) { 2128fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.blk = dx_db->min_hash; 2138fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.blk2 = dx_db->node_min_hash; 2148fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o code = PR_2_HTREE_MIN_HASH; 2158fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o fix_problem(ctx, code, &pctx); 2168fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o bad_dir++; 2178fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 218ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o if (dx_db->type == DX_DIRBLOCK_LEAF) { 219ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o depth = htree_depth(dx_dir, dx_db); 220ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o if (depth != dx_dir->depth) { 221e5e12db959d3c18f6cf4ac938a14f68be0a89accAndreas Dilger pctx.num = dx_dir->depth; 222ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o code = PR_2_HTREE_BAD_DEPTH; 223ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o fix_problem(ctx, code, &pctx); 224ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o bad_dir++; 225ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o } 226ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o } 2278fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o /* 228efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * This test doesn't apply for the root block 2298fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * at block #0 2308fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */ 2318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (b && 2328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o (dx_db->max_hash > dx_db->node_max_hash)) { 2338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.blk = dx_db->max_hash; 2348fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o pctx.blk2 = dx_db->node_max_hash; 2358fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o code = PR_2_HTREE_MAX_HASH; 2368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o fix_problem(ctx, code, &pctx); 237503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3Theodore Ts'o bad_dir++; 2388fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 2398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (!(dx_db->flags & DX_FLAG_REFERENCED)) { 2408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o code = PR_2_HTREE_NOTREF; 2418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o fix_problem(ctx, code, &pctx); 2428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o bad_dir++; 2438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } else if (dx_db->flags & DX_FLAG_DUP_REF) { 2448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o code = PR_2_HTREE_DUPREF; 2458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o fix_problem(ctx, code, &pctx); 2468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o bad_dir++; 2478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 2488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 2498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) { 2508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o clear_htree(ctx, dx_dir->ino); 25162acaa1de132a808949d71264731bba7fe095705Theodore Ts'o dx_dir->numblocks = 0; 2528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 2538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 25423f75f6efaac6b756e0f3e4e1d33b6798347f66aTheodore Ts'o e2fsck_free_dx_dir_info(ctx); 255149640fabcf140d8ede596b06ff8c191ca23cacaTheodore Ts'o 256c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&buf); 25721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o ext2fs_free_dblist(fs->dblist); 25821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 2591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (ctx->inode_bad_map) { 2601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_free_inode_bitmap(ctx->inode_bad_map); 2611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx->inode_bad_map = 0; 2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 263aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o if (ctx->inode_reg_map) { 264aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o ext2fs_free_inode_bitmap(ctx->inode_reg_map); 265aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o ctx->inode_reg_map = 0; 266aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o } 267dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o if (ctx->encrypted_dirs) { 268dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o ext2fs_u32_list_free(ctx->encrypted_dirs); 269dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o ctx->encrypted_dirs = 0; 270dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o } 271a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o 272a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o clear_problem_context(&pctx); 273a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o if (ctx->large_files) { 27486f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (!ext2fs_has_feature_large_file(sb) && 275a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) { 27686f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong ext2fs_set_feature_large_file(sb); 2770cfce7f749ea519522929d91e705cf90518594c4Theodore Ts'o fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 278a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o ext2fs_mark_super_dirty(fs); 279a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o } 280a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o if (sb->s_rev_level == EXT2_GOOD_OLD_REV && 281a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) { 282a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o ext2fs_update_dynamic_rev(fs); 283a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o ext2fs_mark_super_dirty(fs); 284a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o } 285a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o } 286efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 2879facd076ae8af6e908e228392cea866ce0faf1bcKen Chen print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io); 2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 290ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o#define MAX_DEPTH 32000 291ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic int htree_depth(struct dx_dir_info *dx_dir, 292ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o struct dx_dirblock_info *dx_db) 293ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o{ 294ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o int depth = 0; 295ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o 296ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o while (dx_db->type != DX_DIRBLOCK_ROOT && depth < MAX_DEPTH) { 297ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o dx_db = &dx_dir->dx_block[dx_db->parent]; 298ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o depth++; 299ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o } 300ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o return depth; 301ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o} 302ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o 3030926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'ostatic int dict_de_cmp(const void *a, const void *b) 3040926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o{ 305520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o const struct ext2_dir_entry *de_a, *de_b; 3060926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o int a_len, b_len; 3070926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o 308520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o de_a = (const struct ext2_dir_entry *) a; 30970f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara a_len = ext2fs_dirent_name_len(de_a); 310520ead378ec5ddef828a8d206434cc3a444b2e9eTheodore Ts'o de_b = (const struct ext2_dir_entry *) b; 31170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara b_len = ext2fs_dirent_name_len(de_b); 3120926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o 3130926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o if (a_len != b_len) 3140926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o return (a_len - b_len); 3150926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o 316baa14bd17fb7f83b8f95e32318a7319a762ce000Theodore Ts'o return memcmp(de_a->name, de_b->name, a_len); 3170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o} 318ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o 3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 320ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This is special sort function that makes sure that directory blocks 321ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * with a dirblock of zero are sorted to the beginning of the list. 322ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * This guarantees that the root node of the htree directories are 323ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o * processed first, so we know what hash version to use. 324ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o */ 325ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'ostatic EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b) 326ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o{ 3276dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson const struct ext2_db_entry2 *db_a = 3286dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson (const struct ext2_db_entry2 *) a; 3296dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson const struct ext2_db_entry2 *db_b = 3306dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson (const struct ext2_db_entry2 *) b; 331ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o 332ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o if (db_a->blockcnt && !db_b->blockcnt) 333ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o return 1; 334ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o 335ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o if (!db_a->blockcnt && db_b->blockcnt) 336ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o return -1; 337efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 338ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o if (db_a->blk != db_b->blk) 339ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o return (int) (db_a->blk - db_b->blk); 340efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 341ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o if (db_a->ino != db_b->ino) 342ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o return (int) (db_a->ino - db_b->ino); 343ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o 344ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o return (int) (db_a->blockcnt - db_b->blockcnt); 345ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o} 346ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o 347ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o 348ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o/* 3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the first entry in the directory is '.', and that the 3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane. 3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 3521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dot(e2fsck_t ctx, 3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_dir_entry *dirent, 35486c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t ino, struct problem_context *pctx) 3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_dir_entry *nextdir; 3578a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o unsigned int rec_len, new_len; 3583c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o int status = 0; 3593c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o int created = 0; 3603c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o problem_t problem = 0; 361efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 36221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!dirent->inode) 36321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o problem = PR_2_MISSING_DOT; 36470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara else if ((ext2fs_dirent_name_len(dirent) != 1) || 36521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o (dirent->name[0] != '.')) 36621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o problem = PR_2_1ST_NOT_DOT; 36721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o else if (dirent->name[1] != '\0') 36821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o problem = PR_2_DOT_NULL_TERM; 3695dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o 3708a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); 37121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (problem) { 3721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, problem, pctx)) { 3735dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (rec_len < 12) 3745dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o rec_len = dirent->rec_len = 12; 3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = ino; 37670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_name_len(dirent, 1); 37770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); 3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->name[0] = '.'; 37921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o dirent->name[1] = '\0'; 3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o status = 1; 3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o created = 1; 3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dirent->inode != ino) { 3851b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_2_BAD_INODE_DOT, pctx)) { 3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = ino; 3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o status = 1; 38821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3905dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (rec_len > 12) { 3915dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o new_len = rec_len - 12; 3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (new_len > 12) { 3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (created || 394f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) { 3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o nextdir = (struct ext2_dir_entry *) 3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ((char *) dirent + 12); 3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->rec_len = 12; 3988a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_set_rec_len(ctx->fs, new_len, 3998a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o nextdir); 4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o nextdir->inode = 0; 40170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_name_len(nextdir, 0); 40270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_file_type(nextdir, 40370f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara EXT2_FT_UNKNOWN); 4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o status = 1; 4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return status; 4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the second entry in the directory is '..', and that the 4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry is sane. We do not check the inode number of '..' 4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * here; this gets done in pass 3. 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4161b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_dotdot(e2fsck_t ctx, 4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_dir_entry *dirent, 41828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o ext2_ino_t ino, struct problem_context *pctx) 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4203c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o problem_t problem = 0; 421cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger unsigned int rec_len; 422efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 42321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!dirent->inode) 42421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o problem = PR_2_MISSING_DOT_DOT; 42570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara else if ((ext2fs_dirent_name_len(dirent) != 2) || 42621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o (dirent->name[0] != '.') || 42721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o (dirent->name[1] != '.')) 42821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o problem = PR_2_2ND_NOT_DOT_DOT; 42921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o else if (dirent->name[2] != '\0') 43021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o problem = PR_2_DOT_DOT_NULL_TERM; 43121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 4328a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); 43321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (problem) { 4341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, problem, pctx)) { 4355dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (rec_len < 12) 43621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o dirent->rec_len = 12; 4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Note: we don't have the parent inode just 4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * yet, so we will fill it in with the root 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * inode. This will get fixed in pass 3. 4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = EXT2_ROOT_INO; 44370f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_name_len(dirent, 2); 44470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); 4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->name[0] = '.'; 4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->name[1] = '.'; 44721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o dirent->name[2] = '\0'; 4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 1; 449efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o } 4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 45228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o if (e2fsck_dir_info_set_dotdot(ctx, ino, dirent->inode)) { 45328db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o fix_problem(ctx, PR_2_NO_DIRINFO, pctx); 45428db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o return -1; 45528db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o } 4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Check to make sure a directory entry doesn't contain any illegal 4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * characters. 4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 4631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int check_name(e2fsck_t ctx, 4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_dir_entry *dirent, 465544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o struct problem_context *pctx) 4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int i; 4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int fixup = -1; 4693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int ret = 0; 470efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 47170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) { 472dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o if (dirent->name[i] != '/' && dirent->name[i] != '\0') 473dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o continue; 474dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o if (fixup < 0) 475dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); 476dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o if (fixup == 0) 477dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o return 0; 478dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o dirent->name[i] = '.'; 479dbff534ec685ea0815544746558dbd3e31284912Theodore Ts'o ret = 1; 4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ret; 4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 484e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'ostatic int encrypted_check_name(e2fsck_t ctx, 485e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o struct ext2_dir_entry *dirent, 486e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o struct problem_context *pctx) 487e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o{ 488e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) { 489e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) { 490e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o dirent->inode = 0; 491e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o return 1; 492e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o } 493e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o ext2fs_unmark_valid(ctx->fs); 494e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o } 495e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o return 0; 496e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o} 497e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o 498aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o/* 499aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o * Check the directory filetype (if present) 500aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o */ 501aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'ostatic _INLINE_ int check_filetype(e2fsck_t ctx, 502544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o struct ext2_dir_entry *dirent, 503544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ext2_ino_t dir_ino EXT2FS_ATTR((unused)), 504544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o struct problem_context *pctx) 505aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o{ 50670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara int filetype = ext2fs_dirent_file_type(dirent); 507aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o int should_be = EXT2_FT_UNKNOWN; 508aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o struct ext2_inode inode; 509aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 51086f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (!ext2fs_has_feature_filetype(ctx->fs->super)) { 5117847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o if (filetype == 0 || 5127847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx)) 5137847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o return 0; 51470f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); 5157847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o return 1; 5167847c1d4fff9195c16b6d74194d104200b3f6c67Theodore Ts'o } 517aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 518c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dirent->inode)) { 519aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o should_be = EXT2_FT_DIR; 520c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson } else if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map, 521aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o dirent->inode)) { 522aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o should_be = EXT2_FT_REG_FILE; 523aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o } else if (ctx->inode_bad_map && 524c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson ext2fs_test_inode_bitmap2(ctx->inode_bad_map, 525aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o dirent->inode)) 526aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o should_be = 0; 527aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o else { 528aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o e2fsck_read_inode(ctx, dirent->inode, &inode, 529aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o "check_filetype"); 5306fdc7a325c8bff67fc3a0489d0858bc7c48dc1a3Theodore Ts'o should_be = ext2_file_type(inode.i_mode); 531aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o } 532aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o if (filetype == should_be) 533aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o return 0; 534aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o pctx->num = should_be; 535aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 536aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE, 537aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o pctx) == 0) 538aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o return 0; 539efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 54070f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_file_type(dirent, should_be); 541aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o return 1; 542aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o} 543aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 5448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void parse_int_node(ext2_filsys fs, 5456dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson struct ext2_db_entry2 *db, 5468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct check_dir_struct *cd, 5478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct dx_dir_info *dx_dir, 54807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong char *block_buf, int failed_csum) 5498fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{ 5508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct ext2_dx_root_info *root; 5518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct ext2_dx_entry *ent; 5528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct ext2_dx_countlimit *limit; 5538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct dx_dirblock_info *dx_db; 554ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o int i, expect_limit, count; 5558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o blk_t blk; 5568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o ext2_dirhash_t min_hash = 0xffffffff; 5578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o ext2_dirhash_t max_hash = 0; 558ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o ext2_dirhash_t hash = 0, prev_hash; 55907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong int csum_size = 0; 5608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 5618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (db->blockcnt == 0) { 5628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o root = (struct ext2_dx_root_info *) (block_buf + 24); 563efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 5648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG 5658fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("Root node dump:\n"); 5668deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato printf("\t Reserved zero: %u\n", root->reserved_zero); 5678fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("\t Hash Version: %d\n", root->hash_version); 5688fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("\t Info length: %d\n", root->info_length); 5698fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("\t Indirect levels: %d\n", root->indirect_levels); 5708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("\t Flags: %d\n", root->unused_flags); 5718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif 5728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 5738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length); 57407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong 57507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong if (failed_csum && 57607307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) || 57707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong fix_problem(cd->ctx, PR_2_HTREE_ROOT_CSUM_INVALID, 57807307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong &cd->pctx))) 57907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong goto clear_and_exit; 5808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } else { 5818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o ent = (struct ext2_dx_entry *) (block_buf+8); 58207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong 58307307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong if (failed_csum && 58407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) || 58507307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong fix_problem(cd->ctx, PR_2_HTREE_NODE_CSUM_INVALID, 58607307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong &cd->pctx))) 58707307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong goto clear_and_exit; 5888fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 58907307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong 5908fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o limit = (struct ext2_dx_countlimit *) ent; 5918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 5928fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG 593efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o printf("Number of entries (count): %d\n", 5948132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o ext2fs_le16_to_cpu(limit->count)); 595efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o printf("Number of entries (limit): %d\n", 5968132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o ext2fs_le16_to_cpu(limit->limit)); 5978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif 5988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 5998132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o count = ext2fs_le16_to_cpu(limit->count); 60086f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (ext2fs_has_feature_metadata_csum(fs->super)) 60107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong csum_size = sizeof(struct ext2_dx_tail); 60207307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong expect_limit = (fs->blocksize - 60307307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong (csum_size + ((char *) ent - block_buf))) / 60407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong sizeof(struct ext2_dx_entry); 6058132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) { 6068132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o cd->pctx.num = ext2fs_le16_to_cpu(limit->limit); 607ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx)) 608ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o goto clear_and_exit; 609ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o } 6108132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o if (count > expect_limit) { 6118132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o cd->pctx.num = count; 612ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o if (fix_problem(cd->ctx, PR_2_HTREE_BAD_COUNT, &cd->pctx)) 613ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o goto clear_and_exit; 614ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o count = expect_limit; 615ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o } 616efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 617ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o for (i=0; i < count; i++) { 618ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o prev_hash = hash; 6198132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o hash = i ? (ext2fs_le32_to_cpu(ent[i].hash) & ~1) : 0; 6208fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG 6218deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato printf("Entry #%d: Hash 0x%08x, block %u\n", i, 6228132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o hash, ext2fs_le32_to_cpu(ent[i].block)); 6238fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif 6248132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o blk = ext2fs_le32_to_cpu(ent[i].block) & 0x0ffffff; 6258fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o /* Check to make sure the block is valid */ 626977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o if (blk >= (blk_t) dx_dir->numblocks) { 627b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o cd->pctx.blk = blk; 6288fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK, 629ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o &cd->pctx)) 630ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o goto clear_and_exit; 631977ac8731bf3bd934421dd8107e77325ec7e6de7Theodore Ts'o continue; 6328fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 633ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o if (hash < prev_hash && 634ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o fix_problem(cd->ctx, PR_2_HTREE_HASH_ORDER, &cd->pctx)) 635ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o goto clear_and_exit; 6368fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db = &dx_dir->dx_block[blk]; 6378fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (dx_db->flags & DX_FLAG_REFERENCED) { 6388fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_DUP_REF; 6398fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } else { 6408fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_REFERENCED; 6418fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->parent = db->blockcnt; 6428fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 6438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (hash < min_hash) 6448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o min_hash = hash; 6458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (hash > max_hash) 6468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o max_hash = hash; 6478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->node_min_hash = hash; 6488132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o if ((i+1) < count) 649efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o dx_db->node_max_hash = 6508132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o ext2fs_le32_to_cpu(ent[i+1].hash) & ~1; 6518fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o else { 6528fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->node_max_hash = 0xfffffffe; 6538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_LAST; 6548fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 6558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (i == 0) 6568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_FIRST; 6578fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 6588fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG 6598fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n", 6608fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o db->blockcnt, min_hash, max_hash); 6618fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif 6628fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db = &dx_dir->dx_block[db->blockcnt]; 6638fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->min_hash = min_hash; 6648fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->max_hash = max_hash; 665ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o return; 666ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o 667ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'oclear_and_exit: 668ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o clear_htree(cd->ctx, cd->pctx.ino); 669ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o dx_dir->numblocks = 0; 67007307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino); 6718fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o} 672aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 673e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o/* 674e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * Given a busted directory, try to salvage it somehow. 675efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 676e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */ 677ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'ostatic void salvage_directory(ext2_filsys fs, 678e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o struct ext2_dir_entry *dirent, 679e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o struct ext2_dir_entry *prev, 68082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong unsigned int *offset, 68182ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong unsigned int block_len) 682e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o{ 683e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o char *cp = (char *) dirent; 6848a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o int left; 6858a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o unsigned int rec_len, prev_rec_len; 6864a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong unsigned int name_len; 687e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o 6884a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong /* 6894a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong * If the space left for the entry is too small to be an entry, 6904a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong * we can't access dirent's fields, so plumb in the values needed 6914a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong * so that the previous entry absorbs this one. 6924a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong */ 6934a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong if (block_len - *offset < EXT2_DIR_ENTRY_HEADER_LEN) { 6944a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong name_len = 0; 6954a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong rec_len = block_len - *offset; 6964a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong } else { 6974a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong name_len = ext2fs_dirent_name_len(dirent); 6984a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 6994a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong } 70082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong left = block_len - *offset - rec_len; 7015dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o 702e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o /* 703e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * Special case of directory entry of size 8: copy what's left 704e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * of the directory block up to cover up the invalid hole. 705e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */ 7064a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong if ((left >= 12) && (rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) { 7074a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left); 7084a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN); 709ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o return; 710ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o } 711ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o /* 712ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o * If the directory entry overruns the end of the directory 713ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o * block, and the name is small enough to fit, then adjust the 714ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o * record length. 715ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o */ 716ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o if ((left < 0) && 7174a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong ((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) && 7184a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong ((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) && 719ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o dirent->inode <= fs->super->s_inodes_count && 720ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o strnlen(dirent->name, name_len) == name_len) { 7218a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent); 722ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o return; 723e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o } 724e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o /* 725575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah * If the record length of the directory entry is a multiple 726575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah * of four, and not too big, such that it is valid, let the 727575307cc63d24766ff789262a5cea7b4faf2fa13Kalpak Shah * previous directory entry absorb the invalid one. 728e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */ 7295dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (prev && rec_len && (rec_len % 4) == 0 && 73082ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong (*offset + rec_len <= block_len)) { 7318a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); 7328a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o prev_rec_len += rec_len; 7338a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); 7345dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o *offset += rec_len; 735ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o return; 736e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o } 737e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o /* 738e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * Default salvage method --- kill all of the directory 739e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * entries for the rest of the block. We will either try to 740e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * absorb it into the previous directory entry, or create a 741e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o * new empty directory entry the rest of the directory block. 742e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o */ 743e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o if (prev) { 7448a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); 74582ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong prev_rec_len += block_len - *offset; 7468a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); 747ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o *offset = fs->blocksize; 748e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o } else { 74982ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong rec_len = block_len - *offset; 7508a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_set_rec_len(fs, rec_len, dirent); 75170f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_name_len(dirent, 0); 75270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); 753e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o dirent->inode = 0; 754e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o } 755e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o} 756e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o 757d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong#define NEXT_DIRENT(d) ((void *)((char *)(d) + (d)->rec_len)) 75817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wongstatic errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf) 75917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong{ 76017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong struct ext2_dir_entry *d; 76117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong void *top; 76217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong struct ext2_dir_entry_tail *t; 76317641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong 76417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong d = dirbuf; 76517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong top = EXT2_DIRENT_TAIL(dirbuf, fs->blocksize); 76617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong 767d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong while (d->rec_len && !(d->rec_len & 0x3) && NEXT_DIRENT(d) <= top) 768d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong d = NEXT_DIRENT(d); 76917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong 77017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong if (d != top) { 77162f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o unsigned int min_size = EXT2_DIR_REC_LEN( 77217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong ext2fs_dirent_name_len(dirbuf)); 77362f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o if (min_size > (char *)top - (char *)d) 77417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; 77562f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o d->rec_len = (char *)top - (char *)d; 77617641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong } 77717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong 77817641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong t = (struct ext2_dir_entry_tail *)top; 77917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong if (t->det_reserved_zero1 || 78017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong t->det_rec_len != sizeof(struct ext2_dir_entry_tail) || 78117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong t->det_reserved_name_len != EXT2_DIR_NAME_LEN_CSUM) 78217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong ext2fs_initialize_dirent_tail(fs, t); 78317641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong 78417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong return 0; 78517641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong} 786d3eb1502fd07a4c751d20ad5fa4b75bfda039d52Darrick J. Wong#undef NEXT_DIRENT 78717641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong 78852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongstatic errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino, 78952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong size_t *inline_data_size, 79052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong struct problem_context *pctx, 79152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong char *buf) 79252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong{ 79352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong ext2_filsys fs = ctx->fs; 79452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong struct ext2_inode inode; 79552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong size_t new_size, old_size; 79652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong errcode_t retval; 79752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong 79852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong old_size = *inline_data_size; 7990ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong /* 8000ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong * If there's not enough bytes to start the "second" dir block 8010ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong * (in the EA space) then truncate everything to the first block. 8020ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong */ 8030ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (old_size > EXT4_MIN_INLINE_DATA_SIZE && 8040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong old_size < EXT4_MIN_INLINE_DATA_SIZE + 8050ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong EXT2_DIR_REC_LEN(1)) { 8060ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong old_size = EXT4_MIN_INLINE_DATA_SIZE; 8070ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong new_size = old_size; 8080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong } else 8090ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong /* Increase to the next four-byte boundary for salvaging */ 8100ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong new_size = old_size + (4 - (old_size & 3)); 81152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong memset(buf + old_size, 0, new_size - old_size); 81252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size); 81352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) { 8140ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong /* Or we can't, so truncate. */ 81552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong new_size -= 4; 81652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size); 81752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (retval) { 81852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED, 81952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong pctx)) { 82052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong new_size = 0; 82152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto write_inode; 82252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong } 82352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto err; 82452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong } 82552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong } else if (retval) { 82652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED, 82752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong pctx)) { 82852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong new_size = 0; 82952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto write_inode; 83052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong } 83152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto err; 83252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong } 83352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong 83452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongwrite_inode: 83552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong retval = ext2fs_read_inode(fs, ino, &inode); 83652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (retval) 83752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto err; 83852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong 83952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong retval = ext2fs_inode_size_set(fs, &inode, new_size); 84052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (retval) 84152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto err; 84252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (new_size == 0) 84352b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong inode.i_flags &= ~EXT4_INLINE_DATA_FL; 84452b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong retval = ext2fs_write_inode(fs, ino, &inode); 84552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (retval) 84652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong goto err; 84752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong *inline_data_size = new_size; 84852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong 84952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wongerr: 85052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong return retval; 85152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong} 85252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong 853a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wongstatic int check_dir_block2(ext2_filsys fs, 854a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong struct ext2_db_entry2 *db, 855a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong void *priv_data) 856a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong{ 857a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong int err; 858a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong struct check_dir_struct *cd = priv_data; 859a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong 860a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) { 861a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong err = e2fsck_readahead_dblist(fs, 862a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT, 863a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong fs->dblist, 864a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd->list_offset + cd->ra_entries / 8, 865a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd->ra_entries); 866a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong if (err) 867a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd->ra_entries = 0; 868a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8); 869a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong } 870a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong 871a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong err = check_dir_block(fs, db, priv_data); 872a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong cd->list_offset++; 873a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong return err; 874a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong} 875a5abfe0382729fba2c5fea6aaae486cb8bc98f00Darrick J. Wong 8763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int check_dir_block(ext2_filsys fs, 8776dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson struct ext2_db_entry2 *db, 87854dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o void *priv_data) 8793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 8808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct dx_dir_info *dx_dir; 8818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct dx_dirblock_info *dx_db = 0; 8826582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu struct ext2_dir_entry *dirent, *prev, dot, dotdot; 8838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o ext2_dirhash_t hash; 884544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o unsigned int offset = 0; 8853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dir_modified = 0; 88621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o int dot_state; 88703fa6f8ae28a87018325c892f731097cc97d9eacTheodore Ts'o unsigned int rec_len; 8886dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson blk64_t block_nr = db->blk; 88986c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t ino = db->ino; 89028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o ext2_ino_t subdir_parent; 89121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o __u16 links; 89254dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o struct check_dir_struct *cd; 8930ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong char *buf, *ibuf; 8941b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o e2fsck_t ctx; 8953c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o problem_t problem; 896ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o struct ext2_dx_root_info *root; 897e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o struct ext2_dx_countlimit *limit; 8980926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o static dict_t de_dict; 8990926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o struct problem_context pctx; 9000926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o int dups_found = 0; 90128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o int ret; 902e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong int dx_csum_size = 0, de_csum_size = 0; 90381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong int failed_csum = 0; 904e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong int is_leaf = 1; 90524997f1cd2b3c3ea7a5a2c7fe37013de36a6d8a3Darrick J. Wong size_t inline_data_size = 0; 9066582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu int filetype = 0; 90762ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o int encrypted = 0; 9080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong size_t max_block_size; 9091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 91054dc7ca2869897ae8cb81a9ab9880ebff11680bcTheodore Ts'o cd = (struct check_dir_struct *) priv_data; 9110ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong ibuf = buf = cd->buf; 9121b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx = cd->ctx; 913f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o 914db3d8718be6ad3bdd252b242827fa54914b8ec2eAndreas Dilger if (ctx->flags & E2F_FLAG_RUN_RETURN) 9154cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o return DIRENT_ABORT; 916efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 9174cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max)) 9184cae04529eda0e482ceaa86b48e532f9c8d35f24Theodore Ts'o return DIRENT_ABORT; 919efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 92086f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (ext2fs_has_feature_metadata_csum(fs->super)) { 92107307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong dx_csum_size = sizeof(struct ext2_dx_tail); 922e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong de_csum_size = sizeof(struct ext2_dir_entry_tail); 923e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong } 92407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong 92586f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (ext2fs_has_feature_filetype(fs->super)) 9266582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu filetype = EXT2_FT_DIR << 8; 9276582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu 9283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 929efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * Make sure the inode is still in use (could have been 9303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * deleted in the duplicate/bad blocks pass. 9313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 932c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, ino))) 9333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 93450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 93521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.ino = ino; 93621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.blk = block_nr; 93721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.blkcount = db->blockcnt; 93821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.ino2 = 0; 93921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.dirent = 0; 94021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.num = 0; 94121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 94286f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (ext2fs_has_feature_inline_data(fs->super)) { 9436582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu errcode_t ec; 9446582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu 9456582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu ec = ext2fs_inline_data_size(fs, ino, &inline_data_size); 9466582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu if (ec && ec != EXT2_ET_NO_INLINE_DATA) 9476582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu return DIRENT_ABORT; 9486582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } 9496582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu 9506582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu if (db->blk == 0 && !inline_data_size) { 9511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (allocate_dir_block(ctx, db, buf, &cd->pctx)) 95250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return 0; 95350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o block_nr = db->blk; 95450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o } 955efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 9563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (db->blockcnt) 9573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dot_state = 2; 9583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o else 9593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dot_state = 0; 9603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 9610926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o if (ctx->dirs_to_hash && 9620926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o ext2fs_u32_list_test(ctx->dirs_to_hash, ino)) 9630926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o dups_found++; 9640926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o 9653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 966f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o printf("In process_dir_block block %lu, #%d, inode %lu\n", block_nr, 9673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o db->blockcnt, ino); 9683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 969efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 970f85a9ae6397ff074193322a12ed721dbf5751e41Eric Sandeen ehandler_operation(_("reading directory block")); 971cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong if (inline_data_size) { 9724a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong memset(buf, 0, fs->blocksize - inline_data_size); 9736582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.errcode = ext2fs_inline_data_get(fs, ino, 0, buf, 0); 974cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong if (cd->pctx.errcode) 975cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong goto inline_read_fail; 976cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#ifdef WORDS_BIGENDIAN 9770ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (db->blockcnt) 9780ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong goto skip_first_read_swab; 979cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf)); 980cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong cd->pctx.errcode = ext2fs_dirent_swab_in2(fs, 981cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong buf + EXT4_INLINE_DATA_DOTDOT_SIZE, 9820ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE, 9830ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong 0); 9840ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (cd->pctx.errcode) 9850ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong goto inline_read_fail; 9860ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_first_read_swab: 9870ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE || 9880ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong !db->blockcnt) 9890ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong goto inline_read_fail; 9900ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong cd->pctx.errcode = ext2fs_dirent_swab_in2(fs, 9910ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong buf + EXT4_MIN_INLINE_DATA_SIZE, 9920ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong inline_data_size - EXT4_MIN_INLINE_DATA_SIZE, 993cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong 0); 994cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#endif 995cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong } else 9966582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr, 9976582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu buf, 0, ino); 998cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wonginline_read_fail: 99952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong pctx.ino = ino; 100052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong pctx.num = inline_data_size; 10010ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (((inline_data_size & 3) || 10020ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE && 10030ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong inline_data_size < EXT4_MIN_INLINE_DATA_SIZE + 10040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong EXT2_DIR_REC_LEN(1))) && 100552b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) { 100652b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong errcode_t err = fix_inline_dir_size(ctx, ino, 100752b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong &inline_data_size, &pctx, 100852b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong buf); 100952b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong if (err) 101052b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong return DIRENT_ABORT; 101152b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong 101252b0c6e6c9b2497f5d749bf30e6bc632aa45e6cbDarrick J. Wong } 1013e94bc631648299dca43a6015520b18f6232d50dfTheodore Ts'o ehandler_operation(0); 1014b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED) 1015b9852cd87b42f79d569db68c3fdefe4a8f48ede1Theodore Ts'o cd->pctx.errcode = 0; /* We'll handle this ourselves */ 101681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong else if (cd->pctx.errcode == EXT2_ET_DIR_CSUM_INVALID) { 101781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong cd->pctx.errcode = 0; /* We'll handle this ourselves */ 101881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong failed_csum = 1; 101981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong } 10201b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (cd->pctx.errcode) { 1021e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong char *buf2; 102208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) { 102308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 102408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return DIRENT_ABORT; 102508b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o } 1026e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0, 1027e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong EXT2_ROOT_INO, &buf2); 1028e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong memcpy(buf, buf2, fs->blocksize); 1029e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong ext2fs_free_mem(&buf2); 10303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 10318fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_dir = e2fsck_get_dx_dir_info(ctx, ino); 103262acaa1de132a808949d71264731bba7fe095705Theodore Ts'o if (dx_dir && dx_dir->numblocks) { 10338fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (db->blockcnt >= dx_dir->numblocks) { 1034ea9085c711e92c3727538a0637bc805141333d83Darrick J. Wong pctx.dir = ino; 1035efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o if (fix_problem(ctx, PR_2_UNEXPECTED_HTREE_BLOCK, 1036d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o &pctx)) { 1037d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o clear_htree(ctx, ino); 1038d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o dx_dir->numblocks = 0; 1039d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o dx_db = 0; 1040d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o goto out_htree; 1041d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o } 1042d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'o fatal_error(ctx, _("Can not continue.")); 10438fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 10448fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db = &dx_dir->dx_block[db->blockcnt]; 10458fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->type = DX_DIRBLOCK_LEAF; 10468fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->phys = block_nr; 10478fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->min_hash = ~0; 10488fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->max_hash = 0; 1049efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 10508fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dirent = (struct ext2_dir_entry *) buf; 10518a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 1052e8254bfd3b49cb325a1ff6b21ca86570a1008744Theodore Ts'o limit = (struct ext2_dx_countlimit *) (buf+8); 10538fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (db->blockcnt == 0) { 1054ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o root = (struct ext2_dx_root_info *) (buf + 24); 10558fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->type = DX_DIRBLOCK_ROOT; 10568fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST; 1057ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o if ((root->reserved_zero || 1058ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o root->info_length < 8 || 1059ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o root->indirect_levels > 1) && 1060ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) { 1061ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o clear_htree(ctx, ino); 1062ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o dx_dir->numblocks = 0; 1063ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o dx_db = 0; 1064f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o } 1065ea1959f01523ffc105747d660ccc5b7f02805928Theodore Ts'o dx_dir->hashversion = root->hash_version; 1066f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o if ((dx_dir->hashversion <= EXT2_HASH_TEA) && 1067f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)) 1068f77704e416fca7dbe4cc91abba674d2ae3c14f6fTheodore Ts'o dx_dir->hashversion += 3; 1069ad4fa4660404ed88a3231fee338397af11e041b4Theodore Ts'o dx_dir->depth = root->indirect_levels + 1; 10708fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } else if ((dirent->inode == 0) && 10715dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o (rec_len == fs->blocksize) && 107270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara (ext2fs_dirent_name_len(dirent) == 0) && 1073efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o (ext2fs_le16_to_cpu(limit->limit) == 107407307114dea005917b0c3a18a08948435f4a2abcDarrick J. Wong ((fs->blocksize - (8 + dx_csum_size)) / 10758132d840c8f6b0d90ab5048d6f8529f74e1aa0b3Theodore Ts'o sizeof(struct ext2_dx_entry)))) 10768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->type = DX_DIRBLOCK_NODE; 107795eca2e9228841496a5864605259bf908a5b2d0aDarrick J. Wong is_leaf = (dx_db->type == DX_DIRBLOCK_LEAF); 10788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 1079d45edec0fb2e5d100d122fdda0914560c64def44Theodore Ts'oout_htree: 10803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 10817f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong /* Leaf node with no space for csum? Rebuild dirs in pass 3A. */ 10827f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong if (is_leaf && !inline_data_size && failed_csum && 10837f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) { 10847f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong de_csum_size = 0; 1085d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong if (e2fsck_dir_will_be_rehashed(ctx, ino)) { 1086d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong failed_csum = 0; 1087d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong goto skip_checksum; 1088d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong } 1089d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM, 10907f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong &cd->pctx)) 1091e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong goto skip_checksum; 10927f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong e2fsck_rehash_dir_later(ctx, ino); 1093d02d019557d993c8dfe2f7d0fea841101f0d9e61Darrick J. Wong failed_csum = 0; 10947f43a46fad362435f8420f656c6157dc8be8dd4dDarrick J. Wong goto skip_checksum; 1095e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong } 1096e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong /* htree nodes don't use fake dirents to store checksums */ 1097e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong if (!is_leaf) 1098e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong de_csum_size = 0; 1099e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong 1100e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wongskip_checksum: 11010ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (inline_data_size) { 11020ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (db->blockcnt) { 11030ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong buf += EXT4_MIN_INLINE_DATA_SIZE; 11040ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong max_block_size = inline_data_size - EXT4_MIN_INLINE_DATA_SIZE; 11050ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong /* Zero-length second block, just exit */ 11060ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (max_block_size == 0) 11070ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong return 0; 11080ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong } else { 11090ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong max_block_size = EXT4_MIN_INLINE_DATA_SIZE; 11100ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong } 11110ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong } else 11120ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong max_block_size = fs->blocksize - de_csum_size; 11130ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong 111462ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o if (ctx->encrypted_dirs) 111562ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino); 111662ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5aTheodore Ts'o 11170926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp); 1118e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o prev = 0; 11193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o do { 11203971bfe878d6c30f9b5be3a2c0310943982a4775Theodore Ts'o dgrp_t group; 112149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos ext2_ino_t first_unused_inode; 112270f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara unsigned int name_len; 112349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos 11241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = 0; 11256582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu if (!inline_data_size || dot_state > 1) { 11266582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent = (struct ext2_dir_entry *) (buf + offset); 11274a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong /* 11284a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong * If there's not even space for the entry header, 11294a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong * force salvaging this dir. 11304a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong */ 11314a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN) 11324a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong rec_len = EXT2_DIR_REC_LEN(1); 11334a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong else 11344a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 11356582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.dirent = dirent; 11366582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.num = offset; 11374a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong if ((offset + rec_len > max_block_size) || 11386582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu (rec_len < 12) || 11396582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu ((rec_len % 4) != 0) || 114062f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o (((unsigned) ext2fs_dirent_name_len(dirent) + EXT2_DIR_ENTRY_HEADER_LEN) > rec_len)) { 114182ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong if (fix_problem(ctx, PR_2_DIR_CORRUPTED, 114282ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong &cd->pctx)) { 11434348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#ifdef WORDS_BIGENDIAN 11444348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong /* 11454348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * On big-endian systems, if the dirent 11464348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * swap routine finds a rec_len that it 11474348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * doesn't like, it continues 11484348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * processing the block as if rec_len 11494a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong * == EXT2_DIR_ENTRY_HEADER_LEN. This means that the name 11504348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * field gets byte swapped, which means 11514348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * that salvage will not detect the 11524348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * correct name length (unless the name 11534348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * has a length that's an exact 11544348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * multiple of four bytes), and it'll 11554348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * discard the entry (unnecessarily) 11564348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * and the rest of the dirent block. 11574348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * Therefore, swap the rest of the 11584348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * block back to disk order, run 11594348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * salvage, and re-swap anything after 11604348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong * the salvaged dirent. 11614348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong */ 11624348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong int need_reswab = 0; 11634a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN || rec_len % 4) { 11644348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong need_reswab = 1; 11654348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong ext2fs_dirent_swab_in2(fs, 11664a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong ((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN, 11674a3dc1f0b670960acd570ee64acb436c254135c8Darrick J. Wong max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN, 11684348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong 0); 11694348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong } 11704348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#endif 117182ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong salvage_directory(fs, dirent, prev, 117282ad476d4709faf9f39a9aa581f9679e8181bbeaDarrick J. Wong &offset, 11733a748dfc1cc28878b5c0ffc1042c3efb3d26360eDarrick J. Wong max_block_size); 11744348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#ifdef WORDS_BIGENDIAN 11754348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong if (need_reswab) { 11764348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong (void) ext2fs_get_rec_len(fs, 11774348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong dirent, &rec_len); 11784348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong ext2fs_dirent_swab_in2(fs, 11794348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong ((char *)dirent) + offset + rec_len, 11804348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong max_block_size - offset - rec_len, 11814348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong 0); 11824348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong } 11834348709c5c1daebb1ad2307dbd37f3d04104634eDarrick J. Wong#endif 11846582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dir_modified++; 11856582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu continue; 11866582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } else 11876582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu goto abort_free_dict; 11886582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } 11896582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } else { 11906582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu if (dot_state == 0) { 11916582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu memset(&dot, 0, sizeof(dot)); 11926582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent = ˙ 11936582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->inode = ino; 11946582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->rec_len = EXT2_DIR_REC_LEN(1); 11956582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->name_len = 1 | filetype; 11966582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->name[0] = '.'; 11976582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } else if (dot_state == 1) { 11986582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu memset(&dotdot, 0, sizeof(dotdot)); 11996582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent = &dotdot; 12006582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->inode = 12016582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu ((struct ext2_dir_entry *)buf)->inode; 12026582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->rec_len = EXT2_DIR_REC_LEN(2); 12036582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->name_len = 2 | filetype; 12046582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->name[0] = '.'; 12056582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu dirent->name[1] = '.'; 12066582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } else { 12076582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu fatal_error(ctx, _("Can not continue.")); 12086582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } 12096582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.dirent = dirent; 12106582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.num = offset; 12113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 121250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 1213e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o if (dot_state == 0) { 12141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (check_dot(ctx, dirent, ino, &cd->pctx)) 12153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir_modified++; 1216e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o } else if (dot_state == 1) { 121728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o ret = check_dotdot(ctx, dirent, ino, &cd->pctx); 121828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o if (ret < 0) 12190926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o goto abort_free_dict; 122028db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o if (ret) 12213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir_modified++; 12223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } else if (dirent->inode == ino) { 12231b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = PR_2_LINK_DOT; 12241b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_2_LINK_DOT, &cd->pctx)) { 12253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = 0; 12263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir_modified++; 122721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o goto next; 12283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 12293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1230efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o if (!dirent->inode) 12313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto next; 1232efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 12333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 12343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Make sure the inode listed is a legal one. 1235efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o */ 123670f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara name_len = ext2fs_dirent_name_len(dirent); 12373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (((dirent->inode != EXT2_ROOT_INO) && 12387f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o (dirent->inode < EXT2_FIRST_INODE(fs->super))) || 12393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o (dirent->inode > fs->super->s_inodes_count)) { 12401b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = PR_2_BAD_INO; 12411b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } else if (ctx->inode_bb_map && 1242c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson (ext2fs_test_inode_bitmap2(ctx->inode_bb_map, 12431b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o dirent->inode))) { 12441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o /* 12451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * If the inode is in a bad block, offer to 12461b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * clear it. 12471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o */ 12481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = PR_2_BB_INODE; 124970f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara } else if ((dot_state > 1) && (name_len == 1) && 12501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o (dirent->name[0] == '.')) { 12511b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o /* 12521b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * If there's a '.' entry in anything other 12531b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * than the first directory entry, it's a 12541b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * duplicate entry that should be removed. 12551b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o */ 12561b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = PR_2_DUP_DOT; 125770f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara } else if ((dot_state > 1) && (name_len == 2) && 1258efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o (dirent->name[0] == '.') && 12591b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o (dirent->name[1] == '.')) { 12601b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o /* 12611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * If there's a '..' entry in anything other 12621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * than the second directory entry, it's a 12631b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * duplicate entry that should be removed. 12641b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o */ 12651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = PR_2_DUP_DOT_DOT; 1266e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o } else if ((dot_state > 1) && 12671b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o (dirent->inode == EXT2_ROOT_INO)) { 12681b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o /* 12691b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * Don't allow links to the root directory. 12701b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * We check this specially to make sure we 12711b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * catch this error case even if the root 12721b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o * directory hasn't been created yet. 12731b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o */ 12741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o problem = PR_2_LINK_ROOT; 127570f4632b626e3db94dd02c9dc9b4e643ffb0d048Jan Kara } else if ((dot_state > 1) && (name_len == 0)) { 1276c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o /* 1277c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o * Don't allow zero-length directory names. 1278c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o */ 1279c40db6d5717023bdd6bb4935161e7ce9678d6234Theodore Ts'o problem = PR_2_NULL_NAME; 128021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 128121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 12821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (problem) { 12831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, problem, &cd->pctx)) { 128421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o dirent->inode = 0; 128521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o dir_modified++; 128621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o goto next; 12871b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } else { 12881b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_unmark_valid(fs); 12891b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (problem == PR_2_BAD_INO) 12901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o goto next; 129121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 12923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 12933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 12943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 12953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If the inode was marked as having bad fields in 12963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pass1, process it and offer to fix/clear it. 12973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * (We wait until now so that we can display the 12983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * pathname to the user.) 12993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 13001b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (ctx->inode_bad_map && 1301c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson ext2fs_test_inode_bitmap2(ctx->inode_bad_map, 13023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode)) { 1303e72a9ba39471364ad2f9397f645ca547090e3485Theodore Ts'o if (e2fsck_process_bad_inode(ctx, ino, 1304bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o dirent->inode, 1305bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o buf + fs->blocksize)) { 13063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = 0; 13073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir_modified++; 13083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto next; 13093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 1310a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 131108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return DIRENT_ABORT; 13123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 13133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 131449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos group = ext2fs_group_of_ino(fs, dirent->inode); 131549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos first_unused_inode = group * fs->super->s_inodes_per_group + 131649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos 1 + fs->super->s_inodes_per_group - 1317d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson ext2fs_bg_itable_unused(fs, group); 131849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos cd->pctx.group = group; 131949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos 132049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos /* 132142e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o * Check if the inode was missed out because 132242e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o * _INODE_UNINIT flag was set or bg_itable_unused was 132342e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o * incorrect. If so, clear the _INODE_UNINIT flag and 132442e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o * restart e2fsck. In the future it would be nice if 132542e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o * we could call a function in pass1.c that checks the 132642e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o * newly visible inodes. 132749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos */ 1328cd65a24e756b8f6770a5961fd94c67eb00dd7baaTheodore Ts'o if (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)) { 13296267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger pctx.num = dirent->inode; 133049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT, 133149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos &cd->pctx)){ 1332e633b58ac75f2f544b7d6572e37d4b63da31e59cEric Sandeen ext2fs_bg_flags_clear(fs, group, 1333732c8cd58ff30ffae0d3276c411a08920717a46cTheodore Ts'o EXT2_BG_INODE_UNINIT); 133442e89ce7f8823ad14099b03469c2f4e4f6530d05Theodore Ts'o ext2fs_mark_super_dirty(fs); 13356267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger ctx->flags |= E2F_FLAG_RESTART_LATER; 133649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } else { 133749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos ext2fs_unmark_valid(fs); 133849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (problem == PR_2_BAD_INO) 133949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos goto next; 134049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } 134149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } else if (dirent->inode >= first_unused_inode) { 13426267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger pctx.num = dirent->inode; 134349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){ 1344d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson ext2fs_bg_itable_unused_set(fs, group, 0); 134549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos ext2fs_mark_super_dirty(fs); 13466267ee49be64035d8a9772c3bafed18a09874fa5Andreas Dilger ctx->flags |= E2F_FLAG_RESTART_LATER; 134749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } else { 134849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos ext2fs_unmark_valid(fs); 134949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (problem == PR_2_BAD_INO) 135049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos goto next; 135149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } 135249a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } 135349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos 13540433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o /* 13550433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o * Offer to clear unused inodes; if we are going to be 13560433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o * restarting the scan due to bg_itable_unused being 13570433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o * wrong, then don't clear any inodes to avoid zapping 13580433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o * inodes that were skipped during pass1 due to an 13590433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o * incorrect bg_itable_unused; we'll get any real 13600433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o * problems after we restart. 13610433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o */ 13620433c1f1b72bb85d9ea11e7716a415a878a655c8Theodore Ts'o if (!(ctx->flags & E2F_FLAG_RESTART_LATER) && 136397d26ce9e3589e9f5fa17014467a9730a884d158Theodore Ts'o !(ext2fs_test_inode_bitmap2(ctx->inode_used_map, 136497d26ce9e3589e9f5fa17014467a9730a884d158Theodore Ts'o dirent->inode))) 136549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos problem = PR_2_UNUSED_INODE; 136649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos 136749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (problem) { 136849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (fix_problem(ctx, problem, &cd->pctx)) { 136949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos dirent->inode = 0; 137049a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos dir_modified++; 137149a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos goto next; 137249a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } else { 137349a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos ext2fs_unmark_valid(fs); 137449a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos if (problem == PR_2_BAD_INO) 137549a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos goto next; 137649a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } 137749a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos } 137849a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos 137925f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'o if (!encrypted && check_name(ctx, dirent, &cd->pctx)) 13801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o dir_modified++; 13811b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o 1382e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o if (encrypted && (dot_state) > 1 && 1383e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o encrypted_check_name(ctx, dirent, &cd->pctx)) { 1384e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o dir_modified++; 1385e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o goto next; 1386e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o } 1387e3dd5c6f1a1cf9baeb7073fe2ecc5214fdfe0621Theodore Ts'o 1388aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o if (check_filetype(ctx, dirent, ino, &cd->pctx)) 1389aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o dir_modified++; 1390aa4115a47c554a936fdf5e6679e72a9329fecf45Theodore Ts'o 13918fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (dx_db) { 1392437651ad234e125e2ef9c9f213cb3f5c92e67307Theodore Ts'o ext2fs_dirhash(dx_dir->hashversion, dirent->name, 1393437651ad234e125e2ef9c9f213cb3f5c92e67307Theodore Ts'o ext2fs_dirent_name_len(dirent), 1394437651ad234e125e2ef9c9f213cb3f5c92e67307Theodore Ts'o fs->super->s_hash_seed, &hash, 0); 13958fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (hash < dx_db->min_hash) 13968fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->min_hash = hash; 13978fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (hash > dx_db->max_hash) 13988fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->max_hash = hash; 13998fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 14008fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 140121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o /* 14023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If this is a directory, then mark its parent in its 14033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * dir_info structure. If the parent field is already 14043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * filled in, then this directory has more than one 14053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * hard link. We assume the first link is correct, 14063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * and ask the user if he/she wants to clear this one. 14073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1408e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o if ((dot_state > 1) && 1409c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, 14103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode))) { 141128db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o if (e2fsck_dir_info_get_parent(ctx, dirent->inode, 141228db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o &subdir_parent)) { 14131b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o cd->pctx.ino = dirent->inode; 14141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_NO_DIRINFO, &cd->pctx); 14150926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o goto abort_free_dict; 14163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 141728db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o if (subdir_parent) { 141828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o cd->pctx.ino2 = subdir_parent; 14191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_2_LINK_DIR, 142021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o &cd->pctx)) { 14213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = 0; 14223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dir_modified++; 14233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto next; 142421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 142521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o cd->pctx.ino2 = 0; 142628db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o } else { 1427efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o (void) e2fsck_dir_info_set_parent(ctx, 142828db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o dirent->inode, ino); 142928db82a84a33fab19f22da12bb2a8a3c558ae97bTheodore Ts'o } 14303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 14310926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o 14320926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o if (dups_found) { 14330926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o ; 14340926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o } else if (dict_lookup(&de_dict, dirent)) { 14350926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o clear_problem_context(&pctx); 14360926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o pctx.ino = ino; 14370926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o pctx.dirent = dirent; 14380926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx); 1439e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong e2fsck_rehash_dir_later(ctx, ino); 14400926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o dups_found++; 14410926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o } else 14420926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o dict_alloc_insert(&de_dict, dirent, dirent); 1443efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 14441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2fs_icount_increment(ctx->inode_count, dirent->inode, 14451b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o &links); 144621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (links > 1) 14471b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx->fs_links_count++; 14481b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ctx->fs_total_count++; 14493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o next: 1450e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o prev = dirent; 14515dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (dir_modified) 14528a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o (void) ext2fs_get_rec_len(fs, dirent, &rec_len); 14536582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu if (!inline_data_size || dot_state > 1) { 14546582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu offset += rec_len; 14556582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } else { 14566698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong if (dot_state == 1) { 14576582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu offset = 4; 14586698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong /* 14596698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * If we get here, we're checking an inline 14606698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * directory and we've just checked a (fake) 14616698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * dotdot entry that we created on the stack. 14626698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * Therefore set 'prev' to NULL so that if we 14636698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * call salvage_directory on the next entry, 14646698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * it won't try to absorb the next entry into 14656698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong * the on-stack dotdot entry. 14666698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong */ 14676698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong prev = NULL; 14686698374cc0a0d99c954aa61db771ba4128432337Darrick J. Wong } 14696582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } 1470e70ae99e077f5085c15a4526028e2aac0e91d7c1Theodore Ts'o dot_state++; 14710ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong } while (offset < max_block_size); 14723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#if 0 14733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o printf("\n"); 14743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#endif 14758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if (dx_db) { 14768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#ifdef DX_DEBUG 14778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n", 14788fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o db->blockcnt, dx_db->type, 14798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o dx_db->min_hash, dx_db->max_hash); 14808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o#endif 1481b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o cd->pctx.dir = cd->pctx.ino; 14828fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o if ((dx_db->type == DX_DIRBLOCK_ROOT) || 14838fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o (dx_db->type == DX_DIRBLOCK_NODE)) 148481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong parse_int_node(fs, db, cd, dx_dir, buf, failed_csum); 14858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o } 1486e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong 14870ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (offset != max_block_size) { 14880ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong cd->pctx.num = rec_len + offset - max_block_size; 14890ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) { 14900ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong dirent->rec_len = cd->pctx.num; 14910ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong dir_modified++; 14921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 14933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 14943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dir_modified) { 14952e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong int flags, will_rehash; 1496e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong /* leaf block with no tail? Rehash dirs later. */ 149786f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong if (ext2fs_has_feature_metadata_csum(fs->super) && 1498e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong is_leaf && 149917641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong !inline_data_size && 150017641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) { 150117641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong if (insert_dirent_tail(fs, buf) == 0) 150217641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong goto write_and_fix; 1503e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong e2fsck_rehash_dir_later(ctx, ino); 150417641bf208afc98a59a0a245ecaa06ecb8e081ddDarrick J. Wong } 1505e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong 1506e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wongwrite_and_fix: 15072e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong will_rehash = e2fsck_dir_will_be_rehashed(ctx, ino); 15082e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong if (will_rehash) { 15092e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong flags = ctx->fs->flags; 1510e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; 15112e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong } 15126582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu if (inline_data_size) { 15130ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong buf = ibuf; 1514cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#ifdef WORDS_BIGENDIAN 15150ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (db->blockcnt) 15160ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong goto skip_first_write_swab; 1517cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf)); 1518cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong cd->pctx.errcode = ext2fs_dirent_swab_out2(fs, 1519cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong buf + EXT4_INLINE_DATA_DOTDOT_SIZE, 15200ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong EXT4_MIN_INLINE_DATA_SIZE - 1521cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong EXT4_INLINE_DATA_DOTDOT_SIZE, 1522cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong 0); 15230ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (cd->pctx.errcode) 15240ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong goto skip_second_write_swab; 15250ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_first_write_swab: 15260ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE || 15270ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong !db->blockcnt) 15280ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong goto skip_second_write_swab; 15290ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong cd->pctx.errcode = ext2fs_dirent_swab_out2(fs, 15300ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong buf + EXT4_MIN_INLINE_DATA_SIZE, 15310ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong inline_data_size - 15320ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong EXT4_MIN_INLINE_DATA_SIZE, 15330ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wong 0); 15340ac4b3973f313a0bd914b21e85c67b1b76e742fbDarrick J. Wongskip_second_write_swab: 1535cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong if (cd->pctx.errcode && 1536cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong !fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx)) 1537cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong goto abort_free_dict; 1538cd971869d77a9899db326d2ed42e1ef2916ba29fDarrick J. Wong#endif 15396582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.errcode = 15406582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu ext2fs_inline_data_set(fs, ino, 0, buf, 15416582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu inline_data_size); 15426582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu } else 15436582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr, 15446582dbe91b368ba01eb685d1314dd830fa00bde4Zheng Liu buf, 0, ino); 15452e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong if (will_rehash) 15462e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong ctx->fs->flags = (flags & 15472e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong EXT2_FLAG_IGNORE_CSUM_ERRORS) | 15482e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong (ctx->fs->flags & 15492e9d8391560ecde48e0b21f174fdb7bf3331345aDarrick J. Wong ~EXT2_FLAG_IGNORE_CSUM_ERRORS); 15501b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (cd->pctx.errcode) { 155108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK, 15520926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o &cd->pctx)) 15530926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o goto abort_free_dict; 15543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 15553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ext2fs_mark_changed(fs); 1556e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong } else if (is_leaf && failed_csum && !dir_modified) { 1557e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong /* 1558e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong * If a leaf node that fails csum makes it this far without 1559e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong * alteration, ask the user if the checksum should be fixed. 1560e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong */ 1561e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong if (fix_problem(ctx, PR_2_LEAF_NODE_ONLY_CSUM_INVALID, 1562e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong &cd->pctx)) 1563e8548796a5bb59b2319c81973b7a460f036faa3eDarrick J. Wong goto write_and_fix; 15643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 15650926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o dict_free_nodes(&de_dict); 15663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 15670926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'oabort_free_dict: 15680926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 156949a7360ba6b986242d9f0f33e102291d2e0dfb47Jose R. Santos dict_free_nodes(&de_dict); 15700926668d3af802b4d385d0fc3525a5a4e679574aTheodore Ts'o return DIRENT_ABORT; 15713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 15723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1573624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kalistruct del_block { 1574624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali e2fsck_t ctx; 1575624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali e2_blkcnt_t num; 1576624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali}; 1577624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali 15783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 15793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This function is called to deallocate a block, and is an interator 15803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * functioned called by deallocate inode via ext2fs_iterate_block(). 15813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 15823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int deallocate_inode_block(ext2_filsys fs, 15836dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson blk64_t *block_nr, 1584544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 15856dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson blk64_t ref_block EXT2FS_ATTR((unused)), 1586544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o int ref_offset EXT2FS_ATTR((unused)), 1587133a56dc9da52054bc27b4c1a23f03e3405003dbTheodore Ts'o void *priv_data) 15883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 1589624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali struct del_block *p = priv_data; 1590efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 15914a05268cf86f7138c78d80a53f7e162f32128a3dTheodore Ts'o if (*block_nr == 0) 15923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 15931ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o if ((*block_nr < fs->super->s_first_data_block) || 15944efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson (*block_nr >= ext2fs_blocks_count(fs->super))) 15951ba7a2f2b6a9b152828a06443955a7fb1d139930Theodore Ts'o return 0; 15968dd650ab9ac394c6d6d19b02e8bb22d5a1e5da0dDarrick J. Wong if ((*block_nr % EXT2FS_CLUSTER_RATIO(fs)) == 0) 15978dd650ab9ac394c6d6d19b02e8bb22d5a1e5da0dDarrick J. Wong ext2fs_block_alloc_stats2(fs, *block_nr, -1); 1598624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali p->num++; 15993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 16003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 1601efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 16023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 16033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This fuction deallocates an inode 16043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 16054035f40bc4550ce7520724cc837992a700794e00Theodore Ts'ostatic void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) 16063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 16071b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 16083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 16091b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o struct problem_context pctx; 16100684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o __u32 count; 1611624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali struct del_block del_block; 1612efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 161308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); 16141b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o clear_problem_context(&pctx); 16151b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx.ino = ino; 1616f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 16173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 16183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Fix up the bitmaps... 16193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 1620f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o e2fsck_read_bitmaps(ctx); 16210684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); 16220684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o 16230c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o if (ext2fs_file_acl_block(fs, &inode) && 162486f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong ext2fs_has_feature_xattr(fs->super)) { 162539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong pctx.errcode = ext2fs_adjust_ea_refcount3(fs, 162639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong ext2fs_file_acl_block(fs, &inode), 162739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong block_buf, -1, &count, ino); 16280684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { 16290684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o pctx.errcode = 0; 16300684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o count = 1; 16310684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o } 16320684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o if (pctx.errcode) { 16330c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o pctx.blk = ext2fs_file_acl_block(fs, &inode); 16340684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); 16350684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 16360684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o return; 16370684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o } 16380684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o if (count == 0) { 163948f23054bb8ad0506c0baa9f06ba182acc2aa88bValerie Aurora Henson ext2fs_block_alloc_stats2(fs, 16400c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o ext2fs_file_acl_block(fs, &inode), -1); 16410684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o } 16420c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o ext2fs_file_acl_block_set(fs, &inode, 0); 16430684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o } 16443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 16450c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) 1646c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o goto clear_inode; 1647a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o 16482ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong /* Inline data inodes don't have blocks to iterate */ 16492ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong if (inode.i_flags & EXT4_INLINE_DATA_FL) 16502ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong goto clear_inode; 16512ece839011f3074c2249dcfbf99945c93cc1927dDarrick J. Wong 16523b6c0938ec5aa401c7ae6c95e94e5ad30a7b8562Darrick J. Wong if (LINUX_S_ISREG(inode.i_mode) && 16533b6c0938ec5aa401c7ae6c95e94e5ad30a7b8562Darrick J. Wong ext2fs_needs_large_file_feature(EXT2_I_SIZE(&inode))) 1654a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o ctx->large_files--; 1655a47426914745b7d50bb58a3d44b3509c647c637eTheodore Ts'o 1656624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali del_block.ctx = ctx; 1657624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali del_block.num = 0; 16586dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf, 1659624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali deallocate_inode_block, 1660624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0Aditya Kali &del_block); 16611b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx.errcode) { 16621b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); 166308b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o ctx->flags |= E2F_FLAG_ABORT; 166408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return; 16651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o } 1666c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'oclear_inode: 1667c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o /* Inode may have changed by block_iterate, so reread it */ 1668c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); 1669c8ec2bad18fdaa842f786f3b37c9320a3411aea3Theodore Ts'o e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); 16703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 16713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 16728fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o/* 16738fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o * This fuction clears the htree flag on an inode 16748fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o */ 16758fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'ostatic void clear_htree(e2fsck_t ctx, ext2_ino_t ino) 16768fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o{ 16778fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o struct ext2_inode inode; 1678efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 16798fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o e2fsck_read_inode(ctx, ino, &inode, "clear_htree"); 16808fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL; 16818fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o e2fsck_write_inode(ctx, ino, &inode, "clear_htree"); 1682b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o if (ctx->dirs_to_hash) 1683b7a00563b22b0ea47ddc7117508c0b8e0d65df43Theodore Ts'o ext2fs_u32_list_add(ctx->dirs_to_hash, ino); 16848fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o} 16858fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 16868fdc9985c1e2a4467630b33719b7feb281b7b33bTheodore Ts'o 1687f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'oint e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, 1688f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'o ext2_ino_t ino, char *buf) 16893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 16901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 16913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_inode inode; 16923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int inode_modified = 0; 16936c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o int not_fixed = 0; 16941e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o unsigned char *frag, *fsize; 169521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o struct problem_context pctx; 16963c7c6d73f1a0bd45835966f1179fc3e8236a7d9cTheodore Ts'o problem_t problem = 0; 16973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 169808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode"); 169921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 170021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o clear_problem_context(&pctx); 170121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.ino = ino; 170221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.dir = dir; 170321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.inode = &inode; 170421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 17050c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o if (ext2fs_file_acl_block(fs, &inode) && 170686f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong !ext2fs_has_feature_xattr(fs->super)) { 1707f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) { 17080c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o ext2fs_file_acl_block_set(fs, &inode, 0); 1709f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o inode_modified++; 1710f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o } else 1711f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o not_fixed++; 1712f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o } 17136c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o 171450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) && 171550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) && 171650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) && 171708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o !(LINUX_S_ISSOCK(inode.i_mode))) 171808b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o problem = PR_2_BAD_MODE; 1719fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o else if (LINUX_S_ISCHR(inode.i_mode) 17200684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o && !e2fsck_pass1_check_device_inode(fs, &inode)) 172108b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o problem = PR_2_BAD_CHAR_DEV; 1722fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o else if (LINUX_S_ISBLK(inode.i_mode) 17230684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o && !e2fsck_pass1_check_device_inode(fs, &inode)) 172408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o problem = PR_2_BAD_BLOCK_DEV; 1725fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o else if (LINUX_S_ISFIFO(inode.i_mode) 17260684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o && !e2fsck_pass1_check_device_inode(fs, &inode)) 17271dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o problem = PR_2_BAD_FIFO; 1728fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o else if (LINUX_S_ISSOCK(inode.i_mode) 17290684a4f33b5c268fe12f57fcbc77a880c79ab282Theodore Ts'o && !e2fsck_pass1_check_device_inode(fs, &inode)) 17301dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o problem = PR_2_BAD_SOCKET; 1731fdbdea09b87dbd8e39c23286f22653e7641599aeTheodore Ts'o else if (LINUX_S_ISLNK(inode.i_mode) 17327cadc57780f3e3e8e644e8976e11a336902d4a25Theodore Ts'o && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) { 1733bcf9c5d4016975c3c2afdb4a4b358569bd3c8681Theodore Ts'o problem = PR_2_INVALID_SYMLINK; 173467052a8aeeca8cd80d1dd33c2792f917573accc8Andreas Dilger } 17351dde43f0c1176f61dd0bf91aff265ce8cd1c5fd6Theodore Ts'o 173608b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o if (problem) { 173708b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o if (fix_problem(ctx, problem, &pctx)) { 17381b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o deallocate_inode(ctx, ino, 0); 1739a02ce9df5ff5db2982462aec7162f7142dc18131Theodore Ts'o if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 174008b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o return 0; 17417cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o return 1; 17426c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o } else 17436c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o not_fixed++; 174408b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o problem = 0; 17457cf73dcd3d173d88ceab26d381f4abac362d8518Theodore Ts'o } 1746efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 17476c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o if (inode.i_faddr) { 17486c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) { 17496c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o inode.i_faddr = 0; 17506c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o inode_modified++; 17516c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o } else 17526c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o not_fixed++; 17533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 17541e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 17551e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o switch (fs->super->s_creator_os) { 17561e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o case EXT2_OS_HURD: 17571e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o frag = &inode.osd2.hurd2.h_i_frag; 17581e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o fsize = &inode.osd2.hurd2.h_i_fsize; 17591e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o break; 17601e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o default: 17611e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o frag = fsize = 0; 17621e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o } 176321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (frag && *frag) { 176421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.num = *frag; 17651b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) { 176621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *frag = 0; 176721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o inode_modified++; 17687e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o } else 17697e0282c5f21add344b306876ca999aecd4d5fd0cTheodore Ts'o not_fixed++; 177021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.num = 0; 177121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 177221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (fsize && *fsize) { 177321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.num = *fsize; 17741b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) { 177521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *fsize = 0; 177621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o inode_modified++; 17776c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o } else 17786c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o not_fixed++; 177921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o pctx.num = 0; 178021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 178121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 17825d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o if ((fs->super->s_creator_os == EXT2_OS_LINUX) && 178386f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong !ext2fs_has_feature_huge_file(fs->super) && 17845d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o (inode.osd2.linux2.l_i_blocks_hi != 0)) { 17855d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o pctx.num = inode.osd2.linux2.l_i_blocks_hi; 17865d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) { 17875d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o inode.osd2.linux2.l_i_blocks_hi = 0; 17885d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o inode_modified++; 17895d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o } 17905d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o } 17915d17119d14fe1276936c85d7986695a4543b1aa1Theodore Ts'o 179236769c606c270094df0431cbcab9932905adcedcJustus Winter if ((fs->super->s_creator_os == EXT2_OS_LINUX) && 179386f3b6cf98a72c6dad0738e3af2512ddcbd49be9Darrick J. Wong !ext2fs_has_feature_64bit(fs->super) && 1794911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o inode.osd2.linux2.l_i_file_acl_high != 0) { 1795911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o pctx.num = inode.osd2.linux2.l_i_file_acl_high; 1796911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) { 1797911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o inode.osd2.linux2.l_i_file_acl_high = 0; 1798911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o inode_modified++; 1799911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o } else 1800911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o not_fixed++; 1801911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o } 1802911ec6261568ca56d2d7b9a15f00578c4d127cf4Theodore Ts'o 18030c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o if (ext2fs_file_acl_block(fs, &inode) && 18040c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o ((ext2fs_file_acl_block(fs, &inode) < fs->super->s_first_data_block) || 18050c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o (ext2fs_file_acl_block(fs, &inode) >= ext2fs_blocks_count(fs->super)))) { 18066c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) { 18070c80c44bd08c60f3cd0ad87f12a71a75cac3bcaaTheodore Ts'o ext2fs_file_acl_block_set(fs, &inode, 0); 18086c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o inode_modified++; 18096c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o } else 18106c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o not_fixed++; 1811342d847db355d81299218e07a1e58ece82080a04Theodore Ts'o } 181221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (inode.i_dir_acl && 18136c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o LINUX_S_ISDIR(inode.i_mode)) { 18146c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) { 18156c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o inode.i_dir_acl = 0; 18166c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o inode_modified++; 18176c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o } else 18186c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o not_fixed++; 181921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 18206c313fd4732adbb83d6f9c402300487b6a7e84bbTheodore Ts'o 1821f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (inode_modified) 182208b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode"); 1823f76344fb6f9439ecd5060943930e73cd3b3dd9feTheodore Ts'o if (!not_fixed && ctx->inode_bad_map) 1824c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); 18253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 18263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 18273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 182850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o/* 182950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * allocate_dir_block --- this function allocates a new directory 183050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * block for a particular inode; this is done if a directory has 183150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * a "hole" in it, or if a directory has a illegal block number 183250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * that was zeroed out and now needs to be replaced. 183350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */ 18341b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'ostatic int allocate_dir_block(e2fsck_t ctx, 18356dc64392c052839f373b7bbbb58efa3048bfb355Valerie Aurora Henson struct ext2_db_entry2 *db, 1836efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o char *buf EXT2FS_ATTR((unused)), 1837544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o struct problem_context *pctx) 183850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o{ 18391b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o ext2_filsys fs = ctx->fs; 1840ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong blk64_t blk = 0; 184150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o char *block; 184250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o struct ext2_inode inode; 184350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 18441b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0) 184550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return 1; 184650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 184750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o /* 184850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * Read the inode and block bitmaps in; we'll be messing with 184950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * them. 185050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */ 1851f8188fff23dc2d9c9f858fb21264e46b17672825Theodore Ts'o e2fsck_read_bitmaps(ctx); 1852efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 185350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o /* 185450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * First, find a free block 185550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */ 1856ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block"); 1857ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong pctx->errcode = ext2fs_map_cluster_block(fs, db->ino, &inode, 1858ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong db->blockcnt, &blk); 1859ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong if (pctx->errcode || blk == 0) { 18607b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong blk = ext2fs_find_inode_goal(fs, db->ino, &inode, db->blockcnt); 18617b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong pctx->errcode = ext2fs_new_block2(fs, blk, 1862ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong ctx->block_found_map, &blk); 1863ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong if (pctx->errcode) { 1864ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong pctx->str = "ext2fs_new_block"; 1865ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 1866ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong return 1; 1867ff11309ecc24fae663a4d65947b24c371a04a5c7Darrick J. Wong } 186850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o } 1869c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); 1870c5d2f50dee996e48e96066155f85d7c925fcba0dValerie Aurora Henson ext2fs_mark_block_bitmap2(fs->block_map, blk); 187150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o ext2fs_mark_bb_dirty(fs); 187250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 187350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o /* 187450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * Now let's create the actual data block for the inode 187550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */ 187650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (db->blockcnt) 18771b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block); 187850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o else 18791b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx->errcode = ext2fs_new_dir_block(fs, db->ino, 18801b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o EXT2_ROOT_INO, &block); 188150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 18821b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx->errcode) { 18831b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx->str = "ext2fs_new_dir_block"; 18841b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 188550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return 1; 188650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o } 188750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 188881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong pctx->errcode = ext2fs_write_dir_block4(fs, blk, block, 0, db->ino); 1889c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&block); 18901b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx->errcode) { 18911b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx->str = "ext2fs_write_dir_block"; 18921b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 189350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return 1; 189450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o } 189550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 189650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o /* 189750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * Update the inode block count 189850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */ 18991ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o ext2fs_iblk_add_blocks(fs, &inode, 1); 190062f9bd0e4f7547fe01f829025888d477a973a539Theodore Ts'o if (EXT2_I_SIZE(&inode) < ((__u64) db->blockcnt+1) * fs->blocksize) { 190197c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong pctx->errcode = ext2fs_inode_size_set(fs, &inode, 190297c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong (db->blockcnt+1) * fs->blocksize); 190397c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong if (pctx->errcode) { 190497c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong pctx->str = "ext2fs_inode_size_set"; 190597c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 190697c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong return 1; 190797c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong } 190897c607b1a25e1f4e83bf246c76b679d91470f5dcDarrick J. Wong } 190908b213017f8371ce4b56ad4d368eb0f92211d04eTheodore Ts'o e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block"); 191050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 191150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o /* 191250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o * Finally, update the block pointers for the inode 191350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o */ 191450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o db->blk = blk; 19152d07b3ad98bfe1db5fb1071f53a5338ab6c35522Theodore Ts'o pctx->errcode = ext2fs_bmap2(fs, db->ino, &inode, 0, BMAP_SET, 19162d07b3ad98bfe1db5fb1071f53a5338ab6c35522Theodore Ts'o db->blockcnt, 0, &blk); 19171b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o if (pctx->errcode) { 19181b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o pctx->str = "ext2fs_block_iterate"; 19191b6bf1759af884957234b7dce768b785f792abd0Theodore Ts'o fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); 192050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return 1; 192150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o } 192250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o 192350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return 0; 192450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o} 1925