kernel-ark/arch/i386/kernel
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
..
acpi [PATCH] x86: default to physical mode on hotplug CPU kernels 2007-05-02 19:27:04 +02:00
cpu Merge branch 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6 2007-05-05 14:55:20 -07:00
.gitignore
alternative.c Revert "[PATCH] x86: __pa and __pa_symbol address space separation" 2007-05-07 08:44:24 -07:00
apic.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
apm.c apm: fix incorrect comment 2007-05-08 11:15:10 -07:00
asm-offsets.c [PATCH] i386: map enough initial memory to create lowmem mappings 2007-05-02 19:27:16 +02:00
bootflag.c
cpuid.c [PATCH] i386: use smp_call_function_single() 2007-02-13 13:26:23 +01:00
crash_dump.c
crash.c move die notifier handling to common code 2007-05-08 11:15:04 -07:00
doublefault.c [PATCH] i386: i386 separate hardware-defined TSS from Linux additions 2007-05-02 19:27:13 +02:00
e820.c [PATCH] i386: Drop noisy e820 debugging printks 2007-05-02 19:27:21 +02:00
early_printk.c
efi_stub.S
efi.c EFI: warn only for pre-1.00 system tables 2007-05-08 11:15:10 -07:00
entry.S [PATCH] i386: fix wrong comment for syscall stack layout 2007-05-02 19:27:19 +02:00
head.S [PATCH] i386: map enough initial memory to create lowmem mappings 2007-05-02 19:27:16 +02:00
hpet.c [PATCH] Add suspend/resume for HPET 2007-03-29 10:25:32 -07:00
i386_ksyms.c [PATCH] i386: Convert PDA into the percpu section 2007-05-02 19:27:16 +02:00
i387.c
i8237.c
i8253.c [VOYAGER] clockevents: correct boot cpu is zero assumption 2007-05-01 10:06:42 -05:00
i8259.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
init_task.c
io_apic.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
ioport.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
irq.c [PATCH] i386: Convert PDA into the percpu section 2007-05-02 19:27:16 +02:00
kprobes.c Kprobes: print details of kretprobe on assertion failure 2007-05-08 11:15:08 -07:00
ldt.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
machine_kexec.c
Makefile [PATCH] i386: Convert VMI timer to use clock events 2007-05-02 19:27:16 +02:00
mca.c [PATCH] i386: replace kmalloc+memset with kzalloc 2006-12-07 02:14:19 +01:00
microcode.c [PATCH] Fix microcode-related suspend problem 2007-04-02 10:06:09 -07:00
module.c [PATCH] Generic BUG for i386 2006-12-08 08:28:39 -08:00
mpparse.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
msr.c [PATCH] i386: use smp_call_function_single() 2007-02-13 13:26:23 +01:00
nmi.c move die notifier handling to common code 2007-05-08 11:15:04 -07:00
numaq.c
paravirt.c [PATCH] i386: PARAVIRT: fix startup_ipi_hook config dependency 2007-05-02 19:27:18 +02:00
pci-dma.c dma_declare_coherent_memory wrong allocation 2007-05-08 11:15:14 -07:00
pcspeaker.c [PATCH] x86: Unify pcspeaker platform device code between i386/x86-64 2007-02-13 13:26:26 +01:00
process.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
ptrace.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
quirks.c [PATCH] x86: revert x86_64-mm-fix-the-irqbalance-quirk-for-e7320-e7520-e7525 2007-05-02 19:27:04 +02:00
reboot_fixups.c [PATCH] i386: clean up mach_reboot_fixups 2007-05-02 19:27:06 +02:00
reboot.c [PATCH] i386: replace spin_lock_irqsave with spin_lock 2007-05-02 19:27:18 +02:00
relocate_kernel.S
scx200.c
setup.c [PATCH] clocksource init adjustments (fix bug #7426) 2007-03-05 07:57:53 -08:00
sigframe.h
signal.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
smp.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
smpboot.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
srat.c ACPI: build fix for IBM x440 - CONFIG_X86_SUMMIT 2007-02-02 21:47:33 -05:00
summit.c
sys_i386.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
syscall_table.S utimensat implementation 2007-05-08 11:15:18 -07:00
sysenter.c [PATCH] i386: In compat mode, the return value here was uninitialized. 2007-05-02 19:27:16 +02:00
time.c [PATCH] i386: pit_latch_buggy has no effect 2007-05-02 19:27:05 +02:00
topology.c Replace remaining references to "driverfs" with "sysfs". 2007-02-17 19:13:42 +01:00
trampoline.S [PATCH] i386: Rename boot_gdt_table to boot_gdt 2007-05-02 19:27:10 +02:00
traps.c move die notifier handling to common code 2007-05-08 11:15:04 -07:00
tsc_sync.c [PATCH] x86: rewrite SMP TSC sync code 2007-02-16 08:13:57 -08:00
tsc.c [PATCH] i386: remove xtime_lock'ing around cpufreq notifier 2007-05-02 19:27:18 +02:00
verify_cpu.S [PATCH] i386: Verify important CPUID bits in real mode 2007-05-02 19:27:20 +02:00
vm86.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
vmi.c [PATCH] x86: PARAVIRT: Jeremy Fitzhardinge <jeremy@goop.org> 2007-05-02 19:27:16 +02:00
vmiclock.c [PATCH] i386: Convert VMI timer to use clock events 2007-05-02 19:27:16 +02:00
vmlinux.lds.S [PATCH] i386: Clean up ELF note generation 2007-05-02 19:27:17 +02:00
vsyscall-int80.S
vsyscall-note.S
vsyscall-sigreturn.S
vsyscall-sysenter.S
vsyscall.lds.S [PATCH] i386: VDSO_PRELINK warning fix 2007-05-02 19:27:09 +02:00
vsyscall.S