# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1016 -> 1.1017 # include/linux/ext3_fs.h 1.10 -> 1.11 # fs/ext2/inode.c 1.19 -> 1.20 # fs/ext3/Makefile 1.3 -> 1.4 # include/linux/ext2_fs.h 1.10 -> 1.11 # fs/ext2/Makefile 1.2 -> 1.3 # Documentation/filesystems/ext2.txt 1.3 -> 1.4 # fs/ext3/namei.c 1.5 -> 1.6 # fs/ext2/super.c 1.13 -> 1.14 # fs/ext3/inode.c 1.17 -> 1.18 # fs/ext2/namei.c 1.3 -> 1.4 # fs/ext3/super.c 1.13 -> 1.14 # (new) -> 1.1 fs/ext2/iopen.c # (new) -> 1.1 fs/ext3/iopen.c # (new) -> 1.1 fs/ext2/iopen.h # (new) -> 1.1 fs/ext3/iopen.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/03/12 tytso@think.thunk.org 1.1017 # Open by inode support for ext2 and ext3 filesystems. # -------------------------------------------- # diff -Nru a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt --- a/Documentation/filesystems/ext2.txt Thu Mar 13 00:37:24 2003 +++ b/Documentation/filesystems/ext2.txt Thu Mar 13 00:37:24 2003 @@ -35,6 +35,22 @@ sb=n Use alternate superblock at this location. +iopen Makes an invisible pseudo-directory called + __iopen__ available in the root directory + of the filesystem. Allows open-by-inode- + number. i.e., inode 3145 can be accessed + via /mntpt/__iopen__/3145 + +iopen_nopriv This option makes the iopen directory be + world-readable. This may be safer since it + allows daemons to run as an unprivileged user, + however it significantly changes the security + model of a Unix filesystem, since previously + all files under a mode 700 directory were not + generally avilable even if the + permissions on the file itself is + world-readable. + grpquota,noquota,quota,usrquota Quota options are silently ignored by ext2. diff -Nru a/fs/ext2/Makefile b/fs/ext2/Makefile --- a/fs/ext2/Makefile Thu Mar 13 00:37:24 2003 +++ b/fs/ext2/Makefile Thu Mar 13 00:37:24 2003 @@ -10,7 +10,7 @@ O_TARGET := ext2.o obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o + ioctl.o namei.o super.o symlink.o iopen.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c --- a/fs/ext2/inode.c Thu Mar 13 00:37:24 2003 +++ b/fs/ext2/inode.c Thu Mar 13 00:37:24 2003 @@ -30,6 +30,7 @@ #include #include #include +#include "iopen.h" MODULE_AUTHOR("Remy Card and others"); MODULE_DESCRIPTION("Second Extended Filesystem"); @@ -914,6 +915,9 @@ unsigned long offset; struct ext2_group_desc * gdp; + if (ext2_iopen_get_inode(inode)) + return; + if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO && inode->i_ino != EXT2_ACL_DATA_INO && inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) || diff -Nru a/fs/ext2/iopen.c b/fs/ext2/iopen.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/iopen.c Thu Mar 13 00:37:25 2003 @@ -0,0 +1,139 @@ +/* + * linux/fs/ext2/iopen.c + * + * Special support for open by inode number + * + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu). + * + * This file may be redistributed under the terms of the GNU General + * Public License. + */ + +#include +#include +#include +#include +#include +#include "iopen.h" + +#define IOPEN_NAME_LEN 32 + +/* + * This implements looking up an inode by number. + */ +static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + unsigned long ino; + char buf[IOPEN_NAME_LEN]; + + if (dentry->d_name.len >= IOPEN_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + memcpy(buf, dentry->d_name.name, dentry->d_name.len); + buf[dentry->d_name.len] = 0; + + if (strcmp(buf, ".") == 0) + ino = dir->i_ino; + else if (strcmp(buf, "..") == 0) + ino = EXT2_ROOT_INO; + else + ino = simple_strtoul(buf, 0, 0); + + if ((ino != EXT2_ROOT_INO && + ino != EXT2_ACL_IDX_INO && + ino != EXT2_ACL_DATA_INO && + ino < EXT2_FIRST_INO(dir->i_sb)) || + ino > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count)) + return ERR_PTR(-ENOENT); + + inode = iget(dir->i_sb, ino); + if (!inode) + return ERR_PTR(-EACCES); + if (is_bad_inode(inode)) { + iput(inode); + return ERR_PTR(-ENOENT); + } + d_add(dentry, inode); + return NULL; +} + +/* + * These are the special structures for the iopen pseudo directory. + */ + +static struct inode_operations iopen_inode_operations = { + lookup: iopen_lookup, /* BKL held */ +}; + +static struct file_operations iopen_file_operations = { + read: generic_read_dir, +}; + +static int match_dentry(struct dentry *dentry, const char *name) +{ + int len; + + len = strlen(name); + if (dentry->d_name.len != len) + return 0; + if (strncmp(dentry->d_name.name, name, len)) + return 0; + return 1; +} + +/* + * This function is spliced into ext2_lookup and returns 1 the file + * name is __iopen__ and dentry has been filled in appropriately. + */ +int ext2_check_for_iopen(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + + if (dir->i_ino != EXT2_ROOT_INO || + !test_opt(dir->i_sb, IOPEN) || + !match_dentry(dentry, "__iopen__")) + return 0; + + inode = iget(dir->i_sb, EXT2_BAD_INO); + + if (!inode) + return 0; + d_add(dentry, inode); + return 1; +} + +/* + * This function is spliced into read_inode; it returns 1 if inode + * number is the one for /__iopen__, in which case the inode is filled + * in appropriately. Otherwise, this fuction returns 0. + */ +int ext2_iopen_get_inode(struct inode * inode) +{ + if (inode->i_ino != EXT2_BAD_INO) + return 0; + + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + if (test_opt(inode->i_sb, IOPEN_NOPRIV)) + inode->i_mode |= 0777; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_nlink = 1; + inode->i_size = 4096; + inode->i_atime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + inode->i_mtime = CURRENT_TIME; + inode->u.ext2_i.i_dtime = 0; + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size + * (for stat), not the fs block + * size */ + inode->i_blocks = 0; + inode->i_version = 1; + inode->i_generation = 0; + + inode->i_op = &iopen_inode_operations; + inode->i_fop = &iopen_file_operations; + inode->i_mapping->a_ops = 0; + + return 1; +} diff -Nru a/fs/ext2/iopen.h b/fs/ext2/iopen.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/iopen.h Thu Mar 13 00:37:25 2003 @@ -0,0 +1,15 @@ +/* + * iopen.h + * + * Special support for opening files by inode number. + * + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu). + * + * This file may be redistributed under the terms of the GNU General + * Public License. + */ + +extern int ext2_check_for_iopen(struct inode * dir, struct dentry *dentry); +extern int ext2_iopen_get_inode(struct inode * inode); + + diff -Nru a/fs/ext2/namei.c b/fs/ext2/namei.c --- a/fs/ext2/namei.c Thu Mar 13 00:37:24 2003 +++ b/fs/ext2/namei.c Thu Mar 13 00:37:24 2003 @@ -32,6 +32,7 @@ #include #include #include +#include "iopen.h" /* * Couple of helper functions - make the code slightly cleaner. @@ -72,6 +73,9 @@ if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); + + if (ext2_check_for_iopen(dir, dentry)) + return NULL; ino = ext2_inode_by_name(dir, dentry); inode = NULL; diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c --- a/fs/ext2/super.c Thu Mar 13 00:37:24 2003 +++ b/fs/ext2/super.c Thu Mar 13 00:37:24 2003 @@ -297,6 +297,17 @@ || !strcmp (this_char, "quota") || !strcmp (this_char, "usrquota")) /* Don't do anything ;-) */ ; + else if (!strcmp (this_char, "iopen")) { + set_opt (sbi->s_mount_opt, IOPEN); + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + } else if (!strcmp (this_char, "noiopen")) { + clear_opt (sbi->s_mount_opt, IOPEN); + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + } + else if (!strcmp (this_char, "iopen_nopriv")) { + set_opt (sbi->s_mount_opt, IOPEN); + set_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + } else { printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); return 0; diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile --- a/fs/ext3/Makefile Thu Mar 13 00:37:24 2003 +++ b/fs/ext3/Makefile Thu Mar 13 00:37:24 2003 @@ -10,7 +10,7 @@ O_TARGET := ext3.o obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o + ioctl.o namei.o super.o symlink.o hash.o iopen.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Thu Mar 13 00:37:24 2003 +++ b/fs/ext3/inode.c Thu Mar 13 00:37:24 2003 @@ -31,6 +31,7 @@ #include #include #include +#include "iopen.h" /* The ext3 forget function must perform a revoke if we are freeing data * which has been journaled. Metadata (eg. indirect blocks) must be @@ -2083,6 +2084,9 @@ struct ext3_inode *raw_inode; struct buffer_head *bh; int block; + + if (ext3_iopen_get_inode(inode)) + return; if(ext3_get_inode_loc(inode, &iloc)) goto bad_inode; diff -Nru a/fs/ext3/iopen.c b/fs/ext3/iopen.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/iopen.c Thu Mar 13 00:37:25 2003 @@ -0,0 +1,141 @@ +/* + * linux/fs/ext3/iopen.c + * + * Special support for open by inode number + * + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu). + * + * This file may be redistributed under the terms of the GNU General + * Public License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "iopen.h" + +#define IOPEN_NAME_LEN 32 + +/* + * This implements looking up an inode by number. + */ +static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + unsigned long ino; + char buf[IOPEN_NAME_LEN]; + + if (dentry->d_name.len >= IOPEN_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + memcpy(buf, dentry->d_name.name, dentry->d_name.len); + buf[dentry->d_name.len] = 0; + + if (strcmp(buf, ".") == 0) + ino = dir->i_ino; + else if (strcmp(buf, "..") == 0) + ino = EXT3_ROOT_INO; + else + ino = simple_strtoul(buf, 0, 0); + + if ((ino != EXT3_ROOT_INO && + ino != EXT3_ACL_IDX_INO && + ino != EXT3_ACL_DATA_INO && + ino < EXT3_FIRST_INO(dir->i_sb)) || + ino > le32_to_cpu(dir->i_sb->u.ext3_sb.s_es->s_inodes_count)) + return ERR_PTR(-ENOENT); + + inode = iget(dir->i_sb, ino); + if (!inode) + return ERR_PTR(-EACCES); + if (is_bad_inode(inode)) { + iput(inode); + return ERR_PTR(-ENOENT); + } + d_add(dentry, inode); + return NULL; +} + +/* + * These are the special structures for the iopen pseudo directory. + */ + +static struct inode_operations iopen_inode_operations = { + lookup: iopen_lookup, /* BKL held */ +}; + +static struct file_operations iopen_file_operations = { + read: generic_read_dir, +}; + +static int match_dentry(struct dentry *dentry, const char *name) +{ + int len; + + len = strlen(name); + if (dentry->d_name.len != len) + return 0; + if (strncmp(dentry->d_name.name, name, len)) + return 0; + return 1; +} + +/* + * This function is spliced into ext3_lookup and returns 1 the file + * name is __iopen__ and dentry has been filled in appropriately. + */ +int ext3_check_for_iopen(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + + if (dir->i_ino != EXT3_ROOT_INO || + !test_opt(dir->i_sb, IOPEN) || + !match_dentry(dentry, "__iopen__")) + return 0; + + inode = iget(dir->i_sb, EXT3_BAD_INO); + + if (!inode) + return 0; + d_add(dentry, inode); + return 1; +} + +/* + * This function is spliced into read_inode; it returns 1 if inode + * number is the one for /__iopen__, in which case the inode is filled + * in appropriately. Otherwise, this fuction returns 0. + */ +int ext3_iopen_get_inode(struct inode * inode) +{ + if (inode->i_ino != EXT3_BAD_INO) + return 0; + + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + if (test_opt(inode->i_sb, IOPEN_NOPRIV)) + inode->i_mode |= 0777; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_nlink = 1; + inode->i_size = 4096; + inode->i_atime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + inode->i_mtime = CURRENT_TIME; + inode->u.ext3_i.i_dtime = 0; + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size + * (for stat), not the fs block + * size */ + inode->i_blocks = 0; + inode->i_version = 1; + inode->i_generation = 0; + + inode->i_op = &iopen_inode_operations; + inode->i_fop = &iopen_file_operations; + inode->i_mapping->a_ops = 0; + + return 1; +} diff -Nru a/fs/ext3/iopen.h b/fs/ext3/iopen.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/iopen.h Thu Mar 13 00:37:25 2003 @@ -0,0 +1,15 @@ +/* + * iopen.h + * + * Special support for opening files by inode number. + * + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu). + * + * This file may be redistributed under the terms of the GNU General + * Public License. + */ + +extern int ext3_check_for_iopen(struct inode * dir, struct dentry *dentry); +extern int ext3_iopen_get_inode(struct inode * inode); + + diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c --- a/fs/ext3/namei.c Thu Mar 13 00:37:24 2003 +++ b/fs/ext3/namei.c Thu Mar 13 00:37:24 2003 @@ -34,7 +34,7 @@ #include #include #include - +#include "iopen.h" /* * define how far ahead to read directories while searching them. @@ -977,6 +977,9 @@ if (dentry->d_name.len > EXT3_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); + + if (ext3_check_for_iopen(dir, dentry)) + return NULL; bh = ext3_find_entry(dentry, &de); inode = NULL; diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c --- a/fs/ext3/super.c Thu Mar 13 00:37:25 2003 +++ b/fs/ext3/super.c Thu Mar 13 00:37:25 2003 @@ -586,6 +586,17 @@ || !strcmp (this_char, "quota") || !strcmp (this_char, "usrquota")) /* Don't do anything ;-) */ ; + else if (!strcmp (this_char, "iopen")) { + set_opt (sbi->s_mount_opt, IOPEN); + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + } else if (!strcmp (this_char, "noiopen")) { + clear_opt (sbi->s_mount_opt, IOPEN); + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + } + else if (!strcmp (this_char, "iopen_nopriv")) { + set_opt (sbi->s_mount_opt, IOPEN); + set_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + } else if (!strcmp (this_char, "journal")) { /* @@@ FIXME */ /* Eventually we will want to be able to create diff -Nru a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h --- a/include/linux/ext2_fs.h Thu Mar 13 00:37:24 2003 +++ b/include/linux/ext2_fs.h Thu Mar 13 00:37:24 2003 @@ -316,6 +316,8 @@ #define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ #define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ #define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ +#define EXT2_MOUNT_IOPEN 0x0400 /* Allow access via iopen */ +#define EXT2_MOUNT_IOPEN_NOPRIV 0x1000 /* Make iopen world-readable */ #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt #define set_opt(o, opt) o |= EXT2_MOUNT_##opt diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h --- a/include/linux/ext3_fs.h Thu Mar 13 00:37:24 2003 +++ b/include/linux/ext3_fs.h Thu Mar 13 00:37:24 2003 @@ -346,6 +346,8 @@ #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ #define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ #define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ +#define EXT3_MOUNT_IOPEN 0x4000 /* Allow access via iopen */ +#define EXT3_MOUNT_IOPEN_NOPRIV 0x8000 /* Make iopen world-readable */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H