diff --exclude=.svn -r -u -N e2fsprogs-1.38/configure softs/e2fsprogs/configure --- e2fsprogs-1.38/configure 2005-04-06 20:44:15.000000000 +0200 +++ softs/e2fsprogs/configure 2007-11-29 15:44:50.000000000 +0100 @@ -3118,7 +3118,11 @@ fi else - echo "Disabling compression support by default" + cat >> confdefs.h <<\EOF +#define ENABLE_COMPRESSION 1 +EOF + echo "Enabling compression support by default" + echo "WARNING: Compression support is experimental" fi; # Check whether --enable-htree or --disable-htree was given. diff --exclude=.svn -r -u -N e2fsprogs-1.38/e2fsprogs.spec softs/e2fsprogs/e2fsprogs.spec --- e2fsprogs-1.38/e2fsprogs.spec 2005-06-27 17:20:52.000000000 +0200 +++ softs/e2fsprogs/e2fsprogs.spec 2007-11-29 15:44:50.000000000 +0100 @@ -2,14 +2,15 @@ %define _root_libdir /%{_lib} %define _root_localedir /usr/share/locale -Summary: Utilities for managing the second extended (ext2) filesystem. +Summary: Utilities for managing the second extended (ext2) filesystem (with compression). Name: e2fsprogs -Version: 1.38-WIP +Version: 1.38-e2compr-0.4.11 Release: 0 Copyright: GPL Group: System Environment/Base -Source: ftp://download.sourceforge.net/pub/sourceforge/e2fsprogs/e2fsprogs-%{version}.tar.gz +Source: ftp://download.sourceforge.net/pub/sourceforge/e/e2/e2compr/e2fsprogs-%{version}.tar.bz2 Url: http://e2fsprogs.sourceforge.net/ +Packager: Paul Whittaker Prereq: /sbin/ldconfig BuildRoot: %{_tmppath}/%{name}-root @@ -31,6 +32,9 @@ ext2) for the libuuid and libblkid libraries and fsck tool that are included here. +This version includes support for ext2 compression using the e2compr +0.4 extension. + %package devel Summary: Ext2 filesystem-specific static libraries and headers. Group: Development/Libraries @@ -81,7 +85,7 @@ %files -f %{name}.lang %defattr(-,root,root) -%doc README RELEASE-NOTES +%doc README RELEASE-NOTES README.e2compr %{_root_sbindir}/badblocks %{_root_sbindir}/blkid diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/e2p/e2p.h softs/e2fsprogs/lib/e2p/e2p.h --- e2fsprogs-1.38/lib/e2p/e2p.h 2005-04-09 07:34:49.000000000 +0200 +++ softs/e2fsprogs/lib/e2p/e2p.h 2007-11-29 15:44:48.000000000 +0100 @@ -46,7 +46,7 @@ int e2p_string2mntopt(char *string, unsigned int *mask); int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok); -unsigned long parse_num_blocks(const char *arg, int log_block_size); +__u32 parse_num_blocks(const char *arg, int log_block_size); char *e2p_os2string(int os_type); int e2p_string2os(char *str); diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/e2p/ext2_meth.h softs/e2fsprogs/lib/e2p/ext2_meth.h --- e2fsprogs-1.38/lib/e2p/ext2_meth.h 1970-01-01 01:00:00.000000000 +0100 +++ softs/e2fsprogs/lib/e2p/ext2_meth.h 2007-11-29 15:44:48.000000000 +0100 @@ -0,0 +1,134 @@ +/* + * This file automatically generated by ext2_meth.sh. + * To make changes, either change ext2_meth.sh and rerun it, + * or make the changes to this file and delete ext2_meth.sh. + */ + +#include + +extern unsigned meth_name2id(char const *); +extern char const *meth_id2name(unsigned); + +/* + * The ext2fs library private definition of the ext2 compression method names, + * so we don't have to depend on the kernel's definition of them. + * The idea is to provide a consistent compilation environment. + */ + +#define EXT2FS_LZV1_METH 0 +#define EXT2FS_AUTO_METH 1 +#define EXT2FS_DEFER_METH 2 +#define EXT2FS_NONE_METH EXT2_DEFER_METH +#define EXT2FS_NEVER_METH 3 +#define EXT2FS_BZIP2_METH 4 +#define EXT2FS_LZRW3A_METH 8 +#define EXT2FS_LZO1X_1_METH 0x0a +#define EXT2FS_GZIP_1_METH 0x10 +#define EXT2FS_GZIP_2_METH 0x11 +#define EXT2FS_GZIP_3_METH 0x12 +#define EXT2FS_GZIP_4_METH 0x13 +#define EXT2FS_GZIP_5_METH 0x14 +#define EXT2FS_GZIP_6_METH 0x15 +#define EXT2FS_GZIP_7_METH 0x16 +#define EXT2FS_GZIP_8_METH 0x17 +#define EXT2FS_GZIP_9_METH 0x18 + +/* + * Check for incompatibilities. + */ + +#ifdef EXT2_AUTO_METH +# if EXT2_AUTO_METH != EXT2FS_AUTO_METH +# error "This kernel using a non-standard value of EXT2_AUTO_METH" +# endif +#endif + +#ifdef EXT2_NEVER_METH +# if EXT2_NEVER_METH != EXT2FS_NEVER_METH +# error "This kernel using a non-standard value of EXT2_NEVER_METH" +# endif +#endif + +#ifdef EXT2_DEFER_METH +# if EXT2_DEFER_METH != EXT2FS_DEFER_METH +# error "This kernel using a non-standard value of EXT2_DEFER_METH" +# endif +#endif + +#ifdef EXT2_LZO1X_1_METH +# if EXT2_LZO1X_1_METH != EXT2FS_LZO1X_1_METH +# error "This kernel using a non-standard value of EXT2_LZO1X_1_METH" +# endif +#endif + +#ifdef EXT2_LZV1_METH +# if EXT2_LZV1_METH != EXT2FS_LZV1_METH +# error "This kernel using a non-standard value of EXT2_LZV1_METH" +# endif +#endif + +#ifdef EXT2_LZRW3A_METH +# if EXT2_LZRW3A_METH != EXT2FS_LZRW3A_METH +# error "This kernel using a non-standard value of EXT2_LZRW3A_METH" +# endif +#endif + +#ifdef EXT2_BZIP2_METH +# if EXT2_BZIP2_METH != EXT2FS_BZIP2_METH +# error "This kernel using a non-standard value of EXT2_BZIP2_METH" +# endif +#endif + +#ifdef EXT2_GZIP_1_METH +# if EXT2_GZIP_1_METH != EXT2FS_GZIP_1_METH +# error "This kernel using a non-standard value of EXT2_GZIP_1_METH" +# endif +#endif + +#ifdef EXT2_GZIP_2_METH +# if EXT2_GZIP_2_METH != EXT2FS_GZIP_2_METH +# error "This kernel using a non-standard value of EXT2_GZIP_2_METH" +# endif +#endif + +#ifdef EXT2_GZIP_3_METH +# if EXT2_GZIP_3_METH != EXT2FS_GZIP_3_METH +# error "This kernel using a non-standard value of EXT2_GZIP_3_METH" +# endif +#endif + +#ifdef EXT2_GZIP_4_METH +# if EXT2_GZIP_4_METH != EXT2FS_GZIP_4_METH +# error "This kernel using a non-standard value of EXT2_GZIP_4_METH" +# endif +#endif + +#ifdef EXT2_GZIP_5_METH +# if EXT2_GZIP_5_METH != EXT2FS_GZIP_5_METH +# error "This kernel using a non-standard value of EXT2_GZIP_5_METH" +# endif +#endif + +#ifdef EXT2_GZIP_6_METH +# if EXT2_GZIP_6_METH != EXT2FS_GZIP_6_METH +# error "This kernel using a non-standard value of EXT2_GZIP_6_METH" +# endif +#endif + +#ifdef EXT2_GZIP_7_METH +# if EXT2_GZIP_7_METH != EXT2FS_GZIP_7_METH +# error "This kernel using a non-standard value of EXT2_GZIP_7_METH" +# endif +#endif + +#ifdef EXT2_GZIP_8_METH +# if EXT2_GZIP_8_METH != EXT2FS_GZIP_8_METH +# error "This kernel using a non-standard value of EXT2_GZIP_8_METH" +# endif +#endif + +#ifdef EXT2_GZIP_9_METH +# if EXT2_GZIP_9_METH != EXT2FS_GZIP_9_METH +# error "This kernel using a non-standard value of EXT2_GZIP_9_METH" +# endif +#endif diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/e2p/ext2_meth.sh softs/e2fsprogs/lib/e2p/ext2_meth.sh --- e2fsprogs-1.38/lib/e2p/ext2_meth.sh 1970-01-01 01:00:00.000000000 +0100 +++ softs/e2fsprogs/lib/e2p/ext2_meth.sh 2007-11-29 15:44:48.000000000 +0100 @@ -0,0 +1,62 @@ +#!/bin/sh +# Creates ext2_meth.h +# I wrote this because the C preprocessor isn't powerful enough to do it. +# "Rerolling the loop" in this way should make it easier (?) and safer +# to edit. +# + +SCRIPTNAME=ext2_meth.sh +DEST=ext2_meth.h + +cat > "$DEST" < + +extern unsigned meth_name2id(char const *); +extern char const *meth_id2name(unsigned); + +/* + * The ext2fs library private definition of the ext2 compression method names, + * so we don't have to depend on the kernel's definition of them. + * The idea is to provide a consistent compilation environment. + */ + +#define EXT2FS_LZV1_METH 0 +#define EXT2FS_AUTO_METH 1 +#define EXT2FS_DEFER_METH 2 +#define EXT2FS_NONE_METH EXT2_DEFER_METH +#define EXT2FS_NEVER_METH 3 +#define EXT2FS_BZIP2_METH 4 +#define EXT2FS_LZRW3A_METH 8 +#define EXT2FS_LZO1X_1_METH 0x0a +#define EXT2FS_GZIP_1_METH 0x10 +#define EXT2FS_GZIP_2_METH 0x11 +#define EXT2FS_GZIP_3_METH 0x12 +#define EXT2FS_GZIP_4_METH 0x13 +#define EXT2FS_GZIP_5_METH 0x14 +#define EXT2FS_GZIP_6_METH 0x15 +#define EXT2FS_GZIP_7_METH 0x16 +#define EXT2FS_GZIP_8_METH 0x17 +#define EXT2FS_GZIP_9_METH 0x18 + +/* + * Check for incompatibilities. + */ +EOT +for i in AUTO NEVER DEFER LZO1X_1 LZV1 LZRW3A BZIP2 \ + GZIP_1 GZIP_2 GZIP_3 GZIP_4 GZIP_5 GZIP_6 GZIP_7 GZIP_8 GZIP_9 +do +cat >> "$DEST" <= 'a') + for (i = sizeof(name2id) / sizeof(*name2id) - 1;; i--) { + if ((cmp = strcmp (name, name2id[i].name)) > 0) + continue; + else if (cmp == 0) + return name2id[i].id; + else + break; + } + return ~0u; +} + +#else /* More efficient version. (Typically better than binary search.) */ +typedef unsigned u32; + +/* Unfortunately, the obvious `(*(u32 const *) "blah")' doesn't compile. + But maybe that would be relying too much on compiler alignment + decisions anyway. */ +# define hash(c1,c2,c3,c4) (((u32) (c1) << 24) \ + | ((u32) (c2) << 16) \ + | ((u32) (c3) << 8) \ + | ((u32) (c4))) + +unsigned meth_name2id(char const *name) +{ + /* Needed so that we never access illegal memory. */ + if ((name[0] == '\0') || (name[1] == '\0') || (name[2] == '\0')) + return ~0u; + + switch (hash(name[0], name[1], name[2], name[3])) { + case hash('n', 'e', 'v', 'e'): + if ((name[4] == 'r') && (name[5] == '\0')) + return EXT2FS_NEVER_METH; + break; + case hash('d', 'e', 'f', 'e'): + if ((name[4] == 'r') && (name[5] == '\0')) + return EXT2FS_DEFER_METH; + break; + case hash('n', 'o', 'n', 'e'): + if (name[4] == '\0') + return EXT2FS_DEFER_METH; + break; + case hash('a', 'u', 't', 'o'): + if (name[4] == '\0') + return EXT2FS_AUTO_METH; + break; + case hash('l', 'z', 'o', '\0'): + return EXT2FS_LZO1X_1_METH; + case hash('l', 'z', 'o', '1'): + if ((name[4] == 'x') && (name[5] == '1') + && (name[6] == '\0')) + return EXT2FS_LZO1X_1_METH; + break; + case hash('l', 'z', 'v', '\0'): + return EXT2FS_LZV1_METH; + case hash('l', 'z', 'v', '1'): + if (name[4] == '\0') + return EXT2FS_LZV1_METH; + break; + case hash('l', 'z', 'r', 'w'): + if ((name[4] == '3') && (name[5] == 'a') + && (name[6] == '\0')) + return EXT2FS_LZRW3A_METH; + break; + case hash('b', 'z', 'i', 'p'): + if (((name[4] == '2') && (name[5] == '\0')) + || (name[4] == '\0')) + return EXT2FS_BZIP2_METH; + break; + case hash('g', 'z', 'i', 'p'): + if (name[4] == '\0') + return EXT2FS_GZIP_6_METH; +# if EXT2FS_GZIP_9_METH - EXT2FS_GZIP_1_METH != 8 +# error "Bad assumption here." +# endif + if ((name[4] >= '1') && (name[4] <= '9') + && (name[5] == '\0')) + return EXT2FS_GZIP_1_METH + name[4] - '1'; + break; + default: + break; + } + return ~0u; +} +#endif + +static char const meth_name[32][7] = +{ + "lzv1", "auto", "defer", "never", + "bzip2", "0x05", "0x06", "0x07", + "lzrw3a", "0x09", "lzo1x1","0x0b", + "0x0c", "0x0d", "0x0e", "0x0f", + "gzip1", "gzip2", "gzip3", "gzip4", + "gzip5", "gzip6", "gzip7", "gzip8", + "gzip9", "0x19", "0x1a", "0x1b", + "0x1c", "0x1d", "0x1e", "0x1f" +}; + +#if EXT2FS_LZV1_METH != 0 || EXT2FS_AUTO_METH != 1 || EXT2FS_DEFER_METH != 2 || EXT2FS_NEVER_METH != 3 +# error "method id mismatch row 1" +#endif +#if EXT2FS_BZIP2_METH != 4 || EXT2FS_LZRW3A_METH != 8 +# error "method id mismatch row 2--3" +#endif +#if EXT2FS_GZIP_1_METH != 16 || EXT2FS_GZIP_2_METH != 17 || EXT2FS_GZIP_9_METH != 24 +# error "method id mismatch row 5--7" +#endif + +char const *meth_id2name (unsigned method) +{ + if (method < 32) + return meth_name[method]; + else + return "*inval"; +} diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/e2p/parse_num.c softs/e2fsprogs/lib/e2p/parse_num.c --- e2fsprogs-1.38/lib/e2p/parse_num.c 2005-01-05 08:46:57.000000000 +0100 +++ softs/e2fsprogs/lib/e2p/parse_num.c 2007-11-29 15:44:48.000000000 +0100 @@ -11,7 +11,7 @@ #include -unsigned long parse_num_blocks(const char *arg, int log_block_size) +__u32 parse_num_blocks(const char *arg, int log_block_size) { char *p; unsigned long long num; @@ -39,6 +39,14 @@ default: return 0; } + if (num > (__u32) num) + return 0; +#ifdef ENABLE_COMPRESSION + /* Max size is 0xfffffffe blocks, since 0 and 0xffffffff are reserved + * for holes. */ + if (num == 0xffffffff) + return 0; +#endif return num; } diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/ext2fs/block.c softs/e2fsprogs/lib/ext2fs/block.c --- e2fsprogs-1.38/lib/ext2fs/block.c 2005-01-06 06:04:23.000000000 +0100 +++ softs/e2fsprogs/lib/ext2fs/block.c 2007-11-29 15:44:49.000000000 +0100 @@ -82,7 +82,7 @@ } } else { for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { - if (*block_nr == 0) + if (HOLE_BLKADDR(*block_nr)) continue; flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount, *ind_block, offset, @@ -343,7 +343,7 @@ * Iterate over normal data blocks */ for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) { - if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) { + if (!HOLE_BLKADDR(blocks[i]) || (flags & BLOCK_FLAG_APPEND)) { ret |= (*ctx.func)(fs, &blocks[i], ctx.bcount, 0, i, priv_data); if (ret & BLOCK_ABORT) diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/ext2fs/bmap.c softs/e2fsprogs/lib/ext2fs/bmap.c --- e2fsprogs-1.38/lib/ext2fs/bmap.c 2004-12-23 19:55:34.000000000 +0100 +++ softs/e2fsprogs/lib/ext2fs/bmap.c 2007-11-29 15:44:49.000000000 +0100 @@ -68,7 +68,10 @@ b = ext2fs_swab32(b); #endif - if (!b && (flags & BMAP_ALLOC)) { + /* TODO: Have a look at the situations where this can be + called with BMAP_ALLOC, and check that we're doing the + right thing if b is EXT2FS_COMPRESSED_BLKADDR. */ + if (HOLE_BLKADDR(b) && (flags & BMAP_ALLOC)) { b = nr ? ((blk_t *) block_buf)[nr-1] : 0; retval = ext2fs_alloc_block(fs, b, block_buf + fs->blocksize, &b); @@ -180,7 +183,10 @@ *phys_blk = inode_bmap(inode, block); b = block ? inode_bmap(inode, block-1) : 0; - if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { + /* TODO: Have a look at the situations where this can be + called with BMAP_ALLOC, and check that we're doing the + right thing if b is EXT2FS_COMPRESSED_BLKADDR. */ + if (HOLE_BLKADDR(*phys_blk) && (bmap_flags & BMAP_ALLOC)) { retval = ext2fs_alloc_block(fs, b, block_buf, &b); if (retval) goto done; @@ -202,6 +208,8 @@ goto done; } + /* TODO: Does ext2fs_alloc_block work + correctly if arg2 == 0xffffffff? */ b = inode_bmap(inode, EXT2_IND_BLOCK-1); retval = ext2fs_alloc_block(fs, b, block_buf, &b); if (retval) diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/ext2fs/ext2_iflags.h softs/e2fsprogs/lib/ext2fs/ext2_iflags.h --- e2fsprogs-1.38/lib/ext2fs/ext2_iflags.h 1970-01-01 01:00:00.000000000 +0100 +++ softs/e2fsprogs/lib/ext2fs/ext2_iflags.h 2007-11-29 15:44:49.000000000 +0100 @@ -0,0 +1,106 @@ +/* + * This file automatically generated by ext2_iflags.sh. + * To make changes, either change ext2_iflags.sh and rerun it, + * or make the changes to this file and delete ext2_iflags.sh. + */ + +#if EXT2_FLAT_INCLUDES +#include "ext2_fs.h" +#else +#include +#endif + +/* + * The ext2fs library private definition of the ext2 inode flag bits, + * so we don't have to depend on the kernel's definition of the flag + * bits, which might not have the latest features. + */ + +#define EXT2FS_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2FS_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2FS_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2FS_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2FS_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2FS_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2FS_NOATIME_FL 0x00000080 /* do not update atime */ +#define EXT2FS_DIRTY_FL 0x00000100 /* Needs decompressing. */ +#define EXT2FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters. */ +#define EXT2FS_NOCOMPR_FL 0x00000400 /* Access raw compressed data. */ +#define EXT2FS_ECOMPR_FL 0x00000800 /* Compression error */ + +/* + * Check for incompatibilities. + */ + +#ifdef EXT2_SECRM_FL +# if EXT2_SECRM_FL != EXT2FS_SECRM_FL +# error "This kernel using a non-standard value of EXT2_SECRM_FL" +# endif +#endif + +#ifdef EXT2_UNRM_FL +# if EXT2_UNRM_FL != EXT2FS_UNRM_FL +# error "This kernel using a non-standard value of EXT2_UNRM_FL" +# endif +#endif + +#ifdef EXT2_COMPR_FL +# if EXT2_COMPR_FL != EXT2FS_COMPR_FL +# error "This kernel using a non-standard value of EXT2_COMPR_FL" +# endif +#endif + +#ifdef EXT2_SYNC_FL +# if EXT2_SYNC_FL != EXT2FS_SYNC_FL +# error "This kernel using a non-standard value of EXT2_SYNC_FL" +# endif +#endif + +#ifdef EXT2_IMMUTABLE_FL +# if EXT2_IMMUTABLE_FL != EXT2FS_IMMUTABLE_FL +# error "This kernel using a non-standard value of EXT2_IMMUTABLE_FL" +# endif +#endif + +#ifdef EXT2_APPEND_FL +# if EXT2_APPEND_FL != EXT2FS_APPEND_FL +# error "This kernel using a non-standard value of EXT2_APPEND_FL" +# endif +#endif + +#ifdef EXT2_NODUMP_FL +# if EXT2_NODUMP_FL != EXT2FS_NODUMP_FL +# error "This kernel using a non-standard value of EXT2_NODUMP_FL" +# endif +#endif + +#ifdef EXT2_NOATIME_FL +# if EXT2_NOATIME_FL != EXT2FS_NOATIME_FL +# error "This kernel using a non-standard value of EXT2_NOATIME_FL" +# endif +#endif + +#ifdef EXT2_DIRTY_FL +# if EXT2_DIRTY_FL != EXT2FS_DIRTY_FL +# error "This kernel using a non-standard value of EXT2_DIRTY_FL" +# endif +#endif + +#ifdef EXT2_COMPRBLK_FL +# if EXT2_COMPRBLK_FL != EXT2FS_COMPRBLK_FL +# error "This kernel using a non-standard value of EXT2_COMPRBLK_FL" +# endif +#endif + +#ifdef EXT2_NOCOMPR_FL +# if EXT2_NOCOMPR_FL != EXT2FS_NOCOMPR_FL +# error "This kernel using a non-standard value of EXT2_NOCOMPR_FL" +# endif +#endif + +#ifdef EXT2_ECOMPR_FL +# if EXT2_ECOMPR_FL != EXT2FS_ECOMPR_FL +# error "This kernel using a non-standard value of EXT2_ECOMPR_FL" +# endif +#endif diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/ext2fs/ext2_ioctls.h softs/e2fsprogs/lib/ext2fs/ext2_ioctls.h --- e2fsprogs-1.38/lib/ext2fs/ext2_ioctls.h 1970-01-01 01:00:00.000000000 +0100 +++ softs/e2fsprogs/lib/ext2fs/ext2_ioctls.h 2007-11-29 15:44:49.000000000 +0100 @@ -0,0 +1,24 @@ +#include +#if EXT2_FLAT_INCLUDES +#include "ext2_fs.h" +#else +#include +#endif + +/* [Portability question: gcc accepts these repeated definitions + without even a warning, which is what we want. + (It only gives a warning/error if the second definition + differs from the first.) I don't know how friendly other + compilers are about this.] */ +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) +#define EXT2_IOC_GETCLUSTERSIZE _IOR('c', 0, long) +#define EXT2_IOC_SETCLUSTERSIZE _IOW('c', 0, long) +#define EXT2_IOC_GETCOMPRMETHOD _IOR('c', 1, long) +#define EXT2_IOC_SETCOMPRMETHOD _IOW('c', 1, long) +#define EXT2_IOC_GETFIRSTCLUSTERSIZE _IOR('c', 2, long) +#define EXT2_IOC_RECOGNIZE_COMPRESSED _IOW('c', 2, long) +#define EXT2_IOC_GETCLUSTERBIT _IOR('c', 3, long) +#define EXT2_IOC_GETCOMPRRATIO _IOR('c', 4, long) diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/ext2fs/fileio.c softs/e2fsprogs/lib/ext2fs/fileio.c --- e2fsprogs-1.38/lib/ext2fs/fileio.c 2003-12-07 18:11:38.000000000 +0100 +++ softs/e2fsprogs/lib/ext2fs/fileio.c 2007-11-29 15:44:49.000000000 +0100 @@ -174,13 +174,15 @@ if (retval) return retval; if (!dontfill) { - if (file->physblock) { + if (!HOLE_BLKADDR(file->physblock)) { retval = io_channel_read_blk(fs->io, file->physblock, 1, file->buf); if (retval) return retval; } else + /* TODO: This isn't really correct handling of + EXT2FS_COMPRESSED_BLKADDR. */ memset(file->buf, 0, fs->blocksize); } file->flags |= EXT2_FILE_BUF_VALID; diff --exclude=.svn -r -u -N e2fsprogs-1.38/lib/ext2fs/Makefile.in softs/e2fsprogs/lib/ext2fs/Makefile.in --- e2fsprogs-1.38/lib/ext2fs/Makefile.in 2005-06-29 19:42:20.000000000 +0200 +++ softs/e2fsprogs/lib/ext2fs/Makefile.in 2007-11-29 15:44:49.000000000 +0100 @@ -134,7 +134,8 @@ $(srcdir)/tst_getsize.c \ $(srcdir)/tst_iscan.c -HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h +HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h \ + ext2_ioctls.h ext2_iflags.h HFILES_IN= ext2_err.h ext2_types.h LIBRARY= libext2fs diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/chattr.1.in softs/e2fsprogs/misc/chattr.1.in --- e2fsprogs-1.38/misc/chattr.1.in 2004-02-01 02:27:36.000000000 +0100 +++ softs/e2fsprogs/misc/chattr.1.in 2007-11-29 15:44:50.000000000 +0100 @@ -1,5 +1,5 @@ .\" -*- nroff -*- -.TH CHATTR 1 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" +.TH CHATTR 1 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs vers @E2FSPROGS_VERSION@" .SH NAME chattr \- change file attributes on a Linux second extended file system .SH SYNOPSIS @@ -12,6 +12,14 @@ .I version ] [ +.B \-b +.I cluster_size +] +[ +.B \-m +.I compression_method +] +[ .I mode ] .I files... @@ -19,17 +27,23 @@ .B chattr changes the file attributes on a Linux second extended file system. .PP -The format of a symbolic mode is +-=[ASacDdIijsTtu]. +The format of a symbolic mode is +-=[AaBcDdEIijSsTtuXZ]. .PP The operator `+' causes the selected attributes to be added to the existing attributes of the files; `-' causes them to be removed; and `=' causes them to be the only attributes that the files have. .PP -The letters `acdijsuADST' select the new attributes for the files: -append only (a), compressed (c), no dump (d), immutable (i), -data journalling (j), secure deletion (s), no tail-merging (t), -undeletable (u), no atime updates (A), synchronous directory updates (D), -synchronous updates (S), and top of directory hierarchy (T). +The letters `acdijstuABDESTX' select the new attributes for the files: +append only (a), compression requested (c), no dump (d), immutable (i), +data journalling (j), secure deletion (s), no tail-merging (t), +undeletable (u), no atime updates (A), contains compressed clusters +(B), synchronous directory updates (D), compression error (E), +synchronous updates (S), top of directory hierarchy (T), disable +de/compression on I/O (X), and requires compression (Z). +.PP +The `B' (file contains compressed clusters) and `Z' (file has some +clusters needing compression) flags are accepted but ignored. These +flags cannot be changed from user space. .SH OPTIONS .TP .B \-R @@ -42,6 +56,41 @@ .TP .BI \-v " version" Set the file's version/generation number. +.TP +.BI \-b " cluster_size" +Set the cluster size for compressed files. +The only supported cluster sizes are 4, 8, 16 or 32 blocks per cluster. +Depending on the file system and/or the kernel, some of these values +may not be supported. +.TP +.BI \-m " compression_method" +Set the algorithm used for compression. +Currently, the only supported algorithms are +`bzip2', +`lzo1x1', +`lzrw3a', +`lzv1', +and +`gzip1', `gzip2', ..., `gzip9' (where the number is equivalent to the +compression level used for gzip). The name `lzv' is an alias for +`lzv1', `gzip' is an alias for `gzip6', `lzo' is an alias for `lzo1x1', +and `bzip' is an alias for `bzip2'. Not all kernels have support for +all compression methods. +.PP +There are also some `pseudo-compression methods': `defer', `none' +(an alias for `defer'), `never', and `auto' (which, at present, is just +an alias for the kernel's default compression method). Depending on the +kernel in use, some of these values may not be supported. +.PP +Unless the file is uncompressed (ie. compressed with method `none' or +`defer'), changing the compression algorithm will not cause existing +compressed clusters to be recompressed using that algorithm; it only +changes the default algorithm that will be used for any new or newly- +modified clusters. +.PP +Setting the compression method to `never' will immediately decompress +the entire file and disallow any further algorithm changes while the `c' +attribute remains set. .SH ATTRIBUTES When a file with the 'A' attribute set is accessed, its atime record is not modified. This avoids a certain amount of disk I/O for laptop @@ -51,9 +100,32 @@ Only the superuser or a process possessing the CAP_LINUX_IMMUTABLE capability can set or clear this attribute. .PP +The `B' attribute is used by the experimental compression patches to +indicate that a file contains compressed clusters (or more accurately, +that it contains clusters that the kernel regards as compressed, although +in practice they may be `compressed' using algorithm `none'). The `B' +attribute may not be set or reset using +.BR chattr (1), +although it can be displayed by +.BR lsattr (1). +.PP A file with the `c' attribute set is automatically compressed on the disk -by the kernel. A read from this file returns uncompressed data. A write to -this file compresses data before storing them on the disk. +by the kernel as soon as possible. A read from this file returns +uncompressed data. A write to this file is followed by an attempt to +compress the data written. +.PP +Clearing the `c' attribute will cause a file to be decompressed as soon +as possible, although it may not clear the `B' attribute unless `-m never' +is also specified. +.PP +Directories also can be marked with the `c' attribute; in such a case, +nothing is compressed, but any newly created file in the directory +will automatically be marked with the `c' attribute. Similarly, a +directory can be given an algorithm name and/or cluster size, +so that newly created files will use this algorithm / cluster size. +New files in the directory will only inherit the flags if they get a new +inode, not if they are simply given a new link in that directory (e.g. +with `mv' or `ln'). .PP When a directory with the `D' attribute set is modified, the changes are written synchronously on the disk; this is equivalent to @@ -63,12 +135,8 @@ .BR dump (8) program is run. .PP -The 'E' attribute is used by the experimental compression patches to -indicate that a compressed file has a compression error. It may not be -set or reset using -.BR chattr (1), -although it can be displayed by -.BR lsattr (1). +The `E' attribute is used by the experimental compression patches to +indicate that a compressed file has a compression error. .PP The 'I' attribute is used by the htree code to indicate that a directory is behind indexed using hashed trees. It may not be set or reset using @@ -110,15 +178,13 @@ When a file with the `u' attribute set is deleted, its contents are saved. This allows the user to ask for its undeletion. .PP -The 'X' attribute is used by the experimental compression patches to +The `X' attribute is used by the experimental compression patches to indicate that a raw contents of a compressed file can be accessed -directly. It currently may not be set or reset using -.BR chattr (1), -although it can be displayed by -.BR lsattr (1). +directly. .PP -The 'Z' attribute is used by the experimental compression patches to -indicate a compressed file is dirty. It may not be set or reset using +The `Z' attribute is used by the experimental compression patches to +indicate a compressed file is dirty (ie. that compression or decompression +is pending). It may not be set or reset using .BR chattr (1), although it can be displayed by .BR lsattr (1). @@ -126,19 +192,45 @@ .SH AUTHOR .B chattr was written by Remy Card . It is currently being -maintained by Theodore Ts'o . +maintained by Theodore Ts'o . Modifications to +display information related to file compression were written by Antoine +de Maricourt . .SH BUGS AND LIMITATIONS The `c', 's', and `u' attributes are not honored by the ext2 and ext3 filesystems as implemented in the current mainline Linux kernels. These attributes may be implemented in future versions ext2 and ext3. .PP +The `c' attribute is implemented in the kernel if the e2compr patch +has been applied. The +.B \-m +and +.B \-b +options are also accepted only if the patch has been applied. +.PP +It is currently not possible to change the cluster size for an +already compressed file. You must first decompress the file, and +then compress it again with the new cluster size. +.PP +Changing the compression algorithm will not recompress the already +compressed clusters with the new algorithm. +Only newly written data will be compressed with the new algorithm. +If you want to recompress the complete file with the new algorithm, +you must first decompress it, and then recompress it with the new +algorithm. +.PP The `j' option is only useful if the filesystem is mounted as ext3. .PP The `D' option is only useful on Linux kernel 2.5.19 and later. .SH AVAILABILITY +This version of .B chattr -is part of the e2fsprogs package and is available from -http://e2fsprogs.sourceforge.net. +is modified for the e2compr project. +The original version is part of the e2fsprogs package and is +available from http://e2fsprogs.sourceforge.net. .SH SEE ALSO .BR lsattr (1) +.BR e2compress (1) +(not for use with e2compr-0.4), +.BR e2ratio (1), +.BR e2bitmap (1). diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/chattr.c softs/e2fsprogs/misc/chattr.c --- e2fsprogs-1.38/misc/chattr.c 2005-05-09 22:22:17.000000000 +0200 +++ softs/e2fsprogs/misc/chattr.c 2007-11-29 15:44:50.000000000 +0100 @@ -14,6 +14,7 @@ * 93/10/30 - Creation * 93/11/13 - Replace stat() calls by lstat() to avoid loops * 94/02/27 - Integrated in Ted's distribution + * 96/09/29 - Integrated Antoine de Maricourt's e2compr changes. * 98/12/29 - Ignore symlinks when working recursively (G M Sipe) * 98/12/29 - Display version info only when -V specified (G M Sipe) */ @@ -32,6 +33,7 @@ #endif #include #include +#include #include "ext2fs/ext2_fs.h" #ifdef __GNUC__ @@ -50,6 +52,11 @@ #include "et/com_err.h" #include "e2p/e2p.h" +#ifdef ENABLE_COMPRESSION +# include "e2p/ext2_meth.h" +#endif +#include "ext2fs/ext2_iflags.h" +#include "ext2fs/ext2_ioctls.h" #include "../version.h" #include "nls-enable.h" @@ -60,6 +67,10 @@ static int rem; static int set; static int set_version; +#ifdef ENABLE_COMPRESSION +static unsigned long cluster_size = 0; +static unsigned compr_meth = ~0u; +#endif static unsigned long version; @@ -84,8 +95,59 @@ exit (errcode); } -#define usage() fatal_error(_("Usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"), \ - 1) +#ifdef ENABLE_COMPRESSION +# define USAGE_STRING \ + "usage: %s " \ + "[-RV] [-+=AacDdEijSsuX] " \ + "[-b size] [-m name] " \ + "[-v version] files...\n" \ + "Try `--help' for more information.\n" +#else +# define USAGE_STRING \ + "usage: %s " \ + "[-RV] [-+=AacDdijSsu] " \ + "[-v version] files...\n" \ + "Try `--help' for more information.\n" +#endif + +#define usage() fatal_error (_(USAGE_STRING), 1) + +static void print_version_string(FILE *fp) +{ + fprintf (fp, _("chattr %s (%s)\n"), + E2FSPROGS_VERSION, E2FSPROGS_DATE); +} + +static void help (void) +{ + print_version_string(stdout); + fprintf (stdout, + _(USAGE_STRING + " +-=A set/reset no-atime flag\n" + " +-=a set/reset append-only flag\n" + " +-=B ignored; see man page\n" + " +-=c set/reset compress flag\n" + " +-=D set/reset synchronous directory updates\n" + " +-=d set/reset no-dump flag\n" + " +-=E set/reset compression error flag\n" + " +-=i set/reset immutable flag\n" + " +-=j set/reset data journalling flag\n" + " +-=S set/reset sync flag\n" + " +-=s set/reset secure deletion flag\n" + " +-=u set/reset undelete flag\n" + " +-=X enable or disable compression on I/O\n" + " +-=Z ignored; see man page\n" + " -b size set cluster size (in blocks)\n" + " -m name set compression method\n" + " -v number set file version\n" + " -R recursive mode\n" + " -V verbosely describe changes\n" + " --help show this help message and exit\n" + " --version show program version and exit\n"), + program_name); + + exit (0); +} struct flags_char { unsigned long flag; @@ -94,17 +156,21 @@ static const struct flags_char flags_array[] = { { EXT2_NOATIME_FL, 'A' }, - { EXT2_SYNC_FL, 'S' }, - { EXT2_DIRSYNC_FL, 'D' }, { EXT2_APPEND_FL, 'a' }, + { -1, 'B' }, { EXT2_COMPR_FL, 'c' }, + { EXT2_DIRSYNC_FL, 'D' }, { EXT2_NODUMP_FL, 'd' }, + { EXT2_ECOMPR_FL, 'E' }, { EXT2_IMMUTABLE_FL, 'i' }, { EXT3_JOURNAL_DATA_FL, 'j' }, + { EXT2_SYNC_FL, 'S' }, { EXT2_SECRM_FL, 's' }, { EXT2_UNRM_FL, 'u' }, - { EXT2_NOTAIL_FL, 't' }, { EXT2_TOPDIR_FL, 'T' }, + { EXT2_NOTAIL_FL, 't' }, + { EXT2_NOCOMPR_FL, 'X' }, + { -1, 'Z' }, { 0, 0 } }; @@ -138,6 +204,39 @@ verbose = 1; continue; } +#ifdef ENABLE_COMPRESSION + if (*p == 'b') { + (*i)++; + if (*i >= argc) + usage (); + cluster_size = strtol (argv[*i], &tmp, 0); + + if (*tmp || (cluster_size != 4 && + cluster_size != 8 && + cluster_size != 16 && + cluster_size != 32)) { + com_err (program_name, 0, + _("invalid cluster size: %s\n"), + argv[*i]); + usage (); + } + continue; + } + + if (*p == 'm') { + (*i)++; + if (*i >= argc) + usage (); + compr_meth = meth_name2id(argv[*i]); + if (compr_meth == ~0u) { + com_err (program_name, 0, + _("unknown compression method: %s\n"), + argv[*i]); + exit (1); + } + continue; + } +#endif if (*p == 'v') { (*i)++; if (*i >= argc) @@ -154,8 +253,10 @@ } if ((fl = get_flag(*p)) == 0) usage(); - rf |= fl; - rem = 1; + if (fl != -1) { + rf |= fl; + rem = 1; + } } break; case '+': @@ -163,7 +264,8 @@ for (p = &argv[*i][1]; *p; p++) { if ((fl = get_flag(*p)) == 0) usage(); - af |= fl; + if (fl != -1) + af |= fl; } break; case '=': @@ -171,7 +273,11 @@ for (p = &argv[*i][1]; *p; p++) { if ((fl = get_flag(*p)) == 0) usage(); - sf |= fl; + if (fl != -1) { + sf |= fl; + if (*p == 'E') + rem = 1; + } } break; default: @@ -187,6 +293,7 @@ { unsigned long flags; STRUCT_STAT st; + int fd; if (LSTAT (name, &st) == -1) { com_err (program_name, errno, _("while trying to stat %s"), @@ -204,23 +311,33 @@ !S_ISDIR(st.st_mode)) return; - if (set) { - if (verbose) { - printf (_("Flags of %s set as "), name); - print_flags (stdout, sf, 0); - printf ("\n"); - } - if (fsetflags (name, sf) == -1) - perror (name); - } else { - if (fgetflags (name, &flags) == -1) - com_err (program_name, errno, - _("while reading flags on %s"), name); + /* The problem is that we mustn't close the file between + turning on the `c' attribute and setting the compression + method or cluster size. Thus we can't use fgetflags or + fsetflags. */ + + fd = open (name, O_RDONLY | O_NONBLOCK); + if (fd == -1) { + com_err (program_name, errno, + _("while trying to open %s"), name); + } + else { + if (set) + flags = sf; else { - if (rem) + if (add || rem) { + if (ioctl (fd, EXT2_IOC_GETFLAGS, &flags) + == -1) { + com_err (program_name, errno, + _("while reading flags on %s"), + name); + goto endflags; + } flags &= ~rf; - if (add) flags |= af; + } + } + if (set || add || rem) { if (verbose) { printf (_("Flags of %s set as "), name); print_flags (stdout, flags, 0); @@ -228,11 +345,71 @@ } if (!S_ISDIR(st.st_mode)) flags &= ~EXT2_DIRSYNC_FL; - if (fsetflags (name, flags) == -1) - com_err (program_name, errno, - _("while setting flags on %s"), name); + if (ioctl (fd, EXT2_IOC_SETFLAGS, &flags) == -1) { + if (errno == ENOTTY) + com_err (program_name, 0, + _("Invalid request while " + "setting flags on %s"), name); + else + com_err (program_name, errno, + _("while setting flags on %s"), + name); + goto endflags; + } + } + +#ifdef ENABLE_COMPRESSION + if (cluster_size != 0) { +#ifndef HAVE_EXT2_IOCTLS + com_err (program_name, EOPNOTSUPP, + _("while setting cluster size")); + goto endflags; +#else + if (verbose) + printf (_("Cluster size of %s set to %lu\n"), + name, cluster_size); + flags = cluster_size; + if (cluster_size && (ioctl (fd, + EXT2_IOC_SETCLUSTERSIZE, &flags) == -1)) + com_err (program_name, 0, + _("can't set cluster size of %s"), + name); +#endif } + + if (compr_meth != ~0u) { +#ifndef HAVE_EXT2_IOCTLS + com_err (program_name, EOPNOTSUPP, + _("while setting compression method")); + goto endflags; +#else + if (verbose) + printf (_("Compression method of %s set to " + "%s\n"), name, + meth_id2name(compr_meth)); + flags = compr_meth; + if (ioctl (fd, EXT2_IOC_SETCOMPRMETHOD, &flags) == -1) + com_err (program_name, 0, + _("can't set compression method " + "of %s"), name); + /* e2compr 0.4 kernels write 1 to flags if the + method was recognised, 0 otherwise. + e2compr-0.3 kernels don't write anything. + We try to accommodate both cases. */ + else + if ((!flags) && compr_meth) + fprintf (stderr, _("%s: warning: " + "kernel doesn't recognise " + "compression method %u.\n"), + program_name, compr_meth); +#endif + } +#endif /* ENABLE_COMPRESSION */ + + endflags: + close (fd); } + if (set_version) { if (verbose) printf (_("Version of %s set as %lu\n"), name, version); @@ -274,6 +451,14 @@ #endif if (argc && *argv) program_name = *argv; + + if ((argc == 2) && (strcmp (argv[1], "--version") == 0)) { + print_version_string(stdout); + exit (0); + } + if ((argc >= 2) && (strcmp (argv[1], "--help") == 0)) + help(); + i = 1; while (i < argc && !end_arg) { /* '--' arg should end option processing */ @@ -295,13 +480,16 @@ fputs("Can't both set and unset same flag.\n", stderr); exit (1); } - if (!(add || rem || set || set_version)) { - fputs(_("Must use '-v', =, - or +\n"), stderr); + if (!(add || rem || set || set_version +#ifdef ENABLE_COMPRESSION + || cluster_size || (compr_meth != ~0u) +#endif + )) { + fprintf (stderr, _("Must use `-b', `-m', `-v', =, - or +\n")); exit (1); } if (verbose) - fprintf (stderr, "chattr %s (%s)\n", - E2FSPROGS_VERSION, E2FSPROGS_DATE); + print_version_string(stderr); for (j = i; j < argc; j++) change_attributes (argv[j]); exit(0); diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/lsattr.1.in softs/e2fsprogs/misc/lsattr.1.in --- e2fsprogs-1.38/misc/lsattr.1.in 2004-02-01 02:27:36.000000000 +0100 +++ softs/e2fsprogs/misc/lsattr.1.in 2007-11-29 15:44:50.000000000 +0100 @@ -5,7 +5,7 @@ .SH SYNOPSIS .B lsattr [ -.B \-RVadv +.B \-ARVadlruv ] [ .I files... @@ -15,8 +15,15 @@ lists the file attributes on a second extended file system. See .BR chattr (1) for a description of the attributes and what they mean. +This version is able to display compression information provided by +the e2compr patch, but will also work on unpatched kernels. .SH OPTIONS .TP +.B \-A +List almost every file in directories, +including files that start with `.', +but not special files `.' and `..'. +.TP .B \-R Recursively list attributes of directories and their contents. .TP @@ -29,6 +36,15 @@ .B \-d List directories like other files, rather than listing their contents. .TP +.B \-l +List attributes verbosely. +.TP +.B \-r +Display the compression ratio. +.TP +.B \-u +Display number of blocks in both uncompressed and compressed form. +.TP .B \-v List the file's version/generation number. .SH AUTHOR @@ -43,3 +59,5 @@ http://e2fsprogs.sourceforge.net. .SH SEE ALSO .BR chattr (1) +.BR e2ratio (1), +.BR e2compress (1). diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/lsattr.c softs/e2fsprogs/misc/lsattr.c --- e2fsprogs-1.38/misc/lsattr.c 2004-09-24 18:16:17.000000000 +0200 +++ softs/e2fsprogs/misc/lsattr.c 2007-11-29 15:44:50.000000000 +0100 @@ -14,7 +14,15 @@ * 93/10/30 - Creation * 93/11/13 - Replace stat() calls by lstat() to avoid loops * 94/02/27 - Integrated in Ted's distribution - * 98/12/29 - Display version info only when -V specified (G M Sipe) + * 95/02/17 - Completly rewriten to display compression information + * and to behave much more like `ls'. Useless calls to + * intermediate routines that just call ioctl() were + * replaced by direct calls to ioctl(). Uses less space + * in the stack to store the path name when recursive + * listing. Alphabetic listing thanks to scandir(). + * (Antoine de Maricourt) + * 98/12/29 - Display version/generation info when -V specified + * (G M Sipe) */ #define _LARGEFILE64_SOURCE @@ -35,12 +43,21 @@ #include #include #include +#include +#include + +#include #include #include #include "ext2fs/ext2_fs.h" #include "et/com_err.h" -#include "e2p/e2p.h" +#include "e2p/e2p.h" /* print_flags() */ +#ifdef ENABLE_COMPRESSION +# include "e2p/ext2_meth.h" /* meth_id2name */ +#endif +#include "ext2fs/ext2_ioctls.h" +#include "ext2fs/ext2_iflags.h" #include "../version.h" #include "nls-enable.h" @@ -53,12 +70,18 @@ static const char * program_name = "lsattr"; -static int all; +/* static int all; */ static int dirs_opt; -static unsigned pf_options; +static unsigned pf_options = 0; static int recursive; static int verbose; static int generation_opt; +#ifdef ENABLE_COMPRESSION +static int nblocks_opt = 0; +static int ratio_opt = 0; +#endif +static char *path = NULL; +static size_t path_size = 1; /* Either I'm lazy or I'm safety-conscious. */ #ifdef _LFS64_LARGEFILE #define LSTAT lstat64 @@ -68,87 +91,350 @@ #define STRUCT_STAT struct stat #endif -static void usage(void) +static void print_version_string (FILE *fp) { - fprintf(stderr, _("Usage: %s [-RVadlv] [files...]\n"), program_name); - exit(1); + fprintf (fp, _("lsattr %s (%s)\n"), E2FSPROGS_VERSION, E2FSPROGS_DATE); } +/* String used in getopt calls and in usage messages. */ +#ifdef ENABLE_COMPRESSION +# define GETOPT_FLAGS "ARVadelruv" +#else +# define GETOPT_FLAGS "ARVadlv" +#endif +static void help (void) +{ + print_version_string(stdout); + printf (_("usage: %s [-" GETOPT_FLAGS "] [files...]\n" + " -A show almost every file\n" + " -R recursive mode\n" + " -V verbose (display version number)\n" + " -a show every file\n" + " -d directories behave like normal files\n" + " -l list attributes verbosely\n" + " -r show the compression ratio\n" + " -u show space usage for as-uncompressed and as-current forms\n" + " -v display file generation number\n" + " --help show this help and exit\n" + " --version show program version information and exit\n"), + program_name); + exit (0); +} + +static void usage (void) +{ + fprintf (stderr, + _("Usage: %s [-" GETOPT_FLAGS "] [files...]\n" + "Try `%s --help' for more information.\n"), + program_name, program_name); + exit (1); +} + +/* + * Used by scandir to select file names. + */ + +static int select_normal (const struct dirent *d) +{ + return (d->d_name[0] != '.'); +} + +static int +select_almost_all (const struct dirent *d) +{ + return (d->d_name[0] != '.' + || (d->d_name[1] != '\0' + && (d->d_name[1] != '.' + || d->d_name[2] != '\0'))); +} + +#define select_all NULL + +static int (*select_scope) (const struct dirent *) = select_normal; + static void list_attributes (const char * name) { + int fd; + STRUCT_STAT st; unsigned long flags; unsigned long generation; +#ifdef ENABLE_COMPRESSION + unsigned long size; + unsigned long method = ~0ul; + unsigned long ratio[2]; + int unpatched_kernel = 0; +#endif + + if (LSTAT (path, &st) == -1) { + com_err (program_name, errno, _("during lstat on %s"), path); + return; + } - if (fgetflags (name, &flags) == -1) { - com_err (program_name, errno, _("While reading flags on %s"), - name); + /* + * todo: This could be improved, e.g. displaying the name but + * question marks for other fields. + */ + if ((!S_ISREG(st.st_mode)) && (!S_ISDIR(st.st_mode))) + return; + + if ((fd = open (path, O_RDONLY)) == -1) { + com_err (program_name, errno, _("opening %s"), path); return; } + + if (fgetflags (path, &flags) == -1) { + com_err (program_name, errno, _("while reading flags on %s"), + path); + close (fd); + return; + } + if (generation_opt) { - if (fgetversion (name, &generation) == -1) { + if (fgetversion (path, &generation) == -1) { com_err (program_name, errno, - _("While reading version on %s"), - name); + _("while reading version on %s"), + path); + close (fd); return; } + } + +#ifdef ENABLE_COMPRESSION + /* + * This really ought to use a libe2p function. lsattr shouldn't call + * ioctl directly. + */ + if ((ioctl (fd, EXT2_IOC_GETCLUSTERSIZE, &size) == -1) + || (ioctl (fd, EXT2_IOC_GETCOMPRMETHOD, &method) == -1)) { + assert (errno != EFAULT); /* Having three assert's gives a */ + assert (errno != EBADFD); /* finer diagnostic than one. */ + assert (errno == ENOTTY); + /* + * Presumably we are running under a kernel without e2compr + * support. Kernels without e2compr support pass the + * cluster size and compression algorithm id in the flags + * field. Unfortunately, we don't know for sure whether + * the filesystem is written with e2compr-0.4 or e2compr-0.3 + * (which store cluster size differently). + */ + +# define UNP_UNPATCHED 8 +# define UNP_WARNED 4 +# define UNP_04_FOUND 2 /* At least one file has been found where the + * flags word suggests e2compr-0.4 format. */ +# define UNP_03_FOUND 1 /* At least one file has been found where the + * flags word suggests e2compr-0.3 format. */ + + unpatched_kernel |= UNP_UNPATCHED; + if ((flags & (EXT2FS_COMPR_FL | EXT2FS_COMPRBLK_FL)) + && !(unpatched_kernel & UNP_WARNED)) { + fprintf (stderr, + _("%s: warning: cluster size display is " + "unreliable on unpatched kernels.\n"), + program_name); + /* + * With unpatched kernels, we do our best, but it's + * still just a heuristic (e.g. if different + * filesystems involved, or files we see before seeing + * evidence of either filesystem, or files written + * with a more recent version of e2compr than this + * chattr). + */ + unpatched_kernel |= UNP_WARNED; + } + if ((unpatched_kernel & UNP_04_FOUND) || (flags & (1 << 23))) { + unpatched_kernel |= UNP_04_FOUND; + size = 1 << ((flags >> 23) & 7); + } else { + /* assume e2compr-0.4 unless size out of usual bounds */ + if ((unpatched_kernel & UNP_03_FOUND) + || ((size = 1 << ((flags >> 23) & 7)) < 4) + || (size > 32)) { + /* + * Current versions of e2compr don't allow + * cluster sizes outside of [4, 32], so assume + * e2compr-0.3. + */ + unpatched_kernel |= UNP_03_FOUND; + size = 1 << (((flags >> 24) & 0x03) + 2); + } + } + method = (flags >> 26) & 0x1f; + ratio_opt = 0; + } + + /* + * This really ought to use a libe2p function. lsattr shouldn't call + * ioctl directly. + */ + if ((nblocks_opt || ratio_opt) + && (ioctl (fd, EXT2_IOC_GETCOMPRRATIO, ratio) == -1)) { + if (errno == ENOSYS) + ratio[0] = ~0UL; /* Not a regular file. */ + else { + com_err (program_name, errno, + _("computing ratio of %s"), name); + close (fd); + return; + } + } +#endif /* ENABLE_COMPRESSION */ + + /* + * Display Generation + */ + if (generation_opt) printf ("%5lu ", generation); + + /* + * Display flags on left unless long option. + */ + if (!(pf_options & PFOPT_LONG)) + print_flags (stdout, flags, pf_options); + +#ifdef ENABLE_COMPRESSION + /* + * Display Cluster size + */ + if (flags & (EXT2FS_COMPR_FL | EXT2FS_COMPRBLK_FL)) + printf (" %2lu", size); + else + printf (" -"); + + /* + * Display Compression method + */ + if ((flags & EXT2FS_COMPR_FL)) + printf (" %-6s", meth_id2name (method)); + else + printf (" - "); + + /* + * Optionally display compression ratio and nblocks. + */ + if (nblocks_opt) { + /* + * todo: We should behave as `du' wrt POSIXLY_CORRECT + * environment variable. Of course POSIX doesn't specify + * lsattr behaviour, but people who get this behaviour from + * `du' would probably want the same behaviour here. Same + * goes for e2ratio. + */ + if (unpatched_kernel) + printf (" ? %7llu ", st.st_blocks / 2); + else { + if (ratio[0] == ~0UL) { /* Not a regular file. */ + if (ratio_opt) + printf (" "); + else + printf (_(" N/A ")); + } else + printf ("%7lu %7lu ", ratio[0], ratio[1]); + } + } + + if (ratio_opt) { + if (ratio[0] == ~0UL) + printf (_(" N/A ")); /* Not a regular file. */ + else + if (ratio[0] == 0) + printf (" 100.0%% "); /* 0 / 0 */ + else + printf (" %5.1f%% ", 100.0 * (double) ratio[1] + / ratio[0]); } +#endif + if (pf_options & PFOPT_LONG) { printf("%-28s ", name); print_flags(stdout, flags, pf_options); fputc('\n', stdout); - } else { - print_flags(stdout, flags, pf_options); - printf(" %s\n", name); + } else + printf (" %s\n", name); + + close (fd); +} + +static void grow_path_to(size_t needed_len) +{ + if (path_size < needed_len) { + do + path_size *= 2; + while (path_size < needed_len); + path = realloc (path, path_size); + if (path == NULL) + com_err (program_name, ENOMEM, + _("while allocating %u bytes for path"), + path_size); } } -static int lsattr_dir_proc (const char *, struct dirent *, void *); +/* + * Show attributes for every file in a directory, and go deeper if + * recursive. Files are displayed in alphabetical order. + */ + +enum ph {NO_PRINT_HEAD = 0, PRINT_HEAD}; -static void lsattr_args (const char * name) +static void lsattr_dir (int len, int do_print_head) { - STRUCT_STAT st; + STRUCT_STAT st; + struct dirent **de; + int i, count; - if (LSTAT (name, &st) == -1) - com_err (program_name, errno, _("while trying to stat %s"), - name); - else { - if (S_ISDIR(st.st_mode) && !dirs_opt) - iterate_on_dir (name, lsattr_dir_proc, NULL); - else - list_attributes (name); + if ((len > 0) && (LSTAT (path, &st) == -1)) { + com_err (program_name, errno, _("during lstat on %s"), path); + return; } -} -static int lsattr_dir_proc (const char * dir_name, struct dirent * de, - void * private EXT2FS_ATTR((unused))) -{ - STRUCT_STAT st; - char *path; - int dir_len = strlen(dir_name); + if ((len != 0) && !S_ISDIR (st.st_mode)) + return; - path = malloc(dir_len + strlen (de->d_name) + 2); + if (do_print_head) + printf ("\n%s:\n", path); - if (dir_len && dir_name[dir_len-1] == '/') - sprintf (path, "%s%s", dir_name, de->d_name); - else - sprintf (path, "%s/%s", dir_name, de->d_name); - if (LSTAT (path, &st) == -1) - perror (path); - else { - if (de->d_name[0] != '.' || all) { - list_attributes (path); - if (S_ISDIR(st.st_mode) && recursive && - strcmp(de->d_name, ".") && - strcmp(de->d_name, "..")) { - printf ("\n%s:\n", path); - iterate_on_dir (path, lsattr_dir_proc, NULL); - printf ("\n"); + /* + * Scan the directory and sort files in alphabetical order. + */ + + if ((count = scandir ((len == 0 ? "." : path), &de, select_scope, + alphasort)) < 0) { + com_err (program_name, errno, _("scanning directory \"%s\""), + (len == 0 ? "." : path)); + return; + } + + if (len > 0 && path[len - 1] != '/') + path[len++] = '/'; + + for (i = 0; i < count; i++) { + size_t needed_len = len + strlen (de[i]->d_name) + 1; + + grow_path_to (needed_len); + strcpy (path + len, de[i]->d_name); + list_attributes (de[i]->d_name); + } + + if (recursive) { + for (i = 0; i < count; i++) { + if ((select_scope != select_all) + || select_almost_all (de[i])) { + assert (len + strlen (de[i]->d_name) < + path_size); + strcpy (path + len, de[i]->d_name); + lsattr_dir (len + strlen (de[i]->d_name), + PRINT_HEAD); } } } - free(path); - return 0; + + /* + * Free the list. + */ + for (i = 0; i < count; i++) + free (de[i]); + + free (de); } int main (int argc, char ** argv) @@ -162,40 +448,94 @@ bindtextdomain(NLS_CAT_NAME, LOCALEDIR); textdomain(NLS_CAT_NAME); #endif + if (argc && *argv) program_name = *argv; - while ((c = getopt (argc, argv, "RVadlv")) != EOF) - switch (c) - { + + if ((argc == 2) && (strcmp (argv[1], "--version") == 0)) { + print_version_string(stdout); + exit (0); + } + if ((argc >= 2) && (strcmp (argv[1], "--help") == 0)) + help(); + + while ((c = getopt (argc, argv, GETOPT_FLAGS)) != EOF) { + switch (c) { case 'R': recursive = 1; break; - case 'V': - verbose = 1; - break; case 'a': - all = 1; + select_scope = select_all; + break; + case 'A': + select_scope = select_almost_all; break; case 'd': dirs_opt = 1; break; case 'l': - pf_options = PFOPT_LONG; + pf_options |= PFOPT_LONG; + break; +#ifdef ENABLE_COMPRESSION + case 'r': + ratio_opt = 1; + break; + case 'u': + nblocks_opt = 1; break; +#endif case 'v': generation_opt = 1; break; + case 'V': + verbose = 1; + break; default: - usage(); + usage (); } + } if (verbose) - fprintf (stderr, "lsattr %s (%s)\n", - E2FSPROGS_VERSION, E2FSPROGS_DATE); - if (optind > argc - 1) - lsattr_args ("."); - else - for (i = optind; i < argc; i++) - lsattr_args (argv[i]); - exit(0); + print_version_string(stderr); + + /* + * Antoine was thinking that `lsattr .' shouldn't prefix everything + * with `./'. I don't know what he intended to happen with `lsattr + * foo . bar'. The current behaviour is that with `lsattr' (no file + * argument), no prefix is given; but with `lsattr .' and `lsattr + * foo . bar', `.' is treated as any other directory name. I think + * this is the right behaviour as it is, so I haven't changed it. + */ + + if (optind >= argc) { + if (dirs_opt) { + grow_path_to (2); + strcpy (path, "."); + list_attributes ("."); + } else + lsattr_dir (0, NO_PRINT_HEAD); + } else { + for (i = optind; i < argc; i++) { + grow_path_to (strlen(argv[i]) + 1); + strcpy (path, argv[i]); + if (dirs_opt) + list_attributes (argv[i]); + else { + STRUCT_STAT st; + + if (LSTAT (argv[i], &st) == -1) + fprintf (stderr, _("%s: %s: can't " + "lstat file (%s)\n"), + program_name, argv[i], + strerror (errno)); + else + if (S_ISDIR (st.st_mode)) + lsattr_dir (strlen (argv[i]), + argc - optind - 1); + else + list_attributes (argv[i]); + } + } + } + return 0; } diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/Makefile.in softs/e2fsprogs/misc/Makefile.in --- e2fsprogs-1.38/misc/Makefile.in 2005-06-29 19:42:20.000000000 +0200 +++ softs/e2fsprogs/misc/Makefile.in 2007-11-29 15:44:50.000000000 +0100 @@ -14,7 +14,7 @@ @IMAGER_CMT@E2IMAGE_PROG= e2image @IMAGER_CMT@E2IMAGE_MAN= e2image.8 -SPROGS= mke2fs badblocks tune2fs dumpe2fs blkid logsave \ +SPROGS= mke2fs badblocks tune2fs dumpe2fs blkid logsave e2label \ $(E2IMAGE_PROG) @FSCK_PROG@ USPROGS= mklost+found filefrag SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \ @@ -27,6 +27,7 @@ LPROGS= @E2INITRD_PROG@ TUNE2FS_OBJS= tune2fs.o util.o +E2LABEL_OBJS= e2label.o MKLPF_OBJS= mklost+found.o MKE2FS_OBJS= mke2fs.o util.o CHATTR_OBJS= chattr.o @@ -81,6 +82,11 @@ @$(CC) $(ALL_LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS) \ $(LIBS_BLKID) $(LIBS_E2P) $(LIBINTL) +e2label: $(E2LABEL_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) + @echo " LD $@" + @$(CC) $(ALL_LDFLAGS) -o e2label $(E2LABEL_OBJS) $(LIBS) \ + $(LIBS_E2P) $(LIBINTL) + blkid: $(BLKID_OBJS) $(DEPLIBS_BLKID) @echo " LD $@" @$(CC) $(ALL_LDFLAGS) -o blkid $(BLKID_OBJS) $(LIBS_BLKID) $(LIBINTL) @@ -236,7 +242,7 @@ @$(LN) -f $(DESTDIR)$(root_sbindir)/mke2fs \ $(DESTDIR)$(root_sbindir)/mkfs.ext3 @echo " LINK $(root_sbindir)/e2label" - @$(LN) -f $(DESTDIR)$(root_sbindir)/tune2fs \ + @$(LN) -f $(DESTDIR)$(root_sbindir)/e2label \ $(DESTDIR)$(root_sbindir)/e2label @echo " LINK $(root_sbindir)/findfs" @$(LN) -f $(DESTDIR)$(root_sbindir)/tune2fs \ diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/tune2fs.8.in softs/e2fsprogs/misc/tune2fs.8.in --- e2fsprogs-1.38/misc/tune2fs.8.in 2005-05-08 00:56:28.000000000 +0200 +++ softs/e2fsprogs/misc/tune2fs.8.in 2007-11-29 15:44:50.000000000 +0100 @@ -371,11 +371,18 @@ .B \-j option. .TP +.B compression +Useful only if you've used e2compr-0.4 with the filesystem; +raising this flag is not useful unless you've just accidentally +cleared the flag but haven't yet run e2fsck. +.TP .B sparse_super Limit the number of backup superblocks to save space on large filesystems. .RE .IP After setting or clearing +.B compression +, .B sparse_super and .B filetype diff --exclude=.svn -r -u -N e2fsprogs-1.38/misc/tune2fs.c softs/e2fsprogs/misc/tune2fs.c --- e2fsprogs-1.38/misc/tune2fs.c 2005-06-20 14:35:27.000000000 +0200 +++ softs/e2fsprogs/misc/tune2fs.c 2007-11-29 15:44:50.000000000 +0100 @@ -96,7 +96,8 @@ static __u32 ok_features[3] = { EXT3_FEATURE_COMPAT_HAS_JOURNAL | EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */ - EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */ + EXT2_FEATURE_INCOMPAT_COMPRESSION | + EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */ }; diff --exclude=.svn -r -u -N e2fsprogs-1.38/README.e2compr softs/e2fsprogs/README.e2compr --- e2fsprogs-1.38/README.e2compr 1970-01-01 01:00:00.000000000 +0100 +++ softs/e2fsprogs/README.e2compr 2007-11-29 15:44:50.000000000 +0100 @@ -0,0 +1,13 @@ +The programs modified for e2compr are: + + - libext2fs: Acknowledges support for e2compr filesystems. + - libe2p: Compression method printing & parsing, limit maximum + filesystem size to 2^32 - 2 blocks. + - chattr: Change compression characteristics. + - lsattr: Display compression characteristics. + - tune2fs: Allow compression flag to be changed. + + Some header files and manual pages are also changed or new. + +In case of bugs in these programs, please write to the e2compr mailing list +. diff --exclude=.svn -r -u -N e2fsprogs-1.38/version.h softs/e2fsprogs/version.h --- e2fsprogs-1.38/version.h 2005-07-01 02:06:44.000000000 +0200 +++ softs/e2fsprogs/version.h 2007-11-29 15:44:50.000000000 +0100 @@ -7,5 +7,5 @@ * the GNU Public License. */ -#define E2FSPROGS_VERSION "1.38" -#define E2FSPROGS_DATE "30-Jun-2005" +#define E2FSPROGS_VERSION "1.38-e2compr-0.4.11-0" +#define E2FSPROGS_DATE "04-Aug-2005"