Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

649 lines
20 KiB

  1. #include "ulib.hxx"
  2. #include "untfs.hxx"
  3. #include "indxedit.hxx"
  4. #include "frsstruc.hxx"
  5. #include "ntfssa.hxx"
  6. #include "attrrec.hxx"
  7. #include "cmem.hxx"
  8. #include "ntfssa.hxx"
  9. extern "C" {
  10. #include <stdio.h>
  11. }
  12. ///////////////////////////////////////////////////////////////////////////////
  13. // Common support for USA fixups //
  14. ///////////////////////////////////////////////////////////////////////////////
  15. BOOLEAN
  16. PostReadMultiSectorFixup(
  17. IN OUT PVOID MultiSectorBuffer,
  18. IN ULONG BufferSize
  19. )
  20. /*++
  21. Routine Description:
  22. This routine first verifies that the first element of the
  23. update sequence array is written at the end of every
  24. SEQUENCE_NUMBER_STRIDE bytes. If not, then this routine
  25. returns FALSE.
  26. Otherwise this routine swaps the following elements in the
  27. update sequence array into the appropriate positions in the
  28. multi sector buffer.
  29. This routine will also check to make sure that the update
  30. sequence array is valid and that the BufferSize is appropriate
  31. for this size of update sequence array. Otherwise, this
  32. routine will not update the array sequence and return TRUE.
  33. Arguments:
  34. MultiSectorBuffer - Supplies the buffer to be updated.
  35. BufferSize - Supplies the number of bytes in this
  36. buffer.
  37. Return Value:
  38. FALSE - The last write to this buffer failed.
  39. TRUE - There is no evidence that this buffer is bad.
  40. --*/
  41. {
  42. PUNTFS_MULTI_SECTOR_HEADER pheader;
  43. USHORT i, size, offset;
  44. PUPDATE_SEQUENCE_NUMBER parray, pnumber;
  45. pheader = (PUNTFS_MULTI_SECTOR_HEADER) MultiSectorBuffer;
  46. size = pheader->UpdateSequenceArraySize;
  47. offset = pheader->UpdateSequenceArrayOffset;
  48. if (BufferSize%SEQUENCE_NUMBER_STRIDE ||
  49. offset%sizeof(UPDATE_SEQUENCE_NUMBER) ||
  50. offset + size*sizeof(UPDATE_SEQUENCE_NUMBER) > BufferSize ||
  51. BufferSize/SEQUENCE_NUMBER_STRIDE + 1 != size) {
  52. return TRUE;
  53. }
  54. parray = (PUPDATE_SEQUENCE_NUMBER) ((PCHAR) pheader + offset);
  55. for (i = 1; i < size; i++) {
  56. pnumber = (PUPDATE_SEQUENCE_NUMBER)
  57. ((PCHAR) pheader + (i*SEQUENCE_NUMBER_STRIDE -
  58. sizeof(UPDATE_SEQUENCE_NUMBER)));
  59. if (*pnumber != parray[0]) {
  60. return FALSE;
  61. }
  62. *pnumber = parray[i];
  63. }
  64. return TRUE;
  65. }
  66. VOID
  67. PreWriteMultiSectorFixup(
  68. IN OUT PVOID MultiSectorBuffer,
  69. IN ULONG BufferSize
  70. )
  71. /*++
  72. Routine Description:
  73. This routine first checks to see if the update sequence
  74. array is valid. If it is then this routine increments the
  75. first element of the update sequence array. It then
  76. writes the value of the first element into the buffer at
  77. the end of every SEQUENCE_NUMBER_STRIDE bytes while
  78. saving the old values of those locations in the following
  79. elements of the update sequence arrary.
  80. Arguments:
  81. MultiSectorBuffer - Supplies the buffer to be updated.
  82. BufferSize - Supplies the number of bytes in this
  83. buffer.
  84. Return Value:
  85. None.
  86. --*/
  87. {
  88. PUNTFS_MULTI_SECTOR_HEADER pheader;
  89. USHORT i, size, offset;
  90. PUPDATE_SEQUENCE_NUMBER parray, pnumber;
  91. pheader = (PUNTFS_MULTI_SECTOR_HEADER) MultiSectorBuffer;
  92. size = pheader->UpdateSequenceArraySize;
  93. offset = pheader->UpdateSequenceArrayOffset;
  94. if (BufferSize%SEQUENCE_NUMBER_STRIDE ||
  95. offset%sizeof(UPDATE_SEQUENCE_NUMBER) ||
  96. offset + size*sizeof(UPDATE_SEQUENCE_NUMBER) > BufferSize ||
  97. BufferSize/SEQUENCE_NUMBER_STRIDE + 1 != size) {
  98. return;
  99. }
  100. parray = (PUPDATE_SEQUENCE_NUMBER) ((PCHAR) pheader + offset);
  101. parray[0]++;
  102. for (i = 1; i < size; i++) {
  103. pnumber = (PUPDATE_SEQUENCE_NUMBER)
  104. ((PCHAR) pheader + (i*SEQUENCE_NUMBER_STRIDE -
  105. sizeof(UPDATE_SEQUENCE_NUMBER)));
  106. parray[i] = *pnumber;
  107. *pnumber = parray[0];
  108. }
  109. }
  110. ///////////////////////////////////////////////////////////////////////////////
  111. // Common support for viewing indexes //
  112. ///////////////////////////////////////////////////////////////////////////////
  113. BOOLEAN
  114. INDEX_BUFFER_BASE::Initialize(
  115. IN HWND WindowHandle,
  116. IN INT ClientHeight,
  117. IN INT ClientWidth,
  118. IN PLOG_IO_DP_DRIVE Drive
  119. )
  120. {
  121. TEXTMETRIC textmetric;
  122. HDC hdc;
  123. NTFS_SA ntfssa;
  124. MESSAGE msg;
  125. hdc = GetDC(WindowHandle);
  126. if (hdc == NULL)
  127. return FALSE;
  128. GetTextMetrics(hdc, &textmetric);
  129. ReleaseDC(WindowHandle, hdc);
  130. _buffer = NULL;
  131. _size = 0;
  132. return VERTICAL_TEXT_SCROLL::Initialize(
  133. WindowHandle,
  134. 0,
  135. ClientHeight,
  136. ClientWidth,
  137. textmetric.tmExternalLeading + textmetric.tmHeight,
  138. textmetric.tmMaxCharWidth);
  139. }
  140. VOID
  141. INDEX_BUFFER_BASE::SetBuf(
  142. IN HWND WindowHandle,
  143. IN OUT PVOID Buffer,
  144. IN ULONG Size
  145. )
  146. {
  147. _buffer = Buffer;
  148. _size = Size;
  149. SetScrollPos(WindowHandle, SB_VERT, 0, FALSE);
  150. }
  151. VOID
  152. INDEX_BUFFER_BASE::KeyUp(
  153. IN HWND WindowHandle
  154. )
  155. {
  156. ScrollUp(WindowHandle);
  157. }
  158. VOID
  159. INDEX_BUFFER_BASE::KeyDown(
  160. IN HWND WindowHandle
  161. )
  162. {
  163. ScrollDown(WindowHandle);
  164. }
  165. VOID
  166. INDEX_BUFFER_BASE::Paint(
  167. IN HDC DeviceContext,
  168. IN RECT InvalidRect,
  169. IN HWND WindowHandle
  170. )
  171. {
  172. TCHAR buf[1024];
  173. SelectObject(DeviceContext, GetStockObject(ANSI_FIXED_FONT));
  174. if (!_buffer || !_size) {
  175. return;
  176. }
  177. if (0 != memcmp(_buffer, "INDX", 4) && 0 != memcmp(_buffer, "BAAD", 4)) {
  178. PaintIndexRoot(DeviceContext, InvalidRect, WindowHandle);
  179. return;
  180. }
  181. INT BytesRemaining = _size;
  182. PVOID CurrentBuffer = _buffer;
  183. INT CurrentLine = 0;
  184. ULONG BufferNumber = 0;;
  185. while( BytesRemaining ) {
  186. // Resolve the update sequence array. Note that we must
  187. // resolve it back before we exit this function, or else
  188. // write will get hosed.
  189. //
  190. PINDEX_ALLOCATION_BUFFER IndexBuffer =
  191. (PINDEX_ALLOCATION_BUFFER)CurrentBuffer;
  192. INT BytesPerIndexBuffer =
  193. FIELD_OFFSET( INDEX_ALLOCATION_BUFFER, IndexHeader ) +
  194. IndexBuffer->IndexHeader.BytesAvailable;
  195. ULONG CurrentOffset =
  196. BufferNumber * BytesPerIndexBuffer +
  197. FIELD_OFFSET( INDEX_ALLOCATION_BUFFER, IndexHeader );
  198. PostReadMultiSectorFixup( CurrentBuffer, BytesPerIndexBuffer );
  199. swprintf(buf, TEXT("Signature: %c%c%c%c"),
  200. IndexBuffer->MultiSectorHeader.Signature[0],
  201. IndexBuffer->MultiSectorHeader.Signature[1],
  202. IndexBuffer->MultiSectorHeader.Signature[2],
  203. IndexBuffer->MultiSectorHeader.Signature[3]);
  204. WriteLine( DeviceContext, CurrentLine++, buf );
  205. swprintf(buf, TEXT("Update sequence array offset: %x"),
  206. IndexBuffer->MultiSectorHeader.UpdateSequenceArrayOffset);
  207. WriteLine( DeviceContext, CurrentLine++, buf );
  208. swprintf(buf, TEXT("Update sequence array size: %x"),
  209. IndexBuffer->MultiSectorHeader.UpdateSequenceArraySize);
  210. WriteLine( DeviceContext, CurrentLine++, buf );
  211. swprintf(buf, TEXT("This VCN: %x"), IndexBuffer->ThisVcn.GetLowPart() );
  212. WriteLine( DeviceContext, CurrentLine++, buf );
  213. swprintf( buf, TEXT("") );
  214. WriteLine( DeviceContext, CurrentLine++, buf );
  215. swprintf(buf, TEXT("INDEX HEADER at offset %x"), CurrentOffset );
  216. WriteLine( DeviceContext, CurrentLine++, buf );
  217. swprintf( buf, TEXT(" FirstIndexEntry: \t%x"),
  218. IndexBuffer->IndexHeader.FirstIndexEntry );
  219. WriteLine( DeviceContext, CurrentLine++, buf );
  220. swprintf( buf, TEXT(" FirstFreeByte: \t%x"),
  221. IndexBuffer->IndexHeader.FirstFreeByte );
  222. WriteLine( DeviceContext, CurrentLine++, buf );
  223. swprintf( buf, TEXT(" BytesAvailable: \t%x"),
  224. IndexBuffer->IndexHeader.BytesAvailable );
  225. WriteLine( DeviceContext, CurrentLine++, buf );
  226. swprintf( buf, TEXT(" Flags: \t\t%x"), IndexBuffer->IndexHeader.Flags );
  227. if( IndexBuffer->IndexHeader.Flags & INDEX_NODE ) {
  228. wcscat( buf, TEXT("\t INDEX_NODE "));
  229. }
  230. WriteLine( DeviceContext, CurrentLine++, buf );
  231. //
  232. // Don't print the Update Sequence Array--it's not interesting.
  233. //
  234. //
  235. // Now iterate through the index entries:
  236. //
  237. CurrentOffset += IndexBuffer->IndexHeader.FirstIndexEntry;
  238. WalkAndPaintIndexRecords( DeviceContext, CurrentOffset, CurrentLine );
  239. PreWriteMultiSectorFixup( CurrentBuffer, BytesPerIndexBuffer );
  240. if( BytesRemaining <= BytesPerIndexBuffer ) {
  241. BytesRemaining = 0;
  242. } else {
  243. BytesRemaining -= BytesPerIndexBuffer;
  244. CurrentBuffer = (PBYTE)CurrentBuffer + BytesPerIndexBuffer;
  245. BufferNumber++;
  246. WriteLine( DeviceContext, CurrentLine++, TEXT("") );
  247. WriteLine( DeviceContext, CurrentLine++, TEXT("****************************************") );
  248. WriteLine( DeviceContext, CurrentLine++, TEXT("") );
  249. WriteLine( DeviceContext, CurrentLine++, TEXT("****************************************") );
  250. WriteLine( DeviceContext, CurrentLine++, TEXT("") );
  251. }
  252. }
  253. SetRange(WindowHandle, CurrentLine + 50);
  254. }
  255. VOID
  256. INDEX_BUFFER_BASE::PaintIndexRoot(
  257. IN HDC DeviceContext,
  258. IN RECT InvalidRect,
  259. IN HWND WindowHandle
  260. )
  261. {
  262. TCHAR buf[1024];
  263. INT BytesRemaining = _size;
  264. PVOID CurrentBuffer = _buffer;
  265. INT CurrentLine = 0;
  266. ULONG BufferNumber = 0;
  267. PINDEX_ROOT IndexRoot = (PINDEX_ROOT)CurrentBuffer;
  268. ULONG BytesPerIndexRoot =
  269. FIELD_OFFSET(INDEX_ROOT, IndexHeader ) +
  270. IndexRoot->IndexHeader.BytesAvailable;
  271. ULONG CurrentOffset = FIELD_OFFSET(INDEX_ROOT, IndexHeader);
  272. swprintf(buf, TEXT("Attribute type code: %x"),
  273. IndexRoot->IndexedAttributeType);
  274. WriteLine( DeviceContext, CurrentLine++, buf );
  275. swprintf(buf, TEXT("Collation rule: %x"), IndexRoot->CollationRule);
  276. WriteLine( DeviceContext, CurrentLine++, buf );
  277. swprintf(buf, TEXT("Bytes Per Index Buffer: %x"),
  278. IndexRoot->BytesPerIndexBuffer);
  279. WriteLine( DeviceContext, CurrentLine++, buf );
  280. swprintf(buf, TEXT("Clusters Per Index Buffer: %x"),
  281. IndexRoot->ClustersPerIndexBuffer);
  282. WriteLine( DeviceContext, CurrentLine++, buf );
  283. swprintf(buf, TEXT("INDEX HEADER at offset %x"), CurrentOffset );
  284. WriteLine( DeviceContext, CurrentLine++, buf );
  285. swprintf( buf, TEXT(" FirstIndexEntry: \t%x"),
  286. IndexRoot->IndexHeader.FirstIndexEntry );
  287. WriteLine( DeviceContext, CurrentLine++, buf );
  288. swprintf( buf, TEXT(" FirstFreeByte: \t%x"),
  289. IndexRoot->IndexHeader.FirstFreeByte );
  290. WriteLine( DeviceContext, CurrentLine++, buf );
  291. swprintf( buf, TEXT(" BytesAvailable: \t%x"),
  292. IndexRoot->IndexHeader.BytesAvailable );
  293. WriteLine( DeviceContext, CurrentLine++, buf );
  294. swprintf( buf, TEXT(" Flags: \t\t%x"), IndexRoot->IndexHeader.Flags );
  295. if( IndexRoot->IndexHeader.Flags & INDEX_NODE ) {
  296. wcscat( buf, TEXT("\t INDEX_NODE "));
  297. }
  298. WriteLine( DeviceContext, CurrentLine++, buf );
  299. //
  300. // Now iterate through the index entries:
  301. //
  302. CurrentOffset += IndexRoot->IndexHeader.FirstIndexEntry;
  303. WalkAndPaintIndexRecords( DeviceContext, CurrentOffset, CurrentLine );
  304. }
  305. VOID
  306. INDEX_BUFFER_BASE::WalkAndPaintIndexRecords(
  307. IN HDC DeviceContext,
  308. IN ULONG Offset,
  309. IN OUT int &CurrentLine
  310. )
  311. {
  312. TCHAR buf[1024];
  313. //
  314. // Iterate through the index entries:
  315. //
  316. while( Offset < _size ) {
  317. PINDEX_ENTRY CurrentEntry = (PINDEX_ENTRY)((PBYTE)_buffer + Offset);
  318. //
  319. // check for corruption that will mess up the loop--if
  320. // the length of the current entry is zero or would overflow
  321. // the buffer, exit.
  322. //
  323. if( CurrentEntry->Length == 0 ||
  324. Offset + CurrentEntry->Length > _size ) {
  325. // Don't need to comment on the corruption--the user
  326. // can recognize it by noting that the last entry
  327. // is not an END entry.
  328. //
  329. break;
  330. }
  331. swprintf( buf, TEXT("") );
  332. WriteLine( DeviceContext, CurrentLine++, buf );
  333. swprintf( buf, TEXT("INDEX ENTRY at offset %x"), Offset );
  334. WriteLine( DeviceContext, CurrentLine++, buf );
  335. swprintf( buf, TEXT(" Length: \t %x"), CurrentEntry->Length );
  336. WriteLine( DeviceContext, CurrentLine++, buf );
  337. swprintf( buf, TEXT(" Value Length: %x"), CurrentEntry->AttributeLength );
  338. WriteLine( DeviceContext, CurrentLine++, buf );
  339. swprintf( buf, TEXT(" Flags: \t %x"), CurrentEntry->Flags );
  340. if( CurrentEntry->Flags & INDEX_ENTRY_NODE ) {
  341. wcscat( buf, TEXT(" INDEX_ENTRY_NODE") );
  342. }
  343. if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
  344. wcscat( buf, TEXT(" INDEX_ENTRY_END") );
  345. }
  346. WriteLine( DeviceContext, CurrentLine++, buf );
  347. if( CurrentEntry->Flags & INDEX_ENTRY_NODE ) {
  348. swprintf( buf, TEXT(" Downpointer: %x"), (GetDownpointer(CurrentEntry)).GetLowPart() );
  349. WriteLine( DeviceContext, CurrentLine++, buf );
  350. }
  351. //
  352. // If the current entry is the END entry, we're done.
  353. //
  354. if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
  355. break;
  356. }
  357. if( sizeof( INDEX_ENTRY ) + CurrentEntry->AttributeLength >
  358. CurrentEntry->Length ) {
  359. swprintf( buf, TEXT(" ***Attribute value overflows entry.") );
  360. WriteLine( DeviceContext, CurrentLine++, buf );
  361. } else {
  362. PaintIndexRecord( DeviceContext, CurrentEntry, CurrentLine );
  363. }
  364. Offset += CurrentEntry->Length;
  365. }
  366. }
  367. ///////////////////////////////////////////////////////////////////////////////
  368. // Support for viewing namespace indexes //
  369. ///////////////////////////////////////////////////////////////////////////////
  370. VOID
  371. NAME_INDEX_BUFFER_EDIT::PaintIndexRecord (
  372. IN HDC DeviceContext,
  373. IN PINDEX_ENTRY CurrentEntry,
  374. IN OUT int & CurrentLine
  375. )
  376. {
  377. TCHAR buf[1024];
  378. PFILE_NAME FileName;
  379. ULONG i, j;
  380. swprintf( buf, TEXT(" File Reference (FRS, Seq No): %x, %x"),
  381. CurrentEntry->FileReference.LowPart,
  382. CurrentEntry->FileReference.SequenceNumber );
  383. WriteLine( DeviceContext, CurrentLine++, buf );
  384. // This had better be a file name attribute, since
  385. // that's how I'll display it.
  386. //
  387. swprintf( buf, TEXT(" FILE NAME at offset %x"),
  388. (PCHAR) CurrentEntry - (PCHAR) _buffer + sizeof( INDEX_ENTRY ) );
  389. FileName = (PFILE_NAME)( (PBYTE)CurrentEntry + sizeof(INDEX_ENTRY) );
  390. WriteLine( DeviceContext, CurrentLine++, buf );
  391. swprintf( buf, TEXT(" Parent Directory (FRS, Seq No): %x, %x"),
  392. FileName->ParentDirectory.LowPart,
  393. FileName->ParentDirectory.SequenceNumber );
  394. WriteLine( DeviceContext, CurrentLine++, buf );
  395. swprintf( buf, TEXT(" Name Length: %x"), FileName->FileNameLength );
  396. WriteLine( DeviceContext, CurrentLine++, buf );
  397. swprintf( buf, TEXT(" Flags: \t %x"), FileName->Flags );
  398. if( FileName->Flags & FILE_NAME_DOS ) {
  399. wcscat( buf, TEXT(" D") );
  400. }
  401. if( FileName->Flags & FILE_NAME_NTFS ) {
  402. wcscat( buf, TEXT(" N") );
  403. }
  404. WriteLine( DeviceContext, CurrentLine++, buf );
  405. swprintf( buf, TEXT(" File name: ") );
  406. j = wcslen( buf );
  407. for( i = 0; i < FileName->FileNameLength; i++ ) {
  408. buf[i+j] = (TCHAR)(FileName->FileName[i]);
  409. }
  410. buf[FileName->FileNameLength+j] = 0;
  411. WriteLine( DeviceContext, CurrentLine++, buf );
  412. }
  413. ///////////////////////////////////////////////////////////////////////////////
  414. // Support for viewing Security Id indexes //
  415. ///////////////////////////////////////////////////////////////////////////////
  416. VOID
  417. SECURITY_ID_INDEX_BUFFER_EDIT::PaintIndexRecord(
  418. IN HDC DeviceContext,
  419. IN PINDEX_ENTRY CurrentEntry,
  420. IN OUT int & CurrentLine
  421. )
  422. {
  423. TCHAR buf[1024];
  424. //
  425. // This had better be a security id index record. The format of
  426. // the record is:
  427. //
  428. // INDEX_ENTRY
  429. // DataOffset
  430. // DataLength
  431. // SECURITY_ID
  432. // SECURITY_DESCRIPTOR_HEADER
  433. //
  434. swprintf( buf, TEXT( " DataOffset %x" ), CurrentEntry->DataOffset );
  435. WriteLine( DeviceContext, CurrentLine++, buf );
  436. swprintf( buf, TEXT( " DataLength %x" ), CurrentEntry->DataLength );
  437. WriteLine( DeviceContext, CurrentLine++, buf );
  438. PULONG SecurityId = (PULONG) ((PBYTE)CurrentEntry + sizeof( INDEX_ENTRY ));
  439. PSECURITY_DESCRIPTOR_HEADER Header =
  440. (PSECURITY_DESCRIPTOR_HEADER) ((PBYTE)CurrentEntry + CurrentEntry->DataOffset);
  441. swprintf( buf, TEXT( " Key Security Id %08x" ), *SecurityId );
  442. WriteLine( DeviceContext, CurrentLine++, buf );
  443. swprintf( buf, TEXT( " HashKey.Hash %08x" ), Header->HashKey.Hash );
  444. WriteLine( DeviceContext, CurrentLine++, buf );
  445. swprintf( buf, TEXT( " HashKey.SecurityId %08x" ), Header->HashKey.SecurityId );
  446. WriteLine( DeviceContext, CurrentLine++, buf );
  447. swprintf( buf, TEXT( " Header.Offset %I64x" ), Header->Offset );
  448. WriteLine( DeviceContext, CurrentLine++, buf );
  449. swprintf( buf, TEXT( " Header.Length %x" ), Header->Length );
  450. WriteLine( DeviceContext, CurrentLine++, buf );
  451. }
  452. ///////////////////////////////////////////////////////////////////////////////
  453. // Support for viewing Security Hash indexes //
  454. ///////////////////////////////////////////////////////////////////////////////
  455. VOID
  456. SECURITY_HASH_INDEX_BUFFER_EDIT::PaintIndexRecord(
  457. IN HDC DeviceContext,
  458. IN PINDEX_ENTRY CurrentEntry,
  459. IN OUT int & CurrentLine
  460. )
  461. {
  462. TCHAR buf[1024];
  463. //
  464. // This had better be a security id index record. The format of
  465. // the record is:
  466. //
  467. // INDEX_ENTRY
  468. // DataOffset
  469. // DataLength
  470. // SECURITY_HASHKEY
  471. // SECURITY_DESCRIPTOR_HEADER
  472. //
  473. swprintf( buf, TEXT( " DataOffset %x" ), CurrentEntry->DataOffset );
  474. WriteLine( DeviceContext, CurrentLine++, buf );
  475. swprintf( buf, TEXT( " DataLength %x" ), CurrentEntry->DataLength );
  476. WriteLine( DeviceContext, CurrentLine++, buf );
  477. PSECURITY_HASH_KEY HashKey = (PSECURITY_HASH_KEY) ((PBYTE)CurrentEntry + sizeof( INDEX_ENTRY ));
  478. PSECURITY_DESCRIPTOR_HEADER Header =
  479. (PSECURITY_DESCRIPTOR_HEADER) ((PBYTE)CurrentEntry + CurrentEntry->DataOffset);
  480. swprintf( buf, TEXT( " HashKey.Hash %08x" ), HashKey->Hash );
  481. WriteLine( DeviceContext, CurrentLine++, buf );
  482. swprintf( buf, TEXT( " HashKey.SecurityId %08x" ), HashKey->SecurityId );
  483. WriteLine( DeviceContext, CurrentLine++, buf );
  484. swprintf( buf, TEXT( " HashKey.Hash %08x" ), Header->HashKey.Hash );
  485. WriteLine( DeviceContext, CurrentLine++, buf );
  486. swprintf( buf, TEXT( " HashKey.SecurityId %08x" ), Header->HashKey.SecurityId );
  487. WriteLine( DeviceContext, CurrentLine++, buf );
  488. swprintf( buf, TEXT( " Header.Offset %I64x" ), Header->Offset );
  489. WriteLine( DeviceContext, CurrentLine++, buf );
  490. swprintf( buf, TEXT( " Header.Length %x" ), Header->Length );
  491. WriteLine( DeviceContext, CurrentLine++, buf );
  492. }