diff options
Diffstat (limited to 'fs/hfsplus/ioctl.c')
| -rw-r--r-- | fs/hfsplus/ioctl.c | 153 |
1 files changed, 84 insertions, 69 deletions
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index ac405f099026..5b4667e08ef7 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
| @@ -17,83 +17,98 @@ | |||
| 17 | #include <linux/mount.h> | 17 | #include <linux/mount.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/xattr.h> | 19 | #include <linux/xattr.h> |
| 20 | #include <linux/smp_lock.h> | ||
| 21 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
| 22 | #include "hfsplus_fs.h" | 21 | #include "hfsplus_fs.h" |
| 23 | 22 | ||
| 24 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 23 | static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags) |
| 25 | { | 24 | { |
| 26 | struct inode *inode = filp->f_path.dentry->d_inode; | 25 | struct inode *inode = file->f_path.dentry->d_inode; |
| 26 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | ||
| 27 | unsigned int flags = 0; | ||
| 28 | |||
| 29 | if (inode->i_flags & S_IMMUTABLE) | ||
| 30 | flags |= FS_IMMUTABLE_FL; | ||
| 31 | if (inode->i_flags |= S_APPEND) | ||
| 32 | flags |= FS_APPEND_FL; | ||
| 33 | if (hip->userflags & HFSPLUS_FLG_NODUMP) | ||
| 34 | flags |= FS_NODUMP_FL; | ||
| 35 | |||
| 36 | return put_user(flags, user_flags); | ||
| 37 | } | ||
| 38 | |||
| 39 | static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags) | ||
| 40 | { | ||
| 41 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 42 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | ||
| 27 | unsigned int flags; | 43 | unsigned int flags; |
| 44 | int err = 0; | ||
| 28 | 45 | ||
| 29 | lock_kernel(); | 46 | err = mnt_want_write(file->f_path.mnt); |
| 30 | switch (cmd) { | 47 | if (err) |
| 31 | case HFSPLUS_IOC_EXT2_GETFLAGS: | 48 | goto out; |
| 32 | flags = 0; | ||
| 33 | if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE) | ||
| 34 | flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */ | ||
| 35 | if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND) | ||
| 36 | flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */ | ||
| 37 | if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP) | ||
| 38 | flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */ | ||
| 39 | return put_user(flags, (int __user *)arg); | ||
| 40 | case HFSPLUS_IOC_EXT2_SETFLAGS: { | ||
| 41 | int err = 0; | ||
| 42 | err = mnt_want_write(filp->f_path.mnt); | ||
| 43 | if (err) { | ||
| 44 | unlock_kernel(); | ||
| 45 | return err; | ||
| 46 | } | ||
| 47 | 49 | ||
| 48 | if (!is_owner_or_cap(inode)) { | 50 | if (!is_owner_or_cap(inode)) { |
| 49 | err = -EACCES; | 51 | err = -EACCES; |
| 50 | goto setflags_out; | 52 | goto out_drop_write; |
| 51 | } | 53 | } |
| 52 | if (get_user(flags, (int __user *)arg)) { | ||
| 53 | err = -EFAULT; | ||
| 54 | goto setflags_out; | ||
| 55 | } | ||
| 56 | if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) || | ||
| 57 | HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) { | ||
| 58 | if (!capable(CAP_LINUX_IMMUTABLE)) { | ||
| 59 | err = -EPERM; | ||
| 60 | goto setflags_out; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | 54 | ||
| 64 | /* don't silently ignore unsupported ext2 flags */ | 55 | if (get_user(flags, user_flags)) { |
| 65 | if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) { | 56 | err = -EFAULT; |
| 66 | err = -EOPNOTSUPP; | 57 | goto out_drop_write; |
| 67 | goto setflags_out; | 58 | } |
| 68 | } | 59 | |
| 69 | if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */ | 60 | mutex_lock(&inode->i_mutex); |
| 70 | inode->i_flags |= S_IMMUTABLE; | 61 | |
| 71 | HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE; | 62 | if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) || |
| 72 | } else { | 63 | inode->i_flags & (S_IMMUTABLE|S_APPEND)) { |
| 73 | inode->i_flags &= ~S_IMMUTABLE; | 64 | if (!capable(CAP_LINUX_IMMUTABLE)) { |
| 74 | HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE; | 65 | err = -EPERM; |
| 75 | } | 66 | goto out_unlock_inode; |
| 76 | if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */ | ||
| 77 | inode->i_flags |= S_APPEND; | ||
| 78 | HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND; | ||
| 79 | } else { | ||
| 80 | inode->i_flags &= ~S_APPEND; | ||
| 81 | HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND; | ||
| 82 | } | 67 | } |
| 83 | if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */ | ||
| 84 | HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP; | ||
| 85 | else | ||
| 86 | HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP; | ||
| 87 | |||
| 88 | inode->i_ctime = CURRENT_TIME_SEC; | ||
| 89 | mark_inode_dirty(inode); | ||
| 90 | setflags_out: | ||
| 91 | mnt_drop_write(filp->f_path.mnt); | ||
| 92 | unlock_kernel(); | ||
| 93 | return err; | ||
| 94 | } | 68 | } |
| 69 | |||
| 70 | /* don't silently ignore unsupported ext2 flags */ | ||
| 71 | if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) { | ||
| 72 | err = -EOPNOTSUPP; | ||
| 73 | goto out_unlock_inode; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (flags & FS_IMMUTABLE_FL) | ||
| 77 | inode->i_flags |= S_IMMUTABLE; | ||
| 78 | else | ||
| 79 | inode->i_flags &= ~S_IMMUTABLE; | ||
| 80 | |||
| 81 | if (flags & FS_APPEND_FL) | ||
| 82 | inode->i_flags |= S_APPEND; | ||
| 83 | else | ||
| 84 | inode->i_flags &= ~S_APPEND; | ||
| 85 | |||
| 86 | if (flags & FS_NODUMP_FL) | ||
| 87 | hip->userflags |= HFSPLUS_FLG_NODUMP; | ||
| 88 | else | ||
| 89 | hip->userflags &= ~HFSPLUS_FLG_NODUMP; | ||
| 90 | |||
| 91 | inode->i_ctime = CURRENT_TIME_SEC; | ||
| 92 | mark_inode_dirty(inode); | ||
| 93 | |||
| 94 | out_unlock_inode: | ||
| 95 | mutex_lock(&inode->i_mutex); | ||
| 96 | out_drop_write: | ||
| 97 | mnt_drop_write(file->f_path.mnt); | ||
| 98 | out: | ||
| 99 | return err; | ||
| 100 | } | ||
| 101 | |||
| 102 | long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 103 | { | ||
| 104 | void __user *argp = (void __user *)arg; | ||
| 105 | |||
| 106 | switch (cmd) { | ||
| 107 | case HFSPLUS_IOC_EXT2_GETFLAGS: | ||
| 108 | return hfsplus_ioctl_getflags(file, argp); | ||
| 109 | case HFSPLUS_IOC_EXT2_SETFLAGS: | ||
| 110 | return hfsplus_ioctl_setflags(file, argp); | ||
| 95 | default: | 111 | default: |
| 96 | unlock_kernel(); | ||
| 97 | return -ENOTTY; | 112 | return -ENOTTY; |
| 98 | } | 113 | } |
| 99 | } | 114 | } |
| @@ -110,7 +125,7 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name, | |||
| 110 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | 125 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) |
| 111 | return -EOPNOTSUPP; | 126 | return -EOPNOTSUPP; |
| 112 | 127 | ||
| 113 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); | 128 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); |
| 114 | if (res) | 129 | if (res) |
| 115 | return res; | 130 | return res; |
| 116 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | 131 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); |
| @@ -153,7 +168,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | |||
| 153 | return -EOPNOTSUPP; | 168 | return -EOPNOTSUPP; |
| 154 | 169 | ||
| 155 | if (size) { | 170 | if (size) { |
| 156 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); | 171 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); |
| 157 | if (res) | 172 | if (res) |
| 158 | return res; | 173 | return res; |
| 159 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | 174 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); |
| @@ -177,7 +192,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | |||
| 177 | } else | 192 | } else |
| 178 | res = size ? -ERANGE : 4; | 193 | res = size ? -ERANGE : 4; |
| 179 | } else | 194 | } else |
| 180 | res = -ENODATA; | 195 | res = -EOPNOTSUPP; |
| 181 | out: | 196 | out: |
| 182 | if (size) | 197 | if (size) |
| 183 | hfs_find_exit(&fd); | 198 | hfs_find_exit(&fd); |
