- 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:
KJK::Hyperion 2005-12-12 02:05:54 +00:00
parent 84560b15bb
commit 6b611c45ba
2 changed files with 170 additions and 78 deletions

View file

@ -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;
if(!lpSymlinkFileName || !lpTargetFileName)
ULONG dwCreateOptions;
DWORD dwErr;
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
dwCreateOptions = FILE_NON_DIRECTORY_FILE;
switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
{
IO_STATUS_BLOCK IoStatusBlock;
Status = NtOpenFile(&hTarget,
SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
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;
}
lpTargetFullFileName = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName * sizeof(WCHAR));
if(lpTargetFullFileName == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
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;
}
}
if (!NT_SUCCESS(Status))
cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length + cbPrintName;
pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData);
if(pReparseData == NULL)
{
SetLastErrorByStatus(Status);
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
NtClose(hTarget);
/*
* Create the symbolic link
*/
InitializeObjectAttributes(&ObjectAttributes,
&NtSymLink,
OBJ_PERMANENT,
NULL,
NULL);
pBufTail = (PBYTE)(pReparseData->SymbolicLinkReparseBuffer.PathBuffer);
Status = NtCreateSymbolicLinkObject(&hSymbolicLink,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&NtTargetName);
if (NT_SUCCESS(Status))
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))
{
NtClose(hSymbolicLink);
Ret = TRUE;
dwErr = ERROR_PATH_NOT_FOUND;
goto Cleanup;
}
else
InitializeObjectAttributes(&ObjectAttributes, &SymlinkFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtCreateFile
(
&hSymlink,
FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | dwCreateOptions,
NULL,
0
);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
dwErr = RtlNtStatusToDosError(Status);
goto Cleanup;
}
Status = NtFsControlFile
(
hSymlink,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_SET_REPARSE_POINT,
pReparseData,
cbReparseData,
NULL,
0
);
if(!NT_SUCCESS(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;
}
@ -474,23 +563,24 @@ CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,
{
PWCHAR SymlinkW, TargetW;
BOOL Ret;
if(!lpSymlinkFileName || !lpTargetFileName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!(SymlinkW = FilenameA2W(lpSymlinkFileName, FALSE)))
return FALSE;
if (!(TargetW = FilenameA2W(lpTargetFileName, TRUE)))
return FALSE;
Ret = CreateSymbolicLinkW(SymlinkW,
TargetW,
dwFlags);
RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW);
RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
return Ret;

View file

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