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.

3244 lines
104 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: dumplog.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // Coupling:
  15. //
  16. // Notes:
  17. //
  18. // History: 8-24-1998 benl Created
  19. //
  20. //----------------------------------------------------------------------------
  21. #include "pch.hxx"
  22. #include "utils.hxx"
  23. #include "map.hxx"
  24. typedef void * PSCB;
  25. typedef bool (* PMATCH_FUNC)(PLFS_RECORD_HEADER pRecord, PVOID Context);
  26. typedef struct {
  27. LONGLONG llFileRef;
  28. ULONG AttrType;
  29. } MYENTRY, *PMYENTRY;
  30. typedef struct {
  31. VCN Vcn;
  32. int Offset;
  33. } VCN_OFFSET, *PVCN_OFFSET;
  34. typedef CMap<int, MYENTRY> OPEN_ATTR_MAP, *POPEN_ATTR_MAP;
  35. //
  36. // Map of current lsn to start of transaction lsn
  37. //
  38. typedef CMap<LONGLONG, ULONG> TRANSACTION_MAP, *PTRANSACTION_MAP;
  39. typedef struct {
  40. LONGLONG llFileRef;
  41. OPEN_ATTR_MAP * pAttrMap;
  42. INT ClusterSize;
  43. } FILEREF_MATCH_CTX, *PFILEREF_MATCH_CTX;
  44. typedef struct {
  45. LONGLONG AddRecordLsn;
  46. LONGLONG AddRecordFileRef;
  47. LONGLONG AddRecordVcn;
  48. int AddRecordClusterOffset;
  49. } DEDUCE_CTX, *PDEDUCE_CTX;
  50. #include <ntfslog.h>
  51. typedef struct _LOGCB {
  52. LSN FirstLsn;
  53. LSN CurrentLsn;
  54. } LOGCB, *PLOGCB;
  55. #define WARNING_SIZE 50
  56. #define LOG_PAGE 0x1000
  57. #define TOTAL_PAGE_HEADER ALIGN(sizeof(LFS_RECORD_PAGE_HEADER) + ((LOG_PAGE / 0x200) * sizeof(USHORT)), sizeof(DWORD))
  58. const char * gOpMap[] =
  59. {
  60. "Noop",
  61. "CompensationLogRecord",
  62. "Init FRS",
  63. "Delete FRS",
  64. "Write EOF FRS",
  65. "CreateAttribute",
  66. "DeleteAttribute",
  67. "UpdateResidentValue",
  68. "UpdateNonresidentValue",
  69. "UpdateMappingPairs",
  70. "DeleteDirtyClusters",
  71. "SetNewAttributeSizes",
  72. "AddIndexEntryRoot",
  73. "DeleteIndexEntryRoot",
  74. "AddIndexEntryAllocation",
  75. "DeleteIndexEntryAllocation",
  76. "WriteEndOfIndexBuffer",
  77. "SetIndexEntryVcnRoot",
  78. "SetIndexEntryVcnAllocation",
  79. "UpdateFileNameRoot",
  80. "UpdateFileNameAllocation",
  81. "SetBitsInNonresidentBitMap",
  82. "ClearBitsInNonresidentBitMap",
  83. "HotFix",
  84. "EndTopLevelAction",
  85. "PrepareTransaction",
  86. "CommitTransaction",
  87. "ForgetTransaction",
  88. "OpenNonresidentAttribute",
  89. "OpenAttributeTableDump",
  90. "AttributeNamesDump",
  91. "DirtyPageTableDump",
  92. "TransactionTableDump",
  93. "UpdateRecordDataRoot",
  94. "UpdateRecordDataAllocation"
  95. };
  96. const char * gTransStateMap[] = {
  97. "TransactionUninitialized",
  98. "TransactionActive",
  99. "TransactionPrepared",
  100. "TransactionCommitted"
  101. };
  102. int gcOpMap = (sizeof(gOpMap) / sizeof(char *));
  103. int gcTransStateMap = (sizeof(gTransStateMap) / sizeof(char *));
  104. int gSeqNumberBits = 0;
  105. int gLogFileSize = 0;
  106. //flags
  107. bool gfDumpData = false;
  108. int giPagesBackToDump = 0;
  109. bool gfPrintHeaders = false;
  110. LSN gLsnToDump = {0,0};
  111. VCN_OFFSET gVcnPairToMatch;
  112. LCN gLcnToMatch = 0;
  113. LSN gLsnToTrace = {0,0};
  114. bool gfDumpEverything = false;
  115. LONG glBitToMatch = -1;
  116. LONGLONG gllFileToMatch = 0;
  117. bool gfScanForRestarts = false;
  118. ULONG gulClusterSize = 0;
  119. LSN gllRangeStart = {0,0};
  120. LSN gllRangeEnd = {0,0};
  121. bool gVerboseScan = false;
  122. bool gfScanTransactions = false;
  123. //+---------------------------------------------------------------------------
  124. //
  125. // Function: LsnToOffset
  126. //
  127. // Synopsis: Transforms LSN to its offset in the logfile
  128. //
  129. // Arguments: [Lsn] --
  130. //
  131. // Returns:
  132. //
  133. // History: 8-25-1998 benl Created
  134. //
  135. // Notes:
  136. //
  137. //----------------------------------------------------------------------------
  138. LONGLONG LsnToOffset(LONGLONG Lsn)
  139. {
  140. return (ULONGLONG)(Lsn << gSeqNumberBits) >> (gSeqNumberBits - 3);
  141. } // LsnToOffset
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Function: LsnToSequenceNumber
  145. //
  146. // Synopsis: Transforms LSN to its sequence number
  147. //
  148. // Arguments: [Lsn] --
  149. //
  150. // Returns:
  151. //
  152. // History: 8-25-1998 benl Created
  153. //
  154. // Notes:
  155. //
  156. //----------------------------------------------------------------------------
  157. ULONG LsnToSequenceNumber(LONGLONG Lsn)
  158. {
  159. return (ULONG)(Lsn >> (sizeof(LONGLONG) * 8 - gSeqNumberBits));
  160. } // LsnToOffset
  161. //+---------------------------------------------------------------------------
  162. //
  163. // Function: MyReadFile
  164. //
  165. // Synopsis: Helper wrapper for ReadFile
  166. //
  167. // Arguments: [hFile] --
  168. // [lpBuffer] --
  169. // [cbRange] --
  170. // [pol] --
  171. //
  172. // Returns:
  173. //
  174. // History: 8-25-1998 benl Created
  175. //
  176. // Notes:
  177. //
  178. //----------------------------------------------------------------------------
  179. bool MyReadFile(HANDLE hFile, BYTE * lpBuffer, DWORD cbRange, OVERLAPPED * pol)
  180. {
  181. DWORD dwRead;
  182. if (!ReadFile(hFile, lpBuffer, cbRange, &dwRead, pol)) {
  183. printf("MyReadFile: ReadFile for 0x%x at 0x%x failed %d\n", cbRange, pol->Offset, GetLastError());
  184. return false;
  185. }
  186. if (dwRead != cbRange) {
  187. printf("MyReadFile: Only read: 0x%x\n", dwRead);
  188. return false;
  189. }
  190. return true;
  191. } // MyReadFile
  192. //+---------------------------------------------------------------------------
  193. //
  194. // Function: ApplySectorHdr
  195. //
  196. // Synopsis: Fixes up log record using multisector hdr
  197. //
  198. // Arguments: [pHdr] --
  199. //
  200. // Returns:
  201. //
  202. // History: 8-24-1998 benl Created
  203. //
  204. // Notes:
  205. //
  206. //----------------------------------------------------------------------------
  207. bool ApplySectorHdr(PMULTI_SECTOR_HEADER pHdr, ULONG LogOffset)
  208. {
  209. int iIndex;
  210. USHORT * pShort = NULL;
  211. USHORT sKey;
  212. USHORT * pBuffer;
  213. if (*((DWORD *)pHdr->Signature) == 0xFFFFFFFF) {
  214. printf("Unused page!\n");
  215. return false;
  216. }
  217. if (*((DWORD *)pHdr->Signature) == 0x44414142) {
  218. printf("BAAD page!\n");
  219. return false;
  220. }
  221. if ((pHdr->UpdateSequenceArraySize != PAGE_SIZE / 0x200 + 1)) {
  222. printf("Bogus page!\n");
  223. return false;
  224. }
  225. pBuffer = (USHORT *)((BYTE *)pHdr + 0x1fe);
  226. pShort = (USHORT *) ((BYTE *)pHdr + pHdr->UpdateSequenceArrayOffset);
  227. sKey = *pShort;
  228. pShort++;
  229. //this should reflect the page size
  230. if (!(pHdr->UpdateSequenceArraySize == PAGE_SIZE / 0x200 + 1)) {
  231. printf( "BadSeqSize: 0x%x\n", pHdr->UpdateSequenceArraySize );
  232. return false;
  233. }
  234. for (iIndex=0; iIndex < pHdr->UpdateSequenceArraySize - 1; iIndex++) {
  235. if (sKey != *pBuffer) {
  236. printf( "USA Mismatch: 0x%x 0x%x at offset 0x%x\n", sKey, *pBuffer, LogOffset + (iIndex+1) * 0x200 );
  237. }
  238. *pBuffer = *pShort;
  239. pBuffer = (USHORT *)((BYTE *)pBuffer + 0x200);
  240. pShort++;
  241. }
  242. return true;
  243. } // ApplySectorHdr
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Function: DumpSectorHdr
  247. //
  248. // Synopsis: Dump MultiSectorHdr
  249. //
  250. // Arguments: [pHdr] --
  251. //
  252. // Returns:
  253. //
  254. // History: 8-24-1998 benl Created
  255. //
  256. // Notes:
  257. //
  258. //----------------------------------------------------------------------------
  259. void DumpSectorHdr(PMULTI_SECTOR_HEADER pHdr)
  260. {
  261. int iIndex;
  262. USHORT * pShort = NULL;
  263. printf("Signature: %c%c%c%c\n", pHdr->Signature[0], pHdr->Signature[1],
  264. pHdr->Signature[2], pHdr->Signature[3]);
  265. printf("UpdateSequenceArrayOffset: 0x%x\n", pHdr->UpdateSequenceArrayOffset);
  266. printf("UpdateSequenceArraySize: 0x%x\n", pHdr->UpdateSequenceArraySize);
  267. pShort = (USHORT *) ((BYTE *)pHdr + pHdr->UpdateSequenceArrayOffset);
  268. for (iIndex=0; iIndex < pHdr->UpdateSequenceArraySize; iIndex++) {
  269. printf("0x%x ", *pShort);
  270. pShort++;
  271. }
  272. printf("\n");
  273. } // DumpSectorHdr
  274. //+---------------------------------------------------------------------------
  275. //
  276. // Function: DumpRestartPage
  277. //
  278. // Synopsis: Dumps a lfs restart record page
  279. //
  280. // Arguments: [lpBuffer] --
  281. //
  282. // Returns:
  283. //
  284. // History: 8-24-1998 benl Created
  285. //
  286. // Notes:
  287. //
  288. //----------------------------------------------------------------------------
  289. void DumpRestartPage(BYTE * lpBuffer)
  290. {
  291. PLFS_RESTART_PAGE_HEADER pRestartHdr = (PLFS_RESTART_PAGE_HEADER) lpBuffer;
  292. PLFS_RESTART_AREA pLfsRestart = 0;
  293. int iIndex;
  294. PLFS_CLIENT_RECORD pClient = 0;
  295. printf("Restart Page\n");
  296. printf("ChkDskLsn: 0x%I64x\n", pRestartHdr->ChkDskLsn);
  297. printf("LogPageSize: 0x%x\n", pRestartHdr->LogPageSize);
  298. pLfsRestart = (PLFS_RESTART_AREA) (lpBuffer + pRestartHdr->RestartOffset);
  299. printf("\nLFS Restart Area\n");
  300. printf("CurrentLsn: 0x%I64x\n", pLfsRestart->CurrentLsn);
  301. printf("LogClients: %d\n", pLfsRestart->LogClients);
  302. printf("Flags: 0x%x\n", pLfsRestart->Flags);
  303. printf("LogPage RecordHeaderLength: 0x%x\n", pLfsRestart->RecordHeaderLength);
  304. printf("SeqNumberBits: 0x%x\n", pLfsRestart->SeqNumberBits);
  305. printf("LogFileSize: 0x%I64x\n", pLfsRestart->FileSize);
  306. printf("\nClients\n");
  307. pClient = (PLFS_CLIENT_RECORD)((BYTE *)pLfsRestart + pLfsRestart->ClientArrayOffset);
  308. for (iIndex=0; iIndex < pLfsRestart->LogClients; iIndex++) {
  309. printf("Name: %*S\n", pClient->ClientNameLength, pClient->ClientName);
  310. printf("OldestLsn: 0x%I64x\n", pClient->OldestLsn);
  311. printf("ClientRestartLsn: 0x%I64x\n", pClient->ClientRestartLsn);
  312. pClient = pClient++;
  313. }
  314. } // DumpRestartPage
  315. //+---------------------------------------------------------------------------
  316. //
  317. // Function: DumpOpenAttributeTable
  318. //
  319. // Synopsis: Dump the open attr table
  320. //
  321. // Arguments: [PRESTART_TABLE] --
  322. //
  323. // Returns:
  324. //
  325. // History: 8-28-1998 benl Created
  326. //
  327. // Notes:
  328. //
  329. //----------------------------------------------------------------------------
  330. void DumpOpenAttributeTable(PRESTART_TABLE pRestartTable)
  331. {
  332. POPEN_ATTRIBUTE_ENTRY_V0 pEntry = 0;
  333. int iIndex;
  334. printf("\nOpenAttributeTable\n");
  335. printf("EntrySize: 0x%x\n", pRestartTable->EntrySize);
  336. printf("NumberEntries: 0x%x\n", pRestartTable->NumberEntries);
  337. printf("NumberAllocated: 0x%x\n\n", pRestartTable->NumberAllocated);
  338. pEntry = (POPEN_ATTRIBUTE_ENTRY_V0)((BYTE *)pRestartTable + sizeof(RESTART_TABLE));
  339. for (iIndex=0; iIndex < pRestartTable->NumberEntries; iIndex++) {
  340. printf("Entry 0x%x\n", (BYTE *)pEntry - (BYTE *)pRestartTable);
  341. if (pEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  342. printf("FileRef: 0x%I64x\n", pEntry->FileReference);
  343. printf("LsnOfOpenRecord: 0x%I64x\n", pEntry->LsnOfOpenRecord);
  344. printf("AttributeTypeCode: 0x%x\n", pEntry->AttributeTypeCode);
  345. // printf("AttributeName: 0x%x 0x%x\n\n",
  346. // pEntry->AttributeName.Length,
  347. // pEntry->AttributeName.Buffer);
  348. } else {
  349. printf("free\n");
  350. }
  351. pEntry++;
  352. printf("\n");
  353. }
  354. } // DumpOpenAttributeTable
  355. //+---------------------------------------------------------------------------
  356. //
  357. // Function: DumpAttributeNames
  358. //
  359. // Synopsis: Dump the attribute names
  360. //
  361. // Arguments: [pNameEntry] --
  362. //
  363. // Returns:
  364. //
  365. // History: 8-28-1998 benl Created
  366. //
  367. // Notes:
  368. //
  369. //----------------------------------------------------------------------------
  370. void DumpAttributeNames(PATTRIBUTE_NAME_ENTRY pNameEntry, int TableSize)
  371. {
  372. int cTraversed = 0;
  373. printf("\nAttributeNames\n");
  374. while (pNameEntry->Index != 0 || pNameEntry->NameLength != 0) {
  375. if (cTraversed >= TableSize) {
  376. printf("Table appears invalid\n");
  377. break;
  378. }
  379. printf("Index: 0x%x\n", pNameEntry->Index);
  380. printf("Name: %.*S\n", pNameEntry->NameLength / 2, pNameEntry->Name);
  381. cTraversed += sizeof(ATTRIBUTE_NAME_ENTRY) + pNameEntry->NameLength;
  382. pNameEntry = (PATTRIBUTE_NAME_ENTRY) ((BYTE *) pNameEntry +
  383. sizeof(ATTRIBUTE_NAME_ENTRY) + pNameEntry->NameLength);
  384. printf("\n");
  385. }
  386. } // DumpAttributeNames
  387. //+---------------------------------------------------------------------------
  388. //
  389. // Function: DumpOpenAttribute
  390. //
  391. // Synopsis:
  392. //
  393. // Arguments: [pEntry] --
  394. // [pName] --
  395. // [cNameLen] --
  396. //
  397. // Returns:
  398. //
  399. // History: 9-09-1998 benl Created
  400. //
  401. // Notes:
  402. //
  403. //----------------------------------------------------------------------------
  404. void DumpOpenAttribute(POPEN_ATTRIBUTE_ENTRY_V0 pEntry, WCHAR * pName,
  405. int cNameLen)
  406. {
  407. int iTemp = cNameLen / 2;
  408. printf("\n");
  409. if (pEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  410. printf("FileRef: 0x%I64x\n", pEntry->FileReference);
  411. printf("LsnOfOpenRecord: 0x%I64x\n", pEntry->LsnOfOpenRecord);
  412. printf("AttributeTypeCode: 0x%x\n", pEntry->AttributeTypeCode);
  413. if (cNameLen) {
  414. printf("Name: %.*S\n", iTemp, pName);
  415. }
  416. } else {
  417. printf("free\n");
  418. }
  419. printf("\n");
  420. } // DumpOpenAttribute
  421. //+---------------------------------------------------------------------------
  422. //
  423. // Function: DumpOpenAttributeTable
  424. //
  425. // Synopsis: Dump the open attr table
  426. //
  427. // Arguments: [PRESTART_TABLE] --
  428. //
  429. // Returns:
  430. //
  431. // History: 8-28-1998 benl Created
  432. //
  433. // Notes:
  434. //
  435. //----------------------------------------------------------------------------
  436. void DumpDirtyPageTable(PRESTART_TABLE pRestartTable)
  437. {
  438. PDIRTY_PAGE_ENTRY_V0 pEntry = 0;
  439. int iIndex;
  440. DWORD iIndex2;
  441. printf("\nDirtyPageTable\n");
  442. printf("EntrySize: 0x%x\n", pRestartTable->EntrySize);
  443. printf("NumberEntries: 0x%x\n", pRestartTable->NumberEntries);
  444. printf("NumberAllocated: 0x%x\n\n", pRestartTable->NumberAllocated);
  445. pEntry = (PDIRTY_PAGE_ENTRY_V0)((BYTE *)pRestartTable + sizeof(RESTART_TABLE));
  446. for (iIndex=0; iIndex < pRestartTable->NumberEntries; iIndex++) {
  447. if (pEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  448. printf("Entry 0x%x\n", (BYTE *)pEntry - (BYTE *)pRestartTable);
  449. printf("TargetAttribute: 0x%x\n", pEntry->TargetAttribute);
  450. printf("LengthOfTransfer: 0x%x\n", pEntry->LengthOfTransfer);
  451. printf("VCN: 0x%I64x\n", pEntry->Vcn);
  452. printf("OldestLsn: 0x%I64x\n", pEntry->OldestLsn);
  453. printf("Lcns: ");
  454. for (iIndex2=0; iIndex2 < pEntry->LcnsToFollow; iIndex2++) {
  455. printf("0x%I64x ", pEntry->LcnsForPage[iIndex2]);
  456. }
  457. printf("\n\n");
  458. pEntry = (PDIRTY_PAGE_ENTRY_V0)((BYTE *)pEntry + sizeof(DIRTY_PAGE_ENTRY_V0) - sizeof(LCN) +
  459. pEntry->LcnsToFollow * sizeof(LCN));
  460. } else {
  461. pEntry = (PDIRTY_PAGE_ENTRY_V0)((BYTE *)pEntry + sizeof(DIRTY_PAGE_ENTRY_V0));
  462. // printf("0x%x free: 0x%x\n\n", iIndex, pEntry->AllocatedOrNextFree);
  463. }
  464. // printf("\n");
  465. }
  466. } // DumpOpenAttributeTable
  467. //+---------------------------------------------------------------------------
  468. //
  469. // Function: DumpTransactionTable
  470. //
  471. // Synopsis:
  472. //
  473. // Arguments: [pRestartTable] --
  474. //
  475. // Returns:
  476. //
  477. // History: 9-11-1998 benl Created
  478. //
  479. // Notes:
  480. //
  481. //----------------------------------------------------------------------------
  482. void DumpTransactionTable(PRESTART_TABLE pRestartTable)
  483. {
  484. PTRANSACTION_ENTRY pEntry = 0;
  485. int iIndex;
  486. int iIndex2;
  487. printf("\nTransactionTable\n");
  488. printf("EntrySize: 0x%x\n", pRestartTable->EntrySize);
  489. printf("NumberEntries: 0x%x\n", pRestartTable->NumberEntries);
  490. printf("NumberAllocated: 0x%x\n\n", pRestartTable->NumberAllocated);
  491. pEntry = (PTRANSACTION_ENTRY)((BYTE *)pRestartTable + sizeof(RESTART_TABLE));
  492. for (iIndex=0; iIndex < pRestartTable->NumberEntries; iIndex++) {
  493. if (pEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  494. printf("Entry 0x%x\n", (BYTE *)pEntry - (BYTE *)pRestartTable);
  495. printf("TransactionState: 0x%x (%s)\n", pEntry->TransactionState,
  496. pEntry->TransactionState < gcTransStateMap ? gTransStateMap[pEntry->TransactionState] : "");
  497. printf("FirstLsn: 0x%I64x\n", pEntry->FirstLsn.QuadPart);
  498. printf("PreviousLsn: 0x%I64x\n", pEntry->PreviousLsn.QuadPart);
  499. printf("UndoNextLsn: 0x%I64x\n", pEntry->UndoNextLsn.QuadPart);
  500. printf("UndoRecords: 0x%x\n", pEntry->UndoRecords);
  501. printf("\n");
  502. }
  503. pEntry = (PTRANSACTION_ENTRY)((BYTE *)pEntry + sizeof(TRANSACTION_ENTRY));
  504. // printf("\n");
  505. }
  506. } // DumpTransactionTable
  507. //+---------------------------------------------------------------------------
  508. //
  509. // Function: DumpMappingPair
  510. //
  511. // Synopsis:
  512. //
  513. // Arguments: [Buffer] --
  514. // [Length] --
  515. //
  516. // Returns:
  517. //
  518. // History: 5-02-2000 benl Created
  519. //
  520. // Notes:
  521. //
  522. //----------------------------------------------------------------------------
  523. void DumpMappingPairs(PVOID Buffer, ULONG Length)
  524. {
  525. BYTE * TempByte;
  526. BYTE * OldStart = NULL;
  527. ULONG ChangedLCNBytes;
  528. ULONG ChangedVCNBytes;
  529. ULONG Increment;
  530. ULONG Index;
  531. ULONG Increment2;
  532. ULONG LCN = 0;
  533. ULONG VCN = 0;
  534. //
  535. // Try To Find Start
  536. //
  537. for (Index=0; Index < Length; Index++) {
  538. TempByte = ((BYTE *)Buffer) + Index;
  539. while ((TempByte <= (BYTE*)Buffer + Length) && (*TempByte != 0)) {
  540. ChangedLCNBytes = *TempByte >> 4;
  541. ChangedVCNBytes = *TempByte & (0x0f);
  542. if ((ChangedVCNBytes > 3) ||
  543. (ChangedLCNBytes > sizeof( LONGLONG )) || (ChangedVCNBytes > sizeof( LONGLONG ))) {
  544. //
  545. // set tempbyte so we'll loop again if possible
  546. //
  547. TempByte = (BYTE*)Buffer + Length + 1;
  548. break;
  549. }
  550. TempByte += (ChangedLCNBytes + ChangedVCNBytes + 1);
  551. }
  552. if ((TempByte <= (BYTE*)Buffer + Length) && ((TempByte - (BYTE *)Buffer) > (LONG)Length - 8 )) {
  553. break;
  554. }
  555. }
  556. if (Index >= Length) {
  557. return;
  558. }
  559. printf( "Starting at offset: 0x%x\n", Index );
  560. TempByte = (BYTE *)Buffer + Index;
  561. //
  562. // walk byte stream
  563. //
  564. while(*TempByte != 0)
  565. {
  566. ChangedLCNBytes = *TempByte >> 4;
  567. ChangedVCNBytes = *TempByte & (0x0f);
  568. TempByte++;
  569. for(Increment=0, Index=0; Index < ChangedVCNBytes; Index++)
  570. {
  571. Increment+= *TempByte++ << (8 * Index);
  572. }
  573. for(Increment2 =0, Index=0; Index < ChangedLCNBytes; Index++)
  574. {
  575. Increment2+= *TempByte++ << (8 * Index);
  576. }
  577. //
  578. // if last bit is set (this is a neg) extend with 0xff
  579. //
  580. if (0x80 & (*(TempByte-1)))
  581. {
  582. for(; Index < sizeof(Increment2) ; Index++)
  583. {
  584. Increment2 += 0xff << (8 * Index);
  585. }
  586. }
  587. LCN += Increment2;
  588. printf( "LCN delta: 0x%x VCN delta: 0x%x ", Increment2, Increment );
  589. for (Index = ChangedLCNBytes + ChangedVCNBytes + 1; Index > 0; Index--) {
  590. printf( "%02x", *(TempByte - Index));
  591. }
  592. printf( "\n" );
  593. VCN += Increment;
  594. } //endwhile
  595. printf("Total LcnDelta: 0x%x Total VCNDelta: 0x%x\n", LCN, VCN );
  596. } // DumpMappingPair
  597. //+---------------------------------------------------------------------------
  598. //
  599. // Function: DumpLogRecord
  600. //
  601. // Synopsis: Dumps log records
  602. //
  603. // Arguments: [pRecord] -- record to dump
  604. // [pAttrMap] -- ptr to open attribute table to use to translate
  605. // TargetAttribute - if null no translation is done
  606. //
  607. // Returns:
  608. //
  609. // History: 8-24-1998 benl Created
  610. // 9-09-1998 benl modified
  611. //
  612. // Notes: either is a regular client record or a client restart area
  613. //
  614. //----------------------------------------------------------------------------
  615. void DumpLogRecord(PLFS_RECORD_HEADER pRecord, OPEN_ATTR_MAP * pAttrMap)
  616. {
  617. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  618. int iIndex;
  619. BYTE * pData = 0;
  620. PRESTART_TABLE pRestartTable = 0;
  621. PATTRIBUTE_NAME_ENTRY pNameEntry = 0;
  622. POPEN_ATTRIBUTE_ENTRY_V0 pAttrEntry;
  623. LPWSTR lpName;
  624. MYENTRY * pEntry;
  625. PRESTART_AREA pRestartArea;
  626. printf("ThisLsn, PrevLsn, UndoLsn: 0x%I64x 0x%I64x 0x%I64x\n",
  627. pRecord->ThisLsn, pRecord->ClientPreviousLsn,
  628. pRecord->ClientUndoNextLsn);
  629. printf("Flags: 0x%x %s\n", pRecord->Flags, pRecord->Flags & LOG_RECORD_MULTI_PAGE ? "(multi-page)" : "");
  630. printf("ClientDataLength: 0x%x\n", pRecord->ClientDataLength);
  631. printf("TransactionId: 0x%x\n", pRecord->TransactionId);
  632. if (pRecord->RecordType == LfsClientRecord) {
  633. if (pRecord->ClientDataLength) {
  634. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  635. sizeof(LFS_RECORD_HEADER));
  636. printf("Redo, Undo: (0x%x, 0x%x) (", pNtfsLog->RedoOperation,
  637. pNtfsLog->UndoOperation);
  638. if (pNtfsLog->RedoOperation < gcOpMap ) {
  639. printf("%s, ", gOpMap[pNtfsLog->RedoOperation]);
  640. } else {
  641. printf("unknown, ");
  642. }
  643. if (pNtfsLog->UndoOperation < gcOpMap ) {
  644. printf("%s)\n", gOpMap[pNtfsLog->UndoOperation]);
  645. } else {
  646. printf("unknown)\n");
  647. }
  648. printf("RedoOffset RedoLength: (0x%x 0x%x)\n",
  649. pNtfsLog->RedoOffset, pNtfsLog->RedoLength);
  650. printf("UndoOffset UndoLength: (0x%x 0x%x)\n",
  651. pNtfsLog->UndoOffset, pNtfsLog->UndoLength);
  652. // printf("0x%x 0x%x 0x%x 0x%x\n",pNtfsLog->RedoOffset,
  653. // pNtfsLog->RedoLength, pNtfsLog->UndoLength, pNtfsLog->UndoOffset);
  654. printf("TargetAttribute: 0x%x\n", pNtfsLog->TargetAttribute);
  655. printf("RecordOffset: 0x%x\n", pNtfsLog->RecordOffset);
  656. printf("AttributeOffset: 0x%x\n", pNtfsLog->AttributeOffset);
  657. printf("ClusterBlockOffset: 0x%x\n", pNtfsLog->ClusterBlockOffset);
  658. printf("TargetVcn: 0x%I64x\n", pNtfsLog->TargetVcn);
  659. //
  660. // If we were given an open attr map attempt to get the fileref from the
  661. // target attribute
  662. //
  663. if (pAttrMap) {
  664. pEntry = pAttrMap->Lookup(pNtfsLog->TargetAttribute);
  665. if (pEntry) {
  666. printf("FileRef: 0x%I64x\n", pEntry->llFileRef);
  667. printf("Attribute: 0x%x\n", pEntry->AttrType);
  668. }
  669. }
  670. //
  671. // Dump open-attr table
  672. //
  673. if (pNtfsLog->RedoOperation == OpenAttributeTableDump) {
  674. pRestartTable = (PRESTART_TABLE)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  675. DumpOpenAttributeTable(pRestartTable);
  676. }
  677. if (pNtfsLog->RedoOperation == AttributeNamesDump) {
  678. pNameEntry = (PATTRIBUTE_NAME_ENTRY)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  679. DumpAttributeNames(pNameEntry, pNtfsLog->RedoLength);
  680. }
  681. if (pNtfsLog->RedoOperation == OpenNonresidentAttribute) {
  682. pAttrEntry = (POPEN_ATTRIBUTE_ENTRY_V0)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  683. lpName = (LPWSTR)((BYTE *)pNtfsLog + pNtfsLog->UndoOffset);
  684. DumpOpenAttribute(pAttrEntry, lpName, pNtfsLog->UndoLength);
  685. }
  686. if (pNtfsLog->RedoOperation == DirtyPageTableDump) {
  687. pRestartTable = (PRESTART_TABLE)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  688. DumpDirtyPageTable(pRestartTable);
  689. }
  690. if (pNtfsLog->RedoOperation == TransactionTableDump) {
  691. pRestartTable = (PRESTART_TABLE)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  692. DumpTransactionTable(pRestartTable);
  693. }
  694. if (pNtfsLog->LcnsToFollow > WARNING_SIZE) {
  695. printf("LcnsToFollow: 0x%x is abnormally high probably not a valid record\n",
  696. pNtfsLog->LcnsToFollow);
  697. } else {
  698. printf("LcnsForPage: ");
  699. for (iIndex=0; iIndex < pNtfsLog->LcnsToFollow; iIndex++) {
  700. printf("0x%I64x ", pNtfsLog->LcnsForPage[iIndex]);
  701. }
  702. }
  703. printf("\n");
  704. if (gfDumpData) {
  705. //
  706. // Its usually more useful to dump dwords except for the update
  707. // filemappings case where its better to dump as bytes. If more
  708. // exceptions popup make this logic a little nicer
  709. //
  710. if (pNtfsLog->RedoOperation && pNtfsLog->RedoLength) {
  711. printf("Redo bytes\n");
  712. pData = (BYTE *)pNtfsLog + pNtfsLog->RedoOffset;
  713. if (pNtfsLog->RedoOperation == UpdateMappingPairs ) {
  714. DumpRawBytes(pData, pNtfsLog->RedoLength);
  715. } else {
  716. DumpRawDwords((DWORD *)pData, pNtfsLog->RedoLength);
  717. }
  718. /*
  719. if (pNtfsLog->RedoOperation == UpdateMappingPairs) {
  720. printf("\n");
  721. DumpMappingPairs( pData, pNtfsLog->RedoLength );
  722. printf("\n");
  723. }
  724. */
  725. }
  726. if (pNtfsLog->UndoOperation && pNtfsLog->UndoLength) {
  727. printf("Undo bytes\n");
  728. pData = (BYTE *)pNtfsLog + pNtfsLog->UndoOffset;
  729. if (pNtfsLog->RedoOperation == UpdateMappingPairs ) {
  730. DumpRawBytes(pData, pNtfsLog->UndoLength);
  731. } else {
  732. DumpRawDwords((DWORD *)pData, pNtfsLog->UndoLength);
  733. }
  734. /*
  735. if (pNtfsLog->UndoOperation == UpdateMappingPairs) {
  736. printf("\n");
  737. DumpMappingPairs( pData, pNtfsLog->UndoLength );
  738. printf("\n");
  739. }
  740. */
  741. }
  742. }
  743. }
  744. } else if (pRecord->RecordType == LfsClientRestart) {
  745. printf("\nClient Restart Record\n");
  746. pRestartArea = (PRESTART_AREA) ( (BYTE *)pRecord + sizeof(LFS_RECORD_HEADER) );
  747. printf( "Major, Minor Version: 0x%x,0x%x\n",
  748. pRestartArea->MajorVersion,
  749. pRestartArea->MinorVersion
  750. );
  751. printf( "StartOfCheckpoint: 0x%8I64x\n\n", pRestartArea->StartOfCheckpoint );
  752. printf( "OpenAttributeTableLsn: 0x%08I64x 0x%x bytes\n",
  753. pRestartArea->OpenAttributeTableLsn,
  754. pRestartArea->OpenAttributeTableLength
  755. );
  756. printf( "AttributeNamesLsn: 0x%08I64x 0x%x bytes\n",
  757. pRestartArea->AttributeNamesLsn,
  758. pRestartArea->AttributeNamesLength
  759. );
  760. printf( "DirtyPageTableLsn: 0x%08I64x 0x%x bytes\n",
  761. pRestartArea->DirtyPageTableLsn,
  762. pRestartArea->DirtyPageTableLength
  763. );
  764. printf( "TransactionTableLsn: 0x%08I64x 0x%x bytes\n",
  765. pRestartArea->TransactionTableLsn,
  766. pRestartArea->TransactionTableLength
  767. );
  768. printf( "\nLowestOpenUsn: 0x%I64x\n", pRestartArea->LowestOpenUsn );
  769. //
  770. // Older logs don't have these 2 fields
  771. //
  772. if (pRecord->ClientDataLength >= FIELD_OFFSET(RESTART_AREA, CurrentLsnAtMount)) {
  773. printf( "CurrentLsnAtMount: 0x%I64x\n", pRestartArea->CurrentLsnAtMount );
  774. printf( "BytesPerCluster: 0x%x\n", pRestartArea->BytesPerCluster );
  775. }
  776. }
  777. } // DumpLogRecord
  778. //+---------------------------------------------------------------------------
  779. //
  780. // Function: DumpRecordPage
  781. //
  782. // Synopsis: Dump page header for a record page
  783. //
  784. // Arguments: [lpBuffer] --
  785. //
  786. // Returns:
  787. //
  788. // History: 8-24-1998 benl Created
  789. //
  790. // Notes:
  791. //
  792. //----------------------------------------------------------------------------
  793. void DumpRecordPage(BYTE * lpBuffer)
  794. {
  795. PLFS_RECORD_PAGE_HEADER pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  796. PLFS_RECORD_HEADER pRecord = 0;
  797. INT iNextRecord;
  798. printf("Record Page\n");
  799. // printf("LastLsn: 0x%I64x\n", pHdr->Copy.LastLsn);
  800. printf("Flags: 0x%x %s\n", pHdr->Flags, pHdr->Flags & LOG_PAGE_LOG_RECORD_END ?
  801. "(record end in page)" : "");
  802. printf("LastEndLsn: 0x%I64x (0x%x)\n", pHdr->Header.Packed.LastEndLsn,
  803. ((pHdr->Header.Packed.LastEndLsn.LowPart << 3) & 0xfff));
  804. // printf("0x%x\n", (pHdr->Header.Packed.LastEndLsn.QuadPart << gSeqNumberBits) >> (gSeqNumberBits - 3));
  805. printf("NextRecordOffset: 0x%x\n", pHdr->Header.Packed.NextRecordOffset);
  806. iNextRecord = (pHdr->Header.Packed.LastEndLsn.LowPart << 3) & (LOG_PAGE - 1);
  807. pRecord = (PLFS_RECORD_HEADER)(lpBuffer + iNextRecord);
  808. DumpLogRecord(pRecord, NULL);
  809. } // DumpRecordPage
  810. //+---------------------------------------------------------------------------
  811. //
  812. // Function: DumpPage
  813. //
  814. // Synopsis: Dump out the given page of the logfile
  815. //
  816. // Arguments: [lpBuffer] -- page sized buffer in log
  817. //
  818. // Returns:
  819. //
  820. // History: 8-24-1998 benl Created
  821. // 8-24-1998 benl modified
  822. //
  823. // Notes:
  824. //
  825. //----------------------------------------------------------------------------
  826. void DumpPage(BYTE * lpBuffer)
  827. {
  828. PMULTI_SECTOR_HEADER pMultiHdr = (PMULTI_SECTOR_HEADER) lpBuffer;
  829. // DumpSectorHdr(pMultiHdr);
  830. //
  831. // Determine the record type
  832. //
  833. if (strncmp((char *)(pMultiHdr->Signature), "RSTR", 4) == 0) {
  834. DumpRestartPage(lpBuffer);
  835. } else if (strncmp((char *)(pMultiHdr->Signature), "RCRD", 4) == 0) {
  836. DumpRecordPage(lpBuffer);
  837. }
  838. } // DumpPage
  839. //+---------------------------------------------------------------------------
  840. //
  841. // Function: DumpPageLastLsns
  842. //
  843. // Synopsis: Dump the last LSN in all the pages in the logfile
  844. //
  845. // Arguments: [hFile] --
  846. //
  847. // Returns:
  848. //
  849. // History: 8-25-1998 benl Created
  850. //
  851. // Notes: Used for debug purposes only right now
  852. //
  853. //----------------------------------------------------------------------------
  854. void DumpPageLastLsns(HANDLE hFile)
  855. {
  856. BYTE lpBuffer[LOG_PAGE];
  857. DWORD dwRead;
  858. OVERLAPPED ol;
  859. PLFS_RECORD_PAGE_HEADER pHdr;
  860. PLFS_RECORD_PAGE_HEADER pNextHdr;
  861. PLFS_RECORD_HEADER pRecord;
  862. int cbOffset;
  863. LSN lsn;
  864. int cbOffsetNext;
  865. memset(&ol, 0, sizeof(ol));
  866. ol.Offset = LOG_PAGE * 4;
  867. while (ol.Offset) {
  868. if (!ReadFile(hFile, lpBuffer, LOG_PAGE, &dwRead, &ol)) {
  869. printf("ReadFile failed %d\n", GetLastError());
  870. return;
  871. }
  872. if (dwRead != LOG_PAGE) {
  873. printf("Only read: 0x%x\n", dwRead);
  874. return;
  875. }
  876. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  877. {
  878. break;
  879. }
  880. // DumpPage(lpBuffer);
  881. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  882. MYASSERT(pHdr->Header.Packed.NextRecordOffset <= LOG_PAGE);
  883. if (strncmp((CHAR *)(pHdr->MultiSectorHeader.Signature), "RCRD", 4) != 0) {
  884. printf("Not record at 0x%x!\n", ol.Offset);
  885. } else {
  886. printf("0x%x: LastEndLsn: 0x%I64x NextFreeOffset: 0x%x Flags: 0x%x \n", ol.Offset, pHdr->Header.Packed.LastEndLsn.QuadPart, pHdr->Header.Packed.NextRecordOffset,
  887. pHdr->Flags);
  888. }
  889. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  890. }
  891. } // DumpLastLsns
  892. //+---------------------------------------------------------------------------
  893. //
  894. // Function: ScanForLastLsn
  895. //
  896. // Synopsis: Starting from the current lsn hint walk fwd until we find the
  897. // the last lsn
  898. //
  899. // Arguments: [CurrentLsnHint] -- hint on where to start looking from
  900. //
  901. // Returns: last lsn in logfile
  902. //
  903. // History: 8-25-1998 benl Created
  904. //
  905. // Notes:
  906. //
  907. //----------------------------------------------------------------------------
  908. LSN ScanForLastLsn(HANDLE hFile, LSN CurrentLsnHint)
  909. {
  910. BYTE lpBuffer[LOG_PAGE];
  911. DWORD dwRead;
  912. LSN LsnMax;
  913. OVERLAPPED ol;
  914. PLFS_RECORD_PAGE_HEADER pHdr;
  915. PLFS_RECORD_HEADER pNextRecord = 0;
  916. LsnMax.QuadPart = 0;
  917. memset(&ol, 0, sizeof(ol));
  918. //
  919. // Start 1 page before the hint
  920. //
  921. if (CurrentLsnHint.QuadPart) {
  922. ol.Offset = (ULONG)((LsnToOffset(CurrentLsnHint.QuadPart) & (~(LOG_PAGE - 1))) - LOG_PAGE);
  923. } else {
  924. ol.Offset = LOG_PAGE * 4;
  925. }
  926. // printf("Starting at: Lsn: 0x%I64x Offset: 0x%x\n", CurrentLsnHint, ol.Offset);
  927. while (true) {
  928. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  929. LsnMax.QuadPart = 0;
  930. return LsnMax;
  931. }
  932. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  933. {
  934. break;
  935. }
  936. // DumpPage(lpBuffer);
  937. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  938. if (strncmp((CHAR *)(pHdr->MultiSectorHeader.Signature), "RCRD", 4) != 0) {
  939. // printf("Not record at 0x%x!\n", ol.Offset);
  940. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  941. } else {
  942. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END) {
  943. // printf("0x%x: LastEndLsn: 0x%I64x\n", ol.Offset, pHdr->Header.Packed.LastEndLsn.QuadPart);
  944. if (pHdr->Header.Packed.LastEndLsn.QuadPart >= LsnMax.QuadPart) {
  945. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  946. LsnMax.QuadPart = pHdr->Header.Packed.LastEndLsn.QuadPart;
  947. //check the next one if there is one in this page
  948. if (pHdr->Header.Packed.NextRecordOffset < LOG_PAGE - sizeof(LFS_RECORD_HEADER)) {
  949. pNextRecord = (PLFS_RECORD_HEADER)(lpBuffer + pHdr->Header.Packed.NextRecordOffset);
  950. if (pNextRecord->ThisLsn.QuadPart > LsnMax.QuadPart) {
  951. LsnMax.QuadPart = pNextRecord->ThisLsn.QuadPart;
  952. }
  953. }
  954. } else {
  955. break;
  956. }
  957. } else {
  958. // printf("0x%x: NoEndingLsn\n", ol.Offset);
  959. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  960. }
  961. }
  962. }
  963. return LsnMax;
  964. } // ScanForLast
  965. //+---------------------------------------------------------------------------
  966. //
  967. // Function: ScanForFirstLsn
  968. //
  969. // Synopsis: Returns earliest LSN in file
  970. //
  971. // Arguments: [hFile] -- logfile handle
  972. // [Verbose] --
  973. //
  974. // Returns: lsn or 0 if failure occurs
  975. //
  976. // History: 8-25-1998 benl Created
  977. // 7-29-1999 benl modified
  978. //
  979. // Notes: Be ca
  980. //
  981. //----------------------------------------------------------------------------
  982. LSN ScanForFirstLsn(HANDLE hFile, bool Verbose)
  983. {
  984. BYTE lpBuffer[LOG_PAGE];
  985. DWORD dwRead;
  986. OVERLAPPED ol;
  987. PLFS_RECORD_PAGE_HEADER pHdr;
  988. PLFS_RECORD_PAGE_HEADER pNextHdr;
  989. PLFS_RECORD_HEADER pRecord;
  990. int cbOffset;
  991. LSN LsnMin;
  992. int cbOffsetNext;
  993. memset(&ol, 0, sizeof(ol));
  994. ol.Offset = LOG_PAGE * 4;
  995. LsnMin.QuadPart = 0;
  996. while (ol.Offset) {
  997. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  998. LsnMin.QuadPart = 0;
  999. return LsnMin;
  1000. }
  1001. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1002. {
  1003. break;
  1004. }
  1005. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  1006. /*
  1007. if (pHdr->Header.Packed.NextRecordOffset > LOG_PAGE) {
  1008. printf("0x%x 0x%x\n", pHdr->Header.Packed.NextRecordOffset,
  1009. ol.Offset );
  1010. }
  1011. MYASSERT(pHdr->Header.Packed.NextRecordOffset <= LOG_PAGE);
  1012. */
  1013. if (strncmp((CHAR *)(pHdr->MultiSectorHeader.Signature), "RCRD", 4) == 0) {
  1014. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END && Verbose) {
  1015. printf( "0x%x: LastEndLsn: 0x%I64x NextFreeOffset: 0x%x Flags: 0x%x SeqNum: 0x%x \n", ol.Offset, pHdr->Header.Packed.LastEndLsn.QuadPart, pHdr->Header.Packed.NextRecordOffset,
  1016. pHdr->Flags, LsnToSequenceNumber( pHdr->Header.Packed.LastEndLsn.QuadPart ) );
  1017. }
  1018. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END) {
  1019. if (LsnMin.QuadPart) {
  1020. if (LsnMin.QuadPart > pHdr->Header.Packed.LastEndLsn.QuadPart) {
  1021. //
  1022. // If the last end lsn started before this page then its gone
  1023. // since the page before this must have had a larger min lsn
  1024. // so use the next lsn we find instead
  1025. //
  1026. if (LsnToOffset( pHdr->Header.Packed.LastEndLsn.QuadPart ) > ol.Offset ) {
  1027. LsnMin.QuadPart = pHdr->Header.Packed.LastEndLsn.QuadPart;
  1028. }
  1029. }
  1030. // LsnMin.QuadPart = min(LsnMin.QuadPart, pHdr->Header.Packed.LastEndLsn.QuadPart);
  1031. } else {
  1032. LsnMin.QuadPart = pHdr->Header.Packed.LastEndLsn.QuadPart;
  1033. }
  1034. }
  1035. }
  1036. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  1037. }
  1038. return LsnMin;
  1039. } // ScanForFirstLsn
  1040. //+---------------------------------------------------------------------------
  1041. //
  1042. // Function: ScanForFirstLsn
  1043. //
  1044. // Synopsis: Returns earliest LSN in file
  1045. //
  1046. // Arguments: [hFile] -- logfile handle
  1047. //
  1048. // Returns: lsn or 0 if failure occurs
  1049. //
  1050. // History: 8-25-1998 benl Created
  1051. //
  1052. // Notes: Be ca
  1053. //
  1054. //----------------------------------------------------------------------------
  1055. LSN ScanForNextLsn(HANDLE hFile, LSN LsnStart )
  1056. {
  1057. BYTE lpBuffer[LOG_PAGE];
  1058. DWORD dwRead;
  1059. OVERLAPPED ol;
  1060. PLFS_RECORD_PAGE_HEADER pHdr;
  1061. PLFS_RECORD_PAGE_HEADER pNextHdr;
  1062. PLFS_RECORD_HEADER pRecord;
  1063. int cbOffset;
  1064. LSN LsnMin;
  1065. int cbOffsetNext;
  1066. memset(&ol, 0, sizeof(ol));
  1067. ol.Offset = LOG_PAGE * 4;
  1068. LsnMin.QuadPart = 0x7fffffffffffffffL;
  1069. while (ol.Offset) {
  1070. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1071. LsnMin.QuadPart = LsnStart.QuadPart;
  1072. return LsnMin;
  1073. }
  1074. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1075. {
  1076. break;
  1077. }
  1078. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  1079. /*
  1080. if (pHdr->Header.Packed.NextRecordOffset > LOG_PAGE) {
  1081. printf("0x%x 0x%x\n", pHdr->Header.Packed.NextRecordOffset,
  1082. ol.Offset );
  1083. }
  1084. MYASSERT(pHdr->Header.Packed.NextRecordOffset <= LOG_PAGE);
  1085. */
  1086. if (strncmp((CHAR *)(pHdr->MultiSectorHeader.Signature), "RCRD", 4) == 0) {
  1087. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END) {
  1088. // printf( "0x%x: LastEndLsn: 0x%I64x NextFreeOffset: 0x%x Flags: 0x%x SeqNum: 0x%x \n", ol.Offset, pHdr->Header.Packed.LastEndLsn.QuadPart, pHdr->Header.Packed.NextRecordOffset,
  1089. // pHdr->Flags, LsnToSequenceNumber( pHdr->Header.Packed.LastEndLsn.QuadPart ) );
  1090. }
  1091. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END) {
  1092. if (LsnMin.QuadPart > pHdr->Header.Packed.LastEndLsn.QuadPart &&
  1093. LsnStart.QuadPart < pHdr->Header.Packed.LastEndLsn.QuadPart) {
  1094. //
  1095. // If the last end lsn started before this page then its gone
  1096. // since the page before this must have had a larger min lsn
  1097. // so use the next lsn we find instead
  1098. //
  1099. if (LsnToOffset( pHdr->Header.Packed.LastEndLsn.QuadPart ) > ol.Offset ) {
  1100. LsnMin.QuadPart = pHdr->Header.Packed.LastEndLsn.QuadPart;
  1101. }
  1102. }
  1103. }
  1104. }
  1105. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  1106. }
  1107. return LsnMin;
  1108. } // ScanForFirstLsn
  1109. //+---------------------------------------------------------------------------
  1110. //
  1111. // Function: ScanBackPagesForLastLsn
  1112. //
  1113. // Synopsis: Given an end LSN find an LSN on n pages before it
  1114. //
  1115. // Arguments: [hFile] -- logfile handle
  1116. // [CurrentLsn] -- ending lsn
  1117. // [iPageRange] -- how many pages earlier we want an lsn from
  1118. //
  1119. // Returns: LSN iPageRange pages earlier in the log from CurrentLsn
  1120. //
  1121. // History: 8-25-1998 benl Created
  1122. //
  1123. // Notes: iPageRange is treated like a hint the precise distance will vary
  1124. //
  1125. //----------------------------------------------------------------------------
  1126. LSN ScanBackPagesForLastLsn(HANDLE hFile, LSN CurrentLsn, int iPageRange)
  1127. {
  1128. BYTE lpBuffer[LOG_PAGE];
  1129. DWORD dwRead;
  1130. OVERLAPPED ol;
  1131. PLFS_RECORD_PAGE_HEADER pHdr;
  1132. LSN Lsn;
  1133. Lsn.QuadPart = 0;
  1134. memset(&ol, 0, sizeof(ol));
  1135. //
  1136. // Start iPageRange before the hint
  1137. //
  1138. ol.Offset = (ULONG)((LsnToOffset(CurrentLsn.QuadPart) & (~(LOG_PAGE - 1))) - (LOG_PAGE * iPageRange));
  1139. printf("Starting at: Offset: 0x%x\n", ol.Offset);
  1140. while (iPageRange) {
  1141. if (!ReadFile(hFile, lpBuffer, LOG_PAGE, &dwRead, &ol)) {
  1142. printf("ReadFile failed %d\n", GetLastError());
  1143. Lsn.QuadPart = 0;
  1144. return Lsn;
  1145. }
  1146. if (dwRead != LOG_PAGE) {
  1147. printf("Only read: 0x%x\n", dwRead);
  1148. Lsn.QuadPart = 0;
  1149. return Lsn;
  1150. }
  1151. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1152. {
  1153. break;
  1154. }
  1155. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  1156. if (strncmp((CHAR *)(pHdr->MultiSectorHeader.Signature), "RCRD", 4) != 0) {
  1157. printf("Not record at 0x%x!\n", ol.Offset);
  1158. } else {
  1159. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END) {
  1160. printf("0x%x: LastEndLsn: 0x%I64x\n", ol.Offset, pHdr->Header.Packed.LastEndLsn.QuadPart);
  1161. Lsn.QuadPart = pHdr->Header.Packed.LastEndLsn.QuadPart;
  1162. iPageRange--;
  1163. } else {
  1164. printf("0x%x: NoEndingLsn\n", ol.Offset);
  1165. }
  1166. }
  1167. ol.Offset = (ol.Offset - LOG_PAGE) % gLogFileSize;
  1168. }
  1169. return Lsn;
  1170. } // ScanBackPagesForLastLsn
  1171. //+---------------------------------------------------------------------------
  1172. //
  1173. // Function: AddNewAttributes
  1174. //
  1175. // Synopsis: Add any new attributes from a dump or open to the table
  1176. //
  1177. // Arguments: [pRecord] --
  1178. // [int] --
  1179. // [AttrMap] --
  1180. //
  1181. // Returns:
  1182. //
  1183. // History: 9-09-1998 benl Created
  1184. //
  1185. // Notes:
  1186. //
  1187. //----------------------------------------------------------------------------
  1188. void AddNewAttributes(PLFS_RECORD_HEADER pRecord, CMap<int, MYENTRY> & AttrMap)
  1189. {
  1190. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1191. int iIndex;
  1192. PRESTART_TABLE pRestartTable = 0;
  1193. PATTRIBUTE_NAME_ENTRY pNameEntry = 0;
  1194. POPEN_ATTRIBUTE_ENTRY_V0 pAttrEntry;
  1195. POPEN_ATTRIBUTE_ENTRY pNewAttrEntry;
  1196. LPWSTR lpName;
  1197. int iEntry;
  1198. MYENTRY MyEntry;
  1199. if (pRecord->ClientDataLength) {
  1200. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1201. sizeof(LFS_RECORD_HEADER));
  1202. if (pNtfsLog->RedoOperation == OpenAttributeTableDump) {
  1203. //
  1204. // Walk table adding allocated entries
  1205. //
  1206. pRestartTable = (PRESTART_TABLE)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  1207. pAttrEntry = (POPEN_ATTRIBUTE_ENTRY_V0)((BYTE *)pRestartTable + sizeof(RESTART_TABLE));
  1208. pNewAttrEntry = (POPEN_ATTRIBUTE_ENTRY)((BYTE *)pRestartTable + sizeof(RESTART_TABLE));
  1209. for (iIndex=0; iIndex < pRestartTable->NumberEntries; iIndex++) {
  1210. if (pRestartTable->EntrySize == sizeof( OPEN_ATTRIBUTE_ENTRY_V0 )) {
  1211. if (pAttrEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  1212. iEntry = (ULONG)((BYTE *)pAttrEntry - (BYTE *)pRestartTable);
  1213. memcpy(&(MyEntry.llFileRef), &(pAttrEntry->FileReference), sizeof(MyEntry.llFileRef));
  1214. MyEntry.AttrType = pAttrEntry->AttributeTypeCode;
  1215. if (AttrMap.Lookup(iEntry)) {
  1216. AttrMap.Replace(iEntry, MyEntry);
  1217. } else {
  1218. AttrMap.Insert(iEntry, MyEntry);
  1219. }
  1220. }
  1221. pAttrEntry++;
  1222. } else {
  1223. if (pNewAttrEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  1224. iEntry = (ULONG)((BYTE *)pNewAttrEntry - (BYTE *)pRestartTable);
  1225. memcpy(&(MyEntry.llFileRef), &(pNewAttrEntry->FileReference), sizeof(MyEntry.llFileRef));
  1226. MyEntry.AttrType = pNewAttrEntry->AttributeTypeCode;
  1227. if (AttrMap.Lookup(iEntry)) {
  1228. AttrMap.Replace(iEntry, MyEntry);
  1229. } else {
  1230. AttrMap.Insert(iEntry, MyEntry);
  1231. }
  1232. }
  1233. pNewAttrEntry++;
  1234. }
  1235. }
  1236. }
  1237. if (pNtfsLog->RedoOperation == AttributeNamesDump) {
  1238. pNameEntry = (PATTRIBUTE_NAME_ENTRY)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  1239. // DumpAttributeNames(pNameEntry, pNtfsLog->RedoLength);
  1240. }
  1241. if (pNtfsLog->RedoOperation == OpenNonresidentAttribute) {
  1242. pAttrEntry = (POPEN_ATTRIBUTE_ENTRY_V0)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  1243. lpName = (LPWSTR)((BYTE *)pNtfsLog + pNtfsLog->UndoOffset);
  1244. memcpy(&(MyEntry.llFileRef), &(pAttrEntry->FileReference), sizeof(MyEntry.llFileRef));
  1245. MyEntry.AttrType = pAttrEntry->AttributeTypeCode;
  1246. if (AttrMap.Lookup(pNtfsLog->TargetAttribute)) {
  1247. AttrMap.Replace(pNtfsLog->TargetAttribute, MyEntry);
  1248. } else {
  1249. AttrMap.Insert(pNtfsLog->TargetAttribute, MyEntry);
  1250. }
  1251. }
  1252. }
  1253. } // AddNewAttributes
  1254. //+---------------------------------------------------------------------------
  1255. //
  1256. // Function: MatchVcn
  1257. //
  1258. // Synopsis: Simple function to match a record against a VCN
  1259. //
  1260. // Arguments: [pRecord] -- ptr to head of record
  1261. // [Context] -- actually vcn ptr to match
  1262. //
  1263. // Returns: true if match
  1264. //
  1265. // History: benl Created
  1266. //
  1267. // Notes:
  1268. //
  1269. //----------------------------------------------------------------------------
  1270. bool MatchVcn(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1271. {
  1272. VCN_OFFSET * pVcnPair = (VCN_OFFSET *) Context;
  1273. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1274. bool fRet = false;
  1275. MYASSERT(pVcnPair);
  1276. if (pRecord->ClientDataLength) {
  1277. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1278. sizeof(LFS_RECORD_HEADER));
  1279. if (pNtfsLog->TargetVcn == pVcnPair->Vcn) {
  1280. if ((pVcnPair->Offset == -1) ||
  1281. (pVcnPair->Offset == pNtfsLog->ClusterBlockOffset)) {
  1282. fRet = true;
  1283. }
  1284. }
  1285. }
  1286. return fRet;
  1287. }
  1288. //+---------------------------------------------------------------------------
  1289. //
  1290. // Function: MatchFileRef
  1291. //
  1292. // Synopsis: Match a given file ref
  1293. //
  1294. // Arguments: [pRecord] -- record to test
  1295. // [Context] -- fileref to match
  1296. //
  1297. // Returns:
  1298. //
  1299. // History: 9-11-1998 benl Created
  1300. //
  1301. // Notes: Ignore SequenceNumber
  1302. //
  1303. //----------------------------------------------------------------------------
  1304. bool MatchFileRef(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1305. {
  1306. PFILEREF_MATCH_CTX pFileRefCtx = (PFILEREF_MATCH_CTX) Context;
  1307. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1308. bool fRet = false;
  1309. MYENTRY * pEntry;
  1310. PFILE_REFERENCE pFileRef1;
  1311. PFILE_REFERENCE pFileRef2;
  1312. LONGLONG llFileRef;
  1313. MYASSERT(pFileRefCtx);
  1314. pFileRef1 = (PFILE_REFERENCE) (&(pFileRefCtx->llFileRef));
  1315. AddNewAttributes(pRecord, *(pFileRefCtx->pAttrMap));
  1316. if (pRecord->ClientDataLength) {
  1317. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1318. sizeof(LFS_RECORD_HEADER));
  1319. //
  1320. // Check directly using attribute table
  1321. //
  1322. pEntry = pFileRefCtx->pAttrMap->Lookup(pNtfsLog->TargetAttribute);
  1323. if (pEntry)
  1324. {
  1325. pFileRef2 = (PFILE_REFERENCE) (&(pEntry->llFileRef));
  1326. if ((pFileRef2->SegmentNumberLowPart == pFileRef1->SegmentNumberLowPart) &&
  1327. (pFileRef2->SegmentNumberHighPart == pFileRef1->SegmentNumberHighPart)) {
  1328. fRet = true;
  1329. }
  1330. }
  1331. //
  1332. // Also check for someone with an equivalent vcn
  1333. //
  1334. if (pFileRefCtx->ClusterSize) {
  1335. llFileRef = (LONGLONG)(pFileRef1->SegmentNumberLowPart) +
  1336. ((LONGLONG)(pFileRef1->SegmentNumberHighPart) << 32);
  1337. //
  1338. // ClusterRatio is number of sector per cluster. FileRecord is 2 sectors big 0x400
  1339. //
  1340. if (pNtfsLog->TargetVcn == (llFileRef * 0x400 / pFileRefCtx->ClusterSize)) {
  1341. if (pNtfsLog->ClusterBlockOffset * 0x200 == ((llFileRef * 0x400) % pFileRefCtx->ClusterSize)) {
  1342. fRet = true;
  1343. }
  1344. }
  1345. }
  1346. }
  1347. return fRet;
  1348. } // MatchFileRef
  1349. //+---------------------------------------------------------------------------
  1350. //
  1351. // Function: MatchLcn
  1352. //
  1353. // Synopsis:
  1354. //
  1355. // Arguments: [pRecord] --
  1356. // [Context] --
  1357. //
  1358. // Returns:
  1359. //
  1360. // History: benl Created
  1361. //
  1362. // Notes:
  1363. //
  1364. //----------------------------------------------------------------------------
  1365. bool MatchLcn(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1366. {
  1367. LCN * pLCN = (LCN *) Context;
  1368. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1369. int iIndex;
  1370. bool fRet = false;
  1371. MYASSERT(pLCN);
  1372. if (pRecord->ClientDataLength) {
  1373. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1374. sizeof(LFS_RECORD_HEADER));
  1375. if (pNtfsLog->LcnsToFollow) {
  1376. for (iIndex=0; iIndex < pNtfsLog->LcnsToFollow; iIndex++) {
  1377. if (pNtfsLog->LcnsForPage[iIndex] == *pLCN) {
  1378. fRet = true;
  1379. break;
  1380. }
  1381. }
  1382. }
  1383. if (pNtfsLog->RedoOperation == SetBitsInNonresidentBitMap) {
  1384. PBITMAP_RANGE Range;
  1385. Range = (PBITMAP_RANGE)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset );
  1386. if (Range->BitMapOffset == *pLCN % 0x8000) {
  1387. fRet = true;
  1388. }
  1389. }
  1390. if (pNtfsLog->RedoOperation == DirtyPageTableDump) {
  1391. PRESTART_TABLE pRestartTable;
  1392. PDIRTY_PAGE_ENTRY_V0 pEntry;
  1393. ULONG iIndex2;
  1394. pRestartTable = (PRESTART_TABLE)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  1395. pEntry = (PDIRTY_PAGE_ENTRY_V0)((BYTE *)pRestartTable + sizeof(RESTART_TABLE));
  1396. for (iIndex=0; iIndex < pRestartTable->NumberEntries; iIndex++) {
  1397. if (pEntry->AllocatedOrNextFree == RESTART_ENTRY_ALLOCATED) {
  1398. for (iIndex2=0; iIndex2 < pEntry->LcnsToFollow; iIndex2++) {
  1399. if (pEntry->LcnsForPage[iIndex2] == *pLCN) {
  1400. fRet = true;
  1401. break;
  1402. }
  1403. }
  1404. pEntry = (PDIRTY_PAGE_ENTRY_V0)((BYTE *)pEntry + sizeof(DIRTY_PAGE_ENTRY_V0) - sizeof(LCN) +
  1405. pEntry->LcnsToFollow * sizeof(LCN));
  1406. } else {
  1407. pEntry = (PDIRTY_PAGE_ENTRY_V0)((BYTE *)pEntry + sizeof(DIRTY_PAGE_ENTRY_V0));
  1408. }
  1409. }
  1410. }
  1411. }
  1412. return fRet;
  1413. } // MatchLcn
  1414. //+---------------------------------------------------------------------------
  1415. //
  1416. // Function: MatchAll
  1417. //
  1418. // Synopsis: Used to dump all lsns in range
  1419. //
  1420. // Arguments: [pRecord] --
  1421. // [Context] --
  1422. //
  1423. // Returns:
  1424. //
  1425. // History: benl Created
  1426. //
  1427. // Notes:
  1428. //
  1429. //----------------------------------------------------------------------------
  1430. bool MatchAll(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1431. {
  1432. return true;
  1433. } // MatchAll
  1434. //+---------------------------------------------------------------------------
  1435. //
  1436. // Function: MatchRestartDumps
  1437. //
  1438. // Synopsis: Match if part of a restart table dump
  1439. //
  1440. // Arguments: [pRecord] --
  1441. // [Context] --
  1442. //
  1443. // Returns:
  1444. //
  1445. // History: 9-16-1998 benl Created
  1446. //
  1447. // Notes:
  1448. //
  1449. //----------------------------------------------------------------------------
  1450. bool MatchRestartDumps(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1451. {
  1452. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1453. int iIndex;
  1454. bool fRet = false;
  1455. if (pRecord->RecordType == LfsClientRecord) {
  1456. if (pRecord->ClientDataLength) {
  1457. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1458. sizeof(LFS_RECORD_HEADER));
  1459. if (pNtfsLog->RedoOperation == OpenAttributeTableDump ||
  1460. pNtfsLog->RedoOperation == AttributeNamesDump ||
  1461. pNtfsLog->RedoOperation == DirtyPageTableDump ||
  1462. pNtfsLog->RedoOperation == TransactionTableDump ) {
  1463. fRet = true;
  1464. }
  1465. }
  1466. } else {
  1467. //
  1468. // Always dump a restart area record
  1469. //
  1470. fRet = true;
  1471. }
  1472. return fRet;
  1473. } // MatchRestartDumps
  1474. //+---------------------------------------------------------------------------
  1475. //
  1476. // Function: MatchRecordNewAttributes
  1477. //
  1478. // Synopsis: Used to record open attributes during traversal
  1479. //
  1480. // Arguments: [pRecord] -- current record
  1481. // [Context] -- an open attribute map
  1482. //
  1483. // Returns:
  1484. //
  1485. // History: benl Created
  1486. // 9-09-1998 benl modified
  1487. // 9-09-1998 benl modified
  1488. //
  1489. // Notes: always returns false so nothing is printed
  1490. //
  1491. //----------------------------------------------------------------------------
  1492. bool MatchRecordNewAttributes(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1493. {
  1494. OPEN_ATTR_MAP * pMap = (OPEN_ATTR_MAP *) Context;
  1495. AddNewAttributes(pRecord, *pMap);
  1496. return false;
  1497. } // MatchRecordNewAttributes
  1498. //+---------------------------------------------------------------------------
  1499. //
  1500. // Function: MatchRecordNewAttributes
  1501. //
  1502. // Synopsis: Used to record open attributes during traversal
  1503. //
  1504. // Arguments: [pRecord] -- current record
  1505. // [Context] -- an open attribute map
  1506. //
  1507. // Returns:
  1508. //
  1509. // History: benl Created
  1510. // 9-09-1998 benl modified
  1511. // 9-09-1998 benl modified
  1512. //
  1513. // Notes: always returns false so nothing is printed
  1514. //
  1515. //----------------------------------------------------------------------------
  1516. bool MatchDeduceClusterSize(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1517. {
  1518. PDEDUCE_CTX DeduceCtx = (PDEDUCE_CTX) Context;
  1519. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1520. PINDEX_ENTRY pEntry = NULL;
  1521. MYASSERT(Context);
  1522. if (pRecord->ClientDataLength) {
  1523. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1524. sizeof(LFS_RECORD_HEADER));
  1525. if ((pNtfsLog->RedoOperation == AddIndexEntryAllocation) &&
  1526. (pNtfsLog->RedoLength > 0)) {
  1527. pEntry = (PINDEX_ENTRY)((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  1528. DeduceCtx->AddRecordFileRef = (LONGLONG)(pEntry->FileReference.SegmentNumberLowPart) +
  1529. ((LONGLONG)(pEntry->FileReference.SegmentNumberHighPart) << 32);
  1530. DeduceCtx->AddRecordLsn = pRecord->ThisLsn.QuadPart;
  1531. // printf( "Found fileref add 0x%I64x at Lsn: 0x%I64x\n", DeduceCtx->AddRecordFileRef,
  1532. // DeduceCtx->AddRecordLsn );
  1533. } else if ((pNtfsLog->RedoOperation == InitializeFileRecordSegment) &&
  1534. (pNtfsLog->RedoLength > 0) &&
  1535. (DeduceCtx->AddRecordLsn == pRecord->ClientPreviousLsn.QuadPart)) {
  1536. DeduceCtx->AddRecordVcn = pNtfsLog->TargetVcn;
  1537. DeduceCtx->AddRecordClusterOffset = pNtfsLog->ClusterBlockOffset;
  1538. // printf( "Found file: 0x%I64x at VCN: 0x%I64x offset: 0x%x\n",
  1539. // DeduceCtx->AddRecordFileRef,
  1540. // DeduceCtx->AddRecordVcn,
  1541. // DeduceCtx->AddRecordClusterOffset );
  1542. }
  1543. }
  1544. return false;
  1545. } // MatchRecordNewAttributes
  1546. //+---------------------------------------------------------------------------
  1547. //
  1548. // Function: MatchGetClusterSize
  1549. //
  1550. // Synopsis:
  1551. //
  1552. // Arguments: [pRecord] --
  1553. // [Context] --
  1554. //
  1555. // Returns:
  1556. //
  1557. // History: 12-30-1998 benl Created
  1558. //
  1559. // Notes:
  1560. //
  1561. //----------------------------------------------------------------------------
  1562. bool MatchGetClusterSize(PLFS_RECORD_HEADER pRecord,
  1563. PVOID Context)
  1564. {
  1565. PULONG pClusterSize = (PULONG) Context;
  1566. PRESTART_AREA pRestartArea;
  1567. MYASSERT(Context);
  1568. if (pRecord->RecordType == LfsClientRestart) {
  1569. pRestartArea = (PRESTART_AREA) ( (BYTE *)pRecord + sizeof(LFS_RECORD_HEADER) );
  1570. *pClusterSize = pRestartArea->BytesPerCluster;
  1571. } else {
  1572. printf( "MatchGetClusterSize: not a client restart area\n" );
  1573. }
  1574. //
  1575. // Never print the match
  1576. //
  1577. return false;
  1578. } // MatchGetClusterSize
  1579. //+---------------------------------------------------------------------------
  1580. //
  1581. // Function: MatchBit
  1582. //
  1583. // Synopsis: Match nonres bitmap involving the given bit
  1584. //
  1585. // Arguments: [pRecord] --
  1586. // [Context] --
  1587. //
  1588. // Returns:
  1589. //
  1590. // History: benl Created
  1591. //
  1592. // Notes:
  1593. //
  1594. //----------------------------------------------------------------------------
  1595. bool MatchBit(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1596. {
  1597. ULONG * plBit = (ULONG *) Context;
  1598. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1599. PBITMAP_RANGE pRange;
  1600. bool fRet = false;
  1601. MYASSERT(plBit);
  1602. if (pRecord->ClientDataLength) {
  1603. pNtfsLog = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord +
  1604. sizeof(LFS_RECORD_HEADER));
  1605. if (pNtfsLog->RedoOperation == SetBitsInNonresidentBitMap ||
  1606. pNtfsLog->RedoOperation == ClearBitsInNonresidentBitMap) {
  1607. MYASSERT(pNtfsLog->RedoLength == sizeof(BITMAP_RANGE));
  1608. pRange = (PBITMAP_RANGE) ((BYTE *)pNtfsLog + pNtfsLog->RedoOffset);
  1609. if (pRange->BitMapOffset <= *plBit &&
  1610. pRange->BitMapOffset + pRange->NumberOfBits >= *plBit) {
  1611. fRet = true;
  1612. }
  1613. }
  1614. }
  1615. return fRet;
  1616. } // MatchBit
  1617. //+---------------------------------------------------------------------------
  1618. //
  1619. // Function: MatchTrace
  1620. //
  1621. // Synopsis: Function used to trace forward
  1622. //
  1623. // Arguments: [pRecord] -- record to check
  1624. // [Context] -- prev. lsn to look for
  1625. //
  1626. // Returns:
  1627. //
  1628. // History: 7-29-1999 benl Created
  1629. //
  1630. // Notes:
  1631. //
  1632. //----------------------------------------------------------------------------
  1633. bool MatchTrace(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1634. {
  1635. PLSN LsnMatch = (PLSN) Context;
  1636. if (pRecord->ClientPreviousLsn.QuadPart == LsnMatch->QuadPart) {
  1637. LsnMatch->QuadPart = pRecord->ThisLsn.QuadPart;
  1638. return true;
  1639. } else {
  1640. return false;
  1641. }
  1642. } // MatchTrace
  1643. //+---------------------------------------------------------------------------
  1644. //
  1645. // Function: MatchTrackTransactions
  1646. //
  1647. // Synopsis:
  1648. //
  1649. // Arguments: [pRecord] --
  1650. // [Context] --
  1651. //
  1652. // Returns:
  1653. //
  1654. // History: 5-09-2001 benl Created
  1655. //
  1656. // Notes:
  1657. //
  1658. //----------------------------------------------------------------------------
  1659. bool MatchTrackTransactions(PLFS_RECORD_HEADER pRecord, PVOID Context)
  1660. {
  1661. PTRANSACTION_MAP Map = (PTRANSACTION_MAP) Context;
  1662. PNTFS_LOG_RECORD_HEADER NtfsRecord = NULL;
  1663. LONGLONG StartLsn;
  1664. if (pRecord->ClientDataLength) {
  1665. //
  1666. // If commit remove the transaction from the log
  1667. //
  1668. NtfsRecord = (PNTFS_LOG_RECORD_HEADER)((BYTE *)pRecord + sizeof(LFS_RECORD_HEADER));
  1669. }
  1670. //
  1671. // leave quickly for checkpoint records
  1672. //
  1673. if ((pRecord->RecordType == LfsClientRestart) ||
  1674. (NtfsRecord->RedoOperation == OpenAttributeTableDump) ||
  1675. (NtfsRecord->RedoOperation == AttributeNamesDump) ||
  1676. (NtfsRecord->RedoOperation == DirtyPageTableDump) ||
  1677. (NtfsRecord->RedoOperation == TransactionTableDump)) {
  1678. return false;
  1679. }
  1680. //
  1681. // Update the current state of the transaction - if its new the prev lsn will == 0
  1682. // which won't be present and we'll add a new record - this also happens for partial transactions
  1683. // at the start of the log
  1684. //
  1685. if (Map->Lookup( pRecord->ClientPreviousLsn.QuadPart ) != NULL) {
  1686. if (!Map->Remove( pRecord->ClientPreviousLsn.QuadPart )){
  1687. printf( "problem\n" );
  1688. }
  1689. Map->Insert( pRecord->ThisLsn.QuadPart, NtfsRecord ? NtfsRecord->RedoOperation : -1 );
  1690. // printf( "replaced %I64x\n", pRecord->ThisLsn.QuadPart );
  1691. } else {
  1692. // printf( "added %I64x\n", pRecord->ThisLsn.QuadPart );
  1693. Map->Insert( pRecord->ThisLsn.QuadPart, NtfsRecord ? NtfsRecord->RedoOperation : -1 );
  1694. }
  1695. if (NtfsRecord) {
  1696. //
  1697. // If commit remove the transaction from the log
  1698. //
  1699. if (NtfsRecord->RedoOperation == ForgetTransaction) {
  1700. if (!Map->Remove( pRecord->ThisLsn.QuadPart )) {
  1701. printf( "remove %I64x failed\n", pRecord->ThisLsn.QuadPart );
  1702. } else {
  1703. // printf( "remove %I64x\n", pRecord->ThisLsn.QuadPart );
  1704. }
  1705. }
  1706. }
  1707. return false;
  1708. } // MatchTrackTransactions
  1709. //+---------------------------------------------------------------------------
  1710. //
  1711. // Function: ScanLsnRangeForMatch
  1712. //
  1713. // Synopsis: Walk the range of LSN records and dump any that have to
  1714. // do with the given VCN
  1715. //
  1716. // Arguments: [hFile] -- logfile handle
  1717. // [LsnFirst] -- beginning of LSN range
  1718. // [LsnMax] -- end of LSN range
  1719. // [Vcn] -- vcn to search
  1720. //
  1721. // Returns:
  1722. //
  1723. // History: 8-25-1998 benl Created
  1724. //
  1725. // Notes: VCN is the TargetVcn in the NTFS_LOG_RECORD_HEADER
  1726. //
  1727. //----------------------------------------------------------------------------
  1728. void ScanLsnRangeForMatch(HANDLE hFile, LSN LsnFirst, LSN LsnMax,
  1729. PMATCH_FUNC pMatchFunc, PVOID MatchContext)
  1730. {
  1731. BYTE lpBuffer[LOG_PAGE];
  1732. BYTE * pLargeBuffer = 0;
  1733. INT cbOffset;
  1734. INT cbPage;
  1735. INT cbPageOffset;
  1736. OVERLAPPED ol;
  1737. DWORD dwRead;
  1738. PLFS_RECORD_HEADER pRecord;
  1739. PLFS_RECORD_HEADER pNextRecord;
  1740. bool fStartNextPage = false;
  1741. int iIndex;
  1742. LSN LsnNext = LsnFirst;
  1743. int cbToRead;
  1744. PNTFS_LOG_RECORD_HEADER pNtfsLog;
  1745. int cbLargeBuf;
  1746. CMap<int, MYENTRY> AttrMap;
  1747. PLFS_RECORD_PAGE_HEADER pHdr;
  1748. ULONG ulTemp;
  1749. ULONG SeqNum;
  1750. bool ValidRecord = TRUE;
  1751. memset(&ol, 0, sizeof(ol));
  1752. do {
  1753. cbOffset = (ULONG) LsnToOffset(LsnNext.QuadPart);
  1754. cbPage = cbOffset & ~(LOG_PAGE - 1);
  1755. //
  1756. // Load the 1st page its in
  1757. //
  1758. ol.Offset = cbPage;
  1759. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1760. return;
  1761. }
  1762. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1763. {
  1764. printf( "Failed to resolve USA sequence in page: 0x%x\n", cbPage );
  1765. return;
  1766. }
  1767. fStartNextPage = false;
  1768. do {
  1769. LsnFirst = LsnNext;
  1770. SeqNum = LsnToSequenceNumber( LsnFirst.QuadPart );
  1771. cbOffset = (ULONG) LsnToOffset(LsnFirst.QuadPart);
  1772. cbPageOffset = cbOffset & (LOG_PAGE - 1);
  1773. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + cbPageOffset);
  1774. if (pRecord->ThisLsn.QuadPart != LsnFirst.QuadPart) {
  1775. //
  1776. // Let check the ping pong pages
  1777. //
  1778. ulTemp = ol.Offset;
  1779. ol.Offset = 0x2000;
  1780. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1781. printf("0x%x 0x%x\n", pRecord, pLargeBuffer);
  1782. return;
  1783. }
  1784. ol.Offset = ulTemp;
  1785. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1786. {
  1787. break;
  1788. }
  1789. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + cbPageOffset) ;
  1790. //
  1791. // If the ping-pong is no good go back to the old buffer and do
  1792. // a seq number jump
  1793. //
  1794. if (pRecord->ThisLsn.QuadPart != LsnFirst.QuadPart) {
  1795. ValidRecord = FALSE;
  1796. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1797. printf("0x%x 0x%x\n", pRecord, pLargeBuffer);
  1798. return;
  1799. }
  1800. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1801. {
  1802. break;
  1803. }
  1804. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + cbPageOffset) ;
  1805. printf("Warning: Lsn in record 0x%I64x doesn't match Lsn: 0x%I64x!!\n\n", pRecord->ThisLsn,
  1806. LsnFirst);
  1807. //
  1808. // Start next page
  1809. //
  1810. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  1811. if (pHdr->Flags & LOG_PAGE_LOG_RECORD_END) {
  1812. LsnNext.QuadPart = pHdr->Header.Packed.LastEndLsn.QuadPart;
  1813. } else {
  1814. fStartNextPage = true;
  1815. }
  1816. } else {
  1817. ValidRecord = TRUE;
  1818. }
  1819. } else {
  1820. ValidRecord = TRUE;
  1821. }
  1822. //
  1823. // If its in the page dump it directly o.w get the complete multipage record
  1824. //
  1825. if (ValidRecord) {
  1826. if (!(pRecord->Flags & LOG_RECORD_MULTI_PAGE)) {
  1827. //
  1828. // Add to OpenAttributeTable if necc.
  1829. //
  1830. AddNewAttributes(pRecord, AttrMap);
  1831. if (pMatchFunc(pRecord, MatchContext)) {
  1832. printf("Offset: 0x%x\n", cbOffset);
  1833. DumpLogRecord(pRecord, &AttrMap);
  1834. printf("\n");
  1835. }
  1836. //advance to next
  1837. pNextRecord = (PLFS_RECORD_HEADER)((BYTE *)pRecord +
  1838. pRecord->ClientDataLength + sizeof(LFS_RECORD_HEADER));
  1839. if ((BYTE *)pNextRecord > &lpBuffer[LOG_PAGE - sizeof(LFS_RECORD_HEADER)]) {
  1840. fStartNextPage = true;
  1841. } else {
  1842. LsnNext.QuadPart = pNextRecord->ThisLsn.QuadPart;
  1843. if (LsnNext.QuadPart == 0) {
  1844. fStartNextPage = true;
  1845. }
  1846. }
  1847. } else {
  1848. //
  1849. // Brute force scatter-gather
  1850. //
  1851. cbLargeBuf = 2 * sizeof(LFS_RECORD_HEADER) + pRecord->ClientDataLength;
  1852. if (LOG_PAGE - cbPageOffset > cbLargeBuf) {
  1853. printf("ClientDataLength 0x%x is invalid!\n",
  1854. pRecord->ClientDataLength);
  1855. return;
  1856. }
  1857. pLargeBuffer = new BYTE[cbLargeBuf];
  1858. memcpy(pLargeBuffer, pRecord, LOG_PAGE - cbPageOffset);
  1859. pRecord = (PLFS_RECORD_HEADER) pLargeBuffer;
  1860. pLargeBuffer += LOG_PAGE - cbPageOffset;
  1861. for (iIndex = pRecord->ClientDataLength + sizeof(LFS_RECORD_HEADER) -
  1862. (LOG_PAGE - cbPageOffset);
  1863. iIndex > 0;
  1864. iIndex -= (LOG_PAGE - TOTAL_PAGE_HEADER)) {
  1865. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  1866. if (ol.Offset == 0) {
  1867. ol.Offset = LOG_PAGE * 4;
  1868. }
  1869. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1870. printf("0x%x 0x%x\n", pRecord, pLargeBuffer);
  1871. return;
  1872. }
  1873. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1874. {
  1875. break;
  1876. }
  1877. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  1878. //check if really need the ping-pong page
  1879. if ((pHdr->Flags & LOG_PAGE_LOG_RECORD_END) &&
  1880. (pHdr->Header.Packed.LastEndLsn.QuadPart < LsnFirst.QuadPart)) {
  1881. printf("At ping-pong\n");
  1882. ulTemp = ol.Offset;
  1883. ol.Offset = 0x2000;
  1884. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1885. printf("0x%x 0x%x\n", pRecord, pLargeBuffer);
  1886. return;
  1887. }
  1888. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1889. {
  1890. printf( "Invalid USA sequence\n" );
  1891. break;
  1892. }
  1893. pHdr = (PLFS_RECORD_PAGE_HEADER) lpBuffer;
  1894. ol.Offset = ulTemp;
  1895. }
  1896. cbToRead = min(LOG_PAGE - TOTAL_PAGE_HEADER,
  1897. iIndex + sizeof(LFS_RECORD_HEADER));
  1898. memcpy(pLargeBuffer, lpBuffer + TOTAL_PAGE_HEADER, cbToRead);
  1899. pLargeBuffer += cbToRead;
  1900. }
  1901. if (pRecord->ClientDataLength) {
  1902. //
  1903. // Add to OpenAttributeTable if necc.
  1904. //
  1905. AddNewAttributes(pRecord, AttrMap);
  1906. if (pMatchFunc(pRecord, MatchContext)) {
  1907. printf("Offset: 0x%x\n", cbOffset);
  1908. DumpLogRecord(pRecord, &AttrMap);
  1909. printf("\n");
  1910. }
  1911. }
  1912. pNextRecord = (PLFS_RECORD_HEADER)(pLargeBuffer - sizeof(LFS_RECORD_HEADER));
  1913. if (-1 * iIndex < sizeof(LFS_RECORD_HEADER)) {
  1914. fStartNextPage = true;
  1915. } else {
  1916. LsnNext.QuadPart = pNextRecord->ThisLsn.QuadPart;
  1917. }
  1918. //remove the temp buffer and then restore the regular buffer
  1919. pLargeBuffer = (BYTE *)pRecord;
  1920. delete[] pLargeBuffer;
  1921. }
  1922. }
  1923. if (fStartNextPage) {
  1924. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  1925. if (ol.Offset == 0) {
  1926. ol.Offset = LOG_PAGE * 4;
  1927. }
  1928. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  1929. return;
  1930. }
  1931. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  1932. {
  1933. break;
  1934. }
  1935. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + TOTAL_PAGE_HEADER);
  1936. LsnNext.QuadPart = pRecord->ThisLsn.QuadPart;
  1937. fStartNextPage = false;
  1938. }
  1939. // Check for a sequence jump
  1940. // if so then we need to rescam if it has changed by
  1941. // more than 1
  1942. //
  1943. if (LsnToSequenceNumber( LsnNext.QuadPart ) != SeqNum ) {
  1944. printf( "Sequence number jump 0x%x to 0x%x for LSN: 0x%I64x!\n\n", SeqNum, LsnToSequenceNumber( LsnNext.QuadPart ), LsnNext.QuadPart );
  1945. if (LsnToSequenceNumber( LsnNext.QuadPart ) != SeqNum + 1) {
  1946. //
  1947. // Set to current so we exit this loop and scan for the next
  1948. // LSN
  1949. //
  1950. LsnNext = LsnFirst;
  1951. }
  1952. }
  1953. } while (LsnFirst.QuadPart < LsnMax.QuadPart && LsnFirst.QuadPart < LsnNext.QuadPart );
  1954. LsnNext = ScanForNextLsn( hFile, LsnFirst );
  1955. printf( "skip to 0x%I64x\n", LsnNext );
  1956. } while ( LsnNext.QuadPart != LsnFirst.QuadPart && LsnNext.QuadPart < LsnMax.QuadPart );
  1957. printf("At end page, Lsn: 0x%x 0x%I64x 0x%I64x\n", ol.Offset, LsnFirst, LsnNext);
  1958. } // ScanLsnRangeForMatch
  1959. //+---------------------------------------------------------------------------
  1960. //
  1961. // Function: TraceTransaction
  1962. //
  1963. // Synopsis: Given an lsn show the transaction its involved in
  1964. //
  1965. // Arguments: [hFile] -- logfile handle
  1966. // [Lsn] -- lsn to check
  1967. // [LsnFirst] --
  1968. // [LsnMax] -- ending lsn in the logfile
  1969. //
  1970. // Returns:
  1971. //
  1972. // History: 8-25-1998 benl Created
  1973. // 7-29-1999 benl modified
  1974. //
  1975. // Notes: First use prev back pointers to find the beginning of the transaction
  1976. // then just scan forwards for all pieces
  1977. //
  1978. //----------------------------------------------------------------------------
  1979. void TraceTransaction(HANDLE hFile, LSN Lsn, LSN LsnFirst, LSN LsnMax)
  1980. {
  1981. BYTE lpBuffer[LOG_PAGE];
  1982. BYTE * pLargeBuffer = 0;
  1983. INT cbOffset;
  1984. INT cbPage;
  1985. INT cbPageOffset;
  1986. OVERLAPPED ol;
  1987. DWORD dwRead;
  1988. PLFS_RECORD_HEADER pRecord;
  1989. PLFS_RECORD_HEADER pNextRecord;
  1990. bool fStartNextPage = false;
  1991. int iIndex;
  1992. LSN LsnTemp;
  1993. LSN LsnNext;
  1994. int cbToRead;
  1995. CMap<int, MYENTRY> AttrMap;
  1996. memset(&ol, 0, sizeof(ol));
  1997. do {
  1998. cbOffset = (ULONG)(LsnToOffset(Lsn.QuadPart));
  1999. cbPage = cbOffset & ~(LOG_PAGE - 1);
  2000. cbPageOffset = cbOffset & (LOG_PAGE - 1);
  2001. //
  2002. // Load the 1st page its in
  2003. //
  2004. ol.Offset = cbPage;
  2005. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  2006. return;
  2007. }
  2008. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, ol.Offset))
  2009. {
  2010. break;
  2011. }
  2012. pRecord = (PLFS_RECORD_HEADER)(lpBuffer + cbPageOffset);
  2013. printf("ThisLsn, PrevLsn, UndoLsn: 0x%I64x 0x%I64x 0x%I64x\n",
  2014. pRecord->ThisLsn, pRecord->ClientPreviousLsn,
  2015. pRecord->ClientUndoNextLsn);
  2016. fflush( stdout );
  2017. MYASSERT(pRecord->ThisLsn.QuadPart == Lsn.QuadPart);
  2018. if (pRecord->ClientPreviousLsn.QuadPart) {
  2019. Lsn.QuadPart = pRecord->ClientPreviousLsn.QuadPart;
  2020. }
  2021. } while (pRecord->ClientPreviousLsn.QuadPart);
  2022. printf("\n");
  2023. //
  2024. // Buildup attribute names
  2025. //
  2026. // ScanLsnRangeForMatch(hFile, LsnFirst, Lsn, MatchRecordNewAttributes, &AttrMap);
  2027. LsnTemp.QuadPart = 0;
  2028. ScanLsnRangeForMatch( hFile, Lsn, LsnMax, MatchTrace, &LsnTemp );
  2029. /*
  2030. //
  2031. // Now Scan Forward dumping pieces - Lsn is set to LSN to match 0 to start and
  2032. // LsnNext is the next lsn to look at
  2033. //
  2034. LsnNext = Lsn;
  2035. Lsn.QuadPart = 0;
  2036. do {
  2037. LsnTemp = LsnNext;
  2038. cbOffset = (ULONG)(LsnToOffset(LsnTemp.QuadPart));
  2039. cbPageOffset = cbOffset & (LOG_PAGE - 1);
  2040. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + cbPageOffset);
  2041. if (pRecord->ThisLsn.QuadPart != LsnTemp.QuadPart) {
  2042. ULONG ulTemp;
  2043. //
  2044. // Let check the ping pong pages
  2045. //
  2046. ulTemp = ol.Offset;
  2047. ol.Offset = 0x2000;
  2048. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  2049. printf("0x%x 0x%x\n", pRecord, pLargeBuffer);
  2050. return;
  2051. }
  2052. ol.Offset = ulTemp;
  2053. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer))
  2054. {
  2055. break;
  2056. }
  2057. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + cbPageOffset) ;
  2058. //
  2059. // If the ping-pong is no good go back to the old buffer and do
  2060. // a seq number jump
  2061. //
  2062. if (pRecord->ThisLsn.QuadPart != LsnFirst.QuadPart) {
  2063. printf("Warning: Lsn in record 0x%I64x doesn't match Lsn: 0x%I64x!!\n\n", pRecord->ThisLsn,
  2064. LsnFirst);
  2065. break;
  2066. }
  2067. }
  2068. //
  2069. // If its in the page dump it directly o.w get the complete multipage record
  2070. //
  2071. if (!(pRecord->Flags & LOG_RECORD_MULTI_PAGE)) {
  2072. //
  2073. // Check for matching Lsn prev
  2074. //
  2075. AddNewAttributes(pRecord, AttrMap);
  2076. if (pRecord->ClientPreviousLsn.QuadPart == Lsn.QuadPart) {
  2077. printf("Offset: 0x%x\n", cbOffset);
  2078. DumpLogRecord(pRecord, &AttrMap);
  2079. printf("\n");
  2080. Lsn = pRecord->ThisLsn;
  2081. }
  2082. //advance to next
  2083. pNextRecord = (PLFS_RECORD_HEADER)((BYTE *)pRecord +
  2084. pRecord->ClientDataLength + sizeof(LFS_RECORD_HEADER));
  2085. if ((BYTE *)pNextRecord > &lpBuffer[LOG_PAGE - sizeof(LFS_RECORD_HEADER)]) {
  2086. fStartNextPage = true;
  2087. } else {
  2088. LsnNext.QuadPart = pNextRecord->ThisLsn.QuadPart;
  2089. }
  2090. } else {
  2091. //
  2092. // Brute force scatter-gather
  2093. //
  2094. pLargeBuffer = new BYTE[2 * sizeof(LFS_RECORD_HEADER) + pRecord->ClientDataLength];
  2095. memcpy(pLargeBuffer, pRecord, LOG_PAGE - cbPageOffset);
  2096. pRecord = (PLFS_RECORD_HEADER) pLargeBuffer;
  2097. pLargeBuffer += LOG_PAGE - cbPageOffset;
  2098. for (iIndex = pRecord->ClientDataLength + sizeof(LFS_RECORD_HEADER) -
  2099. (LOG_PAGE - cbPageOffset);
  2100. iIndex > 0;
  2101. iIndex -= (LOG_PAGE - TOTAL_PAGE_HEADER)) {
  2102. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  2103. if (ol.Offset == 0) {
  2104. ol.Offset = LOG_PAGE * 4;
  2105. }
  2106. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  2107. printf("0x%x 0x%x\n", pRecord, pLargeBuffer);
  2108. return;
  2109. }
  2110. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer))
  2111. {
  2112. break;
  2113. }
  2114. cbToRead = min(LOG_PAGE - TOTAL_PAGE_HEADER,
  2115. iIndex + sizeof(LFS_RECORD_HEADER));
  2116. memcpy(pLargeBuffer, lpBuffer + TOTAL_PAGE_HEADER, cbToRead);
  2117. pLargeBuffer += cbToRead;
  2118. }
  2119. AddNewAttributes(pRecord, AttrMap);
  2120. if (pRecord->ClientPreviousLsn.QuadPart == Lsn.QuadPart) {
  2121. printf("Offset: 0x%x\n", cbOffset);
  2122. DumpLogRecord(pRecord, &AttrMap);
  2123. printf("\n");
  2124. Lsn = pRecord->ThisLsn;
  2125. }
  2126. pNextRecord = (PLFS_RECORD_HEADER)(pLargeBuffer - sizeof(LFS_RECORD_HEADER));
  2127. if (-1 * iIndex < sizeof(LFS_RECORD_HEADER)) {
  2128. fStartNextPage = true;
  2129. } else {
  2130. LsnNext.QuadPart = pNextRecord->ThisLsn.QuadPart;
  2131. }
  2132. //remove the temp buffer and then restore the regular buffer
  2133. pLargeBuffer = (BYTE *)pRecord;
  2134. delete[] pLargeBuffer;
  2135. }
  2136. if (fStartNextPage) {
  2137. ol.Offset = (ol.Offset + LOG_PAGE) % gLogFileSize;
  2138. if (ol.Offset == 0) {
  2139. ol.Offset = LOG_PAGE * 4;
  2140. }
  2141. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, &ol)) {
  2142. return;
  2143. }
  2144. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer))
  2145. {
  2146. break;
  2147. }
  2148. pRecord = (PLFS_RECORD_HEADER) (lpBuffer + TOTAL_PAGE_HEADER);
  2149. LsnNext.QuadPart = pRecord->ThisLsn.QuadPart;
  2150. fStartNextPage = false;
  2151. }
  2152. } while (LsnTemp.QuadPart < LsnMax.QuadPart );
  2153. printf("At end page, Lsn: 0x%x 0x%I64x\n", ol.Offset, LsnTemp);
  2154. */
  2155. } // TraceTransaction
  2156. //+---------------------------------------------------------------------------
  2157. //
  2158. // Function: FindClusterRatio
  2159. //
  2160. // Synopsis:
  2161. //
  2162. // Arguments: (none)
  2163. //
  2164. // Returns:
  2165. //
  2166. // History: 12-30-1998 benl Created
  2167. //
  2168. // Notes:
  2169. //
  2170. //----------------------------------------------------------------------------
  2171. ULONG FindClusterRatio(HANDLE hFile)
  2172. {
  2173. BYTE lpRestartPage1[LOG_PAGE];
  2174. BYTE lpRestartPage2[LOG_PAGE];
  2175. LSN LsnRestart = {0,0};
  2176. PLFS_RESTART_PAGE_HEADER pRestartHdr;
  2177. PLFS_RESTART_AREA pLfsRestart1 = 0;
  2178. PLFS_RESTART_AREA pLfsRestart2 = 0;
  2179. int iIndex;
  2180. PLFS_CLIENT_RECORD pClient = 0;
  2181. ULONG ulClusterSize = 0;
  2182. LSN LsnEnd;
  2183. LSN LsnStart;
  2184. DEDUCE_CTX DeduceCtx;
  2185. __try {
  2186. if (0xFFFFFFFF == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) {
  2187. printf("SetFilePtr failed %d\n", GetLastError());
  2188. __leave;
  2189. }
  2190. //
  2191. // Read the two restart pages
  2192. //
  2193. if (!MyReadFile(hFile, lpRestartPage1, LOG_PAGE, NULL)) {
  2194. __leave;
  2195. }
  2196. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpRestartPage1, 0)) {
  2197. __leave;
  2198. }
  2199. if (!MyReadFile(hFile, lpRestartPage2, LOG_PAGE, NULL)) {
  2200. __leave;
  2201. }
  2202. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpRestartPage2, 0x1000)) {
  2203. __leave;
  2204. }
  2205. //
  2206. // Use the newer one of the two restart areas
  2207. //
  2208. pRestartHdr = (PLFS_RESTART_PAGE_HEADER) lpRestartPage1;
  2209. pLfsRestart1 = (PLFS_RESTART_AREA) (lpRestartPage1 + pRestartHdr->RestartOffset);
  2210. pRestartHdr = (PLFS_RESTART_PAGE_HEADER) lpRestartPage2;
  2211. pLfsRestart2 = (PLFS_RESTART_AREA) (lpRestartPage2 + pRestartHdr->RestartOffset);
  2212. if (pLfsRestart2->CurrentLsn.QuadPart > pLfsRestart1->CurrentLsn.QuadPart ) {
  2213. pLfsRestart1 = pLfsRestart2;
  2214. }
  2215. //
  2216. // Find the Lsn for the current restart area
  2217. //
  2218. pClient = (PLFS_CLIENT_RECORD)((BYTE *)pLfsRestart1 + pLfsRestart1->ClientArrayOffset);
  2219. for (iIndex=0; iIndex < pLfsRestart1->LogClients; iIndex++) {
  2220. if (wcsncmp( pClient->ClientName, L"NTFS", 4 ) == 0) {
  2221. LsnRestart.QuadPart = pClient->ClientRestartLsn.QuadPart;
  2222. }
  2223. pClient = pClient++;
  2224. }
  2225. if (LsnRestart.QuadPart == 0) {
  2226. __leave;
  2227. }
  2228. printf( "Client restart area LSN: 0x%I64x\n", LsnRestart );
  2229. ScanLsnRangeForMatch( hFile, LsnRestart, LsnRestart, MatchGetClusterSize, &ulClusterSize );
  2230. //
  2231. // If this was an old logfile try to infer the cluster size anyway
  2232. //
  2233. if (0 == ulClusterSize) {
  2234. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2235. if (LsnStart.QuadPart == 0) {
  2236. __leave;
  2237. }
  2238. LsnEnd = ScanForLastLsn(hFile, LsnStart);
  2239. if (LsnEnd.QuadPart == 0) {
  2240. __leave;
  2241. }
  2242. printf( "Scanning for cluster size\n" );
  2243. memset( &DeduceCtx, 0, sizeof( DeduceCtx ) );
  2244. ScanLsnRangeForMatch( hFile, LsnStart, LsnEnd, MatchDeduceClusterSize, &DeduceCtx );
  2245. if (DeduceCtx.AddRecordVcn != 0 ) {
  2246. ulClusterSize = (ULONG)(DeduceCtx.AddRecordFileRef / DeduceCtx.AddRecordVcn * 2);
  2247. }
  2248. }
  2249. } __finally
  2250. {
  2251. }
  2252. return ulClusterSize;
  2253. } // FindClusterRatio
  2254. //+---------------------------------------------------------------------------
  2255. //
  2256. // Function: InitGlobals
  2257. //
  2258. // Synopsis: Reads restart pages determines more current one and records
  2259. // global values
  2260. //
  2261. // Arguments: [hFile] -- handle to logfile
  2262. // [Lcb] -- lcb for log
  2263. //
  2264. // Returns: true if successfule
  2265. //
  2266. // History: 8-24-1998 benl Created
  2267. // 8-25-1998 benl modified
  2268. //
  2269. // Notes: TODO: move all data from globals into lcb
  2270. //
  2271. //----------------------------------------------------------------------------
  2272. bool InitGlobals(HANDLE hFile, LOGCB & Logcb)
  2273. {
  2274. BYTE lpBuffer[LOG_PAGE];
  2275. PLFS_RESTART_PAGE_HEADER pRestartHdr = (PLFS_RESTART_PAGE_HEADER) lpBuffer;
  2276. PLFS_RESTART_AREA pLfsRestart = 0;
  2277. int iIndex;
  2278. PLFS_CLIENT_RECORD pClient = 0;
  2279. DWORD dwRead;
  2280. OVERLAPPED ol;
  2281. memset(&ol, 0, sizeof(ol));
  2282. //
  2283. // Read 1st restart area
  2284. //
  2285. if (!ReadFile(hFile, lpBuffer, LOG_PAGE, &dwRead, &ol)) {
  2286. printf("ReadFile failed %d\n", GetLastError());
  2287. return false;
  2288. }
  2289. MYASSERT(strncmp((char *)(pRestartHdr->MultiSectorHeader.Signature), "RSTR", 4) == 0);
  2290. pLfsRestart = (PLFS_RESTART_AREA) (lpBuffer + pRestartHdr->RestartOffset);
  2291. gSeqNumberBits = pLfsRestart->SeqNumberBits;
  2292. gLogFileSize = (ULONG)pLfsRestart->FileSize;
  2293. Logcb.CurrentLsn = pLfsRestart->CurrentLsn;
  2294. pClient = (PLFS_CLIENT_RECORD)((BYTE *)pLfsRestart + pLfsRestart->ClientArrayOffset);
  2295. MYASSERT(1 == pLfsRestart->LogClients);
  2296. Logcb.FirstLsn = pClient->OldestLsn;
  2297. //
  2298. // Read 2nd restart area
  2299. //
  2300. ol.Offset += LOG_PAGE;
  2301. if (!ReadFile(hFile, lpBuffer, LOG_PAGE, &dwRead, &ol)) {
  2302. printf("ReadFile failed %d\n", GetLastError());
  2303. return false;
  2304. }
  2305. MYASSERT(strncmp((char *)(pRestartHdr->MultiSectorHeader.Signature), "RSTR", 4) == 0);
  2306. pLfsRestart = (PLFS_RESTART_AREA) (lpBuffer + pRestartHdr->RestartOffset);
  2307. if (pLfsRestart->CurrentLsn.QuadPart > Logcb.CurrentLsn.QuadPart) {
  2308. gSeqNumberBits = pLfsRestart->SeqNumberBits;
  2309. gLogFileSize = (ULONG)(pLfsRestart->FileSize);
  2310. Logcb.CurrentLsn = pLfsRestart->CurrentLsn;
  2311. pClient = (PLFS_CLIENT_RECORD)((BYTE *)pLfsRestart + pLfsRestart->ClientArrayOffset);
  2312. MYASSERT(1 == pLfsRestart->LogClients);
  2313. Logcb.FirstLsn = pClient->OldestLsn;
  2314. }
  2315. return true;
  2316. } // InitGlobals
  2317. //+---------------------------------------------------------------------------
  2318. //
  2319. // Function: Usage
  2320. //
  2321. // Synopsis:
  2322. //
  2323. // Arguments: (none)
  2324. //
  2325. // Returns:
  2326. //
  2327. // History: 8-25-1998 benl Created
  2328. //
  2329. // Notes:
  2330. //
  2331. //----------------------------------------------------------------------------
  2332. void Usage()
  2333. {
  2334. printf("Usage: dumplog logname [-l lsn] [-h] [-d] [-r] [-p pages] [-v vcn [clusterblockoffset]] [-t lsn] [-a] [-L lcn] [-f fileref]\n");
  2335. printf(" -p dumps the given number of pages of lsn records from the end \n");
  2336. printf(" of the log\n");
  2337. printf(" -h dumps the headers of the log including the 2 ping-pong pages\n");
  2338. printf(" -d dumps the redo/undo data\n");
  2339. printf(" -l lsn dumps the log record for the given lsn, the lsn should be in hex\n");
  2340. printf(" -v vcn search for log records dealing with the given vcn in hex optionally\n");
  2341. printf(" a cluster block offset can also be given\n");
  2342. printf(" -t lsn dumps the transaction containing the given lsn which\n");
  2343. printf(" should be in hex\n");
  2344. printf(" -a dump the entire log\n");
  2345. printf(" -L lcn searchs for log records containing the given lcn in hex\n");
  2346. printf(" -f fileref seearchs for log records containing the given fileref \n");
  2347. printf(" [ignores seq number]\n");
  2348. printf(" -r scan for restart table dumps\n");
  2349. printf(" -c [cluster size in hex] override cluster size rather than finding it\n");
  2350. printf(" -R [start stop] dump records in range\n");
  2351. printf(" -s verbose output during scans (shows last lsn for all pages) \n" );
  2352. printf(" -T scan for uncommited transactions in the log\n" );
  2353. } // Usage
  2354. //+---------------------------------------------------------------------------
  2355. //
  2356. // Function: ParseParams
  2357. //
  2358. // Synopsis: Parse params and print a usage message
  2359. //
  2360. // Arguments: [argc] --
  2361. // [argv] --
  2362. //
  2363. // Returns:
  2364. //
  2365. // History: 8-25-1998 benl Created
  2366. //
  2367. // Notes: Sets globals flags
  2368. //
  2369. //----------------------------------------------------------------------------
  2370. bool ParseParams(int argc, TCHAR * argv[])
  2371. {
  2372. int iIndex;
  2373. bool fRet = false;
  2374. LONGLONG llTemp;
  2375. __try
  2376. {
  2377. if (argc < 2 || _tcscmp(argv[1], _T("-?")) == 0) {
  2378. Usage();
  2379. __leave;
  2380. }
  2381. //
  2382. // init globals
  2383. //
  2384. gVcnPairToMatch.Vcn = 0;
  2385. gVcnPairToMatch.Offset = -1;
  2386. for (iIndex=2; iIndex < argc; iIndex++) {
  2387. if ((_tcslen(argv[iIndex]) > 1) && argv[iIndex][0] == _T('-')) {
  2388. if (argv[iIndex][1] == _T('p') && iIndex < argc - 1) {
  2389. giPagesBackToDump = _ttoi(argv[iIndex+1]);
  2390. iIndex++;
  2391. } else if (argv[iIndex][1] == _T('l') && iIndex < argc - 1) {
  2392. HexStrToInt64(argv[iIndex+1], gLsnToDump.QuadPart);
  2393. iIndex++;
  2394. } else if (argv[iIndex][1] == _T('v') && iIndex < argc - 1) {
  2395. HexStrToInt64(argv[iIndex+1], gVcnPairToMatch.Vcn);
  2396. iIndex++;
  2397. if ((iIndex + 1 < argc) && (argv[iIndex+1][0] != _T('-'))) {
  2398. HexStrToInt64(argv[iIndex+1], llTemp);
  2399. gVcnPairToMatch.Offset = (ULONG)llTemp;
  2400. iIndex++;
  2401. }
  2402. } else if (argv[iIndex][1] == _T('t') && iIndex < argc - 1) {
  2403. HexStrToInt64(argv[iIndex+1], gLsnToTrace.QuadPart);
  2404. iIndex++;
  2405. } else if (argv[iIndex][1] == _T('L') && iIndex < argc - 1) {
  2406. HexStrToInt64(argv[iIndex+1], gLcnToMatch);
  2407. iIndex++;
  2408. } else if (argv[iIndex][1] == _T('b') && iIndex < argc - 1) {
  2409. HexStrToInt64(argv[iIndex+1], llTemp);
  2410. glBitToMatch = (ULONG)llTemp;
  2411. iIndex++;
  2412. } else if (argv[iIndex][1] == _T('h')) {
  2413. gfPrintHeaders = true;
  2414. } else if (argv[iIndex][1] == _T('a')) {
  2415. gfDumpEverything = true;
  2416. } else if (argv[iIndex][1] == _T('d')) {
  2417. gfDumpData = true;
  2418. } else if (argv[iIndex][1] == _T('r')) {
  2419. gfScanForRestarts = true;
  2420. } else if (argv[iIndex][1] == _T('f') && iIndex < argc - 1) {
  2421. HexStrToInt64(argv[iIndex+1], gllFileToMatch);
  2422. iIndex++;
  2423. } else if (argv[iIndex][1] == _T('c') && (iIndex < argc - 1)) {
  2424. HexStrToInt64(argv[iIndex+1], llTemp);
  2425. iIndex++;
  2426. gulClusterSize = (ULONG)llTemp;
  2427. } else if (argv[iIndex][1] == _T('R') && (iIndex < argc - 2)) {
  2428. HexStrToInt64(argv[iIndex+1], gllRangeStart.QuadPart);
  2429. HexStrToInt64(argv[iIndex+2], gllRangeEnd.QuadPart);
  2430. iIndex+=2;
  2431. } else if (argv[iIndex][1] == _T('s')) {
  2432. gVerboseScan = true;
  2433. } else if (argv[iIndex][1] == _T('T')) {
  2434. gfScanTransactions = true;
  2435. } else {
  2436. Usage();
  2437. __leave;
  2438. }
  2439. } else {
  2440. Usage();
  2441. __leave;
  2442. }
  2443. }
  2444. fRet = true;
  2445. } __finally
  2446. {
  2447. }
  2448. return fRet;
  2449. } // ParseParams
  2450. //+---------------------------------------------------------------------------
  2451. //
  2452. // Function: _tmain
  2453. //
  2454. // Synopsis:
  2455. //
  2456. // Arguments: [argc] --
  2457. // [argv] --
  2458. //
  2459. // Returns:
  2460. //
  2461. // History: 8-24-1998 benl Created
  2462. //
  2463. // Notes:
  2464. //
  2465. //----------------------------------------------------------------------------
  2466. extern "C" {
  2467. int __cdecl _tmain (int argc, TCHAR *argv[])
  2468. {
  2469. HANDLE hFile;
  2470. BYTE lpBuffer[LOG_PAGE];
  2471. DWORD dwRead;
  2472. int iIndex;
  2473. LOGCB Logcb;
  2474. LSN LsnEnd;
  2475. LSN LsnStart;
  2476. LONGLONG llOffset;
  2477. FILEREF_MATCH_CTX FileRefMatchCtx;
  2478. OPEN_ATTR_MAP AttrMap;
  2479. ULONG ulClusterSize = 0;
  2480. if (!ParseParams(argc, argv)) {
  2481. return 1;
  2482. }
  2483. hFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING,
  2484. FILE_ATTRIBUTE_NORMAL, NULL);
  2485. if (INVALID_HANDLE_VALUE == hFile) {
  2486. _tprintf(_T("Failed to open %s, GLE=%d\n"), argv[1], GetLastError());
  2487. return 1;
  2488. }
  2489. if (!InitGlobals(hFile, Logcb)) {
  2490. return 1;
  2491. }
  2492. //
  2493. // Try to find the sectors per cluster which are in the restart pages
  2494. //
  2495. ulClusterSize = FindClusterRatio( hFile );
  2496. printf("Cluster Size: 0x%x\n", ulClusterSize );
  2497. //
  2498. // Scan for partial transaction
  2499. //
  2500. if (gfScanTransactions) {
  2501. TRANSACTION_MAP Map;
  2502. CMapIter< LONGLONG, ULONG > *Iter;
  2503. LONGLONG Lsn1;
  2504. ULONG Op;
  2505. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2506. if (LsnEnd.QuadPart == 0) {
  2507. return 1;
  2508. }
  2509. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2510. if (LsnStart.QuadPart == 0) {
  2511. return 1;
  2512. }
  2513. printf("Scanning LSN's between 0x%I64x and 0x%I64x for partial transactions\n\n", LsnStart,
  2514. LsnEnd);
  2515. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchTrackTransactions, &Map);
  2516. printf( "Uncommited transactions\n\n" );
  2517. Iter = Map.Enum();
  2518. while (Iter->Next( Lsn1, Op )) {
  2519. printf( "LSN: %I64x operation %s\n", Lsn1, (Op == -1) ? "Unknown" : gOpMap[ Op ] );
  2520. }
  2521. delete Iter;
  2522. }
  2523. //
  2524. // read front pages from the log
  2525. //
  2526. if (gfPrintHeaders) {
  2527. if (0xFFFFFFFF == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) {
  2528. printf("SetFilePtr failed %d\n", GetLastError());
  2529. }
  2530. for (iIndex=0; iIndex < 4; iIndex++) {
  2531. if (!MyReadFile(hFile, lpBuffer, LOG_PAGE, NULL)) {
  2532. return 1;
  2533. }
  2534. if (!ApplySectorHdr((PMULTI_SECTOR_HEADER)lpBuffer, LOG_PAGE * iIndex))
  2535. {
  2536. break;
  2537. }
  2538. DumpPage(lpBuffer);
  2539. printf("\n");
  2540. }
  2541. }
  2542. //
  2543. // Dump Back Pages
  2544. //
  2545. if (giPagesBackToDump) {
  2546. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2547. if (LsnEnd.QuadPart == 0) {
  2548. return 1;
  2549. }
  2550. LsnStart = ScanBackPagesForLastLsn(hFile, LsnEnd, giPagesBackToDump);
  2551. if (LsnStart.QuadPart == 0) {
  2552. return 1;
  2553. }
  2554. printf("Printing LSN's between 0x%I64x and 0x%I64x\n\n", LsnStart,
  2555. LsnEnd);
  2556. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchAll, NULL);
  2557. }
  2558. if (gLsnToDump.QuadPart) {
  2559. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2560. if (LsnEnd.QuadPart == 0) {
  2561. return 1;
  2562. }
  2563. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2564. if (LsnStart.QuadPart == 0) {
  2565. return 1;
  2566. }
  2567. printf("Scanning LSN records for LSN: 0x%I64x between 0x%I64x and 0x%I64x\n\n",
  2568. gLsnToDump.QuadPart, LsnStart, LsnEnd);
  2569. ScanLsnRangeForMatch(hFile, gLsnToDump, gLsnToDump, MatchAll, NULL);
  2570. }
  2571. if (gVcnPairToMatch.Vcn) {
  2572. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2573. if (LsnEnd.QuadPart == 0) {
  2574. return 1;
  2575. }
  2576. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2577. if (LsnStart.QuadPart == 0) {
  2578. return 1;
  2579. }
  2580. printf("Scanning LSN records for VCN: 0x%I64x between 0x%I64x and 0x%I64x\n\n",
  2581. gVcnPairToMatch.Vcn, LsnStart, LsnEnd);
  2582. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchVcn, &gVcnPairToMatch);
  2583. }
  2584. if (gLcnToMatch) {
  2585. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2586. if (LsnEnd.QuadPart == 0) {
  2587. return 1;
  2588. }
  2589. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2590. if (LsnStart.QuadPart == 0) {
  2591. return 1;
  2592. }
  2593. printf("Scanning LSN records for LCN: 0x%I64x between 0x%I64x and 0x%I64x\n\n",
  2594. gLcnToMatch, LsnStart, LsnEnd);
  2595. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchLcn, &gLcnToMatch);
  2596. }
  2597. if (gLsnToTrace.QuadPart) {
  2598. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2599. if (LsnEnd.QuadPart == 0) {
  2600. return 1;
  2601. }
  2602. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2603. if (LsnStart.QuadPart == 0) {
  2604. return 1;
  2605. }
  2606. printf("Scanning LSN records for transaction contain LSN: 0x%I64x\n",
  2607. gLsnToTrace);
  2608. if ((gLsnToTrace.QuadPart < LsnStart.QuadPart) || (gLsnToTrace.QuadPart > LsnEnd.QuadPart )) {
  2609. printf( "LSN out of range for the logfile\n" );
  2610. return 1;
  2611. }
  2612. TraceTransaction(hFile, gLsnToTrace, LsnStart, LsnEnd);
  2613. }
  2614. if (gllFileToMatch) {
  2615. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2616. if (LsnEnd.QuadPart == 0) {
  2617. return 1;
  2618. }
  2619. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2620. if (LsnStart.QuadPart == 0) {
  2621. return 1;
  2622. }
  2623. printf("Scanning LSN records for transaction contain file: 0x%I64x between 0x%I64x and 0x%I64x\n",
  2624. gllFileToMatch, LsnStart, LsnEnd);
  2625. FileRefMatchCtx.llFileRef = gllFileToMatch;
  2626. FileRefMatchCtx.pAttrMap = &AttrMap;
  2627. FileRefMatchCtx.ClusterSize = ulClusterSize;
  2628. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchFileRef, &FileRefMatchCtx);
  2629. }
  2630. if (gfDumpEverything) {
  2631. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2632. if (LsnEnd.QuadPart == 0) {
  2633. return 1;
  2634. }
  2635. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2636. if (LsnStart.QuadPart == 0) {
  2637. return 1;
  2638. }
  2639. printf("Printing LSN records between 0x%I64x and 0x%I64x\n",
  2640. LsnStart, LsnEnd );
  2641. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchAll, NULL);
  2642. }
  2643. if (glBitToMatch != -1) {
  2644. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2645. if (LsnEnd.QuadPart == 0) {
  2646. return 1;
  2647. }
  2648. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2649. if (LsnStart.QuadPart == 0) {
  2650. return 1;
  2651. }
  2652. printf("Scanning LSN records for Bit: 0x%x between 0x%I64x and 0x%I64x\n\n",
  2653. glBitToMatch, LsnStart, LsnEnd);
  2654. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchBit, &glBitToMatch);
  2655. }
  2656. if (gfScanForRestarts == TRUE) {
  2657. LsnEnd = ScanForLastLsn(hFile, Logcb.CurrentLsn);
  2658. if (LsnEnd.QuadPart == 0) {
  2659. return 1;
  2660. }
  2661. LsnStart = ScanForFirstLsn(hFile, gVerboseScan);
  2662. if (LsnStart.QuadPart == 0) {
  2663. return 1;
  2664. }
  2665. printf("Scanning LSN records for Restarts between 0x%I64x and 0x%I64x\n\n",
  2666. LsnStart, LsnEnd);
  2667. ScanLsnRangeForMatch(hFile, LsnStart, LsnEnd, MatchRestartDumps, NULL);
  2668. }
  2669. if (gllRangeStart.QuadPart != 0) {
  2670. printf("Printing LSN records between 0x%I64x and 0x%I64x\n\n",
  2671. gllRangeStart, gllRangeEnd);
  2672. ScanLsnRangeForMatch(hFile, gllRangeStart, gllRangeEnd, MatchAll, NULL);
  2673. }
  2674. printf("\n");
  2675. CloseHandle(hFile);
  2676. return 0;
  2677. } // _tmain
  2678. }