OSDN Git Service

* autoload.cc (CreateHardLinkA): Remove.
authorcorinna <corinna>
Fri, 27 Jul 2007 16:24:06 +0000 (16:24 +0000)
committercorinna <corinna>
Fri, 27 Jul 2007 16:24:06 +0000 (16:24 +0000)
* fhandler_disk_file.cc (fhandler_disk_file::link): Drop GetBinaryType
test.  Just check exe suffix instead.  Tune creating new file name.
Implement creating hard link using native NT functions which works
on all platforms.
* ntdll.h (STATUS_INVALID_DEVICE_REQUEST): Define.
(struct _FILE_LINK_INFORMATION): Define.

winsup/cygwin/ChangeLog
winsup/cygwin/autoload.cc
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/ntdll.h

index b86eb88..0ddebd5 100644 (file)
@@ -1,5 +1,15 @@
 2007-07-27  Corinna Vinschen  <corinna@vinschen.de>
 
+       * autoload.cc (CreateHardLinkA): Remove.
+       * fhandler_disk_file.cc (fhandler_disk_file::link): Drop GetBinaryType
+       test.  Just check exe suffix instead.  Tune creating new file name.
+       Implement creating hard link using native NT functions which works
+       on all platforms.
+       * ntdll.h (STATUS_INVALID_DEVICE_REQUEST): Define.
+       (struct _FILE_LINK_INFORMATION): Define.
+
+2007-07-27  Corinna Vinschen  <corinna@vinschen.de>
+
        * fhandler_disk_file.cc (fhandler_disk_file::ftruncate): Use
        NtQueryInformationFile instead of GetFileSize, NtFsControlFile instead
        of DeviceIoControl.
index c1a2cad..09e645a 100644 (file)
@@ -393,7 +393,6 @@ LoadDLLfuncEx2 (SendARP, 16, iphlpapi, 1, 50)
 
 LoadDLLfunc (CoTaskMemFree, 4, ole32)
 
-LoadDLLfuncEx (CreateHardLinkA, 12, kernel32, 1)
 LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1)
 LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1)
 LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1)
index 2ab830b..dcbc137 100644 (file)
@@ -1028,7 +1028,7 @@ fhandler_disk_file::link (const char *newpath)
 
   if (newpc.exists ())
     {
-      syscall_printf ("file '%s' exists?", (char *) newpc);
+      syscall_printf ("file '%s' exists?", newpc.get_win32 ());
       set_errno (EEXIST);
       return -1;
     }
@@ -1040,141 +1040,74 @@ fhandler_disk_file::link (const char *newpath)
       return -1;
     }
 
-  char new_buf[CYG_MAX_PATH + 5];
+  char new_buf[strlen (newpath) + 5];
   if (!newpc.error && !newpc.case_clash)
     {
-      DWORD bintype;
       int len;
 
       if (allow_winsymlinks && pc.is_lnk_special ())
        {
          /* Shortcut hack. */
-         strcpy (new_buf, newpath);
-         strcat (new_buf, ".lnk");
+         stpcpy (stpcpy (new_buf, newpath), ".lnk");
          newpath = new_buf;
          newpc.check (newpath, PC_SYM_NOFOLLOW);
        }
-      else if (transparent_exe
-              && !pc.isdir ()
-              && GetBinaryType (pc, &bintype)
-              && (len = strlen (newpc)) > 4
-              && !strcasematch ((const char *) newpc + len - 4, ".exe"))
+      else if (!pc.isdir ()
+              && (len = strlen (pc.get_win32 ())) > 4
+              && strcasematch (pc.get_win32 () + len - 4, ".exe")
+              && (len = strlen (newpc.get_win32 ())) > 4
+              && !strcasematch (newpc.get_win32 () + len - 4, ".exe"))
        {
          /* Executable hack. */
-         strcpy (new_buf, newpath);
-         strcat (new_buf, ".exe");
+         stpcpy (stpcpy (new_buf, newpath), ".exe");
          newpath = new_buf;
          newpc.check (newpath, PC_SYM_NOFOLLOW);
        }
     }
 
-  query_open (query_write_attributes);
-  if (!open (O_BINARY, 0))
+  HANDLE fh;
+  NTSTATUS status;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  status = NtOpenFile (&fh, 0,
+                      pc.get_object_attr (attr, sec_none_nih), &io,
+                      FILE_SHARE_VALID_FLAGS,
+                      FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
+  if (!NT_SUCCESS (status))
     {
-      syscall_printf ("Opening file failed");
-      __seterrno ();
+      __seterrno_from_nt_status (status);
       return -1;
     }
-
-  if (CreateHardLinkA (newpc, pc, NULL))
-    goto success;
-
-  /* There are two cases to consider:
-     - The FS doesn't support hard links ==> ERROR_INVALID_FUNCTION
-       We copy the file.
-     - CreateHardLinkA is not supported  ==> ERROR_PROC_NOT_FOUND
-       In that case (<= NT4) we try the old-style method.
-     Any other error should be taken seriously. */
-  if (GetLastError () == ERROR_INVALID_FUNCTION)
-    {
-      syscall_printf ("FS doesn't support hard links: Copy file");
-      goto docopy;
-    }
-  if (GetLastError () != ERROR_PROC_NOT_FOUND)
+  PUNICODE_STRING tgt = newpc.get_nt_native_path ();
+  ULONG size = sizeof (FILE_LINK_INFORMATION) + tgt->Length;
+  PFILE_LINK_INFORMATION pfli = (PFILE_LINK_INFORMATION) alloca (size);
+  pfli->ReplaceIfExists = FALSE;
+  pfli->RootDirectory = NULL;
+  memcpy (pfli->FileName, tgt->Buffer, pfli->FileNameLength = tgt->Length);
+  status = NtSetInformationFile (fh, &io, pfli, size, FileLinkInformation);
+  NtClose (fh);
+  if (!NT_SUCCESS (status))
     {
-      syscall_printf ("CreateHardLinkA failed");
-      __seterrno ();
-      close ();
-      return -1;
-    }
-
-  WIN32_STREAM_ID stream_id;
-  LPVOID context;
-  WCHAR wbuf[CYG_MAX_PATH];
-  BOOL ret;
-  DWORD written, write_err, path_len, size;
-
-  path_len = sys_mbstowcs (wbuf, newpc, CYG_MAX_PATH) * sizeof (WCHAR);
-
-  stream_id.dwStreamId = BACKUP_LINK;
-  stream_id.dwStreamAttributes = 0;
-  stream_id.dwStreamNameSize = 0;
-  stream_id.Size.HighPart = 0;
-  stream_id.Size.LowPart = path_len;
-  size = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**)
-        + stream_id.dwStreamNameSize;
-  context = NULL;
-  write_err = 0;
-  /* Write WIN32_STREAM_ID */
-  ret = BackupWrite (get_handle (), (LPBYTE) &stream_id, size,
-                    &written, FALSE, FALSE, &context);
-  if (ret)
-    {
-      /* write the buffer containing the path */
-      /* FIXME: BackupWrite sometimes traps if linkname is invalid.
-        Need to handle. */
-      ret = BackupWrite (get_handle (), (LPBYTE) wbuf, path_len,
-                        &written, FALSE, FALSE, &context);
-      if (!ret)
-       {
-         write_err = GetLastError ();
-         syscall_printf ("cannot write linkname, %E");
+      if (status == STATUS_INVALID_DEVICE_REQUEST)
+        {
+         /* FS doesn't support hard links.  Try to copy file. */
+         if (!CopyFileA (pc, newpc, TRUE))
+           {
+             __seterrno ();
+             return -1;
+           }
        }
-      /* Free context */
-      BackupWrite (get_handle (), NULL, 0, &written,
-                  TRUE, FALSE, &context);
-    }
-  else
-    {
-      write_err = GetLastError ();
-      syscall_printf ("cannot write stream_id, %E");
-    }
-
-  if (!ret)
-    {
-      /* Only copy file if FS doesn't support hard links */
-      if (write_err == ERROR_INVALID_FUNCTION)
-       {
-         syscall_printf ("FS doesn't support hard links: Copy file");
-         goto docopy;
+      else
+        {
+         __seterrno_from_nt_status (status);
+         return -1;
        }
-
-      close ();
-      __seterrno_from_win_error (write_err);
-      return -1;
     }
-
-success:
-  close ();
   if (!allow_winsymlinks && pc.is_lnk_special ())
     SetFileAttributes (newpc, (DWORD) pc
                               | FILE_ATTRIBUTE_SYSTEM
                               | FILE_ATTRIBUTE_READONLY);
   return 0;
-
-docopy:
-  /* do this with a copy */
-  if (!CopyFileA (pc, newpc, 1))
-    {
-      __seterrno ();
-      return -1;
-    }
-  close ();
-  fhandler_disk_file fh (newpc);
-  fh.query_open (query_write_attributes);
-  if (fh.open (O_BINARY, 0))
-    fh.close ();
-  return 0;
 }
 
 int
index cb2cccf..aca6725 100644 (file)
 #ifndef STATUS_INVALID_INFO_CLASS
 /* Some w32api header file defines this so we need to conditionalize this
    define to avoid warnings. */
-#define STATUS_INVALID_INFO_CLASS   ((NTSTATUS) 0xc0000003)
+#define STATUS_INVALID_INFO_CLASS     ((NTSTATUS) 0xc0000003)
 #endif
-#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
-#define STATUS_INVALID_PARAMETER    ((NTSTATUS) 0xc000000d)
-#define STATUS_BUFFER_TOO_SMALL     ((NTSTATUS) 0xc0000023)
-#define STATUS_SHARING_VIOLATION    ((NTSTATUS) 0xc0000043)
-#define STATUS_DELETE_PENDING       ((NTSTATUS) 0xc0000056)
-#define STATUS_WORKING_SET_QUOTA    ((NTSTATUS) 0xc00000a1)
-#define STATUS_NOT_ALL_ASSIGNED     ((NTSTATUS) 0x00000106)
-#define STATUS_INVALID_LEVEL        ((NTSTATUS) 0xc0000148)
-#define STATUS_NO_MORE_FILES        ((NTSTATUS) 0x80000006)
+#define STATUS_INFO_LENGTH_MISMATCH   ((NTSTATUS) 0xc0000004)
+#define STATUS_INVALID_PARAMETER      ((NTSTATUS) 0xc000000d)
+#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010)
+#define STATUS_BUFFER_TOO_SMALL       ((NTSTATUS) 0xc0000023)
+#define STATUS_SHARING_VIOLATION      ((NTSTATUS) 0xc0000043)
+#define STATUS_DELETE_PENDING         ((NTSTATUS) 0xc0000056)
+#define STATUS_WORKING_SET_QUOTA      ((NTSTATUS) 0xc00000a1)
+#define STATUS_NOT_ALL_ASSIGNED       ((NTSTATUS) 0x00000106)
+#define STATUS_INVALID_LEVEL          ((NTSTATUS) 0xc0000148)
+#define STATUS_NO_MORE_FILES          ((NTSTATUS) 0x80000006)
 #define PDI_MODULES 0x01
 #define PDI_HEAPS 0x04
 #define LDRP_IMAGE_DLL 0x00000004
@@ -581,6 +582,13 @@ typedef struct _FILE_NAME_INFORMATION {
   WCHAR FileName[1];
 } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
 
+typedef struct _FILE_LINK_INFORMATION {
+  BOOLEAN ReplaceIfExists;
+  HANDLE RootDirectory;
+  ULONG FileNameLength;
+  WCHAR FileName[1];
+} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
+
 typedef struct _FILE_RENAME_INFORMATION {
   BOOLEAN ReplaceIfExists;
   HANDLE RootDirectory;