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