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.

1130 lines
32 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. csm.c
  5. Abstract:
  6. Implements the existing state analyze portion of the v1 module.
  7. The existing state module enumerates everything in the environment
  8. variables DelReg* and DelFile* (where * is a one-based number),
  9. and then sets the delete operation on everything that matches.
  10. Author:
  11. Jim Schmidt (jimschm) 21-Mar-2000
  12. Revision History:
  13. <alias> <date> <comments>
  14. --*/
  15. //
  16. // Includes
  17. //
  18. #include "pch.h"
  19. #include "v1p.h"
  20. #define DBG_V1 "v1"
  21. //
  22. // Strings
  23. //
  24. // None
  25. //
  26. // Constants
  27. //
  28. #define NORMAL_DRIVE_BUFFER_BYTES 50000000
  29. #define SYSTEM_DRIVE_BUFFER_BYTES (NORMAL_DRIVE_BUFFER_BYTES + 50000000)
  30. #define MAX_CONTENT_CHECK 0x100000
  31. //
  32. // Macros
  33. //
  34. // None
  35. //
  36. // Types
  37. //
  38. typedef struct {
  39. ULARGE_INTEGER FreeSpace;
  40. DWORD BytesPerCluster;
  41. } DRIVE_INFO, *PDRIVE_INFO;
  42. //
  43. // Globals
  44. //
  45. MIG_OPERATIONID g_DeleteOp;
  46. MIG_OPERATIONID g_PartMoveOp;
  47. HASHTABLE g_PartitionSpaceTable;
  48. HASHTABLE g_PartitionMatchTable;
  49. HASHTABLE g_CollisionSrcTable;
  50. HASHTABLE g_CollisionDestTable;
  51. PMHANDLE g_UntrackedCsmPool;
  52. TCHAR g_SystemDrive[_MAX_DRIVE + 1];
  53. //
  54. // Macro expansion list
  55. //
  56. // None
  57. //
  58. // Private function prototypes
  59. //
  60. CSMINITIALIZE ScriptCsmInitialize;
  61. CSMEXECUTE ScriptCsmExecute;
  62. //
  63. // Macro expansion definition
  64. //
  65. // None
  66. //
  67. // Code
  68. //
  69. VOID
  70. pPopulatePartitionTable (
  71. VOID
  72. )
  73. {
  74. PCTSTR drive;
  75. DRIVE_INFO driveInfo;
  76. ULARGE_INTEGER whoCares;
  77. PTSTR driveList = NULL;
  78. DWORD driveListLen;
  79. DWORD sectPerClust, bytesPerSect, freeClusters, totalClusters;
  80. FARPROC pGetDiskFreeSpaceEx;
  81. BOOL validDrive;
  82. if (!GetEnvironmentVariable (TEXT("SYSTEMDRIVE"), g_SystemDrive, _MAX_DRIVE)) {
  83. StringCopyTcharCount (g_SystemDrive, TEXT("C:"), _MAX_DRIVE);
  84. }
  85. driveListLen = GetLogicalDriveStrings (0, driveList);
  86. driveList = AllocText (driveListLen + 1);
  87. if (!driveList) {
  88. return;
  89. }
  90. GetLogicalDriveStrings (driveListLen, driveList);
  91. drive = driveList;
  92. // Find out if GetDiskFreeSpaceEx is supported
  93. #ifdef UNICODE
  94. pGetDiskFreeSpaceEx = GetProcAddress (GetModuleHandle (TEXT("kernel32.dll")), "GetDiskFreeSpaceExW");
  95. #else
  96. pGetDiskFreeSpaceEx = GetProcAddress (GetModuleHandle (TEXT("kernel32.dll")), "GetDiskFreeSpaceExA");
  97. #endif
  98. while (*drive) {
  99. validDrive = FALSE;
  100. if (GetDriveType (drive) == DRIVE_FIXED) {
  101. ZeroMemory (&driveInfo, sizeof (DRIVE_INFO));
  102. if (pGetDiskFreeSpaceEx) {
  103. if (pGetDiskFreeSpaceEx (drive, &driveInfo.FreeSpace, &whoCares, &whoCares)) {
  104. validDrive = TRUE;
  105. if (GetDiskFreeSpace (drive, &sectPerClust, &bytesPerSect, &freeClusters, &totalClusters)) {
  106. driveInfo.BytesPerCluster = bytesPerSect * sectPerClust;
  107. if (!driveInfo.BytesPerCluster) {
  108. driveInfo.BytesPerCluster = 1;
  109. }
  110. }
  111. }
  112. } else {
  113. if (GetDiskFreeSpace (drive, &sectPerClust, &bytesPerSect, &freeClusters, &totalClusters)) {
  114. driveInfo.FreeSpace.QuadPart = Int32x32To64 ((sectPerClust * bytesPerSect), freeClusters);
  115. driveInfo.BytesPerCluster = bytesPerSect * sectPerClust;
  116. if (!driveInfo.BytesPerCluster) {
  117. driveInfo.BytesPerCluster = 1;
  118. }
  119. validDrive = TRUE;
  120. }
  121. }
  122. }
  123. if (validDrive) {
  124. HtAddStringEx (g_PartitionSpaceTable, drive, &driveInfo, FALSE);
  125. }
  126. // Advance to the next drive in the drive list
  127. drive = _tcschr (drive, 0) + 1;
  128. }
  129. FreeText (driveList);
  130. }
  131. BOOL
  132. pIsSystemDrive (
  133. IN PCTSTR Drive
  134. )
  135. {
  136. if (StringIMatchCharCount (g_SystemDrive, Drive, 2)) {
  137. return TRUE;
  138. }
  139. return FALSE;
  140. }
  141. BOOL
  142. pReserveDiskSpace (
  143. IN PCTSTR DestDrive,
  144. IN ULARGE_INTEGER FileSize,
  145. IN BOOL IgnoreBuffer
  146. )
  147. {
  148. DRIVE_INFO driveInfo;
  149. ULARGE_INTEGER buffer;
  150. HASHITEM hashItem;
  151. BOOL success = FALSE;
  152. hashItem = HtFindStringEx (g_PartitionSpaceTable, DestDrive, &driveInfo, FALSE);
  153. if (hashItem) {
  154. // let's transform the FileSize so it is alligned to BytesPerCluster
  155. FileSize.QuadPart = ((FileSize.QuadPart + driveInfo.BytesPerCluster - 1) / driveInfo.BytesPerCluster) * driveInfo.BytesPerCluster;
  156. if (IgnoreBuffer) {
  157. if (pIsSystemDrive (DestDrive)) {
  158. buffer.QuadPart = NORMAL_DRIVE_BUFFER_BYTES;
  159. } else {
  160. buffer.QuadPart = 0;
  161. }
  162. } else {
  163. if (pIsSystemDrive (DestDrive)) {
  164. buffer.QuadPart = SYSTEM_DRIVE_BUFFER_BYTES;
  165. } else {
  166. buffer.QuadPart = NORMAL_DRIVE_BUFFER_BYTES;
  167. }
  168. }
  169. // Check for available space
  170. if (driveInfo.FreeSpace.QuadPart > buffer.QuadPart &&
  171. FileSize.QuadPart < driveInfo.FreeSpace.QuadPart - buffer.QuadPart) {
  172. // Subtract claimed disk space
  173. driveInfo.FreeSpace.QuadPart -= FileSize.QuadPart;
  174. HtSetStringData (g_PartitionSpaceTable, hashItem, &driveInfo);
  175. success = TRUE;
  176. }
  177. }
  178. return success;
  179. }
  180. BOOL
  181. pValidatePartition (
  182. IN MIG_OBJECTSTRINGHANDLE CurrentObjectName,
  183. IN PCTSTR Destination
  184. )
  185. {
  186. MIG_CONTENT srcContent;
  187. PWIN32_FIND_DATAW findData;
  188. TCHAR tmpDrive[_MAX_DRIVE + 1];
  189. ULARGE_INTEGER fileSize;
  190. UINT driveType;
  191. PTSTR fullDest;
  192. fullDest = DuplicatePathString (Destination, 1);
  193. AppendWack (fullDest);
  194. // Check with full Destination path for cases of UNC paths
  195. driveType = GetDriveType (fullDest);
  196. if (driveType == DRIVE_NO_ROOT_DIR) {
  197. // It thinks there is nothing mounted at that destination. If the destination
  198. // looks like G:\files1 then it will give this error when G: is a valid mapped
  199. // drive. So we'll check one more time with just "G:\"
  200. fullDest[3] = 0;
  201. driveType = GetDriveType (fullDest);
  202. }
  203. FreePathString (fullDest);
  204. if (driveType == DRIVE_REMOTE ||
  205. (Destination[0] == TEXT('\\') && Destination[1] == TEXT('\\'))
  206. ) {
  207. return TRUE;
  208. }
  209. if (driveType == DRIVE_FIXED) {
  210. // Acquire the object to get the filesize
  211. if (IsmAcquireObjectEx (
  212. g_FileType | PLATFORM_SOURCE,
  213. CurrentObjectName,
  214. &srcContent,
  215. CONTENTTYPE_DETAILS_ONLY,
  216. 0
  217. )) {
  218. // Check to see if the desired destination has space
  219. findData = (PWIN32_FIND_DATAW)srcContent.Details.DetailsData;
  220. fileSize.LowPart = findData->nFileSizeLow;
  221. fileSize.HighPart = findData->nFileSizeHigh;
  222. tmpDrive[0] = Destination[0];
  223. tmpDrive[1] = Destination[1];
  224. tmpDrive[2] = TEXT('\\');
  225. tmpDrive[3] = 0;
  226. IsmReleaseObject (&srcContent);
  227. return (pReserveDiskSpace (tmpDrive, fileSize, FALSE));
  228. }
  229. }
  230. // Not a Fixed drive or Remote drive, so it's not a valid destination
  231. return FALSE;
  232. }
  233. BOOL
  234. pFindValidPartition (
  235. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  236. IN OUT PTSTR DestNode,
  237. IN BOOL IgnoreBuffer // must be FALSE except when called by itself
  238. )
  239. {
  240. MIG_CONTENT srcContent;
  241. PWIN32_FIND_DATAW findData;
  242. PTSTR drivePtr;
  243. ULARGE_INTEGER fileSize;
  244. TCHAR tmpDrive[_MAX_DRIVE + 1];
  245. BOOL newDestFound = FALSE;
  246. PTSTR driveList = NULL;
  247. DWORD driveListLen;
  248. TCHAR destDrive;
  249. BOOL destChanged = FALSE;
  250. PCTSTR oldDestNode;
  251. BOOL result = TRUE;
  252. oldDestNode = DuplicatePathString (DestNode, 0);
  253. if (IsmAcquireObjectEx (
  254. g_FileType | PLATFORM_SOURCE,
  255. ObjectName,
  256. &srcContent,
  257. CONTENTTYPE_DETAILS_ONLY,
  258. 0
  259. )) {
  260. // First check to see if we already matched up this file
  261. if (HtFindStringEx (g_PartitionMatchTable, ObjectName, &destDrive, FALSE)) {
  262. DestNode[0] = destDrive;
  263. } else {
  264. // Need a new destination for this file
  265. destChanged = TRUE;
  266. findData = (PWIN32_FIND_DATAW)srcContent.Details.DetailsData;
  267. fileSize.LowPart = findData->nFileSizeLow;
  268. fileSize.HighPart = findData->nFileSizeHigh;
  269. if (GetEnvironmentVariable (TEXT("SYSTEMDRIVE"), tmpDrive, _MAX_DRIVE)) {
  270. AppendWack (tmpDrive);
  271. if (pReserveDiskSpace (tmpDrive, fileSize, IgnoreBuffer)) {
  272. newDestFound = TRUE;
  273. DestNode[0] = tmpDrive[0];
  274. }
  275. }
  276. if (newDestFound == FALSE) {
  277. // Check drives in alphabetical order
  278. driveListLen = GetLogicalDriveStrings (0, driveList);
  279. driveList = AllocText (driveListLen + 1);
  280. GetLogicalDriveStrings (driveListLen, driveList);
  281. drivePtr = driveList;
  282. while (*drivePtr) {
  283. if (pReserveDiskSpace (drivePtr, fileSize, IgnoreBuffer)) {
  284. DestNode[0] = drivePtr[0];
  285. newDestFound = TRUE;
  286. break;
  287. }
  288. // Advance to the next drive in the drive list
  289. drivePtr = _tcschr (drivePtr, 0) + 1;
  290. }
  291. FreeText (driveList);
  292. }
  293. if (newDestFound == FALSE) {
  294. if (IgnoreBuffer == FALSE) {
  295. // We couldn't find space. Look again, but override the buffer space
  296. // NTRAID#NTBUG9-153274-2000/08/01-jimschm It will currently fill up the system drive first, which is not what we should do.
  297. result = pFindValidPartition (ObjectName, DestNode, TRUE);
  298. } else {
  299. // Okay it's hopeless. Keep track of how badly we're out of space
  300. LOG ((
  301. LOG_ERROR,
  302. (PCSTR) MSG_PARTMAP_DISKFULL,
  303. IsmGetNativeObjectName (g_FileType, ObjectName)
  304. ));
  305. result = FALSE;
  306. }
  307. } else {
  308. if (destChanged == TRUE) {
  309. LOG ((
  310. LOG_WARNING,
  311. (PCSTR) MSG_PARTMAP_FORCED_REMAP,
  312. IsmGetNativeObjectName (g_FileType, ObjectName),
  313. oldDestNode,
  314. DestNode
  315. ));
  316. }
  317. }
  318. }
  319. IsmReleaseObject (&srcContent);
  320. }
  321. FreePathString (oldDestNode);
  322. return result;
  323. }
  324. BOOL
  325. WINAPI
  326. ScriptCsmInitialize (
  327. IN PMIG_LOGCALLBACK LogCallback,
  328. IN PVOID Reserved
  329. )
  330. {
  331. //
  332. // Get file and registry types
  333. //
  334. g_FileType = MIG_FILE_TYPE;
  335. g_RegType = MIG_REGISTRY_TYPE;
  336. //
  337. // Get operation types
  338. //
  339. g_DeleteOp = IsmRegisterOperation (S_OPERATION_DELETE, FALSE);
  340. g_PartMoveOp = IsmRegisterOperation (S_OPERATION_PARTITION_MOVE, TRUE);
  341. g_LockPartitionAttr = IsmRegisterAttribute (S_ATTRIBUTE_PARTITIONLOCK, FALSE);
  342. g_CollisionSrcTable = HtAllocWithData (sizeof (HASHITEM));
  343. g_CollisionDestTable = HtAllocWithData (sizeof (MIG_OBJECTSTRINGHANDLE));
  344. g_PartitionSpaceTable = HtAllocWithData (sizeof (DRIVE_INFO));
  345. g_PartitionMatchTable = HtAllocWithData (sizeof (TCHAR));
  346. pPopulatePartitionTable ();
  347. g_UntrackedCsmPool = PmCreatePool ();
  348. PmDisableTracking (g_UntrackedCsmPool);
  349. OE5RemapDefaultId();
  350. return TRUE;
  351. }
  352. VOID
  353. WINAPI
  354. ScriptCsmTerminate (
  355. VOID
  356. )
  357. {
  358. HtFree (g_CollisionSrcTable);
  359. g_CollisionSrcTable = NULL;
  360. HtFree (g_CollisionDestTable);
  361. g_CollisionDestTable = NULL;
  362. HtFree (g_PartitionSpaceTable);
  363. g_PartitionSpaceTable = NULL;
  364. HtFree (g_PartitionMatchTable);
  365. g_PartitionMatchTable = NULL;
  366. PmDestroyPool (g_UntrackedCsmPool);
  367. g_UntrackedCsmPool = NULL;
  368. }
  369. BOOL
  370. pExecuteDeleteEnum (
  371. IN MIG_OBJECTTYPEID ObjectTypeId,
  372. IN MIG_OBJECTSTRINGHANDLE Pattern
  373. )
  374. {
  375. MIG_OBJECT_ENUM e;
  376. BOOL b = TRUE;
  377. if (IsmEnumFirstDestinationObject (&e, ObjectTypeId, Pattern)) {
  378. do {
  379. b = IsmSetOperationOnObject (
  380. e.ObjectTypeId,
  381. e.ObjectName,
  382. g_DeleteOp,
  383. NULL,
  384. NULL
  385. );
  386. if (!b) {
  387. IsmAbortObjectEnum (&e);
  388. break;
  389. }
  390. } while (IsmEnumNextObject (&e));
  391. }
  392. return b;
  393. }
  394. BOOL
  395. pCompareFiles (
  396. IN PCTSTR File1,
  397. IN PCTSTR File2
  398. )
  399. {
  400. HANDLE fileHandle1 = NULL;
  401. HANDLE fileHandle2 = NULL;
  402. #define BUFFER_SIZE 4096
  403. BYTE buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
  404. BOOL result = FALSE;
  405. BOOL res1, res2;
  406. DWORD read1, read2;
  407. __try {
  408. fileHandle1 = BfOpenReadFile (File1);
  409. fileHandle2 = BfOpenReadFile (File2);
  410. if (fileHandle1 && fileHandle2) {
  411. while (TRUE) {
  412. if (IsmCheckCancel ()) {
  413. result = FALSE;
  414. break;
  415. }
  416. res1 = ReadFile (fileHandle1, buffer1, BUFFER_SIZE, &read1, NULL);
  417. res2 = ReadFile (fileHandle2, buffer2, BUFFER_SIZE, &read2, NULL);
  418. if (!res1 && !res2) {
  419. result = TRUE;
  420. break;
  421. }
  422. if (res1 && res2) {
  423. if (read1 != read2) {
  424. break;
  425. }
  426. if (read1 == 0) {
  427. result = TRUE;
  428. break;
  429. }
  430. if (!TestBuffer (buffer1, buffer2, read1)) {
  431. break;
  432. }
  433. } else {
  434. break;
  435. }
  436. }
  437. }
  438. }
  439. __finally {
  440. if (fileHandle1) {
  441. CloseHandle (fileHandle1);
  442. fileHandle1 = NULL;
  443. }
  444. if (fileHandle2) {
  445. CloseHandle (fileHandle2);
  446. fileHandle2 = NULL;
  447. }
  448. }
  449. return result;
  450. }
  451. BOOL
  452. pContentMatch (
  453. IN PMIG_CONTENT SrcContent,
  454. IN PMIG_CONTENT DestContent,
  455. OUT PBOOL DifferentDetailsOnly
  456. )
  457. {
  458. UINT index;
  459. PWIN32_FIND_DATAW find1, find2;
  460. BOOL result = FALSE;
  461. PUBINT src;
  462. PUBINT dest;
  463. UINT remainder;
  464. UINT count;
  465. DWORD allAttribs;
  466. DWORD extendedAttribs;
  467. *DifferentDetailsOnly = FALSE;
  468. if (SrcContent->Details.DetailsSize != DestContent->Details.DetailsSize) {
  469. return FALSE;
  470. }
  471. if (!SrcContent->Details.DetailsData || !DestContent->Details.DetailsData) {
  472. return FALSE;
  473. }
  474. find1 = (PWIN32_FIND_DATAW)SrcContent->Details.DetailsData;
  475. find2 = (PWIN32_FIND_DATAW)DestContent->Details.DetailsData;
  476. if (find1->nFileSizeHigh != find2->nFileSizeHigh) {
  477. return FALSE;
  478. }
  479. if (find1->nFileSizeLow != find2->nFileSizeLow) {
  480. return FALSE;
  481. }
  482. if (SrcContent->ContentInFile && DestContent->ContentInFile) {
  483. result = pCompareFiles (SrcContent->FileContent.ContentPath, DestContent->FileContent.ContentPath);
  484. }
  485. if (!SrcContent->ContentInFile && !DestContent->ContentInFile) {
  486. if (SrcContent->MemoryContent.ContentSize != DestContent->MemoryContent.ContentSize) {
  487. return FALSE;
  488. }
  489. if ((!SrcContent->MemoryContent.ContentBytes && DestContent->MemoryContent.ContentBytes) ||
  490. (SrcContent->MemoryContent.ContentBytes && !DestContent->MemoryContent.ContentBytes)
  491. ) {
  492. return FALSE;
  493. }
  494. //
  495. // Compare the content using the largest unsigned int available, then
  496. // compare any remaining bytes
  497. //
  498. index = 0;
  499. count = SrcContent->MemoryContent.ContentSize / sizeof (UBINT);
  500. remainder = SrcContent->MemoryContent.ContentSize % sizeof (UBINT);
  501. src = (PUBINT) SrcContent->MemoryContent.ContentBytes;
  502. dest = (PUBINT) DestContent->MemoryContent.ContentBytes;
  503. while (count) {
  504. if (*src++ != *dest++) {
  505. DEBUGMSG ((DBG_WARNING, "Content mismatch because UBINTs differ"));
  506. return FALSE;
  507. }
  508. count--;
  509. }
  510. for (index = 0 ; index < remainder ; index++) {
  511. if (((PBYTE) src)[index] != ((PBYTE) dest)[index]) {
  512. DEBUGMSG ((DBG_WARNING, "Content mismatch because bytes differ"));
  513. return FALSE;
  514. }
  515. }
  516. result = TRUE;
  517. }
  518. if (!result) {
  519. return FALSE;
  520. }
  521. //
  522. // At this point the files are the same. Now if the attributes are different, return
  523. // FALSE indicating that only the details differ.
  524. //
  525. *DifferentDetailsOnly = TRUE;
  526. if (find1->dwFileAttributes != find2->dwFileAttributes) {
  527. return FALSE;
  528. }
  529. if (find1->ftLastWriteTime.dwLowDateTime != find2->ftLastWriteTime.dwLowDateTime) {
  530. return FALSE;
  531. }
  532. if (find1->ftLastWriteTime.dwHighDateTime != find2->ftLastWriteTime.dwHighDateTime) {
  533. return FALSE;
  534. }
  535. *DifferentDetailsOnly = FALSE;
  536. return TRUE;
  537. }
  538. BOOL
  539. pDoesDifferentFileExist (
  540. IN MIG_OBJECTSTRINGHANDLE SrcName,
  541. IN MIG_OBJECTSTRINGHANDLE DestName,
  542. IN PCTSTR DestNativeName,
  543. OUT PBOOL DifferentDetailsOnly
  544. )
  545. {
  546. MIG_CONTENT srcContent;
  547. MIG_CONTENT destContent;
  548. WIN32_FIND_DATA findData;
  549. BOOL result = FALSE;
  550. if (!DoesFileExistEx (DestNativeName, &findData)) {
  551. return FALSE;
  552. }
  553. if (findData.nFileSizeHigh) {
  554. return TRUE;
  555. }
  556. if (IsmAcquireObject (
  557. g_FileType | PLATFORM_DESTINATION,
  558. DestName,
  559. &destContent
  560. )) {
  561. result = TRUE;
  562. if (IsmAcquireObject (
  563. g_FileType | PLATFORM_SOURCE,
  564. SrcName,
  565. &srcContent
  566. )) {
  567. result = !pContentMatch (&srcContent, &destContent, DifferentDetailsOnly);
  568. IsmReleaseObject (&srcContent);
  569. }
  570. IsmReleaseObject (&destContent);
  571. } else {
  572. result = DoesFileExist (DestNativeName);
  573. }
  574. return result;
  575. }
  576. BOOL
  577. pIsFileDestCollision (
  578. IN MIG_OBJECTSTRINGHANDLE CurrentObjectName,
  579. IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
  580. IN PCTSTR CurrentNativeName,
  581. IN BOOL CompareDestFiles,
  582. IN BOOL *OnlyDetailsDiffer
  583. )
  584. {
  585. if (HtFindString (g_CollisionDestTable, CurrentObjectName)) {
  586. return TRUE;
  587. }
  588. if (CompareDestFiles &&
  589. pDoesDifferentFileExist (OriginalObjectName,
  590. CurrentObjectName,
  591. CurrentNativeName,
  592. OnlyDetailsDiffer)) {
  593. if (*OnlyDetailsDiffer == FALSE) {
  594. return TRUE;
  595. }
  596. }
  597. return FALSE;
  598. }
  599. MIG_OBJECTSTRINGHANDLE
  600. pCollideFile (
  601. IN MIG_OBJECTID OriginalObjectId,
  602. IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
  603. IN PCTSTR NewNode,
  604. IN PCTSTR NewLeaf,
  605. IN BOOL CompareDestFiles
  606. )
  607. {
  608. MIG_OBJECTSTRINGHANDLE result = NULL;
  609. HASHITEM hashItem;
  610. PCTSTR testNativeName;
  611. PCTSTR leafExt = NULL;
  612. TCHAR buff[MAX_TCHAR_PATH * 2];
  613. PTSTR openParen = NULL;
  614. PTSTR closeParen = NULL;
  615. PTSTR tmpLeaf = NULL;
  616. PTSTR testLeaf = NULL;
  617. PTSTR chr;
  618. BOOL onlyDetailsDiffer = FALSE;
  619. BOOL replaceOk = TRUE;
  620. UINT fileIndex = 0;
  621. MIG_PROPERTYDATAID propDataId;
  622. BOOL specialPattern = FALSE;
  623. PTSTR fileCollPattern = NULL;
  624. MIG_BLOBTYPE propDataType;
  625. UINT requiredSize;
  626. if (!HtFindStringEx (g_CollisionSrcTable, OriginalObjectName, (PVOID)(&hashItem), FALSE)) {
  627. // we don't have a spot just yet. Let's make one.
  628. result = IsmCreateObjectHandle (NewNode, NewLeaf);
  629. testNativeName = JoinPaths (NewNode, NewLeaf);
  630. if (pIsFileDestCollision(result,
  631. OriginalObjectName,
  632. testNativeName,
  633. CompareDestFiles,
  634. &onlyDetailsDiffer)) {
  635. tmpLeaf = AllocText (TcharCount (NewLeaf) + 1);
  636. leafExt = _tcsrchr (NewLeaf, TEXT('.'));
  637. if (leafExt) {
  638. StringCopyAB (tmpLeaf, NewLeaf, leafExt);
  639. leafExt = _tcsinc (leafExt);
  640. } else {
  641. StringCopy (tmpLeaf, NewLeaf);
  642. }
  643. // Let's check if we wanted some special pattern for this file
  644. propDataId = IsmGetPropertyFromObjectId (OriginalObjectId, g_FileCollPatternData);
  645. if (propDataId) {
  646. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  647. if (propDataType == BLOBTYPE_STRING) {
  648. fileCollPattern = IsmGetMemory (requiredSize);
  649. if (fileCollPattern) {
  650. if (IsmGetPropertyData (
  651. propDataId,
  652. (PBYTE)fileCollPattern,
  653. requiredSize,
  654. NULL,
  655. &propDataType)) {
  656. specialPattern = TRUE;
  657. }
  658. if (!specialPattern) {
  659. IsmReleaseMemory (fileCollPattern);
  660. fileCollPattern = NULL;
  661. }
  662. }
  663. }
  664. }
  665. }
  666. if (specialPattern) {
  667. //
  668. // Loop until we find a non-colliding destination, or a colliding
  669. // dest that differs only by attributes
  670. //
  671. do {
  672. FreePathString (testNativeName);
  673. IsmDestroyObjectHandle (result);
  674. fileIndex ++;
  675. wsprintf (buff, fileCollPattern, tmpLeaf, fileIndex, leafExt?leafExt:TEXT(""));
  676. result = IsmCreateObjectHandle (NewNode, buff);
  677. testNativeName = JoinPaths (NewNode, buff);
  678. } while (fileIndex && pIsFileDestCollision(
  679. result,
  680. OriginalObjectName,
  681. testNativeName,
  682. CompareDestFiles,
  683. &onlyDetailsDiffer));
  684. if (fileCollPattern) {
  685. IsmReleaseMemory (fileCollPattern);
  686. fileCollPattern = NULL;
  687. }
  688. if (!fileIndex) {
  689. // The collision pattern was bogus and we looped until
  690. // we ran out of indexes. Let's go with the default
  691. // collision mechanism.
  692. specialPattern = FALSE;
  693. }
  694. }
  695. if (!specialPattern) {
  696. // Check if the filename already has a (number) tacked on
  697. openParen = _tcsrchr (tmpLeaf, TEXT('('));
  698. closeParen = _tcsrchr (tmpLeaf, TEXT(')'));
  699. if (closeParen && openParen &&
  700. closeParen > openParen &&
  701. closeParen - openParen > 1) {
  702. // Make sure it's purely numerical
  703. for (chr = openParen+1; chr < closeParen; chr++) {
  704. if (!_istdigit (*chr)) {
  705. replaceOk = FALSE;
  706. break;
  707. }
  708. }
  709. if (replaceOk == TRUE) {
  710. if (_stscanf (openParen, TEXT("(%d)"), &fileIndex)) {
  711. *openParen = 0;
  712. }
  713. }
  714. }
  715. //
  716. // Loop until we find a non-colliding destination, or a colliding
  717. // dest that differs only by attributes
  718. //
  719. do {
  720. FreePathString (testNativeName);
  721. IsmDestroyObjectHandle (result);
  722. FreeText (testLeaf);
  723. fileIndex ++;
  724. wsprintf (buff, TEXT("(%d)"), fileIndex);
  725. testLeaf = AllocText (TcharCount (tmpLeaf) + TcharCount (buff) + 1);
  726. StringCopy (testLeaf, tmpLeaf);
  727. StringCat (testLeaf, buff);
  728. if (leafExt) {
  729. StringCat (testLeaf, TEXT("."));
  730. StringCat (testLeaf, leafExt);
  731. }
  732. result = IsmCreateObjectHandle (NewNode, testLeaf);
  733. testNativeName = JoinPaths (NewNode, testLeaf);
  734. } while (pIsFileDestCollision(result,
  735. OriginalObjectName,
  736. testNativeName,
  737. CompareDestFiles,
  738. &onlyDetailsDiffer));
  739. }
  740. FreeText (tmpLeaf);
  741. }
  742. if (onlyDetailsDiffer) {
  743. IsmAbandonObjectOnCollision (g_FileType | PLATFORM_DESTINATION, OriginalObjectName);
  744. }
  745. FreePathString (testNativeName);
  746. FreeText (testLeaf);
  747. //
  748. // Put new destination in the hash table and store the Ism handle, which will
  749. // be cleaned up at the end.
  750. //
  751. hashItem = HtAddStringEx (g_CollisionDestTable, result, &result, FALSE);
  752. HtAddStringEx (g_CollisionSrcTable, OriginalObjectName, &hashItem, FALSE);
  753. } else {
  754. //
  755. // Get the already computed collision destination.
  756. //
  757. HtCopyStringData (g_CollisionDestTable, hashItem, (PVOID)(&result));
  758. }
  759. return result;
  760. }
  761. MIG_OBJECTSTRINGHANDLE
  762. pCollisionGetDestination (
  763. IN MIG_OBJECTID OriginalObjectId,
  764. IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
  765. IN PCTSTR NewNode,
  766. IN PCTSTR NewLeaf
  767. )
  768. {
  769. MIG_OBJECTSTRINGHANDLE result = NULL;
  770. BOOL onlyDetailsDiffer = FALSE;
  771. // now we have the destination node. If this is actually a file
  772. // we need to check for collisions. For this we look if the
  773. // destination already has a file like this. After that we use
  774. // a table to reserve ourselves a spot.
  775. if (NewLeaf) {
  776. if (IsmIsObjectAbandonedOnCollision (g_FileType | PLATFORM_DESTINATION, OriginalObjectName)) {
  777. // we don't care about existing files on the destination machine.
  778. // However, some files that we just copy may collide with each other
  779. // so we have to check that.
  780. result = pCollideFile (OriginalObjectId, OriginalObjectName, NewNode, NewLeaf, FALSE);
  781. } else if (IsmIsObjectAbandonedOnCollision (g_FileType | PLATFORM_SOURCE, OriginalObjectName)) {
  782. // this will potentially collide with an existent file but then the source file
  783. // would not survive.
  784. result = IsmCreateObjectHandle (NewNode, NewLeaf);
  785. } else {
  786. result = pCollideFile (OriginalObjectId, OriginalObjectName, NewNode, NewLeaf, TRUE);
  787. }
  788. } else {
  789. result = IsmCreateObjectHandle (NewNode, NULL);
  790. }
  791. return result;
  792. }
  793. BOOL
  794. pExecuteFixFilename (
  795. VOID
  796. )
  797. {
  798. UINT ticks;
  799. MIG_OBJECT_ENUM objectEnum;
  800. MIG_OBJECTSTRINGHANDLE enumPattern;
  801. MIG_PROGRESSSLICEID sliceId;
  802. PCTSTR destination = NULL;
  803. MIG_OBJECTSTRINGHANDLE destFilename;
  804. PTSTR node = NULL;
  805. PCTSTR leaf = NULL;
  806. MIG_BLOB opData;
  807. PMIG_OBJECTCOUNT objectCount;
  808. BOOL deleted;
  809. objectCount = IsmGetObjectsStatistics (g_FileType | PLATFORM_SOURCE);
  810. if (objectCount) {
  811. ticks = objectCount->TotalObjects;
  812. } else {
  813. ticks = 0;
  814. }
  815. sliceId = IsmRegisterProgressSlice (ticks, max (1, ticks / 5));
  816. // Enum source file objects
  817. enumPattern = IsmCreateSimpleObjectPattern (NULL, TRUE, NULL, TRUE); // *,*
  818. if (IsmEnumFirstSourceObject (&objectEnum, g_FileType, enumPattern)) {
  819. do {
  820. // Check if Apply
  821. if (IsmIsApplyObjectId (objectEnum.ObjectId)) {
  822. // Macro expansion, rule processing, etc
  823. destination = IsmFilterObject (objectEnum.ObjectTypeId,
  824. objectEnum.ObjectName,
  825. NULL,
  826. &deleted,
  827. NULL);
  828. if (deleted) {
  829. continue;
  830. }
  831. if (!destination) {
  832. destination = objectEnum.ObjectName;
  833. }
  834. IsmCreateObjectStringsFromHandle (destination, &node, &leaf);
  835. if (node && _tcslen (node) >= 2) {
  836. if (IsValidFileSpec (node)) {
  837. if (!pValidatePartition (objectEnum.ObjectName, node)) {
  838. if (!IsmIsAttributeSetOnObjectId (objectEnum.ObjectId, g_LockPartitionAttr)) {
  839. // Pick a new destination partition
  840. pFindValidPartition (objectEnum.ObjectName, node, FALSE);
  841. }
  842. }
  843. }
  844. }
  845. // We have selected a new partition, so now check for file collisions
  846. destFilename = pCollisionGetDestination (
  847. objectEnum.ObjectId,
  848. objectEnum.ObjectName,
  849. node,
  850. leaf
  851. );
  852. if (node) {
  853. IsmDestroyObjectString (node);
  854. node = NULL;
  855. }
  856. if (leaf) {
  857. IsmDestroyObjectString (leaf);
  858. leaf = NULL;
  859. }
  860. opData.Type = BLOBTYPE_STRING;
  861. opData.String = PmDuplicateString (g_UntrackedCsmPool, destFilename);
  862. IsmDestroyObjectHandle (destFilename);
  863. destFilename = NULL;
  864. // Set a custom operation that will fix the name
  865. IsmSetOperationOnObjectId (
  866. objectEnum.ObjectId,
  867. g_PartMoveOp,
  868. (MIG_DATAHANDLE) 0,
  869. &opData
  870. );
  871. if (!IsmTickProgressBar (sliceId, 1)) {
  872. IsmAbortObjectEnum (&objectEnum);
  873. break;
  874. }
  875. if (destination != objectEnum.ObjectName) {
  876. IsmDestroyObjectHandle (destination);
  877. }
  878. }
  879. } while (IsmEnumNextObject (&objectEnum));
  880. }
  881. IsmDestroyObjectHandle (enumPattern);
  882. INVALID_POINTER (enumPattern);
  883. return TRUE;
  884. }
  885. BOOL
  886. WINAPI
  887. ScriptCsmExecute (
  888. VOID
  889. )
  890. {
  891. UINT u;
  892. TCHAR string[32];
  893. TCHAR pattern[MAX_TCHAR_PATH];
  894. //
  895. // Enumerate the environment variables DelReg* and DelFile*,
  896. // then enumerate all physical objects represented by the
  897. // pattern, and finally, mark the objects with delete operations.
  898. //
  899. u = 1;
  900. for (;;) {
  901. wsprintf (string, TEXT("DelReg%u"), u);
  902. u++;
  903. if (IsmGetEnvironmentString (
  904. PLATFORM_SOURCE,
  905. NULL,
  906. string,
  907. pattern,
  908. ARRAYSIZE(pattern),
  909. NULL
  910. )) {
  911. if (!pExecuteDeleteEnum (g_RegType, (MIG_OBJECTSTRINGHANDLE) pattern)) {
  912. return FALSE;
  913. }
  914. } else {
  915. break;
  916. }
  917. }
  918. u = 1;
  919. for (;;) {
  920. wsprintf (string, TEXT("DelFile%u"), u);
  921. u++;
  922. if (IsmGetEnvironmentString (
  923. PLATFORM_SOURCE,
  924. NULL,
  925. string,
  926. pattern,
  927. ARRAYSIZE(pattern),
  928. NULL
  929. )) {
  930. if (!pExecuteDeleteEnum (g_FileType, (MIG_OBJECTSTRINGHANDLE) pattern)) {
  931. return FALSE;
  932. }
  933. } else {
  934. break;
  935. }
  936. }
  937. pExecuteFixFilename ();
  938. return TRUE;
  939. }