mirror of
https://github.com/reactos/reactos.git
synced 2024-07-13 16:15:05 +00:00
[NDK]: Add RtlReleaseRelativeName.
[RTL]: Re-implement RtlDosSearchPath_U using new path functions from past commits. Uses correct behavior with RtlDoesFileExists (for relative paths, return success when file is locked -- for absolute paths, do not!). Also uses a more optimized path loop that does not alloc/realloc/free heap continously (only one heap allocation is used). svn path=/trunk/; revision=52699
This commit is contained in:
parent
6195434c6b
commit
3aab9ff5f6
|
@ -2412,6 +2412,12 @@ RtlQueryEnvironmentVariable_U(
|
||||||
PUNICODE_STRING Value
|
PUNICODE_STRING Value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
RtlReleaseRelativeName(
|
||||||
|
IN PRTL_RELATIVE_NAME_U RelativeName
|
||||||
|
);
|
||||||
|
|
||||||
NTSYSAPI
|
NTSYSAPI
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -38,101 +38,115 @@ const UNICODE_STRING RtlpDosCONDevice = RTL_CONSTANT_STRING(L"CON");
|
||||||
const UNICODE_STRING RtlpDosSlashCONDevice = RTL_CONSTANT_STRING(L"\\\\.\\CON");
|
const UNICODE_STRING RtlpDosSlashCONDevice = RTL_CONSTANT_STRING(L"\\\\.\\CON");
|
||||||
const UNICODE_STRING RtlpDosNULDevice = RTL_CONSTANT_STRING(L"NUL");
|
const UNICODE_STRING RtlpDosNULDevice = RTL_CONSTANT_STRING(L"NUL");
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
/*
|
BOOLEAN
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
VOID
|
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
|
RtlDoesFileExists_UstrEx(IN PCUNICODE_STRING FileName,
|
||||||
|
IN BOOLEAN SucceedIfBusy)
|
||||||
{
|
{
|
||||||
/* Check if a directory reference was grabbed */
|
BOOLEAN Result;
|
||||||
if (RelativeName->CurDirRef)
|
RTL_RELATIVE_NAME_U RelativeName;
|
||||||
|
UNICODE_STRING NtPathName;
|
||||||
|
PVOID Buffer;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
NTSTATUS Status;
|
||||||
|
FILE_BASIC_INFORMATION BasicInformation;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Get the NT Path */
|
||||||
|
Result = RtlDosPathNameToRelativeNtPathName_Ustr(FileName,
|
||||||
|
&NtPathName,
|
||||||
|
NULL,
|
||||||
|
&RelativeName);
|
||||||
|
#else
|
||||||
|
/* FIXME: Use the old API for now */
|
||||||
|
Result = RtlDosPathNameToNtPathName_U(FileName->Buffer,
|
||||||
|
&NtPathName,
|
||||||
|
NULL,
|
||||||
|
&RelativeName);
|
||||||
|
#endif
|
||||||
|
if (!Result) return FALSE;
|
||||||
|
|
||||||
|
/* Save the buffer */
|
||||||
|
Buffer = NtPathName.Buffer;
|
||||||
|
|
||||||
|
/* Check if we have a relative name */
|
||||||
|
if (RelativeName.RelativeName.Length)
|
||||||
{
|
{
|
||||||
/* FIXME: Not yet supported */
|
/* Use it */
|
||||||
UNIMPLEMENTED;
|
NtPathName = RelativeName.RelativeName;
|
||||||
RelativeName->CurDirRef = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
RtlGetLongestNtPathLength(VOID)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The longest NT path is a DOS path that actually sits on a UNC path (ie:
|
|
||||||
* a mapped network drive), which is accessed through the DOS Global?? path.
|
|
||||||
* This is, and has always been equal to, 269 characters, except in Wine
|
|
||||||
* which claims this is 277. Go figure.
|
|
||||||
*/
|
|
||||||
return (MAX_PATH + _unc.Length + sizeof(ANSI_NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
RtlDetermineDosPathNameType_U(IN PCWSTR Path)
|
|
||||||
{
|
|
||||||
DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
|
|
||||||
ASSERT(Path != NULL);
|
|
||||||
|
|
||||||
/* Unlike the newer RtlDetermineDosPathNameType_U we assume 4 characters */
|
|
||||||
if (IS_PATH_SEPARATOR(Path[0]))
|
|
||||||
{
|
|
||||||
if (!IS_PATH_SEPARATOR(Path[1])) return RtlPathTypeRooted; /* \x */
|
|
||||||
if ((Path[2] != L'.') && (Path[2] != L'?')) return RtlPathTypeUncAbsolute;/* \\x */
|
|
||||||
if (IS_PATH_SEPARATOR(Path[3])) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
|
|
||||||
if (Path[3]) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
|
|
||||||
return RtlPathTypeRootLocalDevice; /* \\. or \\? */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(Path[0]) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */
|
/* Otherwise ignore it */
|
||||||
if (IS_PATH_SEPARATOR(Path[2])) return RtlPathTypeDriveAbsolute; /* x:\ */
|
RelativeName.ContainingDirectory = NULL;
|
||||||
return RtlPathTypeDriveRelative; /* x: */
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/* Initialize the object attributes */
|
||||||
* @implemented
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
*/
|
&NtPathName,
|
||||||
RTL_PATH_TYPE
|
OBJ_CASE_INSENSITIVE,
|
||||||
NTAPI
|
RelativeName.ContainingDirectory,
|
||||||
RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
|
NULL);
|
||||||
{
|
|
||||||
PWCHAR Path = PathString->Buffer;
|
|
||||||
ULONG Chars = PathString->Length / sizeof(WCHAR);
|
|
||||||
|
|
||||||
/*
|
/* Query the attributes and free the buffer now */
|
||||||
* The algorithm is similar to RtlDetermineDosPathNameType_U but here we
|
Status = ZwQueryAttributesFile(&ObjectAttributes, &BasicInformation);
|
||||||
* actually check for the path length before touching the characters
|
RtlReleaseRelativeName(&RelativeName);
|
||||||
*/
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
||||||
if ((Chars < 1) || (IS_PATH_SEPARATOR(Path[0])))
|
|
||||||
|
/* Check if we failed */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted; /* \x */
|
/* Check if we failed because the file is in use */
|
||||||
if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x */
|
if ((Status == STATUS_SHARING_VIOLATION) ||
|
||||||
if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
|
(Status == STATUS_ACCESS_DENIED))
|
||||||
if (Chars != 3) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
|
{
|
||||||
return RtlPathTypeRootLocalDevice; /* \\. or \\? */
|
/* Check if the caller wants this to be considered OK */
|
||||||
|
Result = SucceedIfBusy ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* A failure because the file didn't exist */
|
||||||
|
Result = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((Chars < 2) || (!(Path[0]) || (Path[1] != L':'))) return RtlPathTypeRelative; /* x */
|
/* The file exists */
|
||||||
if ((Chars < 3) || (IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveAbsolute; /* x:\ */
|
Result = TRUE;
|
||||||
return RtlPathTypeDriveRelative; /* x: */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the result */
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
RtlDoesFileExists_UStr(IN PUNICODE_STRING FileName)
|
||||||
|
{
|
||||||
|
/* Call the updated API */
|
||||||
|
return RtlDoesFileExists_UstrEx(FileName, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
RtlDoesFileExists_UEx(IN PCWSTR FileName,
|
||||||
|
IN BOOLEAN SucceedIfBusy)
|
||||||
|
{
|
||||||
|
UNICODE_STRING NameString;
|
||||||
|
|
||||||
|
/* Create the unicode name*/
|
||||||
|
if (NT_SUCCESS(RtlInitUnicodeStringEx(&NameString, FileName)))
|
||||||
|
{
|
||||||
|
/* Call the unicode function */
|
||||||
|
return RtlDoesFileExists_UstrEx(&NameString, SucceedIfBusy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail */
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
ULONG
|
ULONG
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlIsDosDeviceName_Ustr(IN PUNICODE_STRING PathString)
|
RtlIsDosDeviceName_Ustr(IN PUNICODE_STRING PathString)
|
||||||
|
@ -286,6 +300,94 @@ RtlIsDosDeviceName_Ustr(IN PUNICODE_STRING PathString)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTL_PATH_TYPE
|
||||||
|
NTAPI
|
||||||
|
RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString)
|
||||||
|
{
|
||||||
|
PWCHAR Path = PathString->Buffer;
|
||||||
|
ULONG Chars = PathString->Length / sizeof(WCHAR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The algorithm is similar to RtlDetermineDosPathNameType_U but here we
|
||||||
|
* actually check for the path length before touching the characters
|
||||||
|
*/
|
||||||
|
if ((Chars < 1) || (IS_PATH_SEPARATOR(Path[0])))
|
||||||
|
{
|
||||||
|
if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted; /* \x */
|
||||||
|
if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x */
|
||||||
|
if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
|
||||||
|
if (Chars != 3) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
|
||||||
|
return RtlPathTypeRootLocalDevice; /* \\. or \\? */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((Chars < 2) || (!(Path[0]) || (Path[1] != L':'))) return RtlPathTypeRelative; /* x */
|
||||||
|
if ((Chars < 3) || (IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveAbsolute; /* x:\ */
|
||||||
|
return RtlPathTypeDriveRelative; /* x: */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
RtlReleaseRelativeName(IN PRTL_RELATIVE_NAME_U RelativeName)
|
||||||
|
{
|
||||||
|
/* Check if a directory reference was grabbed */
|
||||||
|
if (RelativeName->CurDirRef)
|
||||||
|
{
|
||||||
|
/* FIXME: Not yet supported */
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
RelativeName->CurDirRef = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
ULONG
|
||||||
|
NTAPI
|
||||||
|
RtlGetLongestNtPathLength(VOID)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The longest NT path is a DOS path that actually sits on a UNC path (ie:
|
||||||
|
* a mapped network drive), which is accessed through the DOS Global?? path.
|
||||||
|
* This is, and has always been equal to, 269 characters, except in Wine
|
||||||
|
* which claims this is 277. Go figure.
|
||||||
|
*/
|
||||||
|
return (MAX_PATH + _unc.Length + sizeof(ANSI_NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
ULONG
|
||||||
|
NTAPI
|
||||||
|
RtlDetermineDosPathNameType_U(IN PCWSTR Path)
|
||||||
|
{
|
||||||
|
DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
|
||||||
|
ASSERT(Path != NULL);
|
||||||
|
|
||||||
|
/* Unlike the newer RtlDetermineDosPathNameType_U we assume 4 characters */
|
||||||
|
if (IS_PATH_SEPARATOR(Path[0]))
|
||||||
|
{
|
||||||
|
if (!IS_PATH_SEPARATOR(Path[1])) return RtlPathTypeRooted; /* \x */
|
||||||
|
if ((Path[2] != L'.') && (Path[2] != L'?')) return RtlPathTypeUncAbsolute;/* \\x */
|
||||||
|
if (IS_PATH_SEPARATOR(Path[3])) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */
|
||||||
|
if (Path[3]) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */
|
||||||
|
return RtlPathTypeRootLocalDevice; /* \\. or \\? */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(Path[0]) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */
|
||||||
|
if (IS_PATH_SEPARATOR(Path[2])) return RtlPathTypeDriveAbsolute; /* x:\ */
|
||||||
|
return RtlPathTypeDriveRelative; /* x: */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
@ -295,12 +397,12 @@ RtlIsDosDeviceName_U(IN PWSTR Path)
|
||||||
{
|
{
|
||||||
UNICODE_STRING PathString;
|
UNICODE_STRING PathString;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
/* Build the string */
|
/* Build the string */
|
||||||
Status = RtlInitUnicodeStringEx(&PathString, Path);
|
Status = RtlInitUnicodeStringEx(&PathString, Path);
|
||||||
if (!NT_SUCCESS(Status)) return 0;
|
if (!NT_SUCCESS(Status)) return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 0 if name is not valid DOS device name, or DWORD with
|
* Returns 0 if name is not valid DOS device name, or DWORD with
|
||||||
* offset in bytes to DOS device name from beginning of buffer in high word
|
* offset in bytes to DOS device name from beginning of buffer in high word
|
||||||
* and size in bytes of DOS device name in low word
|
* and size in bytes of DOS device name in low word
|
||||||
|
@ -973,196 +1075,154 @@ RtlDosPathNameToNtPathName_U(IN PCWSTR DosPathName,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
/******************************************************************
|
|
||||||
* RtlDosSearchPath_U
|
|
||||||
*
|
|
||||||
* Searches a file of name 'name' into a ';' separated list of paths
|
|
||||||
* (stored in paths)
|
|
||||||
* Doesn't seem to search elsewhere than the paths list
|
|
||||||
* Stores the result in buffer (file_part will point to the position
|
|
||||||
* of the file name in the buffer)
|
|
||||||
* FIXME:
|
|
||||||
* - how long shall the paths be ??? (MAX_PATH or larger with \\?\ constructs ???)
|
|
||||||
*/
|
|
||||||
ULONG
|
ULONG
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlDosSearchPath_U(PCWSTR paths,
|
RtlDosSearchPath_U(IN PCWSTR Path,
|
||||||
PCWSTR search,
|
IN PCWSTR FileName,
|
||||||
PCWSTR ext,
|
IN PCWSTR Extension,
|
||||||
ULONG buffer_size,
|
IN ULONG Size,
|
||||||
PWSTR buffer,
|
IN PWSTR Buffer,
|
||||||
PWSTR* file_part)
|
OUT PWSTR *PartName)
|
||||||
{
|
{
|
||||||
RTL_PATH_TYPE type = RtlDetermineDosPathNameType_U(search);
|
|
||||||
ULONG len = 0;
|
|
||||||
|
|
||||||
if (type == RtlPathTypeRelative)
|
|
||||||
{
|
|
||||||
ULONG allocated = 0, needed, filelen;
|
|
||||||
WCHAR *name = NULL;
|
|
||||||
|
|
||||||
filelen = 1 /* for \ */ + wcslen(search) + 1 /* \0 */;
|
|
||||||
|
|
||||||
/* Windows only checks for '.' without worrying about path components */
|
|
||||||
if (wcschr( search, '.' )) ext = NULL;
|
|
||||||
if (ext != NULL) filelen += wcslen(ext);
|
|
||||||
|
|
||||||
while (*paths)
|
|
||||||
{
|
|
||||||
LPCWSTR ptr;
|
|
||||||
|
|
||||||
for (needed = 0, ptr = paths; *ptr != 0 && *ptr++ != ';'; needed++);
|
|
||||||
if (needed + filelen > allocated)
|
|
||||||
{
|
|
||||||
if (!name) name = RtlAllocateHeap(RtlGetProcessHeap(), 0,
|
|
||||||
(needed + filelen) * sizeof(WCHAR));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WCHAR *newname = RtlReAllocateHeap(RtlGetProcessHeap(), 0, name,
|
|
||||||
(needed + filelen) * sizeof(WCHAR));
|
|
||||||
if (!newname) RtlFreeHeap(RtlGetProcessHeap(), 0, name);
|
|
||||||
name = newname;
|
|
||||||
}
|
|
||||||
if (!name) return 0;
|
|
||||||
allocated = needed + filelen;
|
|
||||||
}
|
|
||||||
memmove(name, paths, needed * sizeof(WCHAR));
|
|
||||||
/* append '\\' if none is present */
|
|
||||||
if (needed > 0 && name[needed - 1] != '\\') name[needed++] = '\\';
|
|
||||||
wcscpy(&name[needed], search);
|
|
||||||
if (ext) wcscat(&name[needed], ext);
|
|
||||||
if (RtlDoesFileExists_U(name))
|
|
||||||
{
|
|
||||||
len = RtlGetFullPathName_U(name, buffer_size, buffer, file_part);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
paths = ptr;
|
|
||||||
}
|
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, name);
|
|
||||||
}
|
|
||||||
else if (RtlDoesFileExists_U(search))
|
|
||||||
{
|
|
||||||
len = RtlGetFullPathName_U(search, buffer_size, buffer, file_part);
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
RtlDoesFileExists_UstrEx(IN PCUNICODE_STRING FileName,
|
|
||||||
IN BOOLEAN SucceedIfBusy)
|
|
||||||
{
|
|
||||||
BOOLEAN Result;
|
|
||||||
RTL_RELATIVE_NAME_U RelativeName;
|
|
||||||
UNICODE_STRING NtPathName;
|
|
||||||
PVOID Buffer;
|
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
FILE_BASIC_INFORMATION BasicInformation;
|
WCHAR c;
|
||||||
|
ULONG ExtensionLength, Length, FileNameLength, PathLength;
|
||||||
|
UNICODE_STRING TempString;
|
||||||
|
PWCHAR NewBuffer, BufferStart;
|
||||||
|
|
||||||
#if 0
|
/* Check if this is an absolute path */
|
||||||
/* Get the NT Path */
|
if (RtlDetermineDosPathNameType_U(FileName) != RtlPathTypeRelative)
|
||||||
Result = RtlDosPathNameToRelativeNtPathName_Ustr(FileName,
|
|
||||||
&NtPathName,
|
|
||||||
NULL,
|
|
||||||
&RelativeName);
|
|
||||||
#else
|
|
||||||
/* FIXME: Use the old API for now */
|
|
||||||
Result = RtlDosPathNameToNtPathName_U(FileName->Buffer,
|
|
||||||
&NtPathName,
|
|
||||||
NULL,
|
|
||||||
&RelativeName);
|
|
||||||
#endif
|
|
||||||
if (!Result) return FALSE;
|
|
||||||
|
|
||||||
/* Save the buffer */
|
|
||||||
Buffer = NtPathName.Buffer;
|
|
||||||
|
|
||||||
/* Check if we have a relative name */
|
|
||||||
if (RelativeName.RelativeName.Length)
|
|
||||||
{
|
{
|
||||||
/* Use it */
|
/* Check if the file exists */
|
||||||
NtPathName = RelativeName.RelativeName;
|
if (RtlDoesFileExists_UEx(FileName, TRUE))
|
||||||
|
{
|
||||||
|
/* Get the full name, which does the DOS lookup */
|
||||||
|
return RtlGetFullPathName_U(FileName, Size, Buffer, PartName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Doesn't exist, so fail */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan the filename */
|
||||||
|
c = *FileName;
|
||||||
|
while (c)
|
||||||
|
{
|
||||||
|
/* Looking for an extension */
|
||||||
|
if (c == '.')
|
||||||
|
{
|
||||||
|
/* No extension string needed -- it's part of the filename */
|
||||||
|
Extension = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next character */
|
||||||
|
c = *++FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do we have an extension? */
|
||||||
|
if (!Extension)
|
||||||
|
{
|
||||||
|
/* Nope, don't worry about one */
|
||||||
|
ExtensionLength = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Otherwise ignore it */
|
/* Build a temporary string to get the extension length */
|
||||||
RelativeName.ContainingDirectory = NULL;
|
Status = RtlInitUnicodeStringEx(&TempString, Extension);
|
||||||
|
if (!NT_SUCCESS(Status)) return 0;
|
||||||
|
ExtensionLength = TempString.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the object attributes */
|
/* Build a temporary string to get the path length */
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
Status = RtlInitUnicodeStringEx(&TempString, Path);
|
||||||
&NtPathName,
|
if (!NT_SUCCESS(Status)) return 0;
|
||||||
OBJ_CASE_INSENSITIVE,
|
PathLength = TempString.Length;
|
||||||
RelativeName.ContainingDirectory,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* Query the attributes and free the buffer now */
|
/* Build a temporary string to get the filename length */
|
||||||
Status = ZwQueryAttributesFile(&ObjectAttributes, &BasicInformation);
|
Status = RtlInitUnicodeStringEx(&TempString, FileName);
|
||||||
RtlReleaseRelativeName(&RelativeName);
|
if (!NT_SUCCESS(Status)) return 0;
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
FileNameLength = TempString.Length;
|
||||||
|
|
||||||
/* Check if we failed */
|
/* Allocate the buffer for the new string name */
|
||||||
if (!NT_SUCCESS(Status))
|
NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
|
||||||
|
0,
|
||||||
|
FileNameLength +
|
||||||
|
ExtensionLength +
|
||||||
|
PathLength +
|
||||||
|
3 * sizeof(WCHAR));
|
||||||
|
if (!NewBuffer)
|
||||||
{
|
{
|
||||||
/* Check if we failed because the file is in use */
|
/* Fail the call */
|
||||||
if ((Status == STATUS_SHARING_VIOLATION) ||
|
DbgPrint("%s: Failing due to out of memory (RtlAllocateHeap failure)\n",
|
||||||
(Status == STATUS_ACCESS_DENIED))
|
__FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final loop to build the path */
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Check if we have a valid character */
|
||||||
|
c = *Path;
|
||||||
|
BufferStart = NewBuffer;
|
||||||
|
if (c)
|
||||||
{
|
{
|
||||||
/* Check if the caller wants this to be considered OK */
|
/* Loop as long as there's no semicolon */
|
||||||
Result = SucceedIfBusy ? TRUE : FALSE;
|
while (c != ';')
|
||||||
|
{
|
||||||
|
/* Copy the next character */
|
||||||
|
*BufferStart++ = c;
|
||||||
|
c = *++Path;
|
||||||
|
if (!c) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We found a semi-colon, to stop path processing on this loop */
|
||||||
|
if (c == ';') ++Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a terminating slash if needed */
|
||||||
|
if ((BufferStart != NewBuffer) && (BufferStart[-1] != '\\'))
|
||||||
|
{
|
||||||
|
*BufferStart++ = '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bail out if we reached the end */
|
||||||
|
if (!c) Path = NULL;
|
||||||
|
|
||||||
|
/* Copy the file name and check if an extension is needed */
|
||||||
|
RtlCopyMemory(BufferStart, FileName, FileNameLength);
|
||||||
|
if (ExtensionLength)
|
||||||
|
{
|
||||||
|
/* Copy the extension too */
|
||||||
|
RtlCopyMemory((PCHAR)BufferStart + FileNameLength,
|
||||||
|
Extension,
|
||||||
|
ExtensionLength + sizeof(WCHAR));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* A failure because the file didn't exist */
|
/* Just NULL-terminate */
|
||||||
Result = FALSE;
|
*(PWCHAR)((PCHAR)BufferStart + FileNameLength) = UNICODE_NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
/* Now, does this file exist? */
|
||||||
{
|
if (RtlDoesFileExists_UEx(NewBuffer, FALSE))
|
||||||
/* The file exists */
|
{
|
||||||
Result = TRUE;
|
/* Call the full-path API to get the length */
|
||||||
|
Length = RtlGetFullPathName_U(NewBuffer, Size, Buffer, PartName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we got here, path doesn't exist, so fail the call */
|
||||||
|
Length = 0;
|
||||||
|
if (!Path) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the result */
|
/* Free the allocation and return the length */
|
||||||
return Result;
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
|
||||||
}
|
return Length;
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
RtlDoesFileExists_UStr(IN PUNICODE_STRING FileName)
|
|
||||||
{
|
|
||||||
/* Call the updated API */
|
|
||||||
return RtlDoesFileExists_UstrEx(FileName, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
RtlDoesFileExists_UEx(IN PCWSTR FileName,
|
|
||||||
IN BOOLEAN SucceedIfBusy)
|
|
||||||
{
|
|
||||||
UNICODE_STRING NameString;
|
|
||||||
|
|
||||||
/* Create the unicode name*/
|
|
||||||
if (NT_SUCCESS(RtlInitUnicodeStringEx(&NameString, FileName)))
|
|
||||||
{
|
|
||||||
/* Call the unicode function */
|
|
||||||
return RtlDoesFileExists_UstrEx(&NameString, SucceedIfBusy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fail */
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1190,6 +1250,9 @@ RtlDosPathNameToRelativeNtPathName_U(PVOID Unknown1,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS NTAPI
|
||||||
RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
|
RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
|
||||||
{
|
{
|
||||||
|
@ -1197,6 +1260,9 @@ RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS NTAPI
|
||||||
RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
|
RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue