Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shaggy...
[linux-2.6] / fs / jfs / ioctl.c
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 <asm/current.h>
13 #include <asm/uaccess.h>
14
15 #include "jfs_incore.h"
16 #include "jfs_dinode.h"
17 #include "jfs_inode.h"
18
19
20 static struct {
21         long jfs_flag;
22         long ext2_flag;
23 } jfs_map[] = {
24         {JFS_NOATIME_FL,        FS_NOATIME_FL},
25         {JFS_DIRSYNC_FL,        FS_DIRSYNC_FL},
26         {JFS_SYNC_FL,           FS_SYNC_FL},
27         {JFS_SECRM_FL,          FS_SECRM_FL},
28         {JFS_UNRM_FL,           FS_UNRM_FL},
29         {JFS_APPEND_FL,         FS_APPEND_FL},
30         {JFS_IMMUTABLE_FL,      FS_IMMUTABLE_FL},
31         {0, 0},
32 };
33
34 static long jfs_map_ext2(unsigned long flags, int from)
35 {
36         int index=0;
37         long mapped=0;
38
39         while (jfs_map[index].jfs_flag) {
40                 if (from) {
41                         if (jfs_map[index].ext2_flag & flags)
42                                 mapped |= jfs_map[index].jfs_flag;
43                 } else {
44                         if (jfs_map[index].jfs_flag & flags)
45                                 mapped |= jfs_map[index].ext2_flag;
46                 }
47                 index++;
48         }
49         return mapped;
50 }
51
52
53 int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
54                 unsigned long arg)
55 {
56         struct jfs_inode_info *jfs_inode = JFS_IP(inode);
57         unsigned int flags;
58
59         switch (cmd) {
60         case JFS_IOC_GETFLAGS:
61                 flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
62                 flags = jfs_map_ext2(flags, 0);
63                 return put_user(flags, (int __user *) arg);
64         case JFS_IOC_SETFLAGS: {
65                 unsigned int oldflags;
66
67                 if (IS_RDONLY(inode))
68                         return -EROFS;
69
70                 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
71                         return -EACCES;
72
73                 if (get_user(flags, (int __user *) arg))
74                         return -EFAULT;
75
76                 flags = jfs_map_ext2(flags, 1);
77                 if (!S_ISDIR(inode->i_mode))
78                         flags &= ~JFS_DIRSYNC_FL;
79
80                 oldflags = jfs_inode->mode2;
81
82                 /*
83                  * The IMMUTABLE and APPEND_ONLY flags can only be changed by
84                  * the relevant capability.
85                  */
86                 if ((oldflags & JFS_IMMUTABLE_FL) ||
87                         ((flags ^ oldflags) &
88                         (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
89                         if (!capable(CAP_LINUX_IMMUTABLE))
90                                 return -EPERM;
91                 }
92
93                 flags = flags & JFS_FL_USER_MODIFIABLE;
94                 flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
95                 jfs_inode->mode2 = flags;
96
97                 jfs_set_inode_flags(inode);
98                 inode->i_ctime = CURRENT_TIME_SEC;
99                 mark_inode_dirty(inode);
100                 return 0;
101         }
102         default:
103                 return -ENOTTY;
104         }
105 }
106