From ceaf31f416220413feedcad1cc3e9f30f57dc28f Mon Sep 17 00:00:00 2001
From: Corinna Vinschen <corinna@vinschen.de>
Date: Fri, 27 Jul 2007 10:10:57 +0000
Subject: [PATCH] 	* fhandler_disk_file.cc
 (fhandler_base::fstat_by_name): Use 	RtlSplitUnicodePath. 
 (fhandler_disk_file::fstat): Rename oret to opened.  Open file using NT 
 functions right here.  Try to open parent dir instead of root directory 
 to avoid call to rootdir.  Use NtFsControlFile. 	* ntdll.h
 (RtlSplitUnicodePath): Define.

---
 winsup/cygwin/ChangeLog             |  9 ++++
 winsup/cygwin/fhandler_disk_file.cc | 68 ++++++++++++++---------------
 winsup/cygwin/ntdll.h               | 14 ++++++
 3 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index ca68bb8bd..e8574d5dd 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,12 @@
+2007-07-27  Corinna Vinschen  <corinna@vinschen.de>
+
+	* fhandler_disk_file.cc (fhandler_base::fstat_by_name): Use
+	RtlSplitUnicodePath.
+	(fhandler_disk_file::fstat): Rename oret to opened.  Open file using NT
+	functions right here.  Try to open parent dir instead of root directory
+	to avoid call to rootdir.  Use NtFsControlFile.
+	* ntdll.h (RtlSplitUnicodePath): Define.
+
 2007-07-27  Corinna Vinschen  <corinna@vinschen.de>
 
 	* fhandler_disk_file.cc (is_volume_mountpoint): New static inline
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index bebc225e3..9264285d6 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -335,16 +335,7 @@ fhandler_base::fstat_by_name (struct __stat64 *buf)
       set_errno (ENOENT);
       return -1;
     }
-  /* Split path in dirname and basename */
-  dirname = *pc.get_nt_native_path ();
-  USHORT len = dirname.Length / sizeof (WCHAR);
-  while (len > 0 && dirname.Buffer[--len] != L'\\')
-    ;
-  ++len;
-  RtlInitCountedUnicodeString (&basename,
-			       dirname.Length - len * sizeof (WCHAR),
-			       &dirname.Buffer[len]);
-  dirname.Length = len * sizeof (WCHAR);
+  RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, &basename);
   InitializeObjectAttributes (&attr, &dirname, OBJ_CASE_INSENSITIVE,
 			      NULL, NULL);
   if (!NT_SUCCESS (status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
@@ -627,46 +618,51 @@ fhandler_disk_file::fstat (struct __stat64 *buf)
 int __stdcall
 fhandler_disk_file::fstatvfs (struct statvfs *sfs)
 {
-  int ret = -1, oret = 0;
+  int ret = -1, opened = 0;
   NTSTATUS status;
   IO_STATUS_BLOCK io;
   const size_t fvi_size = sizeof (FILE_FS_VOLUME_INFORMATION)
-			  + 256 * sizeof (WCHAR);
+			  + (NAME_MAX + 1) * sizeof (WCHAR);
   PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
 				     alloca (fvi_size);
   const size_t fai_size = sizeof (FILE_FS_ATTRIBUTE_INFORMATION)
-			  + 256 * sizeof (WCHAR);
+			  + (NAME_MAX + 1) * sizeof (WCHAR);
   PFILE_FS_ATTRIBUTE_INFORMATION pfai = (PFILE_FS_ATTRIBUTE_INFORMATION)
 					alloca (fai_size);
   FILE_FS_FULL_SIZE_INFORMATION full_fsi;
   FILE_FS_SIZE_INFORMATION fsi;
+  HANDLE fh = get_handle ();
 
-  if (!get_io_handle ())
+  if (!fh)
     {
-      query_open (query_read_control);
-      oret = open_fs (O_RDONLY | O_BINARY, 0);
-      if (!oret)
+      OBJECT_ATTRIBUTES attr;
+      opened = NT_SUCCESS (NtOpenFile (&fh, READ_CONTROL,
+				     pc.get_object_attr (attr, sec_none_nih),
+				     &io, FILE_SHARE_VALID_FLAGS,
+				     FILE_OPEN_FOR_BACKUP_INTENT));
+      if (!opened)
 	{
-	  /* Can't open file.  Try again with rootdir. */
-	  char root[CYG_MAX_PATH];
-	  if (!rootdir (get_win32_name (), root))
-	    goto out;
-	  pc.check (root, PC_SYM_NOFOLLOW);
-	  oret = open_fs (O_RDONLY | O_BINARY, 0);
-	  if (!oret)
+	  /* Can't open file.  Try again with parent dir. */
+	  UNICODE_STRING dirname;
+	  RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, NULL);
+	  attr.ObjectName = &dirname;
+	  opened = NT_SUCCESS (NtOpenFile (&fh, READ_CONTROL, &attr, &io,
+					 FILE_SHARE_VALID_FLAGS,
+					 FILE_OPEN_FOR_BACKUP_INTENT));
+	  if (!opened)
 	    goto out;
 	}
     }
 
   /* Get basic volume information. */
-  status = NtQueryVolumeInformationFile (get_handle (), &io, pfvi, fvi_size,
+  status = NtQueryVolumeInformationFile (fh, &io, pfvi, fvi_size,
 					 FileFsVolumeInformation);
   if (!NT_SUCCESS (status))
     {
       __seterrno_from_nt_status (status);
       goto out;
     }
-  status = NtQueryVolumeInformationFile (get_handle (), &io, pfai, fai_size,
+  status = NtQueryVolumeInformationFile (fh, &io, pfai, fai_size,
 					 FileFsAttributeInformation);
   if (!NT_SUCCESS (status))
     {
@@ -682,8 +678,7 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
   /* Get allocation related information.  Try to get "full" information
      first, which is only available since W2K.  If that fails, try to
      retrieve normal allocation information. */
-  status = NtQueryVolumeInformationFile (get_handle (), &io, &full_fsi,
-					 sizeof full_fsi,
+  status = NtQueryVolumeInformationFile (fh, &io, &full_fsi, sizeof full_fsi,
 					 FileFsFullSizeInformation);
   if (NT_SUCCESS (status))
     {
@@ -696,11 +691,12 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
 	{
 	  /* Quotas active.  We can't trust TotalAllocationUnits. */
 	  NTFS_VOLUME_DATA_BUFFER nvdb;
-	  DWORD bytes;
 
-	  if (!DeviceIoControl (get_handle (), FSCTL_GET_NTFS_VOLUME_DATA, NULL,
-				0, &nvdb, sizeof nvdb, &bytes, NULL))
-	    debug_printf ("DeviceIoControl (%s) failed, %E", get_name ());
+	  status = NtFsControlFile (fh, NULL, NULL, NULL, &io,
+				    FSCTL_GET_NTFS_VOLUME_DATA,
+				    NULL, 0, &nvdb, sizeof nvdb);
+	  if (!NT_SUCCESS (status))
+	    debug_printf ("NtFsControlFile (%s) failed, status %lx", status);
 	  else
 	    sfs->f_blocks = nvdb.TotalClusters.QuadPart;
 	}
@@ -708,8 +704,8 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
     }
   else
     {
-      status = NtQueryVolumeInformationFile (get_handle (), &io, &fsi,
-					     sizeof fsi, FileFsSizeInformation);
+      status = NtQueryVolumeInformationFile (fh, &io, &fsi, sizeof fsi,
+					     FileFsSizeInformation);
       if (!NT_SUCCESS (status))
 	{
 	  __seterrno_from_nt_status (status);
@@ -723,8 +719,8 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
       ret = 0;
     }
 out:
-  if (oret)
-    close_fs ();
+  if (opened)
+    NtClose (fh);
   syscall_printf ("%d = fstatvfs (%s, %p)", ret, get_name (), sfs);
   return ret;
 }
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index d3837bb99..cb2cccfa1 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -805,4 +805,18 @@ extern "C"
     dest->Length = dest->MaximumLength = len;
     dest->Buffer = (PWSTR) buf;
   }
+  inline
+  VOID NTAPI RtlSplitUnicodePath (PUNICODE_STRING path, PUNICODE_STRING dir,
+				  PUNICODE_STRING file)
+  {
+    USHORT len = path->Length / sizeof (WCHAR);
+    while (len > 0 && path->Buffer[--len] != L'\\')
+      ;
+    ++len;
+    if (dir)
+      RtlInitCountedUnicodeString (dir, len * sizeof (WCHAR), path->Buffer);
+    if (file)
+      RtlInitCountedUnicodeString (file, path->Length - len * sizeof (WCHAR),
+				   &path->Buffer[len]);
+  }
 }