Commit 9d4b74ae authored by Christoph Hellwig's avatar Christoph Hellwig
Browse files

fs: refactor do_utimes



Split out one helper each for path vs fd based operations.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 863b67e1
Loading
Loading
Loading
Loading
+54 −46
Original line number Diff line number Diff line
@@ -70,59 +70,27 @@ out:
	return error;
}

/*
 * do_utimes - change times on filename or file descriptor
 * @dfd: open file descriptor, -1 or AT_FDCWD
 * @filename: path name or NULL
 * @times: new times or NULL
 * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
 *
 * If filename is NULL and dfd refers to an open file, then operate on
 * the file.  Otherwise look up filename, possibly using dfd as a
 * starting point.
 *
 * If times==NULL, set access and modification to current time,
 * must be owner or have write permission.
 * Else, update from *times, must be owner or super user.
 */
long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
	       int flags)
static int do_utimes_path(int dfd, const char __user *filename,
		struct timespec64 *times, int flags)
{
	int error = -EINVAL;

	if (times && (!nsec_valid(times[0].tv_nsec) ||
		      !nsec_valid(times[1].tv_nsec))) {
		goto out;
	}
	struct path path;
	int lookup_flags = 0, error;

	if (times &&
	    (!nsec_valid(times[0].tv_nsec) || !nsec_valid(times[1].tv_nsec)))
		return -EINVAL;
	if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
		goto out;

	if (filename == NULL && dfd != AT_FDCWD) {
		struct fd f;

		if (flags)
			goto out;

		f = fdget(dfd);
		error = -EBADF;
		if (!f.file)
			goto out;

		error = utimes_common(&f.file->f_path, times);
		fdput(f);
	} else {
		struct path path;
		int lookup_flags = 0;
		return -EINVAL;

	if (!(flags & AT_SYMLINK_NOFOLLOW))
		lookup_flags |= LOOKUP_FOLLOW;
	if (flags & AT_EMPTY_PATH)
		lookup_flags |= LOOKUP_EMPTY;

retry:
	error = user_path_at(dfd, filename, lookup_flags, &path);
	if (error)
			goto out;
		return error;

	error = utimes_common(&path, times);
	path_put(&path);
@@ -130,12 +98,52 @@ retry:
		lookup_flags |= LOOKUP_REVAL;
		goto retry;
	}

	return error;
}

out:
static int do_utimes_fd(int fd, struct timespec64 *times, int flags)
{
	struct fd f;
	int error;

	if (times &&
	    (!nsec_valid(times[0].tv_nsec) || !nsec_valid(times[1].tv_nsec)))
		return -EINVAL;
	if (flags)
		return -EINVAL;

	f = fdget(fd);
	if (!f.file)
		return -EBADF;
	error = utimes_common(&f.file->f_path, times);
	fdput(f);
	return error;
}

/*
 * do_utimes - change times on filename or file descriptor
 * @dfd: open file descriptor, -1 or AT_FDCWD
 * @filename: path name or NULL
 * @times: new times or NULL
 * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
 *
 * If filename is NULL and dfd refers to an open file, then operate on
 * the file.  Otherwise look up filename, possibly using dfd as a
 * starting point.
 *
 * If times==NULL, set access and modification to current time,
 * must be owner or have write permission.
 * Else, update from *times, must be owner or super user.
 */
long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
	       int flags)
{
	if (filename == NULL && dfd != AT_FDCWD)
		return do_utimes_fd(dfd, times, flags);
	return do_utimes_path(dfd, filename, times, flags);
}

SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
		struct __kernel_timespec __user *, utimes, int, flags)
{