+++ /dev/null
-/* $Id$
- *
- * 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 "../include/debug.h"
-
-
-/* FUNCTIONS ****************************************************************/
-
-/*
- * @implemented
- */
-HANDLE STDCALL CreateFileA (LPCSTR lpFileName,
- DWORD dwDesiredAccess,
- DWORD dwShareMode,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD dwCreationDisposition,
- DWORD dwFlagsAndAttributes,
- HANDLE hTemplateFile)
-{
- PWCHAR FileNameW;
- HANDLE FileHandle;
-
- DPRINT("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 STDCALL 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;
- 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 = FILE_OPEN_IF;
- break;
-
- case TRUNCATE_EXISTING:
- dwCreationDisposition = FILE_OVERWRITE;
- break;
-
- default:
- SetLastError(ERROR_INVALID_PARAMETER);
- return (INVALID_HANDLE_VALUE);
- }
-
- /* 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;
- }
- }
-
- /* validate & translate the filename */
- if (!RtlDosPathNameToNtPathName_U (lpFileName,
- &NtPathU,
- NULL,
- NULL))
- {
- DPRINT("Invalid path\n");
- SetLastError(ERROR_PATH_NOT_FOUND);
- return INVALID_HANDLE_VALUE;
- }
-
- DPRINT("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
- {
- 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)
- {
- 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;
-}
-
-
-/*
- * @implemented
- */
-BOOL STDCALL
-CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
- IN LPCWSTR lpTargetFileName,
- IN DWORD dwFlags)
-{
- IO_STATUS_BLOCK IoStatusBlock;
- OBJECT_ATTRIBUTES ObjectAttributes;
- HANDLE hSymlink = NULL;
- UNICODE_STRING SymlinkFileName = { 0, 0, NULL };
- UNICODE_STRING TargetFileName = { 0, 0, NULL };
- BOOLEAN bAllocatedTarget = FALSE, bRelativePath = FALSE;
- LPWSTR lpTargetFullFileName = NULL;
- SIZE_T cbPrintName;
- SIZE_T cbReparseData;
- PREPARSE_DATA_BUFFER pReparseData = NULL;
- PBYTE pBufTail;
- NTSTATUS Status;
- ULONG dwCreateOptions;
- DWORD dwErr;
-
- if(!lpSymlinkFileName || !lpTargetFileName || (dwFlags | SYMLINK_FLAG_DIRECTORY) != SYMLINK_FLAG_DIRECTORY)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if(dwFlags & SYMLINK_FLAG_DIRECTORY)
- dwCreateOptions = FILE_DIRECTORY_FILE;
- else
- dwCreateOptions = FILE_NON_DIRECTORY_FILE;
-
- switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
- {
- 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(lpTargetFileName, &TargetFileName, NULL, NULL))
- {
- bAllocatedTarget = TRUE;
- dwErr = ERROR_INVALID_PARAMETER;
- goto Cleanup;
- }
- }
-
- cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
- cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length + cbPrintName;
- pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData);
-
- if(pReparseData == NULL)
- {
- dwErr = ERROR_NOT_ENOUGH_MEMORY;
- goto Cleanup;
- }
-
- 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(lpSymlinkFileName, &SymlinkFileName, NULL, NULL))
- {
- dwErr = ERROR_PATH_NOT_FOUND;
- goto Cleanup;
- }
-
- 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))
- {
- dwErr = RtlNtStatusToDosError(Status);
- goto Cleanup;
- }
-
- Status = NtFsControlFile
- (
- hSymlink,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- FSCTL_SET_REPARSE_POINT,
- pReparseData,
- cbReparseData,
- NULL,
- 0
- );
-
- if(!NT_SUCCESS(Status))
- {
- FILE_DISPOSITION_INFORMATION DispInfo;
- DispInfo.DeleteFile = TRUE;
- NtSetInformationFile(hSymlink, &IoStatusBlock, &DispInfo, sizeof(DispInfo), FileDispositionInformation);
-
- dwErr = RtlNtStatusToDosError(Status);
- goto Cleanup;
- }
-
- dwErr = NO_ERROR;
-
-Cleanup:
- if(hSymlink)
- NtClose(hSymlink);
-
- RtlFreeUnicodeString(&SymlinkFileName);
- if (bAllocatedTarget)
- {
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- TargetFileName.Buffer);
- }
-
- if(lpTargetFullFileName)
- RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName);
-
- if(pReparseData)
- RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData);
-
- if(dwErr)
- {
- SetLastError(dwErr);
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @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, SymlinkW);
- RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
-
- return Ret;
-}
-
-
-/* EOF */