Signed-off-by: Ludwig Nussel <ludwig.nussel@xxxxxxx> --- Documentation/filesystems/ext2.txt | 9 ++++++ fs/ext2/ext2.h | 8 +++++ fs/ext2/inode.c | 42 ++++++++++++++++++++------ fs/ext2/super.c | 57 +++++++++++++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 11 deletions(-) diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index 67639f9..fcc1002 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -42,6 +42,15 @@ orlov (*) Use the Orlov block allocator. resuid=n The user ID which may use the reserved blocks. resgid=n The group ID which may use the reserved blocks. +uid=n[:m] Make all files appear to belong to uid n. + Useful for e.g. removable media with fstab + options 'user,uid=useruid'. The optional second + uid m is actually written to the file system. + +gid=n[:m] Make all files appear to belong to gid n. + The optional second gid m is actually written to + the file system. + sb=n Use alternate superblock at this location. user_xattr Enable "user." POSIX Extended Attributes diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 0b2b4db..b584e45 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -84,6 +84,10 @@ struct ext2_sb_info { unsigned long s_sb_block; uid_t s_resuid; gid_t s_resgid; + uid_t s_uid; /* make all files appear to belong to this uid */ + uid_t s_diskuid; /* write this uid to disk (if s_uid != 0) */ + gid_t s_gid; /* make all files appear to belong to this gid */ + gid_t s_diskgid; /* write this gid to disk (if s_gid != 0) */ unsigned short s_mount_state; unsigned short s_pad; int s_addr_per_block_bits; @@ -639,6 +643,10 @@ struct ext2_mount_options { unsigned long s_mount_opt; uid_t s_resuid; gid_t s_resgid; + uid_t s_uid; + uid_t s_diskuid; + gid_t s_gid; + gid_t s_diskgid; }; /* diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 740cad8..aabcb38 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1316,6 +1316,10 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; } + if (EXT2_SB(sb)->s_uid) + inode->i_uid = EXT2_SB(sb)->s_uid; + if (EXT2_SB(sb)->s_gid) + inode->i_gid = EXT2_SB(sb)->s_gid; set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); inode->i_size = le32_to_cpu(raw_inode->i_size); inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); @@ -1419,6 +1423,10 @@ static int __ext2_write_inode(struct inode *inode, int do_sync) struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); int n; int err = 0; + __le16 uid_low; + __le16 gid_low; + __le16 uid_high; + __le16 gid_high; if (IS_ERR(raw_inode)) return -EIO; @@ -1430,26 +1438,40 @@ static int __ext2_write_inode(struct inode *inode, int do_sync) ext2_get_inode_flags(ei); raw_inode->i_mode = cpu_to_le16(inode->i_mode); + if (EXT2_SB(sb)->s_uid) + uid = EXT2_SB(sb)->s_diskuid; + if (EXT2_SB(sb)->s_gid) + gid = EXT2_SB(sb)->s_diskgid; if (!(test_opt(sb, NO_UID32))) { - raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); - raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid)); + uid_low = cpu_to_le16(low_16_bits(uid)); + gid_low = cpu_to_le16(low_16_bits(gid)); /* * Fix up interoperability with old kernels. Otherwise, old inodes get * re-used with the upper 16 bits of the uid/gid intact */ if (!ei->i_dtime) { - raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid)); - raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid)); + uid_high = cpu_to_le16(high_16_bits(uid)); + gid_high = cpu_to_le16(high_16_bits(gid)); } else { - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; + uid_high = 0; + gid_high = 0; } } else { - raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(uid)); - raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(gid)); - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; + uid_low = cpu_to_le16(fs_high2lowuid(uid)); + gid_low = cpu_to_le16(fs_high2lowgid(gid)); + uid_high = 0; + gid_high = 0; } + /* don't mangle uid/gid of existing files if override is active */ + if (!EXT2_SB(sb)->s_uid || ei->i_state & EXT2_STATE_NEW) { + raw_inode->i_uid_high = uid_high; + raw_inode->i_uid_low = uid_low; + } + if (!EXT2_SB(sb)->s_gid || ei->i_state & EXT2_STATE_NEW) { + raw_inode->i_gid_high = gid_high; + raw_inode->i_gid_low = gid_low; + } + raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); raw_inode->i_size = cpu_to_le32(inode->i_size); raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index e1025c7..0661574 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -236,6 +236,20 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root) le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { seq_printf(seq, ",resgid=%u", sbi->s_resgid); } + if (sbi->s_uid) { + if (sbi->s_uid != sbi->s_diskuid) + seq_printf(seq, ",uid=%u:%u", + sbi->s_uid, sbi->s_diskuid); + else + seq_printf(seq, ",uid=%u", sbi->s_uid); + } + if (sbi->s_gid) { + if (sbi->s_gid != sbi->s_diskgid) + seq_printf(seq, ",gid=%u:%u", + sbi->s_gid, sbi->s_diskgid); + else + seq_printf(seq, ",gid=%u", sbi->s_gid); + } if (test_opt(sb, ERRORS_RO)) { int def_errors = le16_to_cpu(es->s_errors); @@ -393,7 +407,8 @@ enum { Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation + Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation, + Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid }; static const match_table_t tokens = { @@ -427,6 +442,10 @@ static const match_table_t tokens = { {Opt_usrquota, "usrquota"}, {Opt_reservation, "reservation"}, {Opt_noreservation, "noreservation"}, + {Opt_uid, "uid=%u"}, + {Opt_diskuid, "uid=%u:%u"}, + {Opt_gid, "gid=%u"}, + {Opt_diskgid, "gid=%u:%u"}, {Opt_err, NULL} }; @@ -568,6 +587,34 @@ static int parse_options(char *options, struct super_block *sb) clear_opt(sbi->s_mount_opt, RESERVATION); ext2_msg(sb, KERN_INFO, "reservations OFF"); break; + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; + sbi->s_uid = sbi->s_diskuid = option; + break; + case Opt_diskuid: + if (match_int(&args[0], &option)) + return 0; + sbi->s_uid = option; + + if (match_int(&args[1], &option)) + return 0; + sbi->s_diskuid = option; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; + sbi->s_gid = sbi->s_diskgid = option; + break; + case Opt_diskgid: + if (match_int(&args[0], &option)) + return 0; + sbi->s_gid = option; + + if (match_int(&args[1], &option)) + return 0; + sbi->s_diskgid = option; + break; case Opt_ignore: break; default: @@ -1214,6 +1261,10 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) old_opts.s_mount_opt = sbi->s_mount_opt; old_opts.s_resuid = sbi->s_resuid; old_opts.s_resgid = sbi->s_resgid; + old_opts.s_uid = sbi->s_uid; + old_opts.s_diskuid = sbi->s_diskuid; + old_opts.s_gid = sbi->s_gid; + old_opts.s_diskgid = sbi->s_diskgid; /* * Allow the "check" option to be passed as a remount option. @@ -1300,6 +1351,10 @@ restore_opts: sbi->s_mount_opt = old_opts.s_mount_opt; sbi->s_resuid = old_opts.s_resuid; sbi->s_resgid = old_opts.s_resgid; + sbi->s_uid = old_opts.s_uid; + sbi->s_diskuid = old_opts.s_diskuid; + sbi->s_gid = old_opts.s_gid; + sbi->s_diskgid = old_opts.s_diskgid; sb->s_flags = old_sb_flags; spin_unlock(&sbi->s_lock); return err; -- 1.7.7 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html