reactos/dll/win32/kernel32/client/file/dir.c

967 lines
33 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: dll/win32/kernel32/client/file/dir.c
* PURPOSE: Directory functions
* PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
*/
/* 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>
/* Short File Name length in chars (8.3) */
#define SFN_LENGTH 12
/* Match a volume name like:
* \\?\Volume{GUID}
*/
#define IS_VOLUME_NAME(s, l) \
((l == 96 || (l == 98 && s[48] == '\\')) && \
s[0] == '\\'&& (s[1] == '?' || s[1] == '\\') && \
s[2] == '?' && s[3] == '\\' && s[4] == 'V' && \
s[5] == 'o' && s[6] == 'l' && s[7] == 'u' && \
s[8] == 'm' && s[9] == 'e' && s[10] == '{' && \
s[19] == '-' && s[24] == '-' && s[29] == '-' && \
s[34] == '-' && s[47] == '}')
/* 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
*/
BOOL
WINAPI
CreateDirectoryA(IN LPCSTR lpPathName,
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
PUNICODE_STRING PathNameW;
PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
if (!PathNameW)
{
return FALSE;
}
return CreateDirectoryW(PathNameW->Buffer,
lpSecurityAttributes);
}
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
*/
BOOL
WINAPI
CreateDirectoryExA(IN LPCSTR lpTemplateDirectory,
IN LPCSTR lpNewDirectory,
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
PUNICODE_STRING TemplateDirectoryW;
UNICODE_STRING NewDirectoryW;
BOOL ret;
TemplateDirectoryW = Basep8BitStringToStaticUnicodeString(lpTemplateDirectory);
if (!TemplateDirectoryW)
{
return FALSE;
}
if (!Basep8BitStringToDynamicUnicodeString(&NewDirectoryW, lpNewDirectory))
{
return FALSE;
}
ret = CreateDirectoryExW(TemplateDirectoryW->Buffer,
NewDirectoryW.Buffer,
lpSecurityAttributes);
RtlFreeUnicodeString(&NewDirectoryW);
return ret;
}
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
*/
BOOL
WINAPI
CreateDirectoryW(IN LPCWSTR lpPathName,
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
DWORD Length;
NTSTATUS Status;
HANDLE DirectoryHandle;
UNICODE_STRING NtPathU;
PWSTR PathUBuffer, FilePart;
IO_STATUS_BLOCK IoStatusBlock;
RTL_RELATIVE_NAME_U RelativeName;
OBJECT_ATTRIBUTES ObjectAttributes;
/* Get relative name */
if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName))
{
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
/* Check if path length is < MAX_PATH (with space for file name).
* If not, prefix is required.
*/
if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpPathName[0] != L'\\' &&
lpPathName[1] != L'\\' && lpPathName[2] != L'?' && lpPathName[3] != L'\\')
{
/* Get file name position and full path length */
Length = GetFullPathNameW(lpPathName, 0, NULL, &FilePart);
if (Length == 0)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return FALSE;
}
/* Keep place for 8.3 file name */
Length += SFN_LENGTH;
/* No prefix, so, must be smaller than MAX_PATH */
if (Length > MAX_PATH)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(GetProcessHeap(), 0, NtPathU.Buffer);
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return FALSE;
}
}
/* Save buffer to allow later freeing */
PathUBuffer = NtPathU.Buffer;
/* If we have relative name (and root dir), use them instead */
if (RelativeName.RelativeName.Length != 0)
{
NtPathU.Length = RelativeName.RelativeName.Length;
NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
NtPathU.Buffer = RelativeName.RelativeName.Buffer;
}
else
{
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(&ObjectAttributes,
&NtPathU,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
Status = NtCreateFile(&DirectoryHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0);
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
if (NT_SUCCESS(Status))
{
NtClose(DirectoryHandle);
return TRUE;
}
if (RtlIsDosDeviceName_U(lpPathName))
{
Status = STATUS_NOT_A_DIRECTORY;
}
BaseSetLastNTError(Status);
return FALSE;
}
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
*/
BOOL
WINAPI
CreateDirectoryExW(IN LPCWSTR lpTemplateDirectory,
IN LPCWSTR lpNewDirectory,
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
DWORD Length;
NTSTATUS Status;
PVOID EaBuffer = NULL;
BOOL ReparsePoint = FALSE;
IO_STATUS_BLOCK IoStatusBlock;
FILE_EA_INFORMATION FileEaInfo;
ULONG EaLength = 0, StreamSize;
OBJECT_ATTRIBUTES ObjectAttributes;
FILE_BASIC_INFORMATION FileBasicInfo;
PREPARSE_DATA_BUFFER ReparseDataBuffer;
HANDLE TemplateHandle, DirectoryHandle;
PFILE_STREAM_INFORMATION FileStreamInfo;
FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo;
UNICODE_STRING NtPathU, NtTemplatePathU, NewDirectory;
RTL_RELATIVE_NAME_U RelativeName, TemplateRelativeName;
PWSTR TemplateBuffer, PathUBuffer, FilePart, SubstituteName;
/* Get relative name of the template */
if (!RtlDosPathNameToRelativeNtPathName_U(lpTemplateDirectory, &NtTemplatePathU, NULL, &TemplateRelativeName))
{
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
/* Save buffer for further freeing */
TemplateBuffer = NtTemplatePathU.Buffer;
/* If we have relative name (and root dir), use them instead */
if (TemplateRelativeName.RelativeName.Length != 0)
{
NtTemplatePathU.Length = TemplateRelativeName.RelativeName.Length;
NtTemplatePathU.MaximumLength = TemplateRelativeName.RelativeName.MaximumLength;
NtTemplatePathU.Buffer = TemplateRelativeName.RelativeName.Buffer;
}
else
{
TemplateRelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(&ObjectAttributes,
&NtTemplatePathU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Open template directory */
Status = NtOpenFile(&TemplateHandle,
FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(Status))
{
if (Status != STATUS_INVALID_PARAMETER)
{
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
BaseSetLastNTError(Status);
return FALSE;
}
OpenWithoutReparseSupport:
/* Opening failed due to lacking reparse points support in the FSD, try without */
Status = NtOpenFile(&TemplateHandle,
FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(Status))
{
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
BaseSetLastNTError(Status);
return FALSE;
}
/* Request file attributes */
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Status = NtQueryInformationFile(TemplateHandle,
&IoStatusBlock,
&FileBasicInfo,
sizeof(FileBasicInfo),
FileBasicInformation);
if (!NT_SUCCESS(Status))
{
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
CloseHandle(TemplateHandle);
BaseSetLastNTError(Status);
return FALSE;
}
}
else
{
/* Request file attributes */
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Status = NtQueryInformationFile(TemplateHandle,
&IoStatusBlock,
&FileBasicInfo,
sizeof(FileBasicInfo),
FileBasicInformation);
if (!NT_SUCCESS(Status))
{
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
CloseHandle(TemplateHandle);
BaseSetLastNTError(Status);
return FALSE;
}
/* If it is a reparse point, then get information about it */
if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
Status = NtQueryInformationFile(TemplateHandle,
&IoStatusBlock,
&FileTagInfo,
sizeof(FileTagInfo),
FileAttributeTagInformation);
if (!NT_SUCCESS(Status))
{
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
CloseHandle(TemplateHandle);
BaseSetLastNTError(Status);
return FALSE;
}
/* Only mount points are supported, retry without if anything different */
if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
{
CloseHandle(TemplateHandle);
goto OpenWithoutReparseSupport;
}
/* Mark we are playing with a reparse point */
ReparsePoint = TRUE;
}
}
/* Get relative name of the directory */
if (!RtlDosPathNameToRelativeNtPathName_U(lpNewDirectory, &NtPathU, NULL, &RelativeName))
{
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
NtClose(TemplateHandle);
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
/* Save its buffer for further freeing */
PathUBuffer = NtPathU.Buffer;
/* Template & directory can't be the same */
if (RtlEqualUnicodeString(&NtPathU,
&NtTemplatePathU,
TRUE))
{
RtlReleaseRelativeName(&RelativeName);
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
NtClose(TemplateHandle);
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
RtlReleaseRelativeName(&TemplateRelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
/* Check if path length is < MAX_PATH (with space for file name).
* If not, prefix is required.
*/
if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpNewDirectory[0] != L'\\' &&
lpNewDirectory[1] != L'\\' && lpNewDirectory[2] != L'?' && lpNewDirectory[3] != L'\\')
{
/* Get file name position and full path length */
Length = GetFullPathNameW(lpNewDirectory, 0, NULL, &FilePart);
if (Length == 0)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
CloseHandle(TemplateHandle);
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return FALSE;
}
/* Keep place for 8.3 file name */
Length += SFN_LENGTH;
/* No prefix, so, must be smaller than MAX_PATH */
if (Length > MAX_PATH)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
CloseHandle(TemplateHandle);
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return FALSE;
}
}
/* If we have relative name (and root dir), use them instead */
if (RelativeName.RelativeName.Length != 0)
{
NtPathU.Length = RelativeName.RelativeName.Length;
NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
NtPathU.Buffer = RelativeName.RelativeName.Buffer;
}
else
{
RelativeName.ContainingDirectory = NULL;
}
/* Get extended attributes */
Status = NtQueryInformationFile(TemplateHandle,
&IoStatusBlock,
&FileEaInfo,
sizeof(FileEaInfo),
FileEaInformation);
if (!NT_SUCCESS(Status))
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
CloseHandle(TemplateHandle);
BaseSetLastNTError(Status);
return FALSE;
}
/* Start reading extended attributes */
if (FileEaInfo.EaSize != 0)
{
for (EaLength = FileEaInfo.EaSize * 2; ; EaLength = EaLength * 2)
{
/* Allocate buffer for reading */
EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, EaLength);
if (!EaBuffer)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
CloseHandle(TemplateHandle);
BaseSetLastNTError(STATUS_NO_MEMORY);
return FALSE;
}
/* Query EAs */
Status = NtQueryEaFile(TemplateHandle,
&IoStatusBlock,
EaBuffer,
EaLength,
FALSE,
NULL,
0,
NULL,
TRUE);
if (!NT_SUCCESS(Status))
{
RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
IoStatusBlock.Information = 0;
}
/* If we don't fail because of too small buffer, stop here */
if (Status != STATUS_BUFFER_OVERFLOW &&
Status != STATUS_BUFFER_TOO_SMALL)
{
EaLength = IoStatusBlock.Information;
break;
}
}
}
InitializeObjectAttributes(&ObjectAttributes,
&NtPathU,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
/* Ensure attributes are valid */
FileBasicInfo.FileAttributes &= FILE_ATTRIBUTE_VALID_FLAGS;
/* Create the new directory */
Status = NtCreateFile(&DirectoryHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES |
FILE_READ_ATTRIBUTES | (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? FILE_ADD_FILE : 0),
&ObjectAttributes,
&IoStatusBlock,
NULL,
FileBasicInfo.FileAttributes,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT,
EaBuffer,
EaLength);
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_INVALID_PARAMETER || Status == STATUS_ACCESS_DENIED)
{
/* If creation failed, it might be because FSD doesn't support reparse points
* Retry without asking for such support in case template is not a reparse point
*/
if (!ReparsePoint)
{
Status = NtCreateFile(&DirectoryHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE |
FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FileBasicInfo.FileAttributes,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT,
EaBuffer,
EaLength);
}
else
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
if (EaBuffer)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
}
CloseHandle(TemplateHandle);
BaseSetLastNTError(Status);
return FALSE;
}
}
}
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
if (EaBuffer)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
}
if (!NT_SUCCESS(Status))
{
NtClose(TemplateHandle);
if (RtlIsDosDeviceName_U(lpNewDirectory))
{
Status = STATUS_NOT_A_DIRECTORY;
}
BaseSetLastNTError(Status);
return FALSE;
}
/* If template is a reparse point, copy reparse data */
if (ReparsePoint)
{
ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (!ReparseDataBuffer)
{
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
SetLastError(STATUS_NO_MEMORY);
return FALSE;
}
/* First query data */
Status = NtFsControlFile(TemplateHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_GET_REPARSE_POINT,
NULL,
0,
ReparseDataBuffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (!NT_SUCCESS(Status))
{
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
SetLastError(Status);
return FALSE;
}
/* Once again, ensure it is a mount point */
if (ReparseDataBuffer->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
SetLastError(STATUS_OBJECT_NAME_INVALID);
return FALSE;
}
/* Get volume name */
SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
if (IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
{
/* Prepare to define a new mount point for that volume */
RtlInitUnicodeString(&NewDirectory, lpNewDirectory);
NewDirectory.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewDirectory.Length + 2 * sizeof(WCHAR));
if (!NewDirectory.Buffer)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
return FALSE;
}
RtlCopyMemory(&NewDirectory.Buffer, lpNewDirectory, NewDirectory.Length);
if (NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] != L'\\')
{
NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] = L'\\';
NewDirectory.Buffer[(NewDirectory.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
}
/* Define a new mount point for that volume */
SetVolumeMountPointW(NewDirectory.Buffer, SubstituteName);
RtlFreeHeap(RtlGetProcessHeap(), 0, NewDirectory.Buffer);
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
return TRUE;
}
/* Otherwise copy data raw */
Status = NtFsControlFile(DirectoryHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_SET_REPARSE_POINT,
ReparseDataBuffer,
ReparseDataBuffer->ReparseDataLength +
FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer),
NULL,
0);
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
if (NT_SUCCESS(Status))
{
return TRUE;
}
BaseSetLastNTError(Status);
return FALSE;
}
/* In case it's not a reparse point, handle streams on the file */
else
{
for (StreamSize = 0x1000; ; StreamSize = StreamSize * 2)
{
FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, StreamSize);
if (!FileStreamInfo)
{
BaseMarkFileForDelete(DirectoryHandle, FileBasicInfo.FileAttributes);
SetLastError(STATUS_NO_MEMORY);
break;
}
/* Query stream information */
Status = NtQueryInformationFile(TemplateHandle,
&IoStatusBlock,
FileStreamInfo,
StreamSize,
FileStreamInformation);
if (NT_SUCCESS(Status))
{
break;
}
RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
FileStreamInfo = NULL;
/* If it failed, ensure that's not because of too small buffer */
if (Status != STATUS_BUFFER_OVERFLOW &&
Status != STATUS_BUFFER_TOO_SMALL)
{
break;
}
}
if (!NT_SUCCESS(Status) || IoStatusBlock.Information == 0)
{
if (FileStreamInfo)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
}
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
return TRUE;
}
#if 1
/* FIXME: TODO */
DPRINT1("Warning: streams copying is unimplemented!\n");
RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
NtClose(TemplateHandle);
NtClose(DirectoryHandle);
#endif
return TRUE;
}
}
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
*/
BOOL
WINAPI
RemoveDirectoryA(IN LPCSTR lpPathName)
{
PUNICODE_STRING PathNameW;
PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
if (!PathNameW)
{
return FALSE;
}
return RemoveDirectoryW(PathNameW->Buffer);
}
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
*/
BOOL
WINAPI
RemoveDirectoryW(IN LPCWSTR lpPathName)
{
NTSTATUS Status;
DWORD BytesReturned;
HANDLE DirectoryHandle;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING NtPathU, PathName;
RTL_RELATIVE_NAME_U RelativeName;
PWSTR PathUBuffer, SubstituteName;
OBJECT_ATTRIBUTES ObjectAttributes;
PREPARSE_DATA_BUFFER ReparseDataBuffer;
FILE_DISPOSITION_INFORMATION FileDispInfo;
FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo;
/* Get relative name */
if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName))
{
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
/* Save buffer to allow later freeing */
PathUBuffer = NtPathU.Buffer;
/* If we have relative name (and root dir), use them instead */
if (RelativeName.RelativeName.Length != 0)
{
NtPathU.Length = RelativeName.RelativeName.Length;
NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
NtPathU.Buffer = RelativeName.RelativeName.Buffer;
}
else
{
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(&ObjectAttributes,
&NtPathU,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL);
/* Try to open directory */
Status = NtOpenFile(&DirectoryHandle,
DELETE | SYNCHRONIZE | FAILED_ACCESS_ACE_FLAG,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
if (!NT_SUCCESS(Status))
{
/* We only accept failure for reparse points not being supported */
if (Status != STATUS_INVALID_PARAMETER)
{
goto Cleanup;
}
/* Try to open, with reparse points support */
Status = NtOpenFile(&DirectoryHandle,
DELETE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Success, mark directory */
goto MarkFileForDelete;
}
/* Get information about file (and reparse point) */
Status = NtQueryInformationFile(DirectoryHandle,
&IoStatusBlock,
&FileTagInfo,
sizeof(FileTagInfo),
FileAttributeTagInformation);
if (!NT_SUCCESS(Status))
{
/* FSD might not support querying reparse points information */
if (Status != STATUS_NOT_IMPLEMENTED &&
Status != STATUS_INVALID_PARAMETER)
{
goto CleanupHandle;
}
/* If that's the case, then just delete directory */
goto MarkFileForDelete;
}
/* If that's not a reparse point, nothing more to do than just delete */
if (!(FileTagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
{
goto MarkFileForDelete;
}
/* Check if that's a mount point */
if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
{
/* It's not */
NtClose(DirectoryHandle);
/* So, try to reopen directory, ignoring mount point */
Status = NtOpenFile(&DirectoryHandle,
DELETE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT);
if (NT_SUCCESS(Status))
{
/* It succeed, we can safely delete directory (and ignore reparse point) */
goto MarkFileForDelete;
}
/* If it failed, only allow case where IO mount point was ignored */
if (Status != STATUS_IO_REPARSE_TAG_NOT_HANDLED)
{
goto Cleanup;
}
/* Reopen with reparse point support */
Status = NtOpenFile(&DirectoryHandle,
DELETE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
if (NT_SUCCESS(Status))
{
/* And mark for delete */
goto MarkFileForDelete;
}
goto Cleanup;
}
/* Here, we have a mount point, prepare to query information about it */
ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (!ReparseDataBuffer)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
NtClose(DirectoryHandle);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
/* Query */
if (!DeviceIoControl(DirectoryHandle,
FSCTL_GET_REPARSE_POINT,
NULL, 0,
ReparseDataBuffer,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
&BytesReturned,
NULL))
{
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
goto MarkFileForDelete;
}
/* Get volume name */
SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
if (!IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
{
/* This is not a volume, we can safely delete */
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
goto MarkFileForDelete;
}
/* Prepare to delete mount point */
RtlInitUnicodeString(&PathName, lpPathName);
PathName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathName.Length + 2 * sizeof(WCHAR));
if (!PathName.Buffer)
{
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
NtClose(DirectoryHandle);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
RtlCopyMemory(&PathName.Buffer, lpPathName, PathName.Length);
if (PathName.Buffer[PathName.Length / sizeof(WCHAR)] != L'\\')
{
PathName.Buffer[PathName.Length / sizeof(WCHAR)] = L'\\';
PathName.Buffer[(PathName.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
}
/* Delete mount point for that volume */
DeleteVolumeMountPointW(PathName.Buffer);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
/* And mark directory for delete */
MarkFileForDelete:
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
/* Mark & set */
FileDispInfo.DeleteFile = TRUE;
Status = NtSetInformationFile(DirectoryHandle,
&IoStatusBlock,
&FileDispInfo,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation);
NtClose(DirectoryHandle);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
CleanupHandle:
NtClose(DirectoryHandle);
Cleanup:
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
BaseSetLastNTError(Status);
return FALSE;
}
/* EOF */