lkml.org 
[lkml]   [1999]   [Dec]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
SubjectRe: [security] Big problem on 2.0.x? (fwd)
From
Speaking of 2.0 updates, there were some people who expressed interest
at the Linux Standards Base meeting in New York City for my patches
which allow a 2.0 kernel to be able to mount filesystems with sparse
superblocks (which is the default in the latest e2fsprogs, and much more
efficienct on larger disks.)

It's a pretty stable patch, so I'm confident about its stability;
distributions that are still releasing 2.0 kernel updates might want to
consider this for backwards compatibility reasons, if you need to mount
filesystems created on newer systems.

- Ted

Patch generated: on Thu Oct 21 14:27:50 EDT 1999 by tytso@trampoline.thunk.org
against Linux version 2.0.35

===================================================================
RCS file: fs/ext2/RCS/super.c,v
retrieving revision 1.1
diff -u -r1.1 fs/ext2/super.c
--- fs/ext2/super.c 1999/10/15 12:06:21 1.1
+++ fs/ext2/super.c 1999/10/15 15:25:40
@@ -463,6 +463,9 @@
goto failed_mount;
}
}
+ sb->u.ext2_sb.s_feature_compat = es->s_feature_compat;
+ sb->u.ext2_sb.s_feature_incompat = es->s_feature_incompat;
+ sb->u.ext2_sb.s_feature_ro_compat = es->s_feature_ro_compat;
sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
es->s_log_frag_size;
if (sb->u.ext2_sb.s_frag_size)
@@ -710,6 +713,7 @@
unsigned long overhead;
unsigned long overhead_per_group;
struct statfs tmp;
+ int ngroups, i;

if (test_opt (sb, MINIX_DF))
overhead = 0;
@@ -717,13 +721,35 @@
/*
* Compute the overhead (FS structures)
*/
- overhead_per_group = 1 /* super block */ +
- sb->u.ext2_sb.s_db_per_group /* descriptors */ +
- 1 /* block bitmap */ +
- 1 /* inode bitmap */ +
- sb->u.ext2_sb.s_itb_per_group /* inode table */;
- overhead = sb->u.ext2_sb.s_es->s_first_data_block +
- sb->u.ext2_sb.s_groups_count * overhead_per_group;
+
+ /*
+ * All of the blocks before first_data_block are
+ * overhead
+ */
+ overhead = sb->u.ext2_sb.s_es->s_first_data_block;
+
+ /*
+ * Add the overhead attributed to the superblock and
+ * block group descriptors. If this is sparse
+ * superblocks is turned on, then not all groups have
+ * this.
+ */
+ if (sb->u.ext2_sb.s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
+ ngroups = 0;
+ for (i=0 ; i < sb->u.ext2_sb.s_groups_count; i++)
+ if (ext2_group_sparse(i))
+ ngroups++;
+ } else
+ ngroups = sb->u.ext2_sb.s_groups_count;
+ overhead += ngroups * (1 + sb->u.ext2_sb.s_db_per_group);
+
+ /*
+ * Every block group has an inode bitmap, a block
+ * bitmap, and an inode table.
+ */
+ overhead += (sb->u.ext2_sb.s_groups_count *
+ (2 + sb->u.ext2_sb.s_itb_per_group));
}

tmp.f_type = EXT2_SUPER_MAGIC;
===================================================================
RCS file: fs/ext2/RCS/balloc.c,v
retrieving revision 1.1
diff -u -r1.1 fs/ext2/balloc.c
--- fs/ext2/balloc.c 1999/10/15 12:13:01 1.1
+++ fs/ext2/balloc.c 1999/10/15 12:15:57
@@ -645,6 +645,25 @@
EXT2_BLOCKS_PER_GROUP(sb), map);
}

+static int test_root(int a, int b)
+{
+ if (a == 0)
+ return 1;
+ while (1) {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+}
+
+int ext2_group_sparse(int group)
+{
+ return (test_root(group, 3) || test_root(group, 5) ||
+ test_root(group, 7));
+}
+
void ext2_check_blocks_bitmap (struct super_block * sb)
{
struct buffer_head * bh;
@@ -671,16 +690,22 @@

bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];

- if (!test_bit (0, bh->b_data))
- ext2_error (sb, "ext2_check_blocks_bitmap",
- "Superblock in group %d is marked free", i);
-
- for (j = 0; j < desc_blocks; j++)
- if (!test_bit (j + 1, bh->b_data))
+ if (!(sb->u.ext2_sb.s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+ ext2_group_sparse(i)) {
+ if (!test_bit (0, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Superblock in group %d "
+ "is marked free", i);
+
+ for (j = 0; j < desc_blocks; j++)
+ if (!test_bit (j + 1, bh->b_data))
+ ext2_error (sb,
+ "ext2_check_blocks_bitmap",
"Descriptor block #%d in group "
"%d is marked free", j, i);
-
+ }
+
if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
"Block bitmap for group %d is marked free",
===================================================================
RCS file: fs/ext2/RCS/dir.c,v
retrieving revision 1.1
diff -u -r1.1 fs/ext2/dir.c
--- fs/ext2/dir.c 1999/10/20 18:51:43 1.1
+++ fs/ext2/dir.c 1999/10/20 18:54:45
@@ -72,7 +72,7 @@
};

int ext2_check_dir_entry (const char * function, struct inode * dir,
- struct ext2_dir_entry * de, struct buffer_head * bh,
+ struct ext2_dir_entry_2 * de, struct buffer_head * bh,
unsigned long offset)
{
const char * error_msg = NULL;
@@ -104,7 +104,7 @@
unsigned long offset, blk;
int i, num, stored;
struct buffer_head * bh, * tmp, * bha[16];
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct super_block * sb;
int err;

@@ -173,7 +173,7 @@

while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
- de = (struct ext2_dir_entry *) (bh->b_data + offset);
+ de = (struct ext2_dir_entry_2 *) (bh->b_data + offset);
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
bh, offset)) {
/* On error, skip the f_pos to the
===================================================================
RCS file: fs/ext2/RCS/namei.c,v
retrieving revision 1.1
diff -u -r1.1 fs/ext2/namei.c
--- fs/ext2/namei.c 1999/10/20 18:51:43 1.1
+++ fs/ext2/namei.c 1999/10/20 20:14:43
@@ -36,7 +36,7 @@
* NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
*/
static int ext2_match (int len, const char * const name,
- struct ext2_dir_entry * de)
+ struct ext2_dir_entry_2 * de)
{
if (!de || !de->inode || len > EXT2_NAME_LEN)
return 0;
@@ -61,7 +61,7 @@
*/
static struct buffer_head * ext2_find_entry (struct inode * dir,
const char * const name, int namelen,
- struct ext2_dir_entry ** res_dir)
+ struct ext2_dir_entry_2 ** res_dir)
{
struct super_block * sb;
struct buffer_head * bh_use[NAMEI_RA_SIZE];
@@ -92,7 +92,7 @@

for (block = 0, offset = 0; offset < dir->i_size; block++) {
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
char * dlimit;

if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
@@ -115,7 +115,7 @@
break;
}

- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
dlimit = bh->b_data + sb->s_blocksize;
while ((char *) de < dlimit) {
if (!ext2_check_dir_entry ("ext2_find_entry", dir,
@@ -130,7 +130,7 @@
return bh;
}
offset += de->rec_len;
- de = (struct ext2_dir_entry *)
+ de = (struct ext2_dir_entry_2 *)
((char *) de + de->rec_len);
}

@@ -155,7 +155,7 @@
struct inode ** result)
{
unsigned long ino;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct buffer_head * bh;

*result = NULL;
@@ -211,13 +211,13 @@
*/
static struct buffer_head * ext2_add_entry (struct inode * dir,
const char * name, int namelen,
- struct ext2_dir_entry ** res_dir,
+ struct ext2_dir_entry_2 ** res_dir,
int *err)
{
unsigned long offset;
unsigned short rec_len;
struct buffer_head * bh;
- struct ext2_dir_entry * de, * de1;
+ struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;

*err = -EINVAL;
@@ -247,7 +247,7 @@
return NULL;
rec_len = EXT2_DIR_REC_LEN(namelen);
offset = 0;
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
*err = -ENOSPC;
while (1) {
if ((char *)de >= sb->s_blocksize + bh->b_data) {
@@ -264,7 +264,7 @@

ext2_debug ("creating next block\n");

- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
de->inode = 0;
de->rec_len = sb->s_blocksize;
dir->i_size = offset + sb->s_blocksize;
@@ -273,7 +273,7 @@

ext2_debug ("skipping to next block\n");

- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
}
}
if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
@@ -291,7 +291,7 @@
(de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
offset += de->rec_len;
if (de->inode) {
- de1 = (struct ext2_dir_entry *) ((char *) de +
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de +
EXT2_DIR_REC_LEN(de->name_len));
de1->rec_len = de->rec_len -
EXT2_DIR_REC_LEN(de->name_len);
@@ -300,6 +300,7 @@
}
de->inode = 0;
de->name_len = namelen;
+ de->file_type = 0;
memcpy (de->name, name, namelen);
/*
* XXX shouldn't update any times until successful
@@ -321,7 +322,7 @@
return bh;
}
offset += de->rec_len;
- de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + de->rec_len);
}
brelse (bh);
return NULL;
@@ -331,15 +332,15 @@
* ext2_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
-static int ext2_delete_entry (struct ext2_dir_entry * dir,
+static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
struct buffer_head * bh)
{
- struct ext2_dir_entry * de, * pde;
+ struct ext2_dir_entry_2 * de, * pde;
int i;

i = 0;
pde = NULL;
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
while (i < bh->b_size) {
if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
de, bh, i))
@@ -352,7 +353,7 @@
}
i += de->rec_len;
pde = de;
- de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + de->rec_len);
}
return -ENOENT;
}
@@ -362,7 +363,7 @@
{
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
int err;

*result = NULL;
@@ -385,6 +386,9 @@
return err;
}
de->inode = inode->i_ino;
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_REG_FILE;
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
@@ -403,7 +407,7 @@
{
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
int err;

if (!dir)
@@ -427,21 +431,27 @@
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
- else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &ext2_dir_inode_operations;
- if (dir->i_mode & S_ISGID)
- inode->i_mode |= S_ISGID;
- }
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &ext2_symlink_inode_operations;
- else if (S_ISCHR(inode->i_mode))
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_REG_FILE;
+ } else if (S_ISCHR(inode->i_mode)) {
inode->i_op = &chrdev_inode_operations;
- else if (S_ISBLK(inode->i_mode))
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_CHRDEV;
+ } else if (S_ISBLK(inode->i_mode)) {
inode->i_op = &blkdev_inode_operations;
- else if (S_ISFIFO(inode->i_mode))
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_BLKDEV;
+ } else if (S_ISFIFO(inode->i_mode)) {
init_fifo(inode);
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_FIFO;
+ }
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
inode->i_dirt = 1;
@@ -471,7 +481,7 @@
{
struct inode * inode;
struct buffer_head * bh, * dir_block;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
int err;

if (!dir)
@@ -506,16 +516,22 @@
return err;
}
inode->i_blocks = inode->i_sb->s_blocksize / 512;
- de = (struct ext2_dir_entry *) dir_block->b_data;
+ de = (struct ext2_dir_entry_2 *) dir_block->b_data;
de->inode = inode->i_ino;
de->name_len = 1;
de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
strcpy (de->name, ".");
- de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
+ de = (struct ext2_dir_entry_2 *) ((char *) de + de->rec_len);
de->inode = dir->i_ino;
de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1);
de->name_len = 2;
strcpy (de->name, "..");
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
inode->i_nlink = 2;
mark_buffer_dirty(dir_block, 1);
brelse (dir_block);
@@ -532,6 +548,9 @@
return err;
}
de->inode = inode->i_ino;
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
@@ -554,7 +573,7 @@
{
unsigned long offset;
struct buffer_head * bh;
- struct ext2_dir_entry * de, * de1;
+ struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
int err;

@@ -566,8 +585,8 @@
inode->i_ino);
return 1;
}
- de = (struct ext2_dir_entry *) bh->b_data;
- de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de + de->rec_len);
if (de->inode != inode->i_ino || !de1->inode ||
strcmp (".", de->name) || strcmp ("..", de1->name)) {
ext2_warning (inode->i_sb, "empty_dir",
@@ -577,7 +596,7 @@
return 1;
}
offset = de->rec_len + de1->rec_len;
- de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de1 + de1->rec_len);
while (offset < inode->i_size ) {
if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
brelse (bh);
@@ -589,7 +608,7 @@
offset += sb->s_blocksize;
continue;
}
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
}
if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
offset)) {
@@ -601,7 +620,7 @@
return 0;
}
offset += de->rec_len;
- de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + de->rec_len);
}
brelse (bh);
return 1;
@@ -612,7 +631,7 @@
int retval;
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;

repeat:
if (!dir)
@@ -701,7 +720,7 @@
int retval;
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;

repeat:
if (!dir)
@@ -766,7 +785,7 @@
int ext2_symlink (struct inode * dir, const char * name, int len,
const char * symname)
{
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct inode * inode = NULL;
struct buffer_head * bh = NULL, * name_block = NULL;
char * link;
@@ -831,6 +850,9 @@
return err;
}
de->inode = inode->i_ino;
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_SYMLINK;
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
@@ -847,7 +869,7 @@
int ext2_link (struct inode * oldinode, struct inode * dir,
const char * name, int len)
{
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct buffer_head * bh;
int err;

@@ -880,6 +902,21 @@
return err;
}
de->inode = oldinode->i_ino;
+ if (EXT2_HAS_INCOMPAT_FEATURE(oldinode->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+ if (S_ISREG(oldinode->i_mode))
+ de->file_type = EXT2_FT_REG_FILE;
+ else if (S_ISDIR(oldinode->i_mode))
+ de->file_type = EXT2_FT_DIR;
+ else if (S_ISLNK(oldinode->i_mode))
+ de->file_type = EXT2_FT_SYMLINK;
+ else if (S_ISCHR(oldinode->i_mode))
+ de->file_type = EXT2_FT_CHRDEV;
+ else if (S_ISBLK(oldinode->i_mode))
+ de->file_type = EXT2_FT_BLKDEV;
+ else if (S_ISFIFO(oldinode->i_mode))
+ de->file_type = EXT2_FT_FIFO;
+ }
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
@@ -921,12 +958,12 @@
}

#define PARENT_INO(buffer) \
- ((struct ext2_dir_entry *) ((char *) buffer + \
- ((struct ext2_dir_entry *) buffer)->rec_len))->inode
+ ((struct ext2_dir_entry_2 *) ((char *) buffer + \
+ ((struct ext2_dir_entry_2 *) buffer)->rec_len))->inode

#define PARENT_NAME(buffer) \
- ((struct ext2_dir_entry *) ((char *) buffer + \
- ((struct ext2_dir_entry *) buffer)->rec_len))->name
+ ((struct ext2_dir_entry_2 *) ((char *) buffer + \
+ ((struct ext2_dir_entry_2 *) buffer)->rec_len))->name

/*
* rename uses retrying to avoid race-conditions: at least they should be
@@ -946,7 +983,7 @@
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
- struct ext2_dir_entry * old_de, * new_de;
+ struct ext2_dir_entry_2 * old_de, * new_de;
int retval;

goto start_up;
@@ -1060,6 +1097,9 @@
* ok, that's it
*/
new_de->inode = old_inode->i_ino;
+ if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ new_de->file_type = old_de->file_type;
dcache_add(new_dir, new_de->name, new_de->name_len, new_de->inode);
retval = ext2_delete_entry (old_de, old_bh);
if (retval == -ENOENT)
===================================================================
RCS file: include/linux/RCS/ext2_fs.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/ext2_fs.h
--- include/linux/ext2_fs.h 1999/10/15 12:06:06 1.1
+++ include/linux/ext2_fs.h 1999/10/20 20:09:57
@@ -368,6 +368,15 @@
__u32 s_reserved[230]; /* Padding to the end of the block */
};

+#ifdef __KERNEL__
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+#endif
+
/*
* Codes for operating systems
*/
@@ -407,6 +416,35 @@
};

/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
@@ -417,11 +455,23 @@
~EXT2_DIR_ROUND)

/*
- * Feature set definitions --- none are defined as of now
+ * Feature set definitions
*/
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+
#define EXT2_FEATURE_COMPAT_SUPP 0
-#define EXT2_FEATURE_INCOMPAT_SUPP 0
-#define EXT2_FEATURE_RO_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
+#define EXT2_FEATURE_RO_COMPAT_SUPP EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER

#ifdef __KERNEL__
/*
@@ -440,6 +490,7 @@
extern int ext2_permission (struct inode *, int);

/* balloc.c */
+extern int ext2_group_sparse(int group);
extern int ext2_new_block (const struct inode *, unsigned long,
__u32 *, __u32 *, int *);
extern void ext2_free_blocks (const struct inode *, unsigned long,
@@ -452,7 +503,7 @@

/* dir.c */
extern int ext2_check_dir_entry (const char *, struct inode *,
- struct ext2_dir_entry *, struct buffer_head *,
+ struct ext2_dir_entry_2 *, struct buffer_head *,
unsigned long);

/* file.c */
===================================================================
RCS file: include/linux/RCS/ext2_fs_sb.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/ext2_fs_sb.h
--- include/linux/ext2_fs_sb.h 1999/10/15 14:12:51 1.1
+++ include/linux/ext2_fs_sb.h 1999/10/20 20:14:47
@@ -60,6 +60,9 @@
int s_desc_per_block_bits;
int s_inode_size;
int s_first_ino;
+ int s_feature_compat;
+ int s_feature_incompat;
+ int s_feature_ro_compat;
};

#endif /* _LINUX_EXT2_FS_SB */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:55    [from the cache]
©2003-2011 Jasper Spaans