add stubs for CreateSymbolicLinkA/W
[reactos.git] / reactos / lib / kernel32 / file / create.c
index de9fb05..168cb52 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: create.c,v 1.37 2004/07/18 17:08:29 navaraf Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
@@ -34,37 +34,22 @@ HANDLE STDCALL CreateFileA (LPCSTR                  lpFileName,
                            DWORD                       dwFlagsAndAttributes,
                            HANDLE                      hTemplateFile)
 {
-   UNICODE_STRING FileNameU;
-   ANSI_STRING FileName;
+   PWCHAR FileNameW;
    HANDLE FileHandle;
-   
+
    DPRINT("CreateFileA(lpFileName %s)\n",lpFileName);
-   
-   RtlInitAnsiString (&FileName,
-                     (LPSTR)lpFileName);
-   
-   /* convert ansi (or oem) string to unicode */
-   if (bIsFileApiAnsi)
-     RtlAnsiStringToUnicodeString (&FileNameU,
-                                  &FileName,
-                                  TRUE);
-   else
-     RtlOemStringToUnicodeString (&FileNameU,
-                                 &FileName,
-                                 TRUE);
 
-   FileHandle = CreateFileW (FileNameU.Buffer,
+   if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
+      return INVALID_HANDLE_VALUE;
+
+   FileHandle = CreateFileW (FileNameW,
                             dwDesiredAccess,
                             dwShareMode,
                             lpSecurityAttributes,
                             dwCreationDisposition,
                             dwFlagsAndAttributes,
                             hTemplateFile);
-   
-   RtlFreeHeap (RtlGetProcessHeap (),
-               0,
-               FileNameU.Buffer);
-   
+
    return FileHandle;
 }
 
@@ -85,36 +70,28 @@ HANDLE STDCALL CreateFileW (LPCWSTR                 lpFileName,
    UNICODE_STRING NtPathU;
    HANDLE FileHandle;
    NTSTATUS Status;
-   ULONG Flags = 0;
-   ULONG DesiredAccess = 0;
-   CSRSS_API_REQUEST Request;
-   CSRSS_API_REPLY Reply;
+   ULONG FileAttributes, Flags = 0;
+   CSR_API_MESSAGE Request;
+   PVOID EaBuffer = NULL;
+   ULONG EaLength = 0;
 
    DPRINT("CreateFileW(lpFileName %S)\n",lpFileName);
 
-   if(hTemplateFile != NULL)
-   {
-    /* FIXME */
-    DPRINT("Template file feature not supported yet\n");
-    SetLastError(ERROR_NOT_SUPPORTED);
-    return INVALID_HANDLE_VALUE;
-   }
-
    /* 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 = FILE_OPEN_IF;
        break;
@@ -122,7 +99,7 @@ HANDLE STDCALL CreateFileW (LPCWSTR                  lpFileName,
       case TRUNCATE_EXISTING:
        dwCreationDisposition = FILE_OVERWRITE;
         break;
-      
+
       default:
         SetLastError(ERROR_INVALID_PARAMETER);
         return (INVALID_HANDLE_VALUE);
@@ -135,96 +112,82 @@ HANDLE STDCALL CreateFileW (LPCWSTR                       lpFileName,
                                      NULL))
    {
      DPRINT("Invalid path\n");
-     SetLastError(ERROR_BAD_PATHNAME);
+     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)){
-    /* 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_OVERLAPPED))
+   {
+      /* 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;
+      Flags |= FILE_WRITE_THROUGH;
 
    if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
-    Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
+      Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
 
    if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
-    Flags |= FILE_RANDOM_ACCESS;
-   
+      Flags |= FILE_RANDOM_ACCESS;
+
    if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
-    Flags |= FILE_SEQUENTIAL_ONLY;
-   
+      Flags |= FILE_SEQUENTIAL_ONLY;
+
    if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
-    Flags |= FILE_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
-   {
-    Flags |= FILE_NON_DIRECTORY_FILE;
+      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;
+      }
    }
-    
-   if(dwDesiredAccess & GENERIC_ALL)
-     DesiredAccess |= FILE_READ_DATA | FILE_WRITE_DATA;
    else
-   {
-     if(dwDesiredAccess & GENERIC_READ)
-       DesiredAccess |= FILE_READ_DATA;
-     
-     if(dwDesiredAccess & GENERIC_WRITE)
-       DesiredAccess |= FILE_WRITE_DATA;
-   }    
-    
-   /* handle may allways be waited on and querying attributes are allways allowed */
-   DesiredAccess |= SYNCHRONIZE|FILE_READ_ATTRIBUTES; 
-
-   /* FILE_FLAG_POSIX_SEMANTICS is handled later */
+      Flags |= FILE_NON_DIRECTORY_FILE;
 
-#if 0
-   /* FIXME: Win32 constants to be defined */
    if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
-    Flags |= FILE_OPEN_REPARSE_POINT;
-   
+      Flags |= FILE_OPEN_REPARSE_POINT;
+
    if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
-    Flags |= FILE_OPEN_NO_RECALL;
-#endif
+      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 */
-      Request.Type = CSRSS_GET_OUTPUT_HANDLE;
       Status = CsrClientCallServer(&Request,
-                                  &Reply,
-                                  sizeof(CSRSS_API_REQUEST),
-                                  sizeof(CSRSS_API_REPLY));
-      if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
+                                  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 Reply.Data.GetOutputHandleReply.OutputHandle;
+         return Request.Data.GetOutputHandleRequest.OutputHandle;
       }
    }
 
@@ -232,30 +195,96 @@ HANDLE STDCALL CreateFileW (LPCWSTR                       lpFileName,
    if (0 == _wcsicmp(L"CONIN$", lpFileName))
    {
       /* FIXME: Send required access rights to Csrss */
-      Request.Type = CSRSS_GET_INPUT_HANDLE;
       Status = CsrClientCallServer(&Request,
-                                  &Reply,
-                                  sizeof(CSRSS_API_REQUEST),
-                                  sizeof(CSRSS_API_REPLY));
-      if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
+                                  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 Reply.Data.GetInputHandleReply.InputHandle;
+         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
-   );
+   InitializeObjectAttributes(&ObjectAttributes,
+                              &NtPathU,
+                              0,
+                              NULL,
+                              NULL);
 
    if (lpSecurityAttributes)
    {
@@ -264,43 +293,115 @@ HANDLE STDCALL CreateFileW (LPCWSTR                      lpFileName,
 
       ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
    }
-   
+
    if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
     ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
 
    /* perform the call */
    Status = NtCreateFile (&FileHandle,
-                         DesiredAccess,
+                         dwDesiredAccess,
                          &ObjectAttributes,
                          &IoStatusBlock,
                          NULL,
-                         dwFlagsAndAttributes,
+                         FileAttributes,
                          dwShareMode,
                          dwCreationDisposition,
                          Flags,
-                         NULL,
-                         0);
+                         EaBuffer,
+                         EaLength);
 
    RtlFreeUnicodeString(&NtPathU);
 
+   /* free the extended attributes buffer if allocated */
+   if (EaBuffer != NULL)
+   {
+      RtlFreeHeap(RtlGetProcessHeap(),
+                  0,
+                  EaBuffer);
+   }
+
    /* error */
-  if (!NT_SUCCESS(Status))
-  {
-    SetLastErrorByStatus (Status);
-    return INVALID_HANDLE_VALUE;
-  }
-   
+   if (!NT_SUCCESS(Status))
+   {
+      /* 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;
+   }
+
   /*
   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 && IoStatusBlock.Information == FILE_OPENED) ||
-      (dwCreationDisposition == FILE_OVERWRITE_IF && IoStatusBlock.Information == FILE_OVERWRITTEN))
+  */
+  if (dwCreationDisposition == FILE_OPEN_IF)
   {
-    SetLastError(ERROR_ALREADY_EXISTS);
+    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 */