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

  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. pCompareFiles (
  326. IN PCTSTR File1,
  327. IN PCTSTR File2
  328. )
  329. {
  330. HANDLE fileHandle1 = NULL;
  331. HANDLE fileHandle2 = NULL;
  332. #define BUFFER_SIZE 4096
  333. BYTE buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
  334. BOOL result = FALSE;
  335. BOOL res1, res2;
  336. DWORD read1, read2;
  337. __try {
  338. fileHandle1 = BfOpenReadFile (File1);
  339. fileHandle2 = BfOpenReadFile (File2);
  340. if (fileHandle1 && fileHandle2) {
  341. while (TRUE) {
  342. if (IsmCheckCancel ()) {
  343. result = FALSE;
  344. break;
  345. }
  346. res1 = ReadFile (fileHandle1, buffer1, BUFFER_SIZE, &read1, NULL);
  347. res2 = ReadFile (fileHandle2, buffer2, BUFFER_SIZE, &read2, NULL);
  348. if (!res1 && !res2) {
  349. result = TRUE;
  350. break;
  351. }
  352. if (res1 && res2) {
  353. if (read1 != read2) {
  354. break;
  355. }
  356. if (read1 == 0) {
  357. result = TRUE;
  358. break;
  359. }
  360. if (!TestBuffer (buffer1, buffer2, read1)) {
  361. break;
  362. }
  363. } else {
  364. break;
  365. }
  366. }
  367. }
  368. }
  369. __finally {
  370. if (fileHandle1) {
  371. CloseHandle (fileHandle1);
  372. fileHandle1 = NULL;
  373. }
  374. if (fileHandle2) {
  375. CloseHandle (fileHandle2);
  376. fileHandle2 = NULL;
  377. }
  378. }
  379. return result;
  380. }
  381. BOOL
  382. pDoesFileContentMatch (
  383. IN BOOL AlreadyProcessed,
  384. IN MIG_OBJECTTYPEID SrcObjectTypeId,
  385. IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
  386. IN PMIG_CONTENT SrcContent,
  387. IN MIG_OBJECTTYPEID DestObjectTypeId,
  388. IN MIG_OBJECTSTRINGHANDLE DestObjectName,
  389. IN PMIG_CONTENT DestContent,
  390. OUT PBOOL Identical,
  391. OUT PBOOL DifferentDetailsOnly
  392. )
  393. {
  394. UINT index;
  395. PWIN32_FIND_DATAW find1, find2;
  396. BOOL result = FALSE;
  397. PUBINT src;
  398. PUBINT dest;
  399. UINT remainder;
  400. UINT count;
  401. DWORD allAttribs;
  402. DWORD extendedAttribs;
  403. if (AlreadyProcessed) {
  404. return FALSE;
  405. }
  406. if ((SrcObjectTypeId != MIG_FILE_TYPE) ||
  407. (DestObjectTypeId != MIG_FILE_TYPE)
  408. ) {
  409. return FALSE;
  410. }
  411. if (DifferentDetailsOnly) {
  412. *DifferentDetailsOnly = FALSE;
  413. }
  414. if (SrcContent->Details.DetailsSize != DestContent->Details.DetailsSize) {
  415. if (Identical) {
  416. Identical = FALSE;
  417. }
  418. return TRUE;
  419. }
  420. if (!SrcContent->Details.DetailsData || !DestContent->Details.DetailsData) {
  421. if (Identical) {
  422. Identical = FALSE;
  423. }
  424. return TRUE;
  425. }
  426. find1 = (PWIN32_FIND_DATAW)SrcContent->Details.DetailsData;
  427. find2 = (PWIN32_FIND_DATAW)DestContent->Details.DetailsData;
  428. if (find1->nFileSizeHigh != find2->nFileSizeHigh) {
  429. if (Identical) {
  430. Identical = FALSE;
  431. }
  432. return TRUE;
  433. }
  434. if (find1->nFileSizeLow != find2->nFileSizeLow) {
  435. if (Identical) {
  436. Identical = FALSE;
  437. }
  438. return TRUE;
  439. }
  440. if (SrcContent->ContentInFile && DestContent->ContentInFile) {
  441. result = pCompareFiles (SrcContent->FileContent.ContentPath, DestContent->FileContent.ContentPath);
  442. }
  443. if (!SrcContent->ContentInFile && !DestContent->ContentInFile) {
  444. if (SrcContent->MemoryContent.ContentSize != DestContent->MemoryContent.ContentSize) {
  445. if (Identical) {
  446. Identical = FALSE;
  447. }
  448. return TRUE;
  449. }
  450. if ((!SrcContent->MemoryContent.ContentBytes && DestContent->MemoryContent.ContentBytes) ||
  451. (SrcContent->MemoryContent.ContentBytes && !DestContent->MemoryContent.ContentBytes)
  452. ) {
  453. if (Identical) {
  454. Identical = FALSE;
  455. }
  456. return TRUE;
  457. }
  458. //
  459. // Compare the content using the largest unsigned int available, then
  460. // compare any remaining bytes
  461. //
  462. index = 0;
  463. count = SrcContent->MemoryContent.ContentSize / sizeof (UBINT);
  464. remainder = SrcContent->MemoryContent.ContentSize % sizeof (UBINT);
  465. src = (PUBINT) SrcContent->MemoryContent.ContentBytes;
  466. dest = (PUBINT) DestContent->MemoryContent.ContentBytes;
  467. while (count) {
  468. if (*src++ != *dest++) {
  469. DEBUGMSG ((DBG_WARNING, "Content mismatch because UBINTs differ"));
  470. if (Identical) {
  471. Identical = FALSE;
  472. }
  473. return TRUE;
  474. }
  475. count--;
  476. }
  477. for (index = 0 ; index < remainder ; index++) {
  478. if (((PBYTE) src)[index] != ((PBYTE) dest)[index]) {
  479. DEBUGMSG ((DBG_WARNING, "Content mismatch because bytes differ"));
  480. if (Identical) {
  481. Identical = FALSE;
  482. }
  483. return TRUE;
  484. }
  485. }
  486. result = TRUE;
  487. }
  488. if (!result) {
  489. if (Identical) {
  490. Identical = FALSE;
  491. }
  492. return TRUE;
  493. }
  494. //
  495. // At this point the files are the same. Now if the attributes are different, return
  496. // FALSE indicating that only the details differ.
  497. //
  498. if (DifferentDetailsOnly) {
  499. *DifferentDetailsOnly = TRUE;
  500. }
  501. if (find1->dwFileAttributes != find2->dwFileAttributes) {
  502. if (Identical) {
  503. Identical = FALSE;
  504. }
  505. return TRUE;
  506. }
  507. if (find1->ftLastWriteTime.dwLowDateTime != find2->ftLastWriteTime.dwLowDateTime) {
  508. if (Identical) {
  509. Identical = FALSE;
  510. }
  511. return TRUE;
  512. }
  513. if (find1->ftLastWriteTime.dwHighDateTime != find2->ftLastWriteTime.dwHighDateTime) {
  514. if (Identical) {
  515. Identical = FALSE;
  516. }
  517. return TRUE;
  518. }
  519. if (DifferentDetailsOnly) {
  520. *DifferentDetailsOnly = FALSE;
  521. }
  522. if (Identical) {
  523. *Identical = TRUE;
  524. }
  525. return TRUE;
  526. }
  527. BOOL
  528. WINAPI
  529. ScriptCsmInitialize (
  530. IN PMIG_LOGCALLBACK LogCallback,
  531. IN PVOID Reserved
  532. )
  533. {
  534. //
  535. // Get file and registry types
  536. //
  537. g_FileType = MIG_FILE_TYPE;
  538. g_RegType = MIG_REGISTRY_TYPE;
  539. g_IniType = MIG_INI_TYPE;
  540. //
  541. // Get operation types
  542. //
  543. g_DeleteOp = IsmRegisterOperation (S_OPERATION_DELETE, FALSE);
  544. g_PartMoveOp = IsmRegisterOperation (S_OPERATION_PARTITION_MOVE, TRUE);
  545. g_LockPartitionAttr = IsmRegisterAttribute (S_ATTRIBUTE_PARTITIONLOCK, FALSE);
  546. g_CollisionSrcTable = HtAllocWithData (sizeof (HASHITEM));
  547. g_CollisionDestTable = HtAllocWithData (sizeof (MIG_OBJECTSTRINGHANDLE));
  548. g_PartitionSpaceTable = HtAllocWithData (sizeof (DRIVE_INFO));
  549. g_PartitionMatchTable = HtAllocWithData (sizeof (TCHAR));
  550. pPopulatePartitionTable ();
  551. g_UntrackedCsmPool = PmCreatePool ();
  552. PmDisableTracking (g_UntrackedCsmPool);
  553. OE5RemapDefaultId();
  554. IsmRegisterCompareCallback (MIG_FILE_TYPE, pDoesFileContentMatch);
  555. return TRUE;
  556. }
  557. VOID
  558. WINAPI
  559. ScriptCsmTerminate (
  560. VOID
  561. )
  562. {
  563. HtFree (g_CollisionSrcTable);
  564. g_CollisionSrcTable = NULL;
  565. HtFree (g_CollisionDestTable);
  566. g_CollisionDestTable = NULL;
  567. HtFree (g_PartitionSpaceTable);
  568. g_PartitionSpaceTable = NULL;
  569. HtFree (g_PartitionMatchTable);
  570. g_PartitionMatchTable = NULL;
  571. PmDestroyPool (g_UntrackedCsmPool);
  572. g_UntrackedCsmPool = NULL;
  573. }
  574. BOOL
  575. pExecuteDeleteEnum (
  576. IN MIG_OBJECTTYPEID ObjectTypeId,
  577. IN MIG_OBJECTSTRINGHANDLE Pattern
  578. )
  579. {
  580. MIG_OBJECT_ENUM e;
  581. BOOL b = TRUE;
  582. if (IsmEnumFirstDestinationObject (&e, ObjectTypeId, Pattern)) {
  583. do {
  584. b = IsmSetOperationOnObject (
  585. e.ObjectTypeId,
  586. e.ObjectName,
  587. g_DeleteOp,
  588. NULL,
  589. NULL
  590. );
  591. if (!b) {
  592. IsmAbortObjectEnum (&e);
  593. break;
  594. }
  595. } while (IsmEnumNextObject (&e));
  596. }
  597. return b;
  598. }
  599. BOOL
  600. pDoesDifferentFileExist (
  601. IN MIG_OBJECTSTRINGHANDLE SrcName,
  602. IN MIG_OBJECTSTRINGHANDLE DestName,
  603. IN PCTSTR DestNativeName,
  604. OUT PBOOL DifferentDetailsOnly
  605. )
  606. {
  607. MIG_CONTENT srcContent;
  608. MIG_CONTENT destContent;
  609. WIN32_FIND_DATA findData;
  610. BOOL result = FALSE;
  611. if (!DoesFileExistEx (DestNativeName, &findData)) {
  612. return FALSE;
  613. }
  614. if (findData.nFileSizeHigh) {
  615. return TRUE;
  616. }
  617. if (IsmAcquireObject (
  618. g_FileType | PLATFORM_DESTINATION,
  619. DestName,
  620. &destContent
  621. )) {
  622. result = TRUE;
  623. if (IsmAcquireObject (
  624. g_FileType | PLATFORM_SOURCE,
  625. SrcName,
  626. &srcContent
  627. )) {
  628. result = !IsmAreObjectsIdentical (
  629. MIG_FILE_TYPE,
  630. SrcName,
  631. &srcContent,
  632. MIG_FILE_TYPE,
  633. DestName,
  634. &destContent,
  635. DifferentDetailsOnly
  636. );
  637. IsmReleaseObject (&srcContent);
  638. }
  639. IsmReleaseObject (&destContent);
  640. } else {
  641. result = DoesFileExist (DestNativeName);
  642. }
  643. return result;
  644. }
  645. BOOL
  646. pIsFileDestCollision (
  647. IN MIG_OBJECTSTRINGHANDLE CurrentObjectName,
  648. IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
  649. IN PCTSTR CurrentNativeName,
  650. IN BOOL CompareDestFiles,
  651. IN BOOL *OnlyDetailsDiffer
  652. )
  653. {
  654. if (HtFindString (g_CollisionDestTable, CurrentObjectName)) {
  655. return TRUE;
  656. }
  657. if (CompareDestFiles &&
  658. pDoesDifferentFileExist (OriginalObjectName,
  659. CurrentObjectName,
  660. CurrentNativeName,
  661. OnlyDetailsDiffer)) {
  662. if (*OnlyDetailsDiffer == FALSE) {
  663. return TRUE;
  664. }
  665. }
  666. return FALSE;
  667. }
  668. MIG_OBJECTSTRINGHANDLE
  669. pCollideFile (
  670. IN MIG_OBJECTID OriginalObjectId,
  671. IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
  672. IN PCTSTR NewNode,
  673. IN PCTSTR NewLeaf,
  674. IN BOOL CompareDestFiles
  675. )
  676. {
  677. MIG_OBJECTSTRINGHANDLE result = NULL;
  678. HASHITEM hashItem;
  679. PCTSTR testNativeName;
  680. PCTSTR leafExt = NULL;
  681. TCHAR buff[MAX_TCHAR_PATH * 2];
  682. PTSTR openParen = NULL;
  683. PTSTR closeParen = NULL;
  684. PTSTR tmpLeaf = NULL;
  685. PTSTR testLeaf = NULL;
  686. size_t testLeafTchars;
  687. PTSTR chr;
  688. BOOL onlyDetailsDiffer = FALSE;
  689. BOOL replaceOk = TRUE;
  690. UINT fileIndex = 0;
  691. MIG_PROPERTYDATAID propDataId;
  692. BOOL specialPattern = FALSE;
  693. PTSTR fileCollPattern = NULL;
  694. MIG_BLOBTYPE propDataType;
  695. UINT requiredSize;
  696. HRESULT hr;
  697. if (!HtFindStringEx (g_CollisionSrcTable, OriginalObjectName, (PVOID)(&hashItem), FALSE)) {
  698. // we don't have a spot just yet. Let's make one.
  699. result = IsmCreateObjectHandle (NewNode, NewLeaf);
  700. testNativeName = JoinPaths (NewNode, NewLeaf);
  701. if (pIsFileDestCollision(result,
  702. OriginalObjectName,
  703. testNativeName,
  704. CompareDestFiles,
  705. &onlyDetailsDiffer)) {
  706. tmpLeaf = AllocText (TcharCount (NewLeaf) + 1);
  707. leafExt = _tcsrchr (NewLeaf, TEXT('.'));
  708. if (leafExt) {
  709. StringCopyAB (tmpLeaf, NewLeaf, leafExt);
  710. leafExt = _tcsinc (leafExt);
  711. } else {
  712. StringCopy (tmpLeaf, NewLeaf);
  713. }
  714. // Let's check if we wanted some special pattern for this file
  715. propDataId = IsmGetPropertyFromObjectId (OriginalObjectId, g_FileCollPatternData);
  716. if (propDataId) {
  717. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  718. if (propDataType == BLOBTYPE_STRING) {
  719. fileCollPattern = IsmGetMemory (requiredSize);
  720. if (fileCollPattern) {
  721. if (IsmGetPropertyData (
  722. propDataId,
  723. (PBYTE)fileCollPattern,
  724. requiredSize,
  725. NULL,
  726. &propDataType)) {
  727. specialPattern = TRUE;
  728. }
  729. if (!specialPattern) {
  730. IsmReleaseMemory (fileCollPattern);
  731. fileCollPattern = NULL;
  732. }
  733. }
  734. }
  735. }
  736. }
  737. if (specialPattern) {
  738. //
  739. // Loop until we find a non-colliding destination, or a colliding
  740. // dest that differs only by attributes
  741. //
  742. do {
  743. FreePathString (testNativeName);
  744. IsmDestroyObjectHandle (result);
  745. fileIndex ++;
  746. __try {
  747. hr = StringCbPrintf (buff, sizeof (buff), fileCollPattern, tmpLeaf, fileIndex, leafExt?leafExt:TEXT(""), NULL);
  748. }
  749. __except (EXCEPTION_EXECUTE_HANDLER) {
  750. // something went wrong. The pattern might have been terribly wrong
  751. hr = S_FALSE;
  752. }
  753. if (hr != S_OK) {
  754. // something went wrong, we assume that the pattern from the inf is probably bad.
  755. // Just incrementing the index won't solve the problem. Let's just abort this.
  756. fileIndex = 0;
  757. }
  758. result = IsmCreateObjectHandle (NewNode, buff);
  759. testNativeName = JoinPaths (NewNode, buff);
  760. } while (fileIndex && pIsFileDestCollision(
  761. result,
  762. OriginalObjectName,
  763. testNativeName,
  764. CompareDestFiles,
  765. &onlyDetailsDiffer));
  766. if (fileCollPattern) {
  767. IsmReleaseMemory (fileCollPattern);
  768. fileCollPattern = NULL;
  769. }
  770. if (!fileIndex) {
  771. // The collision pattern was bogus and we looped until
  772. // we ran out of indexes. Let's go with the default
  773. // collision mechanism.
  774. specialPattern = FALSE;
  775. }
  776. }
  777. if (!specialPattern) {
  778. // Check if the filename already has a (number) tacked on
  779. openParen = _tcsrchr (tmpLeaf, TEXT('('));
  780. closeParen = _tcsrchr (tmpLeaf, TEXT(')'));
  781. if (closeParen && openParen &&
  782. closeParen > openParen &&
  783. closeParen - openParen > 1) {
  784. // Make sure it's purely numerical
  785. for (chr = openParen+1; chr < closeParen; chr++) {
  786. if (!_istdigit (*chr)) {
  787. replaceOk = FALSE;
  788. break;
  789. }
  790. }
  791. if (replaceOk == TRUE) {
  792. if (_stscanf (openParen, TEXT("(%d)"), &fileIndex)) {
  793. *openParen = 0;
  794. }
  795. }
  796. }
  797. //
  798. // Loop until we find a non-colliding destination, or a colliding
  799. // dest that differs only by attributes
  800. //
  801. do {
  802. FreePathString (testNativeName);
  803. IsmDestroyObjectHandle (result);
  804. FreeText (testLeaf);
  805. fileIndex ++;
  806. wsprintf (buff, TEXT("(%d)"), fileIndex);
  807. testLeafTchars = TcharCount (tmpLeaf) + TcharCount (buff) + 1;
  808. if (leafExt) {
  809. testLeafTchars += TcharCount (leafExt) + 1;
  810. }
  811. testLeaf = AllocText (testLeafTchars);
  812. StringCopy (testLeaf, tmpLeaf);
  813. StringCat (testLeaf, buff);
  814. if (leafExt) {
  815. StringCat (testLeaf, TEXT("."));
  816. StringCat (testLeaf, leafExt);
  817. }
  818. result = IsmCreateObjectHandle (NewNode, testLeaf);
  819. testNativeName = JoinPaths (NewNode, testLeaf);
  820. } while (pIsFileDestCollision(result,
  821. OriginalObjectName,
  822. testNativeName,
  823. CompareDestFiles,
  824. &onlyDetailsDiffer));
  825. }
  826. FreeText (tmpLeaf);
  827. }
  828. if (onlyDetailsDiffer) {
  829. IsmAbandonObjectOnCollision (g_FileType | PLATFORM_DESTINATION, OriginalObjectName);
  830. }
  831. FreePathString (testNativeName);
  832. FreeText (testLeaf);
  833. //
  834. // Put new destination in the hash table and store the Ism handle, which will
  835. // be cleaned up at the end.
  836. //
  837. hashItem = HtAddStringEx (g_CollisionDestTable, result, &result, FALSE);
  838. HtAddStringEx (g_CollisionSrcTable, OriginalObjectName, &hashItem, FALSE);
  839. } else {
  840. //
  841. // Get the already computed collision destination.
  842. //
  843. HtCopyStringData (g_CollisionDestTable, hashItem, (PVOID)(&result));
  844. }
  845. return result;
  846. }
  847. MIG_OBJECTSTRINGHANDLE
  848. pCollisionGetDestination (
  849. IN MIG_OBJECTID OriginalObjectId,
  850. IN MIG_OBJECTSTRINGHANDLE OriginalObjectName,
  851. IN PCTSTR NewNode,
  852. IN PCTSTR NewLeaf
  853. )
  854. {
  855. MIG_OBJECTSTRINGHANDLE result = NULL;
  856. BOOL onlyDetailsDiffer = FALSE;
  857. // now we have the destination node. If this is actually a file
  858. // we need to check for collisions. For this we look if the
  859. // destination already has a file like this. After that we use
  860. // a table to reserve ourselves a spot.
  861. if (NewLeaf) {
  862. if (IsmIsObjectAbandonedOnCollision (g_FileType | PLATFORM_DESTINATION, OriginalObjectName)) {
  863. // we don't care about existing files on the destination machine.
  864. // However, some files that we just copy may collide with each other
  865. // so we have to check that.
  866. result = pCollideFile (OriginalObjectId, OriginalObjectName, NewNode, NewLeaf, FALSE);
  867. } else if (IsmIsObjectAbandonedOnCollision (g_FileType | PLATFORM_SOURCE, OriginalObjectName)) {
  868. // this will potentially collide with an existent file but then the source file
  869. // would not survive.
  870. result = IsmCreateObjectHandle (NewNode, NewLeaf);
  871. } else {
  872. result = pCollideFile (OriginalObjectId, OriginalObjectName, NewNode, NewLeaf, TRUE);
  873. }
  874. } else {
  875. result = IsmCreateObjectHandle (NewNode, NULL);
  876. }
  877. return result;
  878. }
  879. BOOL
  880. pExecuteFixFilename (
  881. VOID
  882. )
  883. {
  884. UINT ticks;
  885. MIG_OBJECT_ENUM objectEnum;
  886. MIG_OBJECTSTRINGHANDLE enumPattern;
  887. MIG_PROGRESSSLICEID sliceId;
  888. PCTSTR destination = NULL;
  889. MIG_OBJECTSTRINGHANDLE destFilename;
  890. PTSTR node = NULL;
  891. PCTSTR leaf = NULL;
  892. MIG_BLOB opData;
  893. PMIG_OBJECTCOUNT objectCount;
  894. BOOL deleted;
  895. objectCount = IsmGetObjectsStatistics (g_FileType | PLATFORM_SOURCE);
  896. if (objectCount) {
  897. ticks = objectCount->TotalObjects;
  898. } else {
  899. ticks = 0;
  900. }
  901. sliceId = IsmRegisterProgressSlice (ticks, max (1, ticks / 5));
  902. // Enum source file objects
  903. enumPattern = IsmCreateSimpleObjectPattern (NULL, TRUE, NULL, TRUE); // *,*
  904. if (IsmEnumFirstSourceObject (&objectEnum, g_FileType, enumPattern)) {
  905. do {
  906. // Check if Apply
  907. if (IsmIsApplyObjectId (objectEnum.ObjectId)) {
  908. // Macro expansion, rule processing, etc
  909. destination = IsmFilterObject (objectEnum.ObjectTypeId,
  910. objectEnum.ObjectName,
  911. NULL,
  912. &deleted,
  913. NULL);
  914. if (deleted) {
  915. continue;
  916. }
  917. if (!destination) {
  918. destination = objectEnum.ObjectName;
  919. }
  920. IsmCreateObjectStringsFromHandle (destination, &node, &leaf);
  921. if (node && _tcslen (node) >= 2) {
  922. if (IsValidFileSpec (node)) {
  923. if (!pValidatePartition (objectEnum.ObjectName, node)) {
  924. if (!IsmIsAttributeSetOnObjectId (objectEnum.ObjectId, g_LockPartitionAttr)) {
  925. // Pick a new destination partition
  926. pFindValidPartition (objectEnum.ObjectName, node, FALSE);
  927. }
  928. }
  929. }
  930. }
  931. // We have selected a new partition, so now check for file collisions
  932. destFilename = pCollisionGetDestination (
  933. objectEnum.ObjectId,
  934. objectEnum.ObjectName,
  935. node,
  936. leaf
  937. );
  938. if (node) {
  939. IsmDestroyObjectString (node);
  940. node = NULL;
  941. }
  942. if (leaf) {
  943. IsmDestroyObjectString (leaf);
  944. leaf = NULL;
  945. }
  946. opData.Type = BLOBTYPE_STRING;
  947. opData.String = PmDuplicateString (g_UntrackedCsmPool, destFilename);
  948. IsmDestroyObjectHandle (destFilename);
  949. destFilename = NULL;
  950. // Set a custom operation that will fix the name
  951. IsmSetOperationOnObjectId (
  952. objectEnum.ObjectId,
  953. g_PartMoveOp,
  954. (MIG_DATAHANDLE) 0,
  955. &opData
  956. );
  957. if (!IsmTickProgressBar (sliceId, 1)) {
  958. IsmAbortObjectEnum (&objectEnum);
  959. break;
  960. }
  961. if (destination != objectEnum.ObjectName) {
  962. IsmDestroyObjectHandle (destination);
  963. }
  964. }
  965. } while (IsmEnumNextObject (&objectEnum));
  966. }
  967. IsmDestroyObjectHandle (enumPattern);
  968. INVALID_POINTER (enumPattern);
  969. return TRUE;
  970. }
  971. BOOL
  972. WINAPI
  973. ScriptCsmExecute (
  974. VOID
  975. )
  976. {
  977. UINT u;
  978. TCHAR string[32];
  979. TCHAR pattern[MAX_TCHAR_PATH];
  980. //
  981. // Enumerate the environment variables DelReg* and DelFile*,
  982. // then enumerate all physical objects represented by the
  983. // pattern, and finally, mark the objects with delete operations.
  984. //
  985. u = 1;
  986. for (;;) {
  987. wsprintf (string, TEXT("DelReg%u"), u);
  988. u++;
  989. if (IsmGetEnvironmentString (
  990. PLATFORM_SOURCE,
  991. NULL,
  992. string,
  993. pattern,
  994. ARRAYSIZE(pattern),
  995. NULL
  996. )) {
  997. if (!pExecuteDeleteEnum (g_RegType, (MIG_OBJECTSTRINGHANDLE) pattern)) {
  998. return FALSE;
  999. }
  1000. } else {
  1001. break;
  1002. }
  1003. }
  1004. u = 1;
  1005. for (;;) {
  1006. wsprintf (string, TEXT("DelFile%u"), u);
  1007. u++;
  1008. if (IsmGetEnvironmentString (
  1009. PLATFORM_SOURCE,
  1010. NULL,
  1011. string,
  1012. pattern,
  1013. ARRAYSIZE(pattern),
  1014. NULL
  1015. )) {
  1016. if (!pExecuteDeleteEnum (g_FileType, (MIG_OBJECTSTRINGHANDLE) pattern)) {
  1017. return FALSE;
  1018. }
  1019. } else {
  1020. break;
  1021. }
  1022. }
  1023. pExecuteFixFilename ();
  1024. return TRUE;
  1025. }