MOD -> DIS : CONFIG_EDD
[linux-2.6.git] / fs / attr.c
1 /*
2  *  linux/fs/attr.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  *  changes by Thomas Schoebel-Theuer
6  */
7
8 #include <linux/module.h>
9 #include <linux/time.h>
10 #include <linux/mm.h>
11 #include <linux/string.h>
12 #include <linux/smp_lock.h>
13 #include <linux/capability.h>
14 #include <linux/fsnotify.h>
15 #include <linux/fcntl.h>
16 #include <linux/quotaops.h>
17 #include <linux/security.h>
18 #include <linux/proc_fs.h>
19 #include <linux/devpts_fs.h>
20 #include <linux/vs_base.h>
21 #include <linux/vserver/debug.h>
22
23 /* Taken over from the old code... */
24
25 /* POSIX UID/GID verification for setting inode attributes. */
26 int inode_change_ok(struct inode *inode, struct iattr *attr)
27 {
28         int retval = -EPERM;
29         unsigned int ia_valid = attr->ia_valid;
30
31         /* If force is set do it anyway. */
32         if (ia_valid & ATTR_FORCE)
33                 goto fine;
34
35         /* Make sure a caller can chown. */
36         if ((ia_valid & ATTR_UID) &&
37             (current->fsuid != inode->i_uid ||
38              attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
39                 goto error;
40
41         /* Make sure caller can chgrp. */
42         if ((ia_valid & ATTR_GID) &&
43             (current->fsuid != inode->i_uid ||
44             (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
45             !capable(CAP_CHOWN))
46                 goto error;
47
48         /* Make sure a caller can chmod. */
49         if (ia_valid & ATTR_MODE) {
50                 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
51                         goto error;
52                 /* Also check the setgid bit! */
53                 if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
54                                 inode->i_gid) && !capable(CAP_FSETID))
55                         attr->ia_mode &= ~S_ISGID;
56         }
57
58         /* Check for setting the inode time. */
59         if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
60                 if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
61                         goto error;
62         }
63
64         /* Check for evil vserver activity */
65         if (vx_check(0, VX_ADMIN))
66                 goto fine;
67
68         if (IS_BARRIER(inode)) {
69                 vxwprintk(1, "xid=%d messing with the barrier.",
70                         vx_current_xid());
71                 goto error;
72         }
73         switch (inode->i_sb->s_magic) {
74                 case PROC_SUPER_MAGIC:
75                         vxwprintk(1, "xid=%d messing with the procfs.",
76                                 vx_current_xid());
77                         goto error;
78                 case DEVPTS_SUPER_MAGIC:
79                         if (vx_check(inode->i_xid, VX_IDENT))
80                                 goto fine;
81                         vxwprintk(1, "xid=%d messing with the devpts.",
82                                 vx_current_xid());
83                         goto error;
84         }
85 fine:
86         retval = 0;
87 error:
88         return retval;
89 }
90
91 EXPORT_SYMBOL(inode_change_ok);
92
93 int inode_setattr(struct inode * inode, struct iattr * attr)
94 {
95         unsigned int ia_valid = attr->ia_valid;
96
97         if (ia_valid & ATTR_SIZE &&
98             attr->ia_size != i_size_read(inode)) {
99                 int error = vmtruncate(inode, attr->ia_size);
100                 if (error)
101                         return error;
102         }
103
104         if (ia_valid & ATTR_UID)
105                 inode->i_uid = attr->ia_uid;
106         if (ia_valid & ATTR_GID)
107                 inode->i_gid = attr->ia_gid;
108         if ((ia_valid & ATTR_XID) && IS_TAGXID(inode))
109                 inode->i_xid = attr->ia_xid;
110         if (ia_valid & ATTR_ATIME)
111                 inode->i_atime = timespec_trunc(attr->ia_atime,
112                                                 inode->i_sb->s_time_gran);
113         if (ia_valid & ATTR_MTIME)
114                 inode->i_mtime = timespec_trunc(attr->ia_mtime,
115                                                 inode->i_sb->s_time_gran);
116         if (ia_valid & ATTR_CTIME)
117                 inode->i_ctime = timespec_trunc(attr->ia_ctime,
118                                                 inode->i_sb->s_time_gran);
119         if (ia_valid & ATTR_MODE) {
120                 umode_t mode = attr->ia_mode;
121
122                 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
123                         mode &= ~S_ISGID;
124                 inode->i_mode = mode;
125         }
126         mark_inode_dirty(inode);
127
128         return 0;
129 }
130 EXPORT_SYMBOL(inode_setattr);
131
132 int notify_change(struct dentry * dentry, struct iattr * attr)
133 {
134         struct inode *inode = dentry->d_inode;
135         mode_t mode;
136         int error;
137         struct timespec now;
138         unsigned int ia_valid = attr->ia_valid;
139
140         mode = inode->i_mode;
141         now = current_fs_time(inode->i_sb);
142
143         attr->ia_ctime = now;
144         if (!(ia_valid & ATTR_ATIME_SET))
145                 attr->ia_atime = now;
146         if (!(ia_valid & ATTR_MTIME_SET))
147                 attr->ia_mtime = now;
148         if (ia_valid & ATTR_KILL_SUID) {
149                 attr->ia_valid &= ~ATTR_KILL_SUID;
150                 if (mode & S_ISUID) {
151                         if (!(ia_valid & ATTR_MODE)) {
152                                 ia_valid = attr->ia_valid |= ATTR_MODE;
153                                 attr->ia_mode = inode->i_mode;
154                         }
155                         attr->ia_mode &= ~S_ISUID;
156                 }
157         }
158         if (ia_valid & ATTR_KILL_SGID) {
159                 attr->ia_valid &= ~ ATTR_KILL_SGID;
160                 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
161                         if (!(ia_valid & ATTR_MODE)) {
162                                 ia_valid = attr->ia_valid |= ATTR_MODE;
163                                 attr->ia_mode = inode->i_mode;
164                         }
165                         attr->ia_mode &= ~S_ISGID;
166                 }
167         }
168         if (!attr->ia_valid)
169                 return 0;
170
171         if (ia_valid & ATTR_SIZE)
172                 down_write(&dentry->d_inode->i_alloc_sem);
173
174         if (inode->i_op && inode->i_op->setattr) {
175                 error = security_inode_setattr(dentry, attr);
176                 if (!error)
177                         error = inode->i_op->setattr(dentry, attr);
178         } else {
179                 error = inode_change_ok(inode, attr);
180                 if (!error)
181                         error = security_inode_setattr(dentry, attr);
182                 if (!error) {
183                         if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
184                             (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
185                             (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid))
186                                 error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
187                         if (!error)
188                                 error = inode_setattr(inode, attr);
189                 }
190         }
191
192         if (ia_valid & ATTR_SIZE)
193                 up_write(&dentry->d_inode->i_alloc_sem);
194
195         if (!error)
196                 fsnotify_change(dentry, ia_valid);
197
198         return error;
199 }
200
201 EXPORT_SYMBOL(notify_change);