1 /* 2 * linux/fs/ext2/ioctl.c 3 * 4 * Copyright (C) 1993, 1994, 1995 5 * Remy Card (card@masi.ibp.fr) 6 * Laboratoire MASI - Institut Blaise Pascal 7 * Universite Pierre et Marie Curie (Paris VI) 8 */ 9 10 #include "ext2.h" 11 #include <linux/capability.h> 12 #include <linux/time.h> 13 #include <linux/sched.h> 14 #include <linux/compat.h> 15 #include <linux/smp_lock.h> 16 #include <asm/current.h> 17 #include <asm/uaccess.h> 18 19 20 long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 21 { 22 struct inode *inode = filp->f_dentry->d_inode; 23 struct ext2_inode_info *ei = EXT2_I(inode); 24 unsigned int flags; 25 unsigned short rsv_window_size; 26 27 ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); 28 29 switch (cmd) { 30 case EXT2_IOC_GETFLAGS: 31 ext2_get_inode_flags(ei); 32 flags = ei->i_flags & EXT2_FL_USER_VISIBLE; 33 return put_user(flags, (int __user *) arg); 34 case EXT2_IOC_SETFLAGS: { 35 unsigned int oldflags; 36 37 if (IS_RDONLY(inode)) 38 return -EROFS; 39 40 if (!is_owner_or_cap(inode)) 41 return -EACCES; 42 43 if (get_user(flags, (int __user *) arg)) 44 return -EFAULT; 45 46 if (!S_ISDIR(inode->i_mode)) 47 flags &= ~EXT2_DIRSYNC_FL; 48 49 mutex_lock(&inode->i_mutex); 50 /* Is it quota file? Do not allow user to mess with it */ 51 if (IS_NOQUOTA(inode)) { 52 mutex_unlock(&inode->i_mutex); 53 return -EPERM; 54 } 55 oldflags = ei->i_flags; 56 57 /* 58 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 59 * the relevant capability. 60 * 61 * This test looks nicer. Thanks to Pauline Middelink 62 */ 63 if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { 64 if (!capable(CAP_LINUX_IMMUTABLE)) { 65 mutex_unlock(&inode->i_mutex); 66 return -EPERM; 67 } 68 } 69 70 flags = flags & EXT2_FL_USER_MODIFIABLE; 71 flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; 72 ei->i_flags = flags; 73 mutex_unlock(&inode->i_mutex); 74 75 ext2_set_inode_flags(inode); 76 inode->i_ctime = CURRENT_TIME_SEC; 77 mark_inode_dirty(inode); 78 return 0; 79 } 80 case EXT2_IOC_GETVERSION: 81 return put_user(inode->i_generation, (int __user *) arg); 82 case EXT2_IOC_SETVERSION: 83 if (!is_owner_or_cap(inode)) 84 return -EPERM; 85 if (IS_RDONLY(inode)) 86 return -EROFS; 87 if (get_user(inode->i_generation, (int __user *) arg)) 88 return -EFAULT; 89 inode->i_ctime = CURRENT_TIME_SEC; 90 mark_inode_dirty(inode); 91 return 0; 92 case EXT2_IOC_GETRSVSZ: 93 if (test_opt(inode->i_sb, RESERVATION) 94 && S_ISREG(inode->i_mode) 95 && ei->i_block_alloc_info) { 96 rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 97 return put_user(rsv_window_size, (int __user *)arg); 98 } 99 return -ENOTTY; 100 case EXT2_IOC_SETRSVSZ: { 101 102 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 103 return -ENOTTY; 104 105 if (IS_RDONLY(inode)) 106 return -EROFS; 107 108 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 109 return -EACCES; 110 111 if (get_user(rsv_window_size, (int __user *)arg)) 112 return -EFAULT; 113 114 if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) 115 rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; 116 117 /* 118 * need to allocate reservation structure for this inode 119 * before set the window size 120 */ 121 /* 122 * XXX What lock should protect the rsv_goal_size? 123 * Accessed in ext2_get_block only. ext3 uses i_truncate. 124 */ 125 mutex_lock(&ei->truncate_mutex); 126 if (!ei->i_block_alloc_info) 127 ext2_init_block_alloc_info(inode); 128 129 if (ei->i_block_alloc_info){ 130 struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 131 rsv->rsv_goal_size = rsv_window_size; 132 } 133 mutex_unlock(&ei->truncate_mutex); 134 return 0; 135 } 136 default: 137 return -ENOTTY; 138 } 139 } 140 141 #ifdef CONFIG_COMPAT 142 long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 143 { 144 /* These are just misnamed, they actually get/put from/to user an int */ 145 switch (cmd) { 146 case EXT2_IOC32_GETFLAGS: 147 cmd = EXT2_IOC_GETFLAGS; 148 break; 149 case EXT2_IOC32_SETFLAGS: 150 cmd = EXT2_IOC_SETFLAGS; 151 break; 152 case EXT2_IOC32_GETVERSION: 153 cmd = EXT2_IOC_GETVERSION; 154 break; 155 case EXT2_IOC32_SETVERSION: 156 cmd = EXT2_IOC_SETVERSION; 157 break; 158 default: 159 return -ENOIOCTLCMD; 160 } 161 return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 162 } 163 #endif 164