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 DWORD dwFlags)
|
||||
{
|
||||
UNICODE_STRING NtSymLink, NtTargetName;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
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;
|
||||
BOOL Ret = FALSE;
|
||||
ULONG dwCreateOptions;
|
||||
DWORD dwErr;
|
||||
|
||||
if(!lpSymlinkFileName || !lpTargetFileName)
|
||||
if(!lpSymlinkFileName || !lpTargetFileName || (dwFlags | SYMLINK_FLAG_DIRECTORY) != SYMLINK_FLAG_DIRECTORY)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpSymlinkFileName,
|
||||
&NtSymLink,
|
||||
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);
|
||||
}
|
||||
if(dwFlags & SYMLINK_FLAG_DIRECTORY)
|
||||
dwCreateOptions = FILE_DIRECTORY_FILE;
|
||||
else
|
||||
{
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
dwCreateOptions = FILE_NON_DIRECTORY_FILE;
|
||||
|
||||
Status = NtOpenFile(&hTarget,
|
||||
SYNCHRONIZE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
NtClose(hTarget);
|
||||
lpTargetFullFileName = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName * sizeof(WCHAR));
|
||||
|
||||
/*
|
||||
* Create the symbolic link
|
||||
*/
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&NtSymLink,
|
||||
OBJ_PERMANENT,
|
||||
NULL,
|
||||
NULL);
|
||||
if(lpTargetFullFileName == NULL)
|
||||
{
|
||||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
Status = NtCreateSymbolicLinkObject(&hSymbolicLink,
|
||||
SYMBOLIC_LINK_ALL_ACCESS,
|
||||
if(GetFullPathNameW(lpTargetFileName, cchTargetFullFileName, lpTargetFullFileName, &FilePart) == 0)
|
||||
{
|
||||
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,
|
||||
&NtTargetName);
|
||||
if (NT_SUCCESS(Status))
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
FILE_CREATE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | dwCreateOptions,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
NtClose(hSymbolicLink);
|
||||
Ret = TRUE;
|
||||
dwErr = RtlNtStatusToDosError(Status);
|
||||
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:
|
||||
RtlFreeUnicodeString(&NtTargetName);
|
||||
Cleanup2:
|
||||
RtlFreeUnicodeString(&NtSymLink);
|
||||
if(hSymlink)
|
||||
NtClose(hSymlink);
|
||||
|
||||
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,
|
||||
dwFlags);
|
||||
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
|
||||
|
||||
return Ret;
|
||||
|
|
|
@ -1491,6 +1491,7 @@ typedef enum
|
|||
#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_MOUNT_POINT 0xA0000003
|
||||
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
||||
#ifndef RC_INVOKED
|
||||
typedef DWORD ACCESS_MASK, *PACCESS_MASK;
|
||||
|
||||
|
@ -3113,6 +3114,7 @@ typedef struct _REPARSE_DATA_BUFFER {
|
|||
WORD SubstituteNameLength;
|
||||
WORD PrintNameOffset;
|
||||
WORD PrintNameLength;
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[1];
|
||||
} SymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
|
|
Loading…
Reference in a new issue