Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/fs/attr.c
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 5145 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 5145 byte(s)
Tag kernel26-2.6.12-alx-r9
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/dnotify.h> |
14 | #include <linux/fcntl.h> |
15 | #include <linux/quotaops.h> |
16 | #include <linux/security.h> |
17 | #include <linux/time.h> |
18 | |
19 | /* Taken over from the old code... */ |
20 | |
21 | /* POSIX UID/GID verification for setting inode attributes. */ |
22 | int inode_change_ok(struct inode *inode, struct iattr *attr) |
23 | { |
24 | int retval = -EPERM; |
25 | unsigned int ia_valid = attr->ia_valid; |
26 | |
27 | /* If force is set do it anyway. */ |
28 | if (ia_valid & ATTR_FORCE) |
29 | goto fine; |
30 | |
31 | /* Make sure a caller can chown. */ |
32 | if ((ia_valid & ATTR_UID) && |
33 | (current->fsuid != inode->i_uid || |
34 | attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) |
35 | goto error; |
36 | |
37 | /* Make sure caller can chgrp. */ |
38 | if ((ia_valid & ATTR_GID) && |
39 | (current->fsuid != inode->i_uid || |
40 | (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && |
41 | !capable(CAP_CHOWN)) |
42 | goto error; |
43 | |
44 | /* Make sure a caller can chmod. */ |
45 | if (ia_valid & ATTR_MODE) { |
46 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) |
47 | goto error; |
48 | /* Also check the setgid bit! */ |
49 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : |
50 | inode->i_gid) && !capable(CAP_FSETID)) |
51 | attr->ia_mode &= ~S_ISGID; |
52 | } |
53 | |
54 | /* Check for setting the inode time. */ |
55 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { |
56 | if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) |
57 | goto error; |
58 | } |
59 | fine: |
60 | retval = 0; |
61 | error: |
62 | return retval; |
63 | } |
64 | |
65 | EXPORT_SYMBOL(inode_change_ok); |
66 | |
67 | int inode_setattr(struct inode * inode, struct iattr * attr) |
68 | { |
69 | unsigned int ia_valid = attr->ia_valid; |
70 | int error = 0; |
71 | |
72 | if (ia_valid & ATTR_SIZE) { |
73 | if (attr->ia_size != i_size_read(inode)) { |
74 | error = vmtruncate(inode, attr->ia_size); |
75 | if (error || (ia_valid == ATTR_SIZE)) |
76 | goto out; |
77 | } else { |
78 | /* |
79 | * We skipped the truncate but must still update |
80 | * timestamps |
81 | */ |
82 | ia_valid |= ATTR_MTIME|ATTR_CTIME; |
83 | } |
84 | } |
85 | |
86 | if (ia_valid & ATTR_UID) |
87 | inode->i_uid = attr->ia_uid; |
88 | if (ia_valid & ATTR_GID) |
89 | inode->i_gid = attr->ia_gid; |
90 | if (ia_valid & ATTR_ATIME) |
91 | inode->i_atime = timespec_trunc(attr->ia_atime, |
92 | inode->i_sb->s_time_gran); |
93 | if (ia_valid & ATTR_MTIME) |
94 | inode->i_mtime = timespec_trunc(attr->ia_mtime, |
95 | inode->i_sb->s_time_gran); |
96 | if (ia_valid & ATTR_CTIME) |
97 | inode->i_ctime = timespec_trunc(attr->ia_ctime, |
98 | inode->i_sb->s_time_gran); |
99 | if (ia_valid & ATTR_MODE) { |
100 | umode_t mode = attr->ia_mode; |
101 | |
102 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) |
103 | mode &= ~S_ISGID; |
104 | inode->i_mode = mode; |
105 | } |
106 | mark_inode_dirty(inode); |
107 | out: |
108 | return error; |
109 | } |
110 | |
111 | EXPORT_SYMBOL(inode_setattr); |
112 | |
113 | int setattr_mask(unsigned int ia_valid) |
114 | { |
115 | unsigned long dn_mask = 0; |
116 | |
117 | if (ia_valid & ATTR_UID) |
118 | dn_mask |= DN_ATTRIB; |
119 | if (ia_valid & ATTR_GID) |
120 | dn_mask |= DN_ATTRIB; |
121 | if (ia_valid & ATTR_SIZE) |
122 | dn_mask |= DN_MODIFY; |
123 | /* both times implies a utime(s) call */ |
124 | if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME)) |
125 | dn_mask |= DN_ATTRIB; |
126 | else if (ia_valid & ATTR_ATIME) |
127 | dn_mask |= DN_ACCESS; |
128 | else if (ia_valid & ATTR_MTIME) |
129 | dn_mask |= DN_MODIFY; |
130 | if (ia_valid & ATTR_MODE) |
131 | dn_mask |= DN_ATTRIB; |
132 | return dn_mask; |
133 | } |
134 | |
135 | int notify_change(struct dentry * dentry, struct iattr * attr) |
136 | { |
137 | struct inode *inode = dentry->d_inode; |
138 | mode_t mode; |
139 | int error; |
140 | struct timespec now; |
141 | unsigned int ia_valid = attr->ia_valid; |
142 | |
143 | if (!inode) |
144 | BUG(); |
145 | |
146 | mode = inode->i_mode; |
147 | now = current_fs_time(inode->i_sb); |
148 | |
149 | attr->ia_ctime = now; |
150 | if (!(ia_valid & ATTR_ATIME_SET)) |
151 | attr->ia_atime = now; |
152 | if (!(ia_valid & ATTR_MTIME_SET)) |
153 | attr->ia_mtime = now; |
154 | if (ia_valid & ATTR_KILL_SUID) { |
155 | attr->ia_valid &= ~ATTR_KILL_SUID; |
156 | if (mode & S_ISUID) { |
157 | if (!(ia_valid & ATTR_MODE)) { |
158 | ia_valid = attr->ia_valid |= ATTR_MODE; |
159 | attr->ia_mode = inode->i_mode; |
160 | } |
161 | attr->ia_mode &= ~S_ISUID; |
162 | } |
163 | } |
164 | if (ia_valid & ATTR_KILL_SGID) { |
165 | attr->ia_valid &= ~ ATTR_KILL_SGID; |
166 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
167 | if (!(ia_valid & ATTR_MODE)) { |
168 | ia_valid = attr->ia_valid |= ATTR_MODE; |
169 | attr->ia_mode = inode->i_mode; |
170 | } |
171 | attr->ia_mode &= ~S_ISGID; |
172 | } |
173 | } |
174 | if (!attr->ia_valid) |
175 | return 0; |
176 | |
177 | if (ia_valid & ATTR_SIZE) |
178 | down_write(&dentry->d_inode->i_alloc_sem); |
179 | |
180 | if (inode->i_op && inode->i_op->setattr) { |
181 | error = security_inode_setattr(dentry, attr); |
182 | if (!error) |
183 | error = inode->i_op->setattr(dentry, attr); |
184 | } else { |
185 | error = inode_change_ok(inode, attr); |
186 | if (!error) |
187 | error = security_inode_setattr(dentry, attr); |
188 | if (!error) { |
189 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || |
190 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) |
191 | error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; |
192 | if (!error) |
193 | error = inode_setattr(inode, attr); |
194 | } |
195 | } |
196 | |
197 | if (ia_valid & ATTR_SIZE) |
198 | up_write(&dentry->d_inode->i_alloc_sem); |
199 | |
200 | if (!error) { |
201 | unsigned long dn_mask = setattr_mask(ia_valid); |
202 | if (dn_mask) |
203 | dnotify_parent(dentry, dn_mask); |
204 | } |
205 | return error; |
206 | } |
207 | |
208 | EXPORT_SYMBOL(notify_change); |