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