diff options
Diffstat (limited to 'fs/gfs2/ops_inode.c')
-rw-r--r-- | fs/gfs2/ops_inode.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 1c70fa5168d6..f8bd20baf99c 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -262,6 +262,44 @@ out_parent: | |||
262 | return error; | 262 | return error; |
263 | } | 263 | } |
264 | 264 | ||
265 | /* | ||
266 | * gfs2_unlink_ok - check to see that a inode is still in a directory | ||
267 | * @dip: the directory | ||
268 | * @name: the name of the file | ||
269 | * @ip: the inode | ||
270 | * | ||
271 | * Assumes that the lock on (at least) @dip is held. | ||
272 | * | ||
273 | * Returns: 0 if the parent/child relationship is correct, errno if it isn't | ||
274 | */ | ||
275 | |||
276 | static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, | ||
277 | const struct gfs2_inode *ip) | ||
278 | { | ||
279 | int error; | ||
280 | |||
281 | if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) | ||
282 | return -EPERM; | ||
283 | |||
284 | if ((dip->i_inode.i_mode & S_ISVTX) && | ||
285 | dip->i_inode.i_uid != current_fsuid() && | ||
286 | ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER)) | ||
287 | return -EPERM; | ||
288 | |||
289 | if (IS_APPEND(&dip->i_inode)) | ||
290 | return -EPERM; | ||
291 | |||
292 | error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); | ||
293 | if (error) | ||
294 | return error; | ||
295 | |||
296 | error = gfs2_dir_check(&dip->i_inode, name, ip); | ||
297 | if (error) | ||
298 | return error; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
265 | /** | 303 | /** |
266 | * gfs2_unlink - Unlink a file | 304 | * gfs2_unlink - Unlink a file |
267 | * @dir: The inode of the directory containing the file to unlink | 305 | * @dir: The inode of the directory containing the file to unlink |
@@ -473,6 +511,59 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
473 | } | 511 | } |
474 | 512 | ||
475 | /** | 513 | /** |
514 | * gfs2_rmdiri - Remove a directory | ||
515 | * @dip: The parent directory of the directory to be removed | ||
516 | * @name: The name of the directory to be removed | ||
517 | * @ip: The GFS2 inode of the directory to be removed | ||
518 | * | ||
519 | * Assumes Glocks on dip and ip are held | ||
520 | * | ||
521 | * Returns: errno | ||
522 | */ | ||
523 | |||
524 | static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, | ||
525 | struct gfs2_inode *ip) | ||
526 | { | ||
527 | struct qstr dotname; | ||
528 | int error; | ||
529 | |||
530 | if (ip->i_entries != 2) { | ||
531 | if (gfs2_consist_inode(ip)) | ||
532 | gfs2_dinode_print(ip); | ||
533 | return -EIO; | ||
534 | } | ||
535 | |||
536 | error = gfs2_dir_del(dip, name); | ||
537 | if (error) | ||
538 | return error; | ||
539 | |||
540 | error = gfs2_change_nlink(dip, -1); | ||
541 | if (error) | ||
542 | return error; | ||
543 | |||
544 | gfs2_str2qstr(&dotname, "."); | ||
545 | error = gfs2_dir_del(ip, &dotname); | ||
546 | if (error) | ||
547 | return error; | ||
548 | |||
549 | gfs2_str2qstr(&dotname, ".."); | ||
550 | error = gfs2_dir_del(ip, &dotname); | ||
551 | if (error) | ||
552 | return error; | ||
553 | |||
554 | /* It looks odd, but it really should be done twice */ | ||
555 | error = gfs2_change_nlink(ip, -1); | ||
556 | if (error) | ||
557 | return error; | ||
558 | |||
559 | error = gfs2_change_nlink(ip, -1); | ||
560 | if (error) | ||
561 | return error; | ||
562 | |||
563 | return error; | ||
564 | } | ||
565 | |||
566 | /** | ||
476 | * gfs2_rmdir - Remove a directory | 567 | * gfs2_rmdir - Remove a directory |
477 | * @dir: The parent directory of the directory to be removed | 568 | * @dir: The parent directory of the directory to be removed |
478 | * @dentry: The dentry of the directory to remove | 569 | * @dentry: The dentry of the directory to remove |
@@ -885,6 +976,61 @@ out: | |||
885 | } | 976 | } |
886 | 977 | ||
887 | /** | 978 | /** |
979 | * gfs2_readlinki - return the contents of a symlink | ||
980 | * @ip: the symlink's inode | ||
981 | * @buf: a pointer to the buffer to be filled | ||
982 | * @len: a pointer to the length of @buf | ||
983 | * | ||
984 | * If @buf is too small, a piece of memory is kmalloc()ed and needs | ||
985 | * to be freed by the caller. | ||
986 | * | ||
987 | * Returns: errno | ||
988 | */ | ||
989 | |||
990 | static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) | ||
991 | { | ||
992 | struct gfs2_holder i_gh; | ||
993 | struct buffer_head *dibh; | ||
994 | unsigned int x; | ||
995 | int error; | ||
996 | |||
997 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); | ||
998 | error = gfs2_glock_nq(&i_gh); | ||
999 | if (error) { | ||
1000 | gfs2_holder_uninit(&i_gh); | ||
1001 | return error; | ||
1002 | } | ||
1003 | |||
1004 | if (!ip->i_disksize) { | ||
1005 | gfs2_consist_inode(ip); | ||
1006 | error = -EIO; | ||
1007 | goto out; | ||
1008 | } | ||
1009 | |||
1010 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
1011 | if (error) | ||
1012 | goto out; | ||
1013 | |||
1014 | x = ip->i_disksize + 1; | ||
1015 | if (x > *len) { | ||
1016 | *buf = kmalloc(x, GFP_NOFS); | ||
1017 | if (!*buf) { | ||
1018 | error = -ENOMEM; | ||
1019 | goto out_brelse; | ||
1020 | } | ||
1021 | } | ||
1022 | |||
1023 | memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); | ||
1024 | *len = x; | ||
1025 | |||
1026 | out_brelse: | ||
1027 | brelse(dibh); | ||
1028 | out: | ||
1029 | gfs2_glock_dq_uninit(&i_gh); | ||
1030 | return error; | ||
1031 | } | ||
1032 | |||
1033 | /** | ||
888 | * gfs2_readlink - Read the value of a symlink | 1034 | * gfs2_readlink - Read the value of a symlink |
889 | * @dentry: the symlink | 1035 | * @dentry: the symlink |
890 | * @buf: the buffer to read the symlink data into | 1036 | * @buf: the buffer to read the symlink data into |