diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2012-08-02 17:27:43 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-08-02 17:27:43 -0400 |
commit | 81683c6a32045cf04d76a024e6f1753535b97c22 (patch) | |
tree | 0b624027ad1a3c3210907c0739c29e46ad040ec7 /lib/ext2fs | |
parent | 07307114dea005917b0c3a18a08948435f4a2abc (diff) | |
download | e2fsprogs-81683c6a32045cf04d76a024e6f1753535b97c22.tar.gz |
libext2fs: add checksums to the end of directory leaf nodes
Introduce small structures for recording directory tree checksums, and
some API changes to support writing out directory blocks with
checksums.
Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'lib/ext2fs')
-rw-r--r-- | lib/ext2fs/csum.c | 148 | ||||
-rw-r--r-- | lib/ext2fs/dir_iterate.c | 14 | ||||
-rw-r--r-- | lib/ext2fs/dirblock.c | 98 | ||||
-rw-r--r-- | lib/ext2fs/expanddir.c | 5 | ||||
-rw-r--r-- | lib/ext2fs/ext2_err.et.in | 3 | ||||
-rw-r--r-- | lib/ext2fs/ext2fs.h | 18 | ||||
-rw-r--r-- | lib/ext2fs/link.c | 6 | ||||
-rw-r--r-- | lib/ext2fs/mkdir.c | 2 | ||||
-rw-r--r-- | lib/ext2fs/newdir.c | 15 | ||||
-rw-r--r-- | lib/ext2fs/swapfs.c | 62 |
10 files changed, 306 insertions, 65 deletions
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c index 262eb759..e92bac53 100644 --- a/lib/ext2fs/csum.c +++ b/lib/ext2fs/csum.c @@ -93,6 +93,122 @@ errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, return __get_dx_countlimit(fs, dirent, cc, offset, 0); } +void ext2fs_initialize_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry_tail *t) +{ + memset(t, 0, sizeof(struct ext2_dir_entry_tail)); + ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail), + (struct ext2_dir_entry *)t); + t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM; +} + +static errcode_t __get_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dir_entry_tail **tt, + int need_swab) +{ + struct ext2_dir_entry *d; + void *top; + struct ext2_dir_entry_tail *t; + unsigned int rec_len; + errcode_t retval = 0; + __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16); + + d = dirent; + top = EXT2_DIRENT_TAIL(dirent, fs->blocksize); + + rec_len = translate(d->rec_len); + while (rec_len && !(rec_len & 0x3)) { + d = (struct ext2_dir_entry *)(((void *)d) + rec_len); + if ((void *)d >= top) + break; + rec_len = translate(d->rec_len); + } + + if (d != top) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + t = (struct ext2_dir_entry_tail *)d; + if (t->det_reserved_zero1 || + translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) || + translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + if (tt) + *tt = t; + return retval; +} + +int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent) +{ + return __get_dirent_tail(fs, dirent, NULL, 0) == 0; +} + +static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, __u32 *crc, + int size) +{ + errcode_t retval; + char *buf = (char *)dirent; + __u32 gen; + struct ext2_inode inode; + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size); + + return 0; +} + +int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + errcode_t retval; + __u32 calculated; + struct ext2_dir_entry_tail *t; + + retval = __get_dirent_tail(fs, dirent, &t, 1); + if (retval) + return 1; + + /* + * The checksum field is overlaid with the dirent->name field + * so the swapfs.c functions won't change the endianness. + */ + retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated, + (void *)t - (void *)dirent); + if (retval) + return 0; + return ext2fs_le32_to_cpu(t->det_checksum) == calculated; +} + +static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + errcode_t retval; + __u32 crc; + struct ext2_dir_entry_tail *t; + + retval = __get_dirent_tail(fs, dirent, &t, 1); + if (retval) + return retval; + + /* swapfs.c functions don't change the checksum endianness */ + retval = ext2fs_dirent_csum(fs, inum, dirent, &crc, + (void *)t - (void *)dirent); + if (retval) + return retval; + t->det_checksum = ext2fs_cpu_to_le32(crc); + return 0; +} + static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, struct ext2_dir_entry *dirent, __u32 *crc, int count_offset, int count, @@ -179,6 +295,38 @@ static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum, return retval; } +int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + return 1; + + if (__get_dirent_tail(fs, dirent, NULL, 1) == 0) + return ext2fs_dirent_csum_verify(fs, inum, dirent); + if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0) + return ext2fs_dx_csum_verify(fs, inum, dirent); + + return 0; +} + +errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + return 0; + + if (__get_dirent_tail(fs, dirent, NULL, 1) == 0) + return ext2fs_dirent_csum_set(fs, inum, dirent); + if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0) + return ext2fs_dx_csum_set(fs, inum, dirent); + + if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) + return 0; + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; +} + #define EXT3_EXTENT_TAIL_OFFSET(hdr) (sizeof(struct ext3_extent_header) + \ (sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max))) diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c index 5125d199..c24015cc 100644 --- a/lib/ext2fs/dir_iterate.c +++ b/lib/ext2fs/dir_iterate.c @@ -192,17 +192,23 @@ int ext2fs_process_dir_block(ext2_filsys fs, unsigned int rec_len, size; int entry; struct ext2_dir_entry *dirent; + int csum_size = 0; if (blockcnt < 0) return 0; entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE; - ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0); + ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0, + ctx->dir); if (ctx->errcode) return BLOCK_ABORT; - while (offset < fs->blocksize) { + if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + while (offset < (fs->blocksize - csum_size)) { dirent = (struct ext2_dir_entry *) (ctx->buf + offset); if (ext2fs_get_rec_len(fs, dirent, &rec_len)) return BLOCK_ABORT; @@ -259,8 +265,8 @@ next: } if (changed) { - ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf, - 0); + ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, ctx->buf, + 0, ctx->dir); if (ctx->errcode) return BLOCK_ABORT; } diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c index cb3a104c..54b27772 100644 --- a/lib/ext2fs/dirblock.c +++ b/lib/ext2fs/dirblock.c @@ -20,45 +20,36 @@ #include "ext2_fs.h" #include "ext2fs.h" -errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, - void *buf, int flags EXT2FS_ATTR((unused))) +errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags EXT2FS_ATTR((unused)), + ext2_ino_t ino) { errcode_t retval; - char *p, *end; - struct ext2_dir_entry *dirent; - unsigned int name_len, rec_len; - + int corrupt = 0; retval = io_channel_read_blk64(fs->io, block, 1, buf); if (retval) return retval; - p = (char *) buf; - end = (char *) buf + fs->blocksize; - while (p < end-8) { - dirent = (struct ext2_dir_entry *) p; -#ifdef WORDS_BIGENDIAN - dirent->inode = ext2fs_swab32(dirent->inode); - dirent->rec_len = ext2fs_swab16(dirent->rec_len); - dirent->name_len = ext2fs_swab16(dirent->name_len); -#endif - name_len = dirent->name_len; + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_dir_block_csum_verify(fs, ino, + (struct ext2_dir_entry *)buf)) + corrupt = 1; + #ifdef WORDS_BIGENDIAN - if (flags & EXT2_DIRBLOCK_V2_STRUCT) - dirent->name_len = ext2fs_swab16(dirent->name_len); + retval = ext2fs_dirent_swab_in(fs, buf, flags); #endif - if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0) - return retval; - if ((rec_len < 8) || (rec_len % 4)) { - rec_len = 8; - retval = EXT2_ET_DIR_CORRUPTED; - } else if (((name_len & 0xFF) + 8) > rec_len) - retval = EXT2_ET_DIR_CORRUPTED; - p += rec_len; - } + if (!retval && corrupt) + retval = EXT2_ET_DIR_CSUM_INVALID; return retval; } +errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_read_dir_block4(fs, block, buf, flags, 0); +} + errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, void *buf, int flags EXT2FS_ATTR((unused))) { @@ -72,45 +63,40 @@ errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, } -errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, - void *inbuf, int flags EXT2FS_ATTR((unused))) +errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block, + void *inbuf, int flags EXT2FS_ATTR((unused)), + ext2_ino_t ino) { -#ifdef WORDS_BIGENDIAN errcode_t retval; - char *p, *end; - char *buf = 0; - unsigned int rec_len; - struct ext2_dir_entry *dirent; + char *buf = inbuf; +#ifdef WORDS_BIGENDIAN retval = ext2fs_get_mem(fs->blocksize, &buf); if (retval) return retval; memcpy(buf, inbuf, fs->blocksize); - p = buf; - end = buf + fs->blocksize; - while (p < end) { - dirent = (struct ext2_dir_entry *) p; - if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0) - return retval; - if ((rec_len < 8) || - (rec_len % 4)) { - ext2fs_free_mem(&buf); - return (EXT2_ET_DIR_CORRUPTED); - } - p += rec_len; - dirent->inode = ext2fs_swab32(dirent->inode); - dirent->rec_len = ext2fs_swab16(dirent->rec_len); - dirent->name_len = ext2fs_swab16(dirent->name_len); - - if (flags & EXT2_DIRBLOCK_V2_STRUCT) - dirent->name_len = ext2fs_swab16(dirent->name_len); - } + retval = ext2fs_dirent_swab_out(fs, buf, flags); + if (retval) + return retval; +#endif + retval = ext2fs_dir_block_csum_set(fs, ino, + (struct ext2_dir_entry *)buf); + if (retval) + goto out; + retval = io_channel_write_blk64(fs->io, block, 1, buf); + +out: +#ifdef WORDS_BIGENDIAN ext2fs_free_mem(&buf); - return retval; -#else - return io_channel_write_blk64(fs->io, block, 1, (char *) inbuf); #endif + return retval; +} + +errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, + void *inbuf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0); } errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c index 41c40882..22558d66 100644 --- a/lib/ext2fs/expanddir.c +++ b/lib/ext2fs/expanddir.c @@ -24,6 +24,7 @@ struct expand_dir_struct { int newblocks; blk64_t goal; errcode_t err; + ext2_ino_t dir; }; static int expand_dir_proc(ext2_filsys fs, @@ -62,7 +63,8 @@ static int expand_dir_proc(ext2_filsys fs, return BLOCK_ABORT; } es->done = 1; - retval = ext2fs_write_dir_block(fs, new_blk, block); + retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, + es->dir); } else { retval = ext2fs_get_mem(fs->blocksize, &block); if (retval) { @@ -110,6 +112,7 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) es.err = 0; es.goal = 0; es.newblocks = 0; + es.dir = dir; retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 0, expand_dir_proc, &es); diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index 7289ae1c..430d5670 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -458,4 +458,7 @@ ec EXT2_ET_EXTENT_CSUM_INVALID, ec EXT2_ET_DIR_NO_SPACE_FOR_CSUM, "Directory block does not have space for checksum" +ec EXT2_ET_DIR_CSUM_INVALID, + "Directory block checksum does not match directory block" + end diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index ba4521ad..cc473990 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -943,6 +943,18 @@ extern __u32 ext2fs_crc32c_be(__u32 crc, unsigned char const *p, size_t len); extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len); /* csum.c */ +#define EXT2_DIRENT_TAIL(block, blocksize) \ + ((struct ext2_dir_entry_tail *)(((void *)(block)) + \ + (blocksize) - sizeof(struct ext2_dir_entry_tail))) + +extern void ext2fs_initialize_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry_tail *t); +extern int ext2fs_dirent_has_tail(ext2_filsys fs, + struct ext2_dir_entry *dirent); +extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, struct ext2_dir_entry *dirent, struct ext2_dx_countlimit **cc, @@ -1025,12 +1037,16 @@ extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, void *buf, int flags); extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, void *buf, int flags); +extern errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags, ext2_ino_t ino); extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, void *buf); extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, void *buf, int flags); extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, void *buf, int flags); +extern errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags, ext2_ino_t ino); /* dirhash.c */ extern errcode_t ext2fs_dirhash(int version, const char *name, int len, @@ -1427,6 +1443,8 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); /* swapfs.c */ +extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags); +extern errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags); extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header); extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header, diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c index 2d03b573..2dec5dc2 100644 --- a/lib/ext2fs/link.c +++ b/lib/ext2fs/link.c @@ -41,6 +41,7 @@ static int link_proc(struct ext2_dir_entry *dirent, struct ext2_dir_entry *next; unsigned int rec_len, min_rec_len, curr_rec_len; int ret = 0; + int csum_size = 0; rec_len = EXT2_DIR_REC_LEN(ls->namelen); @@ -48,12 +49,15 @@ static int link_proc(struct ext2_dir_entry *dirent, if (ls->err) return DIRENT_ABORT; + if (EXT2_HAS_RO_COMPAT_FEATURE(ls->fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + csum_size = sizeof(struct ext2_dir_entry_tail); /* * See if the following directory entry (if any) is unused; * if so, absorb it into this one. */ next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len); - if ((offset + (int) curr_rec_len < blocksize - 8) && + if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) && (next->inode == 0) && (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) { curr_rec_len += next->rec_len; diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c index 861ddabb..4a854391 100644 --- a/lib/ext2fs/mkdir.c +++ b/lib/ext2fs/mkdir.c @@ -100,7 +100,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; - retval = ext2fs_write_dir_block(fs, blk, block); + retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); if (retval) goto cleanup; diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c index b0a1e476..2cd541d7 100644 --- a/lib/ext2fs/newdir.c +++ b/lib/ext2fs/newdir.c @@ -34,6 +34,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, char *buf; int rec_len; int filetype = 0; + struct ext2_dir_entry_tail *t; + int csum_size = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); @@ -43,7 +45,11 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, memset(buf, 0, fs->blocksize); dir = (struct ext2_dir_entry *) buf; - retval = ext2fs_set_rec_len(fs, fs->blocksize, dir); + if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + retval = ext2fs_set_rec_len(fs, fs->blocksize - csum_size, dir); if (retval) return retval; @@ -57,7 +63,7 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, dir->inode = dir_ino; dir->name_len = 1 | filetype; dir->name[0] = '.'; - rec_len = fs->blocksize - EXT2_DIR_REC_LEN(1); + rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1); dir->rec_len = EXT2_DIR_REC_LEN(1); /* @@ -73,6 +79,11 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, dir->name[1] = '.'; } + + if (csum_size) { + t = EXT2_DIRENT_TAIL(buf, fs->blocksize); + ext2fs_initialize_dirent_tail(fs, t); + } *block = buf; return 0; } diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c index 7c99373c..69916e59 100644 --- a/lib/ext2fs/swapfs.c +++ b/lib/ext2fs/swapfs.c @@ -350,4 +350,66 @@ void ext2fs_swap_mmp(struct mmp_struct *mmp) mmp->mmp_check_interval = ext2fs_swab16(mmp->mmp_check_interval); } +errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags) +{ + errcode_t retval; + char *p, *end; + struct ext2_dir_entry *dirent; + unsigned int name_len, rec_len; + + p = (char *) buf; + end = (char *) buf + fs->blocksize; + while (p < end-8) { + dirent = (struct ext2_dir_entry *) p; + dirent->inode = ext2fs_swab32(dirent->inode); + dirent->rec_len = ext2fs_swab16(dirent->rec_len); + dirent->name_len = ext2fs_swab16(dirent->name_len); + name_len = dirent->name_len; + if (flags & EXT2_DIRBLOCK_V2_STRUCT) + dirent->name_len = ext2fs_swab16(dirent->name_len); + retval = ext2fs_get_rec_len(fs, dirent, &rec_len); + if (retval) + return retval; + if ((rec_len < 8) || (rec_len % 4)) { + rec_len = 8; + retval = EXT2_ET_DIR_CORRUPTED; + } else if (((name_len & 0xFF) + 8) > rec_len) + retval = EXT2_ET_DIR_CORRUPTED; + p += rec_len; + } + + return 0; +} + +errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags) +{ + errcode_t retval; + char *p, *end; + unsigned int rec_len; + struct ext2_dir_entry *dirent; + + p = buf; + end = buf + fs->blocksize; + while (p < end) { + dirent = (struct ext2_dir_entry *) p; + retval = ext2fs_get_rec_len(fs, dirent, &rec_len); + if (retval) + return retval; + if ((rec_len < 8) || + (rec_len % 4)) { + ext2fs_free_mem(&buf); + return EXT2_ET_DIR_CORRUPTED; + } + p += rec_len; + dirent->inode = ext2fs_swab32(dirent->inode); + dirent->rec_len = ext2fs_swab16(dirent->rec_len); + dirent->name_len = ext2fs_swab16(dirent->name_len); + + if (flags & EXT2_DIRBLOCK_V2_STRUCT) + dirent->name_len = ext2fs_swab16(dirent->name_len); + } + + return 0; +} + #endif |