Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3743 lines
109 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
pathmisc.c
Abstract:
Win32 misceleneous path functions
Author:
Mark Lucovsky (markl) 16-Oct-1990
Revision History:
--*/
#include "basedll.h"
#include "apcompat.h"
#include <wow64t.h>
BOOL
IsThisARootDirectory(
HANDLE RootHandle,
PUNICODE_STRING FileName OPTIONAL
)
{
PFILE_NAME_INFORMATION FileNameInfo;
WCHAR Buffer[MAX_PATH+sizeof(FileNameInfo)];
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
BOOL rv;
OBJECT_ATTRIBUTES Attributes;
HANDLE LinkHandle;
WCHAR LinkValueBuffer[2*MAX_PATH];
UNICODE_STRING LinkValue;
ULONG ReturnedLength;
rv = FALSE;
FileNameInfo = (PFILE_NAME_INFORMATION)Buffer;
if (RootHandle == NULL) {
Status = STATUS_INVALID_HANDLE;
} else {
Status = NtQueryInformationFile (RootHandle,
&IoStatusBlock,
FileNameInfo,
sizeof(Buffer),
FileNameInformation);
}
if (NT_SUCCESS (Status)) {
if ( FileNameInfo->FileName[(FileNameInfo->FileNameLength>>1)-1] == (WCHAR)'\\' ) {
rv = TRUE;
}
}
if ( !rv ) {
//
// See if this is a dos substed drive (or) redirected net drive
//
if (ARGUMENT_PRESENT (FileName)) {
FileName->Length = FileName->Length - sizeof((WCHAR)'\\');
InitializeObjectAttributes( &Attributes,
FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenSymbolicLinkObject (&LinkHandle,
SYMBOLIC_LINK_QUERY,
&Attributes);
FileName->Length = FileName->Length + sizeof((WCHAR)'\\');
if (NT_SUCCESS (Status)) {
//
// Now query the link and see if there is a redirection
//
LinkValue.Buffer = LinkValueBuffer;
LinkValue.Length = 0;
LinkValue.MaximumLength = (USHORT)(sizeof(LinkValueBuffer));
ReturnedLength = 0;
Status = NtQuerySymbolicLinkObject( LinkHandle,
&LinkValue,
&ReturnedLength
);
NtClose( LinkHandle );
if ( NT_SUCCESS(Status) ) {
rv = TRUE;
}
}
}
}
return rv;
}
UINT
APIENTRY
GetSystemDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
ANSI thunk to GetSystemDirectoryW
--*/
{
ANSI_STRING AnsiString;
NTSTATUS Status;
ULONG cbAnsiString;
PUNICODE_STRING WindowsSystemDirectory = &BaseWindowsSystemDirectory;
#ifdef WX86
if (NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll) {
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
WindowsSystemDirectory = &BaseWindowsSys32x86Directory;
}
#endif
// BaseWindowsSystemDirectory.Length contains the byte
// count of unicode string.
// Original code does "UnicodeLength / sizeof(WCHAR)" to
// get the size of corresponding ansi string.
// This is correct in SBCS environment. However in DBCS
// environment, it's definitely WRONG.
Status = RtlUnicodeToMultiByteSize(&cbAnsiString,
WindowsSystemDirectory->Buffer,
WindowsSystemDirectory->MaximumLength
);
if ( !NT_SUCCESS(Status) ) {
return 0;
}
if ( (USHORT)uSize < (USHORT)cbAnsiString ) {
return cbAnsiString;
}
AnsiString.MaximumLength = (USHORT)(uSize);
AnsiString.Buffer = lpBuffer;
Status = BasepUnicodeStringTo8BitString(
&AnsiString,
WindowsSystemDirectory,
FALSE
);
if ( !NT_SUCCESS(Status) ) {
return 0;
}
return AnsiString.Length;
}
UINT
APIENTRY
GetSystemDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the Windows system
subdirectory. The system subdirectory contains such files as
Windows libraries, drivers, and font files.
The pathname retrieved by this function does not end with a
backslash unless the system directory is the root directory. For
example, if the system directory is named WINDOWS\SYSTEM on drive
C:, the pathname of the system subdirectory retrieved by this
function is C:\WINDOWS\SYSTEM.
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in WCHARs) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the 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 uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
PUNICODE_STRING WindowsSystemDirectory = &BaseWindowsSystemDirectory;
#ifdef WX86
if (NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll) {
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
WindowsSystemDirectory = &BaseWindowsSys32x86Directory;
}
#endif
if ( uSize*2 < WindowsSystemDirectory->MaximumLength ) {
return WindowsSystemDirectory->MaximumLength/2;
}
RtlCopyMemory(
lpBuffer,
WindowsSystemDirectory->Buffer,
WindowsSystemDirectory->Length
);
lpBuffer[(WindowsSystemDirectory->Length>>1)] = UNICODE_NULL;
return WindowsSystemDirectory->Length/2;
}
UINT
APIENTRY
GetSystemWindowsDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
ANSI thunk to GetSystemWindowsDirectoryW
--*/
{
ANSI_STRING AnsiString;
NTSTATUS Status;
ULONG cbAnsiString;
// BaseWindowsDirectory.Length contains the byte
// count of unicode string.
// Original code does "UnicodeLength / sizeof(WCHAR)" to
// get the size of corresponding ansi string.
// This is correct in SBCS environment. However in DBCS
// environment, it's definitely WRONG.
Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
BaseWindowsDirectory.Buffer,
BaseWindowsDirectory.MaximumLength);
if ( !NT_SUCCESS(Status) ) {
return 0;
}
if ( (USHORT)uSize < (USHORT)cbAnsiString ) {
return cbAnsiString;
}
AnsiString.MaximumLength = (USHORT)(uSize);
AnsiString.Buffer = lpBuffer;
Status = BasepUnicodeStringTo8BitString(
&AnsiString,
&BaseWindowsDirectory,
FALSE
);
if ( !NT_SUCCESS(Status) ) {
return 0;
}
return AnsiString.Length;
}
UINT
APIENTRY
GetSystemWindowsDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the system Windows directory.
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in wchars) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the 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 uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
if ( uSize*2 < BaseWindowsDirectory.MaximumLength ) {
return BaseWindowsDirectory.MaximumLength/2;
}
RtlCopyMemory(
lpBuffer,
BaseWindowsDirectory.Buffer,
BaseWindowsDirectory.Length
);
lpBuffer[(BaseWindowsDirectory.Length>>1)] = UNICODE_NULL;
return BaseWindowsDirectory.Length/2;
}
UINT
APIENTRY
GetSystemWow64DirectoryA(
LPSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the system wow64 directory.
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in bytes) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the 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 uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
#if ! defined(BUILD_WOW6432) && ! defined(_WIN64)
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
#else // BUILD_WOW6432 || _WIN64
const CHAR syswowdir[] = "\\" WOW64_SYSTEM_DIRECTORY;
UINT Available, Needed;
if (uSize < sizeof(syswowdir)) {
// We don't even have enough room to hold the syswow64
// subdirectory component, much less the whole path. Pass in a
// zero length so that we get back the length needed.
Available = 0;
} else {
// We might have enough room; decrement the size passed in by the
// amount of overhead we'll use.
Available = uSize - sizeof(syswowdir) + 1 /* NULL compensation */;
}
Needed = GetSystemWindowsDirectoryA(lpBuffer, Available);
if (Needed == 0) {
// The call failed -- just return zero.
return 0;
}
if (Needed <= Available) {
// We had enough buffer space, even with our overhead; we can go
// ahead and tack on the syswow64 directory name.
RtlCopyMemory(lpBuffer + Needed,
syswowdir,
sizeof(syswowdir));
}
return (Needed + sizeof(syswowdir) - 1);
#endif // BUILD_WOW6432 || _WIN64
}
UINT
APIENTRY
GetSystemWow64DirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the system wow64 directory.
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in wchars) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the 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 uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
#if ! defined(BUILD_WOW6432) && ! defined(_WIN64)
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
#else // BUILD_WOW6432 || _WIN64
const WCHAR syswowdir[] = L"\\" WOW64_SYSTEM_DIRECTORY_U;
UINT Available, Needed;
const UINT SysWCharSize = sizeof(syswowdir) / sizeof(WCHAR);
if (uSize < SysWCharSize) {
// We don't even have enough room to hold the syswow64
// subdirectory component, much less the whole path. Pass in a
// zero length so that we get back the length needed.
Available = 0;
} else {
// We might have enough room; decrement the size passed in by the
// amount of overhead we'll use.
Available = uSize - SysWCharSize + 1 /* NULL compensation */;
}
Needed = GetSystemWindowsDirectoryW(lpBuffer, Available);
if (Needed == 0) {
// The call failed -- just return zero.
return 0;
}
if (Needed <= Available) {
// We had enough buffer space, even with our overhead; we can go
// ahead and tack on the syswow64 directory name.
RtlCopyMemory(lpBuffer + Needed,
syswowdir,
sizeof(syswowdir));
}
return (Needed + SysWCharSize - 1);
#endif // BUILD_WOW6432 || _WIN64
}
UINT
APIENTRY
GetWindowsDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
--*/
{
if (gpTermsrvGetWindowsDirectoryA) {
//
// If Terminal Server get the Per User Windows Directory
//
UINT retval;
if (retval = gpTermsrvGetWindowsDirectoryA(lpBuffer, uSize)) {
return retval;
}
}
return GetSystemWindowsDirectoryA(lpBuffer,uSize);
}
UINT
APIENTRY
GetWindowsDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the Windows directory. The
Windows directory contains such files as Windows applications,
initialization files, and help files.
425
The pathname retrieved by this function does not end with a
backslash unless the Windows directory is the root directory. For
example, if the Windows directory is named WINDOWS on drive C:, the
pathname of the Windows directory retrieved by this function is
C:\WINDOWS If Windows was installed in the root directory of drive
C:, the pathname retrieved by this function is C:\
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in bytes) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the 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 uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
if (gpTermsrvGetWindowsDirectoryW) {
//
// If Terminal Server get the Per User Windows Directory
//
UINT retval;
if (retval = gpTermsrvGetWindowsDirectoryW(lpBuffer, uSize)) {
return retval;
}
}
return GetSystemWindowsDirectoryW(lpBuffer,uSize);
}
UINT
APIENTRY
GetDriveTypeA(
LPCSTR lpRootPathName
)
/*++
Routine Description:
ANSI thunk to GetDriveTypeW
--*/
{
PUNICODE_STRING Unicode;
LPCWSTR lpRootPathName_U;
if (ARGUMENT_PRESENT(lpRootPathName)) {
Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
if (Unicode == NULL) {
return 1;
}
lpRootPathName_U = (LPCWSTR)Unicode->Buffer;
}
else {
lpRootPathName_U = NULL;
}
return GetDriveTypeW(lpRootPathName_U);
}
UINT
APIENTRY
GetDriveTypeW(
LPCWSTR lpRootPathName
)
/*++
Routine Description:
This function determines whether a disk drive is removeable, fixed,
remote, CD ROM, or a RAM disk.
The return value is zero if the function cannot determine the drive
type, or 1 if the specified root directory does not exist.
Arguments:
lpRootPathName - An optional parameter, that if specified, supplies
the root directory of the disk whose drive type is to be
determined. If this parameter is not specified, then the root
of the current directory is used.
Return Value:
The return value specifies the type of drive. It can be one of the
following values:
DRIVE_UNKNOWN - The drive type can not be determined.
DRIVE_NO_ROOT_DIR - The root directory does not exist.
DRIVE_REMOVABLE - Disk can be removed from the drive.
DRIVE_FIXED - Disk cannot be removed from the drive.
DRIVE_REMOTE - Drive is a remote (network) drive.
DRIVE_CDROM - Drive is a CD rom drive.
DRIVE_RAMDISK - Drive is a RAM disk.
--*/
{
WCHAR wch;
ULONG n, DriveNumber;
WCHAR DefaultPath[MAX_PATH];
PWSTR RootPathName;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName, volumeNameString;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
DWORD ReturnValue;
FILE_FS_DEVICE_INFORMATION DeviceInfo;
PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
WCHAR volumeName[MAX_PATH];
if (!ARGUMENT_PRESENT(lpRootPathName)) {
n = RtlGetCurrentDirectory_U(sizeof(DefaultPath), DefaultPath);
RootPathName = DefaultPath;
if (n > (3 * sizeof(WCHAR))) {
RootPathName[3]=UNICODE_NULL;
}
}
else
if (lpRootPathName == (PWSTR)IntToPtr(0xFFFFFFFF)) {
//
// Hack to be compatible with undocumented feature of old
// implementation.
//
return 0;
}
else {
//
// If input string is just C: then convert to C:\ so it does
// not default to current directory which may or may not be
// at the root.
//
RootPathName = (PWSTR)lpRootPathName;
if (wcslen( RootPathName ) == 2) {
wch = RtlUpcaseUnicodeChar( *RootPathName );
if (wch >= (WCHAR)'A' &&
wch <= (WCHAR)'Z' &&
RootPathName[1] == (WCHAR)':'
) {
RootPathName = wcscpy(DefaultPath, lpRootPathName);
RootPathName[2] = (WCHAR)'\\';
RootPathName[3] = UNICODE_NULL;
}
}
}
//
// If input string is of the form C:\ then look in the drive letter
// cache maintained by the kernel to see if the drive type is already
// known.
//
wch = RtlUpcaseUnicodeChar( *RootPathName );
if (wch >= (WCHAR)'A' &&
wch <= (WCHAR)'Z' &&
RootPathName[1]==(WCHAR)':' &&
RootPathName[2]==(WCHAR)'\\' &&
RootPathName[3]==UNICODE_NULL
) {
Status = NtQueryInformationProcess( NtCurrentProcess(),
ProcessDeviceMap,
&ProcessDeviceMapInfo.Query,
sizeof( ProcessDeviceMapInfo.Query ),
NULL
);
if (!NT_SUCCESS( Status )) {
RtlZeroMemory( &ProcessDeviceMapInfo, sizeof( ProcessDeviceMapInfo ) );
}
DriveNumber = wch - (WCHAR)'A';
if (ProcessDeviceMapInfo.Query.DriveMap & (1 << DriveNumber)) {
switch ( ProcessDeviceMapInfo.Query.DriveType[ DriveNumber ] ) {
case DOSDEVICE_DRIVE_UNKNOWN:
return DRIVE_UNKNOWN;
case DOSDEVICE_DRIVE_REMOVABLE:
return DRIVE_REMOVABLE;
case DOSDEVICE_DRIVE_FIXED:
return DRIVE_FIXED;
case DOSDEVICE_DRIVE_REMOTE:
return DRIVE_REMOTE;
case DOSDEVICE_DRIVE_CDROM:
return DRIVE_CDROM;
case DOSDEVICE_DRIVE_RAMDISK:
return DRIVE_RAMDISK;
}
}
}
//
// Either not C:\ or kernel does not know the drive type, so try to
// calculate the drive type by opening the root directory and doing
// a query volume information.
//
//
// If curdir is a UNC connection, and default path is used,
// the RtlGetCurrentDirectory logic is wrong, so throw it away.
//
if (!ARGUMENT_PRESENT(lpRootPathName)) {
RootPathName = L"\\";
}
TranslationStatus = RtlDosPathNameToNtPathName_U( RootPathName,
&FileName,
NULL,
NULL
);
if (!TranslationStatus) {
return DRIVE_NO_ROOT_DIR;
}
FreeBuffer = FileName.Buffer;
//
// Check to make sure a root was specified
//
if (FileName.Buffer[(FileName.Length >> 1)-1] != '\\') {
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
return DRIVE_NO_ROOT_DIR;
}
FileName.Length -= 2;
InitializeObjectAttributes( &Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
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 | FILE_NON_DIRECTORY_FILE
);
//
//
// substd drives are really directories, so if we are dealing with one
// of them, bypass this
//
if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
if (BasepGetVolumeNameFromReparsePoint(lpRootPathName, volumeName,
MAX_PATH, NULL)) {
RtlInitUnicodeString(&volumeNameString, volumeName);
volumeNameString.Buffer[1] = '?';
volumeNameString.Length -= sizeof(WCHAR);
InitializeObjectAttributes( &Obja,
&volumeNameString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
}
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
}
else {
//
// check for substed drives another way just in case
//
FileName.Length = FileName.Length + sizeof((WCHAR)'\\');
if (!IsThisARootDirectory(NULL,&FileName) ) {
FileName.Length = FileName.Length - sizeof((WCHAR)'\\');
if (NT_SUCCESS(Status)) {
NtClose(Handle);
}
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
}
}
RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer );
if (!NT_SUCCESS( Status )) {
return DRIVE_NO_ROOT_DIR;
}
//
// Determine if this is a network or disk file system. If it
// is a disk file system determine if this is removable or not
//
Status = NtQueryVolumeInformationFile( Handle,
&IoStatusBlock,
&DeviceInfo,
sizeof(DeviceInfo),
FileFsDeviceInformation
);
if (!NT_SUCCESS( Status )) {
ReturnValue = DRIVE_UNKNOWN;
}
else
if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) {
ReturnValue = DRIVE_REMOTE;
}
else {
switch (DeviceInfo.DeviceType) {
case FILE_DEVICE_NETWORK:
case FILE_DEVICE_NETWORK_FILE_SYSTEM:
ReturnValue = DRIVE_REMOTE;
break;
case FILE_DEVICE_CD_ROM:
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
ReturnValue = DRIVE_CDROM;
break;
case FILE_DEVICE_VIRTUAL_DISK:
ReturnValue = DRIVE_RAMDISK;
break;
case FILE_DEVICE_DISK:
case FILE_DEVICE_DISK_FILE_SYSTEM:
if ( DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA ) {
ReturnValue = DRIVE_REMOVABLE;
}
else {
ReturnValue = DRIVE_FIXED;
}
break;
default:
ReturnValue = DRIVE_UNKNOWN;
break;
}
}
NtClose( Handle );
return ReturnValue;
}
DWORD
APIENTRY
SearchPathA(
LPCSTR lpPath,
LPCSTR lpFileName,
LPCSTR lpExtension,
DWORD nBufferLength,
LPSTR lpBuffer,
LPSTR *lpFilePart
)
/*++
Routine Description:
ANSI thunk to SearchPathW
--*/
{
UNICODE_STRING xlpPath;
PUNICODE_STRING Unicode;
UNICODE_STRING xlpExtension;
PWSTR xlpBuffer;
DWORD ReturnValue;
NTSTATUS Status;
PWSTR FilePart;
PWSTR *FilePartPtr;
if ( ARGUMENT_PRESENT(lpFilePart) ) {
FilePartPtr = &FilePart;
}
else {
FilePartPtr = NULL;
}
Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
if (Unicode == NULL) {
return 0;
}
if ( ARGUMENT_PRESENT(lpExtension) ) {
if (!Basep8BitStringToDynamicUnicodeString( &xlpExtension, lpExtension )) {
return 0;
}
} else {
xlpExtension.Buffer = NULL;
}
if ( ARGUMENT_PRESENT(lpPath) ) {
if (!Basep8BitStringToDynamicUnicodeString( &xlpPath, lpPath )) {
if ( ARGUMENT_PRESENT(lpExtension) ) {
RtlFreeUnicodeString(&xlpExtension);
}
return 0;
}
} else {
xlpPath.Buffer = NULL;
}
xlpBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nBufferLength<<1);
if ( !xlpBuffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
ReturnValue = 0;
goto bail0;
}
ReturnValue = SearchPathW(
xlpPath.Buffer,
Unicode->Buffer,
xlpExtension.Buffer,
nBufferLength,
xlpBuffer,
FilePartPtr
);
//
// === DBCS modification note [takaok] ===
//
// SearchPathW retruns:
//
// buffer size needed(including null terminator) if buffer size is too small.
// number of characters( not including null terminator) if buffer size is enougth
//
// This means SearchPathW never returns value which is equal to nBufferLength.
//
if ( ReturnValue > nBufferLength ) {
//
// To know the ansi buffer size needed, we should get all of
// unicode string.
//
RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
xlpBuffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
ReturnValue * sizeof(WCHAR));
if ( !xlpBuffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
goto bail0;
}
ReturnValue = SearchPathW(
xlpPath.Buffer,
Unicode->Buffer,
xlpExtension.Buffer,
ReturnValue,
xlpBuffer,
FilePartPtr
);
if ( ReturnValue > 0 ) {
//
// We called SearchPathW with the enough size of buffer.
// So, ReturnValue is the size of the path not including the
// terminating null character.
//
Status = RtlUnicodeToMultiByteSize( &ReturnValue,
xlpBuffer,
ReturnValue * sizeof(WCHAR));
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = 0;
}
else {
ReturnValue += 1;
}
}
} else if ( ReturnValue > 0 ) {
INT AnsiByteCount;
//
// We have unicode string. We need to compute the ansi byte count
// of the string.
//
// ReturnValue : unicode character count not including null terminator
// AnsiByteCount : ansi byte count not including null terminator
//
Status = RtlUnicodeToMultiByteSize( &AnsiByteCount,
xlpBuffer,
ReturnValue * sizeof(WCHAR) );
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = 0;
}
else {
if ( AnsiByteCount < (INT)nBufferLength ) {
//
// The string (including null terminator) fits to the buffer
//
Status = RtlUnicodeToMultiByteN ( lpBuffer,
nBufferLength - 1,
&AnsiByteCount,
xlpBuffer,
ReturnValue * sizeof(WCHAR)
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = 0;
}
else {
lpBuffer[ AnsiByteCount ] = '\0';
//
// The return value is the byte count copied to the buffer
// not including the terminating null character.
//
ReturnValue = AnsiByteCount;
if ( ARGUMENT_PRESENT(lpFilePart) ) {
if ( FilePart == NULL ) {
*lpFilePart = NULL;
} else {
INT PrefixLength;
PrefixLength = (INT)(FilePart - xlpBuffer);
Status = RtlUnicodeToMultiByteSize( &PrefixLength,
xlpBuffer,
PrefixLength * sizeof(WCHAR));
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = 0;
}
else {
*lpFilePart = lpBuffer + PrefixLength;
}
}
}
}
} else {
//
// We should return the size of the buffer required to
// hold the path. The size should include the
// terminating null character.
//
ReturnValue = AnsiByteCount + 1;
}
}
}
RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
bail0:
if ( ARGUMENT_PRESENT(lpExtension) ) {
RtlFreeUnicodeString(&xlpExtension);
}
if ( ARGUMENT_PRESENT(lpPath) ) {
RtlFreeUnicodeString(&xlpPath);
}
return ReturnValue;
}
#ifdef WX86
ULONG
GetFullPathNameWithWx86Override(
PCWSTR lpFileName,
ULONG nBufferLength,
PWSTR lpBuffer,
PWSTR *lpFilePart
)
{
UNICODE_STRING FullPathName, PathUnicode, Wx86PathName;
PUNICODE_STRING FoundFileName;
RTL_PATH_TYPE PathType;
PWSTR FilePart;
ULONG Length, LengthPath;
ULONG PathNameLength;
FullPathName.Buffer = NULL;
Wx86PathName.Buffer = NULL;
if (lpFilePart) {
*lpFilePart = NULL;
}
FullPathName.MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR)) + sizeof(WCHAR);
FullPathName.Length = 0;
FullPathName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
FullPathName.MaximumLength
);
if (!FullPathName.Buffer) {
PathNameLength = 0;
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto WDOExitCleanup;
}
FoundFileName = &FullPathName;
PathNameLength = RtlGetFullPathName_U(lpFileName,
FullPathName.MaximumLength,
FullPathName.Buffer,
&FilePart
);
if (!PathNameLength || PathNameLength >= FullPathName.MaximumLength) {
PathNameLength = 0;
goto WDOExitCleanup;
}
FullPathName.Length = (USHORT)PathNameLength;
PathUnicode = FullPathName;
PathUnicode.Length = (USHORT)((ULONG_PTR)FilePart -
(ULONG_PTR)FullPathName.Buffer);
PathUnicode.Length -= sizeof(WCHAR);
if (!RtlEqualUnicodeString(&PathUnicode, &BaseWindowsSystemDirectory, TRUE)) {
goto WDOExitCleanup;
}
Wx86PathName.MaximumLength = BaseWindowsSys32x86Directory.Length +
FullPathName.Length - PathUnicode.Length +
2*sizeof(WCHAR);
Wx86PathName.Length = 0;
Wx86PathName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
Wx86PathName.MaximumLength
);
if (!Wx86PathName.Buffer) {
goto WDOExitCleanup;
}
RtlCopyUnicodeString(&Wx86PathName, &BaseWindowsSys32x86Directory);
Length = Wx86PathName.Length + sizeof(WCHAR);
RtlAppendUnicodeToString (&Wx86PathName, FilePart - 1);
if (RtlDoesFileExists_U(Wx86PathName.Buffer)) {
FoundFileName = &Wx86PathName;
FilePart = Wx86PathName.Buffer + Length/sizeof(WCHAR);
}
WDOExitCleanup:
if (PathNameLength) {
if (FoundFileName->Length >= nBufferLength) {
PathNameLength = FoundFileName->Length + sizeof(WCHAR);
}
else {
RtlMoveMemory(lpBuffer,
FoundFileName->Buffer,
FoundFileName->Length + sizeof(WCHAR)
);
PathNameLength = FoundFileName->Length;
Length = (ULONG)(FilePart - FoundFileName->Buffer);
if (lpFilePart) {
*lpFilePart = lpBuffer + Length/sizeof(WCHAR);
}
}
}
if (FullPathName.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, FullPathName.Buffer);
}
if (Wx86PathName.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, Wx86PathName.Buffer);
}
return PathNameLength;
}
#endif
DWORD
APIENTRY
SearchPathW(
LPCWSTR lpPath,
LPCWSTR lpFileName,
LPCWSTR lpExtension,
DWORD nBufferLength,
LPWSTR lpBuffer,
LPWSTR *lpFilePart
)
/*++
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 - An optional parameter, that if specified, supplies the
search path to be used when locating the file. If this
parameter is not specified, the default windows search path is
used. The default path is:
- The current directory
- The windows directory
- The windows system directory
- The directories listed in the path environment variable
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 characters 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 - 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.
--*/
{
UNICODE_STRING Path;
UNICODE_STRING FileName;
UNICODE_STRING DefaultExtension;
UNICODE_STRING CallersBuffer;
LPWSTR AllocatedPath = NULL;
SIZE_T BytesRequired = 0;
SIZE_T FilePartPrefixCch = 0;
NTSTATUS Status;
DWORD dwReturnValue = 0;
//
// The guts of this function are now in common ntdll code; however the win32 search
// path has a few interesting differences from the ntdll search path code. First, it
// does not search the path if the filename is ".\foo" or "..\foo" and second, when the
// filename passed in is not a relative path but the file is not found, the default
// extension is applied regardless of whether the existing filename has an extension.
//
// These flags enable those feature-compatibility modes.
//
ULONG SearchPathFlags =
RTL_DOS_SEARCH_PATH_FLAG_DISALLOW_DOT_RELATIVE_PATH_SEARCH |
RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION;
if (lpFilePart != NULL)
*lpFilePart = NULL;
Path.Buffer = NULL;
RtlInitUnicodeString(&FileName, lpFileName);
//
// trim trailing spaces, and then check for a real filelength
// if length is 0 (NULL, "", or " ") passed in then abort the
// search
//
while ((FileName.Length >= sizeof(WCHAR)) &&
(FileName.Buffer[(FileName.Length / sizeof(WCHAR)) - 1] == L' '))
FileName.Length -= sizeof(WCHAR);
if (FileName.Length == 0) {
SetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
RtlInitUnicodeString(&DefaultExtension, lpExtension);
if ( !ARGUMENT_PRESENT(lpPath) ) {
SIZE_T Cch;
Path.Buffer = BaseComputeProcessSearchPath();
if (Path.Buffer == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto Exit;
}
Cch = lstrlenW(Path.Buffer);
if (Cch > UNICODE_STRING_MAX_CHARS) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
goto Exit;
}
Path.Length = (USHORT) (Cch * sizeof(WCHAR));
Path.MaximumLength = Path.Length;
SearchPathFlags |= RTL_DOS_SEARCH_PATH_FLAG_APPLY_ISOLATION_REDIRECTION;
} else {
Status = RtlInitUnicodeStringEx(&Path, lpPath);
if (NT_ERROR(Status)) {
BaseSetLastNTError(Status);
goto Exit;
}
}
CallersBuffer.Length = 0;
if (nBufferLength > UNICODE_STRING_MAX_CHARS) {
CallersBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
} else {
CallersBuffer.MaximumLength = (USHORT) (nBufferLength * sizeof(WCHAR));
}
CallersBuffer.Buffer = lpBuffer;
Status = RtlDosSearchPath_Ustr(
SearchPathFlags,
&Path,
&FileName,
&DefaultExtension,
&CallersBuffer,
NULL, // dynamicstring
NULL, // fullfilenameout
&FilePartPrefixCch,
&BytesRequired);
if (NT_ERROR(Status)) {
#if DBG
// Don't bother with debug spew for the two common expected cases.
if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL)) {
DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n", __FUNCTION__, &FileName, Status);
DbgPrint(" Path = %wZ\n", &Path);
}
#endif // DBG
if (Status == STATUS_BUFFER_TOO_SMALL) {
SIZE_T CchRequired = BytesRequired / sizeof(WCHAR);
if (CchRequired > 0xffffffff) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
goto Exit;
}
dwReturnValue = (DWORD) CchRequired;
goto Exit;
}
// Only set the last error if it wasn't an insufficient buffer; this is just preserving
// Windows 2000 behavior.
BaseSetLastNTError(Status);
goto Exit;
}
#ifdef WX86
if (UseKnownWx86Dll) {
WCHAR TempBuffer[MAX_PATH];
RtlCopyMemory(TempBuffer, lpBuffer, CallersBuffer.Length);
TempBuffer[CallersBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL;
dwReturnValue = GetFullPathNameWithWx86Override(
TempBuffer,
nBufferLength,
lpBuffer,
lpFilePart
);
goto Exit;
} else if (lpFilePart != NULL) {
*lpFilePart = lpBuffer + FilePartPrefixCch;
}
#else
if (lpFilePart != NULL) {
*lpFilePart = lpBuffer + FilePartPrefixCch;
}
#endif // WX86
dwReturnValue = CallersBuffer.Length / sizeof(WCHAR);
Exit:
if ((Path.Buffer != lpPath) && (Path.Buffer != NULL))
RtlFreeHeap(RtlProcessHeap(), 0, Path.Buffer);
return dwReturnValue;
}
DWORD
APIENTRY
GetTempPathA(
DWORD nBufferLength,
LPSTR lpBuffer
)
/*++
Routine Description:
ANSI thunk to GetTempPathW
--*/
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
ULONG cbAnsiString;
UnicodeString.MaximumLength = (USHORT)((nBufferLength<<1)+sizeof(UNICODE_NULL));
UnicodeString.Buffer = RtlAllocateHeap(
RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
UnicodeString.MaximumLength
);
if ( !UnicodeString.Buffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
UnicodeString.Length = (USHORT)GetTempPathW(
(DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2,
UnicodeString.Buffer
)*2;
if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
//
// given buffer size is too small.
// allocate enough size of buffer and try again
//
// we need to get entire unicode temporary path
// otherwise we can't figure out the exact length
// of corresponding ansi string (cbAnsiString).
UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
UnicodeString.Length+ sizeof(UNICODE_NULL));
if ( !UnicodeString.Buffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
UnicodeString.Length = (USHORT)GetTempPathW(
(DWORD)(UnicodeString.Length)/2,
UnicodeString.Buffer) * 2;
Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
UnicodeString.Buffer,
UnicodeString.Length );
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
BaseSetLastNTError(Status);
return 0;
}
else if ( nBufferLength <= cbAnsiString ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
return cbAnsiString + sizeof(ANSI_NULL);
}
}
AnsiString.Buffer = lpBuffer;
AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return 0;
}
return AnsiString.Length;
}
DWORD
APIENTRY
GetTempPathW(
DWORD nBufferLength,
LPWSTR lpBuffer
)
/*++
Routine Description:
This function is used to return the pathname of the directory that
should be used to create temporary files.
Arguments:
nBufferLength - Supplies the length in bytes of the buffer that is
to receive the temporary file path.
lpBuffer - Returns the pathname of the directory that should be used
to create temporary files in.
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 nSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
return BasepGetTempPathW(0, nBufferLength, lpBuffer);
}
DWORD
APIENTRY
BasepGetTempPathW(
ULONG Flags,
DWORD nBufferLength,
LPWSTR lpBuffer
)
/*++
Routine Description:
This function is used to return the pathname of the directory that
should be used to create temporary files.
Arguments:
nBufferLength - Supplies the length in bytes of the buffer that is
to receive the temporary file path.
lpBuffer - Returns the pathname of the directory that should be used
to create temporary files in.
Flags -
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 nSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
DWORD Length;
BOOLEAN AddTrailingSlash;
UNICODE_STRING EnvironmentValue;
NTSTATUS Status;
LPWSTR Name;
ULONG Position;
DWORD ReturnLength;
if (
(Flags & ~BASEP_GET_TEMP_PATH_PRESERVE_TEB) != 0
) {
BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
return 0;
}
//
// Some apps don't work with the new long path for the temp directory
//
if (APPCOMPATFLAG(KACF_GETTEMPPATH)) {
#define OLD_TEMP_PATH L"c:\\temp\\"
#define OLD_TEMP_PATH_SIZE (sizeof(OLD_TEMP_PATH) / sizeof(WCHAR))
BOOL bRet;
//
// If there isn't enough space provided in the buffer return
// the desired size.
//
if (nBufferLength < OLD_TEMP_PATH_SIZE) {
return OLD_TEMP_PATH_SIZE;
}
wcscpy(lpBuffer, OLD_TEMP_PATH);
//
// Use the correct drive letter
//
lpBuffer[0] = BaseWindowsDirectory.Buffer[0];
bRet = CreateDirectoryW(lpBuffer, NULL);
if (!bRet) {
if (GetLastError() != ERROR_ALREADY_EXISTS)
return 0;
}
return OLD_TEMP_PATH_SIZE - 1;
}
nBufferLength *= 2;
EnvironmentValue = NtCurrentTeb()->StaticUnicodeString;
if (Flags & BASEP_GET_TEMP_PATH_PRESERVE_TEB) {
EnvironmentValue.Buffer = (PWSTR)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), EnvironmentValue.MaximumLength);
if (EnvironmentValue.Buffer == NULL) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
}
ReturnLength = 0;
__try {
AddTrailingSlash = FALSE;
Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTmpVariableName,&EnvironmentValue);
if ( !NT_SUCCESS(Status) ) {
Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTempVariableName,&EnvironmentValue);
if ( !NT_SUCCESS(Status) ) {
Status = RtlQueryEnvironmentVariable_U(NULL,&BaseUserProfileVariableName,&EnvironmentValue);
}
}
if ( NT_SUCCESS(Status) ) {
Name = EnvironmentValue.Buffer;
if ( Name[(EnvironmentValue.Length>>1)-1] != (WCHAR)'\\' ) {
AddTrailingSlash = TRUE;
}
}
else {
Name = BaseWindowsDirectory.Buffer;
if ( Name[(BaseWindowsDirectory.Length>>1)-1] != (WCHAR)'\\' ) {
AddTrailingSlash = TRUE;
}
}
Length = RtlGetFullPathName_U(
Name,
nBufferLength,
lpBuffer,
NULL
);
Position = Length>>1;
//
// Make sure there is room for a trailing back slash
//
if ( Length && Length < nBufferLength ) {
if ( lpBuffer[Position-1] != '\\' ) {
if ( Length+sizeof((WCHAR)'\\') < nBufferLength ) {
lpBuffer[Position] = (WCHAR)'\\';
lpBuffer[Position+1] = UNICODE_NULL;
ReturnLength = (Length+sizeof((WCHAR)'\\'))/2;
__leave;
}
else {
ReturnLength = (Length+sizeof((WCHAR)'\\')+sizeof(UNICODE_NULL))/2;
__leave;
}
}
else {
ReturnLength = Length/2;
__leave;
}
}
else {
if ( AddTrailingSlash ) {
Length += sizeof((WCHAR)'\\');
}
ReturnLength = Length/2;
__leave;
}
}
__finally {
if (Flags & BASEP_GET_TEMP_PATH_PRESERVE_TEB) {
RtlFreeHeap(RtlProcessHeap(), 0, EnvironmentValue.Buffer);
}
}
return ReturnLength;
}
UINT
APIENTRY
GetTempFileNameA(
LPCSTR lpPathName,
LPCSTR lpPrefixString,
UINT uUnique,
LPSTR lpTempFileName
)
/*++
Routine Description:
ANSI thunk to GetTempFileNameW
--*/
{
PUNICODE_STRING Unicode;
UNICODE_STRING UnicodePrefix;
NTSTATUS Status;
UINT ReturnValue;
UNICODE_STRING UnicodeResult;
Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
if (Unicode == NULL) {
return 0;
}
if (!Basep8BitStringToDynamicUnicodeString( &UnicodePrefix, lpPrefixString )) {
return 0;
}
UnicodeResult.MaximumLength = (USHORT)((MAX_PATH<<1));
UnicodeResult.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), UnicodeResult.MaximumLength);
if ( !UnicodeResult.Buffer ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
RtlFreeUnicodeString(&UnicodePrefix);
return 0;
}
ReturnValue = GetTempFileNameW(
Unicode->Buffer,
UnicodePrefix.Buffer,
uUnique,
UnicodeResult.Buffer
);
if ( ReturnValue ) {
ANSI_STRING AnsiString;
RtlInitUnicodeString(&UnicodeResult,UnicodeResult.Buffer);
AnsiString.Buffer = lpTempFileName;
AnsiString.MaximumLength = MAX_PATH;
Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeResult,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = 0;
}
}
RtlFreeUnicodeString(&UnicodePrefix);
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeResult.Buffer);
return ReturnValue;
}
UINT
APIENTRY
GetTempFileNameW(
LPCWSTR lpPathName,
LPCWSTR lpPrefixString,
UINT uUnique,
LPWSTR lpTempFileName
)
/*++
Routine Description:
This function creates a temporary filename of the following form:
drive:\path\prefixuuuu.tmp
In this syntax line, drive:\path\ is the path specified by the
lpPathName parameter; prefix is all the letters (up to the first
three) of the string pointed to by the lpPrefixString parameter; and
uuuu is the hexadecimal value of the number specified by the
uUnique parameter.
To avoid problems resulting from converting OEM character an string
to an ANSI string, an application should call the CreateFile
function to create the temporary file.
If the uUnique parameter is zero, GetTempFileName attempts to form a
unique number based on the current system time. If a file with the
resulting filename exists, the number is increased by one and the
test for existence is repeated. This continues until a unique
filename is found; GetTempFileName then creates a file by that name
and closes it. No attempt is made to create and open the file when
uUnique is nonzero.
Arguments:
lpPathName - Specifies the null terminated pathname of the directory
to create the temporary file within.
lpPrefixString - Points to a null-terminated character string to be
used as the temporary filename prefix. This string must consist
of characters in the OEM-defined character set.
uUnique - Specifies an unsigned integer.
lpTempFileName - Points to the buffer that is to receive the
temporary filename. This string consists of characters in the
OEM-defined character set. This buffer should be at least MAX_PATH
characters in length to allow sufficient room for the pathname.
Return Value:
The return value specifies a unique numeric value used in the
temporary filename. If a nonzero value was given for the uUnique
parameter, the return value specifies this same number.
--*/
{
#if !defined(BUILD_WOW6432)
BASE_API_MSG m;
PBASE_GETTEMPFILE_MSG a = &m.u.GetTempFile;
#endif
LPWSTR p,savedp;
ULONG Length;
HANDLE FileHandle;
ULONG PassCount;
DWORD LastError;
UNICODE_STRING UnicodePath, UnicodePrefix;
CHAR UniqueAsAnsi[8];
CHAR *c;
ULONG i;
#if defined(BUILD_WOW6432)
UINT uNewUnique;
#endif
PassCount = 0;
RtlInitUnicodeString(&UnicodePath,lpPathName);
Length = UnicodePath.Length;
if ( !Length || lpPathName[(Length>>1)-1] != (WCHAR)'\\' ) {
Length += sizeof(UNICODE_NULL);
}
// Length is the number of bytes of data in lpPathName, *not*
// including the trailing NULL but including the whack.
// 12 is the number of characters we might append, including the
// trailing NULL but not including the whack -- preXXXX.tmp\0.
if (Length > ((MAX_PATH - 12) * sizeof(WCHAR))) {
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
if (lpTempFileName != lpPathName) {
// N.B. Must use RtlMoveMemory here -- some callers depend on
// lpPathName and lpTempFileName overlapping.
RtlMoveMemory(lpTempFileName,lpPathName,UnicodePath.Length);
}
lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
i = GetFileAttributesW(lpTempFileName);
if (i == 0xFFFFFFFF) {
lpTempFileName[(Length>>1)-1] = (WCHAR)'\\';
lpTempFileName[(Length>>1)] = UNICODE_NULL;
i = GetFileAttributesW(lpTempFileName);
lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
}
if ( (i == 0xFFFFFFFF) ||
!(i & FILE_ATTRIBUTE_DIRECTORY) ) {
SetLastError(ERROR_DIRECTORY);
return FALSE;
}
lpTempFileName[(Length>>1)-1] = (WCHAR)'\\';
RtlInitUnicodeString(&UnicodePrefix,lpPrefixString);
if ( UnicodePrefix.Length > (USHORT)6 ) {
UnicodePrefix.Length = (USHORT)6;
}
p = &lpTempFileName[Length>>1];
Length = UnicodePrefix.Length;
RtlMoveMemory(p,lpPrefixString,Length);
p += (Length>>1);
savedp = p;
//
// If uUnique is not specified, then get one
//
uUnique = uUnique & 0x0000ffff;
try_again:
p = savedp;
if ( !uUnique ) {
#if defined(BUILD_WOW6432)
uNewUnique = CsrBasepGetTempFile();
if ( uNewUnique == 0 ) {
#else
CsrClientCallServer( (PCSR_API_MSG)&m,
NULL,
CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
BasepGetTempFile
),
sizeof( *a )
);
a->uUnique = (UINT)m.ReturnValue;
if ( m.ReturnValue == 0 ) {
#endif
PassCount++;
if ( PassCount & 0xffff0000 ) {
return 0;
}
goto try_again;
}
} else {
#if defined(BUILD_WOW6432)
uNewUnique = uUnique;
#else
a->uUnique = uUnique;
#endif
}
//
// Convert the unique value to a 4 byte character string
//
#if defined(BUILD_WOW6432)
RtlIntegerToChar ((ULONG) uNewUnique,16,5,UniqueAsAnsi);
#else
RtlIntegerToChar ((ULONG) a->uUnique,16,5,UniqueAsAnsi);
#endif
c = UniqueAsAnsi;
for(i=0;i<4;i++){
*p = RtlAnsiCharToUnicodeChar(&c);
if ( *p == UNICODE_NULL ) {
break;
}
p++;
}
RtlMoveMemory(p,BaseDotTmpSuffixName.Buffer,BaseDotTmpSuffixName.MaximumLength);
if ( !uUnique ) {
//
// test for resulting name being a device (prefix com, uUnique 1-9...
//
if ( RtlIsDosDeviceName_U(lpTempFileName) ) {
PassCount++;
if ( PassCount & 0xffff0000 ) {
SetLastError(ERROR_INVALID_NAME);
return 0;
}
goto try_again;
}
FileHandle = CreateFileW(
lpTempFileName,
GENERIC_READ,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL
);
//
// If the create worked, then we are ok. Just close the file.
// Otherwise, try again.
//
if ( FileHandle != INVALID_HANDLE_VALUE ) {
NtClose(FileHandle);
} else {
//
// NTRAID#60021-2002/03/14-earhart: This test should be
// inverted when time permits sufficient testing to nail
// down the error codes that would indicate is is
// reasonable to continue the loop as opposed to stop the
// loop. All it currently takes is CreateFile coming back
// with an error we don't know about to make us spin here
// for a long time.
//
LastError = GetLastError();
switch (LastError) {
case ERROR_INVALID_PARAMETER :
case ERROR_WRITE_PROTECT :
case ERROR_FILE_NOT_FOUND :
case ERROR_BAD_PATHNAME :
case ERROR_INVALID_NAME :
case ERROR_PATH_NOT_FOUND :
case ERROR_NETWORK_ACCESS_DENIED :
case ERROR_DISK_CORRUPT :
case ERROR_FILE_CORRUPT :
case ERROR_DISK_FULL :
case ERROR_CANNOT_MAKE :
return 0;
case ERROR_ACCESS_DENIED :
// It's possible for us to hit this if there's a
// directory with the name we're trying; in that
// case, we can usefully continue.
// CreateFile() uses BaseSetLastNTError() to set
// LastStatusValue to the actual NT error in the
// TEB; we just need to check it, and only abort
// if it's not a directory.
// This was bug #397477.
if (NtCurrentTeb()->LastStatusValue
!= STATUS_FILE_IS_A_DIRECTORY)
return 0;
}
PassCount++;
if ( PassCount & 0xffff0000 ) {
return 0;
}
goto try_again;
}
}
#if defined(BUILD_WOW6432)
return uNewUnique;
#else
return a->uUnique;
#endif
}
BOOL
APIENTRY
GetDiskFreeSpaceA(
LPCSTR lpRootPathName,
LPDWORD lpSectorsPerCluster,
LPDWORD lpBytesPerSector,
LPDWORD lpNumberOfFreeClusters,
LPDWORD lpTotalNumberOfClusters
)
/*++
Routine Description:
ANSI thunk to GetDiskFreeSpaceW
--*/
{
PUNICODE_STRING Unicode;
if (!ARGUMENT_PRESENT( lpRootPathName )) {
lpRootPathName = "\\";
}
Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
if (Unicode == NULL) {
return FALSE;
}
return ( GetDiskFreeSpaceW(
(LPCWSTR)Unicode->Buffer,
lpSectorsPerCluster,
lpBytesPerSector,
lpNumberOfFreeClusters,
lpTotalNumberOfClusters
)
);
}
BOOL
APIENTRY
GetDiskFreeSpaceW(
LPCWSTR lpRootPathName,
LPDWORD lpSectorsPerCluster,
LPDWORD lpBytesPerSector,
LPDWORD lpNumberOfFreeClusters,
LPDWORD lpTotalNumberOfClusters
)
#define MAKE2GFRIENDLY(lpOut, dwSize) \
\
if (!bAppHack) { \
*lpOut = dwSize; \
} else { \
dwTemp = SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector; \
\
if (0x7FFFFFFF / dwTemp < dwSize) { \
\
*lpOut = 0x7FFFFFFF / dwTemp; \
} else { \
*lpOut = dwSize; \
} \
}
/*++
Routine Description:
The free space on a disk and the size parameters can be returned
using GetDiskFreeSpace.
Arguments:
lpRootPathName - An optional parameter, that if specified, supplies
the root directory of the disk whose free space is to be
returned for. If this parameter is not specified, then the root
of the current directory is used.
lpSectorsPerCluster - Returns the number of sectors per cluster
where a cluster is the allocation granularity on the disk.
lpBytesPerSector - Returns the number of bytes per sector.
lpNumberOfFreeClusters - Returns the total number of free clusters
on the disk.
lpTotalNumberOfClusters - Returns the total number of clusters on
the disk.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
FILE_FS_SIZE_INFORMATION SizeInfo;
WCHAR DefaultPath[2];
DWORD dwTemp;
BOOL bAppHack;
DefaultPath[0] = (WCHAR)'\\';
DefaultPath[1] = UNICODE_NULL;
TranslationStatus = RtlDosPathNameToNtPathName_U(
ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the file
//
Status = NtOpenFile(
&Handle,
SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
//
// Prior releases of NT where these parameters were not optional
// zeroed out this field even in the failure case. Some applications
// failed to check the return value from this function and instead
// relied on this side effect. I'm putting that back now so the apps
// can still treat an unformatted volume as a zero size volume.
//
if (ARGUMENT_PRESENT( lpBytesPerSector )) {
*lpBytesPerSector = 0;
}
return FALSE;
}
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
//
// Determine the size parameters of the volume.
//
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo),
FileFsSizeInformation
);
NtClose(Handle);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// See if the calling process needs hack to work with HDD > 2GB
// 2GB is 0x80000000 bytes and some apps treat that as a signed LONG.
//
if (APPCOMPATFLAG(KACF_GETDISKFREESPACE)) {
bAppHack = TRUE;
} else {
bAppHack = FALSE;
}
//
// Deal with 64 bit sizes
//
if ( SizeInfo.TotalAllocationUnits.HighPart ) {
SizeInfo.TotalAllocationUnits.LowPart = (ULONG)-1;
}
if ( SizeInfo.AvailableAllocationUnits.HighPart ) {
SizeInfo.AvailableAllocationUnits.LowPart = (ULONG)-1;
}
if (ARGUMENT_PRESENT( lpSectorsPerCluster )) {
*lpSectorsPerCluster = SizeInfo.SectorsPerAllocationUnit;
}
if (ARGUMENT_PRESENT( lpBytesPerSector )) {
*lpBytesPerSector = SizeInfo.BytesPerSector;
}
if (ARGUMENT_PRESENT( lpNumberOfFreeClusters )) {
MAKE2GFRIENDLY(lpNumberOfFreeClusters, SizeInfo.AvailableAllocationUnits.LowPart);
}
if (ARGUMENT_PRESENT( lpTotalNumberOfClusters )) {
MAKE2GFRIENDLY(lpTotalNumberOfClusters, SizeInfo.TotalAllocationUnits.LowPart);
}
return TRUE;
}
WINBASEAPI
BOOL
WINAPI
GetDiskFreeSpaceExA(
LPCSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes
)
{
PUNICODE_STRING Unicode;
if (!ARGUMENT_PRESENT( lpDirectoryName )) {
lpDirectoryName = "\\";
}
Unicode = Basep8BitStringToStaticUnicodeString( lpDirectoryName );
if (Unicode == NULL) {
return FALSE;
}
return ( GetDiskFreeSpaceExW(
(LPCWSTR)Unicode->Buffer,
lpFreeBytesAvailableToCaller,
lpTotalNumberOfBytes,
lpTotalNumberOfFreeBytes
)
);
}
WINBASEAPI
BOOL
WINAPI
GetDiskFreeSpaceExW(
LPCWSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
union {
FILE_FS_SIZE_INFORMATION Normal;
FILE_FS_FULL_SIZE_INFORMATION Full;
} SizeInfo;
WCHAR DefaultPath[2];
ULARGE_INTEGER BytesPerAllocationUnit;
ULARGE_INTEGER FreeBytesAvailableToCaller;
ULARGE_INTEGER TotalNumberOfBytes;
DefaultPath[0] = (WCHAR)'\\';
DefaultPath[1] = UNICODE_NULL;
TranslationStatus = RtlDosPathNameToNtPathName_U(
ARGUMENT_PRESENT(lpDirectoryName) ? lpDirectoryName : DefaultPath,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the file
//
Status = NtOpenFile(
&Handle,
SYNCHRONIZE,
&Obja,
&IoStatusBlock,
0,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
if ( GetLastError() == ERROR_FILE_NOT_FOUND ) {
SetLastError(ERROR_PATH_NOT_FOUND);
}
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
return FALSE;
}
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
//
// If the caller wants the volume total then try to get a full
// file size.
//
if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo.Full),
FileFsFullSizeInformation
);
if ( NT_SUCCESS(Status) ) {
NtClose(Handle);
BytesPerAllocationUnit.QuadPart =
SizeInfo.Full.BytesPerSector * SizeInfo.Full.SectorsPerAllocationUnit;
if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
lpFreeBytesAvailableToCaller->QuadPart =
BytesPerAllocationUnit.QuadPart *
SizeInfo.Full.CallerAvailableAllocationUnits.QuadPart;
}
if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
lpTotalNumberOfBytes->QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.Full.TotalAllocationUnits.QuadPart;
}
lpTotalNumberOfFreeBytes->QuadPart =
BytesPerAllocationUnit.QuadPart *
SizeInfo.Full.ActualAvailableAllocationUnits.QuadPart;
return TRUE;
}
}
//
// Determine the size parameters of the volume.
//
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo.Normal),
FileFsSizeInformation
);
NtClose(Handle);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
BytesPerAllocationUnit.QuadPart =
SizeInfo.Normal.BytesPerSector * SizeInfo.Normal.SectorsPerAllocationUnit;
FreeBytesAvailableToCaller.QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.AvailableAllocationUnits.QuadPart;
TotalNumberOfBytes.QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.TotalAllocationUnits.QuadPart;
if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
lpFreeBytesAvailableToCaller->QuadPart = FreeBytesAvailableToCaller.QuadPart;
}
if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
lpTotalNumberOfBytes->QuadPart = TotalNumberOfBytes.QuadPart;
}
if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
lpTotalNumberOfFreeBytes->QuadPart = FreeBytesAvailableToCaller.QuadPart;
}
return TRUE;
}
BOOL
APIENTRY
GetVolumeInformationA(
LPCSTR lpRootPathName,
LPSTR lpVolumeNameBuffer,
DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber,
LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags,
LPSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize
)
/*++
Routine Description:
ANSI thunk to GetVolumeInformationW
--*/
{
PUNICODE_STRING Unicode;
NTSTATUS Status;
UNICODE_STRING UnicodeVolumeName;
UNICODE_STRING UnicodeFileSystemName;
ANSI_STRING AnsiVolumeName;
ANSI_STRING AnsiFileSystemName;
BOOL ReturnValue;
if (!ARGUMENT_PRESENT( lpRootPathName )) {
lpRootPathName = "\\";
}
Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
if (Unicode == NULL) {
return FALSE;
}
UnicodeVolumeName.Buffer = NULL;
UnicodeFileSystemName.Buffer = NULL;
UnicodeVolumeName.MaximumLength = 0;
UnicodeFileSystemName.MaximumLength = 0;
AnsiVolumeName.Buffer = lpVolumeNameBuffer;
AnsiVolumeName.MaximumLength = (USHORT)(nVolumeNameSize+1);
AnsiFileSystemName.Buffer = lpFileSystemNameBuffer;
AnsiFileSystemName.MaximumLength = (USHORT)(nFileSystemNameSize+1);
try {
if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
UnicodeVolumeName.MaximumLength = AnsiVolumeName.MaximumLength << 1;
UnicodeVolumeName.Buffer = RtlAllocateHeap(
RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
UnicodeVolumeName.MaximumLength
);
if ( !UnicodeVolumeName.Buffer ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ReturnValue = FALSE;
leave;
}
}
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
UnicodeFileSystemName.MaximumLength = AnsiFileSystemName.MaximumLength << 1;
UnicodeFileSystemName.Buffer = RtlAllocateHeap(
RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
UnicodeFileSystemName.MaximumLength
);
if ( !UnicodeFileSystemName.Buffer ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ReturnValue = FALSE;
leave;
}
}
ReturnValue = GetVolumeInformationW(
(LPCWSTR)Unicode->Buffer,
UnicodeVolumeName.Buffer,
nVolumeNameSize,
lpVolumeSerialNumber,
lpMaximumComponentLength,
lpFileSystemFlags,
UnicodeFileSystemName.Buffer,
nFileSystemNameSize
);
if ( ReturnValue ) {
if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
RtlInitUnicodeString(
&UnicodeVolumeName,
UnicodeVolumeName.Buffer
);
Status = BasepUnicodeStringTo8BitString(
&AnsiVolumeName,
&UnicodeVolumeName,
FALSE
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = FALSE;
leave;
}
}
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
RtlInitUnicodeString(
&UnicodeFileSystemName,
UnicodeFileSystemName.Buffer
);
Status = BasepUnicodeStringTo8BitString(
&AnsiFileSystemName,
&UnicodeFileSystemName,
FALSE
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = FALSE;
leave;
}
}
}
}
finally {
if ( UnicodeVolumeName.Buffer ) {
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeVolumeName.Buffer);
}
if ( UnicodeFileSystemName.Buffer ) {
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeFileSystemName.Buffer);
}
}
return ReturnValue;
}
BOOL
APIENTRY
GetVolumeInformationW(
LPCWSTR lpRootPathName,
LPWSTR lpVolumeNameBuffer,
DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber,
LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags,
LPWSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize
)
/*++
Routine Description:
This function returns information about the file system whose root
directory is specified.
Arguments:
lpRootPathName - An optional parameter, that if specified, supplies
the root directory of the file system that information is to be
returned about. If this parameter is not specified, then the
root of the current directory is used.
lpVolumeNameBuffer - An optional parameter that if specified returns
the name of the specified volume.
nVolumeNameSize - Supplies the length of the volume name buffer.
This parameter is ignored if the volume name buffer is not
supplied.
lpVolumeSerialNumber - An optional parameter that if specified
points to a DWORD. The DWORD contains the 32-bit of the volume
serial number.
lpMaximumComponentLength - An optional parameter that if specified
returns the maximum length of a filename component supported by
the specified file system. A filename component is that portion
of a filename between pathname seperators.
lpFileSystemFlags - An optional parameter that if specified returns
flags associated with the specified file system.
lpFileSystemFlags Flags:
FS_CASE_IS_PRESERVED - Indicates that the case of file names
is preserved when the name is placed on disk.
FS_CASE_SENSITIVE - Indicates that the file system supports
case sensitive file name lookup.
FS_UNICODE_STORED_ON_DISK - Indicates that the file system
supports unicode in file names as they appear on disk.
lpFileSystemNameBuffer - An optional parameter that if specified returns
the name for the specified file system (e.g. FAT, HPFS...).
nFileSystemNameSize - Supplies the length of the file system name
buffer. This parameter is ignored if the file system name
buffer is not supplied.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
PFILE_FS_ATTRIBUTE_INFORMATION AttributeInfo;
PFILE_FS_VOLUME_INFORMATION VolumeInfo;
ULONG AttributeInfoLength;
ULONG VolumeInfoLength;
WCHAR DefaultPath[2];
BOOL rv;
ULONG OriginalErrorMode;
rv = FALSE;
DefaultPath[0] = (WCHAR)'\\';
DefaultPath[1] = UNICODE_NULL;
nVolumeNameSize *= 2;
nFileSystemNameSize *= 2;
TranslationStatus = RtlDosPathNameToNtPathName_U(
ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
//
// Check to make sure a root was specified
//
if ( FileName.Buffer[(FileName.Length >> 1)-1] != '\\' ) {
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
return FALSE;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
AttributeInfo = NULL;
VolumeInfo = NULL;
//
// Open the file
//
RtlSetThreadErrorMode(RTL_ERRORMODE_FAILCRITICALERRORS,
&OriginalErrorMode);
Status = NtOpenFile(
&Handle,
SYNCHRONIZE,
&Obja,
&IoStatusBlock,
0,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
);
RtlSetThreadErrorMode(OriginalErrorMode, NULL);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
return FALSE;
}
if ( !IsThisARootDirectory(Handle,&FileName) ) {
NtClose(Handle);
SetLastError(ERROR_DIR_NOT_ROOT);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
return FALSE;
}
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ||
ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
VolumeInfoLength = sizeof(*VolumeInfo)+nVolumeNameSize;
} else {
VolumeInfoLength = sizeof(*VolumeInfo)+MAX_PATH;
}
VolumeInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), VolumeInfoLength);
if ( !VolumeInfo ) {
NtClose(Handle);
BaseSetLastNTError(STATUS_NO_MEMORY);
return FALSE;
}
}
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ||
ARGUMENT_PRESENT(lpMaximumComponentLength) ||
ARGUMENT_PRESENT(lpFileSystemFlags) ) {
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
AttributeInfoLength = sizeof(*AttributeInfo) + nFileSystemNameSize;
} else {
AttributeInfoLength = sizeof(*AttributeInfo) + MAX_PATH;
}
AttributeInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AttributeInfoLength);
if ( !AttributeInfo ) {
NtClose(Handle);
if ( VolumeInfo ) {
RtlFreeHeap(RtlProcessHeap(), 0,VolumeInfo);
}
BaseSetLastNTError(STATUS_NO_MEMORY);
return FALSE;
}
}
try {
if ( VolumeInfo ) {
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
VolumeInfo,
VolumeInfoLength,
FileFsVolumeInformation
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
rv = FALSE;
goto finally_exit;
}
}
if ( AttributeInfo ) {
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
AttributeInfo,
AttributeInfoLength,
FileFsAttributeInformation
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
rv = FALSE;
goto finally_exit;
}
}
try {
if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
if ( VolumeInfo->VolumeLabelLength >= nVolumeNameSize ) {
SetLastError(ERROR_BAD_LENGTH);
rv = FALSE;
goto finally_exit;
} else {
RtlCopyMemory( lpVolumeNameBuffer,
VolumeInfo->VolumeLabel,
VolumeInfo->VolumeLabelLength );
*(lpVolumeNameBuffer + (VolumeInfo->VolumeLabelLength >> 1)) = UNICODE_NULL;
}
}
if ( ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
*lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
}
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
if ( AttributeInfo->FileSystemNameLength >= nFileSystemNameSize ) {
SetLastError(ERROR_BAD_LENGTH);
rv = FALSE;
goto finally_exit;
} else {
RtlCopyMemory( lpFileSystemNameBuffer,
AttributeInfo->FileSystemName,
AttributeInfo->FileSystemNameLength );
*(lpFileSystemNameBuffer + (AttributeInfo->FileSystemNameLength >> 1)) = UNICODE_NULL;
}
}
if ( ARGUMENT_PRESENT(lpMaximumComponentLength) ) {
*lpMaximumComponentLength = AttributeInfo->MaximumComponentNameLength;
}
if ( ARGUMENT_PRESENT(lpFileSystemFlags) ) {
*lpFileSystemFlags = AttributeInfo->FileSystemAttributes;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
rv = FALSE;
goto finally_exit;
}
rv = TRUE;
finally_exit:;
} finally {
NtClose(Handle);
if ( VolumeInfo ) {
RtlFreeHeap(RtlProcessHeap(), 0,VolumeInfo);
}
if ( AttributeInfo ) {
RtlFreeHeap(RtlProcessHeap(), 0,AttributeInfo);
}
}
return rv;
}
DWORD
APIENTRY
GetLogicalDriveStringsA(
DWORD nBufferLength,
LPSTR lpBuffer
)
{
ULONG DriveMap;
ANSI_STRING RootName;
int i;
PUCHAR Dst;
DWORD BytesLeft;
DWORD BytesNeeded;
BOOL WeFailed;
CHAR szDrive[] = "A:\\";
BytesNeeded = 0;
BytesLeft = nBufferLength;
Dst = (PUCHAR)lpBuffer;
WeFailed = FALSE;
RtlInitAnsiString(&RootName, szDrive);
DriveMap = GetLogicalDrives();
for ( i=0; i<26; i++ ) {
RootName.Buffer[0] = (CHAR)((CHAR)i+'A');
if (DriveMap & (1 << i) ) {
BytesNeeded += RootName.MaximumLength;
if ( BytesNeeded < (USHORT)BytesLeft ) {
RtlCopyMemory(Dst,RootName.Buffer,RootName.MaximumLength);
Dst += RootName.MaximumLength;
*Dst = '\0';
} else {
WeFailed = TRUE;
}
}
}
if ( WeFailed ) {
BytesNeeded++;
}
//
// Need to handle network uses;
//
return( BytesNeeded );
}
DWORD
APIENTRY
GetLogicalDriveStringsW(
DWORD nBufferLength,
LPWSTR lpBuffer
)
{
ULONG DriveMap;
UNICODE_STRING RootName;
int i;
PUCHAR Dst;
DWORD BytesLeft;
DWORD BytesNeeded;
BOOL WeFailed;
WCHAR wszDrive[] = L"A:\\";
nBufferLength = nBufferLength*2;
BytesNeeded = 0;
BytesLeft = nBufferLength;
Dst = (PUCHAR)lpBuffer;
WeFailed = FALSE;
RtlInitUnicodeString(&RootName, wszDrive);
DriveMap = GetLogicalDrives();
for ( i=0; i<26; i++ ) {
RootName.Buffer[0] = (WCHAR)((CHAR)i+'A');
if (DriveMap & (1 << i) ) {
BytesNeeded += RootName.MaximumLength;
if ( BytesNeeded < (USHORT)BytesLeft ) {
RtlCopyMemory(Dst,RootName.Buffer,RootName.MaximumLength);
Dst += RootName.MaximumLength;
*(PWSTR)Dst = UNICODE_NULL;
} else {
WeFailed = TRUE;
}
}
}
if ( WeFailed ) {
BytesNeeded += 2;
}
//
// Need to handle network uses;
//
return( BytesNeeded/2 );
}
BOOL
WINAPI
SetVolumeLabelA(
LPCSTR lpRootPathName,
LPCSTR lpVolumeName
)
{
PUNICODE_STRING Unicode;
UNICODE_STRING UnicodeVolumeName;
BOOL ReturnValue;
if (!ARGUMENT_PRESENT( lpRootPathName )) {
lpRootPathName = "\\";
}
Unicode = Basep8BitStringToStaticUnicodeString( lpRootPathName );
if (Unicode == NULL) {
return FALSE;
}
if ( ARGUMENT_PRESENT(lpVolumeName) ) {
if (!Basep8BitStringToDynamicUnicodeString( &UnicodeVolumeName, lpVolumeName )) {
return FALSE;
}
} else {
UnicodeVolumeName.Buffer = NULL;
}
ReturnValue = SetVolumeLabelW((LPCWSTR)Unicode->Buffer,(LPCWSTR)UnicodeVolumeName.Buffer);
RtlFreeUnicodeString(&UnicodeVolumeName);
return ReturnValue;
}
BOOL
WINAPI
SetVolumeLabelW(
LPCWSTR lpRootPathName,
LPCWSTR lpVolumeName
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
UNICODE_STRING LabelName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
PFILE_FS_LABEL_INFORMATION LabelInformation;
ULONG LabelInfoLength;
WCHAR DefaultPath[2];
BOOL rv;
WCHAR volumeName[MAX_PATH];
BOOL usingVolumeName;
rv = FALSE;
DefaultPath[0] = (WCHAR)'\\';
DefaultPath[1] = UNICODE_NULL;
if ( ARGUMENT_PRESENT(lpVolumeName) ) {
RtlInitUnicodeString(&LabelName,lpVolumeName);
}
else {
LabelName.Length = 0;
LabelName.MaximumLength = 0;
LabelName.Buffer = NULL;
}
if (ARGUMENT_PRESENT(lpRootPathName)) {
if (GetVolumeNameForVolumeMountPointW(lpRootPathName, volumeName,
MAX_PATH)) {
usingVolumeName = TRUE;
} else {
usingVolumeName = FALSE;
}
} else {
usingVolumeName = FALSE;
}
TranslationStatus = RtlDosPathNameToNtPathName_U(
usingVolumeName ? volumeName : (ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : DefaultPath),
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
//
// Check to make sure a root was specified
//
if ( FileName.Buffer[(FileName.Length >> 1)-1] != '\\' ) {
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
return FALSE;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the file
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_WRITE_DATA | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
BaseSetLastNTError(Status);
return FALSE;
}
if ( !IsThisARootDirectory(Handle,NULL) ) {
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
NtClose(Handle);
SetLastError(ERROR_DIR_NOT_ROOT);
return FALSE;
}
NtClose(Handle);
//
// Now open the volume DASD by ignoring the ending backslash
//
FileName.Length -= 2;
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the volume
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_WRITE_DATA | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Set the volume label
//
LabelInformation = NULL;
try {
rv = TRUE;
//
// the label info buffer contains a single wchar that is the basis of
// the label name. Subtract this out so the info length is the length
// of the label and the structure (not including the extra wchar)
//
if ( LabelName.Length ) {
LabelInfoLength = sizeof(*LabelInformation) + LabelName.Length - sizeof(WCHAR);
}
else {
LabelInfoLength = sizeof(*LabelInformation);
}
LabelInformation = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), LabelInfoLength);
if ( LabelInformation ) {
RtlCopyMemory(
LabelInformation->VolumeLabel,
LabelName.Buffer,
LabelName.Length
);
LabelInformation->VolumeLabelLength = LabelName.Length;
Status = NtSetVolumeInformationFile(
Handle,
&IoStatusBlock,
(PVOID) LabelInformation,
LabelInfoLength,
FileFsLabelInformation
);
if ( !NT_SUCCESS(Status) ) {
rv = FALSE;
BaseSetLastNTError(Status);
}
}
else {
rv = FALSE;
BaseSetLastNTError(STATUS_NO_MEMORY);
}
}
finally {
NtClose(Handle);
if ( LabelInformation ) {
RtlFreeHeap(RtlProcessHeap(), 0,LabelInformation);
}
}
return rv;
}
BOOL
APIENTRY
CheckNameLegalDOS8Dot3A(
IN LPCSTR lpName,
OUT LPSTR lpOemName OPTIONAL,
IN DWORD OemNameSize OPTIONAL,
OUT PBOOL pbNameContainsSpaces OPTIONAL,
OUT PBOOL pbNameLegal
)
/*++
ANSI thunk to IsNameLegalDOS8Dot3W
--*/
{
ANSI_STRING AnsiStr;
PUNICODE_STRING pUnicodeStr;
NTSTATUS Status;
BOOL Result;
if( (lpName == NULL) || (pbNameLegal == NULL) ||
((lpOemName == NULL) && (OemNameSize != 0)) ||
(OemNameSize > MAXUSHORT)
) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
pUnicodeStr = Basep8BitStringToStaticUnicodeString( lpName );
if( pUnicodeStr == NULL ) {
//
// LastError already set by Basep8BitStringToStaticUnicodeString
//
return FALSE;
}
Result = CheckNameLegalDOS8Dot3W(
(LPCWSTR)(pUnicodeStr->Buffer),
lpOemName,
OemNameSize,
pbNameContainsSpaces,
pbNameLegal
);
return Result;
}
BOOL
APIENTRY
CheckNameLegalDOS8Dot3W(
IN LPCWSTR lpName,
OUT LPSTR lpOemName OPTIONAL,
IN DWORD OemNameSize OPTIONAL,
OUT PBOOL pbNameContainsSpaces OPTIONAL,
OUT PBOOL pbNameLegal
)
/*++
Routine Description:
This function determines whether this name can successfully be used to
create a file on the FAT file system.
This routine can therefore also be used to determine if a name is
appropriate to be passed back to a Win31 or DOS app, i.e. whether
the downlevel APP will understand the name.
Arguments:
lpName - The UNICODE name to test for conformance to 8.3 symantics.
lpOemName - If specified, will receive the Oem name corresponding
to the passed in lpName. Storage must be provided by the caller.
The name is undefined if the routine returns FALSE or lpName
does not conform to 8.3 symantics.
OemNameSize - If lpOemName is specified, then OemNameSize must specify
the size of the lpOemName buffer in chars. If lpOemName is not
specified, then OemNameSize must be set to zero.
pbNameContainsSpaces - If the name is a valid 8.3 FAT name, then this
parameter will indicate if the names contains spaces. If
the name is not 8.3 compliant, this parameter is undefined. In
many instances, the alternate name is more appropriate to
use if spaces are present in the principle name, even if
it is 8.3 compliant.
pbNameLegal - If the function returns TRUE, then this
parameter will indicate if the passed in UNICODE name forms a valid
8.3 FAT name when upcased to the current Oem code page. If
the name is not 8.3 compliant, this parameter is undefined.
TRUE - passed in UNICODE name forms a valid 8.3 FAT name
FALSE - passed in UNICODE name does not forms a valid 8.3 FAT name
Return Value:
TRUE - function succeeds
FALSE - Function fails. Extended error status is available using
GetLastError.
--*/
{
#define BASEP_LOCAL_OEM_BUFFER_SIZE (12 * sizeof(ANSI_NULL))
UNICODE_STRING UnicodeStr;
OEM_STRING OemStr;
POEM_STRING pOemStr;
UCHAR OemBuffer[BASEP_LOCAL_OEM_BUFFER_SIZE];
BOOLEAN SpacesInName, Result;
if( (lpName == NULL) || (pbNameLegal == NULL) ||
((lpOemName == NULL) && (OemNameSize != 0)) ||
(OemNameSize > MAXUSHORT)
) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if( lpOemName != NULL ) {
//
// Use a local buffer so that RtlIsNameLegalDOS8Dot3 will not fail
// due to insufficent OemName buffer size
//
OemStr.Length = 0;
OemStr.MaximumLength = BASEP_LOCAL_OEM_BUFFER_SIZE;
OemStr.Buffer = OemBuffer;
pOemStr = &OemStr;
}
else {
pOemStr = NULL;
}
RtlInitUnicodeString( &UnicodeStr, lpName );
Result = RtlIsNameLegalDOS8Dot3(
&UnicodeStr,
pOemStr,
&SpacesInName
);
if( Result != FALSE ) {
if( pOemStr != NULL ) {
if( OemNameSize < (OemStr.Length + sizeof(ANSI_NULL)) ) {
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
RtlCopyMemory( lpOemName, OemStr.Buffer, OemStr.Length );
lpOemName[OemStr.Length/sizeof(ANSI_NULL)] = ANSI_NULL;
}
if( pbNameContainsSpaces != NULL ) {
*pbNameContainsSpaces = SpacesInName;
}
}
*pbNameLegal = Result;
return TRUE;
#undef BASEP_LOCAL_OEM_BUFFER_SIZE
}
#if 0
//
// frankar, let me know if this is needed...
//
UINT
WINAPI
GetZawSysDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
ULONG cbAnsiString;
UnicodeString.MaximumLength = (USHORT)((uSize<<1)+sizeof(UNICODE_NULL));
UnicodeString.Buffer = RtlAllocateHeap(
RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
UnicodeString.MaximumLength
);
if ( !UnicodeString.Buffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
UnicodeString.Length = (USHORT)GetZawSysDirectoryW(
UnicodeString.Buffer,
(DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2
)*2;
if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
//
// given buffer size is too small.
// allocate enough size of buffer and try again
//
// we need to get entire unicode path
// otherwise we can't figure out the exact length
// of corresponding ansi string (cbAnsiString).
UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
UnicodeString.Length+ sizeof(UNICODE_NULL));
if ( !UnicodeString.Buffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
UnicodeString.Length = (USHORT)GetZawSysDirectoryW(
UnicodeString.Buffer,
(DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2,
) * 2;
Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
UnicodeString.Buffer,
UnicodeString.Length );
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
BaseSetLastNTError(Status);
return 0;
}
else if ( nBufferLength < cbAnsiString ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
return cbAnsiString;
}
}
AnsiString.Buffer = lpBuffer;
AnsiString.MaximumLength = (USHORT)(uSize+1);
Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return 0;
}
return AnsiString.Length;
}
UINT
WINAPI
GetZawWindDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
ULONG cbAnsiString;
UnicodeString.MaximumLength = (USHORT)((uSize<<1)+sizeof(UNICODE_NULL));
UnicodeString.Buffer = RtlAllocateHeap(
RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
UnicodeString.MaximumLength
);
if ( !UnicodeString.Buffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
UnicodeString.Length = (USHORT)GetZawWindDirectoryW(
UnicodeString.Buffer,
(DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2
)*2;
if ( UnicodeString.Length > (USHORT)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL)) ) {
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
//
// given buffer size is too small.
// allocate enough size of buffer and try again
//
// we need to get entire unicode path
// otherwise we can't figure out the exact length
// of corresponding ansi string (cbAnsiString).
UnicodeString.Buffer = RtlAllocateHeap ( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
UnicodeString.Length+ sizeof(UNICODE_NULL));
if ( !UnicodeString.Buffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
UnicodeString.Length = (USHORT)GetZawWindDirectoryW(
UnicodeString.Buffer,
(DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2
) * 2;
Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
UnicodeString.Buffer,
UnicodeString.Length );
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
BaseSetLastNTError(Status);
return 0;
}
else if ( nBufferLength < cbAnsiString ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
return cbAnsiString;
}
}
AnsiString.Buffer = lpBuffer;
AnsiString.MaximumLength = (USHORT)(uSize+1);
Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
RtlFreeHeap(RtlProcessHeap(), 0,UnicodeString.Buffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return 0;
}
return AnsiString.Length;
}
UINT
WINAPI
GetZawSysDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
{
NTSTATUS Status;
HANDLE CurrentUserKey;
HANDLE DirKey;
UNICODE_STRING KeyName;
UNICODE_STRING KeyValueName;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG DataLength;
ULONG ValueInfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+MAX_PATH/2];
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
Status = RtlOpenCurrentUser(GENERIC_READ,&CurrentUserKey);
if ( !NT_SUCCESS(Status) ) {
bail_gzsd:
return GetSystemDirectoryW(lpBuffer,uSize);
}
RtlInitUnicodeString(&KeyName,L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ZAW");
InitializeObjectAttributes( &ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
CurrentUserKey,
NULL
);
Status = NtOpenKey( &DirKey,
KEY_READ | KEY_NOTIFY | KEY_WRITE,
&ObjectAttributes
);
NtClose(CurrentUserKey);
if ( !NT_SUCCESS(Status) ) {
goto bail_gzsd;
}
RtlInitUnicodeString(&KeyValueName,L"ZawSys");
ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&ValueInfoBuffer;
Status = NtQueryValueKey( DirKey,
&KeyValueName,
KeyValuePartialInformation,
ValueInfo,
sizeof(ValueInfoBuffer),
&DataLength
);
NtClose(DirKey);
if ( !NT_SUCCESS(Status) ) {
goto bail_gzsd;
}
if ( ValueInfo->DataLength > (uSize<<1) ) {
goto bail_gzsd;
}
RtlCopyMemory(lpBuffer,ValueInfo->Data,ValueInfo->DataLength);
return (ValueInfo->DataLength >> 1)-1;
}
UINT
WINAPI
GetZawWindDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
{
NTSTATUS Status;
HANDLE CurrentUserKey;
HANDLE DirKey;
UNICODE_STRING KeyName;
UNICODE_STRING KeyValueName;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG DataLength;
ULONG ValueInfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+MAX_PATH/2];
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
Status = RtlOpenCurrentUser(GENERIC_READ,&CurrentUserKey);
if ( !NT_SUCCESS(Status) ) {
bail_gzwd:
return GetWindowsDirectoryW(lpBuffer,uSize);
}
RtlInitUnicodeString(&KeyName,L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ZAW");
InitializeObjectAttributes( &ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
CurrentUserKey,
NULL
);
Status = NtOpenKey( &DirKey,
KEY_READ | KEY_NOTIFY | KEY_WRITE,
&ObjectAttributes
);
NtClose(CurrentUserKey);
if ( !NT_SUCCESS(Status) ) {
goto bail_gzwd;
}
RtlInitUnicodeString(&KeyValueName,L"ZawWind");
ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&ValueInfoBuffer;
Status = NtQueryValueKey( DirKey,
&KeyValueName,
KeyValuePartialInformation,
ValueInfo,
sizeof(ValueInfoBuffer),
&DataLength
);
NtClose(DirKey);
if ( !NT_SUCCESS(Status) ) {
goto bail_gzwd;
}
if ( ValueInfo->DataLength > (uSize<<1) ) {
goto bail_gzwd;
}
RtlCopyMemory(lpBuffer,ValueInfo->Data,ValueInfo->DataLength);
return (ValueInfo->DataLength >> 1)-1;
}
#endif