diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b86eb882e..0ddebd52d 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,13 @@ +2007-07-27 Corinna Vinschen + + * 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 * fhandler_disk_file.cc (fhandler_disk_file::ftruncate): Use diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index c1a2cad0d..09e645a72 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -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) diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 2ab830bc5..dcbc137e9 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -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) + 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 ("FS doesn't support hard links: Copy file"); - goto docopy; - } - if (GetLastError () != ERROR_PROC_NOT_FOUND) - { - 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 diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index cb2cccfa1..aca672533 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -11,17 +11,18 @@ #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;