Files
kernel/include/linux
Ulrich Drepper 1c710c896e 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 11:15:18 -07:00
..
2007-05-01 16:11:57 +02:00
2007-05-08 11:15:16 -07:00
2007-04-30 22:17:15 -07:00
2007-02-20 17:10:15 -08:00
2007-05-07 12:12:55 -07:00
2007-01-30 08:26:45 -08:00
2007-02-20 17:10:14 -08:00
2007-05-08 11:15:15 -07:00
2007-05-07 12:13:00 -07:00
2007-05-07 12:13:00 -07:00
2007-05-08 11:15:04 -07:00
2007-05-08 11:15:03 -07:00
2007-04-27 10:57:31 -07:00
2007-05-01 09:11:12 +01:00
2007-02-09 17:39:36 -05:00
2007-02-11 11:18:07 -08:00
2007-05-07 12:12:58 -07:00
2007-05-03 13:17:25 -07:00
2007-03-27 09:05:15 -07:00
2007-05-06 20:38:28 -04:00
2007-05-08 11:15:04 -07:00
2007-04-28 11:01:07 -04:00
2007-04-19 14:56:12 +02:00
2007-03-16 00:59:29 -04:00
2007-04-07 10:03:43 -07:00
2007-05-01 23:26:34 +02:00
2007-05-05 22:03:49 +02:00
2007-04-25 22:30:01 -07:00
2007-04-25 22:29:10 -07:00
2007-04-25 22:24:41 -07:00
2007-04-25 22:29:10 -07:00
2007-05-08 11:15:09 -07:00
2007-04-25 22:25:52 -07:00
2007-05-07 12:13:00 -07:00
2007-04-25 22:29:49 -07:00
2007-05-03 10:52:32 +03:00
2007-02-17 19:17:37 +01:00
2007-05-03 10:52:22 +03:00
2007-05-07 12:12:53 -07:00
2007-01-23 00:34:54 -05:00
2007-05-04 17:59:07 -07:00
2007-05-07 12:12:59 -07:00
2007-05-08 11:15:05 -07:00
2007-05-08 11:15:05 -07:00
2007-05-05 14:15:32 -07:00
2007-03-12 16:31:50 -07:00
2007-05-08 11:15:14 -07:00
2007-03-27 08:55:47 +02:00
2007-04-17 16:36:26 -07:00
2007-04-30 16:40:41 -07:00
2007-05-08 11:15:00 -07:00
2007-05-08 11:14:57 -07:00
2007-01-11 18:18:21 -08:00
2007-05-07 12:12:54 -07:00
2007-02-11 10:51:28 -08:00
2007-05-07 12:12:58 -07:00
2007-05-07 12:12:50 -07:00
2007-05-03 03:16:20 -07:00
2007-05-07 12:12:54 -07:00
2007-02-20 17:10:14 -08:00
2007-02-20 17:10:14 -08:00
2007-05-08 11:14:58 -07:00
2007-05-08 11:15:18 -07:00
2007-05-07 12:12:59 -07:00
2007-02-12 09:48:41 -08:00
2007-02-11 10:51:18 -08:00
2007-02-20 17:10:13 -08:00
2007-05-08 11:15:18 -07:00
2007-05-08 11:15:05 -07:00
2007-02-16 08:13:56 -08:00
2007-03-05 07:57:51 -08:00
2007-05-07 12:12:58 -07:00
2007-02-11 10:51:25 -08:00
2007-02-11 11:18:05 -08:00
2007-05-04 12:55:39 -07:00