--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: lib/kernel32/file/create.c
+ * PURPOSE: Directory functions
+ * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
+ * 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 <k32.h>
+#define NDEBUG
+#include <debug.h>
+
+#if DBG
+DEBUG_CHANNEL(kernel32file);
+#endif
+
+#define SYMLINK_FLAG_RELATIVE 1
+
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
+
+/* FUNCTIONS ****************************************************************/
+
+/*
+ * @implemented
+ */
+HANDLE WINAPI CreateFileA (LPCSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile)
+{
+ PWCHAR FileNameW;
+ HANDLE FileHandle;
+
+ TRACE("CreateFileA(lpFileName %s)\n",lpFileName);
+
+ if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
+ return INVALID_HANDLE_VALUE;
+
+ FileHandle = CreateFileW (FileNameW,
+ dwDesiredAccess,
+ dwShareMode,
+ lpSecurityAttributes,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ hTemplateFile);
+
+ return FileHandle;
+}
+
+
+/*
+ * @implemented
+ */
+HANDLE WINAPI CreateFileW (LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING NtPathU;
+ LPCWSTR pszConsoleFileName;
+ HANDLE FileHandle;
+ NTSTATUS Status;
+ ULONG FileAttributes, Flags = 0;
+ PVOID EaBuffer = NULL;
+ ULONG EaLength = 0;
+
+ if (!lpFileName || !lpFileName[0])
+ {
+ SetLastError( ERROR_PATH_NOT_FOUND );
+ return INVALID_HANDLE_VALUE;
+ }
+
+ TRACE("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 = FILE_OPEN_IF;
+ break;
+
+ case TRUNCATE_EXISTING:
+ dwCreationDisposition = FILE_OVERWRITE;
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (INVALID_HANDLE_VALUE);
+ }
+
+ /* check for console input/output */
+ pszConsoleFileName = IntCheckForConsoleFileName(lpFileName, dwDesiredAccess);
+ if (pszConsoleFileName)
+ {
+ return OpenConsoleW(pszConsoleFileName,
+ dwDesiredAccess,
+ lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE);
+ }
+
+ /* 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;
+ dwDesiredAccess |= DELETE;
+ }
+
+ if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
+ {
+ if(dwDesiredAccess & GENERIC_ALL)
+ Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REMOTE_INSTANCE;
+ else
+ {
+ if(dwDesiredAccess & GENERIC_READ)
+ Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
+
+ if(dwDesiredAccess & GENERIC_WRITE)
+ Flags |= FILE_OPEN_REMOTE_INSTANCE;
+ }
+ }
+ 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 always be waited on and querying attributes are always allowed */
+ dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
+
+ /* FILE_FLAG_POSIX_SEMANTICS is handled later */
+
+ /* validate & translate the filename */
+ if (!RtlDosPathNameToNtPathName_U (lpFileName,
+ &NtPathU,
+ NULL,
+ NULL))
+ {
+ WARN("Invalid path\n");
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ TRACE("NtPathU \'%wZ\'\n", &NtPathU);
+
+ 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)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(),
+ 0,
+ NtPathU.Buffer);
+
+ /* 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);
+
+ RtlFreeHeap(RtlGetProcessHeap(),
+ 0,
+ NtPathU.Buffer);
+
+ /* free the extended attributes buffer if allocated */
+ if (EaBuffer != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(),
+ 0,
+ EaBuffer);
+ }
+
+ /* error */
+ 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
+ {
+ BaseSetLastNTError (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)
+ {
+ SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
+ }
+ else if (dwCreationDisposition == FILE_OVERWRITE_IF)
+ {
+ SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
+ }
+ else
+ {
+ SetLastError(ERROR_SUCCESS);
+ }
+
+ return FileHandle;
+}
+
+/*
+ * @implemented
+ */
+HFILE WINAPI
+OpenFile(LPCSTR lpFileName,
+ LPOFSTRUCT lpReOpenBuff,
+ UINT uStyle)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING FileNameString;
+ UNICODE_STRING FileNameU;
+ ANSI_STRING FileName;
+ WCHAR PathNameW[MAX_PATH];
+ HANDLE FileHandle = NULL;
+ NTSTATUS errCode;
+ PWCHAR FilePart;
+ ULONG Len;
+
+ TRACE("OpenFile('%s', lpReOpenBuff %p, uStyle %x)\n", lpFileName, lpReOpenBuff, uStyle);
+
+ if (lpReOpenBuff == NULL)
+ {
+ return HFILE_ERROR;
+ }
+
+ lpReOpenBuff->nErrCode = 0;
+
+ if (uStyle & OF_REOPEN) lpFileName = lpReOpenBuff->szPathName;
+
+ if (!lpFileName)
+ {
+ return HFILE_ERROR;
+ }
+
+ if (!GetFullPathNameA(lpFileName,
+ sizeof(lpReOpenBuff->szPathName),
+ lpReOpenBuff->szPathName,
+ NULL))
+ {
+ lpReOpenBuff->nErrCode = (WORD)GetLastError();
+ return HFILE_ERROR;
+ }
+
+ if (uStyle & OF_PARSE)
+ {
+ lpReOpenBuff->fFixedDisk = (GetDriveTypeA(lpReOpenBuff->szPathName) != DRIVE_REMOVABLE);
+ TRACE("(%s): OF_PARSE, res = '%s'\n", lpFileName, lpReOpenBuff->szPathName);
+ return 0;
+ }
+
+ if ((uStyle & OF_EXIST) && !(uStyle & OF_CREATE))
+ {
+ DWORD dwAttributes = GetFileAttributesA(lpReOpenBuff->szPathName);
+
+ switch (dwAttributes)
+ {
+ case 0xFFFFFFFF: /* File does not exist */
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ lpReOpenBuff->nErrCode = (WORD) ERROR_FILE_NOT_FOUND;
+ return -1;
+
+ case FILE_ATTRIBUTE_DIRECTORY:
+ SetLastError(ERROR_ACCESS_DENIED);
+ lpReOpenBuff->nErrCode = (WORD) ERROR_ACCESS_DENIED;
+ return -1;
+
+ default:
+ lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
+ return 1;
+ }
+ }
+ lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
+ if ((uStyle & OF_CREATE) == OF_CREATE)
+ {
+ DWORD Sharing;
+ switch (uStyle & 0x70)
+ {
+ case OF_SHARE_EXCLUSIVE: Sharing = 0; break;
+ case OF_SHARE_DENY_WRITE: Sharing = FILE_SHARE_READ; break;
+ case OF_SHARE_DENY_READ: Sharing = FILE_SHARE_WRITE; break;
+ case OF_SHARE_DENY_NONE:
+ case OF_SHARE_COMPAT:
+ default:
+ Sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ }
+ return (HFILE) CreateFileA (lpFileName,
+ GENERIC_READ | GENERIC_WRITE,
+ Sharing,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0);
+ }
+
+ RtlInitAnsiString (&FileName, (LPSTR)lpFileName);
+
+ /* convert ansi (or oem) string to unicode */
+ if (bIsFileApiAnsi)
+ RtlAnsiStringToUnicodeString (&FileNameU, &FileName, TRUE);
+ else
+ RtlOemStringToUnicodeString (&FileNameU, &FileName, TRUE);
+
+ Len = SearchPathW (NULL,
+ FileNameU.Buffer,
+ NULL,
+ OFS_MAXPATHNAME,
+ PathNameW,
+ &FilePart);
+
+ RtlFreeUnicodeString(&FileNameU);
+
+ if (Len == 0 || Len > OFS_MAXPATHNAME)
+ {
+ lpReOpenBuff->nErrCode = (WORD)GetLastError();
+ return (HFILE)INVALID_HANDLE_VALUE;
+ }
+
+ if (uStyle & OF_DELETE)
+ {
+ if (!DeleteFileW(PathNameW))
+ {
+ lpReOpenBuff->nErrCode = (WORD)GetLastError();
+ return HFILE_ERROR;
+ }
+ TRACE("(%s): OF_DELETE return = OK\n", lpFileName);
+ return TRUE;
+ }
+
+ FileName.Buffer = lpReOpenBuff->szPathName;
+ FileName.Length = 0;
+ FileName.MaximumLength = OFS_MAXPATHNAME;
+
+ RtlInitUnicodeString(&FileNameU, PathNameW);
+
+ /* convert unicode string to ansi (or oem) */
+ if (bIsFileApiAnsi)
+ RtlUnicodeStringToAnsiString (&FileName, &FileNameU, FALSE);
+ else
+ RtlUnicodeStringToOemString (&FileName, &FileNameU, FALSE);
+
+ if (!RtlDosPathNameToNtPathName_U (PathNameW,
+ &FileNameString,
+ NULL,
+ NULL))
+ {
+ return (HFILE)INVALID_HANDLE_VALUE;
+ }
+
+ // FILE_SHARE_READ
+ // FILE_NO_INTERMEDIATE_BUFFERING
+
+ ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
+ ObjectAttributes.RootDirectory = NULL;
+ ObjectAttributes.ObjectName = &FileNameString;
+ ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT;
+ ObjectAttributes.SecurityDescriptor = NULL;
+ ObjectAttributes.SecurityQualityOfService = NULL;
+
+ errCode = NtOpenFile (&FileHandle,
+ GENERIC_READ | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameString.Buffer);
+
+ lpReOpenBuff->nErrCode = (WORD)RtlNtStatusToDosError(errCode);
+
+ if (!NT_SUCCESS(errCode))
+ {
+ BaseSetLastNTError (errCode);
+ return (HFILE)INVALID_HANDLE_VALUE;
+ }
+
+ if (uStyle & OF_EXIST)
+ {
+ NtClose(FileHandle);
+ return (HFILE)1;
+ }
+
+ return (HFILE)FileHandle;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+OpenDataFile(HANDLE hFile, DWORD dwUnused)
+{
+ STUB;
+ return FALSE;
+}
+
+/*
+ * @unimplemented
+ */
+HANDLE
+WINAPI
+ReOpenFile(IN HANDLE hOriginalFile,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwShareMode,
+ IN DWORD dwFlags)
+{
+ STUB;
+ return INVALID_HANDLE_VALUE;
+}
+
+/* EOF */