/*++ 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: --*/ // // 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, §PerClust, &bytesPerSect, &freeClusters, &totalClusters)) { driveInfo.BytesPerCluster = bytesPerSect * sectPerClust; if (!driveInfo.BytesPerCluster) { driveInfo.BytesPerCluster = 1; } } } } else { if (GetDiskFreeSpace (drive, §PerClust, &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; }