-/*
+/* $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)
- */
-
-/*
- * NOTES: Please don't alter without debugging
- *
+ * 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 <wstring.h>
-#include <string.h>
-#include <ddk/li.h>
-#include <ddk/rtl.h>
+#include <k32.h>
#define NDEBUG
-#include <kernel32/kernel32.h>
+#include "../include/debug.h"
+
/* 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;
-
- DPRINT("CreateFileW(lpFileName %w)\n",lpFileName);
-
- if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
- {
- Flags |= FILE_SYNCHRONOUS_IO_ALERT;
- }
-
- if ( lpFileName[0] == L'\\' || lpFileName[1] == L':')
- {
- wcscpy(PathNameW,lpFileName);
- }
- else
+ 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)
{
- 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);
+ 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;
+
+ case TRUNCATE_EXISTING:
+ dwCreationDisposition = FILE_OVERWRITE;
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (INVALID_HANDLE_VALUE);
}
-
- 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);
-
- DPRINT("After create file\n");
+
+ /* 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))
+ {
+ /* 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
+ 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 NULL;
+ /* 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;
}
-#if 0
-HANDLE STDCALL CreateFileW(LPCWSTR lpFileName,
- DWORD dwDesiredAccess,
- DWORD dwShareMode,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD dwCreationDisposition,
- DWORD dwFlagsAndAttributes,
- HANDLE hTemplateFile)
+
+/*
+ * @unimplemented
+ */
+BOOL STDCALL
+CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
+ IN LPCWSTR lpTargetFileName,
+ IN DWORD dwFlags)
{
- HANDLE FileHandle;
- NTSTATUS Status;
-
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING FileNameString;
- ULONG Flags = 0;
- WCHAR PathNameW[MAX_PATH];
- WCHAR *FilePart;
- UINT Len = 0;
- WCHAR CurrentDir[MAX_PATH];
-
- OutputDebugStringA("CreateFileW\n");
-
- if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
- {
- Flags |= FILE_SYNCHRONOUS_IO_ALERT;
- }
-
-// lstrcpyW(PathNameW,L"\\??\\");
- PathNameW[0] = '\\';
- PathNameW[1] = '?';
- PathNameW[2] = '?';
- PathNameW[3] = '\\';
- PathNameW[4] = 0;
-
- dprintf("Name %w\n",PathNameW);
- if (lpFileName[0] != L'\\' && lpFileName[1] != L':')
- {
- Len = GetCurrentDirectoryW(MAX_PATH,CurrentDir);
- dprintf("CurrentDir %w\n",CurrentDir);
- lstrcatW(PathNameW,CurrentDir);
- dprintf("Name %w\n",PathNameW);
- }
- lstrcatW(PathNameW,lpFileName);
- dprintf("Name %w\n",PathNameW);
-
- FileNameString.Length = lstrlenW( PathNameW)*sizeof(WCHAR);
-
- if ( FileNameString.Length == 0 )
- return NULL;
-
- if ( FileNameString.Length > MAX_PATH )
- return NULL;
-
- FileNameString.Buffer = (WCHAR *)PathNameW;
- 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;
-
- Status = NtCreateFile(&FileHandle,
- dwDesiredAccess,
- &ObjectAttributes,
- &IoStatusBlock,
- NULL,
- dwFlagsAndAttributes,
- dwShareMode,
- dwCreationDisposition,
- Flags,
- NULL,
- 0);
- return(FileHandle);
+ 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;
}
-#endif
+
+/* EOF */