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/time.h> 12 #include <linux/sched.h> 13 #include <asm/current.h> 14 #include <asm/uaccess.h> 15 16 17 int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, 18 unsigned long arg) 19 { 20 struct ext2_inode_info *ei = EXT2_I(inode); 21 unsigned int flags; 22 23 ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); 24 25 switch (cmd) { 26 case EXT2_IOC_GETFLAGS: 27 flags = ei->i_flags & EXT2_FL_USER_VISIBLE; 28 return put_user(flags, (int __user *) arg); 29 case EXT2_IOC_SETFLAGS: { 30 unsigned int oldflags; 31 32 if (IS_RDONLY(inode)) 33 return -EROFS; 34 35 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 36 return -EACCES; 37 38 if (get_user(flags, (int __user *) arg)) 39 return -EFAULT; 40 41 if (!S_ISDIR(inode->i_mode)) 42 flags &= ~EXT2_DIRSYNC_FL; 43 44 oldflags = ei->i_flags; 45 46 /* 47 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 48 * the relevant capability. 49 * 50 * This test looks nicer. Thanks to Pauline Middelink 51 */ 52 if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { 53 if (!capable(CAP_LINUX_IMMUTABLE)) 54 return -EPERM; 55 } 56 57 flags = flags & EXT2_FL_USER_MODIFIABLE; 58 flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; 59 ei->i_flags = flags; 60 61 ext2_set_inode_flags(inode); 62 inode->i_ctime = CURRENT_TIME_SEC; 63 mark_inode_dirty(inode); 64 return 0; 65 } 66 case EXT2_IOC_GETVERSION: 67 return put_user(inode->i_generation, (int __user *) arg); 68 case EXT2_IOC_SETVERSION: 69 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 70 return -EPERM; 71 if (IS_RDONLY(inode)) 72 return -EROFS; 73 if (get_user(inode->i_generation, (int __user *) arg)) 74 return -EFAULT; 75 inode->i_ctime = CURRENT_TIME_SEC; 76 mark_inode_dirty(inode); 77 return 0; 78 default: 79 return -ENOTTY; 80 } 81 } 82