reactos/dll/win32/kernel32/file/create.c

614 lines
17 KiB
C
Raw Normal View History

/* $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 *****************************************************************/
2003-01-15 Casper S. Hornstrup <chorns@users.sourceforge.net> * lib/kernel32/k32.h: New file. * lib/kernel32/makefile (TARGET_CFLAGS): Add -I./. (TARGET_PCH): Set to k32.h. * lib/kernel32/except/except.c: Use <k32.h>. * lib/kernel32/file/backup.c: Ditto. * lib/kernel32/file/cnotify.c: Ditto. * lib/kernel32/file/copy.c: Ditto. * lib/kernel32/file/create.c: Ditto. * lib/kernel32/file/curdir.c: Ditto. * lib/kernel32/file/delete.c: Ditto. * lib/kernel32/file/deviceio.c: Ditto. * lib/kernel32/file/dir.c: Ditto. * lib/kernel32/file/dosdev.c: Ditto. * lib/kernel32/file/file.c: Ditto. * lib/kernel32/file/find.c: Ditto. * lib/kernel32/file/iocompl.c: Ditto. * lib/kernel32/file/lfile.c: Ditto. * lib/kernel32/file/lock.c: Ditto. * lib/kernel32/file/mailslot.c: Ditto. * lib/kernel32/file/move.c: Ditto. * lib/kernel32/file/npipe.c: Ditto. * lib/kernel32/file/pipe.c: Ditto. * lib/kernel32/file/rw.c: Ditto. * lib/kernel32/file/tape.c: Ditto. * lib/kernel32/file/volume.c: Ditto. * lib/kernel32/mem/global.c: Ditto. * lib/kernel32/mem/heap.c: Ditto. * lib/kernel32/mem/isbad.c: Ditto. * lib/kernel32/mem/local.c: Ditto. * lib/kernel32/mem/procmem.c: Ditto. * lib/kernel32/mem/section.c: Ditto. * lib/kernel32/mem/virtual.c: Ditto. * lib/kernel32/misc/atom.c: Ditto. * lib/kernel32/misc/comm.c: Ditto. * lib/kernel32/misc/console.c: Ditto. * lib/kernel32/misc/debug.c: Ditto. * lib/kernel32/misc/dllmain.c: Ditto. * lib/kernel32/misc/env.c: Ditto. * lib/kernel32/misc/error.c: Ditto. * lib/kernel32/misc/handle.c: Ditto. * lib/kernel32/misc/ldr.c: Ditto. * lib/kernel32/misc/profile.c: Ditto. * lib/kernel32/misc/res.c: Ditto. * lib/kernel32/misc/stubs.c: Ditto. * lib/kernel32/misc/sysinfo.c: Ditto. * lib/kernel32/misc/time.c: Ditto. * lib/kernel32/process/cmdline.c: Ditto. * lib/kernel32/process/create.c: Ditto. * lib/kernel32/process/proc.c: Ditto. * lib/kernel32/process/session.c: Ditto. * lib/kernel32/string/lstring.c: Ditto. * lib/kernel32/synch/critical.c: Ditto. * lib/kernel32/synch/event.c: Ditto. * lib/kernel32/synch/intrlck.c: Ditto. * lib/kernel32/synch/mutex.c: Ditto. * lib/kernel32/synch/sem.c: Ditto. * lib/kernel32/synch/timer.c: Ditto. * lib/kernel32/synch/wait.c: Ditto. * lib/kernel32/thread/fiber.c: Ditto. * lib/kernel32/thread/thread.c: Ditto. * lib/kernel32/thread/tls.c: Ditto. svn path=/trunk/; revision=4009
2003-01-15 21:24:36 +00:00
#include <k32.h>
[KERNEL32]: While working on the CMAKE branch, Amine and myself discovered a rather serious issue in kernel32 (and perhaps other libraries as well). Unlike rbuild, CMake does not allow you to export non-existant DLL functions (try it: add "poopyhead" in kernel32's exports under RBuild, and will it export "poopyhead", God knowing what that will actually link to). As an additional feature on top of the "allow non-existing functions to be exported" "feature", because rbuild generates and links STDCALL function names without the proper decoration (vs. enforcing decoration at linking, but only removing it at export-time), this allows the definition (as an export) of a STDCALL function that is completely different from the actual function itself. For example, the 5-parameter Foo function is normally Foo@20, while the 3-parameter Foo function woudl be Foo@12. Linking one against the other would fail (say, 2 parameters were added to Foo in a newer version). However, under RBUILD, both of these would appear as "Foo", and the linker/compiler would happilly connect the caller of Foo@3 (that has pushed 3 parameters) to the receiving side of Foo@5 (that is about to pop 5 parameters). Even -if- decorations WERE to be applied, Foo@12 would STILL succeed, because of the first feature, which would enable the export of Foo@12 even though no such function exist. In a further, bizare, twist of fate, the behavior of this RBUILD "feature", when the target function is not found, is to link the exported DLL TO ITSELF. Therefore, one can see how, previously to this patch, kernel32.dll would import a dozen functions from itself (all the non-existing functions). To really seal the deal, the behavior of exported functions used by kernel32, but that are actually forwarded to another DLL deserves a special mention. GetLastError, for example, merely forwards to RtlGetLastWin32Error, so it is normal behavior to use a #define in the C code so that all internal calls to the function are routed correctly. This did not happen, so instead, kernel32 tried importing/linking/exporting GetLastError, but this symbol is not found in the binary, because it is only a forwarder. This caused kernel32 to import from itself (the behavior when an exported symbol is not found). When importing from itself, the loader would now find the _forwarded_ for GetLastError, and correctly link with ntdll. What should be a one-liner of assembly (inline TEB access) thus became a triple-call indirection (GetLastError@0->StubLastError@0->__impGetLastError@0->__impRtlGetLastWin32Error->RtlGetLastWin32Error. While analyzing these issues, we also realized a strange macro SetLastErrorByStatus that manually tried to perform what there already exists a function for: RtlSetLastNtStatusFromWin32Error. And, in an exciting coda, we also realized that our Server 2003 Kernel32 exports more than a dozen Windows 95 APIs, through an auto-stub generation mechanism within winebuild, that gets linked as an object behind the scenes. [KERNEL32]: Removed all Win95 exports, cleaned up exports. [KERNEL32]: Fixed up set/get error macros by making them inline and/or calling the correct ntdll function. [KERNEL32]: Removed bizare calls to Wine-internal/specific APIs from our core Win32 DLL. [KERNEL32]: Wrote stubs for all functions which should be exported, and set the correct number of parameters for them. [KERNEL32]: Kernel32 is smaller, loads faster, does not export Windows 95 functions, does not export non-existing functions, and does not import from itself anymore. Note: This is one of the many failings of RBUILD the CMAKE system has helped us discover. I believe these issues are serious enough to warrant an immediate sync with trunk, but rest assured, there are many more completely broken, infinitely-regressing things that we discovered while switching to CMAKE. svn path=/trunk/; revision=48475
2010-08-07 05:02:58 +00:00
#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 ****************************************************************/
2003-07-10 Casper S. Hornstrup <chorns@users.sourceforge.net> * lib/kernel32/debug/break.c: Add @implemented and @unimplemented to APIs. * lib/kernel32/debug/debugger.c: Ditto. * lib/kernel32/debug/output.c: Ditto. * lib/kernel32/except/except.c: Ditto. * lib/kernel32/file/backup.c: Ditto. * lib/kernel32/file/cnotify.c: Ditto. * lib/kernel32/file/copy.c: Ditto. * lib/kernel32/file/create.c: Ditto. * lib/kernel32/file/curdir.c: Ditto. * lib/kernel32/file/delete.c: Ditto. * lib/kernel32/file/deviceio.c: Ditto. * lib/kernel32/file/dir.c: Ditto. * lib/kernel32/file/dosdev.c: Ditto. * lib/kernel32/file/file.c: Ditto. * lib/kernel32/file/find.c: Ditto. * lib/kernel32/file/iocompl.c: Ditto. * lib/kernel32/file/lfile.c: Ditto. * lib/kernel32/file/lock.c: Ditto. * lib/kernel32/file/mailslot.c: Ditto. * lib/kernel32/file/move.c: Ditto. * lib/kernel32/file/npipe.c: Ditto. * lib/kernel32/file/pipe.c: Ditto. * lib/kernel32/file/rw.c: Ditto. * lib/kernel32/file/tape.c: Ditto. * lib/kernel32/file/volume.c: Ditto. * lib/kernel32/mem/global.c: Ditto. * lib/kernel32/mem/heap.c: Ditto. * lib/kernel32/mem/isbad.c: Ditto. * lib/kernel32/mem/local.c: Ditto. * lib/kernel32/mem/procmem.c: Ditto. * lib/kernel32/mem/section.c: Ditto. * lib/kernel32/mem/virtual.c: Ditto. * lib/kernel32/misc/atom.c: Ditto. * lib/kernel32/misc/comm.c: Ditto. * lib/kernel32/misc/computername.c: Ditto. * lib/kernel32/misc/console.c: Ditto. * lib/kernel32/misc/env.c: Ditto. * lib/kernel32/misc/error.c: Ditto. * lib/kernel32/misc/errormsg.c: Ditto. * lib/kernel32/misc/handle.c: Ditto. * lib/kernel32/misc/ldr.c: Ditto. * lib/kernel32/misc/mbchars.c: Ditto. * lib/kernel32/misc/muldiv.c: Ditto. * lib/kernel32/misc/perfcnt.c: Ditto. * lib/kernel32/misc/profile.c: Ditto. * lib/kernel32/misc/res.c: Ditto. * lib/kernel32/misc/stubs.c: Ditto. * lib/kernel32/misc/sysinfo.c: Ditto. * lib/kernel32/misc/time.c: Ditto. * lib/kernel32/misc/toolhelp.c: Ditto. * lib/kernel32/process/cmdline.c: Ditto. * lib/kernel32/process/create.c: Ditto. * lib/kernel32/process/proc.c: Ditto. * lib/kernel32/process/session.c: Ditto. * lib/kernel32/string/lstring.c: Ditto. * lib/kernel32/synch/critical.c: Ditto. * lib/kernel32/synch/event.c: Ditto. * lib/kernel32/synch/intrlck.c: Ditto. * lib/kernel32/synch/mutex.c: Ditto. * lib/kernel32/synch/sem.c: Ditto. * lib/kernel32/synch/timer.c: Ditto. * lib/kernel32/synch/wait.c: Ditto. * lib/kernel32/thread/fiber.c: Ditto. * lib/kernel32/thread/fls.c: Ditto. * lib/kernel32/thread/thread.c: Ditto. * lib/kernel32/thread/tls.c: Ditto. svn path=/trunk/; revision=5045
2003-07-10 18:50:51 +00:00
/*
* @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;
}
2003-07-10 Casper S. Hornstrup <chorns@users.sourceforge.net> * lib/kernel32/debug/break.c: Add @implemented and @unimplemented to APIs. * lib/kernel32/debug/debugger.c: Ditto. * lib/kernel32/debug/output.c: Ditto. * lib/kernel32/except/except.c: Ditto. * lib/kernel32/file/backup.c: Ditto. * lib/kernel32/file/cnotify.c: Ditto. * lib/kernel32/file/copy.c: Ditto. * lib/kernel32/file/create.c: Ditto. * lib/kernel32/file/curdir.c: Ditto. * lib/kernel32/file/delete.c: Ditto. * lib/kernel32/file/deviceio.c: Ditto. * lib/kernel32/file/dir.c: Ditto. * lib/kernel32/file/dosdev.c: Ditto. * lib/kernel32/file/file.c: Ditto. * lib/kernel32/file/find.c: Ditto. * lib/kernel32/file/iocompl.c: Ditto. * lib/kernel32/file/lfile.c: Ditto. * lib/kernel32/file/lock.c: Ditto. * lib/kernel32/file/mailslot.c: Ditto. * lib/kernel32/file/move.c: Ditto. * lib/kernel32/file/npipe.c: Ditto. * lib/kernel32/file/pipe.c: Ditto. * lib/kernel32/file/rw.c: Ditto. * lib/kernel32/file/tape.c: Ditto. * lib/kernel32/file/volume.c: Ditto. * lib/kernel32/mem/global.c: Ditto. * lib/kernel32/mem/heap.c: Ditto. * lib/kernel32/mem/isbad.c: Ditto. * lib/kernel32/mem/local.c: Ditto. * lib/kernel32/mem/procmem.c: Ditto. * lib/kernel32/mem/section.c: Ditto. * lib/kernel32/mem/virtual.c: Ditto. * lib/kernel32/misc/atom.c: Ditto. * lib/kernel32/misc/comm.c: Ditto. * lib/kernel32/misc/computername.c: Ditto. * lib/kernel32/misc/console.c: Ditto. * lib/kernel32/misc/env.c: Ditto. * lib/kernel32/misc/error.c: Ditto. * lib/kernel32/misc/errormsg.c: Ditto. * lib/kernel32/misc/handle.c: Ditto. * lib/kernel32/misc/ldr.c: Ditto. * lib/kernel32/misc/mbchars.c: Ditto. * lib/kernel32/misc/muldiv.c: Ditto. * lib/kernel32/misc/perfcnt.c: Ditto. * lib/kernel32/misc/profile.c: Ditto. * lib/kernel32/misc/res.c: Ditto. * lib/kernel32/misc/stubs.c: Ditto. * lib/kernel32/misc/sysinfo.c: Ditto. * lib/kernel32/misc/time.c: Ditto. * lib/kernel32/misc/toolhelp.c: Ditto. * lib/kernel32/process/cmdline.c: Ditto. * lib/kernel32/process/create.c: Ditto. * lib/kernel32/process/proc.c: Ditto. * lib/kernel32/process/session.c: Ditto. * lib/kernel32/string/lstring.c: Ditto. * lib/kernel32/synch/critical.c: Ditto. * lib/kernel32/synch/event.c: Ditto. * lib/kernel32/synch/intrlck.c: Ditto. * lib/kernel32/synch/mutex.c: Ditto. * lib/kernel32/synch/sem.c: Ditto. * lib/kernel32/synch/timer.c: Ditto. * lib/kernel32/synch/wait.c: Ditto. * lib/kernel32/thread/fiber.c: Ditto. * lib/kernel32/thread/fls.c: Ditto. * lib/kernel32/thread/thread.c: Ditto. * lib/kernel32/thread/tls.c: Ditto. svn path=/trunk/; revision=5045
2003-07-10 18:50:51 +00:00
/*
* @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);
}
2003-11-27 20:57:58 +00:00
/* 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_PATH_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
{
SetLastErrorByStatus (Status);
}
return INVALID_HANDLE_VALUE;
}
2003-11-27 20:57:58 +00:00
/*
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)
2003-11-27 20:57:58 +00:00
{
SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
}
else if (dwCreationDisposition == FILE_OVERWRITE_IF)
{
SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
2003-11-27 20:57:58 +00:00
}
return FileHandle;
}
/*
* @implemented
*/
BOOLEAN
WINAPI
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 | SYMBOLIC_LINK_FLAG_DIRECTORY) != SYMBOLIC_LINK_FLAG_DIRECTORY)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if(dwFlags & SYMBOLIC_LINK_FLAG_DIRECTORY)
dwCreateOptions = FILE_DIRECTORY_FILE;
else
dwCreateOptions = FILE_NON_DIRECTORY_FILE;
switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
{
case RtlPathTypeUnknown:
case RtlPathTypeRooted:
case RtlPathTypeRelative:
bRelativePath = TRUE;
RtlInitUnicodeString(&TargetFileName, lpTargetFileName);
break;
case RtlPathTypeDriveRelative:
{
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 RtlPathTypeUncAbsolute:
case RtlPathTypeDriveAbsolute:
case RtlPathTypeLocalDevice:
case RtlPathTypeRootLocalDevice:
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 = (ULONG)IO_REPARSE_TAG_SYMLINK;
pReparseData->ReparseDataLength = (USHORT)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 = (USHORT)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
*/
BOOLEAN
NTAPI
CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,
IN LPCSTR lpTargetFileName,
IN DWORD dwFlags)
{
PWCHAR SymlinkW, TargetW;
BOOLEAN 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 */