diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-06-21 21:07:38 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-06-21 21:07:38 -0400 |
commit | 8a480350952f6f0fdbce54326b6d847e66368897 (patch) | |
tree | 8f09d26e06335f00dec8166acaae425cc30c3523 /e2fsck | |
parent | 8a6ede8b7a8d5be0d49d6bfa7616537b61dfdc1b (diff) | |
download | e2fsprogs-8a480350952f6f0fdbce54326b6d847e66368897.tar.gz |
Fix encoding for rec_len in directories for >= 64k blocksize file systems
Previously e2fsprogs interpreted 0 for a rec_len of 65536 (which could
occur if the directory block is completely empty in 64k blocksize
filesystems), while the kernel interpreted 65535 to mean 65536. The
kernel will accept both to mean 65536, and encodes 65535 to be 65536.
This commit changes e2fsprogs to match.
We add the encoding agreed upon for 128k and 256k filesystems, but we
don't enable support for these larger block sizes, since they haven't
been fully tested.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'e2fsck')
-rw-r--r-- | e2fsck/message.c | 13 | ||||
-rw-r--r-- | e2fsck/pass1.c | 10 | ||||
-rw-r--r-- | e2fsck/pass2.c | 42 | ||||
-rw-r--r-- | e2fsck/rehash.c | 37 |
4 files changed, 60 insertions, 42 deletions
diff --git a/e2fsck/message.c b/e2fsck/message.c index 5158ed64..3f859160 100644 --- a/e2fsck/message.c +++ b/e2fsck/message.c @@ -347,10 +347,11 @@ static _INLINE_ void expand_inode_expression(char ch, /* * This function expands '%dX' expressions */ -static _INLINE_ void expand_dirent_expression(char ch, +static _INLINE_ void expand_dirent_expression(ext2_filsys fs, char ch, struct problem_context *ctx) { struct ext2_dir_entry *dirent; + unsigned int rec_len; int len; if (!ctx || !ctx->dirent) @@ -366,12 +367,14 @@ static _INLINE_ void expand_dirent_expression(char ch, len = dirent->name_len & 0xFF; if (len > EXT2_NAME_LEN) len = EXT2_NAME_LEN; - if (len > dirent->rec_len) - len = dirent->rec_len; + if ((ext2fs_get_rec_len(fs, dirent, &rec_len) == 0) && + (len > rec_len)) + len = rec_len; safe_print(dirent->name, len); break; case 'r': - printf("%u", dirent->rec_len); + (void) ext2fs_get_rec_len(fs, dirent, &rec_len); + printf("%u", rec_len); break; case 'l': printf("%u", dirent->name_len & 0xFF); @@ -490,7 +493,7 @@ void print_e2fsck_message(e2fsck_t ctx, const char *msg, expand_inode_expression(*cp, pctx); } else if (cp[0] == '%' && cp[1] == 'D') { cp += 2; - expand_dirent_expression(*cp, pctx); + expand_dirent_expression(fs, *cp, pctx); } else if ((cp[0] == '%')) { cp++; expand_percent_expression(fs, *cp, pctx); diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 46189c0d..518c2ff8 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -434,8 +434,9 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, return; dirent = (struct ext2_dir_entry *) buf; - rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ? - dirent->rec_len : 65536; + retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); + if (retval) + return; if (((dirent->name_len & 0xFF) != 1) || (dirent->name[0] != '.') || (dirent->inode != pctx->ino) || @@ -445,8 +446,9 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, return; dirent = (struct ext2_dir_entry *) (buf + rec_len); - rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ? - dirent->rec_len : 65536; + retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); + if (retval) + return; if (((dirent->name_len & 0xFF) != 2) || (dirent->name[0] != '.') || (dirent->name[1] != '.') || diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index f5a326d3..bb3813cd 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -352,9 +352,9 @@ static int check_dot(e2fsck_t ctx, ext2_ino_t ino, struct problem_context *pctx) { struct ext2_dir_entry *nextdir; + unsigned int rec_len, new_len; int status = 0; int created = 0; - int rec_len, new_len; int problem = 0; if (!dirent->inode) @@ -365,8 +365,7 @@ static int check_dot(e2fsck_t ctx, else if (dirent->name[1] != '\0') problem = PR_2_DOT_NULL_TERM; - rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); if (problem) { if (fix_problem(ctx, problem, pctx)) { if (rec_len < 12) @@ -393,7 +392,8 @@ static int check_dot(e2fsck_t ctx, nextdir = (struct ext2_dir_entry *) ((char *) dirent + 12); dirent->rec_len = 12; - nextdir->rec_len = new_len; + (void) ext2fs_set_rec_len(ctx->fs, new_len, + nextdir); nextdir->inode = 0; nextdir->name_len = 0; status = 1; @@ -423,8 +423,7 @@ static int check_dotdot(e2fsck_t ctx, else if (dirent->name[2] != '\0') problem = PR_2_DOT_DOT_NULL_TERM; - rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); if (problem) { if (fix_problem(ctx, problem, pctx)) { if (rec_len < 12) @@ -647,11 +646,11 @@ static void salvage_directory(ext2_filsys fs, unsigned int *offset) { char *cp = (char *) dirent; - int left, rec_len; + int left; + unsigned int rec_len, prev_rec_len; unsigned int name_len = dirent->name_len & 0xFF; - rec_len = (dirent->rec_len || fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(fs, dirent, &rec_len); left = fs->blocksize - *offset - rec_len; /* @@ -669,10 +668,11 @@ static void salvage_directory(ext2_filsys fs, * record length. */ if ((left < 0) && - (name_len + 8 <= rec_len + (unsigned) left) && + ((int) rec_len + left > 8) && + (name_len + 8 <= (int) rec_len + left) && dirent->inode <= fs->super->s_inodes_count && strnlen(dirent->name, name_len) == name_len) { - dirent->rec_len += left; + (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent); return; } /* @@ -682,7 +682,9 @@ static void salvage_directory(ext2_filsys fs, */ if (prev && rec_len && (rec_len % 4) == 0 && (*offset + rec_len <= fs->blocksize)) { - prev->rec_len += rec_len; + (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); + prev_rec_len += rec_len; + (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); *offset += rec_len; return; } @@ -693,10 +695,13 @@ static void salvage_directory(ext2_filsys fs, * new empty directory entry the rest of the directory block. */ if (prev) { - prev->rec_len += fs->blocksize - *offset; + (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); + prev_rec_len += fs->blocksize - *offset; + (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); *offset = fs->blocksize; } else { - dirent->rec_len = fs->blocksize - *offset; + rec_len = fs->blocksize - *offset; + (void) ext2fs_set_rec_len(fs, rec_len, dirent); dirent->name_len = 0; dirent->inode = 0; } @@ -808,8 +813,7 @@ static int check_dir_block(ext2_filsys fs, dx_db->max_hash = 0; dirent = (struct ext2_dir_entry *) buf; - rec_len = (dirent->rec_len || fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(fs, dirent, &rec_len); limit = (struct ext2_dx_countlimit *) (buf+8); if (db->blockcnt == 0) { root = (struct ext2_dx_root_info *) (buf + 24); @@ -847,8 +851,7 @@ out_htree: problem = 0; dirent = (struct ext2_dir_entry *) (buf + offset); - rec_len = (dirent->rec_len || fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(fs, dirent, &rec_len); cd->pctx.dirent = dirent; cd->pctx.num = offset; if (((offset + rec_len) > fs->blocksize) || @@ -1104,8 +1107,7 @@ out_htree: next: prev = dirent; if (dir_modified) - rec_len = (dirent->rec_len || fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(fs, dirent, &rec_len); offset += rec_len; dot_state++; } while (offset < fs->blocksize); diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index d2dbcce1..50388f36 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -88,8 +88,8 @@ static int fill_dir_block(ext2_filsys fs, struct hash_entry *new_array, *ent; struct ext2_dir_entry *dirent; char *dir; - unsigned int offset, dir_offset; - int rec_len, hash_alg; + unsigned int offset, dir_offset, rec_len; + int hash_alg; if (blockcnt < 0) return 0; @@ -103,7 +103,7 @@ static int fill_dir_block(ext2_filsys fs, if (HOLE_BLKADDR(*block_nr)) { memset(dir, 0, fs->blocksize); dirent = (struct ext2_dir_entry *) dir; - dirent->rec_len = fs->blocksize; + (void) ext2fs_set_rec_len(fs, fs->blocksize, dirent); } else { fd->err = ext2fs_read_dir_block(fs, *block_nr, dir); if (fd->err) @@ -117,8 +117,7 @@ static int fill_dir_block(ext2_filsys fs, dir_offset = 0; while (dir_offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (dir + dir_offset); - rec_len = (dirent->rec_len || fs->blocksize < 65536) ? - dirent->rec_len : 65536; + (void) ext2fs_get_rec_len(fs, dirent, &rec_len); if (((dir_offset + rec_len) > fs->blocksize) || (rec_len < 8) || ((rec_len % 4) != 0) || @@ -404,7 +403,8 @@ static errcode_t copy_dir_entries(e2fsck_t ctx, char *block_start; struct hash_entry *ent; struct ext2_dir_entry *dirent; - int i, rec_len, left; + unsigned int rec_len, prev_rec_len; + int i, left; ext2_dirhash_t prev_hash; int offset, slack; @@ -429,6 +429,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx, if ((retval = get_next_block(fs, outdir, &block_start))) return retval; dirent = (struct ext2_dir_entry *) block_start; + prev_rec_len = 0; left = fs->blocksize; slack = fd->compress ? 12 : (fs->blocksize * ctx->htree_slack_percentage)/100; @@ -440,8 +441,12 @@ static errcode_t copy_dir_entries(e2fsck_t ctx, continue; rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF); if (rec_len > left) { - if (left) - dirent->rec_len += left; + if (left) { + left += prev_rec_len; + retval = ext2fs_set_rec_len(fs, left, dirent); + if (retval) + return retval; + } if ((retval = get_next_block(fs, outdir, &block_start))) return retval; @@ -457,21 +462,27 @@ static errcode_t copy_dir_entries(e2fsck_t ctx, } dirent->inode = ent->dir->inode; dirent->name_len = ent->dir->name_len; - dirent->rec_len = rec_len; + retval = ext2fs_set_rec_len(fs, rec_len, dirent); + if (retval) + return retval; + prev_rec_len = rec_len; memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF); offset += rec_len; left -= rec_len; if (left < slack) { - dirent->rec_len += left; + prev_rec_len += left; + retval = ext2fs_set_rec_len(fs, prev_rec_len, dirent); + if (retval) + return retval; offset += left; left = 0; } prev_hash = ent->hash; } if (left) - dirent->rec_len += left; + retval = ext2fs_set_rec_len(fs, rec_len + left, dirent); - return 0; + return retval; } @@ -522,7 +533,7 @@ static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf) memset(buf, 0, fs->blocksize); dir = (struct ext2_dir_entry *) buf; dir->inode = 0; - dir->rec_len = fs->blocksize; + (void) ext2fs_set_rec_len(fs, fs->blocksize, dir); limits = (struct ext2_dx_countlimit *) (buf+8); limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry); |