| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #ifndef _LINUX_STAT_H
 | 
					
						
							|  |  |  | #define _LINUX_STAT_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/stat.h>
 | 
					
						
							| 
									
										
										
										
											2012-10-13 10:46:48 +01:00
										 |  |  | #include <uapi/linux/stat.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												utimensat implementation
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>
											
										 
											2007-05-08 00:33:25 -07:00
										 |  |  | #define UTIME_NOW	((1l << 30) - 1l)
 | 
					
						
							|  |  |  | #define UTIME_OMIT	((1l << 30) - 2l)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  | #include <linux/time.h>
 | 
					
						
							| 
									
										
										
										
											2012-02-09 09:10:30 -08:00
										 |  |  | #include <linux/uidgid.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct kstat { | 
					
						
							| 
									
										
										
										
											2006-10-03 01:13:46 -07:00
										 |  |  | 	u64		ino; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	dev_t		dev; | 
					
						
							|  |  |  | 	umode_t		mode; | 
					
						
							|  |  |  | 	unsigned int	nlink; | 
					
						
							| 
									
										
										
										
											2012-02-09 09:10:30 -08:00
										 |  |  | 	kuid_t		uid; | 
					
						
							|  |  |  | 	kgid_t		gid; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	dev_t		rdev; | 
					
						
							|  |  |  | 	loff_t		size; | 
					
						
							|  |  |  | 	struct timespec  atime; | 
					
						
							|  |  |  | 	struct timespec	mtime; | 
					
						
							|  |  |  | 	struct timespec	ctime; | 
					
						
							|  |  |  | 	unsigned long	blksize; | 
					
						
							| 
									
										
										
										
											2006-03-26 01:37:51 -08:00
										 |  |  | 	unsigned long long	blocks; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |