From 674a4ee1e3e05133ddad701730bfc21c283272a4 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 23 Mar 1998 02:06:52 +0000 Subject: [PATCH] Many files: ext2fs.h: Add new superblock fields (s_algorithm_usage_bitmap, s_prealloc_blocks, s_prealloc_dir_blocks). Added conditional defines of new features COMPAT_DIR_PREALLOC, RO_COMPAT_LARGE_FILE RO_COMPAT_BTREE_DIR, INCOMPAT_COMPRESSION, INCOMPAT_DIRNAME_SIZE. Changed the library to declare that we support COMPAT_DIR_PREALLOC, INCOMPAT_DIRNAME_SIZE, RO_COMPAT_LARGE_FILE. fileio.c: Rename function ext2fs_file_llseek to be ext2fs_file_lseek, which is more accurate. block.c: Add new function ext2fs_block_iterate3 which calls the iterator function with the blockcount argument of type blkcnt_t. This version of the function is allowed to handle large files; the other fucntions are not. ext2fs.h: Add new type blkcnt_t ext2_err.et.in: Add error code EXT2_ET_FILE_TOO_BIG block.c (ext2fs_block_iterate2): Fix bug where the block count field wasn't getting correctly incremented for sparse files when the indirect or doubly-indirect block specified in the inode was zero. unlink.c (unlink_proc): lookup.c (lookup_proc): link.c (link_proc): get_pathname.c (get_pathname_proc): dir_iterate.c (ext2fs_process_dir_block): Mask off high 8 bits from dirent->name_len, so it can be used for other purposes. ext2fs.h: Add definition of EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE, and indicate that we have support for this incompatible option. --- lib/ext2fs/ChangeLog | 42 ++++++++++++++++++++++ lib/ext2fs/block.c | 88 +++++++++++++++++++++++++++++++++++++++++------ lib/ext2fs/dir_iterate.c | 2 +- lib/ext2fs/dll/jump.funcs | 3 +- lib/ext2fs/ext2_err.et.in | 3 ++ lib/ext2fs/ext2fs.h | 59 +++++++++++++++++++++++++++---- lib/ext2fs/fileio.c | 4 +-- lib/ext2fs/get_pathname.c | 8 ++--- lib/ext2fs/link.c | 10 +++--- lib/ext2fs/lookup.c | 4 +-- lib/ext2fs/unlink.c | 5 +-- 11 files changed, 195 insertions(+), 33 deletions(-) diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index aa5aa5f..99285ee 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,45 @@ +1998-03-21 Theodore Ts'o + + * ext2fs.h: Add new superblock fields (s_algorithm_usage_bitmap, + s_prealloc_blocks, s_prealloc_dir_blocks). Added + conditional defines of new features COMPAT_DIR_PREALLOC, + RO_COMPAT_LARGE_FILE RO_COMPAT_BTREE_DIR, + INCOMPAT_COMPRESSION, INCOMPAT_DIRNAME_SIZE. Changed + the library to declare that we support COMPAT_DIR_PREALLOC, + INCOMPAT_DIRNAME_SIZE, RO_COMPAT_LARGE_FILE. + + * fileio.c: Rename function ext2fs_file_llseek to be + ext2fs_file_lseek, which is more accurate. + + * block.c: Add new function ext2fs_block_iterate3 which calls + the iterator function with the blockcount argument of + type blkcnt_t. This version of the function is + allowed to handle large files; the other fucntions are + not. + + * ext2fs.h: Add new type blkcnt_t + + * ext2_err.et.in: Add error code EXT2_ET_FILE_TOO_BIG + + * block.c (ext2fs_block_iterate2): Fix bug where the block count + field wasn't getting correctly incremented for sparse + files when the indirect or doubly-indirect block + specified in the inode was zero. + +Sun Mar 8 22:42:47 1998 Theodore Ts'o + + * unlink.c (unlink_proc): + * lookup.c (lookup_proc): + * link.c (link_proc): + * get_pathname.c (get_pathname_proc): + * dir_iterate.c (ext2fs_process_dir_block): Mask off high 8 bits + from dirent->name_len, so it can be used for other + purposes. + + * ext2fs.h: Add definition of EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE, + and indicate that we have support for this incompatible + option. + Mon Feb 23 08:46:33 1998 Theodore Ts'o * ext2_err.et.in: Added new error code, EXT2_ET_CANCEL_REQUESTED. diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c index 1293403..455307b 100644 --- a/lib/ext2fs/block.c +++ b/lib/ext2fs/block.c @@ -27,11 +27,11 @@ struct block_context { ext2_filsys fs; int (*func)(ext2_filsys fs, blk_t *blocknr, - int bcount, + blkcnt_t bcount, blk_t ref_blk, int ref_offset, void *priv_data); - int bcount; + blkcnt_t bcount; int bsize; int flags; errcode_t errcode; @@ -301,13 +301,13 @@ static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, return ret; } -errcode_t ext2fs_block_iterate2(ext2_filsys fs, +errcode_t ext2fs_block_iterate3(ext2_filsys fs, ino_t ino, int flags, char *block_buf, int (*func)(ext2_filsys fs, blk_t *blocknr, - int blockcnt, + blkcnt_t blockcnt, blk_t ref_blk, int ref_offset, void *priv_data), @@ -320,13 +320,29 @@ errcode_t ext2fs_block_iterate2(ext2_filsys fs, struct ext2_inode inode; errcode_t retval; struct block_context ctx; + int limit; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + /* + * Check to see if we need to limit large files + */ + if (flags & BLOCK_FLAG_NO_LARGE) { + ctx.errcode = ext2fs_read_inode(fs, ino, &inode); + if (ctx.errcode) + goto abort; + got_inode = 1; + if (!LINUX_S_ISDIR(inode.i_mode) && + (inode.i_size_high != 0)) + return EXT2_ET_FILE_TOO_BIG; + } + retval = ext2fs_get_blocks(fs, ino, blocks); if (retval) return retval; + limit = fs->blocksize >> 2; + ctx.fs = fs; ctx.func = func; ctx.priv_data = priv_data; @@ -378,13 +394,15 @@ errcode_t ext2fs_block_iterate2(ext2_filsys fs, 0, 0, &ctx); if (ret & BLOCK_ABORT) goto abort; - } + } else + ctx.bcount += limit; if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK, 0, 0, &ctx); if (ret & BLOCK_ABORT) goto abort; - } + } else + ctx.bcount += limit * limit; if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK, 0, 0, &ctx); @@ -412,6 +430,10 @@ abort: return (ret & BLOCK_ERROR) ? ctx.errcode : 0; } +/* + * Emulate the old ext2fs_block_iterate function! + */ + struct xlate { int (*func)(ext2_filsys fs, blk_t *blocknr, @@ -423,12 +445,12 @@ struct xlate { #ifdef __TURBOC__ #pragma argsused #endif -static int xlate_func(ext2_filsys fs, blk_t *blocknr, int blockcnt, +static int xlate_func(ext2_filsys fs, blk_t *blocknr, blkcnt_t blockcnt, blk_t ref_block, int ref_offset, void *priv_data) { struct xlate *xl = (struct xlate *) priv_data; - return (*xl->func)(fs, blocknr, blockcnt, xl->real_private); + return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private); } errcode_t ext2fs_block_iterate(ext2_filsys fs, @@ -446,8 +468,54 @@ errcode_t ext2fs_block_iterate(ext2_filsys fs, xl.real_private = priv_data; xl.func = func; - return ext2fs_block_iterate2(fs, ino, flags, block_buf, - xlate_func, &xl); + return ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_NO_LARGE | flags, + block_buf, xlate_func, &xl); +} + +/* + * Emulate the old ext2fs_block_iterate2 function! + */ + +struct xlate2 { + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data); + void *real_private; +}; + +#ifdef __TURBOC__ +#pragma argsused +#endif +static int xlate_func2(ext2_filsys fs, blk_t *blocknr, blkcnt_t blockcnt, + blk_t ref_block, int ref_offset, void *priv_data) +{ + struct xlate2 *xl = (struct xlate2 *) priv_data; + + return (*xl->func)(fs, blocknr, (int) blockcnt, ref_block, + ref_offset, xl->real_private); } +errcode_t ext2fs_block_iterate2(ext2_filsys fs, + ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data) +{ + struct xlate2 xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_NO_LARGE | flags, + block_buf, xlate_func2, &xl); +} diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c index 9d18570..2d254b7 100644 --- a/lib/ext2fs/dir_iterate.c +++ b/lib/ext2fs/dir_iterate.c @@ -120,7 +120,7 @@ extern int ext2fs_process_dir_block(ext2_filsys fs, next: if (((offset + dirent->rec_len) > fs->blocksize) || (dirent->rec_len < 8) || - ((dirent->name_len+8) > dirent->rec_len)) { + (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { ctx->errcode = EXT2_ET_DIR_CORRUPTED; return BLOCK_ABORT; } diff --git a/lib/ext2fs/dll/jump.funcs b/lib/ext2fs/dll/jump.funcs index 89cda86..63377ee 100644 --- a/lib/ext2fs/dll/jump.funcs +++ b/lib/ext2fs/dll/jump.funcs @@ -163,9 +163,10 @@ 00000000 T _ext2fs_file_close libext2fs fileio 00000000 T _ext2fs_file_read libext2fs fileio 00000000 T _ext2fs_file_write libext2fs fileio -00000000 T _ext2fs_file_llseek libext2fs fileio +00000000 T _ext2fs_file_lseek libext2fs fileio 00000000 T _ext2fs_file_get_size libext2fs fileio 00000000 T _ext2fs_file_set_size libext2fs fileio 00000000 T _ext2fs_get_mem libext2fs inline 00000000 T _ext2fs_free_mem libext2fs inline 00000000 T _ext2fs_resize_mem libext2fs inline +00000000 T _ext2fs_block_iterate3 libext2fs block diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index 6479fee..e47e141 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -254,5 +254,8 @@ ec EXT2_ET_UNIMPLEMENTED, ec EXT2_ET_CANCEL_REQUESTED, "User cancel requested" +ec EXT2_ET_FILE_TOO_BIG, + "Ext2 file too big" + end diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 1292804..0180a43 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -50,6 +50,7 @@ typedef __u32 blk_t; typedef unsigned int dgrp_t; typedef __u32 ext2_off_t; +typedef __s64 blkcnt_t; #if EXT2_FLAT_INCLUDES #include "com_err.h" @@ -225,12 +226,17 @@ struct struct_ext2_filsys { * * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be * called for data blocks only. + * + * BLOCK_FLAG_NO_LARGE is for internal use only. It informs + * ext2fs_block_iterate3 that large files won't be accepted. */ #define BLOCK_FLAG_APPEND 1 #define BLOCK_FLAG_HOLE 1 #define BLOCK_FLAG_DEPTH_TRAVERSE 2 #define BLOCK_FLAG_DATA_ONLY 4 +#define BLOCK_FLAG_NO_LARGE 0x1000 + /* * Magic "block count" return values for the block iterator function. */ @@ -396,21 +402,51 @@ struct ext2fs_sb { __u8 s_uuid[16]; /* 128-bit uuid for volume */ char s_volume_name[16]; /* volume name */ char s_last_mounted[64]; /* directory where last mounted */ - __u32 s_reserved[206]; /* Padding to the end of the block */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_COMPAT_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + __u32 s_reserved[204]; /* Padding to the end of the block */ }; /* * Feature set definitions (that might not be in ext2_fs.h * (was EXT2_COMPAT_SPARSE_SUPER) */ + +#ifndef EXT2_FEATURE_COMPAT_DIR_PREALLOC +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#endif + #ifndef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #endif -#define EXT2_LIB_FEATURE_COMPAT_SUPP 0 -#define EXT2_LIB_FEATURE_INCOMPAT_SUPP 0 -#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER +#ifndef EXT2_FEATURE_RO_COMPAT_LARGE_FILE +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define i_size_high i_dir_acl +#endif + +#ifndef EXT2_FEATURE_RO_COMPAT_BTREE_DIR +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#endif + +#ifndef EXT2_FEATURE_INCOMPAT_COMPRESSION +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#endif +#ifndef EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE +#define EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE 0x0002 +#endif + +#define EXT2_LIB_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_DIR_PREALLOC +#define EXT2_LIB_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE +#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE) /* * function prototypes */ @@ -509,6 +545,17 @@ errcode_t ext2fs_block_iterate2(ext2_filsys fs, int ref_offset, void *priv_data), void *priv_data); +errcode_t ext2fs_block_iterate3(ext2_filsys fs, + ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data); /* bmap.c */ extern errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino, @@ -605,8 +652,8 @@ extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf, unsigned int wanted, unsigned int *got); extern errcode_t ext2fs_file_write(ext2_file_t file, void *buf, unsigned int nbytes, unsigned int *written); -extern errcode_t ext2fs_file_llseek(ext2_file_t file, ext2_off_t offset, - int whence, ext2_off_t *ret_pos); +extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos); extern ext2_off_t ext2fs_file_get_size(ext2_file_t file); extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size); diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c index fbe10fb..51375b7 100644 --- a/lib/ext2fs/fileio.c +++ b/lib/ext2fs/fileio.c @@ -275,8 +275,8 @@ fail: } -errcode_t ext2fs_file_llseek(ext2_file_t file, ext2_off_t offset, - int whence, ext2_off_t *ret_pos) +errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos) { EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); diff --git a/lib/ext2fs/get_pathname.c b/lib/ext2fs/get_pathname.c index b8a9f83..ddbc58a 100644 --- a/lib/ext2fs/get_pathname.c +++ b/lib/ext2fs/get_pathname.c @@ -53,18 +53,18 @@ static int get_pathname_proc(struct ext2_dir_entry *dirent, gp = (struct get_pathname_struct *) priv_data; - if ((dirent->name_len == 2) && + if (((dirent->name_len & 0xFF) == 2) && !strncmp(dirent->name, "..", 2)) gp->parent = dirent->inode; if (dirent->inode == gp->search_ino) { - retval = ext2fs_get_mem(dirent->name_len + 1, + retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1, (void **) &gp->name); if (!gp->name) { gp->errcode = EXT2_ET_NO_MEMORY; return DIRENT_ABORT; } - strncpy(gp->name, dirent->name, dirent->name_len); - gp->name[dirent->name_len] = '\0'; + strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF)); + gp->name[dirent->name_len & 0xFF] = '\0'; return DIRENT_ABORT; } return 0; diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c index b1a1572..2bef3dc 100644 --- a/lib/ext2fs/link.c +++ b/lib/ext2fs/link.c @@ -39,7 +39,7 @@ static int link_proc(struct ext2_dir_entry *dirent, { struct link_struct *ls = (struct link_struct *) priv_data; struct ext2_dir_entry *next; - int rec_len; + int rec_len, min_rec_len; int ret = 0; rec_len = EXT2_DIR_REC_LEN(ls->namelen); @@ -62,11 +62,11 @@ static int link_proc(struct ext2_dir_entry *dirent, * truncate it and return. */ if (dirent->inode) { - if (dirent->rec_len < (EXT2_DIR_REC_LEN(dirent->name_len) + - rec_len)) + min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF); + if (dirent->rec_len < (min_rec_len + rec_len)) return ret; - rec_len = dirent->rec_len - EXT2_DIR_REC_LEN(dirent->name_len); - dirent->rec_len = EXT2_DIR_REC_LEN(dirent->name_len); + rec_len = dirent->rec_len - min_rec_len; + dirent->rec_len = min_rec_len; next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len); next->inode = 0; diff --git a/lib/ext2fs/lookup.c b/lib/ext2fs/lookup.c index 7996c16..282180c 100644 --- a/lib/ext2fs/lookup.c +++ b/lib/ext2fs/lookup.c @@ -41,9 +41,9 @@ static int lookup_proc(struct ext2_dir_entry *dirent, { struct lookup_struct *ls = (struct lookup_struct *) priv_data; - if (ls->len != dirent->name_len) + if (ls->len != (dirent->name_len & 0xFF)) return 0; - if (strncmp(ls->name, dirent->name, dirent->name_len)) + if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF))) return 0; *ls->inode = dirent->inode; ls->found++; diff --git a/lib/ext2fs/unlink.c b/lib/ext2fs/unlink.c index fad9d63..ead5ec3 100644 --- a/lib/ext2fs/unlink.c +++ b/lib/ext2fs/unlink.c @@ -42,9 +42,10 @@ static int unlink_proc(struct ext2_dir_entry *dirent, { struct link_struct *ls = (struct link_struct *) priv_data; - if (ls->name && (dirent->name_len != ls->namelen)) + if (ls->name && ((dirent->name_len & 0xFF) != ls->namelen)) return 0; - if (ls->name && strncmp(ls->name, dirent->name, dirent->name_len)) + if (ls->name && strncmp(ls->name, dirent->name, + dirent->name_len & 0xFF)) return 0; if (ls->inode && (dirent->inode != ls->inode)) return 0; -- 1.8.3.1