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