* 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.
This commit is contained in:
Corinna Vinschen 2007-07-27 16:24:07 +00:00
parent f590b14dfd
commit 745c29fe7b
4 changed files with 68 additions and 118 deletions

View File

@ -1,3 +1,13 @@
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

View 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)

View 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)
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

View File

@ -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;