1 /* 2 * linux/fs/jfs/ioctl.c 3 * 4 * Copyright (C) 2006 Herbert Poetzl 5 * adapted from Remy Card's ext2/ioctl.c 6 */ 7 8 #include <linux/fs.h> 9 #include <linux/ctype.h> 10 #include <linux/capability.h> 11 #include <linux/mount.h> 12 #include <linux/time.h> 13 #include <linux/sched.h> 14 #include <asm/current.h> 15 #include <asm/uaccess.h> 16 17 #include "jfs_incore.h" 18 #include "jfs_dinode.h" 19 #include "jfs_inode.h" 20 21 22 static struct { 23 long jfs_flag; 24 long ext2_flag; 25 } jfs_map[] = { 26 {JFS_NOATIME_FL, FS_NOATIME_FL}, 27 {JFS_DIRSYNC_FL, FS_DIRSYNC_FL}, 28 {JFS_SYNC_FL, FS_SYNC_FL}, 29 {JFS_SECRM_FL, FS_SECRM_FL}, 30 {JFS_UNRM_FL, FS_UNRM_FL}, 31 {JFS_APPEND_FL, FS_APPEND_FL}, 32 {JFS_IMMUTABLE_FL, FS_IMMUTABLE_FL}, 33 {0, 0}, 34 }; 35 36 static long jfs_map_ext2(unsigned long flags, int from) 37 { 38 int index=0; 39 long mapped=0; 40 41 while (jfs_map[index].jfs_flag) { 42 if (from) { 43 if (jfs_map[index].ext2_flag & flags) 44 mapped |= jfs_map[index].jfs_flag; 45 } else { 46 if (jfs_map[index].jfs_flag & flags) 47 mapped |= jfs_map[index].ext2_flag; 48 } 49 index++; 50 } 51 return mapped; 52 } 53 54 55 long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 56 { 57 struct inode *inode = filp->f_dentry->d_inode; 58 struct jfs_inode_info *jfs_inode = JFS_IP(inode); 59 unsigned int flags; 60 61 switch (cmd) { 62 case JFS_IOC_GETFLAGS: 63 jfs_get_inode_flags(jfs_inode); 64 flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; 65 flags = jfs_map_ext2(flags, 0); 66 return put_user(flags, (int __user *) arg); 67 case JFS_IOC_SETFLAGS: { 68 unsigned int oldflags; 69 int err; 70 71 err = mnt_want_write(filp->f_path.mnt); 72 if (err) 73 return err; 74 75 if (!is_owner_or_cap(inode)) { 76 err = -EACCES; 77 goto setflags_out; 78 } 79 if (get_user(flags, (int __user *) arg)) { 80 err = -EFAULT; 81 goto setflags_out; 82 } 83 84 flags = jfs_map_ext2(flags, 1); 85 if (!S_ISDIR(inode->i_mode)) 86 flags &= ~JFS_DIRSYNC_FL; 87 88 /* Is it quota file? Do not allow user to mess with it */ 89 if (IS_NOQUOTA(inode)) { 90 err = -EPERM; 91 goto setflags_out; 92 } 93 94 /* Lock against other parallel changes of flags */ 95 mutex_lock(&inode->i_mutex); 96 97 jfs_get_inode_flags(jfs_inode); 98 oldflags = jfs_inode->mode2; 99 100 /* 101 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 102 * the relevant capability. 103 */ 104 if ((oldflags & JFS_IMMUTABLE_FL) || 105 ((flags ^ oldflags) & 106 (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { 107 if (!capable(CAP_LINUX_IMMUTABLE)) { 108 mutex_unlock(&inode->i_mutex); 109 err = -EPERM; 110 goto setflags_out; 111 } 112 } 113 114 flags = flags & JFS_FL_USER_MODIFIABLE; 115 flags |= oldflags & ~JFS_FL_USER_MODIFIABLE; 116 jfs_inode->mode2 = flags; 117 118 jfs_set_inode_flags(inode); 119 mutex_unlock(&inode->i_mutex); 120 inode->i_ctime = CURRENT_TIME_SEC; 121 mark_inode_dirty(inode); 122 setflags_out: 123 mnt_drop_write(filp->f_path.mnt); 124 return err; 125 } 126 default: 127 return -ENOTTY; 128 } 129 } 130 131 #ifdef CONFIG_COMPAT 132 long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 133 { 134 /* While these ioctl numbers defined with 'long' and have different 135 * numbers than the 64bit ABI, 136 * the actual implementation only deals with ints and is compatible. 137 */ 138 switch (cmd) { 139 case JFS_IOC_GETFLAGS32: 140 cmd = JFS_IOC_GETFLAGS; 141 break; 142 case JFS_IOC_SETFLAGS32: 143 cmd = JFS_IOC_SETFLAGS; 144 break; 145 } 146 return jfs_ioctl(filp, cmd, arg); 147 } 148 #endif 149