This is the mail archive of the cygwin-developers@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

WriteFile() whacks st_atime (was Re: stat() whacks st_atime)


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
#include <windows.h>

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);
}
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;
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]