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.

942 lines
27 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: main.cxx
  7. //
  8. // Contents: Fixes a catalog after propagating from one machine to another.
  9. //
  10. // History: 12 Jan 2000 dlee Created from propdump
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <proprec.hxx>
  16. #include <propdesc.hxx>
  17. #include "mmfile.hxx"
  18. DECLARE_INFOLEVEL(ci)
  19. unsigned const SixtyFourK = 1024 * 64;
  20. //#define LOG
  21. CCoTaskAllocator CoTaskAllocator; // exported data definition
  22. void * CCoTaskAllocator::Allocate(ULONG cbSize)
  23. {
  24. return CoTaskMemAlloc( cbSize );
  25. }
  26. void CCoTaskAllocator::Free(void *pv)
  27. {
  28. CoTaskMemFree(pv);
  29. }
  30. void Usage()
  31. {
  32. printf( "Usage: PropCi directory\n");
  33. printf( " directory specifies the directory where the catalog exists.\n");
  34. printf( "\n" );
  35. printf( "This application converts file indexes in the catalog specified.\n" );
  36. exit( 1 );
  37. }
  38. WCHAR const * wcsistr( WCHAR const * wcsString, WCHAR const * wcsPattern )
  39. {
  40. if ( (wcsPattern == 0) || (*wcsPattern == 0) )
  41. return wcsString;
  42. ULONG cwcPattern = wcslen(wcsPattern);
  43. while ( *wcsString != 0 )
  44. {
  45. while ( (*wcsString != 0) &&
  46. (towupper(*wcsString) != towupper(*wcsPattern)) )
  47. wcsString++;
  48. if ( 0 == *wcsString )
  49. return 0;
  50. if ( _wcsnicmp( wcsString, wcsPattern, cwcPattern) == 0 )
  51. return wcsString;
  52. wcsString++;
  53. }
  54. return 0;
  55. } //wcsistr
  56. void AppendBackslash( WCHAR *p )
  57. {
  58. int x = wcslen( p );
  59. if ( 0 != x && L'\\' != p[x-1] )
  60. {
  61. p[x] = L'\\';
  62. p[x+1] = 0;
  63. }
  64. } //AppendBackslash
  65. void FindFieldRec(
  66. WCHAR const * pwcFile,
  67. PROPID pid,
  68. CPropDesc & prop,
  69. ULONG & cTotal,
  70. ULONG & cFixed,
  71. ULONG & culFixed )
  72. {
  73. cTotal = 0;
  74. cFixed = 0;
  75. culFixed = 0;
  76. HANDLE h = CreateFile( pwcFile,
  77. GENERIC_READ,
  78. FILE_SHARE_READ,
  79. 0,
  80. OPEN_EXISTING,
  81. 0,
  82. 0 );
  83. if ( INVALID_HANDLE_VALUE == h )
  84. {
  85. printf( "Can't open file %ws. Error %u\n", pwcFile, GetLastError() );
  86. exit( 1 );
  87. }
  88. ULONG cbRead;
  89. static BYTE abTemp[SixtyFourK];
  90. if ( ReadFile( h,
  91. abTemp,
  92. sizeof abTemp ,
  93. &cbRead,
  94. 0 ) )
  95. {
  96. // Loop through records
  97. BOOL fFound = FALSE;
  98. CPropDesc * pPropDesc = (CPropDesc *)abTemp;
  99. for ( unsigned i = 0;
  100. i < cbRead/(sizeof(CPropDesc) + sizeof(ULONG));
  101. i++, pPropDesc = (CPropDesc *)(((BYTE *)pPropDesc) + sizeof(CPropDesc) + sizeof(ULONG)) )
  102. {
  103. if ( 0 != pPropDesc->Pid() )
  104. {
  105. if ( pPropDesc->Pid() == pid )
  106. {
  107. memcpy( &prop, pPropDesc, sizeof prop );
  108. fFound = TRUE;
  109. }
  110. cTotal++;
  111. if ( pPropDesc->Offset() != -1 )
  112. {
  113. cFixed++;
  114. culFixed += (pPropDesc->Size() / sizeof(DWORD));
  115. }
  116. }
  117. }
  118. if ( !fFound )
  119. {
  120. printf( "can't find pid %#x\n", pid );
  121. exit( 1 );
  122. }
  123. }
  124. else
  125. {
  126. printf( "Can't read file %ws. Error %u\n", pwcFile, GetLastError() );
  127. exit( 1 );
  128. }
  129. #ifdef LOG
  130. printf( "pid %d, total %d, fixed %d\n", pid, cTotal, cFixed );
  131. printf( " pid %d, vt %d, ostart %d, cbmax %d, ordinal %d, mask %d, rec %d, fmodify %d\n",
  132. prop.Pid(),
  133. prop.Type(),
  134. prop.Offset(),
  135. prop.Size(),
  136. prop.Ordinal(),
  137. prop.Mask(),
  138. prop.Record(),
  139. prop.Modifiable() );
  140. #endif
  141. CloseHandle( h );
  142. } //FindFieldRec
  143. NTSTATUS CiNtOpenNoThrow(
  144. HANDLE & h,
  145. WCHAR const * pwcsPath,
  146. ACCESS_MASK DesiredAccess,
  147. ULONG ShareAccess,
  148. ULONG OpenOptions )
  149. {
  150. h = INVALID_HANDLE_VALUE;
  151. UNICODE_STRING uScope;
  152. if ( !RtlDosPathNameToNtPathName_U( pwcsPath,
  153. &uScope,
  154. 0,
  155. 0 ) )
  156. return STATUS_INSUFFICIENT_RESOURCES;
  157. //
  158. // Open the file
  159. //
  160. OBJECT_ATTRIBUTES ObjectAttr;
  161. InitializeObjectAttributes( &ObjectAttr, // Structure
  162. &uScope, // Name
  163. OBJ_CASE_INSENSITIVE, // Attributes
  164. 0, // Root
  165. 0 ); // Security
  166. IO_STATUS_BLOCK IoStatus;
  167. NTSTATUS Status = NtOpenFile( &h, // Handle
  168. DesiredAccess, // Access
  169. &ObjectAttr, // Object Attributes
  170. &IoStatus, // I/O Status block
  171. ShareAccess, // Shared access
  172. OpenOptions ); // Flags
  173. RtlFreeHeap( RtlProcessHeap(), 0, uScope.Buffer );
  174. return Status;
  175. } //CiNtOpenNoThrow
  176. FILEID GetFileId( WCHAR * pwcPath )
  177. {
  178. if ( 2 == wcslen( pwcPath ) )
  179. wcscat( pwcPath, L"\\" );
  180. HANDLE h;
  181. NTSTATUS status = CiNtOpenNoThrow( h,
  182. pwcPath,
  183. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  184. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  185. 0 );
  186. if ( FAILED( status ) )
  187. {
  188. printf( "Can't open file %ws to get fileid. Error %#x\n", pwcPath, status );
  189. return 0;
  190. }
  191. FILE_INTERNAL_INFORMATION fii;
  192. IO_STATUS_BLOCK IoStatus;
  193. status = NtQueryInformationFile( h,
  194. &IoStatus,
  195. &fii,
  196. sizeof fii,
  197. FileInternalInformation );
  198. NtClose( h );
  199. if ( NT_SUCCESS( status ) )
  200. status = IoStatus.Status;
  201. if ( NT_SUCCESS( status ) )
  202. return fii.IndexNumber.QuadPart;
  203. return 0;
  204. } //GetFileId
  205. void GetRecordInformation(
  206. WCHAR const * pwcFile,
  207. ULONG & cRecPerBuf,
  208. ULONG & cbRec )
  209. {
  210. cRecPerBuf = 0;
  211. cbRec = 0;
  212. HANDLE h = CreateFile( pwcFile,
  213. GENERIC_READ,
  214. FILE_SHARE_READ,
  215. 0,
  216. OPEN_EXISTING,
  217. 0,
  218. 0 );
  219. if ( INVALID_HANDLE_VALUE == h )
  220. {
  221. printf( "Can't open file %ws. Error %u\n", pwcFile, GetLastError() );
  222. exit( 1 );
  223. }
  224. ULONG cbRead;
  225. static BYTE abTemp[SixtyFourK];
  226. if ( ReadFile( h,
  227. abTemp,
  228. sizeof(abTemp),
  229. &cbRead,
  230. 0 ) )
  231. {
  232. //
  233. // Determine record size
  234. //
  235. if ( abTemp[0] != 0 || abTemp[1] != 0 )
  236. {
  237. printf( "Record 0 not blank. File corrupt!\n" );
  238. exit( 1 );
  239. }
  240. // First record should be all empty and only the first
  241. // record should be so. So counting all leading zeros gives us
  242. // the size of the record.
  243. for ( unsigned i = 0; i < cbRead && abTemp[i] == 0; i++ )
  244. continue;
  245. if ( i == cbRead )
  246. {
  247. printf( "First %uK segment all zero!. File corrupt!\n", sizeof(abTemp)/1024 );
  248. exit( 1 );
  249. }
  250. switch ( *(USHORT *)&abTemp[i] )
  251. {
  252. case 0x5555:
  253. case 0xAAAA:
  254. case 0xBBBB:
  255. case 0xCCCC:
  256. case 0xDDDD:
  257. cbRec = i;
  258. if ( cbRec % 4 != 0 )
  259. {
  260. printf( "Record size (%u bytes) not DWORD aligned!\n\n", cbRec );
  261. exit( 1 );
  262. }
  263. cRecPerBuf = sizeof(abTemp) / cbRec;
  264. break;
  265. default:
  266. printf( "First non-zero byte is not a proper signature (%u)!\n", *(SHORT *)&abTemp[i] );
  267. exit( 1 );
  268. }
  269. }
  270. else
  271. {
  272. printf( "can't read from file %ws, error %d\n", pwcFile, GetLastError() );
  273. exit( 1 );
  274. }
  275. #ifdef LOG
  276. printf( "cRecPerBuf %d, cbRec %d\n", cRecPerBuf, cbRec );
  277. #endif
  278. CloseHandle( h );
  279. } //GetRecordInformation
  280. void PatchFileIDs(
  281. WCHAR const * pwcDir,
  282. WCHAR const * pwcPri,
  283. WCHAR const * pwcSec )
  284. {
  285. //
  286. // First, read the property specifications for secondary wid, fileindex,
  287. // lastseen, and path. The first 3 are in the primary and the last in
  288. // the secondary.
  289. //
  290. WCHAR awcPriProp[ MAX_PATH ];
  291. wcscpy( awcPriProp, pwcDir );
  292. wcscat( awcPriProp, L"CIP10000.001" );
  293. ULONG cPriTotal, cPriFixed, culPriFixed;
  294. CPropDesc SecWidPtrFieldRec;
  295. FindFieldRec( awcPriProp,
  296. pidSecondaryStorage,
  297. SecWidPtrFieldRec,
  298. cPriTotal,
  299. cPriFixed,
  300. culPriFixed );
  301. CPropDesc FileIdFieldRec;
  302. FindFieldRec( awcPriProp,
  303. pidFileIndex,
  304. FileIdFieldRec,
  305. cPriTotal,
  306. cPriFixed,
  307. culPriFixed );
  308. CPropDesc LastSeenFieldRec;
  309. FindFieldRec( awcPriProp,
  310. pidLastSeenTime,
  311. LastSeenFieldRec,
  312. cPriTotal,
  313. cPriFixed,
  314. culPriFixed );
  315. WCHAR awcSecProp[ MAX_PATH ];
  316. wcscpy( awcSecProp, pwcDir );
  317. wcscat( awcSecProp, L"CIP20000.001" );
  318. ULONG cSecTotal, cSecFixed, culSecFixed;
  319. CPropDesc PathFieldRec;
  320. FindFieldRec( awcSecProp,
  321. pidPath,
  322. PathFieldRec,
  323. cSecTotal,
  324. cSecFixed,
  325. culSecFixed );
  326. //
  327. // Get information about the number and size of records.
  328. //
  329. ULONG cPriRecPerBuf, cbPriRec;
  330. GetRecordInformation( pwcPri, cPriRecPerBuf, cbPriRec );
  331. ULONG cSecRecPerBuf, cbSecRec;
  332. GetRecordInformation( pwcSec, cSecRecPerBuf, cbSecRec );
  333. //
  334. // Walk the property store, get the secondary wid, read the path from
  335. // the secondary store, lookup the fileid, and write the fileid back
  336. // info the primary store.
  337. //
  338. CMMFile pri( pwcPri, TRUE );
  339. if ( !pri.Ok() )
  340. {
  341. printf( "can't map primary\n" );
  342. exit( 1 );
  343. }
  344. BYTE * pb = (BYTE *) pri.GetMapping();
  345. BYTE * pbBase = pb;
  346. CMMFile sec( pwcSec, TRUE );
  347. if ( !sec.Ok() )
  348. {
  349. printf( "can't map secondary\n" );
  350. exit( 1 );
  351. }
  352. BYTE * pbSecBase = (BYTE *) sec.GetMapping();
  353. FILETIME ftNow;
  354. GetSystemTimeAsFileTime( &ftNow );
  355. #ifdef LOG
  356. printf( "pb %#x, size %d\n", pb, pri.FileSize() );
  357. #endif
  358. ULONG iRec = 0, iRecTotal = 0;
  359. do
  360. {
  361. #ifdef LOG
  362. printf( "record %d\n", iRecTotal );
  363. #endif
  364. // If we're at the end of a 64k page, go on to the next one.
  365. if ( iRec == cPriRecPerBuf )
  366. {
  367. iRec = 0;
  368. pb += 65536;
  369. }
  370. COnDiskPropertyRecord * pRec = new( iRec, pb, cbPriRec/4 ) COnDiskPropertyRecord;
  371. if ( (BYTE *) pRec >= ( pbBase + pri.FileSize() ) )
  372. break;
  373. if ( pRec->IsTopLevel() )
  374. {
  375. PROPVARIANT var;
  376. static BYTE abExtra[MAX_PATH * 5];
  377. unsigned cbExtra = sizeof(abExtra);
  378. pRec->ReadFixed( SecWidPtrFieldRec.Ordinal(),
  379. SecWidPtrFieldRec.Mask(),
  380. SecWidPtrFieldRec.Offset(),
  381. cPriTotal,
  382. SecWidPtrFieldRec.Type(),
  383. var,
  384. abExtra,
  385. &cbExtra,
  386. *((PStorage *)0) );
  387. if ( VT_UI4 != var.vt )
  388. {
  389. printf( "failure: secondary wid wasn't a UI4\n" );
  390. exit( 1 );
  391. }
  392. #ifdef LOG
  393. printf( "secondary wid %d\n", var.ulVal );
  394. #endif
  395. ULONG iTargetSection = var.ulVal/cSecRecPerBuf;
  396. BYTE * pbSec = pbSecBase + ( iTargetSection * SixtyFourK );
  397. // Get the secondary store record
  398. COnDiskPropertyRecord * pRec2 = new( var.ulVal % cSecRecPerBuf, pbSec, cbSecRec/4 ) COnDiskPropertyRecord;
  399. // Read the path
  400. cbExtra = sizeof abExtra;
  401. #ifdef LOG
  402. printf( "pRec2: %#x\n", pRec2 );
  403. #endif
  404. var.vt = VT_EMPTY;
  405. if ( !pRec2->ReadVariable( PathFieldRec.Ordinal(),
  406. PathFieldRec.Mask(),
  407. culSecFixed,
  408. cSecTotal,
  409. cSecFixed,
  410. var,
  411. abExtra,
  412. &cbExtra ) )
  413. {
  414. // It's in an overflow record
  415. BOOL fOk;
  416. do
  417. {
  418. //
  419. // Check for existing overflow block.
  420. //
  421. WORKID widOverflow = pRec2->OverflowBlock();
  422. if ( 0 == widOverflow )
  423. break;
  424. iTargetSection = widOverflow / cSecRecPerBuf;
  425. pbSec = pbSecBase + ( iTargetSection * SixtyFourK );
  426. pRec2 = new( widOverflow % cSecRecPerBuf, pbSec, cbSecRec/4 ) COnDiskPropertyRecord;
  427. #ifdef LOG
  428. printf( "overflow pRec2: %#x\n", pRec2 );
  429. #endif
  430. ULONG Ordinal = PathFieldRec.Ordinal() - cSecFixed;
  431. DWORD Mask = (1 << ((Ordinal % 16) * 2) );
  432. fOk = pRec2->ReadVariable( Ordinal, // Ordinal (assuming 0 fixed)
  433. Mask, // Mask (assuming 0 fixed)
  434. 0, // Fixed properties
  435. cSecTotal - cSecFixed,
  436. 0, // Count of fixed properties
  437. var,
  438. abExtra,
  439. &cbExtra );
  440. } while ( !fOk );
  441. }
  442. if ( VT_LPWSTR == var.vt )
  443. {
  444. // Get and set the fileindex for this volume
  445. FILEID fid = GetFileId( var.pwszVal );
  446. PROPVARIANT varId;
  447. varId.vt = VT_UI8;
  448. varId.hVal.QuadPart = fid;
  449. pRec->WriteFixed( FileIdFieldRec.Ordinal(),
  450. FileIdFieldRec.Mask(),
  451. FileIdFieldRec.Offset(),
  452. FileIdFieldRec.Type(),
  453. cPriTotal,
  454. varId );
  455. // Set the last seen time so we don't reindex the file
  456. PROPVARIANT varLS;
  457. varLS.vt = VT_FILETIME;
  458. varLS.filetime = ftNow;
  459. pRec->WriteFixed( LastSeenFieldRec.Ordinal(),
  460. LastSeenFieldRec.Mask(),
  461. LastSeenFieldRec.Offset(),
  462. LastSeenFieldRec.Type(),
  463. cPriTotal,
  464. varLS );
  465. #ifdef LOG
  466. printf( "fileid %#I64x, %ws\n", fid, var.pwszVal );
  467. #endif
  468. }
  469. }
  470. if ( pRec->IsValidType() )
  471. {
  472. iRec += pRec->CountRecords();
  473. iRecTotal += pRec->CountRecords();
  474. }
  475. else
  476. {
  477. iRec++;
  478. iRecTotal++;
  479. }
  480. } while ( TRUE );
  481. pri.Flush();
  482. } //PatchFileIDs
  483. void GetNtVolumeInformation(
  484. ULONG ulVolumeId,
  485. ULONGLONG & ullVolumeCreationTime,
  486. ULONG & ulVolumeSerialNumber,
  487. ULONGLONG & ullJournalId )
  488. {
  489. ullVolumeCreationTime = 0;
  490. ulVolumeSerialNumber = 0;
  491. ullJournalId = 0;
  492. WCHAR wszVolumePath[] = L"\\\\.\\a:";
  493. wszVolumePath[4] = (WCHAR) ulVolumeId;
  494. FILE_FS_VOLUME_INFORMATION VolumeInfo;
  495. VolumeInfo.VolumeCreationTime.QuadPart = 0;
  496. VolumeInfo.VolumeSerialNumber = 0;
  497. HANDLE hVolume = CreateFile( wszVolumePath,
  498. GENERIC_READ | GENERIC_WRITE,
  499. FILE_SHARE_READ | FILE_SHARE_WRITE,
  500. 0,
  501. OPEN_EXISTING,
  502. 0,
  503. 0 );
  504. if ( INVALID_HANDLE_VALUE == hVolume )
  505. {
  506. printf( "failure: can't open volume %ws\n", wszVolumePath );
  507. exit( 1 );
  508. }
  509. IO_STATUS_BLOCK iosb;
  510. RtlZeroMemory( &VolumeInfo, sizeof VolumeInfo );
  511. NtQueryVolumeInformationFile( hVolume,
  512. &iosb,
  513. &VolumeInfo,
  514. sizeof(VolumeInfo),
  515. FileFsVolumeInformation );
  516. //
  517. // This call will only succeed on NTFS NT5 w/ USN Journal enabled.
  518. //
  519. USN_JOURNAL_DATA UsnJournalInfo;
  520. RtlZeroMemory( &UsnJournalInfo, sizeof UsnJournalInfo );
  521. NTSTATUS Status = NtFsControlFile( hVolume,
  522. 0,
  523. 0,
  524. 0,
  525. &iosb,
  526. FSCTL_QUERY_USN_JOURNAL,
  527. 0,
  528. 0,
  529. &UsnJournalInfo,
  530. sizeof UsnJournalInfo );
  531. if ( NT_SUCCESS(Status) && NT_SUCCESS( iosb.Status ) )
  532. {
  533. // cool, it's a usn volume
  534. }
  535. else if ( ( STATUS_JOURNAL_NOT_ACTIVE == Status ||
  536. STATUS_INVALID_DEVICE_STATE == Status ) )
  537. {
  538. //
  539. // Usn journal not created, create it
  540. //
  541. CREATE_USN_JOURNAL_DATA usnCreateData;
  542. usnCreateData.MaximumSize = 0x800000; // 8 meg
  543. usnCreateData.AllocationDelta = 0x100000; // 1 meg
  544. Status = NtFsControlFile( hVolume,
  545. 0,
  546. 0,
  547. 0,
  548. &iosb,
  549. FSCTL_CREATE_USN_JOURNAL,
  550. &usnCreateData,
  551. sizeof usnCreateData,
  552. 0,
  553. 0 );
  554. if ( NT_SUCCESS( Status ) && NT_SUCCESS( iosb.Status ) )
  555. {
  556. Status = NtFsControlFile( hVolume,
  557. 0,
  558. 0,
  559. 0,
  560. &iosb,
  561. FSCTL_QUERY_USN_JOURNAL,
  562. 0,
  563. 0,
  564. &UsnJournalInfo,
  565. sizeof UsnJournalInfo );
  566. if (! ( NT_SUCCESS(Status) && NT_SUCCESS( iosb.Status ) ) )
  567. {
  568. printf( "can't query usn vol info after creating it %#x\n", Status );
  569. exit( 1 );
  570. }
  571. }
  572. else
  573. {
  574. printf( "can't create usn journal %#x\n", Status );
  575. exit( 1 );
  576. }
  577. }
  578. else
  579. {
  580. printf( "can't get USN information, probably FAT: %#x\n", Status );
  581. }
  582. ullVolumeCreationTime = VolumeInfo.VolumeCreationTime.QuadPart;
  583. ulVolumeSerialNumber = VolumeInfo.VolumeSerialNumber;
  584. ullJournalId = UsnJournalInfo.UsnJournalID;
  585. printf( " new volumecreationtime: %#I64x\n", ullVolumeCreationTime );
  586. printf( " new volumeserialnumber: %#x\n", ulVolumeSerialNumber );
  587. printf( " new journalid: %#I64x\n", ullJournalId );
  588. CloseHandle( hVolume );
  589. } //GetNtVolumeInformation
  590. void PatchScopeTable( WCHAR const * pwcDir )
  591. {
  592. // Find out how many scopes are in the scope table
  593. ULONG cScopes = 0;
  594. {
  595. WCHAR awcControl[ MAX_PATH ];
  596. wcscpy( awcControl, pwcDir );
  597. wcscat( awcControl, L"cisp0000.000" );
  598. CMMFile Control( awcControl, FALSE );
  599. if ( 0 == Control.GetMapping() )
  600. {
  601. printf( "can't open file %ws\n", awcControl );
  602. exit( 1 );
  603. }
  604. cScopes = ((ULONG *) Control.GetMapping())[4];
  605. }
  606. WCHAR awcOne[ MAX_PATH ];
  607. wcscpy( awcOne, pwcDir );
  608. wcscat( awcOne, L"cisp0000.001" );
  609. // Loop through the scopes and patch
  610. {
  611. printf( " scope table: %ws has %d scopes\n", awcOne, cScopes );
  612. CMMFile One( awcOne, TRUE );
  613. if ( !One.Ok() )
  614. {
  615. printf( "can't map scope table\n" );
  616. exit( 1 );
  617. }
  618. BYTE * pb = (BYTE *) One.GetMapping();
  619. for ( ULONG i = 0; i < cScopes; i++ )
  620. {
  621. const LONGLONG eSigCiScopeTable = 0x5158515851585158i64;
  622. LONGLONG signature;
  623. memcpy( &signature, pb, sizeof signature );
  624. pb += sizeof signature;
  625. if ( 0 == signature )
  626. break;
  627. printf( " scope record: \n" );
  628. if ( eSigCiScopeTable != signature )
  629. {
  630. printf( "invalid scope signature: %#I64x\n", signature );
  631. exit( 1 );
  632. }
  633. VOLUMEID volumeId;
  634. memcpy( &volumeId, pb, sizeof volumeId );
  635. printf( " volumeId: %x\n", volumeId );
  636. pb += sizeof volumeId;
  637. ULONGLONG ullNewVolumeCreationTime;
  638. ULONG ulNewVolumeSerialNumber;
  639. ULONGLONG ullNewJournalId;
  640. GetNtVolumeInformation( volumeId,
  641. ullNewVolumeCreationTime,
  642. ulNewVolumeSerialNumber,
  643. ullNewJournalId );
  644. ULONGLONG ullVolumeCreationTime;
  645. memcpy( &ullVolumeCreationTime, pb, sizeof ullVolumeCreationTime );
  646. printf( " creation time: %#I64x\n", ullVolumeCreationTime );
  647. memcpy( pb,
  648. &ullNewVolumeCreationTime,
  649. sizeof ullNewVolumeCreationTime );
  650. pb += sizeof ullVolumeCreationTime;
  651. ULONG ulVolumeSerialNumber;
  652. memcpy( &ulVolumeSerialNumber, pb, sizeof ulVolumeSerialNumber );
  653. printf( " serial number: %x\n", ulVolumeSerialNumber );
  654. memcpy( pb,
  655. &ulNewVolumeSerialNumber,
  656. sizeof ulNewVolumeSerialNumber );
  657. pb += sizeof ulVolumeSerialNumber;
  658. if ( CI_VOLID_USN_NOT_ENABLED == volumeId )
  659. {
  660. FILETIME ft;
  661. memcpy( &ft, pb, sizeof ft );
  662. printf( " filetime: %#I64x\n", ft );
  663. pb += sizeof ft;
  664. }
  665. else
  666. {
  667. USN usn;
  668. memcpy( &usn, pb, sizeof usn );
  669. printf( " usn: %#I64x\n", usn );
  670. USN usnNewMax = 0;
  671. memcpy( pb,
  672. &usnNewMax,
  673. sizeof usnNewMax );
  674. pb += sizeof usn;
  675. ULONGLONG JournalId;
  676. memcpy( &JournalId, pb, sizeof JournalId );
  677. printf( " JournalId: %#I64x\n", JournalId );
  678. memcpy( pb,
  679. &ullNewJournalId,
  680. sizeof ullNewJournalId );
  681. pb += sizeof JournalId;
  682. }
  683. ULONG cwcPath;
  684. memcpy( &cwcPath, pb, sizeof cwcPath );
  685. pb += sizeof cwcPath;
  686. WCHAR awcPath[ MAX_PATH ];
  687. memcpy( awcPath, pb, cwcPath * sizeof WCHAR );
  688. printf( " path: %ws\n", awcPath );
  689. pb += ( cwcPath * sizeof WCHAR );
  690. }
  691. One.Flush();
  692. }
  693. WCHAR awcTwo[ MAX_PATH ];
  694. wcscpy( awcTwo, pwcDir );
  695. wcscat( awcTwo, L"cisp0000.002" );
  696. BOOL f = CopyFile( awcOne, awcTwo, FALSE );
  697. if ( !f )
  698. {
  699. printf( "can't copy scope list, error %d\n", GetLastError() );
  700. exit( 1 );
  701. }
  702. } //PatchScopeDir
  703. extern "C" int __cdecl wmain( int argc, WCHAR * argv[] )
  704. {
  705. if ( 2 != argc )
  706. Usage();
  707. //
  708. // The lone argument is the catalog directory, with or without catalog.wci
  709. //
  710. WCHAR awcDir[ MAX_PATH ];
  711. wcscpy( awcDir, argv[1] );
  712. AppendBackslash( awcDir );
  713. if ( 0 == wcsistr( awcDir, L"catalog.wci" ) )
  714. wcscat( awcDir, L"catalog.wci\\" );
  715. // Find and validate the primary and secondary stores exist
  716. WCHAR awcPri[MAX_PATH];
  717. wcscpy( awcPri, awcDir );
  718. wcscat( awcPri, L"*.ps1" );
  719. WIN32_FIND_DATA findData;
  720. HANDLE h = FindFirstFile( awcPri, &findData );
  721. if ( INVALID_HANDLE_VALUE == h )
  722. {
  723. printf( "can't find primary *.ps1 store\n" );
  724. exit( 1 );
  725. }
  726. FindClose( h );
  727. wcscpy( awcPri, awcDir );
  728. wcscat( awcPri, findData.cFileName );
  729. WCHAR awcSec[MAX_PATH];
  730. wcscpy( awcSec, awcDir );
  731. wcscat( awcSec, L"*.ps2" );
  732. h = FindFirstFile( awcSec, &findData );
  733. if ( INVALID_HANDLE_VALUE == h )
  734. {
  735. printf( "can't find secondary *.ps2 store\n" );
  736. exit( 1 );
  737. }
  738. FindClose( h );
  739. wcscpy( awcSec, awcDir );
  740. wcscat( awcSec, findData.cFileName );
  741. //
  742. // Do the core work here -- patch the file IDs in the primary store.
  743. // Also whack the last seen times so the files aren't refiltered in
  744. // case they were copied to the target machine after the catalog was
  745. // snapped.
  746. //
  747. printf( "patching file IDs\n" );
  748. PatchFileIDs( awcDir, awcPri, awcSec );
  749. //
  750. // Patch the scope table so cisvc doesn't think it's a different volume.
  751. //
  752. printf( "patching the scope table\n" );
  753. PatchScopeTable( awcDir );
  754. //
  755. // Delete the old fileid hash table since the fileids are wrong.
  756. // It'll get recreated automatically when the catalog is opened.
  757. //
  758. printf( "deleting the fileid hash map\n" );
  759. WCHAR awcHashMap[ MAX_PATH ];
  760. wcscpy( awcHashMap, awcDir );
  761. wcscat( awcHashMap, L"cicat.fid" );
  762. DeleteFile( awcHashMap );
  763. printf( "catalog successfully converted\n" );
  764. return 0;
  765. } //wmain