NT4/private/windows/base/client/pathmisc.c
2020-09-30 17:12:29 +02:00

2724 lines
77 KiB
C

/*++
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"
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;
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;
#ifdef DBCS // GetSystemDirectoryA(): bug fix
// 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.
RtlUnicodeToMultiByteSize( &cbAnsiString,
BaseWindowsSystemDirectory.Buffer,
BaseWindowsSystemDirectory.MaximumLength);
#else
cbAnsiString = BaseWindowsSystemDirectory.MaximumLength>>1;
#endif // DBCS
if ( (USHORT)uSize < (USHORT)cbAnsiString ) {
return cbAnsiString;
}
AnsiString.MaximumLength = (USHORT)(uSize);
AnsiString.Buffer = lpBuffer;
Status = BasepUnicodeStringTo8BitString(
&AnsiString,
&BaseWindowsSystemDirectory,
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 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 ( uSize*2 < BaseWindowsSystemDirectory.MaximumLength ) {
return BaseWindowsSystemDirectory.MaximumLength/2;
}
RtlMoveMemory(
lpBuffer,
BaseWindowsSystemDirectory.Buffer,
BaseWindowsSystemDirectory.Length
);
lpBuffer[(BaseWindowsSystemDirectory.Length>>1)] = UNICODE_NULL;
return BaseWindowsSystemDirectory.Length/2;
}
UINT
APIENTRY
GetWindowsDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
ANSI thunk to GetWindowsDirectoryW
--*/
{
ANSI_STRING AnsiString;
NTSTATUS Status;
ULONG cbAnsiString;
#ifdef DBCS // GetWindowsDirectoryA(): bug fix
// 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.
RtlUnicodeToMultiByteSize( &cbAnsiString,
BaseWindowsDirectory.Buffer,
BaseWindowsDirectory.MaximumLength);
#else
cbAnsiString = BaseWindowsDirectory.MaximumLength>>1;
#endif // DBCS
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
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.
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 ( uSize*2 < BaseWindowsDirectory.MaximumLength ) {
return BaseWindowsDirectory.MaximumLength/2;
}
RtlMoveMemory(
lpBuffer,
BaseWindowsDirectory.Buffer,
BaseWindowsDirectory.Length
);
lpBuffer[(BaseWindowsDirectory.Length>>1)] = UNICODE_NULL;
return BaseWindowsDirectory.Length/2;
}
UINT
APIENTRY
GetDriveTypeA(
LPCSTR lpRootPathName
)
/*++
Routine Description:
ANSI thunk to GetDriveTypeW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
LPCWSTR lpRootPathName_U;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
if (ARGUMENT_PRESENT(lpRootPathName)) {
RtlInitAnsiString( &AnsiString, lpRootPathName );
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
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;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
DWORD ReturnValue;
FILE_FS_DEVICE_INFORMATION DeviceInfo;
UINT DriveType;
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)0xFFFFFFFF) {
//
// Hack to be compatible with undocumented feature of old
// implementation.
//
return 0;
}
else {
RootPathName = (PWSTR)lpRootPathName;
}
wch = RtlUpcaseUnicodeChar(*RootPathName);
if ( wch >= (WCHAR)'A' && wch <= (WCHAR)'Z' ) {
if (RootPathName[1]==(WCHAR)':' &&
(RootPathName[2]==UNICODE_NULL || RootPathName[2]==(WCHAR)'\\') &&
(RootPathName[2]==UNICODE_NULL || RootPathName[3]==UNICODE_NULL)
) {
DriveNumber = wch - (WCHAR)'A';
if (USER_SHARED_DATA->DosDeviceMap & (1 << DriveNumber)) {
switch ( USER_SHARED_DATA->DosDeviceDriveType[ 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;
}
}
}
}
//
// 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 ) {
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;
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
PWSTR FilePart;
PWSTR *FilePartPtr;
if ( ARGUMENT_PRESENT(lpFilePart) ) {
FilePartPtr = &FilePart;
}
else {
FilePartPtr = NULL;
}
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return 0;
}
if ( ARGUMENT_PRESENT(lpExtension) ) {
RtlInitAnsiString(&AnsiString,lpExtension);
Status = Basep8BitStringToUnicodeString(&xlpExtension,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return 0;
}
}
else {
xlpExtension.Buffer = NULL;
}
if ( ARGUMENT_PRESENT(lpPath) ) {
RtlInitAnsiString(&AnsiString,lpPath);
Status = Basep8BitStringToUnicodeString(&xlpPath,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
if ( ARGUMENT_PRESENT(lpExtension) ) {
RtlFreeUnicodeString(&xlpExtension);
}
BaseSetLastNTError(Status);
return 0;
}
}
else {
xlpPath.Buffer = NULL;
}
xlpBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nBufferLength<<1);
if ( !xlpBuffer ) {
BaseSetLastNTError(STATUS_NO_MEMORY);
goto bail0;
}
ReturnValue = SearchPathW(
xlpPath.Buffer,
Unicode->Buffer,
xlpExtension.Buffer,
nBufferLength,
xlpBuffer,
FilePartPtr
);
#ifdef DBCS // SearchPathA(): DBCS enabling
//
// === 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.
//
RtlUnicodeToMultiByteSize( &ReturnValue,
xlpBuffer,
ReturnValue * sizeof(WCHAR));
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
//
RtlUnicodeToMultiByteSize( &AnsiByteCount,
xlpBuffer,
ReturnValue * sizeof(WCHAR) );
if ( AnsiByteCount < (INT)nBufferLength ) {
//
// The string (including null terminator) fits to the buffer
//
Status = RtlUnicodeToMultiByteN ( lpBuffer,
nBufferLength - 1,
&AnsiByteCount,
xlpBuffer,
ReturnValue * sizeof(WCHAR)
);
lpBuffer[ AnsiByteCount ] = '\0';
if ( ARGUMENT_PRESENT(lpFilePart) ) {
if ( FilePart == NULL ) {
*lpFilePart = NULL;
} else {
INT PrefixLength;
PrefixLength = (INT)(FilePart - xlpBuffer);
RtlUnicodeToMultiByteSize( &PrefixLength,
xlpBuffer,
PrefixLength * sizeof(WCHAR));
*lpFilePart = lpBuffer + PrefixLength;
}
}
//
// The return value is the byte count copied to the buffer
// not including the terminating null character.
//
ReturnValue = AnsiByteCount;
} 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;
}
}
#else
if ( ReturnValue && ReturnValue <= nBufferLength ) {
RtlInitUnicodeString(&UnicodeString,xlpBuffer);
AnsiString.MaximumLength = (USHORT)(nBufferLength+1);
AnsiString.Buffer = lpBuffer;
Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
ReturnValue = 0;
}
else {
if ( ARGUMENT_PRESENT(lpFilePart) ) {
if ( FilePart == NULL ) {
*lpFilePart = NULL;
}
else {
*lpFilePart = (LPSTR)(FilePart - xlpBuffer);
*lpFilePart = *lpFilePart + (DWORD)lpBuffer;
}
}
}
}
#endif // DBCS
RtlFreeHeap(RtlProcessHeap(), 0,xlpBuffer);
bail0:
if ( ARGUMENT_PRESENT(lpExtension) ) {
RtlFreeUnicodeString(&xlpExtension);
}
if ( ARGUMENT_PRESENT(lpPath) ) {
RtlFreeUnicodeString(&xlpPath);
}
return ReturnValue;
}
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.
--*/
{
LPWSTR ComputedFileName;
ULONG ExtensionLength;
ULONG PathLength;
ULONG FileLength;
LPCWSTR p;
LPWSTR p1;
LPWSTR AllocatedPath;
ULONG ComputedLength;
UNICODE_STRING Scratch;
UNICODE_STRING AllocatedPathString;
NTSTATUS Status;
RTL_PATH_TYPE PathType;
WCHAR wch;
//
// if the file name is not a relative name, then
// check to see if the file exists.
//
nBufferLength *= 2;
PathType = RtlDetermineDosPathNameType_U(lpFileName);
if ( PathType == RtlPathTypeRelative ) {
//
// for .\ and ..\ names don't search path
//
if ( lpFileName[0] == (WCHAR)'.') {
if ( lpFileName[1] == (WCHAR)'\\' || lpFileName[1] == (WCHAR)'/') {
PathType = RtlPathTypeUnknown;
}
else {
if ( lpFileName[1] == (WCHAR)'.' &&
(lpFileName[2] == (WCHAR)'\\' || lpFileName[2] == (WCHAR)'/') ) {
PathType = RtlPathTypeUnknown;
}
}
}
}
if ( PathType != RtlPathTypeRelative ) {
if (RtlDoesFileExists_U(lpFileName) ) {
ExtensionLength = RtlGetFullPathName_U(
lpFileName,
nBufferLength,
lpBuffer,
lpFilePart
);
return ExtensionLength/2;
}
else {
//
// if the name does not exist, then see if adding the extension
// helps any
//
if ( ARGUMENT_PRESENT(lpExtension) ) {
RtlInitUnicodeString(&Scratch,lpExtension);
ExtensionLength = Scratch.Length;
RtlInitUnicodeString(&Scratch,lpFileName);
AllocatedPathString.Length = (USHORT)ExtensionLength + Scratch.Length;
AllocatedPathString.MaximumLength = AllocatedPathString.Length + (USHORT)sizeof(UNICODE_NULL);
AllocatedPathString.Buffer = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
AllocatedPathString.MaximumLength
);
if ( !AllocatedPathString.Buffer ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
RtlCopyMemory(AllocatedPathString.Buffer,lpFileName,Scratch.Length);
RtlCopyMemory(AllocatedPathString.Buffer+(Scratch.Length>>1),lpExtension,ExtensionLength+sizeof(UNICODE_NULL));
if (RtlDoesFileExists_U(AllocatedPathString.Buffer) ) {
ExtensionLength = RtlGetFullPathName_U(
AllocatedPathString.Buffer,
nBufferLength,
lpBuffer,
lpFilePart
);
ExtensionLength /= 2;
}
else {
SetLastError(ERROR_FILE_NOT_FOUND);
ExtensionLength = 0;
}
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPathString.Buffer);
return ExtensionLength;
}
else {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
}
//
// Determine if the file name contains an extension
//
ExtensionLength = 1;
p = lpFileName;
while (*p) {
if ( *p == (WCHAR)'.' ) {
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) ) {
RtlInitUnicodeString(&Scratch,lpExtension);
ExtensionLength = Scratch.Length;
}
else {
ExtensionLength = 0;
}
}
else {
ExtensionLength = 0;
}
//
// If the lpPath parameter is not specified, then use the
// default windows search.
//
if ( !ARGUMENT_PRESENT(lpPath) ) {
AllocatedPath = BaseComputeProcessDllPath(NULL, GetEnvironmentStringsW());
RtlInitUnicodeString(&Scratch,AllocatedPath);
PathLength = Scratch.Length;
lpPath = AllocatedPath;
}
else {
RtlInitUnicodeString(&Scratch,lpPath);
PathLength = Scratch.Length;
AllocatedPath = NULL;
}
//
// Compute the file name length and the path length;
//
RtlInitUnicodeString(&Scratch,lpFileName);
FileLength = Scratch.Length;
//
// trim trailing spaces, and then check for a real filelength
// if length is 0 (NULL, "", or " ") passed in then abort the
// search
//
if ( FileLength ) {
wch = Scratch.Buffer[(FileLength>>1) - 1];
while ( FileLength && wch == (WCHAR)' ' ) {
FileLength -= sizeof(WCHAR);
wch = Scratch.Buffer[(FileLength>>1) - 1];
}
if ( !FileLength ) {
if ( AllocatedPath ) {
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
else {
FileLength = Scratch.Length;
}
}
else {
if ( AllocatedPath ) {
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
ComputedLength = PathLength + FileLength + ExtensionLength + 3*sizeof(UNICODE_NULL);
ComputedFileName = RtlAllocateHeap(
RtlProcessHeap(), MAKE_TAG( TMP_TAG ),
ComputedLength
);
if ( !ComputedFileName ) {
if ( AllocatedPath ) {
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
BaseSetLastNTError(STATUS_NO_MEMORY);
return 0;
}
//
// find ; 's in path and copy path component to computed file name
//
do {
p1 = ComputedFileName;
while (*lpPath) {
if (*lpPath == (WCHAR)';') {
lpPath++;
break;
}
*p1++ = *lpPath++;
}
if (p1 != ComputedFileName &&
p1 [ -1 ] != (WCHAR)'\\' ) {
*p1++ = (WCHAR)'\\';
}
if (*lpPath == UNICODE_NULL) {
lpPath = NULL;
}
RtlMoveMemory(p1,lpFileName,FileLength);
if ( ExtensionLength ) {
RtlMoveMemory((PUCHAR)p1+FileLength,lpExtension,ExtensionLength+sizeof(UNICODE_NULL));
}
else {
*(LPWSTR)(((PUCHAR)p1+FileLength)) = UNICODE_NULL;
}
if (RtlDoesFileExists_U(ComputedFileName) ) {
ExtensionLength = RtlGetFullPathName_U(
ComputedFileName,
nBufferLength,
lpBuffer,
lpFilePart
);
if ( AllocatedPath ) {
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
RtlFreeHeap(RtlProcessHeap(), 0, ComputedFileName);
return ExtensionLength/2;
}
}
while ( lpPath );
if ( AllocatedPath ) {
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedPath);
}
RtlFreeHeap(RtlProcessHeap(), 0, ComputedFileName);
SetLastError(ERROR_FILE_NOT_FOUND);
return 0;
}
DWORD
APIENTRY
GetTempPathA(
DWORD nBufferLength,
LPSTR lpBuffer
)
/*++
Routine Description:
ANSI thunk to GetTempPathW
--*/
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
#ifdef DBCS // GetTempPathA(): local variable
ULONG cbAnsiString;
#endif // DBCS
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);
#ifdef DBCS // GetTempPathA(): bug fix
//
// 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));
UnicodeString.Length = (USHORT)GetTempPathW(
(DWORD)(UnicodeString.MaximumLength-sizeof(UNICODE_NULL))/2,
UnicodeString.Buffer) * 2;
Status = RtlUnicodeToMultiByteSize( &cbAnsiString,
UnicodeString.Buffer,
UnicodeString.Length );
if ( nBufferLength < cbAnsiString ) {
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeString.Buffer);
return cbAnsiString;
}
#else
return UnicodeString.Length>>1;
#endif // DBCS
}
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.
--*/
{
DWORD Length;
BOOLEAN AddTrailingSlash;
PUNICODE_STRING Unicode;
UNICODE_STRING EnvironmentValue;
NTSTATUS Status;
LPWSTR Name;
ULONG Position;
nBufferLength *= 2;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
EnvironmentValue = *Unicode;
AddTrailingSlash = FALSE;
Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTmpVariableName,&EnvironmentValue);
if ( !NT_SUCCESS(Status) ) {
Status = RtlQueryEnvironmentVariable_U(NULL,&BaseTempVariableName,&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;
return (Length+sizeof((WCHAR)'\\'))/2;
}
else {
return (Length+sizeof((WCHAR)'\\')+sizeof(UNICODE_NULL))/2;
}
}
else {
return Length/2;
}
}
else {
if ( AddTrailingSlash ) {
Length += sizeof((WCHAR)'\\');
}
return Length/2;
}
}
UINT
APIENTRY
GetTempFileNameA(
LPCSTR lpPathName,
LPCSTR lpPrefixString,
UINT uUnique,
LPSTR lpTempFileName
)
/*++
Routine Description:
ANSI thunk to GetTempFileNameW
--*/
{
PUNICODE_STRING Unicode;
UNICODE_STRING UnicodePrefix;
ANSI_STRING AnsiString;
NTSTATUS Status;
UINT ReturnValue;
UNICODE_STRING UnicodeResult;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpPathName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return 0;
}
RtlInitAnsiString(&AnsiString,lpPrefixString);
Status = Basep8BitStringToUnicodeString(&UnicodePrefix,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return 0;
}
UnicodeResult.MaximumLength = (USHORT)((MAX_PATH<<1)+sizeof(UNICODE_NULL));
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 ) {
RtlInitUnicodeString(&UnicodeResult,UnicodeResult.Buffer);
AnsiString.Buffer = lpTempFileName;
AnsiString.MaximumLength = MAX_PATH+1;
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.
--*/
{
BASE_API_MSG m;
PBASE_GETTEMPFILE_MSG a = (PBASE_GETTEMPFILE_MSG)&m.u.GetTempFile;
LPWSTR p,savedp;
ULONG Length;
HANDLE FileHandle;
ULONG PassCount;
DWORD LastError;
UNICODE_STRING UnicodePath, UnicodePrefix;
CHAR UniqueAsAnsi[8];
CHAR *c;
ULONG i;
PassCount = 0;
RtlInitUnicodeString(&UnicodePath,lpPathName);
Length = UnicodePath.Length;
RtlMoveMemory(lpTempFileName,lpPathName,UnicodePath.MaximumLength);
if ( lpTempFileName[(Length>>1)-1] != (WCHAR)'\\' ) {
lpTempFileName[Length>>1] = (WCHAR)'\\';
Length += sizeof(UNICODE_NULL);
}
lpTempFileName[(Length>>1)-1] = UNICODE_NULL;
i = GetFileAttributesW(lpTempFileName);
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 ) {
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 ) {
PassCount++;
if ( PassCount & 0xffff0000 ) {
return 0;
}
goto try_again;
}
}
else {
a->uUnique = uUnique;
}
//
// Convert the unique value to a 4 byte character string
//
RtlIntegerToChar ((ULONG) a->uUnique,16,5,UniqueAsAnsi);
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 ) {
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 {
LastError = GetLastError();
switch (LastError) {
case ERROR_WRITE_PROTECT :
case ERROR_FILE_NOT_FOUND :
case ERROR_BAD_PATHNAME :
case ERROR_INVALID_NAME :
case ERROR_PATH_NOT_FOUND :
case ERROR_ACCESS_DENIED :
case ERROR_NETWORK_ACCESS_DENIED :
case ERROR_DISK_CORRUPT :
case ERROR_FILE_CORRUPT :
case ERROR_DISK_FULL :
return 0;
}
PassCount++;
if ( PassCount & 0xffff0000 ) {
return 0;
}
goto try_again;
}
}
return a->uUnique;
}
BOOL
APIENTRY
GetDiskFreeSpaceA(
LPCSTR lpRootPathName,
LPDWORD lpSectorsPerCluster,
LPDWORD lpBytesPerSector,
LPDWORD lpNumberOfFreeClusters,
LPDWORD lpTotalNumberOfClusters
)
/*++
Routine Description:
ANSI thunk to GetDiskFreeSpaceW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(
&AnsiString,
ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : "\\"
);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return ( GetDiskFreeSpaceW(
(LPCWSTR)Unicode->Buffer,
lpSectorsPerCluster,
lpBytesPerSector,
lpNumberOfFreeClusters,
lpTotalNumberOfClusters
)
);
}
BOOL
APIENTRY
GetDiskFreeSpaceW(
LPCWSTR lpRootPathName,
LPDWORD lpSectorsPerCluster,
LPDWORD lpBytesPerSector,
LPDWORD lpNumberOfFreeClusters,
LPDWORD lpTotalNumberOfClusters
)
/*++
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];
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;
//
// Check to make sure a root was specified
//
if ( FileName.Buffer[(FileName.Length >> 1)-1] != (WCHAR)'\\' ) {
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_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
);
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);
//
// 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;
}
//
// Deal with 64 bit sizes
//
if ( SizeInfo.TotalAllocationUnits.HighPart ) {
SizeInfo.TotalAllocationUnits.LowPart = (ULONG)-1;
}
if ( SizeInfo.AvailableAllocationUnits.HighPart ) {
SizeInfo.AvailableAllocationUnits.LowPart = (ULONG)-1;
}
*lpSectorsPerCluster = SizeInfo.SectorsPerAllocationUnit;
*lpBytesPerSector = SizeInfo.BytesPerSector;
*lpNumberOfFreeClusters = SizeInfo.AvailableAllocationUnits.LowPart;
*lpTotalNumberOfClusters = SizeInfo.TotalAllocationUnits.LowPart;
return TRUE;
}
WINBASEAPI
BOOL
WINAPI
GetDiskFreeSpaceExA(
LPCSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes
)
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(
&AnsiString,
ARGUMENT_PRESENT(lpDirectoryName) ? lpDirectoryName : "\\"
);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
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;
FILE_FS_SIZE_INFORMATION SizeInfo;
WCHAR DefaultPath[2];
ULARGE_INTEGER BytesPerAllocationUnit;
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,
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
);
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);
//
// 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;
}
//
// jhavens, your quota support needs to modify this slightly
//
BytesPerAllocationUnit.QuadPart = SizeInfo.BytesPerSector * SizeInfo.SectorsPerAllocationUnit;
lpFreeBytesAvailableToCaller->QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.AvailableAllocationUnits.QuadPart;
lpTotalNumberOfBytes->QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.TotalAllocationUnits.QuadPart;
if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
lpTotalNumberOfFreeBytes->QuadPart = lpFreeBytesAvailableToCaller->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;
ANSI_STRING AnsiString;
NTSTATUS Status;
UNICODE_STRING UnicodeVolumeName;
UNICODE_STRING UnicodeFileSystemName;
ANSI_STRING AnsiVolumeName;
ANSI_STRING AnsiFileSystemName;
BOOL ReturnValue;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(
&AnsiString,
ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : "\\"
);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
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);
return FALSE;
}
}
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);
return FALSE;
}
}
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);
return FALSE;
}
}
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
RtlInitUnicodeString(
&UnicodeFileSystemName,
UnicodeFileSystemName.Buffer
);
Status = BasepUnicodeStringTo8BitString(
&AnsiFileSystemName,
&UnicodeFileSystemName,
FALSE
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
}
}
}
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 HardErrorValue;
PTEB Teb;
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
//
Teb = NtCurrentTeb();
HardErrorValue = Teb->HardErrorsAreDisabled;
Teb->HardErrorsAreDisabled = 1;
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
);
Teb->HardErrorsAreDisabled = HardErrorValue;
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 ( 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);
}
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 ( VolumeInfo ) {
//
// BUGBUG DeleteMe NT is still not unicode, so this
// code accounts for that
//
if ( ARGUMENT_PRESENT(lpVolumeNameBuffer) ) {
if ( VolumeInfo->VolumeLabelLength >= nVolumeNameSize ) {
SetLastError(ERROR_BAD_LENGTH);
rv = FALSE;
goto finally_exit;
}
else {
RtlMoveMemory( lpVolumeNameBuffer,
VolumeInfo->VolumeLabel,
VolumeInfo->VolumeLabelLength );
*(lpVolumeNameBuffer + (VolumeInfo->VolumeLabelLength >> 1)) = UNICODE_NULL;
}
}
}
if ( ARGUMENT_PRESENT(lpVolumeSerialNumber) ) {
*lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
}
if ( ARGUMENT_PRESENT(lpFileSystemNameBuffer) ) {
//
// BUGBUG DeleteMe NT is still not unicode, so this
// code accounts for that
//
if ( AttributeInfo->FileSystemNameLength >= nFileSystemNameSize ) {
SetLastError(ERROR_BAD_LENGTH);
rv = FALSE;
goto finally_exit;
}
else {
RtlMoveMemory( 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);
return FALSE;
}
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
)
{
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);
for ( i=0; i<26; i++ ) {
RootName.Buffer[0] = (CHAR)((CHAR)i+'A');
if (USER_SHARED_DATA->DosDeviceMap & (1 << i) ) {
BytesNeeded += RootName.MaximumLength;
if ( BytesNeeded < (USHORT)BytesLeft ) {
RtlMoveMemory(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
)
{
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);
for ( i=0; i<26; i++ ) {
RootName.Buffer[0] = (WCHAR)((CHAR)i+'A');
if (USER_SHARED_DATA->DosDeviceMap & (1 << i) ) {
BytesNeeded += RootName.MaximumLength;
if ( BytesNeeded < (USHORT)BytesLeft ) {
RtlMoveMemory(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;
ANSI_STRING AnsiString;
NTSTATUS Status;
UNICODE_STRING UnicodeVolumeName;
BOOL ReturnValue;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(
&AnsiString,
ARGUMENT_PRESENT(lpRootPathName) ? lpRootPathName : "\\"
);
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return FALSE;
}
if ( ARGUMENT_PRESENT(lpVolumeName) ) {
RtlInitAnsiString(&AnsiString,lpVolumeName);
Status = RtlAnsiStringToUnicodeString(&UnicodeVolumeName,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
}
else {
UnicodeVolumeName.Buffer = NULL;
}
ReturnValue = SetVolumeLabelW((LPCWSTR)Unicode->Buffer,(LPCWSTR)UnicodeVolumeName.Buffer);
if ( 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;
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;
}
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
);
//
// 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;
}