Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-developers-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin-developers AT sources DOT redhat DOT com Date: Wed, 5 Sep 2001 16:38:56 -0400 From: Jason Tishler To: Cygwin-Developers Subject: WriteFile() whacks st_atime (was Re: stat() whacks st_atime) Message-ID: <20010905163856.A616@dothill.com> Mail-Followup-To: Cygwin-Developers Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="+hupnHfSQzmGFwlm" Content-Disposition: inline In-Reply-To: <20010727095842.N439@dothill.com> User-Agent: Mutt/1.3.18i --+hupnHfSQzmGFwlm Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Jul 27, 2001 at 09:58:42AM -0400, Jason Tishler wrote: > On Fri, Jul 27, 2001 at 10:21:09AM +1000, Robert Collins wrote: > > My guess would be it's the file header reading logic - looking for > > #!/bin/foo > > > > that means that a file access _has occured_. CloseHandle triggering the > > actual write might jsut eb a win32 optimisation, to only wr > > Bingo! Thanks for helping me to see what I was missing in my haste. I > guess that the solution is to starting using ntsec (which I should be > doing for other reasons too). After converting to ntsec, the above problem has been corrected. Unfortunately, I was still having problems with st_atime getting set unexpectedly. I finally found the root cause, WriteFile(). However Microsoft obfuscated this fact by documenting it in the MSDN entries for GetFileTime()/SetFileTime() instead of WriteFile(): lpLastAccessTime Pointer to a FILETIME structure that contains the date and time the file was last accessed. The last access time includes the last time the file was written to, read from, or (in the case of executable ^^^^^^^ files) run. This parameter can be NULL if the application does not need to set this information. The first attachment, wtest4.c, demonstrates that the problem due is to Win32 and not Cygwin. The second attachment is a "patch" (I'm using the term very loosely) that works around this Windows-ism so that Cygwin behaves Posix-like with regard to write() and st_atime. Does a cleaned up version of this patch have a chance of being accepted? I'm concerned about race conditions, performance impact, affecting non-disk files, etc. Is this simplistic approach the best way to work around the problem? Or, are there better ways? Thanks, Jason --+hupnHfSQzmGFwlm Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="wtest4.c" #include char d[] = "hello\n"; int main(int argc, char* argv[]) { HANDLE h; BOOL s; DWORD r; FILETIME access; h = CreateFile( argv[1], GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) { printf("CreateFile() failed with error = %ld\n", GetLastError()); exit(1); } r = SetFilePointer(h, 0, 0, FILE_END); if (r == 0xFFFFFFFF) { printf("SetFilePoint() failed with error = %ld\n", GetLastError()); exit(1); } s = GetFileTime(h, 0, &access, 0); if (!s) { printf("GetFileTime() failed with error = %ld\n", GetLastError()); exit(1); } s = WriteFile(h, d, strlen(d), &r, 0); if (!s) { printf("WriteFile() failed with error = %ld\n", GetLastError()); exit(1); } /* XXX uncomment to workaround Windows XXX s = SetFileTime(h, 0, &access, 0); if (!s) { printf("SetFileTime() failed with error = %ld\n", GetLastError()); exit(1); } */ CloseHandle(h); } --+hupnHfSQzmGFwlm Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="fhandler.cc.diff" Index: fhandler.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler.cc,v retrieving revision 1.77 diff -u -p -r1.77 fhandler.cc --- fhandler.cc 2001/09/01 05:17:34 1.77 +++ fhandler.cc 2001/09/05 20:14:35 @@ -254,6 +254,8 @@ fhandler_base::raw_write (const void *pt { DWORD bytes_written; + FILETIME access; + GetFileTime(get_handle(), 0, &access, 0); if (!WriteFile (get_handle(), ptr, len, &bytes_written, 0)) { if (GetLastError () == ERROR_DISK_FULL && bytes_written > 0) @@ -263,6 +265,7 @@ fhandler_base::raw_write (const void *pt raise (SIGPIPE); return -1; } + SetFileTime(get_handle(), 0, &access, 0); return bytes_written; } --+hupnHfSQzmGFwlm--