mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
![Ulrich Drepper](/assets/img/avatar_default.png)
Implement utimensat(2) which is an extension to futimesat(2) in that it a) supports nano-second resolution for the timestamps b) allows to selectively ignore the atime/mtime value c) allows to selectively use the current time for either atime or mtime d) supports changing the atime/mtime of a symlink itself along the lines of the BSD lutimes(3) functions For this change the internally used do_utimes() functions was changed to accept a timespec time value and an additional flags parameter. Additionally the sys_utime function was changed to match compat_sys_utime which already use do_utimes instead of duplicating the work. Also, the completely missing futimensat() functionality is added. We have such a function in glibc but we have to resort to using /proc/self/fd/* which not everybody likes (chroot etc). Test application (the syscall number will need per-arch editing): #include <errno.h> #include <fcntl.h> #include <time.h> #include <sys/time.h> #include <stddef.h> #include <syscall.h> #define __NR_utimensat 280 #define UTIME_NOW ((1l << 30) - 1l) #define UTIME_OMIT ((1l << 30) - 2l) int main(void) { int status = 0; int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666); if (fd == -1) error (1, errno, "failed to create test file \"ttt\""); struct stat64 st1; if (fstat64 (fd, &st1) != 0) error (1, errno, "fstat failed"); struct timespec t[2]; t[0].tv_sec = 0; t[0].tv_nsec = 0; t[1].tv_sec = 0; t[1].tv_nsec = 0; if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0) error (1, errno, "utimensat failed"); struct stat64 st2; if (fstat64 (fd, &st2) != 0) error (1, errno, "fstat failed"); if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0) { puts ("atim not reset to zero"); status = 1; } if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0) { puts ("mtim not reset to zero"); status = 1; } if (status != 0) goto out; t[0] = st1.st_atim; t[1].tv_sec = 0; t[1].tv_nsec = UTIME_OMIT; if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0) error (1, errno, "utimensat failed"); if (fstat64 (fd, &st2) != 0) error (1, errno, "fstat failed"); if (st2.st_atim.tv_sec != st1.st_atim.tv_sec || st2.st_atim.tv_nsec != st1.st_atim.tv_nsec) { puts ("atim not set"); status = 1; } if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0) { puts ("mtim changed from zero"); status = 1; } if (status != 0) goto out; t[0].tv_sec = 0; t[0].tv_nsec = UTIME_OMIT; t[1] = st1.st_mtim; if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0) error (1, errno, "utimensat failed"); if (fstat64 (fd, &st2) != 0) error (1, errno, "fstat failed"); if (st2.st_atim.tv_sec != st1.st_atim.tv_sec || st2.st_atim.tv_nsec != st1.st_atim.tv_nsec) { puts ("mtim changed from original time"); status = 1; } if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec || st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec) { puts ("mtim not set"); status = 1; } if (status != 0) goto out; sleep (2); t[0].tv_sec = 0; t[0].tv_nsec = UTIME_NOW; t[1].tv_sec = 0; t[1].tv_nsec = UTIME_NOW; if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0) error (1, errno, "utimensat failed"); if (fstat64 (fd, &st2) != 0) error (1, errno, "fstat failed"); struct timeval tv; gettimeofday(&tv,NULL); if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec || st2.st_atim.tv_sec > tv.tv_sec) { puts ("atim not set to NOW"); status = 1; } if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec || st2.st_mtim.tv_sec > tv.tv_sec) { puts ("mtim not set to NOW"); status = 1; } if (symlink ("ttt", "tttsym") != 0) error (1, errno, "cannot create symlink"); t[0].tv_sec = 0; t[0].tv_nsec = 0; t[1].tv_sec = 0; t[1].tv_nsec = 0; if (syscall(__NR_utimensat, AT_FDCWD, "tttsym", t, AT_SYMLINK_NOFOLLOW) != 0) error (1, errno, "utimensat failed"); if (lstat64 ("tttsym", &st2) != 0) error (1, errno, "lstat failed"); if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0) { puts ("symlink atim not reset to zero"); status = 1; } if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0) { puts ("symlink mtim not reset to zero"); status = 1; } if (status != 0) goto out; t[0].tv_sec = 1; t[0].tv_nsec = 0; t[1].tv_sec = 1; t[1].tv_nsec = 0; if (syscall(__NR_utimensat, fd, NULL, t, 0) != 0) error (1, errno, "utimensat failed"); if (fstat64 (fd, &st2) != 0) error (1, errno, "fstat failed"); if (st2.st_atim.tv_sec != 1 || st2.st_atim.tv_nsec != 0) { puts ("atim not reset to one"); status = 1; } if (st2.st_mtim.tv_sec != 1 || st2.st_mtim.tv_nsec != 0) { puts ("mtim not reset to one"); status = 1; } if (status == 0) puts ("all OK"); out: close (fd); unlink ("ttt"); unlink ("tttsym"); return status; } [akpm@linux-foundation.org: add missing i386 syscall table entry] Signed-off-by: Ulrich Drepper <drepper@redhat.com> Cc: Alexey Dobriyan <adobriyan@openvz.org> Cc: Michael Kerrisk <mtk-manpages@gmx.net> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
80 lines
1.7 KiB
C
80 lines
1.7 KiB
C
#ifndef _LINUX_STAT_H
|
|
#define _LINUX_STAT_H
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
#include <asm/stat.h>
|
|
|
|
#endif
|
|
|
|
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
|
|
|
|
#define S_IFMT 00170000
|
|
#define S_IFSOCK 0140000
|
|
#define S_IFLNK 0120000
|
|
#define S_IFREG 0100000
|
|
#define S_IFBLK 0060000
|
|
#define S_IFDIR 0040000
|
|
#define S_IFCHR 0020000
|
|
#define S_IFIFO 0010000
|
|
#define S_ISUID 0004000
|
|
#define S_ISGID 0002000
|
|
#define S_ISVTX 0001000
|
|
|
|
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
|
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
|
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
|
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
|
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
|
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
|
|
|
#define S_IRWXU 00700
|
|
#define S_IRUSR 00400
|
|
#define S_IWUSR 00200
|
|
#define S_IXUSR 00100
|
|
|
|
#define S_IRWXG 00070
|
|
#define S_IRGRP 00040
|
|
#define S_IWGRP 00020
|
|
#define S_IXGRP 00010
|
|
|
|
#define S_IRWXO 00007
|
|
#define S_IROTH 00004
|
|
#define S_IWOTH 00002
|
|
#define S_IXOTH 00001
|
|
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
|
|
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
|
|
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
|
|
#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>
|
|
|
|
struct kstat {
|
|
u64 ino;
|
|
dev_t dev;
|
|
umode_t mode;
|
|
unsigned int nlink;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
dev_t rdev;
|
|
loff_t size;
|
|
struct timespec atime;
|
|
struct timespec mtime;
|
|
struct timespec ctime;
|
|
unsigned long blksize;
|
|
unsigned long long blocks;
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif
|