diff options
| author | Miklos Szeredi <mszeredi@suse.cz> | 2008-07-01 09:01:27 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-07-26 20:53:26 -0400 |
| commit | e9b76fedc61235da80b6b7f81dfd67ec224dfb49 (patch) | |
| tree | 550aa17f359ac24b4d5720e8fa77f171d338bb25 | |
| parent | 9767d74957450da6365c363d69e3d02d605d7375 (diff) | |
[patch 2/4] vfs: utimes cleanup
Untange the mess that is do_utimes(). Add kerneldoc comment to
do_utimes().
CC: Ulrich Drepper <drepper@redhat.com>
CC: Michael Kerrisk <mtk.manpages@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/utimes.c | 114 |
1 files changed, 65 insertions, 49 deletions
diff --git a/fs/utimes.c b/fs/utimes.c index ecf8941ba34a..8e09dbdfd7f5 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
| @@ -48,54 +48,15 @@ static bool nsec_valid(long nsec) | |||
| 48 | return nsec >= 0 && nsec <= 999999999; | 48 | return nsec >= 0 && nsec <= 999999999; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | /* If times==NULL, set access and modification to current time, | 51 | static int utimes_common(struct path *path, struct timespec *times) |
| 52 | * must be owner or have write permission. | ||
| 53 | * Else, update from *times, must be owner or super user. | ||
| 54 | */ | ||
| 55 | long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) | ||
| 56 | { | 52 | { |
| 57 | int error; | 53 | int error; |
| 58 | struct nameidata nd; | ||
| 59 | struct dentry *dentry; | ||
| 60 | struct inode *inode; | ||
| 61 | struct iattr newattrs; | 54 | struct iattr newattrs; |
| 62 | struct file *f = NULL; | 55 | struct inode *inode = path->dentry->d_inode; |
| 63 | struct vfsmount *mnt; | ||
| 64 | |||
| 65 | error = -EINVAL; | ||
| 66 | if (times && (!nsec_valid(times[0].tv_nsec) || | ||
| 67 | !nsec_valid(times[1].tv_nsec))) { | ||
| 68 | goto out; | ||
| 69 | } | ||
| 70 | |||
| 71 | if (flags & ~AT_SYMLINK_NOFOLLOW) | ||
| 72 | goto out; | ||
| 73 | |||
| 74 | if (filename == NULL && dfd != AT_FDCWD) { | ||
| 75 | error = -EINVAL; | ||
| 76 | if (flags & AT_SYMLINK_NOFOLLOW) | ||
| 77 | goto out; | ||
| 78 | |||
| 79 | error = -EBADF; | ||
| 80 | f = fget(dfd); | ||
| 81 | if (!f) | ||
| 82 | goto out; | ||
| 83 | dentry = f->f_path.dentry; | ||
| 84 | mnt = f->f_path.mnt; | ||
| 85 | } else { | ||
| 86 | error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd); | ||
| 87 | if (error) | ||
| 88 | goto out; | ||
| 89 | |||
| 90 | dentry = nd.path.dentry; | ||
| 91 | mnt = nd.path.mnt; | ||
| 92 | } | ||
| 93 | |||
| 94 | inode = dentry->d_inode; | ||
| 95 | 56 | ||
| 96 | error = mnt_want_write(mnt); | 57 | error = mnt_want_write(path->mnt); |
| 97 | if (error) | 58 | if (error) |
| 98 | goto dput_and_out; | 59 | goto out; |
| 99 | 60 | ||
| 100 | if (times && times[0].tv_nsec == UTIME_NOW && | 61 | if (times && times[0].tv_nsec == UTIME_NOW && |
| 101 | times[1].tv_nsec == UTIME_NOW) | 62 | times[1].tv_nsec == UTIME_NOW) |
| @@ -145,15 +106,70 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
| 145 | } | 106 | } |
| 146 | } | 107 | } |
| 147 | mutex_lock(&inode->i_mutex); | 108 | mutex_lock(&inode->i_mutex); |
| 148 | error = notify_change(dentry, &newattrs); | 109 | error = notify_change(path->dentry, &newattrs); |
| 149 | mutex_unlock(&inode->i_mutex); | 110 | mutex_unlock(&inode->i_mutex); |
| 111 | |||
| 150 | mnt_drop_write_and_out: | 112 | mnt_drop_write_and_out: |
| 151 | mnt_drop_write(mnt); | 113 | mnt_drop_write(path->mnt); |
| 152 | dput_and_out: | 114 | out: |
| 153 | if (f) | 115 | return error; |
| 154 | fput(f); | 116 | } |
| 155 | else | 117 | |
| 118 | /* | ||
| 119 | * do_utimes - change times on filename or file descriptor | ||
| 120 | * @dfd: open file descriptor, -1 or AT_FDCWD | ||
| 121 | * @filename: path name or NULL | ||
| 122 | * @times: new times or NULL | ||
| 123 | * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) | ||
| 124 | * | ||
| 125 | * If filename is NULL and dfd refers to an open file, then operate on | ||
| 126 | * the file. Otherwise look up filename, possibly using dfd as a | ||
| 127 | * starting point. | ||
| 128 | * | ||
| 129 | * If times==NULL, set access and modification to current time, | ||
| 130 | * must be owner or have write permission. | ||
| 131 | * Else, update from *times, must be owner or super user. | ||
| 132 | */ | ||
| 133 | long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) | ||
| 134 | { | ||
| 135 | int error = -EINVAL; | ||
| 136 | |||
| 137 | if (times && (!nsec_valid(times[0].tv_nsec) || | ||
| 138 | !nsec_valid(times[1].tv_nsec))) { | ||
| 139 | goto out; | ||
| 140 | } | ||
| 141 | |||
| 142 | if (flags & ~AT_SYMLINK_NOFOLLOW) | ||
| 143 | goto out; | ||
| 144 | |||
| 145 | if (filename == NULL && dfd != AT_FDCWD) { | ||
| 146 | struct file *file; | ||
| 147 | |||
| 148 | if (flags & AT_SYMLINK_NOFOLLOW) | ||
| 149 | goto out; | ||
| 150 | |||
| 151 | file = fget(dfd); | ||
| 152 | error = -EBADF; | ||
| 153 | if (!file) | ||
| 154 | goto out; | ||
| 155 | |||
| 156 | error = utimes_common(&file->f_path, times); | ||
| 157 | fput(file); | ||
| 158 | } else { | ||
| 159 | struct nameidata nd; | ||
| 160 | int lookup_flags = 0; | ||
| 161 | |||
| 162 | if (!(flags & AT_SYMLINK_NOFOLLOW)) | ||
| 163 | lookup_flags |= LOOKUP_FOLLOW; | ||
| 164 | |||
| 165 | error = __user_walk_fd(dfd, filename, lookup_flags, &nd); | ||
| 166 | if (error) | ||
| 167 | goto out; | ||
| 168 | |||
| 169 | error = utimes_common(&nd.path, times); | ||
| 156 | path_put(&nd.path); | 170 | path_put(&nd.path); |
| 171 | } | ||
| 172 | |||
| 157 | out: | 173 | out: |
| 158 | return error; | 174 | return error; |
| 159 | } | 175 | } |
