Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

4744 lines
123 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
file.c
Abstract:
General file-related functions.
Author:
Mike Condra 16-Aug-1996
Revision History:
calinn 23-Sep-1998 Additional options to file enum
jimschm 05-Feb-1998 File enumeration code
jimschm 30-Sep-1997 WriteFileString routines
--*/
#include "pch.h"
//
// Function accepts paths within the limit of our stack variable size
//
BOOL
IsPathLengthOkA (
IN PCSTR FileSpec
)
{
return SizeOfStringA(FileSpec) < MAX_MBCHAR_PATH;
}
BOOL
IsPathLengthOkW (
IN PCWSTR FileSpec
)
{
return SizeOfStringW(FileSpec) < (MAX_WCHAR_PATH * sizeof (WCHAR));
}
BOOL
IsPathOnFixedDriveA (
IN PCSTR FileSpec OPTIONAL
)
{
static CHAR root[] = "?:\\";
UINT type;
static BOOL lastResult;
if (!FileSpec) {
return FALSE;
}
if (!FileSpec[0]) {
return FALSE;
}
if (FileSpec[1] != ':' || FileSpec[2] != '\\') {
return FALSE;
}
if (root[0] == FileSpec[0]) {
return lastResult;
}
root[0] = FileSpec[0];
type = GetDriveTypeA (root);
if (type != DRIVE_FIXED && type != DRIVE_REMOTE) {
DEBUGMSGA_IF ((
type != DRIVE_REMOVABLE && type != DRIVE_NO_ROOT_DIR,
DBG_VERBOSE,
"Path %s is on unexpected drive type %u",
FileSpec,
type
));
lastResult = FALSE;
} else {
lastResult = TRUE;
}
return lastResult;
}
BOOL
IsPathOnFixedDriveW (
IN PCWSTR FileSpec OPTIONAL
)
{
static WCHAR root[] = L"?:\\";
UINT type;
static BOOL lastResult;
PCWSTR p;
if (!FileSpec) {
return FALSE;
}
p = FileSpec;
if (p[0] == L'\\' && p[1] == L'\\' && p[2] == L'?' && p[3] == L'\\') {
p += 4;
}
MYASSERT (ISNT());
if (!p[0]) {
return FALSE;
}
if (p[1] != L':' || p[2] != L'\\') {
return FALSE;
}
if (root[0] == p[0]) {
return lastResult;
}
root[0] = p[0];
type = GetDriveTypeW (root);
if (type != DRIVE_FIXED && type != DRIVE_REMOTE) {
DEBUGMSGW_IF ((
type != DRIVE_REMOVABLE && type != DRIVE_NO_ROOT_DIR,
DBG_VERBOSE,
"Path %s is on unexpected drive type %u",
FileSpec,
type
));
lastResult = FALSE;
} else {
lastResult = TRUE;
}
return lastResult;
}
BOOL
CopyFileSpecToLongA (
IN PCSTR FullFileSpecIn,
OUT PSTR OutPath
)
{
CHAR fullFileSpec[MAX_MBCHAR_PATH];
WIN32_FIND_DATAA findData;
HANDLE findHandle;
PSTR end;
PSTR currentIn;
PSTR currentOut;
PSTR outEnd;
PSTR maxOutPath = OutPath + MAX_PATH - 1;
BOOL result = FALSE;
UINT oldMode;
BOOL forceCopy = FALSE;
oldMode = SetErrorMode (SEM_FAILCRITICALERRORS);
__try {
//
// Limit length
//
if (!IsPathLengthOkA (FullFileSpecIn)) {
DEBUGMSGA ((DBG_ERROR, "Inbound file spec is too long: %s", FullFileSpecIn));
__leave;
}
//
// If path is on removable media, don't touch the disk
//
if (!IsPathOnFixedDriveA (FullFileSpecIn)) {
forceCopy = TRUE;
__leave;
}
//
// Make a copy of the file spec so we can truncate it at the wacks
//
StringCopyA (fullFileSpec, FullFileSpecIn);
//
// Begin building the path
//
OutPath[0] = fullFileSpec[0];
OutPath[1] = fullFileSpec[1];
OutPath[2] = fullFileSpec[2];
OutPath[3] = 0;
currentIn = fullFileSpec + 3;
currentOut = OutPath + 3;
for (;;) {
end = _mbschr (currentIn, '\\');
if (end == (currentIn + 1)) {
currentIn++;
continue;
}
if (end) {
*end = 0;
}
findHandle = FindFirstFileA (fullFileSpec, &findData);
if (findHandle != INVALID_HANDLE_VALUE) {
FindClose (findHandle);
//
// Copy long file name obtained from FindFirstFile
//
outEnd = currentOut + TcharCountA (findData.cFileName);
if (outEnd > maxOutPath) {
#ifdef DEBUG
*currentOut = 0;
DEBUGMSGA ((
DBG_WARNING,
"Path %s too long to append to %s",
findData.cFileName,
OutPath
));
#endif
__leave;
}
StringCopyA (currentOut, findData.cFileName);
currentOut = outEnd;
} else {
//
// Copy the rest of the path since it doesn't exist
//
if (end) {
*end = '\\';
}
outEnd = currentOut + TcharCountA (currentIn);
if (outEnd > maxOutPath) {
#ifdef DEBUG
DEBUGMSGA ((
DBG_WARNING,
"Path %s too long to append to %s",
currentIn,
OutPath
));
#endif
__leave;
}
StringCopyA (currentOut, currentIn);
break; // done with path
}
if (!end) {
MYASSERT (*currentOut == 0);
break; // done with path
}
*currentOut++ = '\\';
*currentOut = 0;
*end = '\\';
currentIn = end + 1;
}
result = TRUE;
}
__finally {
SetErrorMode (oldMode);
}
if (forceCopy) {
StringCopyA (OutPath, FullFileSpecIn);
return TRUE;
}
if (!result) {
StringCopyTcharCountA (OutPath, FullFileSpecIn, MAX_PATH);
}
return result;
}
BOOL
CopyFileSpecToLongW (
IN PCWSTR FullFileSpecIn,
OUT PWSTR OutPath
)
{
WCHAR fullFileSpec[MAX_WCHAR_PATH];
WIN32_FIND_DATAW findData;
HANDLE findHandle;
PWSTR end;
PWSTR currentIn;
PWSTR currentOut;
PWSTR outEnd;
PWSTR maxOutPath = OutPath + MAX_PATH - 1;
BOOL result = FALSE;
UINT oldMode;
BOOL forceCopy = FALSE;
MYASSERT (ISNT());
oldMode = SetErrorMode (SEM_FAILCRITICALERRORS);
__try {
//
// Limit length
//
if (!IsPathLengthOkW (FullFileSpecIn)) {
DEBUGMSGW ((DBG_ERROR, "Inbound file spec is too long: %s", FullFileSpecIn));
__leave;
}
//
// If path is on removable media, don't touch the disk
//
if (!IsPathOnFixedDriveW (FullFileSpecIn)) {
forceCopy = TRUE;
__leave;
}
//
// Make a copy of the file spec so we can truncate it at the wacks
//
StringCopyW (fullFileSpec, FullFileSpecIn);
//
// Begin building the path
//
OutPath[0] = fullFileSpec[0];
OutPath[1] = fullFileSpec[1];
OutPath[2] = fullFileSpec[2];
OutPath[3] = 0;
currentIn = fullFileSpec + 3;
currentOut = OutPath + 3;
for (;;) {
end = wcschr (currentIn, L'\\');
if (end == (currentIn + 1)) {
currentIn++;
continue;
}
if (end) {
*end = 0;
}
findHandle = FindFirstFileW (fullFileSpec, &findData);
if (findHandle != INVALID_HANDLE_VALUE) {
FindClose (findHandle);
//
// Copy long file name obtained from FindFirstFile
//
outEnd = currentOut + TcharCountW (findData.cFileName);
if (outEnd > maxOutPath) {
DEBUGMSGW ((
DBG_WARNING,
"Path %s too long to append to %s",
findData.cFileName,
OutPath
));
__leave;
}
StringCopyW (currentOut, findData.cFileName);
currentOut = outEnd;
} else {
//
// Copy the rest of the path since it doesn't exist
//
if (end) {
*end = L'\\';
}
outEnd = currentOut + TcharCountW (currentIn);
if (outEnd > maxOutPath) {
DEBUGMSGW ((
DBG_WARNING,
"Path %s too long to append to %s",
currentIn,
OutPath
));
__leave;
}
StringCopyW (currentOut, currentIn);
break; // done with path
}
if (!end) {
MYASSERT (*currentOut == 0);
break; // done with path
}
*currentOut++ = L'\\';
*currentOut = 0;
*end = L'\\';
currentIn = end + 1;
}
result = TRUE;
}
__finally {
SetErrorMode (oldMode);
}
if (forceCopy) {
StringCopyW (OutPath, FullFileSpecIn);
return TRUE;
}
if (!result) {
StringCopyTcharCountW (OutPath, FullFileSpecIn, MAX_PATH);
}
return result;
}
BOOL
DoesFileExistExA(
IN PCSTR FileName,
OUT PWIN32_FIND_DATAA FindData OPTIONAL
)
/*++
Routine Description:
Determine if a file exists and is accessible.
Errormode is set (and then restored) so the user will not see
any pop-ups.
Arguments:
FileName - supplies full path of file to check for existance.
FindData - if specified, receives find data for the file.
Return Value:
TRUE if the file exists and is accessible.
FALSE if not. GetLastError() returns extended error info.
--*/
{
WIN32_FIND_DATAA ourFindData;
HANDLE FindHandle;
UINT OldMode;
DWORD Error;
if (!FindData) {
return GetFileAttributesA (FileName) != 0xffffffff;
}
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
FindHandle = FindFirstFileA(FileName, &ourFindData);
if (FindHandle == INVALID_HANDLE_VALUE) {
Error = GetLastError();
} else {
FindClose(FindHandle);
*FindData = ourFindData;
Error = NO_ERROR;
}
SetErrorMode(OldMode);
SetLastError(Error);
return (Error == NO_ERROR);
}
BOOL
DoesFileExistExW (
IN PCWSTR FileName,
OUT PWIN32_FIND_DATAW FindData OPTIONAL
)
/*++
Routine Description:
Determine if a file exists and is accessible.
Errormode is set (and then restored) so the user will not see
any pop-ups.
Arguments:
FileName - supplies full path of file to check for existance.
FindData - if specified, receives find data for the file.
Return Value:
TRUE if the file exists and is accessible.
FALSE if not. GetLastError() returns extended error info.
--*/
{
WIN32_FIND_DATAW ourFindData;
HANDLE FindHandle;
UINT OldMode;
DWORD Error = NO_ERROR;
UINT length;
BOOL result = FALSE;
PCWSTR longFileName = NULL;
__try {
if (FileName[0] != TEXT('\\')) {
length = TcharCountW (FileName);
if (length >= MAX_PATH) {
longFileName = JoinPathsW (L"\\\\?", FileName);
MYASSERT (longFileName);
FileName = longFileName;
}
}
if (!FindData) {
result = (GetLongPathAttributesW (FileName) != 0xffffffff);
__leave;
}
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
FindHandle = FindFirstFileW(FileName,&ourFindData);
if (FindHandle == INVALID_HANDLE_VALUE) {
Error = GetLastError();
} else {
FindClose(FindHandle);
*FindData = ourFindData;
}
SetErrorMode(OldMode);
SetLastError(Error);
result = (Error == NO_ERROR);
}
__finally {
if (longFileName) {
FreePathStringW (longFileName);
}
}
return result;
}
DWORD
MakeSurePathExistsA(
IN PCSTR FullFileSpec,
IN BOOL PathOnly
)
{
CHAR Buffer[MAX_MBCHAR_PATH];
PCHAR p,q;
BOOL Done;
BOOL isUnc;
DWORD d;
WIN32_FIND_DATAA FindData;
isUnc = (FullFileSpec[0] == '\\') && (FullFileSpec[1] == '\\');
//
// Locate and strip off the final component
//
_mbssafecpy(Buffer,FullFileSpec,sizeof(Buffer));
p = _mbsrchr(Buffer, '\\');
if (p) {
if (!PathOnly) {
*p = 0;
}
//
// If it's a drive root, nothing to do.
//
if(Buffer[0] && (Buffer[1] == ':') && !Buffer[2]) {
return(NO_ERROR);
}
} else {
//
// Just a relative filename, nothing to do.
//
return(NO_ERROR);
}
//
// If it already exists do nothing.
//
if (DoesFileExistExA (Buffer,&FindData)) {
return NO_ERROR;
}
p = Buffer;
//
// Compensate for drive spec.
//
if(p[0] && (p[1] == ':')) {
p += 2;
}
//
// Compensate for UNC paths.
//
if (isUnc) {
//
// Skip the initial wack wack before machine name.
//
p += 2;
//
// Skip to the share.
//
p = _mbschr(p, '\\');
if (p==NULL) {
return ERROR_BAD_PATHNAME;
}
//
// Skip past the share.
//
p = _mbschr(p, '\\');
if (p==NULL) {
return ERROR_BAD_PATHNAME;
}
}
Done = FALSE;
do {
//
// Skip path sep char.
//
while(*p == '\\') {
p++;
}
//
// Locate next path sep char or terminating nul.
//
if(q = _mbschr(p, '\\')) {
*q = 0;
} else {
q = GetEndOfStringA(p);
Done = TRUE;
}
//
// Create this portion of the path.
//
if(!CreateDirectoryA(Buffer,NULL)) {
d = GetLastError();
if(d != ERROR_ALREADY_EXISTS) {
return(d);
}
}
if(!Done) {
*q = '\\';
p = q+1;
}
} while(!Done);
return(NO_ERROR);
}
VOID
DestPathCopyW (
OUT PWSTR DestPath,
IN PCWSTR SrcPath
)
{
PCWSTR p;
PWSTR q;
PCWSTR end;
PCWSTR maxStart;
UINT len;
UINT count;
len = TcharCountW (SrcPath);
if (len < MAX_PATH) {
StringCopyW (DestPath, SrcPath);
return;
}
//
// Path is too long -- try to truncate it
//
wsprintfW (DestPath, L"%c:\\Long", SrcPath[0]);
CreateDirectoryW (DestPath, NULL);
p = SrcPath;
end = SrcPath + len;
maxStart = end - 220;
while (p < end) {
if (*p == '\\') {
if (p >= maxStart) {
break;
}
}
p++;
}
if (p == end) {
p = maxStart;
}
MYASSERT (TcharCountW (p) <= 220);
StringCopyW (AppendWackW (DestPath), p);
q = (PWSTR) GetEndOfStringW (DestPath);
//
// Verify there is no collision
//
for (count = 1 ; count < 1000000 ; count++) {
if (GetFileAttributesW (DestPath) == INVALID_ATTRIBUTES) {
break;
}
wsprintfW (q, L" (%u)", count);
}
}
DWORD
MakeSurePathExistsW(
IN LPCWSTR FullFileSpec,
IN BOOL PathOnly
)
{
PWSTR buffer;
WCHAR *p, *q;
BOOL Done;
DWORD d;
WIN32_FIND_DATAW FindData;
DWORD result = NO_ERROR;
if (FullFileSpec[0] != L'\\') {
if (TcharCountW (FullFileSpec) >= MAX_PATH) {
if (PathOnly || ((wcsrchr (FullFileSpec, L'\\') - FullFileSpec) >= MAX_PATH)) {
LOGW ((LOG_ERROR, "Can't create path %s because it is too long", FullFileSpec));
return ERROR_FILENAME_EXCED_RANGE;
}
}
}
//
// Locate and strip off the final component
//
buffer = DuplicatePathStringW (FullFileSpec, 0);
__try {
p = wcsrchr(buffer, L'\\');
if (p) {
if (!PathOnly) {
*p = 0;
}
} else {
//
// Just a relative filename, nothing to do.
//
__leave;
}
//
// If it already exists do nothing.
//
if (DoesFileExistExW (buffer, &FindData)) {
result = ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? NO_ERROR : ERROR_DIRECTORY);
__leave;
}
p = buffer;
//
// Compensate for drive spec.
//
if (p[0] == L'\\' && p[1] == L'\\' && p[2] == L'?' && p[3] == L'\\') {
p += 4;
}
if (p[0] && (p[1] == L':')) {
p += 2;
}
if ((p[0] == 0) || (p[0] == L'\\' && p[1] == 0)) {
//
// Root -- leave
//
__leave;
}
Done = FALSE;
do {
//
// Skip path sep char.
//
while(*p == L'\\') {
p++;
}
//
// Locate next path sep char or terminating nul.
//
q = wcschr(p, L'\\');
if(q) {
*q = 0;
} else {
q = GetEndOfStringW (p);
Done = TRUE;
}
//
// Create this portion of the path.
//
if(!CreateDirectoryW(buffer,NULL)) {
d = GetLastError();
if(d != ERROR_ALREADY_EXISTS) {
result = d;
__leave;
}
}
if(!Done) {
*q = L'\\';
p = q+1;
}
} while(!Done);
}
__finally {
FreePathStringW (buffer);
}
return result;
}
//
// ...PACKFILE HANDLING...
//
#define PACKFILE_BUFFERSIZE 2048
BOOL
pFillEnumStructureA (
IN PPACKFILEENUMA Enum
)
{
BOOL rSuccess = TRUE;
DWORD numBytesRead;
HANDLE savedHandle;
MYASSERT(Enum && Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
//
// Save this away.. The read below blows it away.
//
savedHandle = Enum -> Handle;
//
// Read the header information from the current position in the file.
//
rSuccess = ReadFile(
Enum -> Handle,
Enum,
sizeof(PACKFILEENUMA),
&numBytesRead,
NULL
);
//
// Restore the handle member.
//
Enum -> Handle = savedHandle;
return rSuccess && numBytesRead == sizeof(PACKFILEENUMA);
}
BOOL
PackedFile_ExtractFileUsingEnumA (
IN PPACKFILEENUMA Enum,
IN LPCSTR FileName OPTIONAL
)
{
BOOL rSuccess = TRUE;
HANDLE newFileHandle;
LONGLONG numberOfBytesToExtract;
LONGLONG numberOfBytesExtracted;
DWORD numberOfBytesToRead;
DWORD numberOfBytesRead;
BYTE buffer[PACKFILE_BUFFERSIZE];
DWORD fileHigh;
DWORD fileLow;
MYASSERT(Enum && Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
//
// First, attempt to create the new file. If FileName was not specified, we'll use the
// Identifier name in the enum struct.
//
if (!FileName) {
FileName = Enum -> Identifier;
}
newFileHandle = CreateFileA (
FileName,
GENERIC_WRITE,
0, // No sharing.
NULL, // No inheritance.
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL // No template file.
);
if (newFileHandle == INVALID_HANDLE_VALUE) {
rSuccess = FALSE;
DEBUGMSG((DBG_ERROR,"PackedFile_ExtractFromEnum: Could not open file %s. FileName"));
}
else {
//
// File was successfully opened. Extract the data starting from the current file position
//
//
// Create a LONGLONG value out of the size of the file.
//
numberOfBytesToExtract = ((LONGLONG)Enum -> SizeHigh) << 32 | ((LONGLONG) Enum -> SizeLow);
numberOfBytesExtracted = 0;
do {
//
// Figure out how much to read from the file.
//
if (numberOfBytesToExtract - numberOfBytesExtracted > PACKFILE_BUFFERSIZE) {
numberOfBytesToRead = PACKFILE_BUFFERSIZE;
}
else {
numberOfBytesToRead = (DWORD) (numberOfBytesToExtract - numberOfBytesExtracted);
}
if (!ReadFile(
Enum -> Handle,
buffer,
numberOfBytesToRead,
&numberOfBytesRead,
NULL
) ||
!WriteFile(
newFileHandle,
buffer,
numberOfBytesRead,
&numberOfBytesRead,
NULL
)) {
numberOfBytesExtracted += (LONGLONG) numberOfBytesRead;
break;
}
//
// Update the count of bytes extracted.
//
numberOfBytesExtracted += (LONGLONG) numberOfBytesRead;
} while (numberOfBytesExtracted < numberOfBytesToExtract);
//
// Close the handle to the new file we created.
//
CloseHandle(newFileHandle);
//
// Reset the file pointer.
//
fileHigh = (DWORD) (numberOfBytesExtracted >> 32);
fileLow = (DWORD) (numberOfBytesExtracted & 0xffffffff);
SetFilePointer(Enum -> Handle,fileLow,&fileHigh,FILE_CURRENT);
if (numberOfBytesExtracted != numberOfBytesToExtract) {
rSuccess = FALSE;
DEBUGMSG((DBG_ERROR,"PackedFile_ExtractFromEnum: Could not extract file."));
}
}
return rSuccess;
}
VOID
PackedFile_AbortEnum (
IN OUT PPACKFILEENUMA Enum
)
{
MYASSERT(Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
//
// Nothing to do except close the handle.
//
CloseHandle(Enum -> Handle);
}
BOOL
PackedFile_EnumNextA (
IN PPACKFILEENUMA Enum
)
{
BOOL rSuccess = TRUE;
MYASSERT(Enum && Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
//
// Move the file pointer ahead by the size contained in the current enum structure.
//
if (SetFilePointer(Enum -> Handle,Enum -> SizeLow,&Enum -> SizeHigh,FILE_CURRENT) == 0xffffffff &&
GetLastError() != NO_ERROR) {
rSuccess = FALSE;
}
else {
//
// Fill in the enum structure with the fresh data.
//
rSuccess = pFillEnumStructureA(Enum);
}
if (!rSuccess) {
PackedFile_AbortEnum(Enum);
}
return rSuccess;
}
BOOL
PackedFile_EnumFirstA (
IN LPCSTR PackFile,
OUT PPACKFILEENUMA Enum
)
{
BOOL rSuccess = FALSE;
MYASSERT(Enum && PackFile);
//
// Clean out the Enum structure.
//
ZeroMemory(Enum,sizeof(PACKFILEENUMA));
//
// Open a handle to the PackFile.
//
Enum -> Handle = CreateFileA (
PackFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // No inheritance.
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL // No template file.
);
//
// If that succeeds, trust EnumNext to handle the dirty work.
//
if (Enum -> Handle != INVALID_HANDLE_VALUE) {
rSuccess = pFillEnumStructureA(Enum);
}
return rSuccess;
}
BOOL
PackedFile_ExtractFileA (
IN LPCSTR PackFile,
IN LPCSTR FileIdentifier,
IN LPCSTR FileName OPTIONAL
)
{
PACKFILEENUMA e;
BOOL rSuccess = FALSE;
MYASSERT(PackFile && FileIdentifier);
if (PackedFile_EnumFirstA(PackFile,&e)) {
do {
if (StringIMatchA (e.Identifier,FileIdentifier)) {
//
// We found the one they were looking for..
//
rSuccess = PackedFile_ExtractFileUsingEnumA(&e,FileName);
PackedFile_AbortEnum(&e);
break;
}
} while (PackedFile_EnumNextA(&e));
}
return rSuccess;
}
BOOL
PackedFile_AddFileA (
IN LPCSTR PackFile,
IN LPCSTR NewFile,
IN LPCSTR Identifier OPTIONAL
)
{
HANDLE packFileHandle = INVALID_HANDLE_VALUE;
HANDLE newFileHandle = INVALID_HANDLE_VALUE;
BOOL rSuccess = TRUE;
PACKFILEENUMA fileHeader;
DWORD numBytes;
BYTE buffer[PACKFILE_BUFFERSIZE];
//
// Now, attempt to open the new file.
//
newFileHandle = CreateFileA (
NewFile,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (newFileHandle == INVALID_HANDLE_VALUE) {
DEBUGMSG((DBG_ERROR,"PackedFile_AddFile could not open %s and therefore cannot add it.",NewFile));
return FALSE;
}
//
// Open or create the packfile. If it does not already exist, then it will be created.
//
packFileHandle = CreateFileA (
PackFile,
GENERIC_READ | GENERIC_WRITE,
0, // No sharing.
NULL, // No inheritance.
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL // No template file.
);
if (packFileHandle == INVALID_HANDLE_VALUE) {
rSuccess = FALSE;
DEBUGMSG((DBG_ERROR,"PackedFile_AddFile Could not open or create the packed file %s.",PackFile));
} else {
//
// Both files have been successfully opened. Add the new file to the packfile.
//
//
// First, we need to set the file pointer to the end of the packed file.
//
SetFilePointer(packFileHandle,0,NULL,FILE_END);
//
// Ok, Fill in a header structure for this file. It is a simple header. All it contains
// is the Identifier (or the file path if Identifier is NULL) and the size of the file.
// There is another parameter (Handle) in the structure, but this is only used
// for enumeration purposes and is always NULL when written into the file.
//
if (!Identifier) {
Identifier = NewFile;
}
fileHeader.Handle = NULL; // This member is only used in enumeration.
_mbssafecpy(fileHeader.Identifier,Identifier,MAX_MBCHAR_PATH);
fileHeader.SizeLow = GetFileSize(newFileHandle,&fileHeader.SizeHigh);
if (fileHeader.SizeLow == 0xffffffff && GetLastError() != NO_ERROR) {
rSuccess = FALSE;
DEBUGMSG((DBG_ERROR,"PackedFile_AddFile Could not get the file size for %s.",NewFile));
}
else {
//
// Now, write the header into the packed file.
//
if (!WriteFile(
packFileHandle,
&fileHeader,
sizeof(PACKFILEENUMA),
&numBytes,
NULL // Not overlapped.
)) {
DEBUGMSG((DBG_ERROR,"PackedFile_AddFile Could not write a file header to the pack file %s.",PackFile));
rSuccess = FALSE;
}
else {
//
// At this point, all that is left to do is to write the bits from the packed file into
// the packed file.
//
do {
if (!ReadFile(
newFileHandle,
buffer,
PACKFILE_BUFFERSIZE,
&numBytes,
NULL
) ||
!WriteFile(
packFileHandle,
buffer,
numBytes,
&numBytes,
NULL
)) {
rSuccess = FALSE;
DEBUGMSG((DBG_ERROR,"PackedFile_AddFile encountered an error writing the file %s to the packed file %s.",NewFile,PackFile));
break;
}
} while (numBytes == PACKFILE_BUFFERSIZE);
}
}
//
// Close the handles to both files. We are done with them.
//
CloseHandle(packFileHandle);
}
CloseHandle(newFileHandle);
return rSuccess;
}
//
// The W versions of these files are unimplemented.
//
BOOL
PackedFile_AddFileW (
IN LPCSTR PackFile,
IN LPCSTR NewFile,
IN LPCSTR Identifier OPTIONAL
)
{
return FALSE;
}
BOOL
PackedFile_ExtractFileW (
IN LPCSTR PackFile,
IN LPCSTR FileIdentifier,
IN LPCSTR FileName OPTIONAL
)
{
return FALSE;
}
BOOL
PackedFile_EnumFirstW (
IN LPCSTR PackFile,
OUT PPACKFILEENUMA Enum
)
{
return FALSE;
}
BOOL
PackedFile_EnumNextW (
IN PPACKFILEENUMA Enum
)
{
return FALSE;
}
BOOL
PackedFile_ExtractFileUsingEnumW (
IN PPACKFILEENUMA Enum,
IN LPCSTR FileName OPTIONAL
)
{
return FALSE;
}
BOOL
WriteFileStringA (
IN HANDLE File,
IN PCSTR String
)
/*++
Routine Description:
Writes a DBCS string to the specified file.
Arguments:
File - Specifies the file handle that was opened with write access.
String - Specifies the nul-terminated string to write to the file.
Return Value:
TRUE if successful, FALSE if an error occurred. Call GetLastError
for error condition.
--*/
{
DWORD DontCare;
return WriteFile (File, String, ByteCountA (String), &DontCare, NULL);
}
BOOL
WriteFileStringW (
IN HANDLE File,
IN PCWSTR String
)
/*++
Routine Description:
Converts a UNICODE string to DBCS, then Writes it to the specified file.
Arguments:
File - Specifies the file handle that was opened with write access.
String - Specifies the UNICODE nul-terminated string to convert and
write to the file.
Return Value:
TRUE if successful, FALSE if an error occurred. Call GetLastError for
error condition.
--*/
{
DWORD DontCare;
PCSTR AnsiVersion;
BOOL b;
AnsiVersion = ConvertWtoA (String);
if (!AnsiVersion) {
return FALSE;
}
b = WriteFile (File, AnsiVersion, ByteCountA (AnsiVersion), &DontCare, NULL);
FreeConvertedStr (AnsiVersion);
return b;
}
/*++
Routine Description:
pFindShortNameA is a helper function for OurGetLongPathName. It
obtains the short file name, if it exists, using FindFirstFile.
Arguments:
WhatToFind - Specifies the short or long name of a file to locate
Buffer - Receives the matching file name
Return Value:
TRUE if the file was found and Buffer was updated, or FALSE if the
file was not found and Buffer was not updated.
--*/
BOOL
pFindShortNameA (
IN PCSTR WhatToFind,
OUT PSTR Buffer,
OUT INT *BufferSizeInBytes
)
{
WIN32_FIND_DATAA fd;
HANDLE hFind;
hFind = FindFirstFileA (WhatToFind, &fd);
if (hFind == INVALID_HANDLE_VALUE) {
return FALSE;
}
FindClose (hFind);
*BufferSizeInBytes -= ByteCountA (fd.cFileName);
if (*BufferSizeInBytes >= sizeof (CHAR)) {
StringCopyA (Buffer, fd.cFileName);
}
return TRUE;
}
BOOL
pFindShortNameW (
IN PCWSTR WhatToFind,
OUT PWSTR Buffer,
OUT INT *BufferSizeInBytes
)
{
WIN32_FIND_DATAA fdA;
WIN32_FIND_DATAW fdW;
PCWSTR UnicodeVersion;
PCSTR AnsiVersion;
HANDLE hFind;
if (ISNT ()) {
hFind = FindFirstFileW (WhatToFind, &fdW);
if (hFind == INVALID_HANDLE_VALUE) {
return FALSE;
}
FindClose (hFind);
} else {
AnsiVersion = ConvertWtoA (WhatToFind);
hFind = FindFirstFileA (AnsiVersion, &fdA);
FreeConvertedStr (AnsiVersion);
if (hFind == INVALID_HANDLE_VALUE) {
return FALSE;
}
FindClose (hFind);
fdW.dwFileAttributes = fdA.dwFileAttributes;
fdW.ftCreationTime = fdA.ftCreationTime;
fdW.ftLastAccessTime = fdA.ftLastAccessTime;
fdW.ftLastWriteTime = fdA.ftLastWriteTime;
fdW.nFileSizeHigh = fdA.nFileSizeHigh;
fdW.nFileSizeLow = fdA.nFileSizeLow;
fdW.dwReserved0 = fdA.dwReserved0;
fdW.dwReserved1 = fdA.dwReserved1;
UnicodeVersion = ConvertAtoW (fdA.cFileName);
StringCopyTcharCountW (fdW.cFileName, UnicodeVersion, MAX_PATH);
FreeConvertedStr (UnicodeVersion);
UnicodeVersion = ConvertAtoW (fdA.cAlternateFileName);
StringCopyTcharCountW (fdW.cAlternateFileName, UnicodeVersion, 14);
FreeConvertedStr (UnicodeVersion);
}
*BufferSizeInBytes -= ByteCountW (fdW.cFileName);
if (*BufferSizeInBytes >= sizeof (WCHAR)) {
StringCopyW (Buffer, fdW.cFileName);
}
return TRUE;
}
/*++
Routine Description:
OurGetLongPathName locates the long name for a file. It first locates the
full path if a path is not explicitly provided, and then uses FindFirstFile
to get the long file name. NOTE: This is exactly what the Win32 function
GetLongPathName does, but unfortunately the Win32 API is not available on Win95.
This routine resolves each piece of a short path name using recursion.
Arguments:
ShortPath - Specifies the file name or full file path to locate
Buffer - Receives the full file path. This buffer must be big enough to
handle the maximum file name size.
Return Value:
TRUE if the file is found and Buffer contains the long name, or FALSE
if the file is not found and Buffer is not modified.
--*/
BOOL
OurGetLongPathNameA (
IN PCSTR ShortPath,
OUT PSTR Buffer,
IN INT BufferSizeInBytes
)
{
CHAR FullPath[MAX_MBCHAR_PATH];
PCSTR SanitizedPath;
PSTR FilePart;
PSTR BufferEnd;
PSTR p, p2;
MBCHAR c;
BOOL result = TRUE;
MYASSERT (BufferSizeInBytes >= MAX_MBCHAR_PATH);
if (ShortPath[0] == 0) {
return FALSE;
}
__try {
SanitizedPath = SanitizePathA (ShortPath);
if (!SanitizedPath) {
SanitizedPath = DuplicatePathStringA (ShortPath, 0);
}
if (!_mbschr (SanitizedPath, '\\')) {
if (!SearchPathA (NULL, SanitizedPath, NULL, sizeof (FullPath), FullPath, &FilePart)) {
result = FALSE;
__leave;
}
} else {
GetFullPathNameA (SanitizedPath, sizeof (FullPath), FullPath, &FilePart);
}
//
// Convert short paths to long paths
//
p = FullPath;
if (!IsPathOnFixedDriveA (FullPath)) {
_mbssafecpy (Buffer, FullPath, BufferSizeInBytes);
__leave;
}
p += 3;
// Copy drive letter to buffer
StringCopyABA (Buffer, FullPath, p);
BufferEnd = GetEndOfStringA (Buffer);
BufferSizeInBytes -= p - FullPath;
// Convert each portion of the path
do {
// Locate end of this file or dir
p2 = _mbschr (p, '\\');
if (!p2) {
p = GetEndOfStringA (p);
} else {
p = p2;
}
// Look up file
c = *p;
*p = 0;
if (!pFindShortNameA (FullPath, BufferEnd, &BufferSizeInBytes)) {
DEBUGMSG ((DBG_VERBOSE, "OurGetLongPathNameA: %s does not exist", FullPath));
result = FALSE;
__leave;
}
*p = (CHAR)c;
// Move on to next part of path
if (*p) {
p = _mbsinc (p);
if (BufferSizeInBytes >= sizeof (CHAR) * 2) {
BufferEnd = _mbsappend (BufferEnd, "\\");
BufferSizeInBytes -= sizeof (CHAR);
}
}
} while (*p);
}
__finally {
FreePathStringA (SanitizedPath);
}
return result;
}
DWORD
OurGetShortPathNameW (
IN PCWSTR LongPath,
OUT PWSTR ShortPath,
IN DWORD CharSize
)
{
PCSTR LongPathA;
PSTR ShortPathA;
PCWSTR ShortPathW;
DWORD result;
if (ISNT()) {
return GetShortPathNameW (LongPath, ShortPath, CharSize);
} else {
LongPathA = ConvertWtoA (LongPath);
if (!IsPathOnFixedDriveA (LongPathA)) {
StringCopyTcharCountW (ShortPath, LongPath, CharSize);
FreeConvertedStr (LongPathA);
return TcharCountW (ShortPath);
}
ShortPathA = AllocPathStringA (CharSize);
result = GetShortPathNameA (LongPathA, ShortPathA, CharSize);
if (result) {
ShortPathW = ConvertAtoW (ShortPathA);
StringCopyTcharCountW (ShortPath, ShortPathW, CharSize);
FreeConvertedStr (ShortPathW);
} else {
StringCopyTcharCountW (ShortPath, LongPath, CharSize);
}
FreePathStringA (ShortPathA);
FreeConvertedStr (LongPathA);
return result;
}
}
DWORD
OurGetFullPathNameW (
PCWSTR FileName,
DWORD CharSize,
PWSTR FullPath,
PWSTR *FilePtr
)
{
PCSTR FileNameA;
PSTR FullPathA;
PSTR FilePtrA;
PCWSTR FullPathW;
DWORD result;
DWORD err;
if (ISNT()) {
return GetFullPathNameW (FileName, CharSize, FullPath, FilePtr);
} else {
FileNameA = ConvertWtoA (FileName);
FullPathA = AllocPathStringA (CharSize);
result = GetFullPathNameA (FileNameA, CharSize, FullPathA, &FilePtrA);
FullPathW = ConvertAtoW (FullPathA);
StringCopyTcharCountW (FullPath, FullPathW, CharSize);
err = GetLastError ();
*FilePtr = (PWSTR)GetFileNameFromPathW (FullPath);
FreeConvertedStr (FullPathW);
FreePathStringA (FullPathA);
FreeConvertedStr (FileNameA);
return result;
}
}
BOOL
OurGetLongPathNameW (
IN PCWSTR ShortPath,
OUT PWSTR Buffer,
IN INT BufferSizeInChars
)
{
WCHAR FullPath[MAX_WCHAR_PATH];
PWSTR FilePart;
PWSTR BufferEnd;
PWSTR p, p2;
WCHAR c;
INT BufferSizeInBytes;
MYASSERT (BufferSizeInChars >= MAX_WCHAR_PATH);
if (ShortPath[0] == 0) {
return FALSE;
}
BufferSizeInBytes = BufferSizeInChars * sizeof (WCHAR);
if (!wcschr (ShortPath, L'\\')) {
if (!SearchPathW (NULL, ShortPath, NULL, MAX_WCHAR_PATH, FullPath, &FilePart)) {
return FALSE;
}
} else {
if (OurGetFullPathNameW (ShortPath, MAX_WCHAR_PATH, FullPath, &FilePart) == 0) {
return FALSE;
}
}
//
// Convert short paths to long paths
//
p = FullPath;
if (!IsPathOnFixedDriveW (FullPath)) {
StringCopyTcharCountW (Buffer, FullPath, BufferSizeInChars);
return TRUE;
}
p += 3;
// Copy drive letter to buffer
StringCopyABW (Buffer, FullPath, p);
BufferEnd = GetEndOfStringW (Buffer);
BufferSizeInBytes -= sizeof (WCHAR) * 3;
// Convert each portion of the path
do {
// Locate end of this file or dir
p2 = wcschr (p, L'\\');
if (!p2) {
p = GetEndOfStringW (p);
} else {
p = p2;
}
// Look up file
c = *p;
*p = 0;
if (!pFindShortNameW (FullPath, BufferEnd, &BufferSizeInBytes)) {
DEBUGMSG ((DBG_VERBOSE, "OurGetLongPathNameW: %ls does not exist", FullPath));
return FALSE;
}
*p = c;
// Move on to next part of path
if (*p) {
p++;
if (BufferSizeInBytes >= sizeof (WCHAR) * 2) {
BufferEnd = _wcsappend (BufferEnd, L"\\");
BufferSizeInBytes -= sizeof (WCHAR);
}
}
} while (*p);
return TRUE;
}
#ifdef DEBUG
UINT g_FileEnumResourcesInUse;
#endif
VOID
pTrackedFindClose (
HANDLE FindHandle
)
{
#ifdef DEBUG
g_FileEnumResourcesInUse--;
#endif
FindClose (FindHandle);
}
BOOL
EnumFirstFileInTreeExA (
OUT PTREE_ENUMA EnumPtr,
IN PCSTR RootPath,
IN PCSTR FilePattern, OPTIONAL
IN BOOL EnumDirsFirst,
IN BOOL EnumDepthFirst,
IN INT MaxLevel
)
/*++
Routine Description:
EnumFirstFileInTree begins an enumeration of a directory tree. The
caller supplies an uninitialized enum structure, a directory path to
enumerate, and an optional file pattern. On return, the caller
receives all files and directories that match the pattern.
If a file pattern is supplied, directories that do not match the
file pattern are enumerated anyway.
Arguments:
EnumPtr - Receives the enumerated file or directory
RootPath - Specifies the full path of the directory to enumerate
FilePattern - Specifies a pattern of files to limit the search to
EnumDirsFirst - Specifies TRUE if the directories should be enumerated
before the files, or FALSE if the directories should
be enumerated after the files.
Return Value:
TRUE if a file or directory was enumerated, or FALSE if enumeration is complete
or an error occurred. (Use GetLastError to determine the result.)
--*/
{
ZeroMemory (EnumPtr, sizeof (TREE_ENUMA));
EnumPtr->State = TREE_ENUM_INIT;
_mbssafecpy (EnumPtr->RootPath, RootPath, MAX_MBCHAR_PATH);
if (FilePattern) {
_mbssafecpy (EnumPtr->FilePattern, FilePattern, MAX_MBCHAR_PATH);
} else {
StringCopyA (EnumPtr->FilePattern, "*.*");
}
EnumPtr->EnumDirsFirst = EnumDirsFirst;
EnumPtr->EnumDepthFirst = EnumDepthFirst;
EnumPtr->Level = 1;
EnumPtr->MaxLevel = MaxLevel;
return EnumNextFileInTreeA (EnumPtr);
}
BOOL
EnumFirstFileInTreeExW (
OUT PTREE_ENUMW EnumPtr,
IN PCWSTR RootPath,
IN PCWSTR FilePattern, OPTIONAL
IN BOOL EnumDirsFirst,
IN BOOL EnumDepthFirst,
IN INT MaxLevel
)
{
ZeroMemory (EnumPtr, sizeof (TREE_ENUMW));
EnumPtr->State = TREE_ENUM_INIT;
_wcssafecpy (EnumPtr->RootPath, RootPath, MAX_PATH);
if (FilePattern) {
_wcssafecpy (EnumPtr->FilePattern, FilePattern, MAX_PATH);
} else {
StringCopyW (EnumPtr->FilePattern, L"*.*");
}
EnumPtr->EnumDirsFirst = EnumDirsFirst;
EnumPtr->EnumDepthFirst = EnumDepthFirst;
EnumPtr->Level = 1;
EnumPtr->MaxLevel = MaxLevel;
return EnumNextFileInTreeW (EnumPtr);
}
BOOL
EnumNextFileInTreeA (
IN OUT PTREE_ENUMA EnumPtr
)
/*++
Routine Description:
EnumNextFileInTree continues an enumeration of a directory tree,
returning the files that match the pattern specified in EnumFirstFileInTree,
and also returning all directories.
Arguments:
EnumPtr - Specifies the enumeration in progress, receives the enumerated file
or directory
Return Value:
TRUE if a file or directory was enumerated, or FALSE if enumeration is complete
or an error occurred. (Use GetLastError to determine the result.)
--*/
{
PSTR p;
for (;;) {
switch (EnumPtr->State) {
case TREE_ENUM_INIT:
//
// Get rid of wack at the end of root path, if it exists
//
p = GetEndOfStringA (EnumPtr->RootPath);
p = _mbsdec2 (EnumPtr->RootPath, p);
if (!p) {
DEBUGMSGA ((DBG_ERROR, "Path spec %s is incomplete", EnumPtr->RootPath));
EnumPtr->State = TREE_ENUM_FAILED;
break;
}
if (_mbsnextc (p) == '\\') {
*p = 0;
}
//
// Initialize enumeration structure
//
EnumPtr->FilePatternSize = SizeOfStringA (EnumPtr->FilePattern);
StringCopyA (EnumPtr->FileBuffer, EnumPtr->RootPath);
EnumPtr->EndOfFileBuffer = GetEndOfStringA (EnumPtr->FileBuffer);
StringCopyA (EnumPtr->Pattern, EnumPtr->RootPath);
EnumPtr->EndOfPattern = GetEndOfStringA (EnumPtr->Pattern);
EnumPtr->FullPath = EnumPtr->FileBuffer;
EnumPtr->RootPathSize = ByteCountA (EnumPtr->RootPath);
//
// Allocate first find data sturct
//
EnumPtr->Current = (PFIND_DATAA) GrowBuffer (
&EnumPtr->FindDataArray,
sizeof (FIND_DATAA)
);
if (!EnumPtr->Current) {
EnumPtr->State = TREE_ENUM_FAILED;
break;
}
#ifdef DEBUG
g_FileEnumResourcesInUse++; // account for grow buffer
#endif
EnumPtr->State = TREE_ENUM_BEGIN;
break;
case TREE_ENUM_BEGIN:
//
// Initialize current find data struct
//
EnumPtr->Current->SavedEndOfFileBuffer = EnumPtr->EndOfFileBuffer;
EnumPtr->Current->SavedEndOfPattern = EnumPtr->EndOfPattern;
//
// Limit the length of the pattern string
//
if ((EnumPtr->EndOfPattern - EnumPtr->Pattern) +
EnumPtr->FilePatternSize >= MAX_MBCHAR_PATH
) {
LOGA ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->Pattern, EnumPtr->FilePattern));
EnumPtr->State = TREE_ENUM_POP;
break;
}
//
// Enuemrate the files or directories
//
if (EnumPtr->EnumDirsFirst) {
EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
} else {
EnumPtr->State = TREE_ENUM_FILES_BEGIN;
}
break;
case TREE_ENUM_FILES_BEGIN:
//
// Begin enumeration of files
//
StringCopyA (EnumPtr->EndOfPattern, "\\");
StringCopyA (EnumPtr->EndOfPattern + 1, EnumPtr->FilePattern);
EnumPtr->Current->FindHandle = FindFirstFileA (
EnumPtr->Pattern,
&EnumPtr->Current->FindData
);
if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
if (EnumPtr->EnumDirsFirst) {
EnumPtr->State = TREE_ENUM_POP;
} else {
EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
}
} else {
#ifdef DEBUG
g_FileEnumResourcesInUse++; // account for creation of find handle
#endif
//
// Skip directories
//
if (EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
EnumPtr->State = TREE_ENUM_FILES_NEXT;
} else {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
}
break;
case TREE_ENUM_RETURN_ITEM:
//
// Update pointers to current item
//
EnumPtr->FindData = &EnumPtr->Current->FindData;
EnumPtr->Name = EnumPtr->FindData->cFileName;
EnumPtr->Directory = (EnumPtr->FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
//
// Limit the length of the resulting full path
//
if ((EnumPtr->EndOfFileBuffer - EnumPtr->FileBuffer) +
SizeOfStringA (EnumPtr->Name) >= MAX_MBCHAR_PATH
) {
LOGA ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
if (EnumPtr->Directory) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
} else {
EnumPtr->State = TREE_ENUM_FILES_NEXT;
}
break;
}
//
// Generate the full path
//
StringCopyA (EnumPtr->EndOfFileBuffer, "\\");
StringCopyA (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Name);
if (EnumPtr->Directory) {
if ((EnumPtr->MaxLevel == FILE_ENUM_ALL_LEVELS) ||
(EnumPtr->Level < EnumPtr->MaxLevel)
) {
if (EnumPtr->EnumDepthFirst) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
else {
EnumPtr->State = TREE_ENUM_PUSH;
}
}
else {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
} else {
EnumPtr->State = TREE_ENUM_FILES_NEXT;
}
EnumPtr->SubPath = (PCSTR) ((PBYTE) EnumPtr->FileBuffer + EnumPtr->RootPathSize);
if (*EnumPtr->SubPath) {
EnumPtr->SubPath++;
}
return TRUE;
case TREE_ENUM_FILES_NEXT:
if (FindNextFileA (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
//
// Return files only
//
if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
} else {
if (!EnumPtr->EnumDirsFirst) {
pTrackedFindClose (EnumPtr->Current->FindHandle);
EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
} else {
EnumPtr->State = TREE_ENUM_POP;
}
}
break;
case TREE_ENUM_DIRS_FILTER:
if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
} else if (StringMatchA (EnumPtr->Current->FindData.cFileName, ".") ||
StringMatchA (EnumPtr->Current->FindData.cFileName, "..")
) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
} else {
if (EnumPtr->EnumDepthFirst) {
EnumPtr->State = TREE_ENUM_PUSH;
}
else {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
}
break;
case TREE_ENUM_DIRS_BEGIN:
//
// Begin enumeration of directories
//
StringCopyA (EnumPtr->EndOfPattern, "\\");
StringCopyA (EnumPtr->EndOfPattern + 1, "*.*");
EnumPtr->Current->FindHandle = FindFirstFileA (
EnumPtr->Pattern,
&EnumPtr->Current->FindData
);
if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
EnumPtr->State = TREE_ENUM_POP;
} else {
#ifdef DEBUG
g_FileEnumResourcesInUse++; // account for creation of find handle
#endif
EnumPtr->State = TREE_ENUM_DIRS_FILTER;
}
break;
case TREE_ENUM_DIRS_NEXT:
if (FindNextFileA (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
//
// Return directories only, then recurse into directory
//
EnumPtr->State = TREE_ENUM_DIRS_FILTER;
} else {
//
// Directory enumeration complete.
//
if (EnumPtr->EnumDirsFirst) {
pTrackedFindClose (EnumPtr->Current->FindHandle);
EnumPtr->State = TREE_ENUM_FILES_BEGIN;
} else {
EnumPtr->State = TREE_ENUM_POP;
}
}
break;
case TREE_ENUM_PUSH:
//
// Limit the length of the resulting full path
//
if ((EnumPtr->EndOfFileBuffer - EnumPtr->FileBuffer) +
SizeOfStringA (EnumPtr->Current->FindData.cFileName) >= MAX_MBCHAR_PATH
) {
LOGA ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
break;
}
//
// Tack on directory name to strings and recalcuate end pointers
//
StringCopyA (EnumPtr->EndOfPattern + 1, EnumPtr->Current->FindData.cFileName);
StringCopyA (EnumPtr->EndOfFileBuffer, "\\");
StringCopyA (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Current->FindData.cFileName);
EnumPtr->EndOfPattern = GetEndOfStringA (EnumPtr->EndOfPattern);
EnumPtr->EndOfFileBuffer = GetEndOfStringA (EnumPtr->EndOfFileBuffer);
//
// Allocate another find data struct
//
EnumPtr->Current = (PFIND_DATAA) GrowBuffer (
&EnumPtr->FindDataArray,
sizeof (FIND_DATAA)
);
if (!EnumPtr->Current) {
EnumPtr->State = TREE_ENUM_FAILED;
break;
}
EnumPtr->Level++;
EnumPtr->State = TREE_ENUM_BEGIN;
break;
case TREE_ENUM_POP:
//
// Free the current resources
//
pTrackedFindClose (EnumPtr->Current->FindHandle);
EnumPtr->Level--;
//
// Get the previous find data struct
//
MYASSERT (EnumPtr->FindDataArray.End >= sizeof (FIND_DATAA));
EnumPtr->FindDataArray.End -= sizeof (FIND_DATAA);
if (!EnumPtr->FindDataArray.End) {
EnumPtr->State = TREE_ENUM_DONE;
break;
}
EnumPtr->Current = (PFIND_DATAA) (EnumPtr->FindDataArray.Buf +
(EnumPtr->FindDataArray.End - sizeof (FIND_DATAA)));
//
// Restore the settings of the parent directory
//
EnumPtr->EndOfPattern = EnumPtr->Current->SavedEndOfPattern;
EnumPtr->EndOfFileBuffer = EnumPtr->Current->SavedEndOfFileBuffer;
if (EnumPtr->EnumDepthFirst) {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
else {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
break;
case TREE_ENUM_DONE:
AbortEnumFileInTreeA (EnumPtr);
SetLastError (ERROR_SUCCESS);
return FALSE;
case TREE_ENUM_FAILED:
PushError();
AbortEnumFileInTreeA (EnumPtr);
PopError();
return FALSE;
case TREE_ENUM_CLEANED_UP:
return FALSE;
}
}
}
BOOL
EnumNextFileInTreeW (
IN OUT PTREE_ENUMW EnumPtr
)
{
PWSTR p;
for (;;) {
switch (EnumPtr->State) {
case TREE_ENUM_INIT:
//
// Get rid of wack at the end of root path, if it exists
//
p = GetEndOfStringW (EnumPtr->RootPath);
p = _wcsdec2 (EnumPtr->RootPath, p);
if (!p) {
DEBUGMSG ((DBG_ERROR, "Path spec %ls is incomplete", EnumPtr->RootPath));
EnumPtr->State = TREE_ENUM_FAILED;
break;
}
if (*p == L'\\') {
*p = 0;
}
//
// Initialize enumeration structure
//
EnumPtr->FilePatternSize = SizeOfStringW (EnumPtr->FilePattern);
StringCopyW (EnumPtr->FileBuffer, EnumPtr->RootPath);
EnumPtr->EndOfFileBuffer = GetEndOfStringW (EnumPtr->FileBuffer);
StringCopyW (EnumPtr->Pattern, EnumPtr->RootPath);
EnumPtr->EndOfPattern = GetEndOfStringW (EnumPtr->Pattern);
EnumPtr->FullPath = EnumPtr->FileBuffer;
EnumPtr->RootPathSize = ByteCountW (EnumPtr->RootPath);
//
// Allocate first find data sturct
//
EnumPtr->Current = (PFIND_DATAW) GrowBuffer (
&EnumPtr->FindDataArray,
sizeof (FIND_DATAW)
);
if (!EnumPtr->Current) {
EnumPtr->State = TREE_ENUM_FAILED;
break;
}
#ifdef DEBUG
g_FileEnumResourcesInUse++; // account for grow buffer
#endif
EnumPtr->State = TREE_ENUM_BEGIN;
break;
case TREE_ENUM_BEGIN:
//
// Initialize current find data struct
//
EnumPtr->Current->SavedEndOfFileBuffer = EnumPtr->EndOfFileBuffer;
EnumPtr->Current->SavedEndOfPattern = EnumPtr->EndOfPattern;
//
// Limit the length of the pattern string
//
if (((PBYTE) EnumPtr->EndOfPattern - (PBYTE) EnumPtr->Pattern) +
EnumPtr->FilePatternSize >= (MAX_PATH * 2 * sizeof (WCHAR))
) {
LOGW ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->Pattern, EnumPtr->FilePattern));
EnumPtr->State = TREE_ENUM_POP;
break;
}
//
// Enuemrate the files or directories
//
if (EnumPtr->EnumDirsFirst) {
EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
} else {
EnumPtr->State = TREE_ENUM_FILES_BEGIN;
}
break;
case TREE_ENUM_FILES_BEGIN:
//
// Begin enumeration of files
//
StringCopyW (EnumPtr->EndOfPattern, L"\\");
StringCopyW (EnumPtr->EndOfPattern + 1, EnumPtr->FilePattern);
EnumPtr->Current->FindHandle = FindFirstFileW (
EnumPtr->Pattern,
&EnumPtr->Current->FindData
);
if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
if (EnumPtr->EnumDirsFirst) {
EnumPtr->State = TREE_ENUM_POP;
} else {
EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
}
} else {
#ifdef DEBUG
g_FileEnumResourcesInUse++; // account for creation of find handle
#endif
//
// Skip directories
//
if (EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
EnumPtr->State = TREE_ENUM_FILES_NEXT;
} else {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
}
break;
case TREE_ENUM_RETURN_ITEM:
//
// Update pointers to current item
//
EnumPtr->FindData = &EnumPtr->Current->FindData;
EnumPtr->Name = EnumPtr->FindData->cFileName;
EnumPtr->Directory = (EnumPtr->FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
//
// Limit the length of the resulting full path
//
if (((PBYTE) EnumPtr->EndOfFileBuffer - (PBYTE) EnumPtr->FileBuffer) +
SizeOfStringW (EnumPtr->Name) >= (MAX_PATH * 2 * sizeof (WCHAR))
) {
LOGW ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
if (EnumPtr->Directory) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
} else {
EnumPtr->State = TREE_ENUM_FILES_NEXT;
}
break;
}
//
// Generate the full path
//
StringCopyW (EnumPtr->EndOfFileBuffer, L"\\");
StringCopyW (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Name);
if (EnumPtr->Directory) {
if ((EnumPtr->MaxLevel == FILE_ENUM_ALL_LEVELS) ||
(EnumPtr->Level < EnumPtr->MaxLevel)
) {
if (EnumPtr->EnumDepthFirst) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
else {
EnumPtr->State = TREE_ENUM_PUSH;
}
}
else {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
} else {
EnumPtr->State = TREE_ENUM_FILES_NEXT;
}
EnumPtr->SubPath = (PCWSTR) ((PBYTE) EnumPtr->FileBuffer + EnumPtr->RootPathSize);
if (*EnumPtr->SubPath) {
EnumPtr->SubPath++;
}
return TRUE;
case TREE_ENUM_FILES_NEXT:
if (FindNextFileW (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
//
// Return files only
//
if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
} else {
if (!EnumPtr->EnumDirsFirst) {
pTrackedFindClose (EnumPtr->Current->FindHandle);
EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
} else {
EnumPtr->State = TREE_ENUM_POP;
}
}
break;
case TREE_ENUM_DIRS_FILTER:
if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
} else if (StringMatchW (EnumPtr->Current->FindData.cFileName, L".") ||
StringMatchW (EnumPtr->Current->FindData.cFileName, L"..")
) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
} else {
if (EnumPtr->EnumDepthFirst) {
EnumPtr->State = TREE_ENUM_PUSH;
}
else {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
}
break;
case TREE_ENUM_DIRS_BEGIN:
//
// Begin enumeration of directories
//
StringCopyW (EnumPtr->EndOfPattern, L"\\*.*");
EnumPtr->Current->FindHandle = FindFirstFileW (
EnumPtr->Pattern,
&EnumPtr->Current->FindData
);
if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
EnumPtr->State = TREE_ENUM_POP;
} else {
#ifdef DEBUG
g_FileEnumResourcesInUse++; // account for creation of find handle
#endif
EnumPtr->State = TREE_ENUM_DIRS_FILTER;
}
break;
case TREE_ENUM_DIRS_NEXT:
if (FindNextFileW (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
//
// Return directories only, then recurse into directory
//
EnumPtr->State = TREE_ENUM_DIRS_FILTER;
} else {
//
// Directory enumeration complete.
//
if (EnumPtr->EnumDirsFirst) {
pTrackedFindClose (EnumPtr->Current->FindHandle);
EnumPtr->State = TREE_ENUM_FILES_BEGIN;
} else {
EnumPtr->State = TREE_ENUM_POP;
}
}
break;
case TREE_ENUM_PUSH:
//
// Limit the length of the resulting full path
//
if (((PBYTE) EnumPtr->EndOfFileBuffer - (PBYTE) EnumPtr->FileBuffer) +
SizeOfStringW (EnumPtr->Current->FindData.cFileName) >= (MAX_PATH * 2 * sizeof (WCHAR))
) {
LOGW ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
break;
}
//
// Tack on directory name to strings and recalcuate end pointers
//
StringCopyW (EnumPtr->EndOfPattern + 1, EnumPtr->Current->FindData.cFileName);
StringCopyW (EnumPtr->EndOfFileBuffer, L"\\");
StringCopyW (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Current->FindData.cFileName);
EnumPtr->EndOfPattern = GetEndOfStringW (EnumPtr->EndOfPattern);
EnumPtr->EndOfFileBuffer = GetEndOfStringW (EnumPtr->EndOfFileBuffer);
//
// Allocate another find data struct
//
EnumPtr->Current = (PFIND_DATAW) GrowBuffer (
&EnumPtr->FindDataArray,
sizeof (FIND_DATAW)
);
if (!EnumPtr->Current) {
EnumPtr->State = TREE_ENUM_FAILED;
break;
}
EnumPtr->Level++;
EnumPtr->State = TREE_ENUM_BEGIN;
break;
case TREE_ENUM_POP:
//
// Free the current resources
//
pTrackedFindClose (EnumPtr->Current->FindHandle);
EnumPtr->Level--;
//
// Get the previous find data struct
//
MYASSERT (EnumPtr->FindDataArray.End >= sizeof (FIND_DATAW));
EnumPtr->FindDataArray.End -= sizeof (FIND_DATAW);
if (!EnumPtr->FindDataArray.End) {
EnumPtr->State = TREE_ENUM_DONE;
break;
}
EnumPtr->Current = (PFIND_DATAW) (EnumPtr->FindDataArray.Buf +
(EnumPtr->FindDataArray.End - sizeof (FIND_DATAW)));
//
// Restore the settings of the parent directory
//
EnumPtr->EndOfPattern = EnumPtr->Current->SavedEndOfPattern;
EnumPtr->EndOfFileBuffer = EnumPtr->Current->SavedEndOfFileBuffer;
if (EnumPtr->EnumDepthFirst) {
EnumPtr->State = TREE_ENUM_RETURN_ITEM;
}
else {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
break;
case TREE_ENUM_DONE:
AbortEnumFileInTreeW (EnumPtr);
SetLastError (ERROR_SUCCESS);
return FALSE;
case TREE_ENUM_FAILED:
PushError();
AbortEnumFileInTreeW (EnumPtr);
PopError();
return FALSE;
case TREE_ENUM_CLEANED_UP:
return FALSE;
}
}
}
VOID
AbortEnumFileInTreeA (
IN OUT PTREE_ENUMA EnumPtr
)
/*++
Routine Description:
AbortEnumFileInTree cleans up all resources used by an enumeration started
by EnumFirstFileInTree. This routine must be called if file enumeration
will not be completed by calling EnumNextFileInTree until it returns FALSE.
If EnumNextFileInTree returns FALSE, it is unnecessary to call this
function.
Arguments:
EnumPtr - Specifies the enumeration in progress, receives the enumerated file
or directory
Return Value:
none
--*/
{
UINT Pos;
PGROWBUFFER g;
PFIND_DATAA Current;
if (EnumPtr->State == TREE_ENUM_CLEANED_UP) {
return;
}
//
// Close any currently open handles
//
g = &EnumPtr->FindDataArray;
for (Pos = 0 ; Pos < g->End ; Pos += sizeof (FIND_DATAA)) {
Current = (PFIND_DATAA) (g->Buf + Pos);
pTrackedFindClose (Current->FindHandle);
}
FreeGrowBuffer (&EnumPtr->FindDataArray);
#ifdef DEBUG
g_FileEnumResourcesInUse--;
#endif
EnumPtr->State = TREE_ENUM_CLEANED_UP;
}
VOID
AbortEnumFileInTreeW (
IN OUT PTREE_ENUMW EnumPtr
)
{
UINT Pos;
PGROWBUFFER g;
PFIND_DATAW Current;
if (EnumPtr->State == TREE_ENUM_CLEANED_UP) {
return;
}
//
// Close any currently open handles
//
g = &EnumPtr->FindDataArray;
for (Pos = 0 ; Pos < g->End ; Pos += sizeof (FIND_DATAW)) {
Current = (PFIND_DATAW) (g->Buf + Pos);
pTrackedFindClose (Current->FindHandle);
}
FreeGrowBuffer (&EnumPtr->FindDataArray);
#ifdef DEBUG
g_FileEnumResourcesInUse--;
#endif
EnumPtr->State = TREE_ENUM_CLEANED_UP;
}
VOID
AbortEnumCurrentDirA (
IN OUT PTREE_ENUMA EnumPtr
)
{
if (EnumPtr->State == TREE_ENUM_PUSH) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
}
VOID
AbortEnumCurrentDirW (
IN OUT PTREE_ENUMW EnumPtr
)
{
if (EnumPtr->State == TREE_ENUM_PUSH) {
EnumPtr->State = TREE_ENUM_DIRS_NEXT;
}
}
BOOL
EnumFirstFileA (
OUT PFILE_ENUMA EnumPtr,
IN PCSTR RootPath,
IN PCSTR FilePattern OPTIONAL
)
{
ZeroMemory (EnumPtr, sizeof (FILE_ENUMA));
EnumPtr->FileName = EnumPtr->fd.cFileName;
EnumPtr->FullPath = EnumPtr->RootPath;
StringCopyA (EnumPtr->RootPath, RootPath);
EnumPtr->EndOfRoot = AppendWackA (EnumPtr->RootPath);
StringCopyA (EnumPtr->EndOfRoot, FilePattern ? FilePattern : "*.*");
EnumPtr->Handle = FindFirstFileA (EnumPtr->RootPath, &EnumPtr->fd);
if (EnumPtr->Handle != INVALID_HANDLE_VALUE) {
if (StringMatchA (EnumPtr->FileName, ".") ||
StringMatchA (EnumPtr->FileName, "..")
) {
return EnumNextFileA (EnumPtr);
}
StringCopyA (EnumPtr->EndOfRoot, EnumPtr->FileName);
EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
return TRUE;
}
return FALSE;
}
BOOL
EnumFirstFileW (
OUT PFILE_ENUMW EnumPtr,
IN PCWSTR RootPath,
IN PCWSTR FilePattern OPTIONAL
)
{
ZeroMemory (EnumPtr, sizeof (FILE_ENUMW));
EnumPtr->FileName = EnumPtr->fd.cFileName;
EnumPtr->FullPath = EnumPtr->RootPath;
StringCopyW (EnumPtr->RootPath, RootPath);
EnumPtr->EndOfRoot = AppendWackW (EnumPtr->RootPath);
StringCopyW (EnumPtr->EndOfRoot, FilePattern ? FilePattern : L"*.*");
EnumPtr->Handle = FindFirstFileW (EnumPtr->RootPath, &EnumPtr->fd);
if (EnumPtr->Handle != INVALID_HANDLE_VALUE) {
if (StringMatchW (EnumPtr->FileName, L".") ||
StringMatchW (EnumPtr->FileName, L"..")
) {
return EnumNextFileW (EnumPtr);
}
StringCopyW (EnumPtr->EndOfRoot, EnumPtr->FileName);
EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
return TRUE;
}
return FALSE;
}
BOOL
EnumNextFileA (
IN OUT PFILE_ENUMA EnumPtr
)
{
do {
if (!FindNextFileA (EnumPtr->Handle, &EnumPtr->fd)) {
AbortFileEnumA (EnumPtr);
return FALSE;
}
} while (StringMatchA (EnumPtr->FileName, ".") ||
StringMatchA (EnumPtr->FileName, "..")
);
StringCopyA (EnumPtr->EndOfRoot, EnumPtr->FileName);
EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
return TRUE;
}
BOOL
EnumNextFileW (
IN OUT PFILE_ENUMW EnumPtr
)
{
do {
if (!FindNextFileW (EnumPtr->Handle, &EnumPtr->fd)) {
AbortFileEnumW (EnumPtr);
return FALSE;
}
} while (StringMatchW (EnumPtr->FileName, L".") ||
StringMatchW (EnumPtr->FileName, L"..")
);
if (!FindNextFileW (EnumPtr->Handle, &EnumPtr->fd)) {
AbortFileEnumW (EnumPtr);
return FALSE;
}
StringCopyW (EnumPtr->EndOfRoot, EnumPtr->FileName);
EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
return TRUE;
}
VOID
AbortFileEnumA (
IN OUT PFILE_ENUMA EnumPtr
)
{
if (EnumPtr->Handle && EnumPtr->Handle != INVALID_HANDLE_VALUE) {
FindClose (EnumPtr->Handle);
ZeroMemory (EnumPtr, sizeof (FILE_ENUMA));
}
}
VOID
AbortFileEnumW (
IN OUT PFILE_ENUMW EnumPtr
)
{
if (EnumPtr->Handle && EnumPtr->Handle != INVALID_HANDLE_VALUE) {
FindClose (EnumPtr->Handle);
ZeroMemory (EnumPtr, sizeof (FILE_ENUMW));
}
}
/*++
Routine Description:
MapFileIntoMemoryA and MapFileIntoMemoryW map a file into memory. It does that
by opening the file, creating a mapping object and mapping opened file into
created mapping object. It returnes the address where the file is mapped and
also sets FileHandle and MapHandle variables to be used in order to unmap the
file when work is done.
Arguments:
FileName - the name of the file to be mapped into memory
FileHandle - will end keeping the file handle if the file was opened successfully
MapHandle - will end keeping the mapping object handle if this object was created successfully
Return Value:
NULL if function fails, a valid memory address if successfull
Comments:
If the return value is NULL you should call UnmapFile to release all allocated resources
--*/
PVOID
MapFileIntoMemoryExA (
IN PCSTR FileName,
OUT PHANDLE FileHandle,
OUT PHANDLE MapHandle,
IN BOOL WriteAccess
)
{
PVOID fileImage = NULL;
//verify function parameters
if ((FileHandle == NULL) || (MapHandle == NULL)) {
return NULL;
}
//first thing. Try to open the file, read-only
*FileHandle = CreateFileA (
FileName,
WriteAccess?GENERIC_READ|GENERIC_WRITE:GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (*FileHandle == INVALID_HANDLE_VALUE) {
return NULL;
}
//now try to create a mapping object, read-only
*MapHandle = CreateFileMappingA (*FileHandle, NULL, WriteAccess?PAGE_READWRITE:PAGE_READONLY, 0, 0, NULL);
if (*MapHandle == NULL) {
return NULL;
}
//one more thing to do: map view of file
fileImage = MapViewOfFile (*MapHandle, WriteAccess?FILE_MAP_WRITE:FILE_MAP_READ, 0, 0, 0);
return fileImage;
}
PVOID
MapFileIntoMemoryExW (
IN PCWSTR FileName,
OUT PHANDLE FileHandle,
OUT PHANDLE MapHandle,
IN BOOL WriteAccess
)
{
PVOID fileImage = NULL;
//verify function parameters
if ((FileHandle == NULL) || (MapHandle == NULL)) {
return NULL;
}
//first thing. Try to open the file, read-only
*FileHandle = CreateFileW (
FileName,
WriteAccess?GENERIC_READ|GENERIC_WRITE:GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (*FileHandle == INVALID_HANDLE_VALUE) {
return NULL;
}
//now try to create a mapping object, read-only
*MapHandle = CreateFileMappingW (*FileHandle, NULL, WriteAccess?PAGE_READWRITE:PAGE_READONLY, 0, 0, NULL);
if (*MapHandle == NULL) {
return NULL;
}
//one more thing to do: map view of file
fileImage = MapViewOfFile (*MapHandle, WriteAccess?FILE_MAP_WRITE:FILE_MAP_READ, 0, 0, 0);
return fileImage;
}
/*++
Routine Description:
UnmapFile is used to release all resources allocated by MapFileIntoMemory.
Arguments:
FileImage - image of the mapped file as returned by MapFileIntoMemory
MapHandle - handle of the mapping object as returned by MapFileIntoMemory
FileHandle - handle of the file as returned by MapFileIntoMemory
Return Value:
TRUE if successfull, FALSE if not
--*/
BOOL
UnmapFile (
IN PVOID FileImage,
IN HANDLE MapHandle,
IN HANDLE FileHandle
)
{
BOOL result = TRUE;
//if FileImage is a valid pointer then try to unmap file
if (FileImage != NULL) {
if (UnmapViewOfFile (FileImage) == 0) {
result = FALSE;
}
}
//if mapping object is valid then try to delete it
if (MapHandle != NULL) {
if (CloseHandle (MapHandle) == 0) {
result = FALSE;
}
}
//if file handle is valid then try to close the file
if (FileHandle != INVALID_HANDLE_VALUE) {
if (CloseHandle (FileHandle) == 0) {
result = FALSE;
}
}
return result;
}
BOOL
RemoveCompleteDirectoryA (
IN PCSTR Dir
)
{
TREE_ENUMA e;
BOOL b = TRUE;
CHAR CurDir[MAX_MBCHAR_PATH];
CHAR NewDir[MAX_MBCHAR_PATH];
LONG rc = ERROR_SUCCESS;
DWORD Attribs;
Attribs = GetFileAttributesA (Dir);
if (Attribs == INVALID_ATTRIBUTES) {
return TRUE;
}
if (!(Attribs & FILE_ATTRIBUTE_DIRECTORY)) {
SetFileAttributesA (Dir, FILE_ATTRIBUTE_NORMAL);
return DeleteFileA (Dir);
}
GetCurrentDirectoryA (MAX_MBCHAR_PATH, CurDir);
SetCurrentDirectoryA (Dir);
GetCurrentDirectoryA (MAX_MBCHAR_PATH, NewDir);
if (EnumFirstFileInTreeA (&e, NewDir, NULL, FALSE)) {
do {
if (!e.Directory) {
SetFileAttributesA (e.FullPath, FILE_ATTRIBUTE_NORMAL);
if (!DeleteFileA (e.FullPath)) {
DEBUGMSGA ((DBG_ERROR, "Can't delete %s", e.FullPath));
if (b) {
b = FALSE;
rc = GetLastError();
}
}
}
} while (EnumNextFileInTreeA (&e));
}
if (EnumFirstFileInTreeExA (&e, NewDir, NULL, TRUE, TRUE, FILE_ENUM_ALL_LEVELS)) {
do {
if (e.Directory) {
SetFileAttributesA (e.FullPath, FILE_ATTRIBUTE_NORMAL);
if (!RemoveDirectoryA (e.FullPath)) {
DEBUGMSGA ((DBG_ERROR, "Can't remove %s", e.FullPath));
if (b) {
b = FALSE;
rc = GetLastError();
}
}
}
} while (EnumNextFileInTreeA (&e));
}
if (b) {
SetFileAttributesA (NewDir, FILE_ATTRIBUTE_NORMAL);
SetCurrentDirectoryA ("..");
b = RemoveDirectoryA (NewDir);
}
if (!b && rc == ERROR_SUCCESS) {
rc = GetLastError();
}
SetCurrentDirectoryA (CurDir);
SetLastError (rc);
return b;
}
BOOL
RemoveCompleteDirectoryW (
IN PCWSTR Dir
)
{
TREE_ENUMW e;
BOOL b = TRUE;
WCHAR CurDir[MAX_WCHAR_PATH];
WCHAR NewDir[MAX_WCHAR_PATH];
LONG rc = ERROR_SUCCESS;
DWORD Attribs;
Attribs = GetLongPathAttributesW (Dir);
if (Attribs == INVALID_ATTRIBUTES) {
return TRUE;
}
if (!(Attribs & FILE_ATTRIBUTE_DIRECTORY)) {
SetLongPathAttributesW (Dir, FILE_ATTRIBUTE_NORMAL);
return DeleteLongPathW (Dir);
}
GetCurrentDirectoryW (MAX_WCHAR_PATH, CurDir);
SetCurrentDirectoryW (Dir);
GetCurrentDirectoryW (MAX_WCHAR_PATH, NewDir);
if (EnumFirstFileInTreeW (&e, NewDir, NULL, FALSE)) {
do {
if (!e.Directory) {
SetLongPathAttributesW (e.FullPath, FILE_ATTRIBUTE_NORMAL);
if (!DeleteLongPathW (e.FullPath)) {
DEBUGMSGW ((DBG_ERROR, "Can't delete %s", e.FullPath));
if (b) {
b = FALSE;
rc = GetLastError();
}
}
}
} while (EnumNextFileInTreeW (&e));
}
if (EnumFirstFileInTreeExW (&e, NewDir, NULL, TRUE, TRUE, FILE_ENUM_ALL_LEVELS)) {
do {
if (e.Directory) {
SetLongPathAttributesW (e.FullPath, FILE_ATTRIBUTE_NORMAL);
if (!RemoveDirectoryW (e.FullPath)) {
DEBUGMSGW ((DBG_ERROR, "Can't remove %s", e.FullPath));
if (b) {
b = FALSE;
rc = GetLastError();
}
}
}
} while (EnumNextFileInTreeW (&e));
}
if (b) {
SetLongPathAttributesW (NewDir, FILE_ATTRIBUTE_NORMAL);
SetCurrentDirectoryW (L"..");
b = RemoveDirectoryW (NewDir);
}
if (!b && rc == ERROR_SUCCESS) {
rc = GetLastError();
}
SetCurrentDirectoryW (CurDir);
SetLastError (rc);
return b;
}
PCMDLINEA
ParseCmdLineA (
IN PCSTR CmdLine,
IN OUT PGROWBUFFER Buffer
)
{
GROWBUFFER SpacePtrs = GROWBUF_INIT;
PCSTR p;
PSTR q;
INT Count;
INT i;
INT j;
PSTR *Array;
PCSTR Start;
CHAR OldChar = 0;
GROWBUFFER StringBuf = GROWBUF_INIT;
PBYTE CopyBuf;
PCMDLINEA CmdLineTable;
PCMDLINEARGA CmdLineArg;
UINT Base;
CHAR Path[MAX_MBCHAR_PATH];
CHAR UnquotedPath[MAX_MBCHAR_PATH];
CHAR FixedFileName[MAX_MBCHAR_PATH];
PCSTR FullPath = NULL;
DWORD Attribs = INVALID_ATTRIBUTES;
PSTR CmdLineCopy;
BOOL Quoted;
UINT OriginalArgOffset = 0;
UINT CleanedUpArgOffset = 0;
BOOL GoodFileFound = FALSE;
PSTR DontCare;
CHAR FirstArgPath[MAX_MBCHAR_PATH];
PSTR EndOfFirstArg;
BOOL QuoteMode = FALSE;
PSTR End;
CmdLineCopy = DuplicateTextA (CmdLine);
//
// Build an array of places to break the string
//
for (p = CmdLineCopy ; *p ; p = _mbsinc (p)) {
if (_mbsnextc (p) == '\"') {
QuoteMode = !QuoteMode;
} else if (!QuoteMode && (_mbsnextc (p) == ' ' || _mbsnextc (p) == '=')) {
//
// Remove excess spaces
//
q = (PSTR) p + 1;
while (_mbsnextc (q) == ' ') {
q++;
}
if (q > p + 1) {
MoveMemory ((PBYTE) p + sizeof (CHAR), q, SizeOfStringA (q));
}
GrowBufAppendDword (&SpacePtrs, (DWORD) p);
}
}
//
// Prepare the CMDLINE struct
//
CmdLineTable = (PCMDLINEA) GrowBuffer (Buffer, sizeof (CMDLINEA));
MYASSERT (CmdLineTable);
//
// NOTE: We store string offsets, then at the end resolve them
// to pointers later.
//
CmdLineTable->CmdLine = (PCSTR) StringBuf.End;
MultiSzAppendA (&StringBuf, CmdLine);
CmdLineTable->ArgCount = 0;
//
// Now test every combination, emulating CreateProcess
//
Count = SpacePtrs.End / sizeof (DWORD);
Array = (PSTR *) SpacePtrs.Buf;
i = -1;
EndOfFirstArg = NULL;
while (i < Count) {
GoodFileFound = FALSE;
Quoted = FALSE;
if (i >= 0) {
Start = Array[i] + 1;
} else {
Start = CmdLineCopy;
}
//
// Check for a full path at Start
//
if (_mbsnextc (Start) != '/') {
for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
FullPath = Start;
//
// Remove quotes; continue in the loop if it has no terminating quotes
//
Quoted = FALSE;
if (_mbsnextc (Start) == '\"') {
StringCopyByteCountA (UnquotedPath, Start + 1, sizeof (UnquotedPath));
q = _mbschr (UnquotedPath, '\"');
if (q) {
*q = 0;
FullPath = UnquotedPath;
Quoted = TRUE;
} else {
FullPath = NULL;
}
}
if (FullPath && *FullPath) {
//
// Look in file system for the path
//
Attribs = GetFileAttributesA (FullPath);
if (Attribs == INVALID_ATTRIBUTES && EndOfFirstArg) {
//
// Try prefixing the path with the first arg's path.
//
StringCopyByteCountA (
EndOfFirstArg,
FullPath,
sizeof (FirstArgPath) - ((PBYTE) EndOfFirstArg - (PBYTE) FirstArgPath)
);
FullPath = FirstArgPath;
Attribs = GetFileAttributesA (FullPath);
}
if (Attribs == INVALID_ATTRIBUTES && i < 0) {
//
// Try appending .exe, then testing again. This
// emulates what CreateProcess does.
//
StringCopyByteCountA (
FixedFileName,
FullPath,
sizeof (FixedFileName) - sizeof (".exe")
);
q = GetEndOfStringA (FixedFileName);
q = _mbsdec (FixedFileName, q);
MYASSERT (q);
if (_mbsnextc (q) != '.') {
q = _mbsinc (q);
}
StringCopyA (q, ".exe");
FullPath = FixedFileName;
Attribs = GetFileAttributesA (FullPath);
}
if (Attribs != INVALID_ATTRIBUTES) {
//
// Full file path found. Test its file status, then
// move on if there are no important operations on it.
//
OriginalArgOffset = StringBuf.End;
MultiSzAppendA (&StringBuf, Start);
if (!StringMatchA (Start, FullPath)) {
CleanedUpArgOffset = StringBuf.End;
MultiSzAppendA (&StringBuf, FullPath);
} else {
CleanedUpArgOffset = OriginalArgOffset;
}
i = j;
GoodFileFound = TRUE;
}
}
if (j < Count) {
*Array[j] = OldChar;
}
}
if (!GoodFileFound) {
//
// If a wack is in the path, then we could have a relative path, an arg, or
// a full path to a non-existent file.
//
if (_mbschr (Start, '\\')) {
#ifdef DEBUG
j = i + 1;
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
DEBUGMSGA ((
DBG_VERBOSE,
"%s is a non-existent path spec, a relative path, or an arg",
Start
));
if (j < Count) {
*Array[j] = OldChar;
}
#endif
} else {
//
// The string at Start did not contain a full path; try using
// SearchPath.
//
for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
FullPath = Start;
//
// Remove quotes; continue in the loop if it has no terminating quotes
//
Quoted = FALSE;
if (_mbsnextc (Start) == '\"') {
StringCopyByteCountA (UnquotedPath, Start + 1, sizeof (UnquotedPath));
q = _mbschr (UnquotedPath, '\"');
if (q) {
*q = 0;
FullPath = UnquotedPath;
Quoted = TRUE;
} else {
FullPath = NULL;
}
}
if (FullPath && *FullPath) {
if (SearchPathA (
NULL,
FullPath,
NULL,
sizeof (Path) / sizeof (Path[0]),
Path,
&DontCare
)) {
FullPath = Path;
} else if (i < 0) {
//
// Try appending .exe and searching the path again
//
StringCopyByteCountA (
FixedFileName,
FullPath,
sizeof (FixedFileName) - sizeof (".exe")
);
q = GetEndOfStringA (FixedFileName);
q = _mbsdec (FixedFileName, q);
MYASSERT (q);
if (_mbsnextc (q) != '.') {
q = _mbsinc (q);
}
StringCopyA (q, ".exe");
if (SearchPathA (
NULL,
FixedFileName,
NULL,
sizeof (Path) / sizeof (Path[0]),
Path,
&DontCare
)) {
FullPath = Path;
} else {
FullPath = NULL;
}
} else {
FullPath = NULL;
}
}
if (FullPath && *FullPath) {
Attribs = GetFileAttributesA (FullPath);
MYASSERT (Attribs != INVALID_ATTRIBUTES);
OriginalArgOffset = StringBuf.End;
MultiSzAppendA (&StringBuf, Start);
if (!StringMatchA (Start, FullPath)) {
CleanedUpArgOffset = StringBuf.End;
MultiSzAppendA (&StringBuf, FullPath);
} else {
CleanedUpArgOffset = OriginalArgOffset;
}
i = j;
GoodFileFound = TRUE;
}
if (j < Count) {
*Array[j] = OldChar;
}
}
}
}
}
CmdLineTable->ArgCount += 1;
CmdLineArg = (PCMDLINEARGA) GrowBuffer (Buffer, sizeof (CMDLINEARGA));
MYASSERT (CmdLineArg);
if (GoodFileFound) {
//
// We have a good full file spec in FullPath, its attributes
// are in Attribs, and i has been moved to the space beyond
// the path. We now add a table entry.
//
CmdLineArg->OriginalArg = (PCSTR) OriginalArgOffset;
CmdLineArg->CleanedUpArg = (PCSTR) CleanedUpArgOffset;
CmdLineArg->Attributes = Attribs;
CmdLineArg->Quoted = Quoted;
if (!EndOfFirstArg) {
StringCopyByteCountA (FirstArgPath, (PCSTR) (StringBuf.Buf + (UINT) CmdLineArg->CleanedUpArg), sizeof (FirstArgPath));
q = (PSTR) GetFileNameFromPathA (FirstArgPath);
if (q) {
q = _mbsdec (FirstArgPath, q);
if (q) {
*q = 0;
}
}
EndOfFirstArg = AppendWackA (FirstArgPath);
}
} else {
//
// We do not have a good file spec; we must have a non-file
// argument. Put it in the table, and advance to the next
// arg.
//
j = i + 1;
if (j <= Count) {
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
CmdLineArg->OriginalArg = (PCSTR) StringBuf.End;
MultiSzAppendA (&StringBuf, Start);
Quoted = FALSE;
if (_mbschr (Start, '\"')) {
p = Start;
q = UnquotedPath;
End = (PSTR) ((PBYTE) UnquotedPath + sizeof (UnquotedPath) - sizeof (CHAR));
while (*p && q < End) {
if (IsLeadByte (*p)) {
*q++ = *p++;
*q++ = *p++;
} else {
if (*p == '\"') {
p++;
} else {
*q++ = *p++;
}
}
}
*q = 0;
CmdLineArg->CleanedUpArg = (PCSTR) StringBuf.End;
MultiSzAppendA (&StringBuf, UnquotedPath);
Quoted = TRUE;
} else {
CmdLineArg->CleanedUpArg = CmdLineArg->OriginalArg;
}
CmdLineArg->Attributes = INVALID_ATTRIBUTES;
CmdLineArg->Quoted = Quoted;
if (j < Count) {
*Array[j] = OldChar;
}
i = j;
}
}
}
//
// We now have a command line table; transfer StringBuf to Buffer, then
// convert all offsets into pointers.
//
MYASSERT (StringBuf.End);
CopyBuf = GrowBuffer (Buffer, StringBuf.End);
MYASSERT (CopyBuf);
Base = (UINT) CopyBuf;
CopyMemory (CopyBuf, StringBuf.Buf, StringBuf.End);
CmdLineTable->CmdLine = (PCSTR) ((PBYTE) CmdLineTable->CmdLine + Base);
CmdLineArg = &CmdLineTable->Args[0];
for (i = 0 ; i < (INT) CmdLineTable->ArgCount ; i++) {
CmdLineArg->OriginalArg = (PCSTR) ((PBYTE) CmdLineArg->OriginalArg + Base);
CmdLineArg->CleanedUpArg = (PCSTR) ((PBYTE) CmdLineArg->CleanedUpArg + Base);
CmdLineArg++;
}
FreeGrowBuffer (&StringBuf);
FreeGrowBuffer (&SpacePtrs);
return (PCMDLINEA) Buffer->Buf;
}
PCMDLINEW
ParseCmdLineW (
IN PCWSTR CmdLine,
IN OUT PGROWBUFFER Buffer
)
{
GROWBUFFER SpacePtrs = GROWBUF_INIT;
PCWSTR p;
PWSTR q;
INT Count;
INT i;
INT j;
PWSTR *Array;
PCWSTR Start;
WCHAR OldChar = 0;
GROWBUFFER StringBuf = GROWBUF_INIT;
PBYTE CopyBuf;
PCMDLINEW CmdLineTable;
PCMDLINEARGW CmdLineArg;
UINT Base;
WCHAR Path[MAX_WCHAR_PATH];
WCHAR UnquotedPath[MAX_WCHAR_PATH];
WCHAR FixedFileName[MAX_WCHAR_PATH];
PCWSTR FullPath = NULL;
DWORD Attribs = INVALID_ATTRIBUTES;
PWSTR CmdLineCopy;
BOOL Quoted;
UINT OriginalArgOffset = 0;
UINT CleanedUpArgOffset = 0;
BOOL GoodFileFound = FALSE;
PWSTR DontCare;
WCHAR FirstArgPath[MAX_MBCHAR_PATH];
PWSTR EndOfFirstArg;
BOOL QuoteMode = FALSE;
PWSTR End;
CmdLineCopy = DuplicateTextW (CmdLine);
//
// Build an array of places to break the string
//
for (p = CmdLineCopy ; *p ; p++) {
if (*p == L'\"') {
QuoteMode = !QuoteMode;
} else if (!QuoteMode && (*p == L' ' || *p == L'=')) {
//
// Remove excess spaces
//
q = (PWSTR) p + 1;
while (*q == L' ') {
q++;
}
if (q > p + 1) {
MoveMemory ((PBYTE) p + sizeof (WCHAR), q, SizeOfStringW (q));
}
GrowBufAppendDword (&SpacePtrs, (DWORD) p);
}
}
//
// Prepare the CMDLINE struct
//
CmdLineTable = (PCMDLINEW) GrowBuffer (Buffer, sizeof (CMDLINEW));
MYASSERT (CmdLineTable);
//
// NOTE: We store string offsets, then at the end resolve them
// to pointers later.
//
CmdLineTable->CmdLine = (PCWSTR) StringBuf.End;
MultiSzAppendW (&StringBuf, CmdLine);
CmdLineTable->ArgCount = 0;
//
// Now test every combination, emulating CreateProcess
//
Count = SpacePtrs.End / sizeof (DWORD);
Array = (PWSTR *) SpacePtrs.Buf;
i = -1;
EndOfFirstArg = NULL;
while (i < Count) {
GoodFileFound = FALSE;
Quoted = FALSE;
if (i >= 0) {
Start = Array[i] + 1;
} else {
Start = CmdLineCopy;
}
//
// Check for a full path at Start
//
if (*Start != L'/') {
for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
FullPath = Start;
//
// Remove quotes; continue in the loop if it has no terminating quotes
//
Quoted = FALSE;
if (*Start == L'\"') {
StringCopyByteCountW (UnquotedPath, Start + 1, sizeof (UnquotedPath));
q = wcschr (UnquotedPath, L'\"');
if (q) {
*q = 0;
FullPath = UnquotedPath;
Quoted = TRUE;
} else {
FullPath = NULL;
}
}
if (FullPath && *FullPath) {
//
// Look in file system for the path
//
Attribs = GetLongPathAttributesW (FullPath);
if (Attribs == INVALID_ATTRIBUTES && EndOfFirstArg) {
//
// Try prefixing the path with the first arg's path.
//
StringCopyByteCountW (
EndOfFirstArg,
FullPath,
sizeof (FirstArgPath) - ((PBYTE) EndOfFirstArg - (PBYTE) FirstArgPath)
);
FullPath = FirstArgPath;
Attribs = GetLongPathAttributesW (FullPath);
}
if (Attribs == INVALID_ATTRIBUTES && i < 0) {
//
// Try appending .exe, then testing again. This
// emulates what CreateProcess does.
//
StringCopyByteCountW (
FixedFileName,
FullPath,
sizeof (FixedFileName) - sizeof (L".exe")
);
q = GetEndOfStringW (FixedFileName);
q--;
MYASSERT (q >= FixedFileName);
if (*q != L'.') {
q++;
}
StringCopyW (q, L".exe");
FullPath = FixedFileName;
Attribs = GetLongPathAttributesW (FullPath);
}
if (Attribs != INVALID_ATTRIBUTES) {
//
// Full file path found. Test its file status, then
// move on if there are no important operations on it.
//
OriginalArgOffset = StringBuf.End;
MultiSzAppendW (&StringBuf, Start);
if (!StringMatchW (Start, FullPath)) {
CleanedUpArgOffset = StringBuf.End;
MultiSzAppendW (&StringBuf, FullPath);
} else {
CleanedUpArgOffset = OriginalArgOffset;
}
i = j;
GoodFileFound = TRUE;
}
}
if (j < Count) {
*Array[j] = OldChar;
}
}
if (!GoodFileFound) {
//
// If a wack is in the path, then we could have a relative path, an arg, or
// a full path to a non-existent file.
//
if (wcschr (Start, L'\\')) {
#ifdef DEBUG
j = i + 1;
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
DEBUGMSGW ((
DBG_VERBOSE,
"%s is a non-existent path spec, a relative path, or an arg",
Start
));
if (j < Count) {
*Array[j] = OldChar;
}
#endif
} else {
//
// The string at Start did not contain a full path; try using
// SearchPath.
//
for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
FullPath = Start;
//
// Remove quotes; continue in the loop if it has no terminating quotes
//
Quoted = FALSE;
if (*Start == L'\"') {
StringCopyByteCountW (UnquotedPath, Start + 1, sizeof (UnquotedPath));
q = wcschr (UnquotedPath, L'\"');
if (q) {
*q = 0;
FullPath = UnquotedPath;
Quoted = TRUE;
} else {
FullPath = NULL;
}
}
if (FullPath && *FullPath) {
if (SearchPathW (
NULL,
FullPath,
NULL,
sizeof (Path) / sizeof (Path[0]),
Path,
&DontCare
)) {
FullPath = Path;
} else if (i < 0) {
//
// Try appending .exe and searching the path again
//
StringCopyByteCountW (
FixedFileName,
FullPath,
sizeof (FixedFileName) - sizeof (L".exe")
);
q = GetEndOfStringW (FixedFileName);
q--;
MYASSERT (q >= FixedFileName);
if (*q != L'.') {
q++;
}
StringCopyW (q, L".exe");
if (SearchPathW (
NULL,
FixedFileName,
NULL,
sizeof (Path) / sizeof (Path[0]),
Path,
&DontCare
)) {
FullPath = Path;
} else {
FullPath = NULL;
}
} else {
FullPath = NULL;
}
}
if (FullPath && *FullPath) {
Attribs = GetLongPathAttributesW (FullPath);
MYASSERT (Attribs != INVALID_ATTRIBUTES);
OriginalArgOffset = StringBuf.End;
MultiSzAppendW (&StringBuf, Start);
if (!StringMatchW (Start, FullPath)) {
CleanedUpArgOffset = StringBuf.End;
MultiSzAppendW (&StringBuf, FullPath);
} else {
CleanedUpArgOffset = OriginalArgOffset;
}
i = j;
GoodFileFound = TRUE;
}
if (j < Count) {
*Array[j] = OldChar;
}
}
}
}
}
CmdLineTable->ArgCount += 1;
CmdLineArg = (PCMDLINEARGW) GrowBuffer (Buffer, sizeof (CMDLINEARGW));
MYASSERT (CmdLineArg);
if (GoodFileFound) {
//
// We have a good full file spec in FullPath, its attributes
// are in Attribs, and i has been moved to the space beyond
// the path. We now add a table entry.
//
CmdLineArg->OriginalArg = (PCWSTR) OriginalArgOffset;
CmdLineArg->CleanedUpArg = (PCWSTR) CleanedUpArgOffset;
CmdLineArg->Attributes = Attribs;
CmdLineArg->Quoted = Quoted;
if (!EndOfFirstArg) {
StringCopyByteCountW (FirstArgPath, (PCWSTR) (StringBuf.Buf + (UINT) CmdLineArg->CleanedUpArg), sizeof (FirstArgPath));
q = (PWSTR) GetFileNameFromPathW (FirstArgPath);
if (q) {
q--;
if (q >= FirstArgPath) {
*q = 0;
}
}
EndOfFirstArg = AppendWackW (FirstArgPath);
}
} else {
//
// We do not have a good file spec; we must have a non-file
// argument. Put it in the table, and advance to the next
// arg.
//
j = i + 1;
if (j <= Count) {
if (j < Count) {
OldChar = *Array[j];
*Array[j] = 0;
}
CmdLineArg->OriginalArg = (PCWSTR) StringBuf.End;
MultiSzAppendW (&StringBuf, Start);
Quoted = FALSE;
if (wcschr (Start, '\"')) {
p = Start;
q = UnquotedPath;
End = (PWSTR) ((PBYTE) UnquotedPath + sizeof (UnquotedPath) - sizeof (WCHAR));
while (*p && q < End) {
if (*p == L'\"') {
p++;
} else {
*q++ = *p++;
}
}
*q = 0;
CmdLineArg->CleanedUpArg = (PCWSTR) StringBuf.End;
MultiSzAppendW (&StringBuf, UnquotedPath);
Quoted = TRUE;
} else {
CmdLineArg->CleanedUpArg = CmdLineArg->OriginalArg;
}
CmdLineArg->Attributes = INVALID_ATTRIBUTES;
CmdLineArg->Quoted = Quoted;
if (j < Count) {
*Array[j] = OldChar;
}
i = j;
}
}
}
//
// We now have a command line table; transfer StringBuf to Buffer, then
// convert all offsets into pointers.
//
MYASSERT (StringBuf.End);
CopyBuf = GrowBuffer (Buffer, StringBuf.End);
MYASSERT (CopyBuf);
Base = (UINT) CopyBuf;
CopyMemory (CopyBuf, StringBuf.Buf, StringBuf.End);
CmdLineTable->CmdLine = (PCWSTR) ((PBYTE) CmdLineTable->CmdLine + Base);
CmdLineArg = &CmdLineTable->Args[0];
for (i = 0 ; i < (INT) CmdLineTable->ArgCount ; i++) {
CmdLineArg->OriginalArg = (PCWSTR) ((PBYTE) CmdLineArg->OriginalArg + Base);
CmdLineArg->CleanedUpArg = (PCWSTR) ((PBYTE) CmdLineArg->CleanedUpArg + Base);
CmdLineArg++;
}
FreeGrowBuffer (&StringBuf);
FreeGrowBuffer (&SpacePtrs);
return (PCMDLINEW) Buffer->Buf;
}
BOOL
GetFileSizeFromFilePathA(
IN PCSTR FilePath,
OUT ULARGE_INTEGER * FileSize
)
{
WIN32_FILE_ATTRIBUTE_DATA fileDataAttributes;
if(!FilePath || !FileSize){
MYASSERT(FALSE);
return FALSE;
}
if (!IsPathOnFixedDriveA (FilePath)) {
FileSize->QuadPart = 0;
MYASSERT(FALSE);
return FALSE;
}
if(!GetFileAttributesExA(FilePath, GetFileExInfoStandard, &fileDataAttributes) ||
fileDataAttributes.dwFileAttributes == INVALID_ATTRIBUTES ||
(fileDataAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
MYASSERT(FALSE);
return FALSE;
}
FileSize->LowPart = fileDataAttributes.nFileSizeLow;
FileSize->HighPart = fileDataAttributes.nFileSizeHigh;
return TRUE;
}
BOOL
GetFileSizeFromFilePathW(
IN PCWSTR FilePath,
OUT ULARGE_INTEGER * FileSize
)
{
WIN32_FILE_ATTRIBUTE_DATA fileDataAttributes;
if(!FilePath || !FileSize){
MYASSERT(FALSE);
return FALSE;
}
if (!IsPathOnFixedDriveW (FilePath)) {
FileSize->QuadPart = 0;
MYASSERT(FALSE);
return FALSE;
}
if(!GetFileAttributesExW(FilePath, GetFileExInfoStandard, &fileDataAttributes) ||
fileDataAttributes.dwFileAttributes == INVALID_ATTRIBUTES ||
(fileDataAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
MYASSERT(FALSE);
return FALSE;
}
FileSize->LowPart = fileDataAttributes.nFileSizeLow;
FileSize->HighPart = fileDataAttributes.nFileSizeHigh;
return TRUE;
}
VOID
InitializeDriveLetterStructureA (
OUT PDRIVELETTERSA DriveLetters
)
{
BYTE bitPosition;
DWORD maxBitPosition = NUMDRIVELETTERS;
CHAR rootPath[] = "?:\\";
BOOL driveExists;
UINT type;
//
// GetLogicalDrives returns a bitmask of all of the drive letters
// in use on the system. (i.e. bit position 0 is turned on if there is
// an 'A' drive, 1 is turned on if there is a 'B' drive, etc.
// This loop will use this bitmask to fill in the global drive
// letters structure with information about what drive letters
// are available and what there drive types are.
//
for (bitPosition = 0; bitPosition < maxBitPosition; bitPosition++) {
//
// Initialize this drive
//
DriveLetters->ExistsOnSystem[bitPosition] = FALSE;
DriveLetters->Type[bitPosition] = 0;
DriveLetters->IdentifierString[bitPosition][0] = 0;
rootPath[0] = 'A' + bitPosition;
DriveLetters->Letter[bitPosition] = rootPath[0];
//
// Determine if there is a drive in this spot.
//
driveExists = GetLogicalDrives() & (1 << bitPosition);
if (driveExists) {
//
// There is. Now, see if it is one that we care about.
//
type = GetDriveTypeA(rootPath);
if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM) {
//
// This is a drive that we are interested in.
//
DriveLetters->ExistsOnSystem[bitPosition] = TRUE;
DriveLetters->Type[bitPosition] = type;
//
// Identifier String is not filled in this function.
//
}
}
}
}
VOID
InitializeDriveLetterStructureW (
OUT PDRIVELETTERSW DriveLetters
)
{
BYTE bitPosition;
DWORD maxBitPosition = NUMDRIVELETTERS;
WCHAR rootPath[] = L"?:\\";
BOOL driveExists;
UINT type;
//
// GetLogicalDrives returns a bitmask of all of the drive letters
// in use on the system. (i.e. bit position 0 is turned on if there is
// an 'A' drive, 1 is turned on if there is a 'B' drive, etc.
// This loop will use this bitmask to fill in the global drive
// letters structure with information about what drive letters
// are available and what there drive types are.
//
for (bitPosition = 0; bitPosition < maxBitPosition; bitPosition++) {
//
// Initialize this drive
//
DriveLetters->ExistsOnSystem[bitPosition] = FALSE;
DriveLetters->Type[bitPosition] = 0;
DriveLetters->IdentifierString[bitPosition][0] = 0;
rootPath[0] = L'A' + bitPosition;
DriveLetters->Letter[bitPosition] = rootPath[0];
//
// Determine if there is a drive in this spot.
//
driveExists = GetLogicalDrives() & (1 << bitPosition);
if (driveExists) {
//
// There is. Now, see if it is one that we care about.
//
type = GetDriveTypeW(rootPath);
if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM) {
//
// This is a drive that we are interested in.
//
DriveLetters->ExistsOnSystem[bitPosition] = TRUE;
DriveLetters->Type[bitPosition] = type;
//
// Identifier String is not filled in this function.
//
}
}
}
}
typedef BOOL (WINAPI * GETDISKFREESPACEEXA)(
PCSTR lpDirectoryName, // directory name
PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
);
typedef BOOL (WINAPI * GETDISKFREESPACEEXW)(
PCWSTR lpDirectoryName, // directory name
PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
);
BOOL
GetDiskFreeSpaceNewA(
IN PCSTR DriveName,
OUT DWORD * OutSectorsPerCluster,
OUT DWORD * OutBytesPerSector,
OUT ULARGE_INTEGER * OutNumberOfFreeClusters,
OUT ULARGE_INTEGER * OutTotalNumberOfClusters
)
/*++
Routine Description:
On Win9x GetDiskFreeSpace never return free/total space more than 2048MB.
GetDiskFreeSpaceNew use GetDiskFreeSpaceEx to calculate real number of free/total clusters.
Has same declaration as GetDiskFreeSpaceA.
Arguments:
DriveName - supplies directory name
OutSectorsPerCluster - receive number of sectors per cluster
OutBytesPerSector - receive number of bytes per sector
OutNumberOfFreeClusters - receive number of free clusters
OutTotalNumberOfClusters - receive number of total clusters
Return Value:
TRUE if the function succeeds.
If the function fails, the return value is FALSE. To get extended error information, call GetLastError
--*/
{
ULARGE_INTEGER TotalNumberOfFreeBytes = {0, 0};
ULARGE_INTEGER TotalNumberOfBytes = {0, 0};
ULARGE_INTEGER DonotCare;
HMODULE hKernel32;
GETDISKFREESPACEEXA pGetDiskFreeSpaceExA;
ULARGE_INTEGER NumberOfFreeClusters = {0, 0};
ULARGE_INTEGER TotalNumberOfClusters = {0, 0};
DWORD SectorsPerCluster;
DWORD BytesPerSector;
if(!GetDiskFreeSpaceA(DriveName,
&SectorsPerCluster,
&BytesPerSector,
&NumberOfFreeClusters.LowPart,
&TotalNumberOfClusters.LowPart)){
DEBUGMSG((DBG_ERROR,"GetDiskFreeSpaceNewA: GetDiskFreeSpaceA failed on drive %s", DriveName));
return FALSE;
}
hKernel32 = LoadLibraryA("kernel32.dll");
pGetDiskFreeSpaceExA = (GETDISKFREESPACEEXA)GetProcAddress(hKernel32, "GetDiskFreeSpaceExA");
if(pGetDiskFreeSpaceExA &&
pGetDiskFreeSpaceExA(DriveName, &DonotCare, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)){
NumberOfFreeClusters.QuadPart = TotalNumberOfFreeBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
TotalNumberOfClusters.QuadPart = TotalNumberOfBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
}
else{
DEBUGMSG((DBG_WARNING,
pGetDiskFreeSpaceExA?
"GetDiskFreeSpaceNewA: GetDiskFreeSpaceExA is failed":
"GetDiskFreeSpaceNewA: GetDiskFreeSpaceExA function is not in kernel32.dll"));
}
FreeLibrary(hKernel32);
if(OutSectorsPerCluster){
*OutSectorsPerCluster = SectorsPerCluster;
}
if(OutBytesPerSector){
*OutBytesPerSector = BytesPerSector;
}
if(OutNumberOfFreeClusters){
OutNumberOfFreeClusters->QuadPart = NumberOfFreeClusters.QuadPart;
}
if(OutTotalNumberOfClusters){
OutTotalNumberOfClusters->QuadPart = TotalNumberOfClusters.QuadPart;
}
DEBUGMSG((DBG_VERBOSE,
"GetDiskFreeSpaceNewA: \n\t"
"SectorsPerCluster = %d\n\t"
"BytesPerSector = %d\n\t"
"NumberOfFreeClusters = %I64u\n\t"
"TotalNumberOfClusters = %I64u",
SectorsPerCluster,
BytesPerSector,
NumberOfFreeClusters.QuadPart,
TotalNumberOfClusters.QuadPart));
return TRUE;
}
BOOL
GetDiskFreeSpaceNewW(
IN PCWSTR DriveName,
OUT DWORD * OutSectorsPerCluster,
OUT DWORD * OutBytesPerSector,
OUT ULARGE_INTEGER * OutNumberOfFreeClusters,
OUT ULARGE_INTEGER * OutTotalNumberOfClusters
)
/*++
Routine Description:
Correct NumberOfFreeClusters and TotalNumberOfClusters out parameters
with using GetDiskFreeSpace and GetDiskFreeSpaceEx
Arguments:
DriveName - supplies directory name
OutSectorsPerCluster - receive number of sectors per cluster
OutBytesPerSector - receive number of bytes per sector
OutNumberOfFreeClusters - receive number of free clusters
OutTotalNumberOfClusters - receive number of total clusters
Return Value:
TRUE if the function succeeds.
If the function fails, the return value is FALSE. To get extended error information, call GetLastError
--*/
{
ULARGE_INTEGER TotalNumberOfFreeBytes = {0, 0};
ULARGE_INTEGER TotalNumberOfBytes = {0, 0};
ULARGE_INTEGER DonotCare;
HMODULE hKernel32;
GETDISKFREESPACEEXW pGetDiskFreeSpaceExW;
ULARGE_INTEGER NumberOfFreeClusters = {0, 0};
ULARGE_INTEGER TotalNumberOfClusters = {0, 0};
DWORD SectorsPerCluster;
DWORD BytesPerSector;
if(!GetDiskFreeSpaceW(DriveName,
&SectorsPerCluster,
&BytesPerSector,
&NumberOfFreeClusters.LowPart,
&TotalNumberOfClusters.LowPart)){
DEBUGMSG((DBG_ERROR,"GetDiskFreeSpaceNewW: GetDiskFreeSpaceW failed on drive %s", DriveName));
return FALSE;
}
hKernel32 = LoadLibraryA("kernel32.dll");
pGetDiskFreeSpaceExW = (GETDISKFREESPACEEXW)GetProcAddress(hKernel32, "GetDiskFreeSpaceExW");
if(pGetDiskFreeSpaceExW &&
pGetDiskFreeSpaceExW(DriveName, &DonotCare, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)){
NumberOfFreeClusters.QuadPart = TotalNumberOfFreeBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
TotalNumberOfClusters.QuadPart = TotalNumberOfBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
}
else{
DEBUGMSG((DBG_WARNING,
pGetDiskFreeSpaceExW?
"GetDiskFreeSpaceNewW: GetDiskFreeSpaceExW is failed":
"GetDiskFreeSpaceNewW: GetDiskFreeSpaceExW function is not in kernel32.dll"));
}
FreeLibrary(hKernel32);
if(OutSectorsPerCluster){
*OutSectorsPerCluster = SectorsPerCluster;
}
if(OutBytesPerSector){
*OutBytesPerSector = BytesPerSector;
}
if(OutNumberOfFreeClusters){
OutNumberOfFreeClusters->QuadPart = NumberOfFreeClusters.QuadPart;
}
if(OutTotalNumberOfClusters){
OutTotalNumberOfClusters->QuadPart = TotalNumberOfClusters.QuadPart;
}
DEBUGMSG((DBG_VERBOSE,
"GetDiskFreeSpaceNewW: \n\t"
"SectorsPerCluster = %d\n\t"
"BytesPerSector = %d\n\t"
"NumberOfFreeClusters = %I64u\n\t"
"TotalNumberOfClusters = %I64u",
SectorsPerCluster,
BytesPerSector,
NumberOfFreeClusters.QuadPart,
TotalNumberOfClusters.QuadPart));
return TRUE;
}
DWORD
QuietGetFileAttributesA (
IN PCSTR FilePath
)
{
if (!IsPathOnFixedDriveA (FilePath)) {
return INVALID_ATTRIBUTES;
}
return GetFileAttributesA (FilePath);
}
DWORD
QuietGetFileAttributesW (
IN PCWSTR FilePath
)
{
MYASSERT (ISNT());
if (!IsPathOnFixedDriveW (FilePath)) {
return INVALID_ATTRIBUTES;
}
return GetLongPathAttributesW (FilePath);
}
DWORD
MakeSureLongPathExistsW (
IN PCWSTR Path,
IN BOOL PathOnly
)
{
PCWSTR tmp;
DWORD result;
if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
result = MakeSurePathExistsW (Path, PathOnly);
} else {
tmp = JoinPathsW (L"\\\\?", Path);
result = MakeSurePathExistsW (tmp, PathOnly);
FreePathStringW (tmp);
}
return result;
}
DWORD
SetLongPathAttributesW (
IN PCWSTR Path,
IN DWORD Attributes
)
{
PCWSTR tmp;
DWORD result;
if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
result = SetFileAttributesW (Path, Attributes);
} else {
tmp = JoinPathsW (L"\\\\?", Path);
result = SetFileAttributesW (tmp, Attributes);
FreePathStringW (tmp);
}
return result;
}
DWORD
GetLongPathAttributesW (
IN PCWSTR Path
)
{
PCWSTR tmp;
DWORD result;
if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
result = GetFileAttributesW (Path);
} else {
tmp = JoinPathsW (L"\\\\?", Path);
result = GetFileAttributesW (tmp);
FreePathStringW (tmp);
}
return result;
}
BOOL
DeleteLongPathW (
IN PCWSTR Path
)
{
PCWSTR tmp;
BOOL result;
if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
result = DeleteFileW (Path);
} else {
tmp = JoinPathsW (L"\\\\?", Path);
result = DeleteFileW (tmp);
FreePathStringW (tmp);
}
return result;
}
BOOL
RemoveLongDirectoryPathW (
IN PCWSTR Path
)
{
PCWSTR tmp;
BOOL result;
if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
result = RemoveDirectoryW (Path);
} else {
tmp = JoinPathsW (L"\\\\?", Path);
result = RemoveDirectoryW (tmp);
FreePathStringW (tmp);
}
return result;
}