diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 2c8a4f4de..bee003c5b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,28 @@ +2008-04-24 Corinna Vinschen + + * cygwin.din (futimens): Export. + (utimensat): Export. + * fhandler.cc (fhandler_base::utimens): Replace fhandler_base::utimes. + Call utimens_fs. + * fhandler.h (class fhandler_base): Declare utimens_fs instead of + utimes_fs, utimens instead of utimes. + (class fhandler_disk_file): Declare utimens instead of utimes. + * fhandler_disk_file.cc (fhandler_disk_file::utimens): Replace + fhandler_disk_file::utimes. + (fhandler_base::utimens_fs): Replace fhandler_base::utimes_fs. + Implement tv_nsec handling according to SUSv4. + * syscalls.cc (utimensat): New function. + * times.cc (timespec_to_filetime): New function. + (timeval_to_timespec): New function. + (utimens_worker): Replace utimes_worker. + (utimes): Convert timeval to timespec and call utimens_worker. + (lutimes): Ditto. + (futimens): Take over implementation from futimes. + (futimes): Convert timeval to timespec and call futimens. + * winsup.h (timespec_to_filetime): Declare. + * include/cygwin/version.h: Bump API minor number. + * posix.sgml: Add SUSv4 section. Add futimens and utimensat to it. + 2008-04-24 Yaakov (Cygwin Ports) * include/wait.h: New file. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 3b1aaf1d4..e418f4033 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -564,6 +564,7 @@ fts_set_clientptr NOSIGFE ftw SIGFE funlockfile SIGFE funopen SIGFE +futimens SIGFE futimes SIGFE futimesat SIGFE fwrite SIGFE @@ -1656,6 +1657,7 @@ usleep SIGFE _usleep = usleep SIGFE utime SIGFE _utime = utime SIGFE +utimensat SIGFE utimes SIGFE _utimes = utimes SIGFE utmpname SIGFE diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index b46756dd0..75711260b 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1516,10 +1516,10 @@ fhandler_base::link (const char *newpath) } int -fhandler_base::utimes (const struct timeval *tvp) +fhandler_base::utimens (const struct timespec *tvp) { if (is_fs_special ()) - return utimes_fs (tvp); + return utimens_fs (tvp); set_errno (EINVAL); return -1; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 856f68321..259a0f450 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -286,7 +286,7 @@ class fhandler_base int __stdcall fstat_by_handle (struct __stat64 *buf) __attribute__ ((regparm (2))); int __stdcall fstat_by_name (struct __stat64 *buf) __attribute__ ((regparm (2))); virtual int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); - int utimes_fs (const struct timeval *) __attribute__ ((regparm (2))); + int utimens_fs (const struct timespec *) __attribute__ ((regparm (2))); virtual int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1))); virtual int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2))); virtual int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3))); @@ -295,7 +295,7 @@ class fhandler_base virtual int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3))); virtual int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); virtual int __stdcall link (const char *) __attribute__ ((regparm (2))); - virtual int __stdcall utimes (const struct timeval *) __attribute__ ((regparm (2))); + virtual int __stdcall utimens (const struct timespec *) __attribute__ ((regparm (2))); virtual int __stdcall fsync () __attribute__ ((regparm (1))); virtual int ioctl (unsigned int cmd, void *); virtual int fcntl (int cmd, void *); @@ -695,7 +695,7 @@ class fhandler_disk_file: public fhandler_base int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3))); int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); int __stdcall link (const char *) __attribute__ ((regparm (2))); - int __stdcall utimes (const struct timeval *) __attribute__ ((regparm (2))); + int __stdcall utimens (const struct timespec *) __attribute__ ((regparm (2))); int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); HANDLE mmap (caddr_t *addr, size_t len, int prot, int flags, _off64_t off); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 4f81bf764..dabee7beb 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1149,16 +1149,17 @@ fhandler_disk_file::link (const char *newpath) } int -fhandler_disk_file::utimes (const struct timeval *tvp) +fhandler_disk_file::utimens (const struct timespec *tvp) { - return utimes_fs (tvp); + return utimens_fs (tvp); } int -fhandler_base::utimes_fs (const struct timeval *tvp) +fhandler_base::utimens_fs (const struct timespec *tvp) { LARGE_INTEGER lastaccess, lastwrite; - struct timeval tmp[2]; + struct timespec timeofday; + struct timespec tmp[2]; bool closeit = false; if (!get_handle ()) @@ -1180,15 +1181,25 @@ fhandler_base::utimes_fs (const struct timeval *tvp) closeit = true; } - gettimeofday (&tmp[0], 0); + gettimeofday (reinterpret_cast (&timeofday), 0); + timeofday.tv_nsec *= 1000; if (!tvp) + tmp[1] = tmp[0] = timeofday; + else { - tmp[1] = tmp[0]; - tvp = tmp; + if ((tmp[0].tv_nsec < UTIME_NOW || tmp[0].tv_nsec > 999999999L) + || (tmp[1].tv_nsec < UTIME_NOW || tmp[1].tv_nsec > 999999999L)) + { + set_errno (EINVAL); + return -1; + } + tmp[0] = (tvp[0].tv_nsec == UTIME_NOW) ? timeofday : tvp[0]; + tmp[1] = (tvp[1].tv_nsec == UTIME_NOW) ? timeofday : tvp[1]; } - timeval_to_filetime (&tvp[0], (FILETIME *) &lastaccess); - timeval_to_filetime (&tvp[1], (FILETIME *) &lastwrite); - debug_printf ("incoming lastaccess %08x %08x", tvp[0].tv_sec, tvp[0].tv_usec); + /* UTIME_OMIT is handled in timespec_to_filetime by setting FILETIME to 0. */ + timespec_to_filetime (&tmp[0], (FILETIME *) &lastaccess); + timespec_to_filetime (&tmp[1], (FILETIME *) &lastwrite); + debug_printf ("incoming lastaccess %08x %08x", tmp[0].tv_sec, tmp[0].tv_nsec); IO_STATUS_BLOCK io; FILE_BASIC_INFORMATION fbi; diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 007032a59..668c0636e 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -331,12 +331,13 @@ details. */ 184: Export openat, faccessat, fchmodat, fchownat, fstatat, futimesat, linkat, mkdirat, mkfifoat, mknodat, readlinkat, renameat, symlinkat, unlinkat. + 185: Export futimens, utimensat. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 184 +#define CYGWIN_VERSION_API_MINOR 185 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml index ca5f5581e..ca9e0cf3e 100644 --- a/winsup/cygwin/posix.sgml +++ b/winsup/cygwin/posix.sgml @@ -1042,6 +1042,15 @@ also ISO/IEC 9945:2003 and IEEE Std 1003.1-2001 (POSIX.1-2001). +System interfaces compatible with the Draft Single Unix Specification, Version 4: + + + futimens + utimensat + + + + Other UNIX system interfaces, deprecated or not in POSIX.1-2001: diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 1a2572186..7da929efa 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -3631,6 +3631,25 @@ fstatat (int dirfd, const char *pathname, struct __stat64 *st, int flags) return (flags & AT_SYMLINK_NOFOLLOW) ? lstat64 (path, st) : stat64 (path, st); } +extern int utimens_worker (path_conv &, const struct timespec *); + +extern "C" int +utimensat (int dirfd, const char *pathname, const struct timespec *times, + int flags) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + tmp_pathbuf tp; + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + return -1; + path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW), + stat_suffixes); + return utimens_worker (win32, times); +} + extern "C" int futimesat (int dirfd, const char *pathname, const struct timeval *times) { diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 1417dc9c7..ee63a2e3a 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -182,6 +182,21 @@ time_t_to_filetime (time_t time_in, FILETIME *out) out->dwLowDateTime = x; } +/* Cygwin internal */ +void __stdcall +timespec_to_filetime (const struct timespec *time_in, FILETIME *out) +{ + if (time_in->tv_nsec == UTIME_OMIT) + out->dwHighDateTime = out->dwLowDateTime = 0; + else + { + long long x = time_in->tv_sec * NSPERSEC + + time_in->tv_nsec / (NSPERSEC/100000) + FACTOR; + out->dwHighDateTime = x >> 32; + out->dwLowDateTime = x; + } +} + /* Cygwin internal */ void __stdcall timeval_to_filetime (const struct timeval *time_in, FILETIME *out) @@ -202,6 +217,30 @@ time_t_to_timeval (time_t in) return res; } +/* Cygwin internal */ +static const struct timespec * +timeval_to_timespec (const struct timeval *tvp, struct timespec *tmp) +{ + if (!tvp) + return NULL; + + tmp[0].tv_sec = tvp[0].tv_sec; + tmp[0].tv_nsec = tvp[0].tv_usec * 1000; + if (tmp[0].tv_nsec < 0) + tmp[0].tv_nsec = 0; + else if (tmp[0].tv_nsec > 999999999) + tmp[0].tv_nsec = 999999999; + + tmp[1].tv_sec = tvp[1].tv_sec; + tmp[1].tv_nsec = tvp[1].tv_usec * 1000; + if (tmp[1].tv_nsec < 0) + tmp[1].tv_nsec = 0; + else if (tmp[1].tv_nsec > 999999999) + tmp[1].tv_nsec = 999999999; + + return tmp; +} + /* Cygwin internal */ /* Convert a Win32 time to "UNIX" format. */ long __stdcall @@ -439,8 +478,8 @@ gmtime (const time_t *tim_p) #endif /* POSIX_LOCALTIME */ -static int -utimes_worker (path_conv &win32, const struct timeval *tvp) +int +utimens_worker (path_conv &win32, const struct timespec *tvp) { int res = -1; @@ -475,7 +514,7 @@ utimes_worker (path_conv &win32, const struct timeval *tvp) } } - res = fh->utimes (tvp); + res = fh->utimens (tvp); if (!fromfd) delete fh; @@ -492,7 +531,8 @@ extern "C" int utimes (const char *path, const struct timeval *tvp) { path_conv win32 (path, PC_POSIX | PC_SYM_FOLLOW, stat_suffixes); - return utimes_worker (win32, tvp); + struct timespec tmp[2]; + return utimens_worker (win32, timeval_to_timespec (tvp, tmp)); } /* BSD */ @@ -500,12 +540,13 @@ extern "C" int lutimes (const char *path, const struct timeval *tvp) { path_conv win32 (path, PC_POSIX | PC_SYM_NOFOLLOW, stat_suffixes); - return utimes_worker (win32, tvp); + struct timespec tmp[2]; + return utimens_worker (win32, timeval_to_timespec (tvp, tmp)); } -/* BSD */ +/* futimens: POSIX/SUSv4 */ extern "C" int -futimes (int fd, const struct timeval *tvp) +futimens (int fd, const struct timespec *tvp) { int res; @@ -513,13 +554,21 @@ futimes (int fd, const struct timeval *tvp) if (cfd < 0) res = -1; else if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE)) - res = cfd->utimes (tvp); + res = cfd->utimens (tvp); else - res = utimes_worker (cfd->pc, tvp); - syscall_printf ("%d = futimes (%d, %p)", res, fd, tvp); + res = utimens_worker (cfd->pc, tvp); + syscall_printf ("%d = futimens (%d, %p)", res, fd, tvp); return res; } +/* BSD */ +extern "C" int +futimes (int fd, const struct timeval *tvp) +{ + struct timespec tmp[2]; + return futimens (fd, timeval_to_timespec (tvp, tmp)); +} + /* utime: POSIX 5.6.6.1 */ extern "C" int utime (const char *path, const struct utimbuf *buf) diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 68a0c2b7b..0852b2908 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -285,6 +285,7 @@ void __stdcall totimeval (struct timeval *, FILETIME *, int, int); long __stdcall to_time_t (FILETIME *); void __stdcall to_timestruc_t (FILETIME *, timestruc_t *); void __stdcall time_as_timestruc_t (timestruc_t *); +void __stdcall timespec_to_filetime (const struct timespec *, FILETIME *); void __stdcall timeval_to_filetime (const struct timeval *, FILETIME *); /* Console related */