* 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

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