* 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:
parent
f590b14dfd
commit
745c29fe7b
@ -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>
|
2007-07-27 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* fhandler_disk_file.cc (fhandler_disk_file::ftruncate): Use
|
* fhandler_disk_file.cc (fhandler_disk_file::ftruncate): Use
|
||||||
|
@ -393,7 +393,6 @@ LoadDLLfuncEx2 (SendARP, 16, iphlpapi, 1, 50)
|
|||||||
|
|
||||||
LoadDLLfunc (CoTaskMemFree, 4, ole32)
|
LoadDLLfunc (CoTaskMemFree, 4, ole32)
|
||||||
|
|
||||||
LoadDLLfuncEx (CreateHardLinkA, 12, kernel32, 1)
|
|
||||||
LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1)
|
LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1)
|
||||||
LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1)
|
LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1)
|
||||||
LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1)
|
LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1)
|
||||||
|
@ -1028,7 +1028,7 @@ fhandler_disk_file::link (const char *newpath)
|
|||||||
|
|
||||||
if (newpc.exists ())
|
if (newpc.exists ())
|
||||||
{
|
{
|
||||||
syscall_printf ("file '%s' exists?", (char *) newpc);
|
syscall_printf ("file '%s' exists?", newpc.get_win32 ());
|
||||||
set_errno (EEXIST);
|
set_errno (EEXIST);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1040,141 +1040,74 @@ fhandler_disk_file::link (const char *newpath)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char new_buf[CYG_MAX_PATH + 5];
|
char new_buf[strlen (newpath) + 5];
|
||||||
if (!newpc.error && !newpc.case_clash)
|
if (!newpc.error && !newpc.case_clash)
|
||||||
{
|
{
|
||||||
DWORD bintype;
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (allow_winsymlinks && pc.is_lnk_special ())
|
if (allow_winsymlinks && pc.is_lnk_special ())
|
||||||
{
|
{
|
||||||
/* Shortcut hack. */
|
/* Shortcut hack. */
|
||||||
strcpy (new_buf, newpath);
|
stpcpy (stpcpy (new_buf, newpath), ".lnk");
|
||||||
strcat (new_buf, ".lnk");
|
|
||||||
newpath = new_buf;
|
newpath = new_buf;
|
||||||
newpc.check (newpath, PC_SYM_NOFOLLOW);
|
newpc.check (newpath, PC_SYM_NOFOLLOW);
|
||||||
}
|
}
|
||||||
else if (transparent_exe
|
else if (!pc.isdir ()
|
||||||
&& !pc.isdir ()
|
&& (len = strlen (pc.get_win32 ())) > 4
|
||||||
&& GetBinaryType (pc, &bintype)
|
&& strcasematch (pc.get_win32 () + len - 4, ".exe")
|
||||||
&& (len = strlen (newpc)) > 4
|
&& (len = strlen (newpc.get_win32 ())) > 4
|
||||||
&& !strcasematch ((const char *) newpc + len - 4, ".exe"))
|
&& !strcasematch (newpc.get_win32 () + len - 4, ".exe"))
|
||||||
{
|
{
|
||||||
/* Executable hack. */
|
/* Executable hack. */
|
||||||
strcpy (new_buf, newpath);
|
stpcpy (stpcpy (new_buf, newpath), ".exe");
|
||||||
strcat (new_buf, ".exe");
|
|
||||||
newpath = new_buf;
|
newpath = new_buf;
|
||||||
newpc.check (newpath, PC_SYM_NOFOLLOW);
|
newpc.check (newpath, PC_SYM_NOFOLLOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query_open (query_write_attributes);
|
HANDLE fh;
|
||||||
if (!open (O_BINARY, 0))
|
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))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
if (status == STATUS_INVALID_DEVICE_REQUEST)
|
||||||
|
{
|
||||||
|
/* FS doesn't support hard links. Try to copy file. */
|
||||||
|
if (!CopyFileA (pc, newpc, TRUE))
|
||||||
{
|
{
|
||||||
syscall_printf ("Opening file failed");
|
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
return -1;
|
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)
|
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
/* Free context */
|
|
||||||
BackupWrite (get_handle (), NULL, 0, &written,
|
|
||||||
TRUE, FALSE, &context);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_err = GetLastError ();
|
__seterrno_from_nt_status (status);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
close ();
|
|
||||||
__seterrno_from_win_error (write_err);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
success:
|
|
||||||
close ();
|
|
||||||
if (!allow_winsymlinks && pc.is_lnk_special ())
|
if (!allow_winsymlinks && pc.is_lnk_special ())
|
||||||
SetFileAttributes (newpc, (DWORD) pc
|
SetFileAttributes (newpc, (DWORD) pc
|
||||||
| FILE_ATTRIBUTE_SYSTEM
|
| FILE_ATTRIBUTE_SYSTEM
|
||||||
| FILE_ATTRIBUTE_READONLY);
|
| FILE_ATTRIBUTE_READONLY);
|
||||||
return 0;
|
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
|
int
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
|
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
|
||||||
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
|
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
|
||||||
|
#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010)
|
||||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
|
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
|
||||||
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
|
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
|
||||||
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056)
|
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056)
|
||||||
@ -581,6 +582,13 @@ typedef struct _FILE_NAME_INFORMATION {
|
|||||||
WCHAR FileName[1];
|
WCHAR FileName[1];
|
||||||
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
|
} 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 {
|
typedef struct _FILE_RENAME_INFORMATION {
|
||||||
BOOLEAN ReplaceIfExists;
|
BOOLEAN ReplaceIfExists;
|
||||||
HANDLE RootDirectory;
|
HANDLE RootDirectory;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user