mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
- Replaced horribly broken implementation of CreateSymbolicLinkW with actual implementation.
- Defined IO_REPARSE_TAG_SYMLINK and corrected REPARSE_DATA_BUFFER as per ntifs.h version 0145 svn path=/trunk/; revision=20098
This commit is contained in:
parent
84560b15bb
commit
6b611c45ba
2 changed files with 170 additions and 78 deletions
|
@ -365,102 +365,191 @@ CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
|
||||||
IN LPCWSTR lpTargetFileName,
|
IN LPCWSTR lpTargetFileName,
|
||||||
IN DWORD dwFlags)
|
IN DWORD dwFlags)
|
||||||
{
|
{
|
||||||
UNICODE_STRING NtSymLink, NtTargetName;
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
HANDLE hTarget, hSymbolicLink;
|
HANDLE hSymlink = NULL;
|
||||||
|
UNICODE_STRING SymlinkFileName = { 0, 0, NULL };
|
||||||
|
UNICODE_STRING TargetFileName = { 0, 0, NULL };
|
||||||
|
BOOLEAN bRelativePath = FALSE;
|
||||||
|
LPWSTR lpTargetFullFileName = NULL;
|
||||||
|
SIZE_T cbPrintName;
|
||||||
|
SIZE_T cbReparseData;
|
||||||
|
PREPARSE_DATA_BUFFER pReparseData = NULL;
|
||||||
|
PBYTE pBufTail;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
BOOL Ret = FALSE;
|
ULONG dwCreateOptions;
|
||||||
|
DWORD dwErr;
|
||||||
|
|
||||||
if(!lpSymlinkFileName || !lpTargetFileName)
|
if(!lpSymlinkFileName || !lpTargetFileName || (dwFlags | SYMLINK_FLAG_DIRECTORY) != SYMLINK_FLAG_DIRECTORY)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpSymlinkFileName,
|
if(dwFlags & SYMLINK_FLAG_DIRECTORY)
|
||||||
&NtSymLink,
|
dwCreateOptions = FILE_DIRECTORY_FILE;
|
||||||
NULL,
|
|
||||||
NULL))
|
|
||||||
{
|
|
||||||
/* FIXME - right error code? */
|
|
||||||
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpTargetFileName,
|
|
||||||
&NtTargetName,
|
|
||||||
NULL,
|
|
||||||
NULL))
|
|
||||||
{
|
|
||||||
/* FIXME - right error code? */
|
|
||||||
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
||||||
goto Cleanup2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to open the target
|
|
||||||
*/
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
|
||||||
&NtTargetName,
|
|
||||||
OBJ_CASE_INSENSITIVE,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (dwFlags == SYMLINK_FLAG_DIRECTORY)
|
|
||||||
{
|
|
||||||
Status = NtOpenDirectoryObject(&hTarget,
|
|
||||||
SYNCHRONIZE,
|
|
||||||
&ObjectAttributes);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
dwCreateOptions = FILE_NON_DIRECTORY_FILE;
|
||||||
IO_STATUS_BLOCK IoStatusBlock;
|
|
||||||
|
|
||||||
Status = NtOpenFile(&hTarget,
|
switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
|
||||||
SYNCHRONIZE,
|
|
||||||
&ObjectAttributes,
|
|
||||||
&IoStatusBlock,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
||||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
SetLastErrorByStatus(Status);
|
case INVALID_PATH:
|
||||||
|
case ABSOLUTE_PATH:
|
||||||
|
case RELATIVE_PATH:
|
||||||
|
bRelativePath = TRUE;
|
||||||
|
RtlInitUnicodeString(&TargetFileName, lpTargetFileName);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RELATIVE_DRIVE_PATH:
|
||||||
|
{
|
||||||
|
LPWSTR FilePart;
|
||||||
|
SIZE_T cchTargetFullFileName;
|
||||||
|
|
||||||
|
cchTargetFullFileName = GetFullPathNameW(lpTargetFileName, 0, NULL, &FilePart);
|
||||||
|
|
||||||
|
if(cchTargetFullFileName == 0)
|
||||||
|
{
|
||||||
|
dwErr = GetLastError();
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
NtClose(hTarget);
|
lpTargetFullFileName = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName * sizeof(WCHAR));
|
||||||
|
|
||||||
/*
|
if(lpTargetFullFileName == NULL)
|
||||||
* Create the symbolic link
|
{
|
||||||
*/
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
goto Cleanup;
|
||||||
&NtSymLink,
|
}
|
||||||
OBJ_PERMANENT,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
Status = NtCreateSymbolicLinkObject(&hSymbolicLink,
|
if(GetFullPathNameW(lpTargetFileName, cchTargetFullFileName, lpTargetFullFileName, &FilePart) == 0)
|
||||||
SYMBOLIC_LINK_ALL_ACCESS,
|
{
|
||||||
|
dwErr = GetLastError();
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lpTargetFileName = lpTargetFullFileName;
|
||||||
|
|
||||||
|
// fallthrough
|
||||||
|
|
||||||
|
case UNC_PATH:
|
||||||
|
case ABSOLUTE_DRIVE_PATH:
|
||||||
|
case DEVICE_PATH:
|
||||||
|
case UNC_DOT_PATH:
|
||||||
|
default:
|
||||||
|
if(!RtlDosPathNameToNtPathName_U((LPWSTR)lpTargetFileName, &TargetFileName, NULL, NULL))
|
||||||
|
{
|
||||||
|
dwErr = ERROR_INVALID_PARAMETER;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
|
||||||
|
cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length + cbPrintName;
|
||||||
|
pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData);
|
||||||
|
|
||||||
|
if(pReparseData == NULL)
|
||||||
|
{
|
||||||
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
pBufTail = (PBYTE)(pReparseData->SymbolicLinkReparseBuffer.PathBuffer);
|
||||||
|
|
||||||
|
pReparseData->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||||
|
pReparseData->ReparseDataLength = cbReparseData - REPARSE_DATA_BUFFER_HEADER_SIZE;
|
||||||
|
pReparseData->Reserved = 0;
|
||||||
|
|
||||||
|
pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
|
||||||
|
pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength = TargetFileName.Length;
|
||||||
|
pBufTail += pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset;
|
||||||
|
RtlCopyMemory(pBufTail, TargetFileName.Buffer, TargetFileName.Length);
|
||||||
|
|
||||||
|
pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset = pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||||
|
pReparseData->SymbolicLinkReparseBuffer.PrintNameLength = cbPrintName;
|
||||||
|
pBufTail += pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset;
|
||||||
|
RtlCopyMemory(pBufTail, lpTargetFileName, cbPrintName);
|
||||||
|
|
||||||
|
pReparseData->SymbolicLinkReparseBuffer.Flags = 0;
|
||||||
|
|
||||||
|
if(bRelativePath)
|
||||||
|
pReparseData->SymbolicLinkReparseBuffer.Flags |= 1; // TODO! give this lone flag a name
|
||||||
|
|
||||||
|
if(!RtlDosPathNameToNtPathName_U((LPWSTR)lpSymlinkFileName, &SymlinkFileName, NULL, NULL))
|
||||||
|
{
|
||||||
|
dwErr = ERROR_PATH_NOT_FOUND;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &SymlinkFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||||
|
|
||||||
|
Status = NtCreateFile
|
||||||
|
(
|
||||||
|
&hSymlink,
|
||||||
|
FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
|
||||||
&ObjectAttributes,
|
&ObjectAttributes,
|
||||||
&NtTargetName);
|
&IoStatusBlock,
|
||||||
if (NT_SUCCESS(Status))
|
NULL,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0,
|
||||||
|
FILE_CREATE,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | dwCreateOptions,
|
||||||
|
NULL,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
NtClose(hSymbolicLink);
|
dwErr = RtlNtStatusToDosError(Status);
|
||||||
Ret = TRUE;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
Status = NtFsControlFile
|
||||||
|
(
|
||||||
|
hSymlink,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&IoStatusBlock,
|
||||||
|
FSCTL_SET_REPARSE_POINT,
|
||||||
|
pReparseData,
|
||||||
|
cbReparseData,
|
||||||
|
NULL,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
SetLastErrorByStatus(Status);
|
FILE_DISPOSITION_INFORMATION DispInfo;
|
||||||
|
DispInfo.DeleteFile = TRUE;
|
||||||
|
NtSetInformationFile(hSymlink, &IoStatusBlock, &DispInfo, sizeof(DispInfo), FileDispositionInformation);
|
||||||
|
|
||||||
|
dwErr = RtlNtStatusToDosError(Status);
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dwErr = NO_ERROR;
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
RtlFreeUnicodeString(&NtTargetName);
|
if(hSymlink)
|
||||||
Cleanup2:
|
NtClose(hSymlink);
|
||||||
RtlFreeUnicodeString(&NtSymLink);
|
|
||||||
|
|
||||||
return Ret;
|
RtlFreeUnicodeString(&SymlinkFileName);
|
||||||
|
RtlFreeUnicodeString(&TargetFileName);
|
||||||
|
|
||||||
|
if(lpTargetFullFileName)
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName);
|
||||||
|
|
||||||
|
if(pReparseData)
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData);
|
||||||
|
|
||||||
|
if(dwErr)
|
||||||
|
{
|
||||||
|
SetLastError(dwErr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -491,6 +580,7 @@ CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,
|
||||||
TargetW,
|
TargetW,
|
||||||
dwFlags);
|
dwFlags);
|
||||||
|
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW);
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
|
RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
|
||||||
|
|
||||||
return Ret;
|
return Ret;
|
||||||
|
|
|
@ -1491,6 +1491,7 @@ typedef enum
|
||||||
#define IsReparseTagValid(x) (!((x)&~IO_REPARSE_TAG_VALID_VALUES)&&((x)>IO_REPARSE_TAG_RESERVED_RANGE))
|
#define IsReparseTagValid(x) (!((x)&~IO_REPARSE_TAG_VALID_VALUES)&&((x)>IO_REPARSE_TAG_RESERVED_RANGE))
|
||||||
#define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO
|
#define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO
|
||||||
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
|
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
|
||||||
|
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
||||||
#ifndef RC_INVOKED
|
#ifndef RC_INVOKED
|
||||||
typedef DWORD ACCESS_MASK, *PACCESS_MASK;
|
typedef DWORD ACCESS_MASK, *PACCESS_MASK;
|
||||||
|
|
||||||
|
@ -3113,6 +3114,7 @@ typedef struct _REPARSE_DATA_BUFFER {
|
||||||
WORD SubstituteNameLength;
|
WORD SubstituteNameLength;
|
||||||
WORD PrintNameOffset;
|
WORD PrintNameOffset;
|
||||||
WORD PrintNameLength;
|
WORD PrintNameLength;
|
||||||
|
ULONG Flags;
|
||||||
WCHAR PathBuffer[1];
|
WCHAR PathBuffer[1];
|
||||||
} SymbolicLinkReparseBuffer;
|
} SymbolicLinkReparseBuffer;
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Reference in a new issue