3475 lines
97 KiB
Plaintext
3475 lines
97 KiB
Plaintext
|
/*++
|
||
|
|
||
|
Copyright (c) 1990 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
curdir.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Current directory support
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Mark Lucovsky (markl) 10-Oct-1990
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "ntos2.h"
|
||
|
#include "ntrtl.h"
|
||
|
#include "nturtl.h"
|
||
|
#include "string.h"
|
||
|
#include "ctype.h"
|
||
|
|
||
|
#define IS_PATH_SEPARATOR(ch) ((ch == '\\') || (ch == '/'))
|
||
|
#define IS_DOT(s) ( s[0] == '.' && ( IS_PATH_SEPARATOR(s[1]) || s[1] == '\0') )
|
||
|
#define IS_DOT_DOT(s) ( s[0] == '.' && s[1] == '.' && ( IS_PATH_SEPARATOR(s[2]) || s[2] == '\0') )
|
||
|
|
||
|
#define IS_PATH_SEPARATOR_U(ch) ((ch == (WCHAR)'\\') || (ch == (WCHAR)'/'))
|
||
|
#define IS_DOT_U(s) ( s[0] == (WCHAR)'.' && ( IS_PATH_SEPARATOR_U(s[1]) || s[1] == UNICODE_NULL) )
|
||
|
#define IS_DOT_DOT_U(s) ( s[0] == (WCHAR)'.' && s[1] == (WCHAR)'.' && ( IS_PATH_SEPARATOR_U(s[2]) || s[2] == UNICODE_NULL) )
|
||
|
|
||
|
ULONG RtlpFilePartOffset;
|
||
|
STRING RtlpLastFullDosPath;
|
||
|
STRING RtlpLastDosPath;
|
||
|
CHAR RtlpLastFullDosPathBuffer[DOS_MAX_PATH_LENGTH];
|
||
|
CHAR RtlpLastDosPathBuffer[DOS_MAX_PATH_LENGTH];
|
||
|
ULONG RtlpCacheHit;
|
||
|
ULONG RtlpCacheMiss;
|
||
|
|
||
|
#define NUMBER_OF_DOS_DEVICE_NAMES 5
|
||
|
#define DOS_DEVICE_LPT 0
|
||
|
#define DOS_DEVICE_COM 1
|
||
|
#define DOS_DEVICE_PRN 2
|
||
|
#define DOS_DEVICE_AUX 3
|
||
|
#define DOS_DEVICE_NUL 4
|
||
|
UNICODE_STRING RtlpDosDevices[NUMBER_OF_DOS_DEVICE_NAMES];
|
||
|
UNICODE_STRING RtlpSlashSlashDot;
|
||
|
ULONG RtlpLongestPrefix;
|
||
|
UNICODE_STRING RtlpDosDevicesPrefix;
|
||
|
UNICODE_STRING RtlpDosDevicesUncPrefix;
|
||
|
|
||
|
#define UNICODE_CHECK
|
||
|
|
||
|
#ifdef UNICODE_CHECK
|
||
|
VOID
|
||
|
CheckDetermineDosPathNameType(
|
||
|
IN PSZ DosFileName,
|
||
|
IN RTL_PATH_TYPE PathType
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
CheckIsDosDeviceName(
|
||
|
IN PSZ DosFileName,
|
||
|
IN ULONG Length
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
CheckFullPathName(
|
||
|
PSZ lpFileName,
|
||
|
ULONG nBufferLength,
|
||
|
PSZ lpBuffer,
|
||
|
PSZ *lpFilePart,
|
||
|
ULONG ReturnedBufferLength
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
CheckDosPathNameToNtPathName(
|
||
|
PSZ DosFileName,
|
||
|
PSTRING NtFileName,
|
||
|
PSZ *FilePart OPTIONAL,
|
||
|
PRTL_RELATIVE_NAME RelativeName OPTIONAL
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
CheckDosFileExist(
|
||
|
PSZ FileName,
|
||
|
BOOLEAN ReturnValue
|
||
|
);
|
||
|
|
||
|
#endif // UNICODE_CHECK
|
||
|
|
||
|
VOID
|
||
|
RtlpCurdirInit()
|
||
|
{
|
||
|
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
RtlpFilePartOffset = 0;
|
||
|
RtlpLastFullDosPath.Length = 0;
|
||
|
RtlpLastFullDosPath.MaximumLength = DOS_MAX_PATH_LENGTH-1;
|
||
|
RtlpLastFullDosPath.Buffer = RtlpLastFullDosPathBuffer;
|
||
|
RtlpLastDosPath.Length = 0;
|
||
|
RtlpLastDosPath.MaximumLength = DOS_MAX_PATH_LENGTH-1;
|
||
|
RtlpLastDosPath.Buffer = RtlpLastDosPathBuffer;
|
||
|
RtlpCacheHit = 0;
|
||
|
RtlpCacheMiss = 0;
|
||
|
|
||
|
//
|
||
|
// Initialize the built in dos device names.
|
||
|
//
|
||
|
|
||
|
RtlInitAnsiString(&AnsiString,"LPT");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevices[ DOS_DEVICE_LPT ] = UnicodeString;
|
||
|
RtlInitAnsiString(&AnsiString,"COM");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevices[ DOS_DEVICE_COM ] = UnicodeString;
|
||
|
RtlInitAnsiString(&AnsiString,"PRN");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevices[ DOS_DEVICE_PRN ] = UnicodeString;
|
||
|
RtlInitAnsiString(&AnsiString,"AUX");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevices[ DOS_DEVICE_AUX ] = UnicodeString;
|
||
|
RtlInitAnsiString(&AnsiString,"NUL");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevices[ DOS_DEVICE_NUL ] = UnicodeString;
|
||
|
|
||
|
RtlInitAnsiString(&AnsiString,"\\\\.\\");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpSlashSlashDot = UnicodeString;
|
||
|
|
||
|
RtlInitAnsiString(&AnsiString,"\\DosDevices\\");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevicesPrefix = UnicodeString;
|
||
|
|
||
|
RtlInitAnsiString(&AnsiString,"\\DosDevices\\UNC\\");
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
RtlpDosDevicesUncPrefix = UnicodeString;
|
||
|
RtlpLongestPrefix = RtlpDosDevicesUncPrefix.Length;
|
||
|
}
|
||
|
|
||
|
#ifdef OLD
|
||
|
|
||
|
RTL_PATH_TYPE
|
||
|
RtlDetermineDosPathNameType(
|
||
|
IN PSZ DosFileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function examines the Dos format file name and determines the
|
||
|
type of file name (i.e. UNC, DriveAbsolute, Current Directory
|
||
|
rooted, or Relative.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos format file name whose type is to be
|
||
|
determined.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
RtlPathTypeUnknown - The path type can not be determined
|
||
|
|
||
|
RtlPathTypeUncAbsolute - The path specifies a Unc absolute path
|
||
|
in the format \\server-name\sharename\rest-of-path
|
||
|
|
||
|
RtlPathTypeLocalDevice - The path specifies a local device in the format
|
||
|
\\.\rest-of-path this can be used for any device where the nt and
|
||
|
Win32 names are the same. For example mailslots.
|
||
|
|
||
|
RtlPathTypeRootLocalDevice - The path specifies the root of the local
|
||
|
devices in the format \\.
|
||
|
|
||
|
RtlPathTypeDriveAbsolute - The path specifies a drive letter absolute
|
||
|
path in the form drive:\rest-of-path
|
||
|
|
||
|
RtlPathTypeDriveRelative - The path specifies a drive letter relative
|
||
|
path in the form drive:rest-of-path
|
||
|
|
||
|
RtlPathTypeRooted - The path is rooted relative to the current disk
|
||
|
designator (either Unc disk, or drive). The form is \rest-of-path.
|
||
|
|
||
|
RtlPathTypeRelative - The path is relative (i.e. not absolute or rooted).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
RTL_PATH_TYPE ReturnValue;
|
||
|
|
||
|
if ( IS_PATH_SEPARATOR(*DosFileName) ) {
|
||
|
if ( IS_PATH_SEPARATOR(*(DosFileName+1)) ) {
|
||
|
if ( DosFileName[2] == '.' ) {
|
||
|
if ( IS_PATH_SEPARATOR(*(DosFileName+3)) ){
|
||
|
ReturnValue = RtlPathTypeLocalDevice;
|
||
|
}
|
||
|
else if ( (*(DosFileName+3)) == '\0' ){
|
||
|
ReturnValue = RtlPathTypeRootLocalDevice;
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeUncAbsolute;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeUncAbsolute;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeRooted;
|
||
|
}
|
||
|
}
|
||
|
else if (*(DosFileName+1)==':') {
|
||
|
if (IS_PATH_SEPARATOR(*(DosFileName+2))) {
|
||
|
ReturnValue = RtlPathTypeDriveAbsolute;
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeDriveRelative;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeRelative;
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE_CHECK
|
||
|
CheckDetermineDosPathNameType(DosFileName,ReturnValue);
|
||
|
#endif // UNICODE_CHECK
|
||
|
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
RtlIsDosDeviceName(
|
||
|
IN PSZ DosFileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function examines the Dos format file name and determines if it
|
||
|
is a Dos device name (e.g. LPT1, etc.). Valid Dos device names are:
|
||
|
|
||
|
LPTn
|
||
|
COMn
|
||
|
PRN
|
||
|
AUX
|
||
|
NUL
|
||
|
|
||
|
when n is a digit. Trailing colon is ignored if present.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos format file name that is to be examined.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 - Specified Dos file name is not the name of a Dos device.
|
||
|
|
||
|
> 0 - Specified Dos file name is the name of a Dos device and the
|
||
|
return value is the length of the name (excluding any optional
|
||
|
trailing colon).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG n = strlen(DosFileName);
|
||
|
ULONG ReturnLength;
|
||
|
|
||
|
if (n && DosFileName[n-1] == ':') {
|
||
|
n--;
|
||
|
}
|
||
|
ReturnLength = n;
|
||
|
if ( n == 4 && isdigit( DosFileName[3] ) &&
|
||
|
( !strnicmp(DosFileName,"LPT",3) || !strnicmp(DosFileName,"COM",3) )
|
||
|
) {
|
||
|
ReturnLength = n;
|
||
|
}
|
||
|
else
|
||
|
if ( n != 3 ) {
|
||
|
ReturnLength = 0;
|
||
|
}
|
||
|
else
|
||
|
if ( !strnicmp(DosFileName,"PRN",3) ) {
|
||
|
;
|
||
|
}
|
||
|
else
|
||
|
if ( !strnicmp(DosFileName,"AUX",3) ) {
|
||
|
;
|
||
|
}
|
||
|
else
|
||
|
if ( !strnicmp(DosFileName,"NUL",3) ) {
|
||
|
;
|
||
|
}
|
||
|
else {
|
||
|
ReturnLength = 0;
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE_CHECK
|
||
|
CheckIsDosDeviceName(DosFileName,ReturnLength);
|
||
|
#endif // UNICODE_CHECK
|
||
|
|
||
|
return ReturnLength;
|
||
|
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RtlGetFullPathName(
|
||
|
PSZ lpFileName,
|
||
|
ULONG nBufferLength,
|
||
|
PSZ lpBuffer,
|
||
|
PSZ *lpFilePart OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function is used to return a fully qualified pathname
|
||
|
corresponding to the specified filename. It does this by merging
|
||
|
the current drive and directory together with the specified file
|
||
|
name. In addition to this, it calculates the address of the file
|
||
|
name portion of the fully qualified pathname.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpFileName - Supplies the file name of the file whose fully
|
||
|
qualified pathname is to be returned.
|
||
|
|
||
|
nBufferLength - Supplies the length in bytes of the buffer that is
|
||
|
to receive the fully qualified path.
|
||
|
|
||
|
lpBuffer - Returns the fully qualified pathname corresponding to the
|
||
|
specified file.
|
||
|
|
||
|
lpFilePart - Optional parameter that if specified, returns the
|
||
|
address of the last component of the fully qualified pathname.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The return value is the length of the string copied to lpBuffer, not
|
||
|
including the terminating null character. If the return value is
|
||
|
greater than nBufferLength, the return value is the size of the buffer
|
||
|
required to hold the pathname. The return value is zero if the
|
||
|
function failed.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG DeviceNameLength;
|
||
|
ULONG PrefixSourceLength;
|
||
|
LONG PathNameLength;
|
||
|
UCHAR CurDrive, NewDrive;
|
||
|
UCHAR EnvVarNameBuffer[4];
|
||
|
STRING EnvVarName;
|
||
|
PSZ Source,Dest;
|
||
|
STRING Prefix;
|
||
|
PCURDIR CurDir;
|
||
|
ULONG MaximumLength;
|
||
|
STRING FullPath;
|
||
|
ULONG BackupIndex;
|
||
|
RTL_PATH_TYPE PathType;
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN StripTrailingSlash;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return zero if zero length file name specified.
|
||
|
//
|
||
|
|
||
|
PathNameLength = strlen(lpFileName);
|
||
|
if ( PathNameLength == 0 ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if ( lpFileName[PathNameLength-1] == '\\' ) {
|
||
|
StripTrailingSlash = FALSE;
|
||
|
}
|
||
|
else {
|
||
|
StripTrailingSlash = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If pass Dos file name is a Dos device name, then turn it into
|
||
|
// \\.\devicename and return its length.
|
||
|
//
|
||
|
|
||
|
DeviceNameLength = RtlIsDosDeviceName(lpFileName);
|
||
|
if ( DeviceNameLength ) {
|
||
|
PathNameLength = DeviceNameLength + sizeof( "\\\\.\\" ) - 1;
|
||
|
if ( PathNameLength < (LONG)nBufferLength ) {
|
||
|
strcpy(lpBuffer,"\\\\.\\");
|
||
|
strncat(lpBuffer,lpFileName,DeviceNameLength);
|
||
|
return PathNameLength;
|
||
|
}
|
||
|
else {
|
||
|
return PathNameLength+1;
|
||
|
}
|
||
|
}
|
||
|
try {
|
||
|
RtlAcquirePebLock();
|
||
|
|
||
|
//
|
||
|
// Check the path cache. If the length of the input string
|
||
|
// matches the last string, and the names compare, then it is
|
||
|
// a cache hit.
|
||
|
//
|
||
|
|
||
|
if ( RtlpLastDosPath.Length ) {
|
||
|
if ( (RtlpLastDosPath.Length == PathNameLength &&
|
||
|
!stricmp(RtlpLastDosPath.Buffer,lpFileName)) ||
|
||
|
(RtlpLastFullDosPath.Length == PathNameLength &&
|
||
|
!stricmp(RtlpLastFullDosPath.Buffer,lpFileName)) ) {
|
||
|
|
||
|
//
|
||
|
// Cache Hit
|
||
|
//
|
||
|
|
||
|
RtlpCacheHit++;
|
||
|
if ( RtlpLastFullDosPath.Length <= (LONG)nBufferLength ) {
|
||
|
|
||
|
//
|
||
|
// Return cached copy
|
||
|
//
|
||
|
|
||
|
strcpy(lpBuffer,RtlpLastFullDosPath.Buffer);
|
||
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
||
|
*lpFilePart = lpBuffer + RtlpFilePartOffset;
|
||
|
}
|
||
|
return RtlpLastFullDosPath.Length;
|
||
|
}
|
||
|
else {
|
||
|
return RtlpLastFullDosPath.Length;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
RtlpLastDosPath.Length = 0;
|
||
|
RtlpCacheMiss++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
RtlReleasePebLock();
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Setup output string that points to callers buffer.
|
||
|
//
|
||
|
|
||
|
FullPath.MaximumLength = (USHORT)nBufferLength;
|
||
|
FullPath.Length = 0;
|
||
|
FullPath.Buffer = lpBuffer;
|
||
|
RtlZeroMemory(lpBuffer,nBufferLength);
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the current directory structure.
|
||
|
//
|
||
|
|
||
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Determine the type of Dos Path Name specified.
|
||
|
//
|
||
|
|
||
|
PathType = RtlDetermineDosPathNameType(lpFileName);
|
||
|
|
||
|
//
|
||
|
// Determine the prefix and backup index.
|
||
|
//
|
||
|
// Input Prefix Backup Index
|
||
|
//
|
||
|
// \\ -> \\, end of \\server\share
|
||
|
// \\.\ -> \\.\, 4
|
||
|
// \\. -> \\. 3 (\\.)
|
||
|
// \ -> Drive: from CurDir.DosPath 3 (Drive:\)
|
||
|
// d: -> Drive:\curdir from environment 3 (Drive:\)
|
||
|
// d:\ -> no prefix 3 (Drive:\)
|
||
|
// any -> CurDir.DosPath 3 (Drive:\)
|
||
|
//
|
||
|
|
||
|
try {
|
||
|
RtlAcquirePebLock();
|
||
|
|
||
|
//
|
||
|
// No prefixes yet.
|
||
|
//
|
||
|
|
||
|
Source = lpFileName;
|
||
|
PrefixSourceLength = 0;
|
||
|
Prefix.Length = 0;
|
||
|
Prefix.MaximumLength = 0;
|
||
|
Prefix.Buffer = NULL;
|
||
|
|
||
|
switch (PathType) {
|
||
|
case RtlPathTypeUncAbsolute :
|
||
|
{
|
||
|
PSZ UncPathPointer;
|
||
|
ULONG NumberOfPathSeparators;
|
||
|
|
||
|
//
|
||
|
// We want to scan the supplied path to determine where
|
||
|
// the "share" ends, and set BackupIndex to that point.
|
||
|
//
|
||
|
|
||
|
UncPathPointer = lpFileName + 2;
|
||
|
NumberOfPathSeparators = 0;
|
||
|
while (*UncPathPointer) {
|
||
|
if (IS_PATH_SEPARATOR(*UncPathPointer)) {
|
||
|
|
||
|
NumberOfPathSeparators++;
|
||
|
|
||
|
if (NumberOfPathSeparators == 2) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UncPathPointer++;
|
||
|
|
||
|
}
|
||
|
|
||
|
BackupIndex = UncPathPointer - lpFileName;
|
||
|
|
||
|
//
|
||
|
// Unc name. prefix = \\server\share
|
||
|
//
|
||
|
|
||
|
PrefixSourceLength = BackupIndex;
|
||
|
Source += PrefixSourceLength;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeLocalDevice :
|
||
|
|
||
|
//
|
||
|
// Local device name. prefix = \\.\
|
||
|
//
|
||
|
|
||
|
PrefixSourceLength = 4;
|
||
|
BackupIndex = PrefixSourceLength;
|
||
|
Source += PrefixSourceLength;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRootLocalDevice :
|
||
|
|
||
|
//
|
||
|
// Local Device root. prefix = \\.\
|
||
|
//
|
||
|
|
||
|
PrefixSourceLength = 3;
|
||
|
RtlInitString(&Prefix,"\\");
|
||
|
BackupIndex = PrefixSourceLength + Prefix.Length;
|
||
|
Source += PrefixSourceLength;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeDriveAbsolute :
|
||
|
|
||
|
//
|
||
|
// Dos drive absolute name
|
||
|
//
|
||
|
|
||
|
BackupIndex = 3;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeDriveRelative :
|
||
|
|
||
|
//
|
||
|
// Dos drive relative name
|
||
|
//
|
||
|
|
||
|
CurDrive = (UCHAR)toupper( CurDir->DosPath.Buffer[0] );
|
||
|
NewDrive = (UCHAR)toupper( lpFileName[0] );
|
||
|
if ( CurDrive == NewDrive ) {
|
||
|
Prefix = CurDir->DosPath;
|
||
|
}
|
||
|
else {
|
||
|
EnvVarNameBuffer[0] = '=';
|
||
|
EnvVarNameBuffer[1] = NewDrive;
|
||
|
EnvVarNameBuffer[2] = ':';
|
||
|
EnvVarNameBuffer[3] = '\0';
|
||
|
RtlInitString(&EnvVarName,EnvVarNameBuffer);
|
||
|
|
||
|
Prefix = FullPath;
|
||
|
Status = RtlQueryEnvironmentVariable( NULL,
|
||
|
&EnvVarName,
|
||
|
&Prefix
|
||
|
);
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
|
return Prefix.Length + PathNameLength + 2;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// Otherwise default to root directory of drive
|
||
|
//
|
||
|
|
||
|
EnvVarNameBuffer[0] = NewDrive;
|
||
|
EnvVarNameBuffer[1] = ':';
|
||
|
EnvVarNameBuffer[2] = '\\';
|
||
|
EnvVarNameBuffer[3] = '\0';
|
||
|
RtlInitString(&Prefix,EnvVarNameBuffer);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (Prefix.Length > 3) {
|
||
|
Prefix.Buffer[ Prefix.Length++ ] = '\\';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BackupIndex = 3;
|
||
|
Source += 2;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRooted :
|
||
|
|
||
|
//
|
||
|
// Rooted name. Prefix is drive portion of current directory
|
||
|
//
|
||
|
|
||
|
Prefix = CurDir->DosPath;
|
||
|
Prefix.Length = 2;
|
||
|
BackupIndex = 3;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRelative :
|
||
|
|
||
|
//
|
||
|
// Current drive:directory relative name
|
||
|
//
|
||
|
|
||
|
Prefix = CurDir->DosPath;
|
||
|
BackupIndex = 3;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Maximum length required is the length of the prefix plus
|
||
|
// the length of the specified pathname. If the callers buffer
|
||
|
// is not at least this large, then return an error.
|
||
|
//
|
||
|
|
||
|
MaximumLength = PathNameLength + Prefix.Length + 1;
|
||
|
|
||
|
if ( MaximumLength > nBufferLength ) {
|
||
|
if ( (MaximumLength - nBufferLength != 1) ||
|
||
|
(PathNameLength > 1) ||
|
||
|
(*lpFileName != '.') ) {
|
||
|
return MaximumLength;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PrefixSourceLength || Prefix.Buffer != FullPath.Buffer) {
|
||
|
//
|
||
|
// Copy the prefix from the source string.
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory(FullPath.Buffer,lpFileName,PrefixSourceLength);
|
||
|
FullPath.Length = (USHORT)PrefixSourceLength;
|
||
|
|
||
|
//
|
||
|
// Append any additional prefix
|
||
|
//
|
||
|
|
||
|
RtlAppendStringToString(&FullPath,&Prefix);
|
||
|
}
|
||
|
else {
|
||
|
FullPath.Length = Prefix.Length;
|
||
|
}
|
||
|
|
||
|
Dest = FullPath.Buffer + FullPath.Length;
|
||
|
*Dest = '\0';
|
||
|
|
||
|
while ( *Source != '\0' ) {
|
||
|
switch ( *Source ) {
|
||
|
|
||
|
case '\\' :
|
||
|
case '/' :
|
||
|
|
||
|
//
|
||
|
// collapse multiple "\" characters.
|
||
|
//
|
||
|
|
||
|
if ( *(Dest-1) != '\\' ) {
|
||
|
*Dest++ = '\\';
|
||
|
}
|
||
|
|
||
|
Source++;
|
||
|
break;
|
||
|
|
||
|
case '.' :
|
||
|
|
||
|
//
|
||
|
// Ignore dot in a leading //./
|
||
|
// Eat single dots as in /./
|
||
|
// Double dots back up one level as in /../
|
||
|
// Any other . is just a filename character
|
||
|
//
|
||
|
|
||
|
if ( IS_DOT(Source) ) {
|
||
|
Source++;
|
||
|
if (IS_PATH_SEPARATOR(*Source)) {
|
||
|
Source++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else if ( IS_DOT_DOT(Source) ) {
|
||
|
|
||
|
//
|
||
|
// backup destination string looking for
|
||
|
// a \
|
||
|
//
|
||
|
|
||
|
while (*Dest != '\\') Dest--;
|
||
|
|
||
|
//
|
||
|
// backup to previous component..
|
||
|
// \a\b\c\.. to \a\b
|
||
|
//
|
||
|
|
||
|
do {
|
||
|
|
||
|
//
|
||
|
// If we bump into root prefix, then
|
||
|
// stay at root
|
||
|
//
|
||
|
|
||
|
if ( Dest == FullPath.Buffer + (BackupIndex-1) ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Dest--;
|
||
|
|
||
|
} while (*Dest != '\\');
|
||
|
if ( Dest == FullPath.Buffer + (BackupIndex-1) ) {
|
||
|
Dest++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Advance source past ..
|
||
|
//
|
||
|
|
||
|
Source += 2;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// FALLTHRU
|
||
|
//
|
||
|
|
||
|
default:
|
||
|
|
||
|
//
|
||
|
// Copy the filename. The copy will stop
|
||
|
// on "non-portable" characters. Note that
|
||
|
// null and /,\ will stop the copy. If any
|
||
|
// charcter other than null or /,\ is encountered,
|
||
|
// then the pathname is invalid.
|
||
|
//
|
||
|
|
||
|
while ( *Source && !IS_PATH_SEPARATOR(*Source) ) {
|
||
|
*Dest++ = *Source++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*Dest = '\0';
|
||
|
|
||
|
if ( StripTrailingSlash ) {
|
||
|
if ( Dest > (FullPath.Buffer + BackupIndex ) && *(Dest-1) == '\\' ) {
|
||
|
Dest--;
|
||
|
*Dest = '\0';
|
||
|
}
|
||
|
}
|
||
|
FullPath.Length = (USHORT)Dest - (USHORT)FullPath.Buffer;
|
||
|
|
||
|
//
|
||
|
// Locate the file part...
|
||
|
//
|
||
|
|
||
|
Source = lpBuffer;
|
||
|
Dest = NULL;
|
||
|
|
||
|
while(*Source) {
|
||
|
if ( *Source == '\\' ) {
|
||
|
Dest = Source + 1;
|
||
|
}
|
||
|
Source++;
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT( lpFilePart ) ) {
|
||
|
if ( Dest && *Dest ) {
|
||
|
*lpFilePart = Dest;
|
||
|
}
|
||
|
else {
|
||
|
*lpFilePart = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( Dest && *Dest ) {
|
||
|
RtlpFilePartOffset = Dest - lpBuffer;
|
||
|
}
|
||
|
else {
|
||
|
RtlpFilePartOffset = 0;
|
||
|
}
|
||
|
RtlpLastFullDosPath.Length = FullPath.Length;
|
||
|
RtlMoveMemory(RtlpLastFullDosPath.Buffer,lpBuffer,FullPath.Length+1);
|
||
|
RtlpLastDosPath.Length = PathNameLength;
|
||
|
RtlMoveMemory(RtlpLastDosPath.Buffer,lpFileName,PathNameLength+1);
|
||
|
}
|
||
|
|
||
|
finally {
|
||
|
RtlReleasePebLock();
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
DbgPrint( "RtlGetFullPath( %s => %S ", lpFileName, &FullPath );
|
||
|
if ( ARGUMENT_PRESENT( lpFilePart ) ) {
|
||
|
DbgPrint("fp %s\n",*lpFilePart ? *lpFilePart : "None");
|
||
|
}
|
||
|
else {
|
||
|
DbgPrint("NOT SPECIFIED\n");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef UNICODE_CHECK
|
||
|
CheckFullPathName(lpFileName,nBufferLength,lpBuffer,lpFilePart,FullPath.Length);
|
||
|
#endif // UNICODE_CHECK
|
||
|
return FullPath.Length;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
RtlDosPathNameToNtPathName(
|
||
|
IN PSZ DosFileName,
|
||
|
OUT PSTRING NtFileName,
|
||
|
OUT PSZ *FilePart OPTIONAL,
|
||
|
OUT PRTL_RELATIVE_NAME RelativeName OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
A Dos pathname can be translated into an Nt style pathname
|
||
|
using this function.
|
||
|
|
||
|
This function is used only within the Base dll to translate Dos
|
||
|
pathnames to Nt pathnames. Upon successful translation, the
|
||
|
pointer (NtFileName->Buffer) points to memory from RtlProcessHeap()
|
||
|
that contains the Nt version of the input dos file name.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos style file name that is to be
|
||
|
translated into an equivalent Nt file name.
|
||
|
|
||
|
NtFileName - Returns the address of memory in the RtlProcessHeap() that
|
||
|
contains an NT filename that refers to the specified Dos file
|
||
|
name.
|
||
|
|
||
|
FilePart - Optional parameter that if specified, returns the
|
||
|
trailing file portion of the file name. A path of \foo\bar\x.x
|
||
|
returns the address of x.x as the file part.
|
||
|
|
||
|
RelativeName - An optional parameter, that if specified, returns
|
||
|
a pathname relative to the current directory of the file. The
|
||
|
length field of RelativeName->RelativeName is 0 if the relative
|
||
|
name can not be used.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The path name translation was successful. Once the caller is
|
||
|
done with the translated name, the memory pointed to by
|
||
|
NtFileName.Buffer should be returned to the RtlProcessHeap().
|
||
|
|
||
|
FALSE - The operation failed.
|
||
|
|
||
|
Note:
|
||
|
The buffers pointed to by RelativeName, FilePart, and NtFileName must ALL
|
||
|
point within the same memory address. If they don't, code that calls
|
||
|
this routine will fail.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
ULONG BufferLength;
|
||
|
ULONG DosPathLength;
|
||
|
PSZ FullNtPathName = NULL;
|
||
|
PSZ FullDosPathName = NULL;
|
||
|
STRING Prefix;
|
||
|
PCURDIR CurDir;
|
||
|
RTL_PATH_TYPE DosPathType;
|
||
|
ULONG DosPathNameOffset;
|
||
|
ULONG FullDosPathNameLength;
|
||
|
|
||
|
//
|
||
|
// Calculate the size needed for the full pathname. Add in
|
||
|
// space for the longest Nt prefix
|
||
|
//
|
||
|
|
||
|
DosPathLength = BufferLength = RtlGetFullPathName(DosFileName,0,NULL,FilePart)+1;
|
||
|
|
||
|
if ( !BufferLength ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
try {
|
||
|
|
||
|
RtlAcquirePebLock();
|
||
|
|
||
|
//
|
||
|
// The dos name starts just after the longest Nt prefix
|
||
|
//
|
||
|
|
||
|
FullDosPathName = RtlAllocateHeap(RtlProcessHeap(), BufferLength);
|
||
|
|
||
|
if ( !FullDosPathName ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BufferLength += sizeof("\\DosDevices\\UNC\\");
|
||
|
|
||
|
//
|
||
|
// Allocate space for the full Nt Name (including DOS name portion)
|
||
|
//
|
||
|
|
||
|
FullNtPathName = RtlAllocateHeap(RtlProcessHeap(), BufferLength);
|
||
|
|
||
|
if ( !FullNtPathName ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
FullDosPathNameLength = RtlGetFullPathName(
|
||
|
DosFileName,
|
||
|
DosPathLength,
|
||
|
FullDosPathName,
|
||
|
FilePart
|
||
|
);
|
||
|
|
||
|
if ( !FullDosPathNameLength ||
|
||
|
FullDosPathNameLength > DosPathLength ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine how to format prefix of FullNtPathName base on the
|
||
|
// the type of Dos path name. All Nt names begin in the \DosDevices
|
||
|
// directory.
|
||
|
//
|
||
|
|
||
|
RtlInitString(&Prefix,"\\DosDevices\\");
|
||
|
DosPathType = RtlDetermineDosPathNameType(FullDosPathName);
|
||
|
|
||
|
switch (DosPathType) {
|
||
|
case RtlPathTypeUncAbsolute :
|
||
|
|
||
|
//
|
||
|
// Unc name, use \DosDevices\UNC symbolic link to find
|
||
|
// redirector. Skip of \\ in source Dos path.
|
||
|
//
|
||
|
|
||
|
RtlInitString(&Prefix,"\\DosDevices\\UNC\\");
|
||
|
DosPathNameOffset = 2;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeLocalDevice :
|
||
|
|
||
|
//
|
||
|
// Local device name, so just use \DosDevices prefix and
|
||
|
// skip \\.\ in source Dos path.
|
||
|
//
|
||
|
|
||
|
DosPathNameOffset = 4;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRootLocalDevice :
|
||
|
|
||
|
ASSERT( FALSE );
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeDriveAbsolute :
|
||
|
case RtlPathTypeDriveRelative :
|
||
|
case RtlPathTypeRooted :
|
||
|
case RtlPathTypeRelative :
|
||
|
|
||
|
//
|
||
|
// All drive references just use \DosDevices prefix and
|
||
|
// do not skip any of the characters in the source Dos path.
|
||
|
//
|
||
|
|
||
|
DosPathNameOffset = 0;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the full DOS path next to the name prefix, skipping over
|
||
|
// the "\\" at the front of the UNC path or the "\\.\" at the front
|
||
|
// of a device name.
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory(FullNtPathName,Prefix.Buffer,Prefix.Length);
|
||
|
RtlMoveMemory(FullNtPathName+Prefix.Length,
|
||
|
FullDosPathName + DosPathNameOffset,
|
||
|
FullDosPathNameLength - DosPathNameOffset);
|
||
|
|
||
|
//
|
||
|
// Null terminate the path name to make strlen below happy.
|
||
|
//
|
||
|
|
||
|
|
||
|
NtFileName->Buffer = FullNtPathName;
|
||
|
NtFileName->Length = (USHORT)(FullDosPathNameLength-DosPathNameOffset)+Prefix.Length;
|
||
|
NtFileName->MaximumLength = (USHORT)BufferLength;
|
||
|
FullNtPathName[ NtFileName->Length ] = '\0';
|
||
|
|
||
|
|
||
|
//
|
||
|
// Readjust the file part to point to the appropriate position within
|
||
|
// the FullNtPathName buffer instead of inside the FullDosPathName
|
||
|
// buffer
|
||
|
//
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(FilePart) ) {
|
||
|
if (*FilePart) {
|
||
|
*FilePart = (FullNtPathName + NtFileName->Length) -
|
||
|
strlen(*FilePart);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(RelativeName) ) {
|
||
|
|
||
|
//
|
||
|
// If the current directory is a sub-string of the
|
||
|
// Nt file name, and if a handle exists for the current
|
||
|
// directory, then return the directory handle and name
|
||
|
// relative to the directory.
|
||
|
//
|
||
|
|
||
|
RelativeName->RelativeName.Length = 0;
|
||
|
RelativeName->RelativeName.MaximumLength = 0;
|
||
|
RelativeName->RelativeName.Buffer = 0;
|
||
|
RelativeName->ContainingDirectory = NULL;
|
||
|
|
||
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||
|
|
||
|
if ( CurDir->Handle ) {
|
||
|
if ( !strnicmp(FullDosPathName,CurDir->DosPath.Buffer,CurDir->DosPath.Length) ) {
|
||
|
|
||
|
//
|
||
|
// The full dos pathname is a substring of the current directory.
|
||
|
// Compute the start of the relativename.
|
||
|
//
|
||
|
|
||
|
RelativeName->RelativeName.Buffer = FullNtPathName + Prefix.Length + CurDir->DosPath.Length;
|
||
|
RelativeName->RelativeName.Length = (USHORT)FullDosPathNameLength - CurDir->DosPath.Length;
|
||
|
if ( *RelativeName->RelativeName.Buffer == '\\' ) {
|
||
|
RelativeName->RelativeName.Buffer++;
|
||
|
RelativeName->RelativeName.Length--;
|
||
|
}
|
||
|
RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length;
|
||
|
RelativeName->ContainingDirectory = CurDir->Handle;
|
||
|
//DbgPrint("RelativeName %S CurDir %S\n",&RelativeName->RelativeName,&CurDir->DosPath);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
|
||
|
//
|
||
|
// Always free up the DOS path name - it was allocated as temp storage.
|
||
|
//
|
||
|
|
||
|
if ( FullDosPathName ) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), FullDosPathName, 0);
|
||
|
}
|
||
|
|
||
|
if ( AbnormalTermination() ) {
|
||
|
if ( FullNtPathName ) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), FullNtPathName, 0);
|
||
|
}
|
||
|
|
||
|
RtlReleasePebLock();
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ASSERT (NtFileName->Length < MAXIMUM_FILENAME_LENGTH);
|
||
|
ASSERT (NtFileName->MaximumLength < MAXIMUM_FILENAME_LENGTH);
|
||
|
|
||
|
if (ARGUMENT_PRESENT(RelativeName)) {
|
||
|
ASSERT (NtFileName->Length < MAXIMUM_FILENAME_LENGTH);
|
||
|
ASSERT (NtFileName->MaximumLength < MAXIMUM_FILENAME_LENGTH);
|
||
|
}
|
||
|
|
||
|
RtlReleasePebLock();
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE_CHECK
|
||
|
CheckDosPathNameToNtPathName(DosFileName,NtFileName,FilePart,RelativeName);
|
||
|
#endif // UNICODE_CHECK
|
||
|
|
||
|
//DbgPrint( "RtlDosPathNameToNtPathName( %s => %S )\n", DosFileName, NtFileName );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
RtlDoesFileExists(
|
||
|
PSZ FileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function checks to see if the specified filename exists.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FileName - Supplies the file name of the file to find.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The file was found.
|
||
|
|
||
|
FALSE - The file was not found.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
OBJECT_ATTRIBUTES Obja;
|
||
|
HANDLE Handle;
|
||
|
STRING NtFileName;
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
BOOLEAN ReturnValue;
|
||
|
RTL_RELATIVE_NAME RelativeName;
|
||
|
PVOID FreeBuffer;
|
||
|
|
||
|
ReturnValue = RtlDosPathNameToNtPathName(
|
||
|
FileName,
|
||
|
&NtFileName,
|
||
|
NULL,
|
||
|
&RelativeName
|
||
|
);
|
||
|
|
||
|
if ( !ReturnValue ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
FreeBuffer = NtFileName.Buffer;
|
||
|
|
||
|
if ( RelativeName.RelativeName.Length ) {
|
||
|
NtFileName = RelativeName.RelativeName;
|
||
|
}
|
||
|
else {
|
||
|
RelativeName.ContainingDirectory = NULL;
|
||
|
}
|
||
|
|
||
|
InitializeObjectAttributes(
|
||
|
&Obja,
|
||
|
&NtFileName,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
RelativeName.ContainingDirectory,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Open the file
|
||
|
//
|
||
|
|
||
|
Status = NtOpenFile(
|
||
|
&Handle,
|
||
|
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
||
|
&Obja,
|
||
|
&IoStatusBlock,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
FILE_SYNCHRONOUS_IO_NONALERT
|
||
|
);
|
||
|
RtlFreeHeap(RtlProcessHeap(),FreeBuffer,0);
|
||
|
NtClose(Handle);
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
if ( Status == STATUS_SHARING_VIOLATION ||
|
||
|
Status == STATUS_ACCESS_DENIED ) {
|
||
|
ReturnValue = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = TRUE;
|
||
|
}
|
||
|
#ifdef UNICODE_CHECK
|
||
|
CheckDosFileExist(FileName,ReturnValue);
|
||
|
#endif // UNICODE_CHECK
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
#else
|
||
|
|
||
|
RTL_PATH_TYPE
|
||
|
RtlDetermineDosPathNameType(
|
||
|
IN PSZ DosFileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function examines the Dos format file name and determines the
|
||
|
type of file name (i.e. UNC, DriveAbsolute, Current Directory
|
||
|
rooted, or Relative.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos format file name whose type is to be
|
||
|
determined.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
RtlPathTypeUnknown - The path type can not be determined
|
||
|
|
||
|
RtlPathTypeUncAbsolute - The path specifies a Unc absolute path
|
||
|
in the format \\server-name\sharename\rest-of-path
|
||
|
|
||
|
RtlPathTypeLocalDevice - The path specifies a local device in the format
|
||
|
\\.\rest-of-path this can be used for any device where the nt and
|
||
|
Win32 names are the same. For example mailslots.
|
||
|
|
||
|
RtlPathTypeRootLocalDevice - The path specifies the root of the local
|
||
|
devices in the format \\.
|
||
|
|
||
|
RtlPathTypeDriveAbsolute - The path specifies a drive letter absolute
|
||
|
path in the form drive:\rest-of-path
|
||
|
|
||
|
RtlPathTypeDriveRelative - The path specifies a drive letter relative
|
||
|
path in the form drive:rest-of-path
|
||
|
|
||
|
RtlPathTypeRooted - The path is rooted relative to the current disk
|
||
|
designator (either Unc disk, or drive). The form is \rest-of-path.
|
||
|
|
||
|
RtlPathTypeRelative - The path is relative (i.e. not absolute or rooted).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
RTL_PATH_TYPE ReturnValue;
|
||
|
NTSTATUS Status;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
|
||
|
RtlInitString(&AnsiString,DosFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
|
||
|
ReturnValue = RtlDetermineDosPathNameType_U(UnicodeString.Buffer);
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
RtlIsDosDeviceName(
|
||
|
IN PSZ DosFileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function examines the Dos format file name and determines if it
|
||
|
is a Dos device name (e.g. LPT1, etc.). Valid Dos device names are:
|
||
|
|
||
|
LPTn
|
||
|
COMn
|
||
|
PRN
|
||
|
AUX
|
||
|
NUL
|
||
|
|
||
|
when n is a digit. Trailing colon is ignored if present.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos format file name that is to be examined.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 - Specified Dos file name is not the name of a Dos device.
|
||
|
|
||
|
> 0 - Specified Dos file name is the name of a Dos device and the
|
||
|
return value is the length of the name (excluding any optional
|
||
|
trailing colon).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG ReturnLength;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
|
||
|
RtlInitString(&AnsiString,DosFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
|
||
|
ReturnLength = RtlIsDosDeviceName_U(UnicodeString.Buffer);
|
||
|
ReturnLength >>= 1;
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
return ReturnLength;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RtlGetFullPathName(
|
||
|
PSZ lpFileName,
|
||
|
ULONG nBufferLength,
|
||
|
PSZ lpBuffer,
|
||
|
PSZ *lpFilePart OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function is used to return a fully qualified pathname
|
||
|
corresponding to the specified filename. It does this by merging
|
||
|
the current drive and directory together with the specified file
|
||
|
name. In addition to this, it calculates the address of the file
|
||
|
name portion of the fully qualified pathname.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpFileName - Supplies the file name of the file whose fully
|
||
|
qualified pathname is to be returned.
|
||
|
|
||
|
nBufferLength - Supplies the length in bytes of the buffer that is
|
||
|
to receive the fully qualified path.
|
||
|
|
||
|
lpBuffer - Returns the fully qualified pathname corresponding to the
|
||
|
specified file.
|
||
|
|
||
|
lpFilePart - Optional parameter that if specified, returns the
|
||
|
address of the last component of the fully qualified pathname.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The return value is the length of the string copied to lpBuffer, not
|
||
|
including the terminating null character. If the return value is
|
||
|
greater than nBufferLength, the return value is the size of the buffer
|
||
|
required to hold the pathname. The return value is zero if the
|
||
|
function failed.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
NTSTATUS Status;
|
||
|
ULONG UnicodeLength;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
UNICODE_STRING UnicodeResult;
|
||
|
ANSI_STRING AnsiString;
|
||
|
ANSI_STRING AnsiResult;
|
||
|
PWSTR Ubuff;
|
||
|
PWSTR FilePart;
|
||
|
PWSTR *FilePartPtr;
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
||
|
FilePartPtr = &FilePart;
|
||
|
}
|
||
|
else {
|
||
|
FilePartPtr = NULL;
|
||
|
}
|
||
|
|
||
|
RtlInitString(&AnsiString,lpFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
Ubuff = RtlAllocateHeap(RtlProcessHeap(),512);
|
||
|
|
||
|
UnicodeLength = RtlGetFullPathName_U(
|
||
|
UnicodeString.Buffer,
|
||
|
510,
|
||
|
Ubuff,
|
||
|
FilePartPtr
|
||
|
);
|
||
|
UnicodeLength >>= 1;
|
||
|
if ( UnicodeLength && UnicodeLength <= nBufferLength ) {
|
||
|
RtlInitUnicodeString(&UnicodeResult,Ubuff);
|
||
|
RtlUnicodeStringToAnsiString(&AnsiResult,&UnicodeResult,TRUE);
|
||
|
RtlMoveMemory(lpBuffer,AnsiResult.Buffer,UnicodeLength+1);
|
||
|
RtlFreeAnsiString(&AnsiResult);
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
||
|
if ( FilePart == NULL ) {
|
||
|
*lpFilePart = NULL;
|
||
|
}
|
||
|
else {
|
||
|
*lpFilePart = (PSZ)(FilePart - Ubuff);
|
||
|
*lpFilePart = *lpFilePart + (ULONG)lpBuffer;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
RtlFreeHeap(RtlProcessHeap(),Ubuff,0);
|
||
|
#if 0
|
||
|
DbgPrint( "RtlGetFullPath( %s => %s ", lpFileName, lpBuffer );
|
||
|
if ( ARGUMENT_PRESENT( lpFilePart ) ) {
|
||
|
DbgPrint("fp %s\n",*lpFilePart ? *lpFilePart : "None");
|
||
|
}
|
||
|
else {
|
||
|
DbgPrint("NOT SPECIFIED\n");
|
||
|
}
|
||
|
#endif // 0
|
||
|
return UnicodeLength;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
RtlDosPathNameToNtPathName(
|
||
|
IN PSZ DosFileName,
|
||
|
OUT PSTRING NtFileName,
|
||
|
OUT PSZ *FilePart OPTIONAL,
|
||
|
OUT PRTL_RELATIVE_NAME RelativeName OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
A Dos pathname can be translated into an Nt style pathname
|
||
|
using this function.
|
||
|
|
||
|
This function is used only within the Base dll to translate Dos
|
||
|
pathnames to Nt pathnames. Upon successful translation, the
|
||
|
pointer (NtFileName->Buffer) points to memory from RtlProcessHeap()
|
||
|
that contains the Nt version of the input dos file name.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos style file name that is to be
|
||
|
translated into an equivalent Nt file name.
|
||
|
|
||
|
NtFileName - Returns the address of memory in the RtlProcessHeap() that
|
||
|
contains an NT filename that refers to the specified Dos file
|
||
|
name.
|
||
|
|
||
|
FilePart - Optional parameter that if specified, returns the
|
||
|
trailing file portion of the file name. A path of \foo\bar\x.x
|
||
|
returns the address of x.x as the file part.
|
||
|
|
||
|
RelativeName - An optional parameter, that if specified, returns
|
||
|
a pathname relative to the current directory of the file. The
|
||
|
length field of RelativeName->RelativeName is 0 if the relative
|
||
|
name can not be used.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The path name translation was successful. Once the caller is
|
||
|
done with the translated name, the memory pointed to by
|
||
|
NtFileName.Buffer should be returned to the RtlProcessHeap().
|
||
|
|
||
|
FALSE - The operation failed.
|
||
|
|
||
|
Note:
|
||
|
The buffers pointed to by RelativeName, FilePart, and NtFileName must ALL
|
||
|
point within the same memory address. If they don't, code that calls
|
||
|
this routine will fail.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
UNICODE_STRING UnicodeResult;
|
||
|
ANSI_STRING AnsiString;
|
||
|
ANSI_STRING AnsiResult;
|
||
|
PWSTR UFilePart;
|
||
|
PWSTR *UFilePartPtr;
|
||
|
BOOLEAN b;
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(FilePart) ) {
|
||
|
UFilePartPtr = &UFilePart;
|
||
|
}
|
||
|
else {
|
||
|
UFilePartPtr = NULL;
|
||
|
}
|
||
|
|
||
|
RtlInitString(&AnsiString,DosFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
b = RtlDosPathNameToNtPathName_U(
|
||
|
UnicodeString.Buffer,
|
||
|
&UnicodeResult,
|
||
|
UFilePartPtr,
|
||
|
RelativeName
|
||
|
);
|
||
|
if ( !b ) {
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
}
|
||
|
|
||
|
RtlUnicodeStringToAnsiString(&AnsiResult,&UnicodeResult,TRUE);
|
||
|
NtFileName->Buffer = RtlAllocateHeap(RtlProcessHeap(),AnsiResult.MaximumLength);
|
||
|
NtFileName->Length = AnsiResult.Length;
|
||
|
NtFileName->MaximumLength = AnsiResult.MaximumLength;
|
||
|
RtlMoveMemory(NtFileName->Buffer,AnsiResult.Buffer,AnsiResult.MaximumLength);
|
||
|
RtlFreeAnsiString(&AnsiResult);
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(FilePart) ) {
|
||
|
if ( UFilePart == NULL ) {
|
||
|
*FilePart = NULL;
|
||
|
}
|
||
|
else {
|
||
|
*FilePart = (PSZ)(UFilePart - UnicodeResult.Buffer);
|
||
|
*FilePart = *FilePart + (ULONG)NtFileName->Buffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(RelativeName) ) {
|
||
|
if ( RelativeName->RelativeName.Length ) {
|
||
|
RelativeName->RelativeName.Buffer =
|
||
|
(PCHAR)((PWSTR)RelativeName->RelativeName.Buffer - UnicodeResult.Buffer);
|
||
|
RelativeName->RelativeName.Buffer =
|
||
|
RelativeName->RelativeName.Buffer + (ULONG)NtFileName->Buffer;
|
||
|
RelativeName->RelativeName.Length >>= 1;
|
||
|
RelativeName->RelativeName.MaximumLength >>= 1;
|
||
|
}
|
||
|
}
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
RtlFreeHeap(RtlProcessHeap(),UnicodeResult.Buffer,0);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
RtlDoesFileExists(
|
||
|
PSZ FileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function checks to see if the specified filename exists.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FileName - Supplies the file name of the file to find.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The file was found.
|
||
|
|
||
|
FALSE - The file was not found.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
BOOLEAN ReturnValue;
|
||
|
|
||
|
RtlInitString(&AnsiString,FileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
|
||
|
ReturnValue = RtlDoesFileExists_U(UnicodeString.Buffer);
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
#endif // OLD
|
||
|
|
||
|
ULONG
|
||
|
RtlGetCurrentDirectory(
|
||
|
ULONG nBufferLength,
|
||
|
PSZ lpBuffer
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The current directory for a process can be retreived using
|
||
|
GetCurrentDirectory.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
nBufferLength - Supplies the length in bytes of the buffer that is to
|
||
|
receive the current directory string.
|
||
|
|
||
|
lpBuffer - Returns the current directory string for the current
|
||
|
process. The string is a null terminated string and specifies
|
||
|
the absolute path to the current directory.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The return value is the length of the string copied to lpBuffer, not
|
||
|
including the terminating null character. If the return value is
|
||
|
greater than nBufferLength, the return value is the size of the buffer
|
||
|
required to hold the pathname. The return value is zero if the
|
||
|
function failed.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCURDIR CurDir;
|
||
|
ULONG Length;
|
||
|
|
||
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||
|
|
||
|
RtlAcquirePebLock();
|
||
|
|
||
|
//
|
||
|
// Make sure user's buffer is big enough to hold the null
|
||
|
// terminated current directory
|
||
|
//
|
||
|
|
||
|
Length = CurDir->DosPath.Length;
|
||
|
if (CurDir->DosPath.Buffer[Length-2] != ':') {
|
||
|
if ( nBufferLength < Length-1 ) {
|
||
|
RtlReleasePebLock();
|
||
|
return Length-1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if ( nBufferLength < Length ) {
|
||
|
RtlReleasePebLock();
|
||
|
return Length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
RtlMoveMemory(lpBuffer,CurDir->DosPath.Buffer,Length);
|
||
|
ASSERT(lpBuffer[Length-1] == '\\');
|
||
|
if (lpBuffer[Length-2] == ':') {
|
||
|
lpBuffer[Length] = '\0';
|
||
|
}
|
||
|
else {
|
||
|
lpBuffer[Length-1] = '\0';
|
||
|
Length--;
|
||
|
}
|
||
|
}
|
||
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
RtlReleasePebLock();
|
||
|
return 0L;
|
||
|
}
|
||
|
RtlReleasePebLock();
|
||
|
return Length;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
RtlSetCurrentDirectory(
|
||
|
PSZ lpPathName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The current directory for a process is changed using
|
||
|
SetCurrentDirectory.
|
||
|
|
||
|
Each process has a single current directory. A current directory is
|
||
|
made up of type parts.
|
||
|
|
||
|
- A disk designator either which is either a drive letter followed
|
||
|
by a colon, or a UNC servername/sharename "\\servername\sharename".
|
||
|
|
||
|
- A directory on the disk designator.
|
||
|
|
||
|
For APIs that manipulate files, the file names may be relative to
|
||
|
the current directory. A filename is relative to the entire current
|
||
|
directory if it does not begin with a disk designator or a path name
|
||
|
SEPARATOR. If the file name begins with a path name SEPARATOR, then
|
||
|
it is relative to the disk designator of the current directory. If
|
||
|
a file name begins with a disk designator, than it is a fully
|
||
|
qualified absolute path name.
|
||
|
|
||
|
The value of lpPathName supplies the current directory. The value
|
||
|
of lpPathName, may be a relative path name as described above, or a
|
||
|
fully qualified absolute path name. In either case, the fully
|
||
|
qualified absolute path name of the specified directory is
|
||
|
calculated and is stored as the current directory.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpPathName - Supplies the pathname of the directory that is to be
|
||
|
made the current directory.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT_SUCCESS - The operation was successful
|
||
|
|
||
|
!NT_SUCCESS - The operation failed
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCURDIR CurDir;
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN TranslationStatus;
|
||
|
PVOID FreeBuffer;
|
||
|
ULONG DosDirLength;
|
||
|
STRING DosDir;
|
||
|
STRING NtFileName;
|
||
|
HANDLE NewDirectoryHandle;
|
||
|
OBJECT_ATTRIBUTES Obja;
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
|
||
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||
|
|
||
|
DosDir.Buffer = NULL;
|
||
|
FreeBuffer = NULL;
|
||
|
NewDirectoryHandle = NULL;
|
||
|
|
||
|
RtlAcquirePebLock();
|
||
|
try {
|
||
|
try {
|
||
|
|
||
|
//
|
||
|
// Compute the length of the Dos style fully qualified current
|
||
|
// directory
|
||
|
//
|
||
|
|
||
|
DosDirLength = CurDir->DosPath.MaximumLength;
|
||
|
DosDir.Buffer = RtlAllocateHeap(RtlProcessHeap(),DosDirLength);
|
||
|
DosDir.Length = 0;
|
||
|
DosDir.MaximumLength = (USHORT)DosDirLength;
|
||
|
|
||
|
//
|
||
|
// Now get the full pathname for the Dos style current
|
||
|
// directory
|
||
|
//
|
||
|
RtlpLastDosPath.Length = 0;
|
||
|
|
||
|
DosDirLength = RtlGetFullPathName(
|
||
|
lpPathName,
|
||
|
DosDirLength,
|
||
|
DosDir.Buffer,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Get the Nt filename of the new current directory
|
||
|
//
|
||
|
|
||
|
TranslationStatus = RtlDosPathNameToNtPathName(
|
||
|
DosDir.Buffer,
|
||
|
&NtFileName,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if ( !TranslationStatus ) {
|
||
|
return STATUS_OBJECT_NAME_INVALID;
|
||
|
}
|
||
|
FreeBuffer = NtFileName.Buffer;
|
||
|
|
||
|
InitializeObjectAttributes(
|
||
|
&Obja,
|
||
|
&NtFileName,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Open a handle to the current directory. Don't allow
|
||
|
// deletes of the directory.
|
||
|
//
|
||
|
|
||
|
Status = NtOpenFile(
|
||
|
&NewDirectoryHandle,
|
||
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
||
|
&Obja,
|
||
|
&IoStatusBlock,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
|
||
|
);
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If there is no trailing '\', than place one
|
||
|
//
|
||
|
|
||
|
if ( DosDir.Buffer[DosDirLength] != '\\' &&
|
||
|
DosDir.Buffer[DosDirLength-1] != '\\') {
|
||
|
DosDir.Buffer[DosDirLength] = '\\';
|
||
|
DosDir.Buffer[DosDirLength+1] = '\0';
|
||
|
DosDir.Length = (USHORT)(DosDirLength + 1L);
|
||
|
}
|
||
|
else {
|
||
|
DosDir.Length = (USHORT)DosDirLength;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we are set to change to the new directory.
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory( CurDir->DosPath.Buffer, DosDir.Buffer, DosDir.Length+1 );
|
||
|
CurDir->DosPath.Length = DosDir.Length;
|
||
|
|
||
|
if ( CurDir->Handle ) {
|
||
|
NtClose(CurDir->Handle);
|
||
|
}
|
||
|
CurDir->Handle = NewDirectoryHandle;
|
||
|
NewDirectoryHandle = NULL;
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
finally {
|
||
|
if ( DosDir.Buffer ) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), DosDir.Buffer, 0L);
|
||
|
}
|
||
|
if ( FreeBuffer ) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), FreeBuffer, 0L);
|
||
|
}
|
||
|
if ( NewDirectoryHandle ) {
|
||
|
NtClose(NewDirectoryHandle);
|
||
|
}
|
||
|
RtlReleasePebLock();
|
||
|
}
|
||
|
}
|
||
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
return STATUS_ACCESS_VIOLATION;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
RtlDosSearchPath(
|
||
|
PSZ lpPath,
|
||
|
PSZ lpFileName,
|
||
|
PSZ lpExtension,
|
||
|
ULONG nBufferLength,
|
||
|
PSZ lpBuffer,
|
||
|
PSZ *lpFilePart OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function is used to search for a file specifying a search path
|
||
|
and a filename. It returns with a fully qualified pathname of the
|
||
|
found file.
|
||
|
|
||
|
This function is used to locate a file using the specified path. If
|
||
|
the file is found, its fully qualified pathname is returned. In
|
||
|
addition to this, it calculates the address of the file name portion
|
||
|
of the fully qualified pathname.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpPath - Supplies the search path to be used when locating the file.
|
||
|
|
||
|
lpFileName - Supplies the file name of the file to search for.
|
||
|
|
||
|
lpExtension - An optional parameter, that if specified, supplies an
|
||
|
extension to be added to the filename when doing the search.
|
||
|
The extension is only added if the specified filename does not
|
||
|
end with an extension.
|
||
|
|
||
|
nBufferLength - Supplies the length in bytes of the buffer that is
|
||
|
to receive the fully qualified path.
|
||
|
|
||
|
lpBuffer - Returns the fully qualified pathname corresponding to the
|
||
|
file that was found.
|
||
|
|
||
|
lpFilePart - Optional parameter that if specified, returns the
|
||
|
address of the last component of the fully qualified pathname.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The return value is the length of the string copied to lpBuffer, not
|
||
|
including the terminating null character. If the return value is
|
||
|
greater than nBufferLength, the return value is the size of the buffer
|
||
|
required to hold the pathname. The return value is zero if the
|
||
|
function failed.
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
PSZ ComputedFileName;
|
||
|
ULONG ExtensionLength;
|
||
|
ULONG PathLength;
|
||
|
ULONG FileLength;
|
||
|
PSZ p;
|
||
|
|
||
|
//
|
||
|
// if the file name is not a relative name, then
|
||
|
// return an if the file does not exist.
|
||
|
//
|
||
|
|
||
|
if ( RtlDetermineDosPathNameType(lpFileName) != RtlPathTypeRelative ) {
|
||
|
if (RtlDoesFileExists(lpFileName) ) {
|
||
|
PathLength = RtlGetFullPathName(
|
||
|
lpFileName,
|
||
|
nBufferLength,
|
||
|
lpBuffer,
|
||
|
lpFilePart
|
||
|
);
|
||
|
return PathLength;
|
||
|
}
|
||
|
else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine if the file name contains an extension
|
||
|
//
|
||
|
|
||
|
ExtensionLength = 1;
|
||
|
p = lpFileName;
|
||
|
while (*p) {
|
||
|
if ( *p == '.' ) {
|
||
|
ExtensionLength = 0;
|
||
|
break;
|
||
|
}
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If no extension was found, then determine the extension length
|
||
|
// that should be used to search for the file
|
||
|
//
|
||
|
|
||
|
if ( ExtensionLength ) {
|
||
|
if ( ARGUMENT_PRESENT(lpExtension) ) {
|
||
|
ExtensionLength = strlen(lpExtension);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ExtensionLength = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Compute the file name length and the path length;
|
||
|
//
|
||
|
|
||
|
PathLength = strlen(lpPath);
|
||
|
FileLength = strlen(lpFileName);
|
||
|
|
||
|
ComputedFileName = RtlAllocateHeap(
|
||
|
RtlProcessHeap(),
|
||
|
PathLength + FileLength + ExtensionLength + 3
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// find ; 's in path and copy path component to computed file name
|
||
|
//
|
||
|
|
||
|
do {
|
||
|
p = ComputedFileName;
|
||
|
while (*lpPath) {
|
||
|
if (*lpPath == ';') {
|
||
|
lpPath++;
|
||
|
break;
|
||
|
}
|
||
|
*p++ = *lpPath++;
|
||
|
}
|
||
|
|
||
|
if (p != ComputedFileName &&
|
||
|
p [ -1 ] != '\\' ) {
|
||
|
*p++ = '\\';
|
||
|
}
|
||
|
if (*lpPath == '\0') {
|
||
|
lpPath = NULL;
|
||
|
}
|
||
|
RtlMoveMemory(p,lpFileName,FileLength);
|
||
|
if ( ExtensionLength ) {
|
||
|
RtlMoveMemory(p+FileLength,lpExtension,ExtensionLength+1);
|
||
|
}
|
||
|
else {
|
||
|
*(p+FileLength) = '\0';
|
||
|
}
|
||
|
|
||
|
if (RtlDoesFileExists(ComputedFileName) ) {
|
||
|
PathLength = RtlGetFullPathName(
|
||
|
ComputedFileName,
|
||
|
nBufferLength,
|
||
|
lpBuffer,
|
||
|
lpFilePart
|
||
|
);
|
||
|
RtlFreeHeap(RtlProcessHeap(), ComputedFileName, 0);
|
||
|
return PathLength;
|
||
|
}
|
||
|
}
|
||
|
while ( lpPath );
|
||
|
|
||
|
RtlFreeHeap(RtlProcessHeap(), ComputedFileName, 0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
RTL_PATH_TYPE
|
||
|
RtlDetermineDosPathNameType_U(
|
||
|
IN PWSTR DosFileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function examines the Dos format file name and determines the
|
||
|
type of file name (i.e. UNC, DriveAbsolute, Current Directory
|
||
|
rooted, or Relative.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos format file name whose type is to be
|
||
|
determined.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
RtlPathTypeUnknown - The path type can not be determined
|
||
|
|
||
|
RtlPathTypeUncAbsolute - The path specifies a Unc absolute path
|
||
|
in the format \\server-name\sharename\rest-of-path
|
||
|
|
||
|
RtlPathTypeLocalDevice - The path specifies a local device in the format
|
||
|
\\.\rest-of-path this can be used for any device where the nt and
|
||
|
Win32 names are the same. For example mailslots.
|
||
|
|
||
|
RtlPathTypeRootLocalDevice - The path specifies the root of the local
|
||
|
devices in the format \\.
|
||
|
|
||
|
RtlPathTypeDriveAbsolute - The path specifies a drive letter absolute
|
||
|
path in the form drive:\rest-of-path
|
||
|
|
||
|
RtlPathTypeDriveRelative - The path specifies a drive letter relative
|
||
|
path in the form drive:rest-of-path
|
||
|
|
||
|
RtlPathTypeRooted - The path is rooted relative to the current disk
|
||
|
designator (either Unc disk, or drive). The form is \rest-of-path.
|
||
|
|
||
|
RtlPathTypeRelative - The path is relative (i.e. not absolute or rooted).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
RTL_PATH_TYPE ReturnValue;
|
||
|
|
||
|
if ( IS_PATH_SEPARATOR_U(*DosFileName) ) {
|
||
|
if ( IS_PATH_SEPARATOR_U(*(DosFileName+1)) ) {
|
||
|
if ( DosFileName[2] == '.' ) {
|
||
|
if ( IS_PATH_SEPARATOR_U(*(DosFileName+3)) ){
|
||
|
ReturnValue = RtlPathTypeLocalDevice;
|
||
|
}
|
||
|
else if ( (*(DosFileName+3)) == UNICODE_NULL ){
|
||
|
ReturnValue = RtlPathTypeRootLocalDevice;
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeUncAbsolute;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeUncAbsolute;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeRooted;
|
||
|
}
|
||
|
}
|
||
|
else if (*(DosFileName+1)==(WCHAR)':') {
|
||
|
if (IS_PATH_SEPARATOR_U(*(DosFileName+2))) {
|
||
|
ReturnValue = RtlPathTypeDriveAbsolute;
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeDriveRelative;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = RtlPathTypeRelative;
|
||
|
}
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RtlIsDosDeviceName_U(
|
||
|
IN PWSTR DosFileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function examines the Dos format file name and determines if it
|
||
|
is a Dos device name (e.g. LPT1, etc.). Valid Dos device names are:
|
||
|
|
||
|
LPTn
|
||
|
COMn
|
||
|
PRN
|
||
|
AUX
|
||
|
NUL
|
||
|
|
||
|
when n is a digit. Trailing colon is ignored if present.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the Dos format file name that is to be examined.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 - Specified Dos file name is not the name of a Dos device.
|
||
|
|
||
|
> 0 - Specified Dos file name is the name of a Dos device and the
|
||
|
return value is the length of the name (excluding any optional
|
||
|
trailing colon).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ULONG NumberOfCharacters;
|
||
|
ULONG ReturnLength;
|
||
|
|
||
|
RtlInitUnicodeString(&UnicodeString,DosFileName);
|
||
|
|
||
|
NumberOfCharacters = UnicodeString.Length >> 1;
|
||
|
|
||
|
if (NumberOfCharacters && DosFileName[NumberOfCharacters-1] == (WCHAR)':') {
|
||
|
NumberOfCharacters--;
|
||
|
}
|
||
|
ReturnLength = NumberOfCharacters << 1;
|
||
|
|
||
|
if ( NumberOfCharacters == 4 && isdigit( (WCHAR)DosFileName[3] ) ) {
|
||
|
UnicodeString.Length -= sizeof(WCHAR);
|
||
|
if ( !RtlCompareString((PSTRING)&UnicodeString,(PSTRING)&RtlpDosDevices[ DOS_DEVICE_LPT ],TRUE) ||
|
||
|
!RtlCompareString((PSTRING)&UnicodeString,(PSTRING)&RtlpDosDevices[ DOS_DEVICE_COM ],TRUE) ) {
|
||
|
;
|
||
|
}
|
||
|
else {
|
||
|
ReturnLength = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if ( NumberOfCharacters != 3 ) {
|
||
|
ReturnLength = 0;
|
||
|
}
|
||
|
else
|
||
|
if ( !RtlCompareString((PSTRING)&UnicodeString,(PSTRING)&RtlpDosDevices[ DOS_DEVICE_PRN ],TRUE) ) {
|
||
|
;
|
||
|
}
|
||
|
else
|
||
|
if ( !RtlCompareString((PSTRING)&UnicodeString,(PSTRING)&RtlpDosDevices[ DOS_DEVICE_AUX ],TRUE) ) {
|
||
|
;
|
||
|
}
|
||
|
else
|
||
|
if ( !RtlCompareString((PSTRING)&UnicodeString,(PSTRING)&RtlpDosDevices[ DOS_DEVICE_NUL ],TRUE) ) {
|
||
|
;
|
||
|
}
|
||
|
else {
|
||
|
ReturnLength = 0;
|
||
|
}
|
||
|
return ReturnLength;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RtlGetFullPathName_U(
|
||
|
PWSTR lpFileName,
|
||
|
ULONG nBufferLength,
|
||
|
PWSTR lpBuffer,
|
||
|
PWSTR *lpFilePart OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function is used to return a fully qualified pathname
|
||
|
corresponding to the specified unicode filename. It does this by
|
||
|
merging the current drive and directory together with the specified
|
||
|
file name. In addition to this, it calculates the address of the
|
||
|
file name portion of the fully qualified pathname.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpFileName - Supplies the unicode file name of the file whose fully
|
||
|
qualified pathname is to be returned.
|
||
|
|
||
|
nBufferLength - Supplies the length in bytes of the buffer that is
|
||
|
to receive the fully qualified path.
|
||
|
|
||
|
lpBuffer - Returns the fully qualified pathname corresponding to the
|
||
|
specified file.
|
||
|
|
||
|
lpFilePart - Optional parameter that if specified, returns the
|
||
|
address of the last component of the fully qualified pathname.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The return value is the length of the string copied to lpBuffer, not
|
||
|
including the terminating unicode null character. If the return
|
||
|
value is greater than nBufferLength, the return value is the size of
|
||
|
the buffer required to hold the pathname. The return value is zero
|
||
|
if the function failed.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG DeviceNameLength;
|
||
|
ULONG PrefixSourceLength;
|
||
|
LONG PathNameLength;
|
||
|
UCHAR CurDrive, NewDrive;
|
||
|
UCHAR EnvVarNameBuffer[4];
|
||
|
STRING EnvVarName;
|
||
|
PWSTR Source,Dest;
|
||
|
UNICODE_STRING Prefix;
|
||
|
PCURDIR CurDir;
|
||
|
ULONG MaximumLength;
|
||
|
UNICODE_STRING FullPath;
|
||
|
ULONG BackupIndex;
|
||
|
RTL_PATH_TYPE PathType;
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN StripTrailingSlash;
|
||
|
UNICODE_STRING UnicodeString,DeleteMe;
|
||
|
ULONG NumberOfCharacters;
|
||
|
|
||
|
DeleteMe.Buffer = NULL;
|
||
|
RtlInitUnicodeString(&UnicodeString,lpFileName);
|
||
|
|
||
|
NumberOfCharacters = UnicodeString.Length >> 1;
|
||
|
PathNameLength = UnicodeString.Length;
|
||
|
|
||
|
if ( PathNameLength == 0 ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if ( lpFileName[NumberOfCharacters-1] == (WCHAR)'\\' ) {
|
||
|
StripTrailingSlash = FALSE;
|
||
|
}
|
||
|
else {
|
||
|
StripTrailingSlash = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If pass Dos file name is a Dos device name, then turn it into
|
||
|
// \\.\devicename and return its length.
|
||
|
//
|
||
|
|
||
|
DeviceNameLength = RtlIsDosDeviceName_U(lpFileName);
|
||
|
if ( DeviceNameLength ) {
|
||
|
|
||
|
PathNameLength = DeviceNameLength + RtlpSlashSlashDot.Length;
|
||
|
if ( PathNameLength <= (LONG)nBufferLength ) {
|
||
|
RtlMoveMemory(
|
||
|
lpBuffer,
|
||
|
RtlpSlashSlashDot.Buffer,
|
||
|
RtlpSlashSlashDot.Length
|
||
|
);
|
||
|
RtlMoveMemory(
|
||
|
(PVOID)((PUCHAR)lpBuffer+RtlpSlashSlashDot.Length),
|
||
|
lpFileName,
|
||
|
DeviceNameLength+sizeof(UNICODE_NULL)
|
||
|
);
|
||
|
|
||
|
return PathNameLength;
|
||
|
}
|
||
|
else {
|
||
|
return PathNameLength+1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Setup output string that points to callers buffer.
|
||
|
//
|
||
|
|
||
|
FullPath.MaximumLength = (USHORT)nBufferLength;
|
||
|
FullPath.Length = 0;
|
||
|
FullPath.Buffer = lpBuffer;
|
||
|
RtlZeroMemory(lpBuffer,nBufferLength);
|
||
|
//
|
||
|
// Get a pointer to the current directory structure.
|
||
|
//
|
||
|
|
||
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Determine the type of Dos Path Name specified.
|
||
|
//
|
||
|
|
||
|
PathType = RtlDetermineDosPathNameType_U(lpFileName);
|
||
|
|
||
|
//
|
||
|
// Determine the prefix and backup index.
|
||
|
//
|
||
|
// Input Prefix Backup Index
|
||
|
//
|
||
|
// \\ -> \\, end of \\server\share
|
||
|
// \\.\ -> \\.\, 4
|
||
|
// \\. -> \\. 3 (\\.)
|
||
|
// \ -> Drive: from CurDir.DosPath 3 (Drive:\)
|
||
|
// d: -> Drive:\curdir from environment 3 (Drive:\)
|
||
|
// d:\ -> no prefix 3 (Drive:\)
|
||
|
// any -> CurDir.DosPath 3 (Drive:\)
|
||
|
//
|
||
|
|
||
|
try {
|
||
|
RtlAcquirePebLock();
|
||
|
|
||
|
//
|
||
|
// No prefixes yet.
|
||
|
//
|
||
|
|
||
|
Source = lpFileName;
|
||
|
PrefixSourceLength = 0;
|
||
|
Prefix.Length = 0;
|
||
|
Prefix.MaximumLength = 0;
|
||
|
Prefix.Buffer = NULL;
|
||
|
|
||
|
switch (PathType) {
|
||
|
case RtlPathTypeUncAbsolute :
|
||
|
{
|
||
|
PWSTR UncPathPointer;
|
||
|
ULONG NumberOfPathSeparators;
|
||
|
|
||
|
//
|
||
|
// We want to scan the supplied path to determine where
|
||
|
// the "share" ends, and set BackupIndex to that point.
|
||
|
//
|
||
|
|
||
|
UncPathPointer = lpFileName + 2;
|
||
|
NumberOfPathSeparators = 0;
|
||
|
while (*UncPathPointer) {
|
||
|
if (IS_PATH_SEPARATOR_U(*UncPathPointer)) {
|
||
|
|
||
|
NumberOfPathSeparators++;
|
||
|
|
||
|
if (NumberOfPathSeparators == 2) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UncPathPointer++;
|
||
|
|
||
|
}
|
||
|
|
||
|
BackupIndex = (UncPathPointer - lpFileName) >> 1;
|
||
|
|
||
|
//
|
||
|
// Unc name. prefix = \\server\share
|
||
|
//
|
||
|
|
||
|
PrefixSourceLength = BackupIndex << 1;
|
||
|
Source += BackupIndex;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeLocalDevice :
|
||
|
|
||
|
//
|
||
|
// Local device name. prefix = \\.\
|
||
|
//
|
||
|
|
||
|
PrefixSourceLength = RtlpSlashSlashDot.Length;
|
||
|
BackupIndex = 4;
|
||
|
Source += BackupIndex;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRootLocalDevice :
|
||
|
|
||
|
//
|
||
|
// Local Device root. prefix = \\.\
|
||
|
//
|
||
|
|
||
|
|
||
|
Prefix = RtlpSlashSlashDot;
|
||
|
Prefix.Length = (USHORT)(Prefix.Length - (USHORT)(2*sizeof(UNICODE_NULL)));
|
||
|
PrefixSourceLength = Prefix.Length + sizeof(UNICODE_NULL);
|
||
|
BackupIndex = 3;
|
||
|
Source += BackupIndex;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeDriveAbsolute :
|
||
|
|
||
|
//
|
||
|
// Dos drive absolute name
|
||
|
//
|
||
|
|
||
|
BackupIndex = 3;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeDriveRelative :
|
||
|
|
||
|
//
|
||
|
// Dos drive relative name
|
||
|
//
|
||
|
//
|
||
|
// BUGBUG CURDIR ASSUMED ANSI
|
||
|
//
|
||
|
CurDrive = (UCHAR)toupper( CurDir->DosPath.Buffer[0] );
|
||
|
NewDrive = (UCHAR)toupper( (UCHAR)lpFileName[0] );
|
||
|
if ( CurDrive == NewDrive ) {
|
||
|
RtlAnsiStringToUnicodeString(
|
||
|
&DeleteMe,
|
||
|
(PANSI_STRING)&CurDir->DosPath,
|
||
|
TRUE
|
||
|
);
|
||
|
Prefix = DeleteMe;
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
EnvVarNameBuffer[0] = '=';
|
||
|
EnvVarNameBuffer[1] = NewDrive;
|
||
|
EnvVarNameBuffer[2] = ':';
|
||
|
EnvVarNameBuffer[3] = '\0';
|
||
|
RtlInitString(&EnvVarName,EnvVarNameBuffer);
|
||
|
|
||
|
Prefix = FullPath;
|
||
|
Status = RtlQueryEnvironmentVariable( NULL,
|
||
|
&EnvVarName,
|
||
|
(PSTRING)&Prefix
|
||
|
);
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
|
return (Prefix.Length*2) + PathNameLength + 2;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// Otherwise default to root directory of drive
|
||
|
//
|
||
|
|
||
|
EnvVarNameBuffer[0] = NewDrive;
|
||
|
EnvVarNameBuffer[1] = ':';
|
||
|
EnvVarNameBuffer[2] = '\\';
|
||
|
EnvVarNameBuffer[3] = '\0';
|
||
|
RtlInitAnsiString((PANSI_STRING)&Prefix,EnvVarNameBuffer);
|
||
|
RtlAnsiStringToUnicodeString(
|
||
|
&DeleteMe,
|
||
|
(PANSI_STRING)&Prefix,
|
||
|
TRUE
|
||
|
);
|
||
|
Prefix = DeleteMe;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
RtlAnsiStringToUnicodeString(
|
||
|
&DeleteMe,
|
||
|
(PANSI_STRING)&Prefix,
|
||
|
TRUE
|
||
|
);
|
||
|
Prefix = DeleteMe;
|
||
|
|
||
|
{
|
||
|
ULONG LastChar;
|
||
|
|
||
|
//
|
||
|
// Determine
|
||
|
// if a backslash needs to be added
|
||
|
//
|
||
|
|
||
|
LastChar = Prefix.Length >> 1;
|
||
|
|
||
|
if (LastChar > 3) {
|
||
|
Prefix.Buffer[ LastChar ] = (WCHAR)'\\';
|
||
|
Prefix.Length += sizeof(UNICODE_NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BackupIndex = 3;
|
||
|
Source += 2;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRooted :
|
||
|
|
||
|
//
|
||
|
// Rooted name. Prefix is drive portion of current directory
|
||
|
//
|
||
|
RtlAnsiStringToUnicodeString(
|
||
|
&DeleteMe,
|
||
|
(PANSI_STRING)&CurDir->DosPath,
|
||
|
TRUE
|
||
|
);
|
||
|
Prefix = DeleteMe;
|
||
|
Prefix.Length = 2*sizeof(UNICODE_NULL);
|
||
|
BackupIndex = 3;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRelative :
|
||
|
|
||
|
//
|
||
|
// Current drive:directory relative name
|
||
|
//
|
||
|
|
||
|
RtlAnsiStringToUnicodeString(
|
||
|
&DeleteMe,
|
||
|
(PANSI_STRING)&CurDir->DosPath,
|
||
|
TRUE
|
||
|
);
|
||
|
Prefix = DeleteMe;
|
||
|
BackupIndex = 3;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Maximum length required is the length of the prefix plus
|
||
|
// the length of the specified pathname. If the callers buffer
|
||
|
// is not at least this large, then return an error.
|
||
|
//
|
||
|
|
||
|
MaximumLength = PathNameLength + Prefix.Length;
|
||
|
|
||
|
if ( MaximumLength > nBufferLength ) {
|
||
|
if ( (MaximumLength - nBufferLength != sizeof(UNICODE_NULL)) ||
|
||
|
(NumberOfCharacters > 1) ||
|
||
|
(*lpFileName != (WCHAR)'.') ) {
|
||
|
return MaximumLength;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PrefixSourceLength || Prefix.Buffer != FullPath.Buffer) {
|
||
|
//
|
||
|
// Copy the prefix from the source string.
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory(FullPath.Buffer,lpFileName,PrefixSourceLength);
|
||
|
FullPath.Length = (USHORT)PrefixSourceLength;
|
||
|
|
||
|
//
|
||
|
// Append any additional prefix
|
||
|
//
|
||
|
|
||
|
RtlAppendStringToString((PSTRING)&FullPath,(PSTRING)&Prefix);
|
||
|
}
|
||
|
else {
|
||
|
FullPath.Length = Prefix.Length;
|
||
|
}
|
||
|
|
||
|
Dest = (PWSTR)((PUCHAR)FullPath.Buffer + FullPath.Length);
|
||
|
*Dest = UNICODE_NULL;
|
||
|
|
||
|
while ( *Source ) {
|
||
|
switch ( *Source ) {
|
||
|
|
||
|
case (WCHAR)'\\' :
|
||
|
case (WCHAR)'/' :
|
||
|
|
||
|
//
|
||
|
// collapse multiple "\" characters.
|
||
|
//
|
||
|
|
||
|
if ( *(Dest-1) != (WCHAR)'\\' ) {
|
||
|
*Dest++ = (WCHAR)'\\';
|
||
|
}
|
||
|
|
||
|
Source++;
|
||
|
break;
|
||
|
|
||
|
case '.' :
|
||
|
|
||
|
//
|
||
|
// Ignore dot in a leading //./
|
||
|
// Eat single dots as in /./
|
||
|
// Double dots back up one level as in /../
|
||
|
// Any other . is just a filename character
|
||
|
//
|
||
|
if ( IS_DOT_U(Source) ) {
|
||
|
Source++;
|
||
|
if (IS_PATH_SEPARATOR_U(*Source)) {
|
||
|
Source++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else if ( IS_DOT_DOT_U(Source) ) {
|
||
|
//
|
||
|
// backup destination string looking for
|
||
|
// a \
|
||
|
//
|
||
|
|
||
|
while (*Dest != (WCHAR)'\\') Dest--;
|
||
|
|
||
|
//
|
||
|
// backup to previous component..
|
||
|
// \a\b\c\.. to \a\b
|
||
|
//
|
||
|
|
||
|
do {
|
||
|
|
||
|
//
|
||
|
// If we bump into root prefix, then
|
||
|
// stay at root
|
||
|
//
|
||
|
|
||
|
if ( Dest == FullPath.Buffer + (BackupIndex-1) ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Dest--;
|
||
|
|
||
|
} while (*Dest != (WCHAR)'\\');
|
||
|
if ( Dest == FullPath.Buffer + (BackupIndex-1) ) {
|
||
|
Dest++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Advance source past ..
|
||
|
//
|
||
|
|
||
|
Source += 2;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// FALLTHRU
|
||
|
//
|
||
|
|
||
|
default:
|
||
|
|
||
|
//
|
||
|
// Copy the filename. The copy will stop
|
||
|
// on "non-portable" characters. Note that
|
||
|
// null and /,\ will stop the copy. If any
|
||
|
// charcter other than null or /,\ is encountered,
|
||
|
// then the pathname is invalid.
|
||
|
//
|
||
|
|
||
|
while ( *Source && !IS_PATH_SEPARATOR_U(*Source) ) {
|
||
|
*Dest++ = *Source++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*Dest = UNICODE_NULL;
|
||
|
|
||
|
if ( StripTrailingSlash ) {
|
||
|
if ( Dest > (FullPath.Buffer + BackupIndex ) && *(Dest-1) == (WCHAR)'\\' ) {
|
||
|
Dest--;
|
||
|
*Dest = UNICODE_NULL;
|
||
|
}
|
||
|
}
|
||
|
FullPath.Length = (USHORT)Dest - (USHORT)FullPath.Buffer;
|
||
|
|
||
|
//
|
||
|
// Locate the file part...
|
||
|
//
|
||
|
|
||
|
Source = lpBuffer;
|
||
|
Dest = NULL;
|
||
|
|
||
|
while(*Source) {
|
||
|
if ( *Source == (WCHAR)'\\' ) {
|
||
|
Dest = Source + 1;
|
||
|
}
|
||
|
Source++;
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT( lpFilePart ) ) {
|
||
|
if ( Dest && *Dest ) {
|
||
|
*lpFilePart = Dest;
|
||
|
}
|
||
|
else {
|
||
|
*lpFilePart = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
if ( DeleteMe.Buffer ) {
|
||
|
RtlFreeUnicodeString(&DeleteMe);
|
||
|
}
|
||
|
RtlReleasePebLock();
|
||
|
}
|
||
|
|
||
|
return FullPath.Length;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RtlGetCurrentDirectory_U(
|
||
|
ULONG nBufferLength,
|
||
|
PWSTR lpBuffer
|
||
|
)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
RtlSetCurrentDirectory_U(
|
||
|
PSTRING PathName
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ANSI_STRING CurDirA;
|
||
|
|
||
|
Status = RtlUnicodeStringToAnsiString(
|
||
|
&CurDirA,
|
||
|
(PUNICODE_STRING)PathName,
|
||
|
TRUE
|
||
|
);
|
||
|
if ( NT_SUCCESS(Status) ) {
|
||
|
Status = RtlSetCurrentDirectory(CurDirA.Buffer);
|
||
|
RtlFreeAnsiString(&CurDirA);
|
||
|
}
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
RtlDosPathNameToNtPathName_U(
|
||
|
IN PWSTR DosFileName,
|
||
|
OUT PUNICODE_STRING NtFileName,
|
||
|
OUT PWSTR *FilePart OPTIONAL,
|
||
|
OUT PRTL_RELATIVE_NAME RelativeName OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
A Dos pathname can be translated into an Nt style pathname
|
||
|
using this function.
|
||
|
|
||
|
This function is used only within the Base dll to translate Dos
|
||
|
pathnames to Nt pathnames. Upon successful translation, the
|
||
|
pointer (NtFileName->Buffer) points to memory from RtlProcessHeap()
|
||
|
that contains the Nt version of the input dos file name.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DosFileName - Supplies the unicode Dos style file name that is to be
|
||
|
translated into an equivalent unicode Nt file name.
|
||
|
|
||
|
NtFileName - Returns the address of memory in the RtlProcessHeap() that
|
||
|
contains an NT filename that refers to the specified Dos file
|
||
|
name.
|
||
|
|
||
|
FilePart - Optional parameter that if specified, returns the
|
||
|
trailing file portion of the file name. A path of \foo\bar\x.x
|
||
|
returns the address of x.x as the file part.
|
||
|
|
||
|
RelativeName - An optional parameter, that if specified, returns
|
||
|
a pathname relative to the current directory of the file. The
|
||
|
length field of RelativeName->RelativeName is 0 if the relative
|
||
|
name can not be used.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The path name translation was successful. Once the caller is
|
||
|
done with the translated name, the memory pointed to by
|
||
|
NtFileName.Buffer should be returned to the RtlProcessHeap().
|
||
|
|
||
|
FALSE - The operation failed.
|
||
|
|
||
|
Note:
|
||
|
The buffers pointed to by RelativeName, FilePart, and NtFileName must ALL
|
||
|
point within the same memory address. If they don't, code that calls
|
||
|
this routine will fail.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
ULONG BufferLength;
|
||
|
ULONG DosPathLength;
|
||
|
PWSTR FullNtPathName = NULL;
|
||
|
PWSTR FullDosPathName = NULL;
|
||
|
UNICODE_STRING Prefix;
|
||
|
UNICODE_STRING UnicodeFilePart;
|
||
|
UNICODE_STRING DeleteMe;
|
||
|
UNICODE_STRING FullDosPathString;
|
||
|
PCURDIR CurDir;
|
||
|
RTL_PATH_TYPE DosPathType;
|
||
|
ULONG DosPathNameOffset;
|
||
|
ULONG FullDosPathNameLength;
|
||
|
ULONG LastCharacter;
|
||
|
|
||
|
//
|
||
|
// Calculate the size needed for the full pathname. Add in
|
||
|
// space for the longest Nt prefix
|
||
|
//
|
||
|
DeleteMe.Buffer = NULL;
|
||
|
|
||
|
DosPathLength = BufferLength = RtlGetFullPathName_U(
|
||
|
DosFileName,
|
||
|
0,
|
||
|
NULL,
|
||
|
FilePart
|
||
|
)+sizeof(UNICODE_NULL);
|
||
|
|
||
|
if ( !BufferLength ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
try {
|
||
|
|
||
|
RtlAcquirePebLock();
|
||
|
|
||
|
//
|
||
|
// The dos name starts just after the longest Nt prefix
|
||
|
//
|
||
|
|
||
|
FullDosPathName = RtlAllocateHeap(RtlProcessHeap(), BufferLength);
|
||
|
|
||
|
if ( !FullDosPathName ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BufferLength += RtlpLongestPrefix;
|
||
|
|
||
|
//
|
||
|
// Allocate space for the full Nt Name (including DOS name portion)
|
||
|
//
|
||
|
|
||
|
FullNtPathName = RtlAllocateHeap(RtlProcessHeap(), BufferLength);
|
||
|
|
||
|
if ( !FullNtPathName ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
FullDosPathNameLength = RtlGetFullPathName_U(
|
||
|
DosFileName,
|
||
|
DosPathLength,
|
||
|
FullDosPathName,
|
||
|
FilePart
|
||
|
);
|
||
|
|
||
|
if ( !FullDosPathNameLength ||
|
||
|
FullDosPathNameLength > DosPathLength ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine how to format prefix of FullNtPathName base on the
|
||
|
// the type of Dos path name. All Nt names begin in the \DosDevices
|
||
|
// directory.
|
||
|
//
|
||
|
|
||
|
Prefix = RtlpDosDevicesPrefix;
|
||
|
|
||
|
DosPathType = RtlDetermineDosPathNameType_U(FullDosPathName);
|
||
|
|
||
|
switch (DosPathType) {
|
||
|
case RtlPathTypeUncAbsolute :
|
||
|
|
||
|
//
|
||
|
// Unc name, use \DosDevices\UNC symbolic link to find
|
||
|
// redirector. Skip of \\ in source Dos path.
|
||
|
//
|
||
|
|
||
|
Prefix = RtlpDosDevicesUncPrefix;
|
||
|
DosPathNameOffset = 2;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeLocalDevice :
|
||
|
|
||
|
//
|
||
|
// Local device name, so just use \DosDevices prefix and
|
||
|
// skip \\.\ in source Dos path.
|
||
|
//
|
||
|
|
||
|
DosPathNameOffset = 4;
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeRootLocalDevice :
|
||
|
|
||
|
ASSERT( FALSE );
|
||
|
break;
|
||
|
|
||
|
case RtlPathTypeDriveAbsolute :
|
||
|
case RtlPathTypeDriveRelative :
|
||
|
case RtlPathTypeRooted :
|
||
|
case RtlPathTypeRelative :
|
||
|
|
||
|
//
|
||
|
// All drive references just use \DosDevices prefix and
|
||
|
// do not skip any of the characters in the source Dos path.
|
||
|
//
|
||
|
|
||
|
DosPathNameOffset = 0;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the full DOS path next to the name prefix, skipping over
|
||
|
// the "\\" at the front of the UNC path or the "\\.\" at the front
|
||
|
// of a device name.
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory(FullNtPathName,Prefix.Buffer,Prefix.Length);
|
||
|
RtlMoveMemory((PUCHAR)FullNtPathName+Prefix.Length,
|
||
|
FullDosPathName + DosPathNameOffset,
|
||
|
FullDosPathNameLength - (DosPathNameOffset<<1));
|
||
|
|
||
|
//
|
||
|
// Null terminate the path name to make strlen below happy.
|
||
|
//
|
||
|
|
||
|
|
||
|
NtFileName->Buffer = FullNtPathName;
|
||
|
NtFileName->Length = (USHORT)(FullDosPathNameLength-(DosPathNameOffset<<1))+Prefix.Length;
|
||
|
NtFileName->MaximumLength = (USHORT)BufferLength;
|
||
|
LastCharacter = NtFileName->Length >> 1;
|
||
|
FullNtPathName[ LastCharacter ] = UNICODE_NULL;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Readjust the file part to point to the appropriate position within
|
||
|
// the FullNtPathName buffer instead of inside the FullDosPathName
|
||
|
// buffer
|
||
|
//
|
||
|
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(FilePart) ) {
|
||
|
if (*FilePart) {
|
||
|
RtlInitUnicodeString(&UnicodeFilePart,*FilePart);
|
||
|
*FilePart = &FullNtPathName[ LastCharacter ] - (UnicodeFilePart.Length >> 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(RelativeName) ) {
|
||
|
|
||
|
//
|
||
|
// If the current directory is a sub-string of the
|
||
|
// Nt file name, and if a handle exists for the current
|
||
|
// directory, then return the directory handle and name
|
||
|
// relative to the directory.
|
||
|
//
|
||
|
|
||
|
RelativeName->RelativeName.Length = 0;
|
||
|
RelativeName->RelativeName.MaximumLength = 0;
|
||
|
RelativeName->RelativeName.Buffer = 0;
|
||
|
RelativeName->ContainingDirectory = NULL;
|
||
|
|
||
|
CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
|
||
|
|
||
|
if ( CurDir->Handle ) {
|
||
|
|
||
|
//
|
||
|
// Until unicode curdir...
|
||
|
//
|
||
|
|
||
|
RtlAnsiStringToUnicodeString(
|
||
|
&DeleteMe,
|
||
|
(PANSI_STRING)&CurDir->DosPath,
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Now compare curdir to full dos path. If curdir length is
|
||
|
// greater than full path. It is not a match. Otherwise,
|
||
|
// trim full path length to cur dir length and compare.
|
||
|
//
|
||
|
|
||
|
RtlInitUnicodeString(&FullDosPathString,FullDosPathName);
|
||
|
|
||
|
if ( DeleteMe.Length <= FullDosPathString.Length ) {
|
||
|
FullDosPathString.Length = DeleteMe.Length;
|
||
|
if ( !RtlCompareString(
|
||
|
(PSTRING)&DeleteMe,
|
||
|
(PSTRING)&FullDosPathString,
|
||
|
TRUE
|
||
|
) ) {
|
||
|
|
||
|
//
|
||
|
// The full dos pathname is a substring of the
|
||
|
// current directory. Compute the start of the
|
||
|
// relativename.
|
||
|
//
|
||
|
|
||
|
RelativeName->RelativeName.Buffer = ((PUCHAR)FullNtPathName + Prefix.Length + (CurDir->DosPath.Length<<1));
|
||
|
RelativeName->RelativeName.Length = (USHORT)FullDosPathNameLength - (CurDir->DosPath.Length<<1);
|
||
|
if ( *(PWSTR)(RelativeName->RelativeName.Buffer) == (WCHAR)'\\' ) {
|
||
|
(PWSTR)(RelativeName->RelativeName.Buffer)++;
|
||
|
RelativeName->RelativeName.Length -= 2;
|
||
|
}
|
||
|
RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length;
|
||
|
RelativeName->ContainingDirectory = CurDir->Handle;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
|
||
|
if ( DeleteMe.Buffer ) {
|
||
|
RtlFreeUnicodeString(&DeleteMe);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Always free up the DOS path name - it was allocated as temp storage.
|
||
|
//
|
||
|
|
||
|
if ( FullDosPathName ) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), FullDosPathName, 0);
|
||
|
}
|
||
|
|
||
|
if ( AbnormalTermination() ) {
|
||
|
if ( FullNtPathName ) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), FullNtPathName, 0);
|
||
|
}
|
||
|
|
||
|
RtlReleasePebLock();
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ASSERT (NtFileName->Length < MAXIMUM_FILENAME_LENGTH);
|
||
|
ASSERT (NtFileName->MaximumLength < MAXIMUM_FILENAME_LENGTH);
|
||
|
|
||
|
if (ARGUMENT_PRESENT(RelativeName)) {
|
||
|
ASSERT (NtFileName->Length < MAXIMUM_FILENAME_LENGTH);
|
||
|
ASSERT (NtFileName->MaximumLength < MAXIMUM_FILENAME_LENGTH);
|
||
|
}
|
||
|
|
||
|
RtlReleasePebLock();
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RtlDosSearchPath_U(
|
||
|
IN PWSTR lpPath,
|
||
|
IN PWSTR lpFileName,
|
||
|
IN PWSTR lpExtension OPTIONAL,
|
||
|
IN ULONG nBufferLength,
|
||
|
OUT PWSTR lpBuffer,
|
||
|
OUT PWSTR *lpFilePart
|
||
|
)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
RtlDoesFileExists_U(
|
||
|
IN PWSTR FileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function checks to see if the specified unicode filename exists.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FileName - Supplies the file name of the file to find.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - The file was found.
|
||
|
|
||
|
FALSE - The file was not found.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
OBJECT_ATTRIBUTES Obja;
|
||
|
HANDLE Handle;
|
||
|
UNICODE_STRING NtFileName;
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
BOOLEAN ReturnValue;
|
||
|
RTL_RELATIVE_NAME RelativeName;
|
||
|
PVOID FreeBuffer;
|
||
|
|
||
|
ReturnValue = RtlDosPathNameToNtPathName_U(
|
||
|
FileName,
|
||
|
&NtFileName,
|
||
|
NULL,
|
||
|
&RelativeName
|
||
|
);
|
||
|
|
||
|
if ( !ReturnValue ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
FreeBuffer = NtFileName.Buffer;
|
||
|
|
||
|
if ( RelativeName.RelativeName.Length ) {
|
||
|
NtFileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
|
||
|
}
|
||
|
else {
|
||
|
RelativeName.ContainingDirectory = NULL;
|
||
|
}
|
||
|
|
||
|
InitializeObjectAttributes_U(
|
||
|
&Obja,
|
||
|
&NtFileName,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
RelativeName.ContainingDirectory,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Open the file
|
||
|
//
|
||
|
|
||
|
Status = NtOpenFile(
|
||
|
&Handle,
|
||
|
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
||
|
&Obja,
|
||
|
&IoStatusBlock,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
FILE_SYNCHRONOUS_IO_NONALERT
|
||
|
);
|
||
|
RtlFreeHeap(RtlProcessHeap(),FreeBuffer,0);
|
||
|
NtClose(Handle);
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
if ( Status == STATUS_SHARING_VIOLATION ||
|
||
|
Status == STATUS_ACCESS_DENIED ) {
|
||
|
ReturnValue = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ReturnValue = TRUE;
|
||
|
}
|
||
|
return ReturnValue;
|
||
|
}
|
||
|
|
||
|
PUNICODE_STRING
|
||
|
RtlQueryNtPrefix_U(
|
||
|
IN PWSTR FullDosPathName
|
||
|
)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef UNICODE_CHECK
|
||
|
VOID
|
||
|
CheckDetermineDosPathNameType(
|
||
|
IN PSZ DosFileName,
|
||
|
IN RTL_PATH_TYPE PathType
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
RTL_PATH_TYPE UPathType;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
|
||
|
RtlInitString(&AnsiString,DosFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
|
||
|
UPathType = RtlDetermineDosPathNameType_U(UnicodeString.Buffer);
|
||
|
if (UPathType != PathType) {
|
||
|
DbgPrint("CheckDetermineDosPathNameType(%s,%d) == %d\n",
|
||
|
DosFileName,
|
||
|
PathType,
|
||
|
UPathType
|
||
|
);
|
||
|
DbgPrint("UnicodeString at %lx AnsiString at %lx\n",&UnicodeString,&AnsiString);
|
||
|
}
|
||
|
ASSERT(UPathType == PathType);
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CheckIsDosDeviceName(
|
||
|
IN PSZ DosFileName,
|
||
|
IN ULONG Length
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG ULength;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
|
||
|
RtlInitString(&AnsiString,DosFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
|
||
|
ULength = RtlIsDosDeviceName_U(UnicodeString.Buffer);
|
||
|
ULength >>= 1;
|
||
|
if (ULength != Length) {
|
||
|
DbgPrint("CheckIsDosDeviceName(%s,%d) == %d\n",
|
||
|
DosFileName,
|
||
|
Length,
|
||
|
ULength
|
||
|
);
|
||
|
DbgPrint("UnicodeString at %lx AnsiString at %lx\n",&UnicodeString,&AnsiString);
|
||
|
}
|
||
|
ASSERT(ULength == Length);
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CheckFullPathName(
|
||
|
PSZ lpFileName,
|
||
|
ULONG nBufferLength,
|
||
|
PSZ lpBuffer,
|
||
|
PSZ *lpFilePart,
|
||
|
ULONG ReturnedBufferLength
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG UnicodeLength;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
UNICODE_STRING UnicodeResult;
|
||
|
ANSI_STRING AnsiString;
|
||
|
ANSI_STRING AnsiResult;
|
||
|
PWSTR Ubuff;
|
||
|
PWSTR FilePart;
|
||
|
PWSTR *FilePartPtr;
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
||
|
FilePartPtr = &FilePart;
|
||
|
}
|
||
|
else {
|
||
|
FilePartPtr = NULL;
|
||
|
}
|
||
|
|
||
|
RtlInitString(&AnsiString,lpFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
Ubuff = RtlAllocateHeap(RtlProcessHeap(),512);
|
||
|
|
||
|
UnicodeLength = RtlGetFullPathName_U(
|
||
|
UnicodeString.Buffer,
|
||
|
510,
|
||
|
Ubuff,
|
||
|
FilePartPtr
|
||
|
);
|
||
|
UnicodeLength >>= 1;
|
||
|
if (UnicodeLength != ReturnedBufferLength) {
|
||
|
DbgPrint("CheckFullPathName(\n%s,\n%d,\n%s,\n,%d) == %d\n",
|
||
|
lpFileName,
|
||
|
nBufferLength,
|
||
|
lpBuffer,
|
||
|
ReturnedBufferLength,
|
||
|
UnicodeLength
|
||
|
);
|
||
|
DbgPrint("UnicodeString at %lx AnsiString at %lx\n",&UnicodeString,&AnsiString);
|
||
|
DbgPrint("Ubuff %lx\n",Ubuff);
|
||
|
DbgBreakPoint();
|
||
|
UnicodeLength = RtlGetFullPathName_U(
|
||
|
UnicodeString.Buffer,
|
||
|
510,
|
||
|
Ubuff,
|
||
|
FilePartPtr
|
||
|
);
|
||
|
|
||
|
}
|
||
|
ASSERT(UnicodeLength == ReturnedBufferLength);
|
||
|
if ( UnicodeLength ) {
|
||
|
RtlInitUnicodeString(&UnicodeResult,UnicodeString.Buffer);
|
||
|
RtlUnicodeStringToAnsiString(&AnsiResult,&UnicodeResult,TRUE);
|
||
|
if ( strcmp(lpFileName,AnsiResult.Buffer) ) {
|
||
|
DbgPrint("CheckFullPathName(\n%s,\n%d,\n%s,\n,%d) == %d\n",
|
||
|
lpFileName,
|
||
|
nBufferLength,
|
||
|
lpBuffer,
|
||
|
ReturnedBufferLength,
|
||
|
UnicodeLength
|
||
|
);
|
||
|
DbgPrint("Ansi %s == Uni %s\n",lpFileName,AnsiResult.Buffer);
|
||
|
}
|
||
|
ASSERT( !strcmp(lpFileName,AnsiResult.Buffer) );
|
||
|
RtlFreeAnsiString(&AnsiResult);
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
||
|
if ( *lpFilePart == NULL ) {
|
||
|
ASSERT(FilePart == NULL);
|
||
|
}
|
||
|
else {
|
||
|
UNICODE_STRING UnicodeFilePart;
|
||
|
ANSI_STRING AnsiFilePart;
|
||
|
|
||
|
ASSERT(FilePart);
|
||
|
|
||
|
RtlInitUnicodeString(&UnicodeFilePart,FilePart);
|
||
|
RtlUnicodeStringToAnsiString(&AnsiFilePart,&UnicodeFilePart,TRUE);
|
||
|
if ( strcmp(*lpFilePart,AnsiFilePart.Buffer) ) {
|
||
|
DbgPrint("CheckFullPathName(\n%s,\n%d,\n%s,\n,%d) == %d\n",
|
||
|
lpFileName,
|
||
|
nBufferLength,
|
||
|
lpBuffer,
|
||
|
ReturnedBufferLength,
|
||
|
UnicodeLength
|
||
|
);
|
||
|
DbgPrint("Ansi FP %s == Uni FP %s\n",*lpFilePart,AnsiFilePart.Buffer);
|
||
|
}
|
||
|
ASSERT( !strcmp(*lpFilePart,AnsiFilePart.Buffer) );
|
||
|
RtlFreeAnsiString(&AnsiFilePart);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
RtlFreeHeap(RtlProcessHeap(),Ubuff,0);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CheckDosPathNameToNtPathName(
|
||
|
PSZ DosFileName,
|
||
|
PSTRING NtFileName,
|
||
|
PSZ *FilePart OPTIONAL,
|
||
|
PRTL_RELATIVE_NAME RelativeName OPTIONAL
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
UNICODE_STRING UnicodeResult;
|
||
|
ANSI_STRING AnsiString;
|
||
|
ANSI_STRING AnsiResult;
|
||
|
PWSTR UFilePart;
|
||
|
PWSTR *UFilePartPtr;
|
||
|
RTL_RELATIVE_NAME UnicodeRelativeName;
|
||
|
PRTL_RELATIVE_NAME UnicodeRelativeNamePtr;
|
||
|
BOOLEAN b;
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(RelativeName) ) {
|
||
|
UnicodeRelativeNamePtr = &UnicodeRelativeName;
|
||
|
}
|
||
|
else {
|
||
|
UnicodeRelativeNamePtr = NULL;
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(FilePart) ) {
|
||
|
UFilePartPtr = &UFilePart;
|
||
|
}
|
||
|
else {
|
||
|
UFilePartPtr = NULL;
|
||
|
}
|
||
|
|
||
|
RtlInitString(&AnsiString,DosFileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
b = RtlDosPathNameToNtPathName_U(
|
||
|
UnicodeString.Buffer,
|
||
|
&UnicodeResult,
|
||
|
UFilePartPtr,
|
||
|
UnicodeRelativeNamePtr
|
||
|
);
|
||
|
ASSERT(b);
|
||
|
|
||
|
RtlUnicodeStringToAnsiString(&AnsiResult,&UnicodeResult,TRUE);
|
||
|
if ( RtlCompareString(NtFileName,(PSTRING)&AnsiResult,TRUE) ) {
|
||
|
DbgPrint("CheckDosPathNameToNtPathName(\n%s,\n%s)\n\t== %s\n",
|
||
|
DosFileName,
|
||
|
NtFileName->Buffer,
|
||
|
AnsiResult.Buffer
|
||
|
);
|
||
|
DbgPrint("Ansi %s == Uni %s\n",DosFileName,AnsiResult.Buffer);
|
||
|
}
|
||
|
ASSERT(!RtlCompareString(NtFileName,(PSTRING)&AnsiResult,TRUE));
|
||
|
RtlFreeAnsiString(&AnsiResult);
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(FilePart) ) {
|
||
|
if ( *FilePart == NULL ) {
|
||
|
ASSERT(UFilePart == NULL);
|
||
|
}
|
||
|
else {
|
||
|
UNICODE_STRING UnicodeFilePart;
|
||
|
ANSI_STRING AnsiFilePart;
|
||
|
|
||
|
ASSERT(UFilePart);
|
||
|
|
||
|
RtlInitUnicodeString(&UnicodeFilePart,UFilePart);
|
||
|
RtlUnicodeStringToAnsiString(&AnsiFilePart,&UnicodeFilePart,TRUE);
|
||
|
if ( strcmpi(*FilePart,AnsiFilePart.Buffer) ) {
|
||
|
DbgPrint("CheckDosPathNameToNtPathName(\n%s,\n%s,\n) == %S\n",
|
||
|
DosFileName,
|
||
|
NtFileName->Buffer,
|
||
|
AnsiResult.Buffer
|
||
|
);
|
||
|
DbgPrint("Ansi FP %s == Uni FP %s\n",*FilePart,AnsiFilePart.Buffer);
|
||
|
}
|
||
|
ASSERT( !strcmpi(*FilePart,AnsiFilePart.Buffer) );
|
||
|
RtlFreeAnsiString(&AnsiFilePart);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ARGUMENT_PRESENT(RelativeName) ) {
|
||
|
ANSI_STRING AnsiRName;
|
||
|
if ( UnicodeRelativeName.RelativeName.Length ) {
|
||
|
if ( UnicodeRelativeName.ContainingDirectory != RelativeName->ContainingDirectory ) {
|
||
|
DbgPrint("CheckDosPathNameToNtPathName(\n%s,\n%s,\n) == %s\n",
|
||
|
DosFileName,
|
||
|
NtFileName->Buffer,
|
||
|
AnsiResult.Buffer
|
||
|
);
|
||
|
DbgPrint("UContainingDirectory %lx AContainingDirectory %lx\n",
|
||
|
UnicodeRelativeName.ContainingDirectory,
|
||
|
RelativeName->ContainingDirectory
|
||
|
);
|
||
|
}
|
||
|
ASSERT(UnicodeRelativeName.ContainingDirectory == RelativeName->ContainingDirectory );
|
||
|
RtlUnicodeStringToAnsiString(&AnsiRName,(PUNICODE_STRING)&UnicodeRelativeName.RelativeName,TRUE);
|
||
|
if ( strcmpi(RelativeName->RelativeName.Buffer,AnsiRName.Buffer) ) {
|
||
|
DbgPrint("CheckDosPathNameToNtPathName(\n%s,\n%s,\n) == %S\n",
|
||
|
DosFileName,
|
||
|
NtFileName->Buffer,
|
||
|
AnsiResult.Buffer
|
||
|
);
|
||
|
DbgPrint("Ansi Rn %s == Uni Rn %s\n",RelativeName->RelativeName.Buffer,AnsiRName.Buffer);
|
||
|
}
|
||
|
ASSERT( !strcmpi(RelativeName->RelativeName.Buffer,AnsiRName.Buffer) );
|
||
|
RtlFreeAnsiString(&AnsiRName);
|
||
|
}
|
||
|
}
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
RtlFreeHeap(RtlProcessHeap(),UnicodeResult.Buffer,0);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CheckDosFileExist(
|
||
|
PSZ FileName,
|
||
|
BOOLEAN ReturnValue
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
BOOLEAN UnicodeReturnValue;
|
||
|
|
||
|
RtlInitString(&AnsiString,FileName);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
|
||
|
UnicodeReturnValue = RtlDoesFileExists_U(UnicodeString.Buffer);
|
||
|
if (UnicodeReturnValue != ReturnValue) {
|
||
|
DbgPrint("CheckDoesFileExist(%s) Faile\n",
|
||
|
FileName
|
||
|
);
|
||
|
DbgPrint("UnicodeString at %lx AnsiString at %lx\n",&UnicodeString,&AnsiString);
|
||
|
}
|
||
|
ASSERT(UnicodeReturnValue == ReturnValue );
|
||
|
RtlFreeUnicodeString(&UnicodeString);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif // UNICODE_CHECK
|