diff options
-rw-r--r-- | fs/ext4/namei.c | 11 | ||||
-rw-r--r-- | fs/namei.c | 21 | ||||
-rw-r--r-- | include/uapi/linux/fs.h | 2 |
3 files changed, 26 insertions, 8 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d050e043e884..5f19171b3e1f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -3204,6 +3204,16 @@ end_rename: | |||
3204 | return retval; | 3204 | return retval; |
3205 | } | 3205 | } |
3206 | 3206 | ||
3207 | static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry, | ||
3208 | struct inode *new_dir, struct dentry *new_dentry, | ||
3209 | unsigned int flags) | ||
3210 | { | ||
3211 | if (flags & ~RENAME_NOREPLACE) | ||
3212 | return -EINVAL; | ||
3213 | |||
3214 | return ext4_rename(old_dir, old_dentry, new_dir, new_dentry); | ||
3215 | } | ||
3216 | |||
3207 | /* | 3217 | /* |
3208 | * directories can handle most operations... | 3218 | * directories can handle most operations... |
3209 | */ | 3219 | */ |
@@ -3218,6 +3228,7 @@ const struct inode_operations ext4_dir_inode_operations = { | |||
3218 | .mknod = ext4_mknod, | 3228 | .mknod = ext4_mknod, |
3219 | .tmpfile = ext4_tmpfile, | 3229 | .tmpfile = ext4_tmpfile, |
3220 | .rename = ext4_rename, | 3230 | .rename = ext4_rename, |
3231 | .rename2 = ext4_rename2, | ||
3221 | .setattr = ext4_setattr, | 3232 | .setattr = ext4_setattr, |
3222 | .setxattr = generic_setxattr, | 3233 | .setxattr = generic_setxattr, |
3223 | .getxattr = generic_getxattr, | 3234 | .getxattr = generic_getxattr, |
diff --git a/fs/namei.c b/fs/namei.c index ab4e48c4a80a..0e9d186b7f77 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -4142,7 +4142,7 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, | |||
4142 | bool should_retry = false; | 4142 | bool should_retry = false; |
4143 | int error; | 4143 | int error; |
4144 | 4144 | ||
4145 | if (flags) | 4145 | if (flags & ~RENAME_NOREPLACE) |
4146 | return -EINVAL; | 4146 | return -EINVAL; |
4147 | 4147 | ||
4148 | retry: | 4148 | retry: |
@@ -4168,6 +4168,8 @@ retry: | |||
4168 | goto exit2; | 4168 | goto exit2; |
4169 | 4169 | ||
4170 | new_dir = newnd.path.dentry; | 4170 | new_dir = newnd.path.dentry; |
4171 | if (flags & RENAME_NOREPLACE) | ||
4172 | error = -EEXIST; | ||
4171 | if (newnd.last_type != LAST_NORM) | 4173 | if (newnd.last_type != LAST_NORM) |
4172 | goto exit2; | 4174 | goto exit2; |
4173 | 4175 | ||
@@ -4190,22 +4192,25 @@ retry_deleg: | |||
4190 | error = -ENOENT; | 4192 | error = -ENOENT; |
4191 | if (d_is_negative(old_dentry)) | 4193 | if (d_is_negative(old_dentry)) |
4192 | goto exit4; | 4194 | goto exit4; |
4195 | new_dentry = lookup_hash(&newnd); | ||
4196 | error = PTR_ERR(new_dentry); | ||
4197 | if (IS_ERR(new_dentry)) | ||
4198 | goto exit4; | ||
4199 | error = -EEXIST; | ||
4200 | if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) | ||
4201 | goto exit5; | ||
4193 | /* unless the source is a directory trailing slashes give -ENOTDIR */ | 4202 | /* unless the source is a directory trailing slashes give -ENOTDIR */ |
4194 | if (!d_is_dir(old_dentry)) { | 4203 | if (!d_is_dir(old_dentry)) { |
4195 | error = -ENOTDIR; | 4204 | error = -ENOTDIR; |
4196 | if (oldnd.last.name[oldnd.last.len]) | 4205 | if (oldnd.last.name[oldnd.last.len]) |
4197 | goto exit4; | 4206 | goto exit5; |
4198 | if (newnd.last.name[newnd.last.len]) | 4207 | if (newnd.last.name[newnd.last.len]) |
4199 | goto exit4; | 4208 | goto exit5; |
4200 | } | 4209 | } |
4201 | /* source should not be ancestor of target */ | 4210 | /* source should not be ancestor of target */ |
4202 | error = -EINVAL; | 4211 | error = -EINVAL; |
4203 | if (old_dentry == trap) | 4212 | if (old_dentry == trap) |
4204 | goto exit4; | 4213 | goto exit5; |
4205 | new_dentry = lookup_hash(&newnd); | ||
4206 | error = PTR_ERR(new_dentry); | ||
4207 | if (IS_ERR(new_dentry)) | ||
4208 | goto exit4; | ||
4209 | /* target should not be an ancestor of source */ | 4214 | /* target should not be an ancestor of source */ |
4210 | error = -ENOTEMPTY; | 4215 | error = -ENOTEMPTY; |
4211 | if (new_dentry == trap) | 4216 | if (new_dentry == trap) |
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 6c28b61bb690..9250f4dd7d96 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h | |||
@@ -35,6 +35,8 @@ | |||
35 | #define SEEK_HOLE 4 /* seek to the next hole */ | 35 | #define SEEK_HOLE 4 /* seek to the next hole */ |
36 | #define SEEK_MAX SEEK_HOLE | 36 | #define SEEK_MAX SEEK_HOLE |
37 | 37 | ||
38 | #define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */ | ||
39 | |||
38 | struct fstrim_range { | 40 | struct fstrim_range { |
39 | __u64 start; | 41 | __u64 start; |
40 | __u64 len; | 42 | __u64 len; |