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