linux/fs
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
..
9p header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
adfs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
affs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
afs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
autofs [PATCH] Mark struct super_operations const 2007-02-12 09:48:47 -08:00
autofs4 header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
befs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
bfs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
cifs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
coda slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
configfs remove "struct subsystem" as it is no longer needed 2007-05-02 18:57:59 -07:00
cramfs mm: make read_cache_page synchronous 2007-05-07 12:12:51 -07:00
debugfs remove "struct subsystem" as it is no longer needed 2007-05-02 18:57:59 -07:00
devpts devpts: add fsnotify create event 2007-05-08 11:14:59 -07:00
dlm Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw 2007-05-07 12:26:27 -07:00
ecryptfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
efs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
exportfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
ext2 ext3: copy i_flags to inode flags on write 2007-05-08 11:15:13 -07:00
ext3 ext3: copy i_flags to inode flags on write 2007-05-08 11:15:12 -07:00
ext4 header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
fat fat: fix VFAT compat ioctls on 64-bit systems 2007-05-08 11:15:14 -07:00
freevxfs freevxfs: possible null pointer dereference fix 2007-05-08 11:14:59 -07:00
fuse add filesystem subtype support 2007-05-08 11:15:01 -07:00
gfs2 header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
hfs is_power_of_2 in fs/hfs 2007-05-08 11:14:59 -07:00
hfsplus is_power_of_2 in fs/hfs 2007-05-08 11:14:59 -07:00
hostfs uml: hostfs style fixes 2007-05-08 11:14:57 -07:00
hpfs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
hppfs [PATCH] Mark struct super_operations const 2007-02-12 09:48:47 -08:00
hugetlbfs hugetlbfs: add NULL check in hugetlb_zero_setup() 2007-05-07 12:12:57 -07:00
isofs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
jbd jbd: check for error returned by kthread_create on creating journal thread 2007-05-08 11:15:13 -07:00
jbd2 jbd: check for error returned by kthread_create on creating journal thread 2007-05-08 11:15:13 -07:00
jffs2 slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
jfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
lockd header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
minix slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
msdos [PATCH] mark struct inode_operations const 2 2007-02-12 09:48:46 -08:00
ncpfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
nfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
nfs_common [PATCH] nfs_common endianness annotations 2006-10-20 10:26:41 -07:00
nfsd header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
nls [PATCH] fs: make nls_cp936.c handle some U00XY characters and U20AC correctly 2006-12-07 08:39:46 -08:00
ntfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
ocfs2 header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
openpromfs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
partitions partition: add support for sysv68 partitions 2007-05-08 11:15:09 -07:00
proc procfs: use simple_read_from_buffer() 2007-05-08 11:15:14 -07:00
qnx4 slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
ramfs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
reiserfs reiserfs: use __set_current_state() 2007-05-08 11:15:13 -07:00
romfs slab allocators: Remove SLAB_DEBUG_INITIAL flag 2007-05-07 12:12:57 -07:00
smbfs smbfs: remove unnecessary allow_signal 2007-05-08 11:15:11 -07:00
sysfs remove "struct subsystem" as it is no longer needed 2007-05-02 18:57:59 -07:00
sysv header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
udf udf: decrement correct link count in udf_rmdir 2007-05-08 11:15:14 -07:00
ufs header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
vfat [PATCH] mark struct inode_operations const 3 2007-02-12 09:48:46 -08:00
xfs mm: move common segment checks to separate helper function 2007-05-08 11:14:57 -07:00
aio.c KMEM_CACHE(): simplify slab cache creation 2007-05-07 12:12:55 -07:00
attr.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
bad_inode.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_aout.c [PATCH] VFS: change struct file to use struct path 2006-12-08 08:28:41 -08:00
binfmt_elf_fdpic.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_elf.c Invalid return value of execve() resulting in oopses 2007-05-08 11:15:15 -07:00
binfmt_em86.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_flat.c [PATCH] uclinux: correctly remap bin_fmtflat exe allocated mem regions 2007-02-09 10:45:33 -08:00
binfmt_misc.c inode numbering: change libfs sb creation routines to avoid collisions with their root inodes 2007-05-08 11:15:16 -07:00
binfmt_script.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
binfmt_som.c [PARISC] Fix fs/binfmt_som.c 2006-10-04 06:51:26 -06:00
bio.c KMEM_CACHE(): simplify slab cache creation 2007-05-07 12:12:55 -07:00
block_dev.c is_power_of_2 in fs/block_dev.c 2007-05-08 11:14:59 -07:00
buffer.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
char_dev.c [PATCH] remove protection of LANANA-reserved majors 2007-04-04 21:12:47 -07:00
compat_ioctl.c Fix error handling in HDIO_GETGEO compat wrapper 2007-05-08 11:15:14 -07:00
compat.c utimensat implementation 2007-05-08 11:15:18 -07:00
dcache.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
dcookies.c [PATCH] slab: remove kmem_cache_t 2006-12-07 08:39:25 -08:00
direct-io.c [PATCH] dio: lock refcount operations 2006-12-10 09:57:21 -08:00
dnotify.c [PATCH] VFS: change struct file to use struct path 2006-12-08 08:28:41 -08:00
dquot.c Introduce a handy list_first_entry macro 2007-05-08 11:15:11 -07:00
drop_caches.c [PATCH] remove invalidate_inode_pages() 2007-02-11 10:51:31 -08:00
eventpoll.c Introduce a handy list_first_entry macro 2007-05-08 11:15:11 -07:00
exec.c (re)register_binfmt returns with -EBUSY 2007-05-08 11:15:08 -07:00
fcntl.c [PATCH] fdtable: Make fdarray and fdsets equal in size 2006-12-10 09:57:22 -08:00
fifo.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
file_table.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
file.c [PATCH] fdtable: Provide free_fdtable() wrapper 2006-12-22 08:55:50 -08:00
filesystems.c add filesystem subtype support 2007-05-08 11:15:01 -07:00
fs-writeback.c Write back inode data pages even when the inode itself is locked 2007-01-26 12:53:20 -08:00
generic_acl.c [PATCH] Generic infrastructure for acls 2006-09-29 09:18:24 -07:00
inode.c inode numbering: make static counters in new_inode and iunique be 32 bits 2007-05-08 11:15:16 -07:00
inotify_user.c [PATCH] inotify: read return val fix 2007-02-12 09:48:28 -08:00
inotify.c Introduce a handy list_first_entry macro 2007-05-08 11:15:11 -07:00
internal.h cleanup compat ioctl handling 2007-05-08 11:15:09 -07:00
ioctl.c vfs: remove superflous sb == NULL checks 2007-05-08 11:15:02 -07:00
ioprio.c [PATCH] pid: replace do/while_each_task_pid with do/while_each_pid_task 2007-02-12 09:48:32 -08:00
Kconfig reiserfs: proc support requires PROC_FS 2007-05-08 11:15:04 -07:00
Kconfig.binfmt blackfin architecture 2007-05-07 12:12:58 -07:00
libfs.c inode numbering: change libfs sb creation routines to avoid collisions with their root inodes 2007-05-08 11:15:16 -07:00
locks.c Merge branch 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux 2007-05-07 12:34:24 -07:00
Makefile Remove JFFS (version 1), as scheduled. 2007-02-17 16:10:59 -05:00
mbcache.c [PATCH] slab: remove kmem_cache_t 2006-12-07 08:39:25 -08:00
mpage.c Factor outstanding I/O error handling 2007-05-08 11:14:57 -07:00
namei.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
namespace.c check privileges before setting mount propagation 2007-05-08 11:15:12 -07:00
nfsctl.c
no-block.c [PATCH] BLOCK: Make it possible to disable the block layer [try #6] 2006-09-30 20:52:31 +02:00
open.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
pipe.c VFS: delay the dentry name generation on sockets and pipes 2007-05-08 11:15:03 -07:00
pnode.c Introduce a handy list_first_entry macro 2007-05-08 11:15:11 -07:00
pnode.h [PATCH] rename struct namespace to struct mnt_namespace 2006-12-08 08:28:51 -08:00
posix_acl.c [PATCH] kmemdup: some users 2006-10-01 00:39:19 -07:00
quota_v1.c
quota_v2.c
quota.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
read_write.c use use SEEK_MAX to validate user lseek arguments 2007-05-08 11:14:59 -07:00
read_write.h [PATCH] Remove readv/writev methods and use aio_read/aio_write instead 2006-10-01 00:39:28 -07:00
readdir.c ROUND_UP macro cleanup in fs/(select|compat|readdir).c 2007-05-08 11:15:09 -07:00
select.c ROUND_UP macro cleanup in fs/(select|compat|readdir).c 2007-05-08 11:15:09 -07:00
seq_file.c [PATCH] VFS: change struct file to use struct path 2006-12-08 08:28:41 -08:00
splice.c [PATCH] splice: partial write fix 2007-03-29 14:26:42 +02:00
stack.c [PATCH] fs/stack.c: Copy i_nlink after all other attributes are copied 2007-02-19 14:21:50 -08:00
stat.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
super.c add filesystem subtype support 2007-05-08 11:15:01 -07:00
sync.c Remove do_sync_file_range() 2007-05-08 11:15:04 -07:00
utimes.c utimensat implementation 2007-05-08 11:15:18 -07:00
xattr_acl.c [PATCH] remove many unneeded #includes of sched.h 2007-02-14 08:09:54 -08:00
xattr.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00