Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check
[linux-block.git] / fs / ocfs2 / ioctl.c
CommitLineData
ca4d147e
HP
1/*
2 * linux/fs/ocfs2/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/mount.h>
10
11#define MLOG_MASK_PREFIX ML_INODE
12#include <cluster/masklog.h>
13
14#include "ocfs2.h"
15#include "alloc.h"
16#include "dlmglue.h"
b2580103 17#include "file.h"
ca4d147e
HP
18#include "inode.h"
19#include "journal.h"
20
21#include "ocfs2_fs.h"
2d562518
AB
22#include "ioctl.h"
23
ca4d147e
HP
24#include <linux/ext2_fs.h>
25
26static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
27{
28 int status;
29
4bcec184 30 status = ocfs2_meta_lock(inode, NULL, 0);
ca4d147e
HP
31 if (status < 0) {
32 mlog_errno(status);
33 return status;
34 }
6e4b0d56 35 ocfs2_get_inode_flags(OCFS2_I(inode));
ca4d147e
HP
36 *flags = OCFS2_I(inode)->ip_attr;
37 ocfs2_meta_unlock(inode, 0);
38
39 mlog_exit(status);
40 return status;
41}
42
43static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
44 unsigned mask)
45{
46 struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode);
47 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
1fabe148 48 handle_t *handle = NULL;
ca4d147e
HP
49 struct buffer_head *bh = NULL;
50 unsigned oldflags;
51 int status;
52
53 mutex_lock(&inode->i_mutex);
54
4bcec184 55 status = ocfs2_meta_lock(inode, &bh, 1);
ca4d147e
HP
56 if (status < 0) {
57 mlog_errno(status);
58 goto bail;
59 }
60
61 status = -EROFS;
62 if (IS_RDONLY(inode))
63 goto bail_unlock;
64
65 status = -EACCES;
3bd858ab 66 if (!is_owner_or_cap(inode))
ca4d147e
HP
67 goto bail_unlock;
68
69 if (!S_ISDIR(inode->i_mode))
70 flags &= ~OCFS2_DIRSYNC_FL;
71
65eff9cc 72 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
ca4d147e
HP
73 if (IS_ERR(handle)) {
74 status = PTR_ERR(handle);
75 mlog_errno(status);
76 goto bail_unlock;
77 }
78
79 oldflags = ocfs2_inode->ip_attr;
80 flags = flags & mask;
81 flags |= oldflags & ~mask;
82
83 /*
84 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
85 * the relevant capability.
86 */
87 status = -EPERM;
88 if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
89 (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
90 if (!capable(CAP_LINUX_IMMUTABLE))
91 goto bail_unlock;
92 }
93
94 ocfs2_inode->ip_attr = flags;
95 ocfs2_set_inode_flags(inode);
96
97 status = ocfs2_mark_inode_dirty(handle, inode, bh);
98 if (status < 0)
99 mlog_errno(status);
100
02dc1af4 101 ocfs2_commit_trans(osb, handle);
ca4d147e
HP
102bail_unlock:
103 ocfs2_meta_unlock(inode, 1);
104bail:
105 mutex_unlock(&inode->i_mutex);
106
107 if (bh)
108 brelse(bh);
109
110 mlog_exit(status);
111 return status;
112}
113
114int ocfs2_ioctl(struct inode * inode, struct file * filp,
115 unsigned int cmd, unsigned long arg)
116{
117 unsigned int flags;
118 int status;
b2580103 119 struct ocfs2_space_resv sr;
ca4d147e
HP
120
121 switch (cmd) {
122 case OCFS2_IOC_GETFLAGS:
123 status = ocfs2_get_inode_attr(inode, &flags);
124 if (status < 0)
125 return status;
126
127 flags &= OCFS2_FL_VISIBLE;
128 return put_user(flags, (int __user *) arg);
129 case OCFS2_IOC_SETFLAGS:
130 if (get_user(flags, (int __user *) arg))
131 return -EFAULT;
132
133 return ocfs2_set_inode_attr(inode, flags,
134 OCFS2_FL_MODIFIABLE);
b2580103
MF
135 case OCFS2_IOC_RESVSP:
136 case OCFS2_IOC_RESVSP64:
137 case OCFS2_IOC_UNRESVSP:
138 case OCFS2_IOC_UNRESVSP64:
139 if (copy_from_user(&sr, (int __user *) arg, sizeof(sr)))
140 return -EFAULT;
141
142 return ocfs2_change_file_space(filp, cmd, &sr);
ca4d147e
HP
143 default:
144 return -ENOTTY;
145 }
146}
147
586d232b
MF
148#ifdef CONFIG_COMPAT
149long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
150{
151 struct inode *inode = file->f_path.dentry->d_inode;
152 int ret;
153
154 switch (cmd) {
155 case OCFS2_IOC32_GETFLAGS:
156 cmd = OCFS2_IOC_GETFLAGS;
157 break;
158 case OCFS2_IOC32_SETFLAGS:
159 cmd = OCFS2_IOC_SETFLAGS;
160 break;
b2580103
MF
161 case OCFS2_IOC_RESVSP:
162 case OCFS2_IOC_RESVSP64:
163 case OCFS2_IOC_UNRESVSP:
164 case OCFS2_IOC_UNRESVSP64:
165 break;
586d232b
MF
166 default:
167 return -ENOIOCTLCMD;
168 }
169
170 lock_kernel();
171 ret = ocfs2_ioctl(inode, file, cmd, arg);
172 unlock_kernel();
173 return ret;
174}
175#endif