diff --git a/reactos/lib/kernel32/file/create.c b/reactos/lib/kernel32/file/create.c index 168cb52eb16..bcc0f574c08 100644 --- a/reactos/lib/kernel32/file/create.c +++ b/reactos/lib/kernel32/file/create.c @@ -359,15 +359,109 @@ HANDLE STDCALL CreateFileW (LPCWSTR lpFileName, /* - * @unimplemented + * @implemented */ BOOL STDCALL CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName, IN LPCWSTR lpTargetFileName, IN DWORD dwFlags) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + UNICODE_STRING NtSymLink, NtTargetName; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE hTarget, hSymbolicLink; + NTSTATUS Status; + BOOL Ret = FALSE; + + if(!lpSymlinkFileName || !lpTargetFileName) + { + 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); + } + else + { + 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); + } + + if (!NT_SUCCESS(Status)) + { + SetLastErrorByStatus(Status); + goto Cleanup; + } + + NtClose(hTarget); + + /* + * Create the symbolic link + */ + InitializeObjectAttributes(&ObjectAttributes, + &NtSymLink, + OBJ_PERMANENT, + NULL, + NULL); + + Status = NtCreateSymbolicLinkObject(&hSymbolicLink, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &NtTargetName); + if (NT_SUCCESS(Status)) + { + NtClose(hSymbolicLink); + Ret = TRUE; + } + else + { + SetLastErrorByStatus(Status); + } + +Cleanup: + RtlFreeUnicodeString(&NtTargetName); +Cleanup2: + RtlFreeUnicodeString(&NtSymLink); + + return Ret; } diff --git a/reactos/w32api/include/winbase.h b/reactos/w32api/include/winbase.h index 51e4c6a04c0..6d41f6645bd 100644 --- a/reactos/w32api/include/winbase.h +++ b/reactos/w32api/include/winbase.h @@ -504,6 +504,9 @@ extern "C" { #define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x00000004 #define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x00000008 #define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x00000010 +#if (_WIN32_WINNT >= 0x0600) +#define SYMLINK_FLAG_DIRECTORY 0x1 +#endif #endif /* (_WIN32_WINNT >= 0x0501) */ #if (_WIN32_WINNT >= 0x0500) #define REPLACEFILE_WRITE_THROUGH 0x00000001