From 7ba1698ed99abca171d2beb9091168e20cdd8b34 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 21 Sep 2010 16:07:20 +0000 Subject: [PATCH] * fhandler.cc (fhandler_base::open): Always open NFS files with FILE_READ_EA, even when opening with O_WRONLY to allow fstat. * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Call FlushFileBuffers if file has been opened for writing. Explain why. (fhandler_base::fstat_by_handle): Renew content of pc.fnoi if called via fstat. Explain why. Fix formatting. * path.cc (symlink_info::check): Try to open file the second time with FILE_READ_EA permissions since it's needed in later calls to fhandler_base::fstat_by_nfs_ea. --- winsup/cygwin/ChangeLog | 12 ++++++++++++ winsup/cygwin/fhandler.cc | 15 +++++++++------ winsup/cygwin/fhandler_disk_file.cc | 29 +++++++++++++++++++++++++++-- winsup/cygwin/path.cc | 7 ++++--- 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b854c378b..9788adef9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2010-09-21 Corinna Vinschen + + * fhandler.cc (fhandler_base::open): Always open NFS files with + FILE_READ_EA, even when opening with O_WRONLY to allow fstat. + * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Call + FlushFileBuffers if file has been opened for writing. Explain why. + (fhandler_base::fstat_by_handle): Renew content of pc.fnoi if called + via fstat. Explain why. Fix formatting. + * path.cc (symlink_info::check): Try to open file the second time with + FILE_READ_EA permissions since it's needed in later calls to + fhandler_base::fstat_by_nfs_ea. + 2010-09-20 Christopher Faylor * include/sys/cygwin.h (PID_NOTCYGWIN): New enum. diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 1998979f7..64451f672 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -501,16 +501,19 @@ fhandler_base::open (int flags, mode_t mode) break; } - if (query_open () && pc.fs_is_nfs ()) + if (pc.fs_is_nfs ()) { /* Make sure we can read EAs of files on an NFS share. Also make - sure that we're going to act on the file itself, even if it'a + sure that we're going to act on the file itself, even if it's a a symlink. */ access |= FILE_READ_EA; - if (query_open () >= query_write_control) - access |= FILE_WRITE_EA; - plen = sizeof nfs_aol_ffei; - p = (PFILE_FULL_EA_INFORMATION) &nfs_aol_ffei; + if (query_open ()) + { + if (query_open () >= query_write_control) + access |= FILE_WRITE_EA; + plen = sizeof nfs_aol_ffei; + p = (PFILE_FULL_EA_INFORMATION) &nfs_aol_ffei; + } } if ((flags & O_TRUNC) && ((flags & O_ACCMODE) != O_RDONLY)) diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 02376f6a5..cff345d31 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -305,6 +305,14 @@ fhandler_base::fstat_by_nfs_ea (struct __stat64 *buf) char buf[sizeof (NFS_V3_ATTR)]; } fgei_buf; + /* NFS stumbles over its own caching. If you write to the file, + a subsequent fstat does not return the actual size of the file, + but the size at the time the handle has been opened. Unless + access through another handle invalidates the caching within the + NFS client. */ + if (get_io_handle () && (get_access () & GENERIC_WRITE)) + FlushFileBuffers (get_io_handle ()); + fgei_buf.fgei.NextEntryOffset = 0; fgei_buf.fgei.EaNameLength = sizeof (NFS_V3_ATTR) - 1; stpcpy (fgei_buf.fgei.EaName, NFS_V3_ATTR); @@ -356,6 +364,21 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) NTSTATUS status = 0; IO_STATUS_BLOCK io; + /* If the file has been opened for other purposes than stat, we can't rely + on the information stored in pc.fnoi. So we overwrite them here. */ + if (get_io_handle ()) + { + PFILE_NETWORK_OPEN_INFORMATION pfnoi = pc.fnoi (); + status = NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi, + FileNetworkOpenInformation); + if (!NT_SUCCESS (status)) + { + debug_printf ("%p = NtQueryInformationFile(%S, " + "FileNetworkOpenInformation)", + status, pc.get_nt_native_path ()); + return -1; + } + } if (!pc.hasgood_inode ()) fsi.NumberOfLinks = 1; else @@ -364,7 +387,8 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) FileStandardInformation); if (!NT_SUCCESS (status)) { - debug_printf ("%p = NtQueryInformationFile(%S, FileStandardInformation)", + debug_printf ("%p = NtQueryInformationFile(%S, " + "FileStandardInformation)", status, pc.get_nt_native_path ()); return -1; } @@ -374,7 +398,8 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) FileInternalInformation); if (!NT_SUCCESS (status)) { - debug_printf ("%p = NtQueryInformationFile(%S, FileInternalInformation)", + debug_printf ("%p = NtQueryInformationFile(%S, " + "FileInternalInformation)", status, pc.get_nt_native_path ()); return -1; } diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d29aff028..32bb4c0a9 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2296,10 +2296,11 @@ restart: FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, eabuf, easize); - if (status == STATUS_ACCESS_DENIED) + if (status == STATUS_ACCESS_DENIED && eabuf) { - status = NtCreateFile (&h, access = MIN_STAT_ACCESS, &attr, &io, - NULL, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, + status = NtCreateFile (&h, access = MIN_STAT_ACCESS | FILE_READ_EA, + &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, eabuf, easize);