add stubs for CreateSymbolicLinkA/W
[reactos.git] / reactos / lib / kernel32 / file / create.c
index 3c9e636..168cb52 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/file/create.c
  * UPDATE HISTORY:
  *                  Created 01/11/98
  *                  Removed use of SearchPath (not used by Windows)
+ *                  18/08/2002: CreateFileW mess cleaned up (KJK::Hyperion)
+ *                  24/08/2002: removed superfluous DPRINTs (KJK::Hyperion)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <windows.h>
-#include <ddk/ntddk.h>
-#include <wchar.h>
-#include <string.h>
-
-//#define NDEBUG
-#include <kernel32/kernel32.h>
+#include <k32.h>
 
-/* EXTERNS ******************************************************************/
+#define NDEBUG
+#include "../include/debug.h"
 
-DWORD STDCALL GetCurrentDriveW(DWORD nBufferLength, PWSTR lpBuffer);
 
 /* FUNCTIONS ****************************************************************/
 
-HANDLE STDCALL CreateFileA(LPCSTR lpFileName,
-                          DWORD dwDesiredAccess,
-                          DWORD dwShareMode,
-                          LPSECURITY_ATTRIBUTES lpSecurityAttributes,
-                          DWORD dwCreationDisposition,
-                          DWORD dwFlagsAndAttributes,
-                          HANDLE hTemplateFile)
+/*
+ * @implemented
+ */
+HANDLE STDCALL CreateFileA (LPCSTR                     lpFileName,
+                           DWORD                       dwDesiredAccess,
+                           DWORD                       dwShareMode,
+                           LPSECURITY_ATTRIBUTES       lpSecurityAttributes,
+                           DWORD                       dwCreationDisposition,
+                           DWORD                       dwFlagsAndAttributes,
+                           HANDLE                      hTemplateFile)
 {
+   PWCHAR FileNameW;
+   HANDLE FileHandle;
 
-   WCHAR FileNameW[MAX_PATH];
-   ULONG i = 0;
-   
    DPRINT("CreateFileA(lpFileName %s)\n",lpFileName);
-   
-   while ((*lpFileName)!=0 && i < MAX_PATH)
-     {
-       FileNameW[i] = *lpFileName;
-       lpFileName++;
-       i++;
-     }
-   FileNameW[i] = 0;
-   return CreateFileW(FileNameW,dwDesiredAccess,
-                     dwShareMode,
-                     lpSecurityAttributes,
-                     dwCreationDisposition,
-                     dwFlagsAndAttributes, 
-                     hTemplateFile);
+
+   if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
+      return INVALID_HANDLE_VALUE;
+
+   FileHandle = CreateFileW (FileNameW,
+                            dwDesiredAccess,
+                            dwShareMode,
+                            lpSecurityAttributes,
+                            dwCreationDisposition,
+                            dwFlagsAndAttributes,
+                            hTemplateFile);
+
+   return FileHandle;
 }
 
 
-HANDLE STDCALL CreateFileW(LPCWSTR lpFileName,
-                          DWORD dwDesiredAccess,
-                          DWORD dwShareMode,
-                          LPSECURITY_ATTRIBUTES lpSecurityAttributes,
-                          DWORD dwCreationDisposition,
-                          DWORD dwFlagsAndAttributes,
-                          HANDLE hTemplateFile)
+/*
+ * @implemented
+ */
+HANDLE STDCALL CreateFileW (LPCWSTR                    lpFileName,
+                           DWORD                       dwDesiredAccess,
+                           DWORD                       dwShareMode,
+                           LPSECURITY_ATTRIBUTES       lpSecurityAttributes,
+                           DWORD                       dwCreationDisposition,
+                           DWORD                       dwFlagsAndAttributes,
+                           HANDLE                      hTemplateFile)
 {
-   HANDLE FileHandle;
-   NTSTATUS Status;  
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatusBlock;
-   UNICODE_STRING FileNameString;
-   ULONG Flags = 0;
-   WCHAR PathNameW[MAX_PATH];
-   WCHAR FileNameW[MAX_PATH];
-   WCHAR *FilePart;
-   UINT Len = 0;
-   
+   UNICODE_STRING NtPathU;
+   HANDLE FileHandle;
+   NTSTATUS Status;
+   ULONG FileAttributes, Flags = 0;
+   CSR_API_MESSAGE Request;
+   PVOID EaBuffer = NULL;
+   ULONG EaLength = 0;
+
+   DPRINT("CreateFileW(lpFileName %S)\n",lpFileName);
+
+   /* validate & translate the creation disposition */
    switch (dwCreationDisposition)
      {
       case CREATE_NEW:
        dwCreationDisposition = FILE_CREATE;
        break;
-       
+
       case CREATE_ALWAYS:
        dwCreationDisposition = FILE_OVERWRITE_IF;
        break;
-       
+
       case OPEN_EXISTING:
        dwCreationDisposition = FILE_OPEN;
        break;
-       
+
       case OPEN_ALWAYS:
-       dwCreationDisposition = OPEN_ALWAYS;
+       dwCreationDisposition = FILE_OPEN_IF;
        break;
-       
+
       case TRUNCATE_EXISTING:
        dwCreationDisposition = FILE_OVERWRITE;
+        break;
+
+      default:
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return (INVALID_HANDLE_VALUE);
      }
-   
-   DPRINT("CreateFileW(lpFileName %w)\n",lpFileName);
-  
+
+   /* validate & translate the filename */
+   if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
+                                     &NtPathU,
+                                     NULL,
+                                     NULL))
+   {
+     DPRINT("Invalid path\n");
+     SetLastError(ERROR_PATH_NOT_FOUND);
+     return INVALID_HANDLE_VALUE;
+   }
+
+   DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
+
+  /* validate & translate the flags */
+
+   /* translate the flags that need no validation */
    if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
-     {
-       Flags |= FILE_SYNCHRONOUS_IO_ALERT;
-     }
-   
-   if (lpFileName[1] == (WCHAR)':') 
-     {
-       wcscpy(PathNameW, lpFileName);
-     }
-   else if (wcslen(lpFileName) > 4 &&
-           lpFileName[0] == (WCHAR)'\\' &&
-           lpFileName[1] == (WCHAR)'\\' &&
-           lpFileName[2] == (WCHAR)'.' &&
-           lpFileName[3] == (WCHAR)'\\')
-     {
-       wcscpy(PathNameW, lpFileName);
-     }
-   else if (lpFileName[0] == (WCHAR)'\\')
-     {
-       GetCurrentDriveW(MAX_PATH,PathNameW);
-       wcscat(PathNameW, lpFileName);
-     }
+   {
+      /* yes, nonalert is correct! apc's are not delivered
+      while waiting for file io to complete */
+      Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
+   }
+
+   if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
+      Flags |= FILE_WRITE_THROUGH;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
+      Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
+      Flags |= FILE_RANDOM_ACCESS;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
+      Flags |= FILE_SEQUENTIAL_ONLY;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
+      Flags |= FILE_DELETE_ON_CLOSE;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
+   {
+      if(dwDesiredAccess & GENERIC_ALL)
+         Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
+      else
+      {
+         if(dwDesiredAccess & GENERIC_READ)
+            Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
+
+         if(dwDesiredAccess & GENERIC_WRITE)
+            Flags |= FILE_OPEN_FOR_RECOVERY;
+      }
+   }
    else
-     {
-       Len =  GetCurrentDirectoryW(MAX_PATH,PathNameW);
-       if ( Len == 0 )
-         return NULL;
-       if ( PathNameW[Len-1] != L'\\' ) {
-          PathNameW[Len] = L'\\';
-          PathNameW[Len+1] = 0;
-       }
-       wcscat(PathNameW,lpFileName); 
-     }
-   
-   FileNameW[0] = '\\';
-   FileNameW[1] = '?';
-   FileNameW[2] = '?';
-   FileNameW[3] = '\\';
-   FileNameW[4] = 0;
-   wcscat(FileNameW,PathNameW);
-      
-   FileNameString.Length = wcslen( FileNameW)*sizeof(WCHAR);
-   
-   if ( FileNameString.Length == 0 )
-       return NULL;
-
-   if ( FileNameString.Length > MAX_PATH*sizeof(WCHAR) )
-       return NULL;
-   
-   FileNameString.Buffer = (WCHAR *)FileNameW;
-   FileNameString.MaximumLength = FileNameString.Length + sizeof(WCHAR);
-   
-   ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-   ObjectAttributes.RootDirectory = NULL;
-   ObjectAttributes.ObjectName = &FileNameString;
-   ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
-   ObjectAttributes.SecurityDescriptor = NULL;
-   ObjectAttributes.SecurityQualityOfService = NULL;
-
-   DPRINT("File Name %w\n",FileNameW);
-   
-   Status = ZwCreateFile(&FileHandle,
-                        dwDesiredAccess,
-                        &ObjectAttributes,
-                        &IoStatusBlock,
-                        NULL,
-                        dwFlagsAndAttributes,
-                        dwShareMode,
-                        dwCreationDisposition,
-                        Flags,
-                        NULL,
-                        0);
+      Flags |= FILE_NON_DIRECTORY_FILE;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
+      Flags |= FILE_OPEN_REPARSE_POINT;
+
+   if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
+      Flags |= FILE_OPEN_NO_RECALL;
+
+   FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
+
+   /* handle may allways be waited on and querying attributes are allways allowed */
+   dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
+
+   /* FILE_FLAG_POSIX_SEMANTICS is handled later */
+
+   /* check for console output */
+   if (0 == _wcsicmp(L"CONOUT$", lpFileName))
+   {
+      /* FIXME: Send required access rights to Csrss */
+      Status = CsrClientCallServer(&Request,
+                                  NULL,
+                                  MAKE_CSR_API(GET_OUTPUT_HANDLE, CSR_NATIVE),
+                                  sizeof(CSR_API_MESSAGE));
+      if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
+      {
+         SetLastErrorByStatus(Status);
+        return INVALID_HANDLE_VALUE;
+      }
+      else
+      {
+         return Request.Data.GetOutputHandleRequest.OutputHandle;
+      }
+   }
+
+   /* check for console input */
+   if (0 == _wcsicmp(L"CONIN$", lpFileName))
+   {
+      /* FIXME: Send required access rights to Csrss */
+      Status = CsrClientCallServer(&Request,
+                                  NULL,
+                                  MAKE_CSR_API(GET_INPUT_HANDLE, CSR_NATIVE),
+                                  sizeof(CSR_API_MESSAGE));
+      if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
+      {
+         SetLastErrorByStatus(Status);
+        return INVALID_HANDLE_VALUE;
+      }
+      else
+      {
+         return Request.Data.GetInputHandleRequest.InputHandle;
+      }
+   }
+
+   if (hTemplateFile != NULL)
+   {
+      FILE_EA_INFORMATION EaInformation;
+
+      for (;;)
+      {
+         /* try to get the size of the extended attributes, if we fail just continue
+            creating the file without copying the attributes! */
+         Status = NtQueryInformationFile(hTemplateFile,
+                                         &IoStatusBlock,
+                                         &EaInformation,
+                                         sizeof(FILE_EA_INFORMATION),
+                                         FileEaInformation);
+         if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
+         {
+            /* there's extended attributes to read, let's give it a try */
+            EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                       0,
+                                       EaInformation.EaSize);
+            if (EaBuffer == NULL)
+            {
+               /* the template file handle is valid and has extended attributes,
+                  however we seem to lack some memory here. We should fail here! */
+               SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+               return INVALID_HANDLE_VALUE;
+            }
+
+            Status = NtQueryEaFile(hTemplateFile,
+                                   &IoStatusBlock,
+                                   EaBuffer,
+                                   EaInformation.EaSize,
+                                   FALSE,
+                                   NULL,
+                                   0,
+                                   NULL,
+                                   TRUE);
+
+            if (NT_SUCCESS(Status))
+            {
+               /* we successfully read the extended attributes, break the loop
+                  and continue */
+               EaLength = EaInformation.EaSize;
+               break;
+            }
+            else
+            {
+               RtlFreeHeap(RtlGetProcessHeap(),
+                           0,
+                           EaBuffer);
+               EaBuffer = NULL;
+
+               if (Status != STATUS_BUFFER_TOO_SMALL)
+               {
+                  /* unless we just allocated not enough memory, break the loop
+                     and just continue without copying extended attributes */
+                  break;
+               }
+            }
+         }
+         else
+         {
+            /* we either failed to get the size of the extended attributes or
+               they're empty, just continue as there's no need to copy
+               attributes */
+            break;
+         }
+      }
+   }
+
+   /* build the object attributes */
+   InitializeObjectAttributes(&ObjectAttributes,
+                              &NtPathU,
+                              0,
+                              NULL,
+                              NULL);
+
+   if (lpSecurityAttributes)
+   {
+      if(lpSecurityAttributes->bInheritHandle)
+         ObjectAttributes.Attributes |= OBJ_INHERIT;
+
+      ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
+   }
+
+   if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
+    ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
+
+   /* perform the call */
+   Status = NtCreateFile (&FileHandle,
+                         dwDesiredAccess,
+                         &ObjectAttributes,
+                         &IoStatusBlock,
+                         NULL,
+                         FileAttributes,
+                         dwShareMode,
+                         dwCreationDisposition,
+                         Flags,
+                         EaBuffer,
+                         EaLength);
+
+   RtlFreeUnicodeString(&NtPathU);
+
+   /* free the extended attributes buffer if allocated */
+   if (EaBuffer != NULL)
+   {
+      RtlFreeHeap(RtlGetProcessHeap(),
+                  0,
+                  EaBuffer);
+   }
+
+   /* error */
    if (!NT_SUCCESS(Status))
    {
-       SetLastError(RtlNtStatusToDosError(Status));
-       return INVALID_HANDLE_VALUE;
+      /* In the case file creation was rejected due to CREATE_NEW flag
+       * was specified and file with that name already exists, correct
+       * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
+       * Note: RtlNtStatusToDosError is not the subject to blame here.
+       */
+      if (Status == STATUS_OBJECT_NAME_COLLISION &&
+          dwCreationDisposition == FILE_CREATE)
+      {
+         SetLastError( ERROR_FILE_EXISTS );
+      }
+      else
+      {
+         SetLastErrorByStatus (Status);
+      }
+
+      return INVALID_HANDLE_VALUE;
    }
-   return(FileHandle);                  
+
+  /*
+  create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
+  create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
+  */
+  if (dwCreationDisposition == FILE_OPEN_IF)
+  {
+    SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
+  }
+  else if (dwCreationDisposition == FILE_OVERWRITE_IF)
+  {
+    SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
+  }
+
+  return FileHandle;
+}
+
+
+/*
+ * @unimplemented
+ */
+BOOL STDCALL
+CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
+                    IN LPCWSTR lpTargetFileName,
+                    IN DWORD dwFlags)
+{
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,
+                    IN LPCSTR lpTargetFileName,
+                    IN DWORD dwFlags)
+{
+    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, TargetW);
+
+    return Ret;
 }
 
+
+/* EOF */