Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 54765
b: refs/heads/master
c: 1c710c8
h: refs/heads/master
i:
  54763: ba7f124
v: v3
  • Loading branch information
Ulrich Drepper authored and Linus Torvalds committed May 8, 2007
1 parent a2d4d27 commit e711fe7
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 76 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ade5fb818fb1861fd5f84619c761920ade762b5d
refs/heads/master: 1c710c896eb461895d3c399e15bb5f20b39c9073
14 changes: 12 additions & 2 deletions trunk/arch/alpha/kernel/osf_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,15 +953,25 @@ osf_setitimer(int which, struct itimerval32 __user *in, struct itimerval32 __use
asmlinkage int
osf_utimes(char __user *filename, struct timeval32 __user *tvs)
{
struct timeval ktvs[2];
struct timespec tv[2];

if (tvs) {
struct timeval ktvs[2];
if (get_tv32(&ktvs[0], &tvs[0]) ||
get_tv32(&ktvs[1], &tvs[1]))
return -EFAULT;

if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
return -EINVAL;

tv[0].tv_sec = ktvs[0].tv_sec;
tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
tv[1].tv_sec = ktvs[1].tv_sec;
tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
}

return do_utimes(AT_FDCWD, filename, tvs ? ktvs : NULL);
return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
}

#define MAX_SELECT_SECONDS \
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/i386/kernel/syscall_table.S
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,4 @@ ENTRY(sys_call_table)
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
14 changes: 12 additions & 2 deletions trunk/arch/sparc64/kernel/sys_sparc32.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,15 +775,25 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
asmlinkage long sys32_utimes(char __user *filename,
struct compat_timeval __user *tvs)
{
struct timeval ktvs[2];
struct timespec tv[2];

if (tvs) {
struct timeval ktvs[2];
if (get_tv32(&ktvs[0], tvs) ||
get_tv32(&ktvs[1], 1+tvs))
return -EFAULT;

if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
return -EINVAL;

tv[0].tv_sec = ktvs[0].tv_sec;
tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
tv[1].tv_sec = ktvs[1].tv_sec;
tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
}

return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL));
return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL);
}

/* These are here just in case some old sparc32 binary calls it. */
Expand Down
3 changes: 2 additions & 1 deletion trunk/arch/x86_64/ia32/ia32entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -710,9 +710,10 @@ ia32_sys_call_table:
.quad compat_sys_get_robust_list
.quad sys_splice
.quad sys_sync_file_range
.quad sys_tee
.quad sys_tee /* 315 */
.quad compat_sys_vmsplice
.quad compat_sys_move_pages
.quad sys_getcpu
.quad sys_epoll_pwait
.quad compat_sys_utimensat /* 320 */
ia32_syscall_end:
43 changes: 35 additions & 8 deletions trunk/fs/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,30 +77,57 @@ int compat_printk(const char *fmt, ...)
*/
asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
{
struct timeval tv[2];
struct timespec tv[2];

if (t) {
if (get_user(tv[0].tv_sec, &t->actime) ||
get_user(tv[1].tv_sec, &t->modtime))
return -EFAULT;
tv[0].tv_usec = 0;
tv[1].tv_usec = 0;
tv[0].tv_nsec = 0;
tv[1].tv_nsec = 0;
}
return do_utimes(AT_FDCWD, filename, t ? tv : NULL);
return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
}

asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename, struct compat_timespec __user *t, int flags)
{
struct timespec tv[2];

if (t) {
if (get_compat_timespec(&tv[0], &t[0]) ||
get_compat_timespec(&tv[1], &t[1]))
return -EFAULT;

if ((tv[0].tv_nsec == UTIME_OMIT || tv[0].tv_nsec == UTIME_NOW)
&& tv[0].tv_sec != 0)
return -EINVAL;
if ((tv[1].tv_nsec == UTIME_OMIT || tv[1].tv_nsec == UTIME_NOW)
&& tv[1].tv_sec != 0)
return -EINVAL;

if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
return 0;
}
return do_utimes(dfd, filename, t ? tv : NULL, flags);
}

asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, struct compat_timeval __user *t)
{
struct timeval tv[2];
struct timespec tv[2];

if (t) {
if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
get_user(tv[0].tv_usec, &t[0].tv_usec) ||
get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
get_user(tv[1].tv_sec, &t[1].tv_sec) ||
get_user(tv[1].tv_usec, &t[1].tv_usec))
get_user(tv[1].tv_nsec, &t[1].tv_usec))
return -EFAULT;
if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
return -EINVAL;
tv[0].tv_nsec *= 1000;
tv[1].tv_nsec *= 1000;
}
return do_utimes(dfd, filename, t ? tv : NULL);
return do_utimes(dfd, filename, t ? tv : NULL, 0);
}

asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
Expand Down
162 changes: 102 additions & 60 deletions trunk/fs/utimes.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include <linux/compiler.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/linkage.h>
#include <linux/namei.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/utime.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
Expand All @@ -20,54 +22,18 @@
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
{
int error;
struct nameidata nd;
struct inode * inode;
struct iattr newattrs;
struct timespec tv[2];

error = user_path_walk(filename, &nd);
if (error)
goto out;
inode = nd.dentry->d_inode;

error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;

/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (times) {
error = -EPERM;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
goto dput_and_out;

error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
newattrs.ia_atime.tv_nsec = 0;
if (!error)
error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
newattrs.ia_mtime.tv_nsec = 0;
if (error)
goto dput_and_out;

newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
error = -EACCES;
if (IS_IMMUTABLE(inode))
goto dput_and_out;

if (current->fsuid != inode->i_uid &&
(error = vfs_permission(&nd, MAY_WRITE)) != 0)
goto dput_and_out;
if (get_user(tv[0].tv_sec, &times->actime) ||
get_user(tv[1].tv_sec, &times->modtime))
return -EFAULT;
tv[0].tv_nsec = 0;
tv[1].tv_nsec = 0;
}
mutex_lock(&inode->i_mutex);
error = notify_change(nd.dentry, &newattrs);
mutex_unlock(&inode->i_mutex);
dput_and_out:
path_release(&nd);
out:
return error;
return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
}

#endif
Expand All @@ -76,18 +42,38 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
long do_utimes(int dfd, char __user *filename, struct timeval *times)
long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
{
int error;
struct nameidata nd;
struct inode * inode;
struct dentry *dentry;
struct inode *inode;
struct iattr newattrs;
struct file *f = NULL;

error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);

if (error)
error = -EINVAL;
if (flags & ~AT_SYMLINK_NOFOLLOW)
goto out;
inode = nd.dentry->d_inode;

if (filename == NULL && dfd != AT_FDCWD) {
error = -EINVAL;
if (flags & AT_SYMLINK_NOFOLLOW)
goto out;

error = -EBADF;
f = fget(dfd);
if (!f)
goto out;
dentry = f->f_path.dentry;
} else {
error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
if (error)
goto out;

dentry = nd.dentry;
}

inode = dentry->d_inode;

error = -EROFS;
if (IS_RDONLY(inode))
Expand All @@ -100,11 +86,21 @@ long do_utimes(int dfd, char __user *filename, struct timeval *times)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
goto dput_and_out;

newattrs.ia_atime.tv_sec = times[0].tv_sec;
newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
newattrs.ia_mtime.tv_sec = times[1].tv_sec;
newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
if (times[0].tv_nsec == UTIME_OMIT)
newattrs.ia_valid &= ~ATTR_ATIME;
else if (times[0].tv_nsec != UTIME_NOW) {
newattrs.ia_atime.tv_sec = times[0].tv_sec;
newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
newattrs.ia_valid |= ATTR_ATIME_SET;
}

if (times[1].tv_nsec == UTIME_OMIT)
newattrs.ia_valid &= ~ATTR_MTIME;
else if (times[1].tv_nsec != UTIME_NOW) {
newattrs.ia_mtime.tv_sec = times[1].tv_sec;
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
newattrs.ia_valid |= ATTR_MTIME_SET;
}
} else {
error = -EACCES;
if (IS_IMMUTABLE(inode))
Expand All @@ -115,21 +111,67 @@ long do_utimes(int dfd, char __user *filename, struct timeval *times)
goto dput_and_out;
}
mutex_lock(&inode->i_mutex);
error = notify_change(nd.dentry, &newattrs);
error = notify_change(dentry, &newattrs);
mutex_unlock(&inode->i_mutex);
dput_and_out:
path_release(&nd);
if (f)
fput(f);
else
path_release(&nd);
out:
return error;
}

asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __user *utimes, int flags)
{
struct timespec tstimes[2];

if (utimes) {
if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
return -EFAULT;
if ((tstimes[0].tv_nsec == UTIME_OMIT ||
tstimes[0].tv_nsec == UTIME_NOW) &&
tstimes[0].tv_sec != 0)
return -EINVAL;
if ((tstimes[1].tv_nsec == UTIME_OMIT ||
tstimes[1].tv_nsec == UTIME_NOW) &&
tstimes[1].tv_sec != 0)
return -EINVAL;

/* Nothing to do, we must not even check the path. */
if (tstimes[0].tv_nsec == UTIME_OMIT &&
tstimes[1].tv_nsec == UTIME_OMIT)
return 0;
}

return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
}

asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
{
struct timeval times[2];
struct timespec tstimes[2];

if (utimes) {
if (copy_from_user(&times, utimes, sizeof(times)))
return -EFAULT;

/* This test is needed to catch all invalid values. If we
would test only in do_utimes we would miss those invalid
values truncated by the multiplication with 1000. Note
that we also catch UTIME_{NOW,OMIT} here which are only
valid for utimensat. */
if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
return -EINVAL;

tstimes[0].tv_sec = times[0].tv_sec;
tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
tstimes[1].tv_sec = times[1].tv_sec;
tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
}

if (utimes && copy_from_user(&times, utimes, sizeof(times)))
return -EFAULT;
return do_utimes(dfd, filename, utimes ? times : NULL);
return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
}

asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
Expand Down
3 changes: 2 additions & 1 deletion trunk/include/asm-i386/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,11 @@
#define __NR_move_pages 317
#define __NR_getcpu 318
#define __NR_epoll_pwait 319
#define __NR_utimensat 320

#ifdef __KERNEL__

#define NR_syscalls 320
#define NR_syscalls 321

#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/asm-x86_64/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,8 @@ __SYSCALL(__NR_sync_file_range, sys_sync_file_range)
__SYSCALL(__NR_vmsplice, sys_vmsplice)
#define __NR_move_pages 279
__SYSCALL(__NR_move_pages, sys_move_pages)
#define __NR_utimensat 280
__SYSCALL(__NR_utimensat, sys_utimensat)

#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/stat.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)

#define UTIME_NOW ((1l << 30) - 1l)
#define UTIME_OMIT ((1l << 30) - 2l)

#include <linux/types.h>
#include <linux/time.h>

Expand Down
Loading

0 comments on commit e711fe7

Please sign in to comment.