- 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
Modified: trunk/reactos/lib/kernel32/file/create.c
Modified: trunk/reactos/w32api/include/winnt.h
_____
Modified: trunk/reactos/lib/kernel32/file/create.c
--- trunk/reactos/lib/kernel32/file/create.c 2005-12-12 00:36:31 UTC
(rev 20097)
+++ trunk/reactos/lib/kernel32/file/create.c 2005-12-12 02:05:54 UTC
(rev 20098)
@@ -365,102 +365,191 @@
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))
+
+ if(dwFlags & SYMLINK_FLAG_DIRECTORY)
+ dwCreateOptions = FILE_DIRECTORY_FILE;
+ else
+ dwCreateOptions = FILE_NON_DIRECTORY_FILE;
+
+ switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
{
- /* FIXME - right error code? */
- SetLastError(ERROR_PATH_NOT_FOUND);
- return FALSE;
+ 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 (!RtlDosPathNameToNtPathName_U((LPWSTR)lpTargetFileName,
- &NtTargetName,
- NULL,
- NULL))
+
+ cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
+ cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER,
SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length +
cbPrintName;
+ pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0,
cbReparseData);
+
+ if(pReparseData == NULL)
{
- /* FIXME - right error code? */
- SetLastError(ERROR_PATH_NOT_FOUND);
- goto Cleanup2;
+ dwErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
}
-
- /*
- * Try to open the target
- */
- InitializeObjectAttributes(&ObjectAttributes,
- &NtTargetName,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- if (dwFlags == SYMLINK_FLAG_DIRECTORY)
+
+ 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))
{
- Status = NtOpenDirectoryObject(&hTarget,
- SYNCHRONIZE,
- &ObjectAttributes);
+ 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))
{
- 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);
+ dwErr = RtlNtStatusToDosError(Status);
+ goto Cleanup;
}
-
- if (!NT_SUCCESS(Status))
+
+ 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;
}
- NtClose(hTarget);
-
- /*
- * Create the symbolic link
- */
- InitializeObjectAttributes(&ObjectAttributes,
- &NtSymLink,
- OBJ_PERMANENT,
- NULL,
- NULL);
+ dwErr = NO_ERROR;
- Status = NtCreateSymbolicLinkObject(&hSymbolicLink,
- SYMBOLIC_LINK_ALL_ACCESS,
- &ObjectAttributes,
- &NtTargetName);
- if (NT_SUCCESS(Status))
+Cleanup:
+ if(hSymlink)
+ NtClose(hSymlink);
+
+ RtlFreeUnicodeString(&SymlinkFileName);
+ RtlFreeUnicodeString(&TargetFileName);
+
+ if(lpTargetFullFileName)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName);
+
+ if(pReparseData)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData);
+
+ if(dwErr)
{
- NtClose(hSymbolicLink);
- Ret = TRUE;
+ SetLastError(dwErr);
+ return FALSE;
}
- else
- {
- SetLastErrorByStatus(Status);
- }
-Cleanup:
- RtlFreeUnicodeString(&NtTargetName);
-Cleanup2:
- RtlFreeUnicodeString(&NtSymLink);
-
- return Ret;
+ return TRUE;
}
@@ -474,23 +563,24 @@
{
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;
_____
Modified: trunk/reactos/w32api/include/winnt.h
--- trunk/reactos/w32api/include/winnt.h 2005-12-12 00:36:31 UTC
(rev 20097)
+++ trunk/reactos/w32api/include/winnt.h 2005-12-12 02:05:54 UTC
(rev 20098)
@@ -1491,6 +1491,7 @@
#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 @@
WORD SubstituteNameLength;
WORD PrintNameOffset;
WORD PrintNameLength;
+ ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {