/* $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 #define NDEBUG #include #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; 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 */ if (0 == _wcsicmp(L"CONOUT$", lpFileName) || 0 == _wcsicmp(L"CONIN$", lpFileName)) { return OpenConsoleW(lpFileName, 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; 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 allways be waited on and querying attributes are allways 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 %x, 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 = 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 = GetLastError(); return (HFILE)INVALID_HANDLE_VALUE; } if (uStyle & OF_DELETE) { if (!DeleteFileW(PathNameW)) { lpReOpenBuff->nErrCode = 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 = 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 */