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

1221 lines
36 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
csm.c
Abstract:
Implements the existing state analyze portion of the v1 module.
The existing state module enumerates everything in the environment
variables DelReg* and DelFile* (where * is a one-based number),
and then sets the delete operation on everything that matches.
Author:
Jim Schmidt (jimschm) 21-Mar-2000
Revision History:
<alias> <date> <comments>
--*/
//
// Includes
//
#include "pch.h"
#include "v1p.h"
#define DBG_V1 "v1"
//
// Strings
//
// None
//
// Constants
//
#define NORMAL_DRIVE_BUFFER_BYTES 50000000
#define SYSTEM_DRIVE_BUFFER_BYTES (NORMAL_DRIVE_BUFFER_BYTES + 50000000)
#define MAX_CONTENT_CHECK 0x100000
//
// Macros
//
// None
//
// Types
//
typedef struct {
ULARGE_INTEGER FreeSpace;
DWORD BytesPerCluster;
} DRIVE_INFO, *PDRIVE_INFO;
//
// Globals
//
MIG_OPERATIONID g_DeleteOp;
MIG_OPERATIONID g_PartMoveOp;
HASHTABLE g_PartitionSpaceTable;
HASHTABLE g_PartitionMatchTable;
HASHTABLE g_CollisionSrcTable;
HASHTABLE g_CollisionDestTable;
PMHANDLE g_UntrackedCsmPool;
TCHAR g_SystemDrive[_MAX_DRIVE + 1];
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
CSMINITIALIZE ScriptCsmInitialize;
CSMEXECUTE ScriptCsmExecute;
//
// Macro expansion definition
//
// None
//
// Code
//
VOID
pPopulatePartitionTable (
VOID
)
{
PCTSTR drive;
DRIVE_INFO driveInfo;
ULARGE_INTEGER whoCares;
PTSTR driveList = NULL;
DWORD driveListLen;
DWORD sectPerClust, bytesPerSect, freeClusters, totalClusters;
FARPROC pGetDiskFreeSpaceEx;
BOOL validDrive;
if (!GetEnvironmentVariable (TEXT("SYSTEMDRIVE"), g_SystemDrive, _MAX_DRIVE)) {
StringCopyTcharCount (g_SystemDrive, TEXT("C:"), _MAX_DRIVE);
}
driveListLen = GetLogicalDriveStrings (0, driveList);
driveList = AllocText (driveListLen + 1);
if (!driveList) {
return;
}
GetLogicalDriveStrings (driveListLen, driveList);
drive = driveList;
// Find out if GetDiskFreeSpaceEx is supported
#ifdef UNICODE
pGetDiskFreeSpaceEx = GetProcAddress (GetModuleHandle (TEXT("kernel32.dll")), "GetDiskFreeSpaceExW");
#else
pGetDiskFreeSpaceEx = GetProcAddress (GetModuleHandle (TEXT("kernel32.dll")), "GetDiskFreeSpaceExA");
#endif
while (*drive) {
validDrive = FALSE;
if (GetDriveType (drive) == DRIVE_FIXED) {
ZeroMemory (&driveInfo, sizeof (DRIVE_INFO));
if (pGetDiskFreeSpaceEx) {
if (pGetDiskFreeSpaceEx (drive, &driveInfo.FreeSpace, &whoCares, &whoCares)) {
validDrive = TRUE;
if (GetDiskFreeSpace (drive, &sectPerClust, &bytesPerSect, &freeClusters, &totalClusters)) {
driveInfo.BytesPerCluster = bytesPerSect * sectPerClust;
if (!driveInfo.BytesPerCluster) {
driveInfo.BytesPerCluster = 1;
}
}
}
} else {
if (GetDiskFreeSpace (drive, &sectPerClust, &bytesPerSect, &freeClusters, &totalClusters)) {
driveInfo.FreeSpace.QuadPart = Int32x32To64 ((sectPerClust * bytesPerSect), freeClusters);
driveInfo.BytesPerCluster = bytesPerSect * sectPerClust;
if (!driveInfo.BytesPerCluster) {
driveInfo.BytesPerCluster = 1;
}
validDrive = TRUE;
}
}
}
if (validDrive) {
HtAddStringEx (g_PartitionSpaceTable, drive, &driveInfo, FALSE);
}
// Advance to the next drive in the drive list
drive = _tcschr (drive, 0) + 1;
}
FreeText (driveList);
}
BOOL
pIsSystemDrive (
IN PCTSTR Drive
)
{
if (StringIMatchCharCount (g_SystemDrive, Drive, 2)) {
return TRUE;
}
return FALSE;
}
BOOL
pReserveDiskSpace (
IN PCTSTR DestDrive,
IN ULARGE_INTEGER FileSize,
IN BOOL IgnoreBuffer
)
{
DRIVE_INFO driveInfo;
ULARGE_INTEGER buffer;
HASHITEM hashItem;
BOOL success = FALSE;
hashItem = HtFindStringEx (g_PartitionSpaceTable, DestDrive, &driveInfo, FALSE);
if (hashItem) {
// let's transform the FileSize so it is alligned to BytesPerCluster
FileSize.QuadPart = ((FileSize.QuadPart + driveInfo.BytesPerCluster - 1) / driveInfo.BytesPerCluster) * driveInfo.BytesPerCluster;
if (IgnoreBuffer) {
if (pIsSystemDrive (DestDrive)) {
buffer.QuadPart = NORMAL_DRIVE_BUFFER_BYTES;
} else {
buffer.QuadPart = 0;
}
} else {
if (pIsSystemDrive (DestDrive)) {
buffer.QuadPart = SYSTEM_DRIVE_BUFFER_BYTES;
} else {
buffer.QuadPart = NORMAL_DRIVE_BUFFER_BYTES;
}
}
// Check for available space
if (driveInfo.FreeSpace.QuadPart > buffer.QuadPart &&
FileSize.QuadPart < driveInfo.FreeSpace.QuadPart - buffer.QuadPart) {
// Subtract claimed disk space
driveInfo.FreeSpace.QuadPart -= FileSize.QuadPart;
HtSetStringData (g_PartitionSpaceTable, hashItem, &driveInfo);
success = TRUE;
}
}
return success;
}
BOOL
pValidatePartition (
IN MIG_OBJECTSTRINGHANDLE CurrentObjectName,
IN PCTSTR Destination
)
{
MIG_CONTENT srcContent;
PWIN32_FIND_DATAW findData;
TCHAR tmpDrive[_MAX_DRIVE + 1];
ULARGE_INTEGER fileSize;
UINT driveType;
PTSTR fullDest;
fullDest = DuplicatePathString (Destination, 1);
AppendWack (fullDest);
// Check with full Destination path for cases of UNC paths
driveType = GetDriveType (fullDest);
if (driveType == DRIVE_NO_ROOT_DIR) {
// It thinks there is nothing mounted at that destination. If the destination
// looks like G:\files1 then it will give this error when G: is a valid mapped
// drive. So we'll check one more time with just "G:\"
fullDest[3] = 0;
driveType = GetDriveType (fullDest);
}
FreePathString (fullDest);
if (driveType == DRIVE_REMOTE ||
(Destination[0] == TEXT('\\') && Destination[1] == TEXT('\\'))
) {
return TRUE;
}
if (driveType == DRIVE_FIXED) {
// Acquire the object to get the filesize
if (IsmAcquireObjectEx (
g_FileType | PLATFORM_SOURCE,
CurrentObjectName,
&srcContent,
CONTENTTYPE_DETAILS_ONLY,
0
)) {
// Check to see if the desired destination has space
findData = (PWIN32_FIND_DATAW)srcContent.Details.DetailsData;
fileSize.LowPart = findData->nFileSizeLow;
fileSize.HighPart = findData->nFileSizeHigh;
tmpDrive[0] = Destination[0];
tmpDrive[1] = Destination[1];
tmpDrive[2] = TEXT('\\');
tmpDrive[3] = 0;
IsmReleaseObject (&srcContent);
return (pReserveDiskSpace (tmpDrive, fileSize, FALSE));
}
}
// Not a Fixed drive or Remote drive, so it's not a valid destination
return FALSE;
}
BOOL
pFindValidPartition (
IN MIG_OBJECTSTRINGHANDLE ObjectName,
IN OUT PTSTR DestNode,
IN BOOL IgnoreBuffer // must be FALSE except when called by itself
)
{
MIG_CONTENT srcContent;
PWIN32_FIND_DATAW findData;
PTSTR drivePtr;
ULARGE_INTEGER fileSize;
TCHAR tmpDrive[_MAX_DRIVE + 1];
BOOL newDestFound = FALSE;
PTSTR driveList = NULL;
DWORD driveListLen;
TCHAR destDrive;
BOOL destChanged = FALSE;
PCTSTR oldDestNode;
BOOL result = TRUE;
oldDestNode = DuplicatePathString (DestNode, 0);
if (IsmAcquireObjectEx (
g_FileType | PLATFORM_SOURCE,
ObjectName,
&srcContent,
CONTENTTYPE_DETAILS_ONLY,
0
)) {
// First check to see if we already matched up this file
if (HtFindStringEx (g_PartitionMatchTable, ObjectName, &destDrive, FALSE)) {
DestNode[0] = destDrive;
} else {
// Need a new destination for this file
destChanged = TRUE;
findData = (PWIN32_FIND_DATAW)srcContent.Details.DetailsData;
fileSize.LowPart = findData->nFileSizeLow;
fileSize.HighPart = findData->nFileSizeHigh;
if (GetEnvironmentVariable (TEXT("SYSTEMDRIVE"), tmpDrive, _MAX_DRIVE)) {
AppendWack (tmpDrive);
if (pReserveDiskSpace (tmpDrive, fileSize, IgnoreBuffer)) {
newDestFound = TRUE;
DestNode[0] = tmpDrive[0];
}
}
if (newDestFound == FALSE) {
// Check drives in alphabetical order
driveListLen = GetLogicalDriveStrings (0, driveList);
driveList = AllocText (driveListLen + 1);
GetLogicalDriveStrings (driveListLen, driveList);
drivePtr = driveList;
while (*drivePtr) {
if (pReserveDiskSpace (drivePtr, fileSize, IgnoreBuffer)) {
DestNode[0] = drivePtr[0];
newDestFound = TRUE;
break;
}
// Advance to the next drive in the drive list
drivePtr = _tcschr (drivePtr, 0) + 1;
}
FreeText (driveList);
}
if (newDestFound == FALSE) {
if (IgnoreBuffer == FALSE) {
// We couldn't find space. Look again, but override the buffer space
// NTRAID#NTBUG9-153274-2000/08/01-jimschm It will currently fill up the system drive first, which is not what we should do.
result = pFindValidPartition (ObjectName, DestNode, TRUE);
} else {
// Okay it's hopeless. Keep track of how badly we're out of space
LOG ((
LOG_ERROR,
(PCSTR) MSG_PARTMAP_DISKFULL,
IsmGetNativeObjectName (g_FileType, ObjectName)
));
result = FALSE;
}
} else {
if (destChanged == TRUE) {
LOG ((
LOG_WARNING,
(PCSTR) MSG_PARTMAP_FORCED_REMAP,
IsmGetNativeObjectName (g_FileType, ObjectName),
oldDestNode,
DestNode
));
}
}
}
IsmReleaseObject (&srcContent);
}
FreePathString (oldDestNode);
return result;
}
BOOL
pCompareFiles (
IN PCTSTR File1,
IN PCTSTR File2
)
{
HANDLE fileHandle1 = NULL;
HANDLE fileHandle2 = NULL;
#define BUFFER_SIZE 4096
BYTE buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
BOOL result = FALSE;
BOOL res1, res2;
DWORD read1, read2;
__try {
fileHandle1 = BfOpenReadFile (File1);
fileHandle2 = BfOpenReadFile (File2);
if (fileHandle1 && fileHandle2) {
while (TRUE) {
if (IsmCheckCancel ()) {
result = FALSE;
break;
}
res1 = ReadFile (fileHandle1, buffer1, BUFFER_SIZE, &read1, NULL);
res2 = ReadFile (fileHandle2, buffer2, BUFFER_SIZE, &read2, NULL);
if (!res1 && !res2) {
result = TRUE;
break;
}
if (res1 && res2) {
if (read1 != read2) {
break;
}
if (read1 == 0) {
result = TRUE;
break;
}
if (!TestBuffer (buffer1, buffer2, read1)) {
break;
}
} else {
break;
}
}
}
}
__finally {
if (fileHandle1) {
CloseHandle (fileHandle1);
fileHandle1 = NULL;
}
if (fileHandle2) {
CloseHandle (fileHandle2);
fileHandle2 = NULL;
}
}
return result;
}
BOOL
pDoesFileContentMatch (
IN BOOL AlreadyProcessed,
IN MIG_OBJECTTYPEID SrcObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
IN PMIG_CONTENT SrcContent,
IN MIG_OBJECTTYPEID DestObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE DestObjectName,
IN PMIG_CONTENT DestContent,
OUT PBOOL Identical,
OUT PBOOL DifferentDetailsOnly
)
{
UINT index;
PWIN32_FIND_DATAW find1, find2;
BOOL result = FALSE;
PUBINT src;
PUBINT dest;
UINT remainder;
UINT count;
DWORD allAttribs;
DWORD extendedAttribs;
if (AlreadyProcessed) {
return FALSE;
}
if ((SrcObjectTypeId != MIG_FILE_TYPE) ||
(DestObjectTypeId != MIG_FILE_TYPE)
) {
return FALSE;
}
if (DifferentDetailsOnly) {
*DifferentDetailsOnly = FALSE;
}
if (SrcContent->Details.DetailsSize != DestContent->Details.DetailsSize) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if (!SrcContent->Details.DetailsData || !DestContent->Details.DetailsData) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
find1 = (PWIN32_FIND_DATAW)SrcContent->Details.DetailsData;
find2 = (PWIN32_FIND_DATAW)DestContent->Details.DetailsData;
if (find1->nFileSizeHigh != find2->nFileSizeHigh) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if (find1->nFileSizeLow != find2->nFileSizeLow) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if (SrcContent->ContentInFile && DestContent->ContentInFile) {
result = pCompareFiles (SrcContent->FileContent.ContentPath, DestContent->FileContent.ContentPath);
}
if (!SrcContent->ContentInFile && !DestContent->ContentInFile) {
if (SrcContent->MemoryContent.ContentSize != DestContent->MemoryContent.ContentSize) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if ((!SrcContent->MemoryContent.ContentBytes && DestContent->MemoryContent.ContentBytes) ||
(SrcContent->MemoryContent.ContentBytes && !DestContent->MemoryContent.ContentBytes)
) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
//
// Compare the content using the largest unsigned int available, then
// compare any remaining bytes
//
index = 0;
count = SrcContent->MemoryContent.ContentSize / sizeof (UBINT);
remainder = SrcContent->MemoryContent.ContentSize % sizeof (UBINT);
src = (PUBINT) SrcContent->MemoryContent.ContentBytes;
dest = (PUBINT) DestContent->MemoryContent.ContentBytes;
while (count) {
if (*src++ != *dest++) {
DEBUGMSG ((DBG_WARNING, "Content mismatch because UBINTs differ"));
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
count--;
}
for (index = 0 ; index < remainder ; index++) {
if (((PBYTE) src)[index] != ((PBYTE) dest)[index]) {
DEBUGMSG ((DBG_WARNING, "Content mismatch because bytes differ"));
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
}
result = TRUE;
}
if (!result) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
//
// At this point the files are the same. Now if the attributes are different, return
// FALSE indicating that only the details differ.
//
if (DifferentDetailsOnly) {
*DifferentDetailsOnly = TRUE;
}
if (find1->dwFileAttributes != find2->dwFileAttributes) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if (find1->ftLastWriteTime.dwLowDateTime != find2->ftLastWriteTime.dwLowDateTime) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if (find1->ftLastWriteTime.dwHighDateTime != find2->ftLastWriteTime.dwHighDateTime) {
if (Identical) {
Identical = FALSE;
}
return TRUE;
}
if (DifferentDetailsOnly) {
*DifferentDetailsOnly = FALSE;
}
if (Identical) {
*Identical = TRUE;
}
return TRUE;
}
BOOL
WINAPI
ScriptCsmInitialize (
IN PMIG_LOGCALLBACK LogCallback,
IN PVOID Reserved
)
{
//
// Get file and registry types
//
g_FileType = MIG_FILE_TYPE;
g_RegType = MIG_REGISTRY_TYPE;
g_IniType = MIG_INI_TYPE;
//
// Get operation types
//
g_DeleteOp = IsmRegisterOperation (S_OPERATION_DELETE, FALSE);
g_PartMoveOp = IsmRegisterOperation (S_OPERATION_PARTITION_MOVE, TRUE);
g_LockPartitionAttr = IsmRegisterAttribute (S_ATTRIBUTE_PARTITIONLOCK, FALSE);
g_CollisionSrcTable = HtAllocWithData (sizeof (HASHITEM));
g_CollisionDestTable = HtAllocWithData (sizeof (MIG_OBJECTSTRINGHANDLE));
g_PartitionSpaceTable = HtAllocWithData (sizeof (DRIVE_INFO));
g_PartitionMatchTable = HtAllocWithData (sizeof (TCHAR));
pPopulatePartitionTable ();
g_UntrackedCsmPool = PmCreatePool ();
PmDisableTracking (g_UntrackedCsmPool);
OE5RemapDefaultId();
IsmRegisterCompareCallback (MIG_FILE_TYPE, pDoesFileContentMatch);
return TRUE;
}
VOID
WINAPI
ScriptCsmTerminate (
VOID
)
{
HtFree (g_CollisionSrcTable);
g_CollisionSrcTable = NULL;
HtFree (g_CollisionDestTable);
g_CollisionDestTable = NULL;
HtFree (g_PartitionSpaceTable);
g_PartitionSpaceTable = NULL;
HtFree (g_PartitionMatchTable);
g_PartitionMatchTable = NULL;
PmDestroyPool (g_UntrackedCsmPool);
g_UntrackedCsmPool = NULL;
}
BOOL
pExecuteDeleteEnum (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE Pattern
)
{
MIG_OBJECT_ENUM e;
BOOL b = TRUE;
if (IsmEnumFirstDestinationObject (&e, ObjectTypeId, Pattern)) {
do {
b = IsmSetOperationOnObject (
e.ObjectTypeId,
e.ObjectName,
g_DeleteOp,
NULL,
NULL
);
if (!b) {
IsmAbortObjectEnum (&e);
break;
}
} while (IsmEnumNextObject (&e));
}
return b;
}
BOOL
pDoesDifferentFileExist (
IN MIG_OBJECTSTRINGHANDLE SrcName,
IN MIG_OBJECTSTRINGHANDLE DestName,
IN PCTSTR DestNativeName,
OUT PBOOL DifferentDetailsOnly
)
{
MIG_CONTENT srcContent;
MIG_CONTENT destContent;
WIN32_FIND_DATA findData;
BOOL result = FALSE;
if (!DoesFileExistEx (DestNativeName, &findData)) {
return FALSE;
}
if (findData.nFileSizeHigh) {
return TRUE;
}
if (IsmAcquireObject (
g_FileType | PLATFORM_DESTINATION,
DestName,
&destContent
)) {
result = TRUE;
if (IsmAcquireObject (
g_FileType | PLATFORM_SOURCE,
SrcName,
&srcContent
)) {
result = !IsmAreObjectsIdentical (
MIG_FILE_TYPE,
SrcName,
&srcContent,
MIG_FILE_TYPE,
DestName,
&destContent,
DifferentDetailsOnly
);
IsmReleaseObject (&srcContent);
}
IsmReleaseObject (&destContent);
} else {
result = DoesFileExist (DestNativeName);
}
return result;
}
BOOL
pIsFileDestCollision (
IN MIG_OBJECTSTRINGHANDLE CurrentObjectName,
IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
IN PCTSTR CurrentNativeName,
IN BOOL CompareDestFiles,
IN BOOL *OnlyDetailsDiffer
)
{
if (HtFindString (g_CollisionDestTable, CurrentObjectName)) {
return TRUE;
}
if (CompareDestFiles &&
pDoesDifferentFileExist (OriginalObjectName,
CurrentObjectName,
CurrentNativeName,
OnlyDetailsDiffer)) {
if (*OnlyDetailsDiffer == FALSE) {
return TRUE;
}
}
return FALSE;
}
MIG_OBJECTSTRINGHANDLE
pCollideFile (
IN MIG_OBJECTID OriginalObjectId,
IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
IN PCTSTR NewNode,
IN PCTSTR NewLeaf,
IN BOOL CompareDestFiles
)
{
MIG_OBJECTSTRINGHANDLE result = NULL;
HASHITEM hashItem;
PCTSTR testNativeName;
PCTSTR leafExt = NULL;
TCHAR buff[MAX_TCHAR_PATH * 2];
PTSTR openParen = NULL;
PTSTR closeParen = NULL;
PTSTR tmpLeaf = NULL;
PTSTR testLeaf = NULL;
size_t testLeafTchars;
PTSTR chr;
BOOL onlyDetailsDiffer = FALSE;
BOOL replaceOk = TRUE;
UINT fileIndex = 0;
MIG_PROPERTYDATAID propDataId;
BOOL specialPattern = FALSE;
PTSTR fileCollPattern = NULL;
MIG_BLOBTYPE propDataType;
UINT requiredSize;
HRESULT hr;
if (!HtFindStringEx (g_CollisionSrcTable, OriginalObjectName, (PVOID)(&hashItem), FALSE)) {
// we don't have a spot just yet. Let's make one.
result = IsmCreateObjectHandle (NewNode, NewLeaf);
testNativeName = JoinPaths (NewNode, NewLeaf);
if (pIsFileDestCollision(result,
OriginalObjectName,
testNativeName,
CompareDestFiles,
&onlyDetailsDiffer)) {
tmpLeaf = AllocText (TcharCount (NewLeaf) + 1);
leafExt = _tcsrchr (NewLeaf, TEXT('.'));
if (leafExt) {
StringCopyAB (tmpLeaf, NewLeaf, leafExt);
leafExt = _tcsinc (leafExt);
} else {
StringCopy (tmpLeaf, NewLeaf);
}
// Let's check if we wanted some special pattern for this file
propDataId = IsmGetPropertyFromObjectId (OriginalObjectId, g_FileCollPatternData);
if (propDataId) {
if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
if (propDataType == BLOBTYPE_STRING) {
fileCollPattern = IsmGetMemory (requiredSize);
if (fileCollPattern) {
if (IsmGetPropertyData (
propDataId,
(PBYTE)fileCollPattern,
requiredSize,
NULL,
&propDataType)) {
specialPattern = TRUE;
}
if (!specialPattern) {
IsmReleaseMemory (fileCollPattern);
fileCollPattern = NULL;
}
}
}
}
}
if (specialPattern) {
//
// Loop until we find a non-colliding destination, or a colliding
// dest that differs only by attributes
//
do {
FreePathString (testNativeName);
IsmDestroyObjectHandle (result);
fileIndex ++;
__try {
hr = StringCbPrintf (buff, sizeof (buff), fileCollPattern, tmpLeaf, fileIndex, leafExt?leafExt:TEXT(""), NULL);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
// something went wrong. The pattern might have been terribly wrong
hr = S_FALSE;
}
if (hr != S_OK) {
// something went wrong, we assume that the pattern from the inf is probably bad.
// Just incrementing the index won't solve the problem. Let's just abort this.
fileIndex = 0;
}
result = IsmCreateObjectHandle (NewNode, buff);
testNativeName = JoinPaths (NewNode, buff);
} while (fileIndex && pIsFileDestCollision(
result,
OriginalObjectName,
testNativeName,
CompareDestFiles,
&onlyDetailsDiffer));
if (fileCollPattern) {
IsmReleaseMemory (fileCollPattern);
fileCollPattern = NULL;
}
if (!fileIndex) {
// The collision pattern was bogus and we looped until
// we ran out of indexes. Let's go with the default
// collision mechanism.
specialPattern = FALSE;
}
}
if (!specialPattern) {
// Check if the filename already has a (number) tacked on
openParen = _tcsrchr (tmpLeaf, TEXT('('));
closeParen = _tcsrchr (tmpLeaf, TEXT(')'));
if (closeParen && openParen &&
closeParen > openParen &&
closeParen - openParen > 1) {
// Make sure it's purely numerical
for (chr = openParen+1; chr < closeParen; chr++) {
if (!_istdigit (*chr)) {
replaceOk = FALSE;
break;
}
}
if (replaceOk == TRUE) {
if (_stscanf (openParen, TEXT("(%d)"), &fileIndex)) {
*openParen = 0;
}
}
}
//
// Loop until we find a non-colliding destination, or a colliding
// dest that differs only by attributes
//
do {
FreePathString (testNativeName);
IsmDestroyObjectHandle (result);
FreeText (testLeaf);
fileIndex ++;
wsprintf (buff, TEXT("(%d)"), fileIndex);
testLeafTchars = TcharCount (tmpLeaf) + TcharCount (buff) + 1;
if (leafExt) {
testLeafTchars += TcharCount (leafExt) + 1;
}
testLeaf = AllocText (testLeafTchars);
StringCopy (testLeaf, tmpLeaf);
StringCat (testLeaf, buff);
if (leafExt) {
StringCat (testLeaf, TEXT("."));
StringCat (testLeaf, leafExt);
}
result = IsmCreateObjectHandle (NewNode, testLeaf);
testNativeName = JoinPaths (NewNode, testLeaf);
} while (pIsFileDestCollision(result,
OriginalObjectName,
testNativeName,
CompareDestFiles,
&onlyDetailsDiffer));
}
FreeText (tmpLeaf);
}
if (onlyDetailsDiffer) {
IsmAbandonObjectOnCollision (g_FileType | PLATFORM_DESTINATION, OriginalObjectName);
}
FreePathString (testNativeName);
FreeText (testLeaf);
//
// Put new destination in the hash table and store the Ism handle, which will
// be cleaned up at the end.
//
hashItem = HtAddStringEx (g_CollisionDestTable, result, &result, FALSE);
HtAddStringEx (g_CollisionSrcTable, OriginalObjectName, &hashItem, FALSE);
} else {
//
// Get the already computed collision destination.
//
HtCopyStringData (g_CollisionDestTable, hashItem, (PVOID)(&result));
}
return result;
}
MIG_OBJECTSTRINGHANDLE
pCollisionGetDestination (
IN MIG_OBJECTID OriginalObjectId,
IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
IN PCTSTR NewNode,
IN PCTSTR NewLeaf
)
{
MIG_OBJECTSTRINGHANDLE result = NULL;
BOOL onlyDetailsDiffer = FALSE;
// now we have the destination node. If this is actually a file
// we need to check for collisions. For this we look if the
// destination already has a file like this. After that we use
// a table to reserve ourselves a spot.
if (NewLeaf) {
if (IsmIsObjectAbandonedOnCollision (g_FileType | PLATFORM_DESTINATION, OriginalObjectName)) {
// we don't care about existing files on the destination machine.
// However, some files that we just copy may collide with each other
// so we have to check that.
result = pCollideFile (OriginalObjectId, OriginalObjectName, NewNode, NewLeaf, FALSE);
} else if (IsmIsObjectAbandonedOnCollision (g_FileType | PLATFORM_SOURCE, OriginalObjectName)) {
// this will potentially collide with an existent file but then the source file
// would not survive.
result = IsmCreateObjectHandle (NewNode, NewLeaf);
} else {
result = pCollideFile (OriginalObjectId, OriginalObjectName, NewNode, NewLeaf, TRUE);
}
} else {
result = IsmCreateObjectHandle (NewNode, NULL);
}
return result;
}
BOOL
pExecuteFixFilename (
VOID
)
{
UINT ticks;
MIG_OBJECT_ENUM objectEnum;
MIG_OBJECTSTRINGHANDLE enumPattern;
MIG_PROGRESSSLICEID sliceId;
PCTSTR destination = NULL;
MIG_OBJECTSTRINGHANDLE destFilename;
PTSTR node = NULL;
PCTSTR leaf = NULL;
MIG_BLOB opData;
PMIG_OBJECTCOUNT objectCount;
BOOL deleted;
objectCount = IsmGetObjectsStatistics (g_FileType | PLATFORM_SOURCE);
if (objectCount) {
ticks = objectCount->TotalObjects;
} else {
ticks = 0;
}
sliceId = IsmRegisterProgressSlice (ticks, max (1, ticks / 5));
// Enum source file objects
enumPattern = IsmCreateSimpleObjectPattern (NULL, TRUE, NULL, TRUE); // *,*
if (IsmEnumFirstSourceObject (&objectEnum, g_FileType, enumPattern)) {
do {
// Check if Apply
if (IsmIsApplyObjectId (objectEnum.ObjectId)) {
// Macro expansion, rule processing, etc
destination = IsmFilterObject (objectEnum.ObjectTypeId,
objectEnum.ObjectName,
NULL,
&deleted,
NULL);
if (deleted) {
continue;
}
if (!destination) {
destination = objectEnum.ObjectName;
}
IsmCreateObjectStringsFromHandle (destination, &node, &leaf);
if (node && _tcslen (node) >= 2) {
if (IsValidFileSpec (node)) {
if (!pValidatePartition (objectEnum.ObjectName, node)) {
if (!IsmIsAttributeSetOnObjectId (objectEnum.ObjectId, g_LockPartitionAttr)) {
// Pick a new destination partition
pFindValidPartition (objectEnum.ObjectName, node, FALSE);
}
}
}
}
// We have selected a new partition, so now check for file collisions
destFilename = pCollisionGetDestination (
objectEnum.ObjectId,
objectEnum.ObjectName,
node,
leaf
);
if (node) {
IsmDestroyObjectString (node);
node = NULL;
}
if (leaf) {
IsmDestroyObjectString (leaf);
leaf = NULL;
}
opData.Type = BLOBTYPE_STRING;
opData.String = PmDuplicateString (g_UntrackedCsmPool, destFilename);
IsmDestroyObjectHandle (destFilename);
destFilename = NULL;
// Set a custom operation that will fix the name
IsmSetOperationOnObjectId (
objectEnum.ObjectId,
g_PartMoveOp,
(MIG_DATAHANDLE) 0,
&opData
);
if (!IsmTickProgressBar (sliceId, 1)) {
IsmAbortObjectEnum (&objectEnum);
break;
}
if (destination != objectEnum.ObjectName) {
IsmDestroyObjectHandle (destination);
}
}
} while (IsmEnumNextObject (&objectEnum));
}
IsmDestroyObjectHandle (enumPattern);
INVALID_POINTER (enumPattern);
return TRUE;
}
BOOL
WINAPI
ScriptCsmExecute (
VOID
)
{
UINT u;
TCHAR string[32];
TCHAR pattern[MAX_TCHAR_PATH];
//
// Enumerate the environment variables DelReg* and DelFile*,
// then enumerate all physical objects represented by the
// pattern, and finally, mark the objects with delete operations.
//
u = 1;
for (;;) {
wsprintf (string, TEXT("DelReg%u"), u);
u++;
if (IsmGetEnvironmentString (
PLATFORM_SOURCE,
NULL,
string,
pattern,
ARRAYSIZE(pattern),
NULL
)) {
if (!pExecuteDeleteEnum (g_RegType, (MIG_OBJECTSTRINGHANDLE) pattern)) {
return FALSE;
}
} else {
break;
}
}
u = 1;
for (;;) {
wsprintf (string, TEXT("DelFile%u"), u);
u++;
if (IsmGetEnvironmentString (
PLATFORM_SOURCE,
NULL,
string,
pattern,
ARRAYSIZE(pattern),
NULL
)) {
if (!pExecuteDeleteEnum (g_FileType, (MIG_OBJECTSTRINGHANDLE) pattern)) {
return FALSE;
}
} else {
break;
}
}
pExecuteFixFilename ();
return TRUE;
}