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 int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, 21 unsigned long arg) 22 { 23 struct ext2_inode_info *ei = EXT2_I(inode); 24 unsigned int flags; 25 26 ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); 27 28 switch (cmd) { 29 case EXT2_IOC_GETFLAGS: 30 ext2_get_inode_flags(ei); 31 flags = ei->i_flags & EXT2_FL_USER_VISIBLE; 32 return put_user(flags, (int __user *) arg); 33 case EXT2_IOC_SETFLAGS: { 34 unsigned int oldflags; 35 36 if (IS_RDONLY(inode)) 37 return -EROFS; 38 39 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 40 return -EACCES; 41 42 if (get_user(flags, (int __user *) arg)) 43 return -EFAULT; 44 45 if (!S_ISDIR(inode->i_mode)) 46 flags &= ~EXT2_DIRSYNC_FL; 47 48 mutex_lock(&inode->i_mutex); 49 oldflags = ei->i_flags; 50 51 /* 52 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 53 * the relevant capability. 54 * 55 * This test looks nicer. Thanks to Pauline Middelink 56 */ 57 if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { 58 if (!capable(CAP_LINUX_IMMUTABLE)) { 59 mutex_unlock(&inode->i_mutex); 60 return -EPERM; 61 } 62 } 63 64 flags = flags & EXT2_FL_USER_MODIFIABLE; 65 flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; 66 ei->i_flags = flags; 67 mutex_unlock(&inode->i_mutex); 68 69 ext2_set_inode_flags(inode); 70 inode->i_ctime = CURRENT_TIME_SEC; 71 mark_inode_dirty(inode); 72 return 0; 73 } 74 case EXT2_IOC_GETVERSION: 75 return put_user(inode->i_generation, (int __user *) arg); 76 case EXT2_IOC_SETVERSION: 77 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 78 return -EPERM; 79 if (IS_RDONLY(inode)) 80 return -EROFS; 81 if (get_user(inode->i_generation, (int __user *) arg)) 82 return -EFAULT; 83 inode->i_ctime = CURRENT_TIME_SEC; 84 mark_inode_dirty(inode); 85 return 0; 86 default: 87 return -ENOTTY; 88 } 89 } 90 91 #ifdef CONFIG_COMPAT 92 long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 93 { 94 struct inode *inode = file->f_path.dentry->d_inode; 95 int ret; 96 97 /* These are just misnamed, they actually get/put from/to user an int */ 98 switch (cmd) { 99 case EXT2_IOC32_GETFLAGS: 100 cmd = EXT2_IOC_GETFLAGS; 101 break; 102 case EXT2_IOC32_SETFLAGS: 103 cmd = EXT2_IOC_SETFLAGS; 104 break; 105 case EXT2_IOC32_GETVERSION: 106 cmd = EXT2_IOC_GETVERSION; 107 break; 108 case EXT2_IOC32_SETVERSION: 109 cmd = EXT2_IOC_SETVERSION; 110 break; 111 default: 112 return -ENOIOCTLCMD; 113 } 114 lock_kernel(); 115 ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); 116 unlock_kernel(); 117 return ret; 118 } 119 #endif 120