From 2b09be25a3929c8c6d7e23e1abb4756187c5036b Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 20 Feb 2005 11:44:32 +0000 Subject: [PATCH] * fhandler.h (enum query_state): Add query_write_attributes state. (fhandler_base::status.query_open): Add a bit to make room for more states. (class fhandler_base): Declare new method utimes. (class fhandler_socket): Ditto. (class fhandler_disk_file): Ditto. (fhandler_disk_file::fhandler_disk_file): Add constructor with path_conv parameter. * fhandler.cc (fhandler_base::open): Add query_write_attributes handling. (fhandler_base::utimes): New method. * fhandler_disk_file.cc (fhandler_disk_file::link): Simplify. Open file with query_write_attributes instead of query_write_control. (fhandler_disk_file::utimes): New method. (fhandler_disk_file::fhandler_disk_file): Add constructor with path_conv parameter setting pc member immediately. * fhandler_socket.cc (fhandler_socket::fchmod): Use new fhandler_disk_file constructor. (fhandler_socket::fchown): Ditto. (fhandler_socket::facl): Ditto. (fhandler_socket::link): Ditto. (fhandler_socket::utimes): New method. * times.cc: Include dtable.h. (timeval_to_filetime): Make non-static. (utimes): Move functionality into fhandler method utimes. Just call this method from here. * winsup.h: Simplify declarations of time helper functions. (timeval_to_filetime): Add extern declaration. --- winsup/cygwin/ChangeLog | 31 ++++++++ winsup/cygwin/fhandler.cc | 11 +++ winsup/cygwin/fhandler.h | 9 ++- winsup/cygwin/fhandler_disk_file.cc | 112 +++++++++++++++++++--------- winsup/cygwin/fhandler_socket.cc | 23 ++++-- winsup/cygwin/times.cc | 95 ++++------------------- winsup/cygwin/winsup.h | 9 ++- 7 files changed, 161 insertions(+), 129 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index aa47a9064..896e72837 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,34 @@ +2005-02-20 Corinna Vinschen + + * fhandler.h (enum query_state): Add query_write_attributes state. + (fhandler_base::status.query_open): Add a bit to make room for more + states. + (class fhandler_base): Declare new method utimes. + (class fhandler_socket): Ditto. + (class fhandler_disk_file): Ditto. + (fhandler_disk_file::fhandler_disk_file): Add constructor with + path_conv parameter. + * fhandler.cc (fhandler_base::open): Add query_write_attributes + handling. + (fhandler_base::utimes): New method. + * fhandler_disk_file.cc (fhandler_disk_file::link): Simplify. + Open file with query_write_attributes instead of query_write_control. + (fhandler_disk_file::utimes): New method. + (fhandler_disk_file::fhandler_disk_file): Add constructor with + path_conv parameter setting pc member immediately. + * fhandler_socket.cc (fhandler_socket::fchmod): Use new + fhandler_disk_file constructor. + (fhandler_socket::fchown): Ditto. + (fhandler_socket::facl): Ditto. + (fhandler_socket::link): Ditto. + (fhandler_socket::utimes): New method. + * times.cc: Include dtable.h. + (timeval_to_filetime): Make non-static. + (utimes): Move functionality into fhandler method utimes. Just call + this method from here. + * winsup.h: Simplify declarations of time helper functions. + (timeval_to_filetime): Add extern declaration. + 2005-02-19 Corinna Vinschen * fhandler.h (class fhandler_base): Declare new method link. diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index f846d044e..6a935fbec 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -583,6 +583,10 @@ fhandler_base::open (int flags, mode_t mode) access = READ_CONTROL | WRITE_OWNER | WRITE_DAC | FILE_WRITE_ATTRIBUTES; create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY; break; + case query_write_attributes: + access = READ_CONTROL | FILE_WRITE_ATTRIBUTES; + create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY; + break; default: create_options = 0; if (get_major () == DEV_TAPE_MAJOR && (flags & O_TEXT)) @@ -1612,3 +1616,10 @@ fhandler_base::link (const char *newpath) set_errno (EINVAL); return -1; } + +int +fhandler_base::utimes (const struct timeval *tvp) +{ + set_errno (EINVAL); + return -1; +} diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 591c08894..b6d1fae3c 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -66,7 +66,8 @@ enum query_state { no_query = 0, query_read_control = 1, query_stat_control = 2, - query_write_control = 3 + query_write_control = 3, + query_write_attributes = 4 }; class fhandler_base @@ -87,7 +88,7 @@ class fhandler_base _write should check if we've moved beyond EOF, zero filling or making file sparse if so. */ - unsigned query_open : 2; /* open file without requesting either + unsigned query_open : 3; /* open file without requesting either read or write access */ unsigned close_on_exec : 1; /* close-on-exec */ unsigned need_fork_fixup : 1; /* Set if need to fixup after fork. */ @@ -265,6 +266,7 @@ class fhandler_base virtual int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3))); virtual int __stdcall ftruncate (_off64_t) __attribute__ ((regparm (2))); virtual int __stdcall link (const char *) __attribute__ ((regparm (2))); + virtual int __stdcall utimes (const struct timeval *) __attribute__ ((regparm (2))); virtual int ioctl (unsigned int cmd, void *); virtual int fcntl (int cmd, void *); virtual char const *ttyname () { return get_name (); } @@ -438,6 +440,7 @@ class fhandler_socket: public fhandler_base int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2))); int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3))); int __stdcall link (const char *) __attribute__ ((regparm (2))); + int __stdcall utimes (const struct timeval *) __attribute__ ((regparm (2))); bool is_slow () {return 1;} }; @@ -600,6 +603,7 @@ class fhandler_disk_file: public fhandler_base public: fhandler_disk_file (); + fhandler_disk_file (path_conv &pc); int open (int flags, mode_t mode); int close (); @@ -611,6 +615,7 @@ class fhandler_disk_file: public fhandler_base int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3))); int __stdcall ftruncate (_off64_t) __attribute__ ((regparm (2))); int __stdcall link (const char *) __attribute__ ((regparm (2))); + int __stdcall utimes (const struct timeval *) __attribute__ ((regparm (2))); HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, _off64_t off); int munmap (HANDLE h, caddr_t addr, size_t len); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index b77ae82fd..5b057dbbd 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -633,28 +633,27 @@ fhandler_disk_file::ftruncate (_off64_t length) int fhandler_disk_file::link (const char *newpath) { - int res = -1; path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_FULL | PC_POSIX); extern bool allow_winsymlinks; if (newpc.error) { set_errno (newpc.case_clash ? ECASECLASH : newpc.error); - goto done; + return -1; } if (newpc.exists ()) { syscall_printf ("file '%s' exists?", (char *) newpc); set_errno (EEXIST); - goto done; + return -1; } if (newpc[strlen (newpc) - 1] == '.') { syscall_printf ("trailing dot, bailing out"); set_errno (EINVAL); - goto done; + return -1; } /* Shortcut hack. */ @@ -667,12 +666,12 @@ fhandler_disk_file::link (const char *newpath) newpc.check (newpath, PC_SYM_NOFOLLOW | PC_FULL); } - query_open (query_write_control); + query_open (query_write_attributes); if (!open (O_BINARY, 0)) { syscall_printf ("Opening file failed"); __seterrno (); - goto done; + return -1; } /* Try to make hard link first on Windows NT */ @@ -697,17 +696,14 @@ fhandler_disk_file::link (const char *newpath) syscall_printf ("CreateHardLinkA failed"); __seterrno (); close (); - goto done; + return -1; } WIN32_STREAM_ID stream_id; - DWORD written; LPVOID context; - DWORD path_len; - DWORD size; WCHAR wbuf[CYG_MAX_PATH]; BOOL ret; - DWORD write_err; + DWORD written, write_err, path_len, size; path_len = sys_mbstowcs (wbuf, newpc, CYG_MAX_PATH) * sizeof (WCHAR); @@ -756,52 +752,98 @@ fhandler_disk_file::link (const char *newpath) close (); __seterrno_from_win_error (write_err); - goto done; + return -1; } success: - res = 0; - /* touch st_ctime */ + /* Set ctime on success. */ has_changed (true); close (); if (!allow_winsymlinks && pc.is_lnk_symlink ()) SetFileAttributes (newpc, (DWORD) pc | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY); - - goto done; + return 0; } docopy: /* do this with a copy */ - if (CopyFileA (pc, newpc, 1)) + if (!CopyFileA (pc, newpc, 1)) { - res = 0; - /* touch st_ctime */ - has_changed (true); - close (); - fhandler_disk_file fh; - fh.set_name (newpc); - fh.query_open (query_write_control); - if (fh.open (O_BINARY, 0)) - { - fh.has_changed (true); - fh.close (); - } + __seterrno (); + return -1; } - else - __seterrno (); - -done: - syscall_printf ("%d = link (%s, %s)", res, get_name (), newpath); - return res; + /* Set ctime on success, also on the copy. */ + has_changed (true); + close (); + fhandler_disk_file fh (newpc); + fh.query_open (query_write_attributes); + if (fh.open (O_BINARY, 0)) + { + fh.has_changed (true); + fh.close (); + } + return 0; } +int +fhandler_disk_file::utimes (const struct timeval *tvp) +{ + FILETIME lastaccess, lastwrite, lastchange; + struct timeval tmp[2]; + + query_open (query_write_attributes); + if (!open (O_BINARY, 0)) + { + /* It's documented in MSDN that FILE_WRITE_ATTRIBUTES is sufficient + to change the timestamps. Unfortunately it's not sufficient for a + remote HPFS which requires GENERIC_WRITE, so we just retry to open + for writing, though this fails for R/O files of course. */ + query_open (no_query); + if (!open (O_WRONLY | O_BINARY, 0)) + { + syscall_printf ("Opening file failed"); + __seterrno (); + if (pc.isdir ()) /* What we can do with directories more? */ + return 0; + + __seterrno (); + return -1; + } + } + + gettimeofday (&tmp[0], 0); + if (!tvp) + { + tmp[1] = tmp[0]; + tvp = tmp; + } + timeval_to_filetime (&tvp[0], &lastaccess); + timeval_to_filetime (&tvp[1], &lastwrite); + /* Update ctime */ + timeval_to_filetime (&tmp[0], &lastchange); + debug_printf ("incoming lastaccess %08x %08x", tvp[0].tv_sec, tvp[0].tv_usec); + if (!SetFileTime (get_handle (), &lastchange, &lastaccess, &lastwrite)) + { + DWORD errcode = GetLastError (); + close (); + __seterrno_from_win_error (errcode); + return -1; + } + close (); + return 0; +} fhandler_disk_file::fhandler_disk_file () : fhandler_base () { } +fhandler_disk_file::fhandler_disk_file (path_conv &pc) : + fhandler_base () +{ + set_name (pc); +} + int fhandler_disk_file::open (int flags, mode_t mode) { diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 4e3f5e084..9f0b39f53 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -414,8 +414,7 @@ fhandler_socket::fchmod (mode_t mode) { if (get_device () == FH_UNIX) { - fhandler_disk_file fh; - fh.set_name (pc); + fhandler_disk_file fh (pc); fh.get_device () = FH_FS; int ret = fh.fchmod (mode); SetFileAttributes (pc, GetFileAttributes (pc) | FILE_ATTRIBUTE_SYSTEM); @@ -429,8 +428,7 @@ fhandler_socket::fchown (__uid32_t uid, __gid32_t gid) { if (get_device () == FH_UNIX) { - fhandler_disk_file fh; - fh.set_name (pc); + fhandler_disk_file fh (pc); return fh.fchown (uid, gid); } return 0; @@ -441,8 +439,7 @@ fhandler_socket::facl (int cmd, int nentries, __aclent32_t *aclbufp) { if (get_device () == FH_UNIX) { - fhandler_disk_file fh; - fh.set_name (pc); + fhandler_disk_file fh (pc); return fh.facl (cmd, nentries, aclbufp); } return fhandler_base::facl (cmd, nentries, aclbufp); @@ -453,13 +450,23 @@ fhandler_socket::link (const char *newpath) { if (get_device () == FH_UNIX) { - fhandler_disk_file fh; - fh.set_name (pc); + fhandler_disk_file fh (pc); return fh.link (newpath); } return fhandler_base::link (newpath); } +int +fhandler_socket::utimes (const struct timeval *tvp) +{ + if (get_device () == FH_UNIX) + { + fhandler_disk_file fh (pc); + return fh.utimes (tvp); + } + return fhandler_base::utimes (tvp); +} + int fhandler_socket::bind (const struct sockaddr *name, int namelen) { diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 1e1a90abd..5e4496308 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -21,6 +21,7 @@ details. */ #include "security.h" #include "path.h" #include "fhandler.h" +#include "dtable.h" #include "pinfo.h" #include "hires.h" #include "cygtls.h" @@ -30,8 +31,6 @@ details. */ #define FACTOR (0x19db1ded53e8000LL) #define NSPERSEC 10000000LL -static void __stdcall timeval_to_filetime (const struct timeval *time, FILETIME *out); - /* Cygwin internal */ static unsigned long long __stdcall __to_clock_t (FILETIME * src, int flag) @@ -184,7 +183,7 @@ time_t_to_filetime (time_t time_in, FILETIME *out) } /* Cygwin internal */ -static void __stdcall +void __stdcall timeval_to_filetime (const struct timeval *time_in, FILETIME *out) { long long x = time_in->tv_sec * NSPERSEC + @@ -444,91 +443,27 @@ gmtime (const time_t *tim_p) #endif /* POSIX_LOCALTIME */ -/* utimes: standards? */ +/* utimes: POSIX/SUSv3 */ extern "C" int utimes (const char *path, const struct timeval *tvp) { - int res = 0; - struct timeval tmp[2]; - path_conv win32 (path); + int res = -1; + fhandler_base *fh; - if (win32.error) + if (!(fh = build_fh_name (path, NULL, PC_SYM_FOLLOW))) + goto error; + + if (fh->error ()) { - set_errno (win32.error); - syscall_printf ("-1 = utimes (%s, %x)", path, tvp); - return -1; - } - - /* MSDN suggests using FILE_FLAG_BACKUP_SEMANTICS for accessing - the times of directories. */ - /* Note: It's documented in MSDN that FILE_WRITE_ATTRIBUTES is - sufficient to change the timestamps. Unfortunately it's not - sufficient for a remote HPFS which requires GENERIC_WRITE. - Since we don't trust the weird FS name "??SS", we just try to - open with GENERIC_WRITE if opening with FILE_WRITE_ATTRIBUTES - failed. That should do it, though this fails for R/O files - of course. */ - HANDLE h = CreateFile (win32, FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, - 0); - if (h == INVALID_HANDLE_VALUE) - h = CreateFile (win32, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); - - if (h == INVALID_HANDLE_VALUE) - { - if (win32.isdir ()) - { - /* What we can do with directories more? */ - res = 0; - } - else - { - res = -1; - __seterrno (); - } + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); } else - { - gettimeofday (&tmp[0], 0); - if (tvp == 0) - { - tmp[1] = tmp[0]; - tvp = tmp; - } + res = fh->utimes (tvp); - FILETIME lastaccess; - FILETIME lastwrite; - FILETIME lastchange; - - timeval_to_filetime (tvp + 0, &lastaccess); - timeval_to_filetime (tvp + 1, &lastwrite); - /* Update st_ctime */ - timeval_to_filetime (tmp + 0, &lastchange); - - debug_printf ("incoming lastaccess %08x %08x", - tvp->tv_sec, - tvp->tv_usec); - - /* FIXME: SetFileTime needs a handle with a write lock - on the file whose time is being modified. So calls to utime() - fail for read only files. */ - - if (!SetFileTime (h, &lastchange, &lastaccess, &lastwrite)) - { - __seterrno (); - res = -1; - } - else - res = 0; - CloseHandle (h); - } - - syscall_printf ("%d = utimes (%s, %x); (h%d)", - res, path, tvp, h); + delete fh; + error: + syscall_printf ("%d = utimes (%s, %p)", res, path, tvp); return res; } diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index f4de848e2..794fa720f 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -254,10 +254,11 @@ extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2))); /* Time related */ -void __stdcall totimeval (struct timeval *dst, FILETIME * src, int sub, int flag); -long __stdcall to_time_t (FILETIME * ptr); -void __stdcall to_timestruc_t (FILETIME * ptr, timestruc_t * out); -void __stdcall time_as_timestruc_t (timestruc_t * out); +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 timeval_to_filetime (const struct timeval *, FILETIME *); void __stdcall set_console_title (char *); void init_console_handler ();