diff options
Diffstat (limited to 'fs/fat/file.c')
-rw-r--r-- | fs/fat/file.c | 183 |
1 files changed, 84 insertions, 99 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c index 2a3bed967041..b61a98f5398a 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -157,104 +157,6 @@ out: | |||
157 | return err; | 157 | return err; |
158 | } | 158 | } |
159 | 159 | ||
160 | static int check_mode(const struct msdos_sb_info *sbi, mode_t mode) | ||
161 | { | ||
162 | mode_t req = mode & ~S_IFMT; | ||
163 | |||
164 | /* | ||
165 | * Of the r and x bits, all (subject to umask) must be present. Of the | ||
166 | * w bits, either all (subject to umask) or none must be present. | ||
167 | */ | ||
168 | |||
169 | if (S_ISREG(mode)) { | ||
170 | req &= ~sbi->options.fs_fmask; | ||
171 | |||
172 | if ((req & (S_IRUGO | S_IXUGO)) != | ||
173 | ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask)) | ||
174 | return -EPERM; | ||
175 | |||
176 | if ((req & S_IWUGO) != 0 && | ||
177 | (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask)) | ||
178 | return -EPERM; | ||
179 | } else if (S_ISDIR(mode)) { | ||
180 | req &= ~sbi->options.fs_dmask; | ||
181 | |||
182 | if ((req & (S_IRUGO | S_IXUGO)) != | ||
183 | ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask)) | ||
184 | return -EPERM; | ||
185 | |||
186 | if ((req & S_IWUGO) != 0 && | ||
187 | (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask)) | ||
188 | return -EPERM; | ||
189 | } else { | ||
190 | return -EPERM; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | ||
197 | { | ||
198 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
199 | struct inode *inode = dentry->d_inode; | ||
200 | int mask, error = 0; | ||
201 | |||
202 | lock_kernel(); | ||
203 | |||
204 | /* | ||
205 | * Expand the file. Since inode_setattr() updates ->i_size | ||
206 | * before calling the ->truncate(), but FAT needs to fill the | ||
207 | * hole before it. | ||
208 | */ | ||
209 | if (attr->ia_valid & ATTR_SIZE) { | ||
210 | if (attr->ia_size > inode->i_size) { | ||
211 | error = fat_cont_expand(inode, attr->ia_size); | ||
212 | if (error || attr->ia_valid == ATTR_SIZE) | ||
213 | goto out; | ||
214 | attr->ia_valid &= ~ATTR_SIZE; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | error = inode_change_ok(inode, attr); | ||
219 | if (error) { | ||
220 | if (sbi->options.quiet) | ||
221 | error = 0; | ||
222 | goto out; | ||
223 | } | ||
224 | if (((attr->ia_valid & ATTR_UID) && | ||
225 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
226 | ((attr->ia_valid & ATTR_GID) && | ||
227 | (attr->ia_gid != sbi->options.fs_gid))) | ||
228 | error = -EPERM; | ||
229 | |||
230 | if (error) { | ||
231 | if (sbi->options.quiet) | ||
232 | error = 0; | ||
233 | goto out; | ||
234 | } | ||
235 | |||
236 | if (attr->ia_valid & ATTR_MODE) { | ||
237 | error = check_mode(sbi, attr->ia_mode); | ||
238 | if (error != 0 && !sbi->options.quiet) | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | error = inode_setattr(inode, attr); | ||
243 | if (error) | ||
244 | goto out; | ||
245 | |||
246 | if (S_ISDIR(inode->i_mode)) | ||
247 | mask = sbi->options.fs_dmask; | ||
248 | else | ||
249 | mask = sbi->options.fs_fmask; | ||
250 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
251 | out: | ||
252 | unlock_kernel(); | ||
253 | return error; | ||
254 | } | ||
255 | |||
256 | EXPORT_SYMBOL_GPL(fat_notify_change); | ||
257 | |||
258 | /* Free all clusters after the skip'th cluster. */ | 160 | /* Free all clusters after the skip'th cluster. */ |
259 | static int fat_free(struct inode *inode, int skip) | 161 | static int fat_free(struct inode *inode, int skip) |
260 | { | 162 | { |
@@ -355,8 +257,91 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
355 | } | 257 | } |
356 | EXPORT_SYMBOL_GPL(fat_getattr); | 258 | EXPORT_SYMBOL_GPL(fat_getattr); |
357 | 259 | ||
260 | static int fat_check_mode(const struct msdos_sb_info *sbi, mode_t mode) | ||
261 | { | ||
262 | mode_t mask, req = mode & ~S_IFMT; | ||
263 | |||
264 | if (S_ISREG(mode)) | ||
265 | mask = sbi->options.fs_fmask; | ||
266 | else | ||
267 | mask = sbi->options.fs_dmask; | ||
268 | |||
269 | /* | ||
270 | * Of the r and x bits, all (subject to umask) must be present. Of the | ||
271 | * w bits, either all (subject to umask) or none must be present. | ||
272 | */ | ||
273 | req &= ~mask; | ||
274 | if ((req & (S_IRUGO | S_IXUGO)) != ((S_IRUGO | S_IXUGO) & ~mask)) | ||
275 | return -EPERM; | ||
276 | if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) | ||
277 | return -EPERM; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | int fat_setattr(struct dentry *dentry, struct iattr *attr) | ||
283 | { | ||
284 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
285 | struct inode *inode = dentry->d_inode; | ||
286 | int mask, error = 0; | ||
287 | |||
288 | lock_kernel(); | ||
289 | |||
290 | /* | ||
291 | * Expand the file. Since inode_setattr() updates ->i_size | ||
292 | * before calling the ->truncate(), but FAT needs to fill the | ||
293 | * hole before it. | ||
294 | */ | ||
295 | if (attr->ia_valid & ATTR_SIZE) { | ||
296 | if (attr->ia_size > inode->i_size) { | ||
297 | error = fat_cont_expand(inode, attr->ia_size); | ||
298 | if (error || attr->ia_valid == ATTR_SIZE) | ||
299 | goto out; | ||
300 | attr->ia_valid &= ~ATTR_SIZE; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | error = inode_change_ok(inode, attr); | ||
305 | if (error) { | ||
306 | if (sbi->options.quiet) | ||
307 | error = 0; | ||
308 | goto out; | ||
309 | } | ||
310 | if (((attr->ia_valid & ATTR_UID) && | ||
311 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
312 | ((attr->ia_valid & ATTR_GID) && | ||
313 | (attr->ia_gid != sbi->options.fs_gid))) | ||
314 | error = -EPERM; | ||
315 | |||
316 | if (error) { | ||
317 | if (sbi->options.quiet) | ||
318 | error = 0; | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | if (attr->ia_valid & ATTR_MODE) { | ||
323 | error = fat_check_mode(sbi, attr->ia_mode); | ||
324 | if (error != 0 && !sbi->options.quiet) | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | error = inode_setattr(inode, attr); | ||
329 | if (error) | ||
330 | goto out; | ||
331 | |||
332 | if (S_ISDIR(inode->i_mode)) | ||
333 | mask = sbi->options.fs_dmask; | ||
334 | else | ||
335 | mask = sbi->options.fs_fmask; | ||
336 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
337 | out: | ||
338 | unlock_kernel(); | ||
339 | return error; | ||
340 | } | ||
341 | EXPORT_SYMBOL_GPL(fat_setattr); | ||
342 | |||
358 | const struct inode_operations fat_file_inode_operations = { | 343 | const struct inode_operations fat_file_inode_operations = { |
359 | .truncate = fat_truncate, | 344 | .truncate = fat_truncate, |
360 | .setattr = fat_notify_change, | 345 | .setattr = fat_setattr, |
361 | .getattr = fat_getattr, | 346 | .getattr = fat_getattr, |
362 | }; | 347 | }; |