diff -urNX nopatch e2fsprogs-1.06/lib/ext2fs/Makefile.in e2fsprogs-rf/lib/ext2fs/Makefile.in --- e2fsprogs-1.06/lib/ext2fs/Makefile.in Tue Sep 10 04:21:38 1996 +++ e2fsprogs-rf/lib/ext2fs/Makefile.in Mon Apr 14 10:12:05 1997 @@ -19,6 +19,7 @@ cmp_bitmaps.o \ dirblock.o \ expanddir.o \ + features.o \ freefs.o \ get_pathname.o \ getsize.o \ diff -urNX nopatch e2fsprogs-1.06/lib/ext2fs/block.c e2fsprogs-rf/lib/ext2fs/block.c --- e2fsprogs-1.06/lib/ext2fs/block.c Mon Oct 7 05:52:39 1996 +++ e2fsprogs-rf/lib/ext2fs/block.c Mon Apr 14 09:44:05 1997 @@ -33,6 +33,63 @@ void *private; }; +#ifdef EXT2_FEATURE_RO_COMPAT_RES_FORK + +static int block_iterate_res_fork(blk_t *rf_ptr, struct block_context *ctx) +{ + int ret = 0, changed = 0, flags; + blk_t prev_blk = 0, blk, next_blk, *blkp = rf_ptr; + struct ext2_resource_fork_head_struct *rh = + (struct ext2_resource_fork_head_struct *)ctx->ind_buf; + struct ext2_resource_fork_head_struct *prev_rh = + (struct ext2_resource_fork_head_struct *)ctx->dind_buf; + + for(; blk = *blkp; ) { + ctx->errcode = io_channel_read_blk(ctx->fs->io, blk, + 1, ctx->ind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) || + (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) + ext2fs_swap_rfhead(rh); + if(rh->magic != EXT2_RESOURCE_FORK_MAGIC) { + ctx->errcode = EXT2_ET_BAD_RES_FORK_MAGIC; + ret |= BLOCK_ERROR; + return ret; + } + next_blk = rh->next_fork_block; + flags = (*ctx->func)(ctx->fs, blkp, BLOCK_COUNT_RES_FORK, + ctx->private); + changed |= flags; + if (flags & BLOCK_ABORT) { + ret |= BLOCK_ABORT; + break; + } + if(!*blkp) + *blkp = next_blk; + if (prev_blk && (changed & BLOCK_CHANGED)) { + if((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) || + (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) + ext2fs_swap_rfhead(prev_rh); + ctx->errcode = io_channel_write_blk(ctx->fs->io, + prev_blk, + 1, ctx->dind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR | BLOCK_ABORT; + return ret; + } + } + memcpy(ctx->dind_buf, ctx->ind_buf, ctx->fs->blocksize); + blkp = &prev_rh->next_fork_block; + prev_blk = blk; + } + return ret; +} + +#endif /* EXT2_FEATURE_RO_COMPAT_RES_FORK */ + static int block_iterate_ind(blk_t *ind_block, struct block_context *ctx) { int ret = 0, changed = 0; @@ -306,6 +363,23 @@ if (inode.osd1.hurd1.h_i_translator) { ret |= (*func)(fs, &inode.osd1.hurd1.h_i_translator, BLOCK_COUNT_TRANSLATOR, private); + if (ret & BLOCK_ABORT) + goto abort; + } + } + + /* + * Iterate over Linux resource fork (if present) + */ + if ((fs->super->s_creator_os == EXT2_OS_LINUX) && + !(flags & BLOCK_FLAG_DATA_ONLY)) { + ctx.errcode = ext2fs_read_inode(fs, ino, &inode); + if (ctx.errcode) + goto abort; + got_inode = 1; + if (inode.osd1.linux1.l_i_res_fork) { + ret |= block_iterate_res_fork( + &inode.osd1.linux1.l_i_res_fork, &ctx); if (ret & BLOCK_ABORT) goto abort; } diff -urNX nopatch e2fsprogs-1.06/lib/ext2fs/ext2_err.et.in e2fsprogs-rf/lib/ext2fs/ext2_err.et.in --- e2fsprogs-1.06/lib/ext2fs/ext2_err.et.in Tue Aug 27 15:48:38 1996 +++ e2fsprogs-rf/lib/ext2fs/ext2_err.et.in Mon Apr 14 10:27:59 1997 @@ -211,4 +211,13 @@ ec EXT2_ET_CALLBACK_NOTHANDLED, "The callback function will not handle this case" +ec EXT2_ET_WHAT_FEATURE, + "Unsupported filesystem feature flag" + +ec EXT2_ET_BAD_RES_FORK_MAGIC, + "Bad magic number in resource fork" + +ec EXT2_ET_BAD_FEATURE_NAME, + "Unrecognised feature name" + end diff -urNX nopatch e2fsprogs-1.06/lib/ext2fs/ext2fs.h e2fsprogs-rf/lib/ext2fs/ext2fs.h --- e2fsprogs-1.06/lib/ext2fs/ext2fs.h Mon Oct 7 05:52:20 1996 +++ e2fsprogs-rf/lib/ext2fs/ext2fs.h Mon Apr 14 11:51:13 1997 @@ -177,6 +177,7 @@ #define BLOCK_COUNT_DIND (-2) #define BLOCK_COUNT_TIND (-3) #define BLOCK_COUNT_TRANSLATOR (-4) +#define BLOCK_COUNT_RES_FORK (-5) /* * Return flags for the directory iterator functions @@ -415,6 +416,9 @@ /* expanddir.c */ extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ino_t dir); +/* features.c */ +extern errcode_t ext2fs_parse_features(char *str, __u32 *, __u32 *, __u32 *); + /* freefs.c */ extern void ext2fs_free(ext2_filsys fs); extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap); @@ -514,6 +518,7 @@ blk_t blk)); /* swapfs.c */ +extern void ext2fs_swap_rfhead(struct ext2_resource_fork_head_struct *rh); extern void ext2fs_swap_super(struct ext2_super_block * super); extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp); extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t, diff -urNX nopatch e2fsprogs-1.06/lib/ext2fs/features.c e2fsprogs-rf/lib/ext2fs/features.c --- e2fsprogs-1.06/lib/ext2fs/features.c Thu Jan 1 01:00:00 1970 +++ e2fsprogs-rf/lib/ext2fs/features.c Mon Apr 14 10:30:20 1997 @@ -0,0 +1,51 @@ +/* + * features.c --- parse feature names + */ + +#include +#include + +#include + +#include "ext2fs.h" + +static struct fname { + char const *name; + __u32 value; +} comnames[] = { + { NULL, 0 } +}, incomnames[] = { + { NULL, 0 } +}, ro_comnames[] = { +#ifdef EXT2_FEATURE_RO_COMPAT_RES_FORK + { "res_fork", EXT2_FEATURE_RO_COMPAT_RES_FORK }, +#endif + { NULL, 0 } +}; + +static int parseone(char *name, __u32 *set, struct fname *names) +{ + for(; names->name; names++) + if(!strcasecmp(name, names->name)) { + *set |= names->value; + return 1; + } + return 0; +} + +errcode_t ext2fs_parse_features(char *str, + __u32 *com, __u32 *incom, __u32 *ro_com) +{ + for(; *str; ) { + char *p = strchr(str, ','); + char *n = ""; + if(p) + *p = 0, n = p+1; + if(!parseone(str, com, comnames) && + !parseone(str, incom, incomnames) && + !parseone(str, ro_com, ro_comnames)) + return EXT2_ET_BAD_FEATURE_NAME; + str = n; + } + return 0; +} diff -urNX nopatch e2fsprogs-1.06/lib/ext2fs/swapfs.c e2fsprogs-rf/lib/ext2fs/swapfs.c --- e2fsprogs-1.06/lib/ext2fs/swapfs.c Sat Aug 31 02:20:58 1996 +++ e2fsprogs-rf/lib/ext2fs/swapfs.c Mon Apr 14 09:08:59 1997 @@ -14,6 +14,16 @@ #include "ext2fs.h" +#ifdef EXT2_FEATURE_RO_COMPAT_RES_FORK + +void ext2fs_swap_rfhead(struct ext2_resource_fork_head_struct *rh) +{ + rh->magic = ext2fs_swab32(rh->magic); + rh->next_fork_block = ext2fs_swab32(rh->next_fork_block); +} + +#endif /* EXT2_FEATURE_RO_COMPAT_RES_FORK */ + void ext2fs_swap_super(struct ext2_super_block * super) { struct ext2fs_sb *s = (struct ext2fs_sb *) super; @@ -98,6 +108,10 @@ switch (fs->super->s_creator_os) { case EXT2_OS_LINUX: +#ifdef EXT2_FEATURE_RO_COMPAT_RES_FORK + t->osd1.linux1.l_i_res_fork = + ext2fs_swab32 (f->osd1.linux1.l_i_res_fork); +#endif t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag; t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize; t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1); diff -urNX nopatch e2fsprogs-1.06/misc/mke2fs.c e2fsprogs-rf/misc/mke2fs.c --- e2fsprogs-1.06/misc/mke2fs.c Sat Sep 7 12:37:33 1996 +++ e2fsprogs-rf/misc/mke2fs.c Mon Apr 14 11:02:52 1997 @@ -82,7 +82,7 @@ "[-f fragment-size]\n\t[-i bytes-per-inode] " "[-m reserved-blocks-percentage] [-qvS]\n\t" "[-o creator-os] [-g blocks-per-group] [-L volume-label]\n\t" - "[-M last-mounted-directory] device [blocks-count]\n", + "[-M last-mounted-directory] [-O features] device [blocks-count]\n", program_name); exit(1); } @@ -589,7 +589,7 @@ if (argc && *argv) program_name = *argv; while ((c = getopt (argc, argv, - "b:cf:g:i:l:m:o:qr:tvI:SFL:M:")) != EOF) + "b:cf:g:i:l:m:o:qO:tvI:SFL:M:")) != EOF) switch (c) { case 'b': size = strtoul(optarg, &tmp, 0); @@ -666,10 +666,17 @@ case 'o': creator_os = optarg; break; - case 'r': - param.s_rev_level = atoi(optarg); - break; #ifdef EXT2_DYNAMIC_REV + case 'O': + param.s_rev_level = EXT2_DYNAMIC_REV; + param.s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + param.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + if((retval = ext2fs_parse_features(optarg, + ¶m.s_feature_compat, ¶m.s_feature_incompat, + ¶m.s_feature_ro_compat))) { + com_err(program_name, retval, ""); + } + break; case 'I': param.s_inode_size = atoi(optarg); break; diff -urNX nopatch e2fsprogs-1.06/misc/tune2fs.8.in e2fsprogs-rf/misc/tune2fs.8.in --- e2fsprogs-1.06/misc/tune2fs.8.in Sat Sep 7 12:35:49 1996 +++ e2fsprogs-rf/misc/tune2fs.8.in Mon Apr 14 11:20:12 1997 @@ -54,6 +54,10 @@ .B -U .I UUID ] +[ +.B -O +.I features +] device .SH DESCRIPTION .BI tune2fs @@ -116,6 +120,18 @@ "c1b9d5a2-f162-11cf-9ece-0020afc76f16". The uuid may also be "null", which will set the filesystem UUID to the null UUID. The uuid may also be "random", which will generate a new random UUID for the filesystem. +.TP +.I -O features +set the specified feature flags for the filesystem. (The flags are +specified in the form of a comma-separated list.) Feature flags cannot +be cleared in this way. The following feature flags are supported: +.RS +.TP +.B res_fork +Under Linux, permits additional data to be stored with each file in +an extensible manner. If this flag is set, older kernels will be unable +to write to the filesystem, but will still be able to read it. +.RE .PP .SH BUGS We didn't find any bugs yet. Perhaps there are bugs but it's unlikely. diff -urNX nopatch e2fsprogs-1.06/misc/tune2fs.c e2fsprogs-rf/misc/tune2fs.c --- e2fsprogs-1.06/misc/tune2fs.c Sat Sep 7 19:50:00 1996 +++ e2fsprogs-rf/misc/tune2fs.c Mon Apr 14 11:06:03 1997 @@ -49,6 +49,7 @@ char * new_label = NULL; char * new_last_mounted = NULL; char * new_UUID = NULL; +char * new_features = NULL; int c_flag = 0; int C_flag = 0; int e_flag = 0; @@ -61,6 +62,7 @@ int r_flag = 0; int u_flag = 0; int U_flag = 0; +int O_flag = 0; int max_mount_count, mount_count; unsigned long interval; unsigned long reserved_ratio = 0; @@ -91,11 +93,37 @@ "[-g group]\n" "\t[-i interval[d|m|w]] [-l] [-m reserved-blocks-percent]\n" "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n" - "\t[-L volume-label] [-M last-mounted-dir] [-U UUID] " + "\t[-L volume-label] [-M last-mounted-dir] [-U UUID]\n" + "\t[-O features] " "device\n", program_name); exit (1); } +int set_feature_flags(char *features, struct ext2fs_sb *sb) +{ +#ifndef EXT2_DYNAMIC_REV + com_err(program_name, 0, "Feature flags not supported\n"); + return 1; +#else /* EXT2_DYNAMIC_REV */ + __u32 com = 0, incom = 0, ro_com = 0; + errcode_t err; + + if(sb->s_rev_level < EXT2_DYNAMIC_REV) { + sb->s_rev_level = EXT2_DYNAMIC_REV; + sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + } + if((err = ext2fs_parse_features(features, &com, &incom, &ro_com))) { + com_err(program_name, err, ""); + return 1; + } + sb->s_feature_compat |= com; + sb->s_feature_incompat |= incom; + sb->s_feature_ro_compat |= ro_com; + return 0; +#endif /* EXT2_DYNAMIC_REV */ +} + void main (int argc, char ** argv) { char c; @@ -113,7 +141,7 @@ if (argc && *argv) program_name = *argv; initialize_ext2_error_table(); - while ((c = getopt (argc, argv, "c:e:g:i:lm:r:u:C:L:M:U:")) != EOF) + while ((c = getopt (argc, argv, "c:e:g:i:lm:r:u:C:L:M:U:O:")) != EOF) switch (c) { case 'c': @@ -276,6 +304,11 @@ U_flag = 1; open_flag = EXT2_FLAG_RW; break; + case 'O': + new_features = optarg; + O_flag = 1; + open_flag = EXT2_FLAG_RW; + break; default: usage (); } @@ -384,6 +417,11 @@ com_err(program_name, 0, "Invalid UUID format\n"); exit(1); } + ext2fs_mark_super_dirty(fs); + } + if(O_flag) { + if(set_feature_flags(new_features, sb)) + exit(1); ext2fs_mark_super_dirty(fs); }