2005-01-06 13:58:04 +00:00
|
|
|
/* $Id$
|
2000-01-11 17:32:13 +00:00
|
|
|
*
|
1998-12-04 18:28:13 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
|
|
|
* FILE: lib/kernel32/file/dir.c
|
|
|
|
* PURPOSE: Directory functions
|
|
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 01/11/98
|
|
|
|
*/
|
|
|
|
|
1999-01-20 19:02:05 +00:00
|
|
|
/*
|
|
|
|
* NOTES: Changed to using ZwCreateFile
|
|
|
|
*/
|
|
|
|
|
1999-01-17 17:30:18 +00:00
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
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>
|
2010-09-21 17:14:22 +00:00
|
|
|
DEBUG_CHANNEL(kernel32file);
|
1998-12-04 18:28:13 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
UNICODE_STRING DllDirectory = {0, 0, NULL};
|
1999-05-19 17:57:57 +00:00
|
|
|
|
1999-01-17 17:30:18 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
1998-12-04 18:28:13 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
CreateDirectoryA (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCSTR lpPathName,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2005-03-20 20:27:56 +00:00
|
|
|
PWCHAR PathNameW;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
if (!(PathNameW = FilenameA2W(lpPathName, FALSE)))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return CreateDirectoryW (PathNameW,
|
|
|
|
lpSecurityAttributes);
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
CreateDirectoryExA (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCSTR lpTemplateDirectory,
|
|
|
|
LPCSTR lpNewDirectory,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2005-03-20 20:27:56 +00:00
|
|
|
PWCHAR TemplateDirectoryW;
|
|
|
|
PWCHAR NewDirectoryW;
|
2005-03-15 19:40:22 +00:00
|
|
|
BOOL ret;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
if (!(TemplateDirectoryW = FilenameA2W(lpTemplateDirectory, TRUE)))
|
2005-03-15 19:40:22 +00:00
|
|
|
return FALSE;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
if (!(NewDirectoryW = FilenameA2W(lpNewDirectory, FALSE)))
|
|
|
|
{
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
TemplateDirectoryW);
|
2005-03-15 19:40:22 +00:00
|
|
|
return FALSE;
|
2005-03-20 20:27:56 +00:00
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
ret = CreateDirectoryExW (TemplateDirectoryW,
|
2005-03-20 20:27:56 +00:00
|
|
|
NewDirectoryW,
|
|
|
|
lpSecurityAttributes);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
TemplateDirectoryW);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return ret;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
CreateDirectoryW (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCWSTR lpPathName,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2005-03-20 20:27:56 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
UNICODE_STRING NtPathU;
|
2007-11-17 18:23:16 +00:00
|
|
|
HANDLE DirectoryHandle = NULL;
|
2005-03-20 20:27:56 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE ("lpPathName %S lpSecurityAttributes %p\n",
|
2005-03-20 20:27:56 +00:00
|
|
|
lpPathName, lpSecurityAttributes);
|
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpPathName,
|
2005-03-20 20:27:56 +00:00
|
|
|
&NtPathU,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtPathU,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
|
|
|
|
|
|
|
|
Status = NtCreateFile (&DirectoryHandle,
|
2008-12-31 15:09:28 +00:00
|
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
2005-03-20 20:27:56 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
NULL,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
FILE_CREATE,
|
2008-12-31 15:09:28 +00:00
|
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
|
2005-03-20 20:27:56 +00:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
NtPathU.Buffer);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("NtCreateFile failed with Status %lx\n", Status);
|
2005-03-20 20:27:56 +00:00
|
|
|
SetLastErrorByStatus(Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NtClose (DirectoryHandle);
|
|
|
|
|
|
|
|
return TRUE;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
2000-03-15 18:30:30 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
CreateDirectoryExW (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCWSTR lpTemplateDirectory,
|
|
|
|
LPCWSTR lpNewDirectory,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2004-06-02 18:26:58 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
2005-03-20 20:27:56 +00:00
|
|
|
UNICODE_STRING NtPathU, NtTemplatePathU;
|
2005-09-29 19:34:53 +00:00
|
|
|
HANDLE DirectoryHandle = NULL;
|
|
|
|
HANDLE TemplateHandle = NULL;
|
2005-03-20 20:27:56 +00:00
|
|
|
FILE_EA_INFORMATION EaInformation;
|
2005-09-29 19:34:53 +00:00
|
|
|
FILE_BASIC_INFORMATION FileBasicInfo;
|
2004-06-02 18:26:58 +00:00
|
|
|
NTSTATUS Status;
|
2005-09-29 19:34:53 +00:00
|
|
|
ULONG OpenOptions, CreateOptions;
|
|
|
|
ACCESS_MASK DesiredAccess;
|
|
|
|
BOOLEAN ReparsePoint = FALSE;
|
2005-03-20 20:27:56 +00:00
|
|
|
PVOID EaBuffer = NULL;
|
|
|
|
ULONG EaLength = 0;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
OpenOptions = FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT |
|
|
|
|
FILE_OPEN_FOR_BACKUP_INTENT;
|
|
|
|
CreateOptions = FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT;
|
|
|
|
DesiredAccess = FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES |
|
|
|
|
FILE_READ_ATTRIBUTES;
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE ("lpTemplateDirectory %ws lpNewDirectory %ws lpSecurityAttributes %p\n",
|
2004-06-02 18:26:58 +00:00
|
|
|
lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes);
|
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
/*
|
2005-09-29 19:34:53 +00:00
|
|
|
* Translate the template directory path
|
2005-03-20 20:27:56 +00:00
|
|
|
*/
|
2000-03-15 18:30:30 +00:00
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpTemplateDirectory,
|
2005-03-20 20:27:56 +00:00
|
|
|
&NtTemplatePathU,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtTemplatePathU,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
/*
|
|
|
|
* Open the template directory
|
|
|
|
*/
|
|
|
|
|
|
|
|
OpenTemplateDir:
|
|
|
|
Status = NtOpenFile (&TemplateHandle,
|
|
|
|
FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
OpenOptions);
|
2005-03-20 20:27:56 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2005-09-29 19:34:53 +00:00
|
|
|
if (Status == STATUS_INVALID_PARAMETER &&
|
|
|
|
(OpenOptions & FILE_OPEN_REPARSE_POINT))
|
|
|
|
{
|
|
|
|
/* Some FSs (FAT) don't support reparse points, try opening
|
|
|
|
the directory without FILE_OPEN_REPARSE_POINT */
|
|
|
|
OpenOptions &= ~FILE_OPEN_REPARSE_POINT;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("Reparse points not supported, try with less options\n");
|
2005-09-29 19:34:53 +00:00
|
|
|
|
|
|
|
/* try again */
|
|
|
|
goto OpenTemplateDir;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Failed to open the template directory: 0x%x\n", Status);
|
2005-09-29 19:34:53 +00:00
|
|
|
goto CleanupNoNtPath;
|
|
|
|
}
|
2005-03-20 20:27:56 +00:00
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
/*
|
|
|
|
* Translate the new directory path and check if they're the same
|
|
|
|
*/
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpNewDirectory,
|
2005-09-29 19:34:53 +00:00
|
|
|
&NtPathU,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|
|
|
goto CleanupNoNtPath;
|
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
if (RtlEqualUnicodeString(&NtPathU,
|
|
|
|
&NtTemplatePathU,
|
|
|
|
TRUE))
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Both directory paths are the same!\n");
|
2005-09-29 19:34:53 +00:00
|
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
2006-05-07 18:17:50 +00:00
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtPathU,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
|
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
/*
|
|
|
|
* Query the basic file attributes from the template directory
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Make sure FILE_ATTRIBUTE_NORMAL is used in case the information
|
|
|
|
isn't set by the FS */
|
|
|
|
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
Status = NtQueryInformationFile(TemplateHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
&FileBasicInfo,
|
|
|
|
sizeof(FILE_BASIC_INFORMATION),
|
|
|
|
FileBasicInformation);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Failed to query the basic directory attributes\n");
|
2005-09-29 19:34:53 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
/* clear the reparse point attribute if present. We're going to set the
|
|
|
|
reparse point later which will cause the attribute to be set */
|
|
|
|
if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
|
|
|
{
|
|
|
|
FileBasicInfo.FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
|
|
|
|
|
|
|
/* writing the extended attributes requires the FILE_WRITE_DATA
|
|
|
|
access right */
|
|
|
|
DesiredAccess |= FILE_WRITE_DATA;
|
|
|
|
|
|
|
|
CreateOptions |= FILE_OPEN_REPARSE_POINT;
|
|
|
|
ReparsePoint = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the Extended Attributes if present
|
|
|
|
*/
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
Status = NtQueryInformationFile(TemplateHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
&EaInformation,
|
|
|
|
sizeof(FILE_EA_INFORMATION),
|
|
|
|
FileEaInformation);
|
|
|
|
if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
|
|
|
|
{
|
|
|
|
EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
0,
|
|
|
|
EaInformation.EaSize);
|
|
|
|
if (EaBuffer == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
break;
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
Status = NtQueryEaFile(TemplateHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
EaBuffer,
|
|
|
|
EaInformation.EaSize,
|
|
|
|
FALSE,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* we successfully read the extended attributes */
|
|
|
|
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
|
|
|
|
{
|
|
|
|
/* failure or no extended attributes present, break the loop */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-06-02 18:26:58 +00:00
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Querying the EA data failed: 0x%x\n", Status);
|
2005-09-29 19:34:53 +00:00
|
|
|
goto Cleanup;
|
2004-06-02 18:26:58 +00:00
|
|
|
}
|
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
/*
|
2005-09-29 19:34:53 +00:00
|
|
|
* Create the new directory
|
2005-03-20 20:27:56 +00:00
|
|
|
*/
|
2006-05-07 18:17:50 +00:00
|
|
|
|
2004-06-02 18:26:58 +00:00
|
|
|
Status = NtCreateFile (&DirectoryHandle,
|
2005-09-29 19:34:53 +00:00
|
|
|
DesiredAccess,
|
2004-06-02 18:26:58 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
NULL,
|
2005-09-29 19:34:53 +00:00
|
|
|
FileBasicInfo.FileAttributes,
|
2005-03-20 20:27:56 +00:00
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
2004-06-02 18:26:58 +00:00
|
|
|
FILE_CREATE,
|
2005-09-29 19:34:53 +00:00
|
|
|
CreateOptions,
|
2005-03-20 20:27:56 +00:00
|
|
|
EaBuffer,
|
|
|
|
EaLength);
|
2005-09-29 19:34:53 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (ReparsePoint &&
|
|
|
|
(Status == STATUS_INVALID_PARAMETER || Status == STATUS_ACCESS_DENIED))
|
|
|
|
{
|
|
|
|
/* The FS doesn't seem to support reparse points... */
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Cannot copy the hardlink, destination doesn\'t support reparse points!\n");
|
2005-09-29 19:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
if (ReparsePoint)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Copy the reparse point
|
|
|
|
*/
|
|
|
|
|
|
|
|
PREPARSE_GUID_DATA_BUFFER ReparseDataBuffer =
|
|
|
|
(PREPARSE_GUID_DATA_BUFFER)RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
0,
|
|
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
|
|
|
|
|
|
if (ReparseDataBuffer == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* query the size of the reparse data buffer structure */
|
|
|
|
Status = NtFsControlFile(TemplateHandle,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FSCTL_GET_REPARSE_POINT,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
ReparseDataBuffer,
|
|
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* write the reparse point */
|
|
|
|
Status = NtFsControlFile(DirectoryHandle,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FSCTL_SET_REPARSE_POINT,
|
|
|
|
ReparseDataBuffer,
|
|
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
|
|
0,
|
|
|
|
ReparseDataBuffer);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* fail, we were unable to read the reparse point data! */
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Querying or setting the reparse point failed: 0x%x\n", Status);
|
2005-09-29 19:34:53 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Copy alternate file streams, if existing
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* FIXME - enumerate and copy the file streams */
|
|
|
|
}
|
2006-05-07 18:17:50 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
/*
|
|
|
|
* We successfully created the directory and copied all information
|
|
|
|
* from the template directory
|
|
|
|
*/
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
NtPathU.Buffer);
|
|
|
|
|
|
|
|
CleanupNoNtPath:
|
|
|
|
if (TemplateHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(TemplateHandle);
|
|
|
|
}
|
2006-05-07 18:17:50 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
NtTemplatePathU.Buffer);
|
2005-03-20 20:27:56 +00:00
|
|
|
|
|
|
|
/* free the he extended attributes buffer */
|
|
|
|
if (EaBuffer != NULL)
|
|
|
|
{
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
EaBuffer);
|
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-09-29 19:34:53 +00:00
|
|
|
if (DirectoryHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(DirectoryHandle);
|
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SetLastErrorByStatus(Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2000-03-15 18:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
RemoveDirectoryA (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCSTR lpPathName
|
|
|
|
)
|
2000-03-15 18:30:30 +00:00
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
PWCHAR PathNameW;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("RemoveDirectoryA(%s)\n",lpPathName);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!(PathNameW = FilenameA2W(lpPathName, FALSE)))
|
|
|
|
return FALSE;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return RemoveDirectoryW (PathNameW);
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
RemoveDirectoryW (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCWSTR lpPathName
|
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2004-06-02 18:26:58 +00:00
|
|
|
FILE_DISPOSITION_INFORMATION FileDispInfo;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
UNICODE_STRING NtPathU;
|
2007-11-17 18:23:16 +00:00
|
|
|
HANDLE DirectoryHandle = NULL;
|
2004-06-02 18:26:58 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("lpPathName %S\n", lpPathName);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-12-17 15:45:59 +00:00
|
|
|
if (!RtlDosPathNameToNtPathName_U (lpPathName,
|
2004-06-02 18:26:58 +00:00
|
|
|
&NtPathU,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
2009-05-09 12:44:39 +00:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
2004-06-02 18:26:58 +00:00
|
|
|
return FALSE;
|
2009-05-09 12:44:39 +00:00
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-20 20:27:56 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtPathU,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("NtPathU '%S'\n", NtPathU.Buffer);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2009-05-09 12:44:39 +00:00
|
|
|
Status = NtOpenFile(&DirectoryHandle,
|
2009-12-15 18:39:13 +00:00
|
|
|
DELETE | SYNCHRONIZE,
|
2009-05-09 12:44:39 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2009-05-09 12:44:39 +00:00
|
|
|
RtlFreeUnicodeString(&NtPathU);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("Status 0x%08x\n", Status);
|
2004-06-02 18:26:58 +00:00
|
|
|
SetLastErrorByStatus (Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-08-18 02:13:27 +00:00
|
|
|
FileDispInfo.DeleteFile = TRUE;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
|
|
|
Status = NtSetInformationFile (DirectoryHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
&FileDispInfo,
|
|
|
|
sizeof(FILE_DISPOSITION_INFORMATION),
|
|
|
|
FileDispositionInformation);
|
2005-03-20 20:27:56 +00:00
|
|
|
NtClose(DirectoryHandle);
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-06-02 18:26:58 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SetLastErrorByStatus (Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
1999-04-28 14:19:34 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2000-02-18 00:51:03 +00:00
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-02-18 00:51:03 +00:00
|
|
|
GetFullPathNameA (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCSTR lpFileName,
|
|
|
|
DWORD nBufferLength,
|
|
|
|
LPSTR lpBuffer,
|
|
|
|
LPSTR *lpFilePart
|
|
|
|
)
|
1999-04-28 14:19:34 +00:00
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
WCHAR BufferW[MAX_PATH];
|
|
|
|
PWCHAR FileNameW;
|
|
|
|
DWORD ret;
|
|
|
|
LPWSTR FilePartW = NULL;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, "
|
2005-03-15 19:40:22 +00:00
|
|
|
"lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!lpFileName)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
|
|
|
|
return 0;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
ret = GetFullPathNameW(FileNameW, MAX_PATH, BufferW, &FilePartW);
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!ret)
|
|
|
|
return 0;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (ret > MAX_PATH)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
ret = FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (ret < nBufferLength && lpFilePart)
|
|
|
|
{
|
|
|
|
/* if the path closed with '\', FilePart is NULL */
|
2005-05-09 01:46:57 +00:00
|
|
|
if (!FilePartW)
|
2005-03-15 19:40:22 +00:00
|
|
|
*lpFilePart=NULL;
|
|
|
|
else
|
|
|
|
*lpFilePart = (FilePartW - BufferW) + lpBuffer;
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n",
|
2005-03-15 19:40:22 +00:00
|
|
|
lpBuffer, (lpFilePart == NULL) ? "NULL" : *lpFilePart);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return ret;
|
1999-04-28 14:19:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2000-02-18 00:51:03 +00:00
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-02-18 00:51:03 +00:00
|
|
|
GetFullPathNameW (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCWSTR lpFileName,
|
|
|
|
DWORD nBufferLength,
|
|
|
|
LPWSTR lpBuffer,
|
|
|
|
LPWSTR *lpFilePart
|
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2004-10-07 20:39:04 +00:00
|
|
|
ULONG Length;
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, "
|
2004-10-07 20:39:04 +00:00
|
|
|
"lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
|
1999-05-19 17:57:57 +00:00
|
|
|
|
2004-10-07 20:39:04 +00:00
|
|
|
Length = RtlGetFullPathName_U ((LPWSTR)lpFileName,
|
|
|
|
nBufferLength * sizeof(WCHAR),
|
|
|
|
lpBuffer,
|
|
|
|
lpFilePart);
|
1999-05-19 17:57:57 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetFullPathNameW ret: lpBuffer %S lpFilePart %S Length %ld\n",
|
2004-10-07 20:39:04 +00:00
|
|
|
lpBuffer, (lpFilePart == NULL) ? L"NULL" : *lpFilePart, Length / sizeof(WCHAR));
|
1999-05-19 17:57:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return Length/sizeof(WCHAR);
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
2004-06-28 19:46:17 +00:00
|
|
|
* NOTE: Copied from Wine.
|
|
|
|
* @implemented
|
2003-07-10 18:50:51 +00:00
|
|
|
*/
|
1998-12-04 18:28:13 +00:00
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
GetShortPathNameA (
|
2004-06-28 19:46:17 +00:00
|
|
|
LPCSTR longpath,
|
|
|
|
LPSTR shortpath,
|
|
|
|
DWORD shortlen
|
2004-06-02 18:26:58 +00:00
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
PWCHAR LongPathW;
|
|
|
|
WCHAR ShortPathW[MAX_PATH];
|
|
|
|
DWORD ret;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2004-06-28 19:46:17 +00:00
|
|
|
if (!longpath)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!(LongPathW = FilenameA2W(longpath, FALSE)))
|
|
|
|
return 0;
|
2004-06-28 19:46:17 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
ret = GetShortPathNameW(LongPathW, ShortPathW, MAX_PATH);
|
2004-06-28 19:46:17 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!ret)
|
|
|
|
return 0;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (ret > MAX_PATH)
|
2004-06-28 19:46:17 +00:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
2005-03-15 19:40:22 +00:00
|
|
|
return 0;
|
2004-06-28 19:46:17 +00:00
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return FilenameW2A_FitOrFail(shortpath, shortlen, ShortPathW, ret+1);
|
1999-05-19 17:57:57 +00:00
|
|
|
}
|
1998-12-04 18:28:13 +00:00
|
|
|
|
2000-03-15 18:30:30 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
2004-06-28 19:46:17 +00:00
|
|
|
* NOTE: Copied from Wine.
|
|
|
|
* @implemented
|
2003-07-10 18:50:51 +00:00
|
|
|
*/
|
1998-12-04 18:28:13 +00:00
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
GetShortPathNameW (
|
2004-06-28 19:46:17 +00:00
|
|
|
LPCWSTR longpath,
|
|
|
|
LPWSTR shortpath,
|
|
|
|
DWORD shortlen
|
2004-06-02 18:26:58 +00:00
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2005-06-20 04:07:49 +00:00
|
|
|
WCHAR tmpshortpath[MAX_PATH];
|
2004-06-28 19:46:17 +00:00
|
|
|
LPCWSTR p;
|
|
|
|
DWORD sp = 0, lp = 0;
|
|
|
|
DWORD tmplen;
|
|
|
|
WIN32_FIND_DATAW wfd;
|
|
|
|
HANDLE goit;
|
|
|
|
UNICODE_STRING ustr;
|
|
|
|
WCHAR ustr_buf[8+1+3+1];
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetShortPathNameW: %S\n",longpath);
|
2005-03-15 19:40:22 +00:00
|
|
|
|
2004-06-28 19:46:17 +00:00
|
|
|
if (!longpath)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
2004-06-02 18:26:58 +00:00
|
|
|
return 0;
|
2004-06-28 19:46:17 +00:00
|
|
|
}
|
|
|
|
if (!longpath[0])
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_BAD_PATHNAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for drive letter */
|
2010-04-12 19:43:07 +00:00
|
|
|
if (longpath[0] != '/' && longpath[1] == ':' )
|
2004-06-28 19:46:17 +00:00
|
|
|
{
|
|
|
|
tmpshortpath[0] = longpath[0];
|
|
|
|
tmpshortpath[1] = ':';
|
|
|
|
sp = lp = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
ustr.Buffer = ustr_buf;
|
|
|
|
ustr.Length = 0;
|
|
|
|
ustr.MaximumLength = sizeof(ustr_buf);
|
|
|
|
|
|
|
|
while (longpath[lp])
|
|
|
|
{
|
|
|
|
/* check for path delimiters and reproduce them */
|
|
|
|
if (longpath[lp] == '\\' || longpath[lp] == '/')
|
|
|
|
{
|
|
|
|
if (!sp || tmpshortpath[sp-1] != '\\')
|
|
|
|
{
|
|
|
|
/* strip double "\\" */
|
|
|
|
tmpshortpath[sp] = '\\';
|
|
|
|
sp++;
|
|
|
|
}
|
|
|
|
tmpshortpath[sp] = 0; /* terminate string */
|
|
|
|
lp++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (p = longpath + lp; *p && *p != '/' && *p != '\\'; p++);
|
|
|
|
tmplen = p - (longpath + lp);
|
|
|
|
lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
|
|
|
|
/* Check, if the current element is a valid dos name */
|
2010-04-12 19:43:07 +00:00
|
|
|
if (tmplen <= 8+1+3)
|
2004-06-28 19:46:17 +00:00
|
|
|
{
|
|
|
|
BOOLEAN spaces;
|
|
|
|
memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR));
|
|
|
|
ustr_buf[tmplen] = '\0';
|
2007-01-26 07:22:19 +00:00
|
|
|
ustr.Length = (USHORT)tmplen * sizeof(WCHAR);
|
2004-06-28 19:46:17 +00:00
|
|
|
if (RtlIsNameLegalDOS8Dot3(&ustr, NULL, &spaces) && !spaces)
|
|
|
|
{
|
|
|
|
sp += tmplen;
|
|
|
|
lp += tmplen;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the file exists and use the existing short file name */
|
|
|
|
goit = FindFirstFileW(tmpshortpath, &wfd);
|
|
|
|
if (goit == INVALID_HANDLE_VALUE) goto notfound;
|
|
|
|
FindClose(goit);
|
|
|
|
lstrcpyW(tmpshortpath + sp, wfd.cAlternateFileName);
|
|
|
|
sp += lstrlenW(tmpshortpath + sp);
|
|
|
|
lp += tmplen;
|
|
|
|
}
|
|
|
|
tmpshortpath[sp] = 0;
|
|
|
|
|
|
|
|
tmplen = lstrlenW(tmpshortpath) + 1;
|
|
|
|
if (tmplen <= shortlen)
|
|
|
|
{
|
|
|
|
lstrcpyW(shortpath, tmpshortpath);
|
|
|
|
tmplen--; /* length without 0 */
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmplen;
|
|
|
|
|
|
|
|
notfound:
|
|
|
|
SetLastError ( ERROR_FILE_NOT_FOUND );
|
|
|
|
return 0;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
2000-03-15 18:30:30 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
1998-12-04 18:28:13 +00:00
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 18:30:30 +00:00
|
|
|
SearchPathA (
|
2004-06-02 18:26:58 +00:00
|
|
|
LPCSTR lpPath,
|
|
|
|
LPCSTR lpFileName,
|
|
|
|
LPCSTR lpExtension,
|
|
|
|
DWORD nBufferLength,
|
|
|
|
LPSTR lpBuffer,
|
|
|
|
LPSTR *lpFilePart
|
|
|
|
)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2008-12-03 17:33:13 +00:00
|
|
|
UNICODE_STRING PathU = { 0, 0, NULL };
|
|
|
|
UNICODE_STRING FileNameU = { 0, 0, NULL };
|
|
|
|
UNICODE_STRING ExtensionU = { 0, 0, NULL };
|
|
|
|
UNICODE_STRING BufferU = { 0, 0, NULL };
|
2004-06-02 18:26:58 +00:00
|
|
|
ANSI_STRING Path;
|
|
|
|
ANSI_STRING FileName;
|
|
|
|
ANSI_STRING Extension;
|
|
|
|
ANSI_STRING Buffer;
|
|
|
|
PWCHAR FilePartW;
|
2005-12-11 20:04:38 +00:00
|
|
|
DWORD RetValue = 0;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2010-03-15 22:04:15 +00:00
|
|
|
if (!lpFileName)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-06-02 18:26:58 +00:00
|
|
|
RtlInitAnsiString (&Path,
|
|
|
|
(LPSTR)lpPath);
|
|
|
|
RtlInitAnsiString (&FileName,
|
|
|
|
(LPSTR)lpFileName);
|
|
|
|
RtlInitAnsiString (&Extension,
|
|
|
|
(LPSTR)lpExtension);
|
|
|
|
|
|
|
|
/* convert ansi (or oem) strings to unicode */
|
|
|
|
if (bIsFileApiAnsi)
|
|
|
|
{
|
2005-12-11 20:04:38 +00:00
|
|
|
Status = RtlAnsiStringToUnicodeString (&PathU,
|
|
|
|
&Path,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Cleanup;
|
|
|
|
|
|
|
|
Status = RtlAnsiStringToUnicodeString (&FileNameU,
|
|
|
|
&FileName,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Cleanup;
|
|
|
|
|
|
|
|
Status = RtlAnsiStringToUnicodeString (&ExtensionU,
|
|
|
|
&Extension,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Cleanup;
|
2004-06-02 18:26:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-11 20:04:38 +00:00
|
|
|
Status = RtlOemStringToUnicodeString (&PathU,
|
|
|
|
&Path,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Cleanup;
|
|
|
|
Status = RtlOemStringToUnicodeString (&FileNameU,
|
|
|
|
&FileName,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Cleanup;
|
|
|
|
|
|
|
|
Status = RtlOemStringToUnicodeString (&ExtensionU,
|
|
|
|
&Extension,
|
|
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Cleanup;
|
2004-06-02 18:26:58 +00:00
|
|
|
}
|
|
|
|
|
2009-06-06 08:14:11 +00:00
|
|
|
BufferU.MaximumLength = min(nBufferLength * sizeof(WCHAR), USHRT_MAX);
|
2004-06-02 18:26:58 +00:00
|
|
|
BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
BufferU.MaximumLength);
|
2005-12-11 20:04:38 +00:00
|
|
|
if (BufferU.Buffer == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2009-06-06 08:14:11 +00:00
|
|
|
Buffer.MaximumLength = min(nBufferLength, USHRT_MAX);
|
2004-06-02 18:26:58 +00:00
|
|
|
Buffer.Buffer = lpBuffer;
|
|
|
|
|
|
|
|
RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer,
|
|
|
|
NULL == lpFileName ? NULL : FileNameU.Buffer,
|
|
|
|
NULL == lpExtension ? NULL : ExtensionU.Buffer,
|
|
|
|
nBufferLength,
|
|
|
|
BufferU.Buffer,
|
|
|
|
&FilePartW);
|
|
|
|
|
|
|
|
if (0 != RetValue)
|
|
|
|
{
|
|
|
|
BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR);
|
|
|
|
/* convert ansi (or oem) string to unicode */
|
|
|
|
if (bIsFileApiAnsi)
|
2009-02-11 13:54:29 +00:00
|
|
|
Status = RtlUnicodeStringToAnsiString(&Buffer,
|
|
|
|
&BufferU,
|
|
|
|
FALSE);
|
2004-06-02 18:26:58 +00:00
|
|
|
else
|
2009-02-11 13:54:29 +00:00
|
|
|
Status = RtlUnicodeStringToOemString(&Buffer,
|
|
|
|
&BufferU,
|
|
|
|
FALSE);
|
2005-12-11 20:04:38 +00:00
|
|
|
|
2009-02-11 13:54:29 +00:00
|
|
|
if (NT_SUCCESS(Status) && Buffer.Buffer)
|
2005-12-11 20:04:38 +00:00
|
|
|
{
|
2009-02-11 13:54:29 +00:00
|
|
|
/* nul-terminate ascii string */
|
|
|
|
Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0';
|
|
|
|
|
|
|
|
if (NULL != lpFilePart && BufferU.Length != 0)
|
|
|
|
{
|
2005-12-11 20:04:38 +00:00
|
|
|
*lpFilePart = strrchr (lpBuffer, '\\') + 1;
|
2009-02-11 13:54:29 +00:00
|
|
|
}
|
2005-12-11 20:04:38 +00:00
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
}
|
|
|
|
|
2005-12-11 20:04:38 +00:00
|
|
|
Cleanup:
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
PathU.Buffer);
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
FileNameU.Buffer);
|
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
ExtensionU.Buffer);
|
2004-06-02 18:26:58 +00:00
|
|
|
RtlFreeHeap (RtlGetProcessHeap (),
|
|
|
|
0,
|
|
|
|
BufferU.Buffer);
|
|
|
|
|
2005-12-11 20:04:38 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2004-06-02 18:26:58 +00:00
|
|
|
{
|
2005-12-11 20:04:38 +00:00
|
|
|
SetLastErrorByStatus(Status);
|
|
|
|
return 0;
|
2004-06-02 18:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return RetValue;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
2000-03-15 18:30:30 +00:00
|
|
|
|
2009-07-17 13:24:07 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* ContainsPath (Wine name: contains_pathW)
|
|
|
|
*
|
|
|
|
* Check if the file name contains a path; helper for SearchPathW.
|
|
|
|
* A relative path is not considered a path unless it starts with ./ or ../
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
BOOL
|
|
|
|
ContainsPath(LPCWSTR name)
|
|
|
|
{
|
|
|
|
if (RtlDetermineDosPathNameType_U(name) != RtlPathTypeRelative) return TRUE;
|
|
|
|
if (name[0] != '.') return FALSE;
|
2010-08-04 13:33:37 +00:00
|
|
|
if (name[1] == '/' || name[1] == '\\' || name[1] == '\0') return TRUE;
|
2009-07-17 13:24:07 +00:00
|
|
|
return (name[1] == '.' && (name[2] == '/' || name[2] == '\\'));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2000-03-15 18:30:30 +00:00
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2009-07-17 13:24:07 +00:00
|
|
|
SearchPathW(LPCWSTR lpPath,
|
|
|
|
LPCWSTR lpFileName,
|
|
|
|
LPCWSTR lpExtension,
|
|
|
|
DWORD nBufferLength,
|
|
|
|
LPWSTR lpBuffer,
|
|
|
|
LPWSTR *lpFilePart)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2009-07-17 13:24:07 +00:00
|
|
|
DWORD ret = 0;
|
|
|
|
|
2010-03-15 22:04:15 +00:00
|
|
|
if (!lpFileName || !lpFileName[0])
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-07-17 13:24:07 +00:00
|
|
|
/* If the name contains an explicit path, ignore the path */
|
|
|
|
if (ContainsPath(lpFileName))
|
|
|
|
{
|
|
|
|
/* try first without extension */
|
|
|
|
if (RtlDoesFileExists_U(lpFileName))
|
|
|
|
return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
|
|
|
|
|
|
|
|
if (lpExtension)
|
2004-06-02 18:26:58 +00:00
|
|
|
{
|
2009-07-17 13:24:07 +00:00
|
|
|
LPCWSTR p = wcsrchr(lpFileName, '.');
|
|
|
|
if (p && !strchr((const char *)p, '/') && !wcschr( p, '\\' ))
|
|
|
|
lpExtension = NULL; /* Ignore the specified extension */
|
2004-07-01 22:35:35 +00:00
|
|
|
}
|
2009-07-17 13:24:07 +00:00
|
|
|
|
|
|
|
/* Allocate a buffer for the file name and extension */
|
|
|
|
if (lpExtension)
|
2004-07-01 22:35:35 +00:00
|
|
|
{
|
2009-07-17 13:24:07 +00:00
|
|
|
LPWSTR tmp;
|
|
|
|
DWORD len = wcslen(lpFileName) + wcslen(lpExtension);
|
|
|
|
|
|
|
|
if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR))))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
wcscpy(tmp, lpFileName);
|
|
|
|
wcscat(tmp, lpExtension);
|
|
|
|
if (RtlDoesFileExists_U(tmp))
|
|
|
|
ret = GetFullPathNameW(tmp, nBufferLength, lpBuffer, lpFilePart);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (lpPath && lpPath[0]) /* search in the specified path */
|
|
|
|
{
|
|
|
|
ret = RtlDosSearchPath_U(lpPath,
|
|
|
|
lpFileName,
|
|
|
|
lpExtension,
|
|
|
|
nBufferLength * sizeof(WCHAR),
|
|
|
|
lpBuffer,
|
|
|
|
lpFilePart) / sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
else /* search in the default path */
|
|
|
|
{
|
|
|
|
WCHAR *DllPath = GetDllLoadPath(NULL);
|
|
|
|
|
|
|
|
if (DllPath)
|
|
|
|
{
|
|
|
|
ret = RtlDosSearchPath_U(DllPath,
|
|
|
|
lpFileName,
|
|
|
|
lpExtension,
|
|
|
|
nBufferLength * sizeof(WCHAR),
|
|
|
|
lpBuffer,
|
|
|
|
lpFilePart) / sizeof(WCHAR);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
|
2004-07-01 22:35:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-17 13:24:07 +00:00
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2009-07-17 13:24:07 +00:00
|
|
|
if (!ret) SetLastError(ERROR_FILE_NOT_FOUND);
|
2004-06-02 18:26:58 +00:00
|
|
|
|
2009-07-17 13:24:07 +00:00
|
|
|
return ret;
|
1999-01-13 15:57:45 +00:00
|
|
|
}
|
1999-01-16 02:11:45 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-12-09 17:28:10 +00:00
|
|
|
SetDllDirectoryW(
|
|
|
|
LPCWSTR lpPathName
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UNICODE_STRING PathName;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
RtlInitUnicodeString(&PathName, lpPathName);
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
RtlEnterCriticalSection(&DllLock);
|
|
|
|
if(PathName.Length > 0)
|
|
|
|
{
|
|
|
|
if(PathName.Length + sizeof(WCHAR) <= DllDirectory.MaximumLength)
|
|
|
|
{
|
|
|
|
RtlCopyUnicodeString(&DllDirectory, &PathName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RtlFreeUnicodeString(&DllDirectory);
|
|
|
|
if(!(DllDirectory.Buffer = (PWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
0,
|
|
|
|
PathName.Length + sizeof(WCHAR))))
|
|
|
|
{
|
|
|
|
RtlLeaveCriticalSection(&DllLock);
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
DllDirectory.Length = 0;
|
|
|
|
DllDirectory.MaximumLength = PathName.Length + sizeof(WCHAR);
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
RtlCopyUnicodeString(&DllDirectory, &PathName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RtlFreeUnicodeString(&DllDirectory);
|
|
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&DllLock);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-12-09 17:28:10 +00:00
|
|
|
SetDllDirectoryA(
|
2005-03-15 19:40:22 +00:00
|
|
|
LPCSTR lpPathName /* can be NULL */
|
2004-12-09 17:28:10 +00:00
|
|
|
)
|
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
PWCHAR PathNameW=NULL;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if(lpPathName)
|
2004-12-09 17:28:10 +00:00
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!(PathNameW = FilenameA2W(lpPathName, FALSE)))
|
|
|
|
return FALSE;
|
2004-12-09 17:28:10 +00:00
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return SetDllDirectoryW(PathNameW);
|
2004-12-09 17:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-12-09 17:28:10 +00:00
|
|
|
GetDllDirectoryW(
|
|
|
|
DWORD nBufferLength,
|
|
|
|
LPWSTR lpBuffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
DWORD Ret;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
RtlEnterCriticalSection(&DllLock);
|
|
|
|
if(nBufferLength > 0)
|
|
|
|
{
|
|
|
|
Ret = DllDirectory.Length / sizeof(WCHAR);
|
|
|
|
if(Ret > nBufferLength - 1)
|
|
|
|
{
|
|
|
|
Ret = nBufferLength - 1;
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
if(Ret > 0)
|
|
|
|
{
|
|
|
|
RtlCopyMemory(lpBuffer, DllDirectory.Buffer, Ret * sizeof(WCHAR));
|
|
|
|
}
|
|
|
|
lpBuffer[Ret] = L'\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* include termination character, even if the string is empty! */
|
|
|
|
Ret = (DllDirectory.Length / sizeof(WCHAR)) + 1;
|
|
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&DllLock);
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2004-12-09 17:28:10 +00:00
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
DWORD
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-12-09 17:28:10 +00:00
|
|
|
GetDllDirectoryA(
|
|
|
|
DWORD nBufferLength,
|
|
|
|
LPSTR lpBuffer
|
|
|
|
)
|
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
WCHAR BufferW[MAX_PATH];
|
|
|
|
DWORD ret;
|
2004-12-09 17:28:10 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
ret = GetDllDirectoryW(MAX_PATH, BufferW);
|
2004-12-09 17:28:10 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (!ret)
|
|
|
|
return 0;
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
if (ret > MAX_PATH)
|
2004-12-09 17:28:10 +00:00
|
|
|
{
|
2005-03-15 19:40:22 +00:00
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return 0;
|
2004-12-09 17:28:10 +00:00
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
|
2004-12-09 17:28:10 +00:00
|
|
|
}
|
|
|
|
|
2005-02-12 17:15:04 +00:00
|
|
|
|
|
|
|
/*
|
2005-06-30 12:33:12 +00:00
|
|
|
* @implemented
|
2005-02-12 17:15:04 +00:00
|
|
|
*/
|
2008-11-30 11:42:05 +00:00
|
|
|
BOOL WINAPI
|
2005-02-12 17:15:04 +00:00
|
|
|
NeedCurrentDirectoryForExePathW(LPCWSTR ExeName)
|
|
|
|
{
|
2008-07-21 19:54:50 +00:00
|
|
|
static const WCHAR env_name[] = {'N','o','D','e','f','a','u','l','t',
|
|
|
|
'C','u','r','r','e','n','t',
|
|
|
|
'D','i','r','e','c','t','o','r','y',
|
|
|
|
'I','n','E','x','e','P','a','t','h',0};
|
|
|
|
WCHAR env_val;
|
|
|
|
|
|
|
|
/* MSDN mentions some 'registry location'. We do not use registry. */
|
|
|
|
FIXME("(%s): partial stub\n", debugstr_w(ExeName));
|
|
|
|
|
|
|
|
if (wcschr(ExeName, L'\\'))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* Check the existence of the variable, not value */
|
|
|
|
if (!GetEnvironmentVariableW( env_name, &env_val, 1 ))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
2005-02-12 17:15:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-30 11:42:05 +00:00
|
|
|
BOOL WINAPI
|
2005-02-12 17:15:04 +00:00
|
|
|
NeedCurrentDirectoryForExePathA(LPCSTR ExeName)
|
|
|
|
{
|
2008-07-21 19:54:50 +00:00
|
|
|
WCHAR *ExeNameW;
|
|
|
|
|
|
|
|
if (!(ExeNameW = FilenameA2W(ExeName, FALSE)))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return NeedCurrentDirectoryForExePathW(ExeNameW);
|
2005-03-15 19:40:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* @implemented
|
|
|
|
*
|
|
|
|
* GetLongPathNameW (KERNEL32.@)
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* observed (Win2000):
|
|
|
|
* shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
|
|
|
|
* shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0
|
|
|
|
*/
|
2008-11-30 11:42:05 +00:00
|
|
|
DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen )
|
2005-03-15 19:40:22 +00:00
|
|
|
{
|
|
|
|
#define MAX_PATHNAME_LEN 1024
|
|
|
|
|
|
|
|
WCHAR tmplongpath[MAX_PATHNAME_LEN];
|
|
|
|
LPCWSTR p;
|
|
|
|
DWORD sp = 0, lp = 0;
|
|
|
|
DWORD tmplen;
|
2008-05-27 10:53:23 +00:00
|
|
|
BOOL unixabsolute;
|
2005-03-15 19:40:22 +00:00
|
|
|
WIN32_FIND_DATAW wfd;
|
|
|
|
HANDLE goit;
|
|
|
|
|
|
|
|
if (!shortpath)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!shortpath[0])
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetLongPathNameW(%s,%p,%ld)\n", shortpath, longpath, longlen);
|
2005-03-15 19:40:22 +00:00
|
|
|
|
|
|
|
if (shortpath[0] == '\\' && shortpath[1] == '\\')
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
WARN("ERR: UNC pathname %s\n", shortpath);
|
2005-03-15 19:40:22 +00:00
|
|
|
lstrcpynW( longpath, shortpath, longlen );
|
|
|
|
return wcslen(longpath);
|
|
|
|
}
|
2008-05-27 10:53:23 +00:00
|
|
|
unixabsolute = (shortpath[0] == '/');
|
2005-03-15 19:40:22 +00:00
|
|
|
/* check for drive letter */
|
|
|
|
if (!unixabsolute && shortpath[1] == ':' )
|
|
|
|
{
|
|
|
|
tmplongpath[0] = shortpath[0];
|
|
|
|
tmplongpath[1] = ':';
|
|
|
|
lp = sp = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (shortpath[sp])
|
|
|
|
{
|
|
|
|
/* check for path delimiters and reproduce them */
|
|
|
|
if (shortpath[sp] == '\\' || shortpath[sp] == '/')
|
|
|
|
{
|
|
|
|
if (!lp || tmplongpath[lp-1] != '\\')
|
|
|
|
{
|
|
|
|
/* strip double "\\" */
|
|
|
|
tmplongpath[lp++] = '\\';
|
|
|
|
}
|
|
|
|
tmplongpath[lp] = 0; /* terminate string */
|
|
|
|
sp++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = shortpath + sp;
|
|
|
|
if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\\'))
|
|
|
|
{
|
|
|
|
tmplongpath[lp++] = *p++;
|
|
|
|
tmplongpath[lp++] = *p++;
|
|
|
|
}
|
|
|
|
for (; *p && *p != '/' && *p != '\\'; p++);
|
|
|
|
tmplen = p - (shortpath + sp);
|
|
|
|
lstrcpynW(tmplongpath + lp, shortpath + sp, tmplen + 1);
|
|
|
|
/* Check if the file exists and use the existing file name */
|
|
|
|
goit = FindFirstFileW(tmplongpath, &wfd);
|
|
|
|
if (goit == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("not found %s!\n", tmplongpath);
|
2005-03-15 19:40:22 +00:00
|
|
|
SetLastError ( ERROR_FILE_NOT_FOUND );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
FindClose(goit);
|
|
|
|
wcscpy(tmplongpath + lp, wfd.cFileName);
|
|
|
|
lp += wcslen(tmplongpath + lp);
|
|
|
|
sp += tmplen;
|
|
|
|
}
|
|
|
|
tmplen = wcslen(shortpath) - 1;
|
|
|
|
if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\\') &&
|
|
|
|
(tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\\'))
|
|
|
|
tmplongpath[lp++] = shortpath[tmplen];
|
|
|
|
tmplongpath[lp] = 0;
|
|
|
|
|
|
|
|
tmplen = wcslen(tmplongpath) + 1;
|
|
|
|
if (tmplen <= longlen)
|
|
|
|
{
|
|
|
|
wcscpy(longpath, tmplongpath);
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("returning %s\n", longpath);
|
2005-03-15 19:40:22 +00:00
|
|
|
tmplen--; /* length without 0 */
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmplen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* GetLongPathNameA (KERNEL32.@)
|
|
|
|
*/
|
2008-11-30 11:42:05 +00:00
|
|
|
DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen )
|
2005-03-15 19:40:22 +00:00
|
|
|
{
|
|
|
|
WCHAR *shortpathW;
|
|
|
|
WCHAR longpathW[MAX_PATH];
|
|
|
|
DWORD ret;
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("GetLongPathNameA %s, %i\n",shortpath,longlen );
|
2005-03-15 19:40:22 +00:00
|
|
|
|
|
|
|
if (!(shortpathW = FilenameA2W( shortpath, FALSE )))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = GetLongPathNameW(shortpathW, longpathW, MAX_PATH);
|
|
|
|
|
|
|
|
if (!ret) return 0;
|
|
|
|
if (ret > MAX_PATH)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2005-03-15 19:40:22 +00:00
|
|
|
return FilenameW2A_FitOrFail(longpath, longlen, longpathW, ret+1 );
|
2005-02-12 17:15:04 +00:00
|
|
|
}
|
|
|
|
|
2000-02-18 00:51:03 +00:00
|
|
|
/* EOF */
|