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.

836 lines
34 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. engine.cpp
  5. Abstract:
  6. The file system dump utility engine.
  7. Author:
  8. Stefan R. Steiner [ssteiner] 02-18-2000
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "direntrs.h"
  13. #include "extattr.h"
  14. #include "engine.h"
  15. static VOID
  16. TimeString(
  17. IN FILETIME *pFileTime,
  18. IN BOOL bAddMillisecsToTimestamps,
  19. OUT LPWSTR pwszTimeStr
  20. );
  21. /*++
  22. Routine Description:
  23. Performs the actual dump of the directory or file.
  24. Arguments:
  25. Return Value:
  26. <Enter return values here>
  27. --*/
  28. DWORD
  29. CDumpEngine::PerformDump()
  30. {
  31. //
  32. // Perform the actual dump
  33. //
  34. DWORD dwRet;
  35. //
  36. // Kind of a hack, set the no data string if we want something other than dashes
  37. //
  38. if ( m_pcParams->m_bDumpCommaDelimited )
  39. FsdEaSetNoDataString( L"" );
  40. //
  41. // Volume state manager manages all state about all volumes that are encountered during
  42. // the dump.
  43. //
  44. CFsdVolumeStateManager cFsdVolStateManager( m_pcParams );
  45. //
  46. // Get information about the volume
  47. //
  48. CFsdVolumeState *pcFsdVolState;
  49. dwRet = cFsdVolStateManager.GetVolumeState( m_cwsDirFileSpec, &pcFsdVolState );
  50. assert( dwRet != ERROR_ALREADY_EXISTS );
  51. if ( dwRet != ERROR_SUCCESS )
  52. return dwRet;
  53. if ( m_pcParams->m_bDumpCommaDelimited )
  54. {
  55. m_pcParams->DumpPrintAlways( L"File name,Short Name,Creation date,Last modification date,File size,Attr,DACE,SACE,SDCtl,UNamChkS,DStr,DStrSize,DStrChkS,Prop,RPTag,RPSize,RPChkS,EncrChkS,DACLSize,DACLChkS,SACLSize,SACLChkS,NLnk,ObjectId,OIDChkS,FS,Owner Sid,Group Sid" );
  56. //
  57. // Put the current time into the CSV dump file for easy detection of when
  58. // dumps are taken
  59. //
  60. FILETIME sSysFT, sLocalFT;
  61. ::GetSystemTimeAsFileTime( &sSysFT );
  62. ::FileTimeToLocalFileTime( &sSysFT, &sLocalFT );
  63. WCHAR wszCurrentTime[32];
  64. ::TimeString( &sLocalFT, FALSE, wszCurrentTime );
  65. m_pcParams->DumpPrintAlways( L"Dump time: %s", wszCurrentTime );
  66. }
  67. else
  68. {
  69. // if ( ( m_pcParams->m_eFsDumpType == eFsDumpVolume ) &&
  70. // ( m_cwsDirFileSpec != pcFsdVolState->GetVolumePath() ) )
  71. // {
  72. // m_pcParams->ErrPrint( L"'%s' is not a drive specifier or mountpoint, use -dd instead",
  73. // m_cwsDirFileSpec.c_str() );
  74. // return 1;
  75. // }
  76. m_pcParams->DumpPrintAlways( L"\nDumping: '%s' on volume '%s'", m_cwsDirFileSpec.c_str(), pcFsdVolState->GetVolumePath() );
  77. if ( m_pcParams->m_bAddMillisecsToTimestamps )
  78. m_pcParams->DumpPrintAlways(
  79. L" Creation date Last modification date FileSize Attr FileName ShortName DACE SACE SDCtl UNamChkS DStr DStrSize DStrChkS Prop RPTag RPSize RPChkS EncrChkS DACLSize DACLChkS SACLSize SACLChkS NLnk ObjectId OIDChkS OwnerSid/GroupSid" );
  80. else
  81. m_pcParams->DumpPrintAlways( L" Creation date Last mod. date FileSize Attr FileName ShortName DACE SACE SDCtl UNamChkS DStr DStrSize DStrChkS Prop RPTag RPSize RPChkS EncrChkS DACLSize DACLChkS SACLSize SACLChkS NLnk ObjectId OIDChkS OwnerSid/GroupSid" );
  82. }
  83. ////////////////////////////////////////////////////////////////////
  84. //
  85. // Get the file info for the root dir or file
  86. // Bug # 157915
  87. //
  88. ////////////////////////////////////////////////////////////////////
  89. bool bRootIsADir = true;
  90. CBsString cwsDirFileSpecWithoutSlash( m_cwsDirFileSpec );
  91. if ( cwsDirFileSpecWithoutSlash.Right( 1 ) == L"\\" )
  92. cwsDirFileSpecWithoutSlash = cwsDirFileSpecWithoutSlash.Left( cwsDirFileSpecWithoutSlash.GetLength() - 1 );
  93. try
  94. {
  95. CDirectoryEntries cRootEntry(
  96. m_pcParams,
  97. cwsDirFileSpecWithoutSlash
  98. );
  99. //
  100. // Only one entry should be returned in either the directory list or file list
  101. //
  102. SDirectoryEntry *psDirEntry;
  103. //
  104. // See if it is file entry
  105. //
  106. CDirectoryEntriesIterator *pListIter;
  107. pListIter = cRootEntry.GetFileListIterator();
  108. if ( pListIter->GetNext( psDirEntry ) )
  109. {
  110. bRootIsADir = false;
  111. ++m_ullNumFiles;
  112. m_ullNumBytesTotalUnnamedStream += ( ( ( ULONGLONG )psDirEntry->m_sFindData.nFileSizeHigh ) << 32 ) |
  113. psDirEntry->m_sFindData.nFileSizeLow;
  114. if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED )
  115. ++m_ullNumEncryptedFiles;
  116. PrintEntry( pcFsdVolState, cwsDirFileSpecWithoutSlash,
  117. cwsDirFileSpecWithoutSlash.GetLength(), psDirEntry, TRUE );
  118. ASSERT( pListIter->GetNext( psDirEntry ) == false );
  119. }
  120. delete pListIter;
  121. //
  122. // See if it is a directory entry
  123. //
  124. pListIter = cRootEntry.GetDirListIterator();
  125. if ( pListIter->GetNext( psDirEntry ) )
  126. {
  127. ASSERT( bRootIsADir );
  128. // It is
  129. ++m_ullNumDirs;
  130. PrintEntry( pcFsdVolState, cwsDirFileSpecWithoutSlash,
  131. cwsDirFileSpecWithoutSlash.GetLength(), psDirEntry, TRUE );
  132. ASSERT( pListIter->GetNext( psDirEntry ) == false );
  133. }
  134. delete pListIter;
  135. }
  136. catch ( DWORD dwRet )
  137. {
  138. if ( dwRet == ERROR_INVALID_NAME || dwRet == ERROR_BAD_NET_NAME )
  139. {
  140. //
  141. // Must be working with the root of the drive letter name space which
  142. // means we do things slightly differently.
  143. //
  144. SDirectoryEntry sDirEntry;
  145. ::memset( &sDirEntry.m_sFindData, 0x00, sizeof( sDirEntry.m_sFindData ) );
  146. PrintEntry( pcFsdVolState, m_cwsDirFileSpec,
  147. m_cwsDirFileSpec.GetLength(), &sDirEntry, TRUE );
  148. }
  149. else
  150. m_pcParams->ErrPrint( L"PerformDump: Unexpected error trying to process '%s', dwRet: %d",
  151. m_cwsDirFileSpec.c_str(), dwRet );
  152. }
  153. catch ( ... )
  154. {
  155. m_pcParams->ErrPrint( L"ProcessDir() Caught an unexpected exception processing file: '%s', Last dwRet: %d",
  156. m_cwsDirFileSpec.c_str(), ::GetLastError() );
  157. }
  158. //
  159. // Now traverse into the volume/directory if necessary
  160. //
  161. if ( m_pcParams->m_eFsDumpType != eFsDumpFile )
  162. {
  163. if ( bRootIsADir )
  164. {
  165. dwRet = ProcessDir(
  166. &cFsdVolStateManager,
  167. pcFsdVolState,
  168. m_cwsDirFileSpec,
  169. m_cwsDirFileSpec.GetLength(),
  170. ::wcslen( pcFsdVolState->GetVolumePath() ) );
  171. }
  172. //
  173. // Print out some stats about the dump
  174. //
  175. m_pcParams->DumpPrint( L"\nSTATISTICS for '%s':", m_cwsDirFileSpec.c_str() );
  176. if ( m_pcParams->m_bHex )
  177. {
  178. m_pcParams->DumpPrint( L" Number of directories (including mountpoints): %16I64x(hex)", m_ullNumDirs );
  179. m_pcParams->DumpPrint( L" Number of files: %16I64x(hex)", m_ullNumFiles );
  180. m_pcParams->DumpPrint( L" Number of mountpoints: %16I64x(hex)", m_ullNumMountpoints );
  181. m_pcParams->DumpPrint( L" Number of reparse points (excluding mountpoints): %16I64x(hex)", m_ullNumReparsePoints );
  182. m_pcParams->DumpPrint( L" Number of hard-linked files: %16I64x(hex)", m_ullNumHardLinks );
  183. m_pcParams->DumpPrint( L" Number of discrete DACL ACEs: %16I64x(hex)", m_ullNumDiscreteDACEs );
  184. m_pcParams->DumpPrint( L" Number of discrete SACL ACEs: %16I64x(hex)", m_ullNumDiscreteSACEs );
  185. m_pcParams->DumpPrint( L" Number of encrypted files: %16I64x(hex)", m_ullNumEncryptedFiles );
  186. m_pcParams->DumpPrint( L" Number of files with object ids: %16I64x(hex)", m_ullNumFilesWithObjectIds );
  187. if ( m_pcParams->m_bUseExcludeProcessor )
  188. m_pcParams->DumpPrint( L" Number of files excluded due to exclusion rules: %16I64x(hex)", m_ullNumFilesExcluded );
  189. m_pcParams->DumpPrint( L" Total bytes of checksummed data: %16I64x(hex)", m_ullNumBytesChecksummed );
  190. m_pcParams->DumpPrint( L" Total bytes of unnamed stream data: %16I64x(hex)", m_ullNumBytesTotalUnnamedStream );
  191. m_pcParams->DumpPrint( L" Total bytes of named data stream data: %16I64x(hex)", m_ullNumBytesTotalNamedDataStream );
  192. }
  193. else
  194. {
  195. m_pcParams->DumpPrint( L" Number of directories (including mountpoints): %16I64u", m_ullNumDirs );
  196. m_pcParams->DumpPrint( L" Number of files: %16I64u", m_ullNumFiles );
  197. m_pcParams->DumpPrint( L" Number of mountpoints: %16I64u", m_ullNumMountpoints );
  198. m_pcParams->DumpPrint( L" Number of reparse points (excluding mountpoints): %16I64u", m_ullNumReparsePoints );
  199. m_pcParams->DumpPrint( L" Number of hard-linked files: %16I64u", m_ullNumHardLinks );
  200. m_pcParams->DumpPrint( L" Number of discrete DACL ACEs: %16I64u", m_ullNumDiscreteDACEs );
  201. m_pcParams->DumpPrint( L" Number of discrete SACL ACEs: %16I64u", m_ullNumDiscreteSACEs );
  202. m_pcParams->DumpPrint( L" Number of encrypted files: %16I64u", m_ullNumEncryptedFiles );
  203. m_pcParams->DumpPrint( L" Number of files with object ids: %16I64u", m_ullNumFilesWithObjectIds );
  204. if ( m_pcParams->m_bUseExcludeProcessor )
  205. m_pcParams->DumpPrint( L" Number of files excluded due to exclusion rules: %16I64u", m_ullNumFilesExcluded );
  206. m_pcParams->DumpPrint( L" Total bytes of checksummed data: %16I64u", m_ullNumBytesChecksummed );
  207. m_pcParams->DumpPrint( L" Total bytes of unnamed stream data: %16I64u", m_ullNumBytesTotalUnnamedStream );
  208. m_pcParams->DumpPrint( L" Total bytes of named data stream data: %16I64u", m_ullNumBytesTotalNamedDataStream );
  209. }
  210. if ( m_pcParams->m_bUseExcludeProcessor )
  211. {
  212. //
  213. // Print out exclusion information
  214. //
  215. cFsdVolStateManager.PrintExclusionInformation();
  216. }
  217. cFsdVolStateManager.PrintHardLinkInfo();
  218. }
  219. return dwRet;
  220. }
  221. /*++
  222. Routine Description:
  223. Traverses into a directory and dumps all the information about the dir.
  224. NOTE: This is a recursive function.
  225. Arguments:
  226. cwsDirPath - The directory path or file to dump information about
  227. Return Value:
  228. <Enter return values here>
  229. --*/
  230. DWORD
  231. CDumpEngine::ProcessDir(
  232. IN CFsdVolumeStateManager *pcFsdVolStateManager,
  233. IN CFsdVolumeState *pcFsdVolState,
  234. IN const CBsString& cwsDirPath,
  235. IN INT cDirFileSpecLength,
  236. IN INT cVolMountPointOffset
  237. )
  238. {
  239. DWORD dwRet = ERROR_SUCCESS;
  240. try
  241. {
  242. if ( !m_pcParams->m_bDumpCommaDelimited )
  243. {
  244. if ( cwsDirPath.GetLength() == cDirFileSpecLength )
  245. {
  246. //
  247. // This is the root of the directory
  248. //
  249. m_pcParams->DumpPrintAlways( L"'.\\' - %s", ( pcFsdVolState != NULL ) ? pcFsdVolState->GetFileSystemName() : L"???" );
  250. }
  251. else
  252. {
  253. m_pcParams->DumpPrintAlways( L"'%s' - %s", cwsDirPath.c_str() + cDirFileSpecLength,
  254. ( pcFsdVolState != NULL ) ? pcFsdVolState->GetFileSystemName() : L"???" );
  255. }
  256. }
  257. //
  258. // Get the directory entries for the directory/file
  259. //
  260. CDirectoryEntries cDirEntries(
  261. m_pcParams,
  262. cwsDirPath + L"*"
  263. );
  264. SDirectoryEntry *psDirEntry;
  265. //
  266. // First dump out the sub-directory entries
  267. //
  268. CDirectoryEntriesIterator *pDirListIter;
  269. pDirListIter = cDirEntries.GetDirListIterator();
  270. while ( pDirListIter->GetNext( psDirEntry ) )
  271. {
  272. ++m_ullNumDirs;
  273. if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  274. {
  275. ++m_ullNumMountpoints;
  276. }
  277. PrintEntry( pcFsdVolState, cwsDirPath, cDirFileSpecLength, psDirEntry );
  278. }
  279. //
  280. // Next dump out the non-sub-directory entries
  281. //
  282. CDirectoryEntriesIterator *pFileListIter;
  283. pFileListIter = cDirEntries.GetFileListIterator();
  284. while ( pFileListIter->GetNext( psDirEntry ) )
  285. {
  286. ++m_ullNumFiles;
  287. m_ullNumBytesTotalUnnamedStream += ( ( ( ULONGLONG )psDirEntry->m_sFindData.nFileSizeHigh ) << 32 ) |
  288. psDirEntry->m_sFindData.nFileSizeLow;
  289. if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  290. ++m_ullNumReparsePoints;
  291. if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED )
  292. ++m_ullNumEncryptedFiles;
  293. //
  294. // Check to see if we should exclude the file
  295. //
  296. if ( pcFsdVolState->IsExcludedFile( cwsDirPath, cVolMountPointOffset, psDirEntry->GetFileName() ) )
  297. ++m_ullNumFilesExcluded;
  298. else
  299. PrintEntry( pcFsdVolState, cwsDirPath, cDirFileSpecLength, psDirEntry );
  300. }
  301. delete pFileListIter;
  302. if ( m_pcParams->m_eFsDumpType == eFsDumpVolume
  303. || m_pcParams->m_eFsDumpType == eFsDumpDirTraverse )
  304. {
  305. //
  306. // Now traverse into each sub-directory
  307. //
  308. pDirListIter->Reset();
  309. CBsString cwsTraversePath;
  310. while ( pDirListIter->GetNext( psDirEntry ) )
  311. {
  312. if ( m_pcParams->m_bDontTraverseMountpoints
  313. && psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  314. continue;
  315. cwsTraversePath = cwsDirPath + psDirEntry->GetFileName();
  316. cwsTraversePath += L'\\';
  317. //
  318. // Now go into recursion mode
  319. //
  320. if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  321. {
  322. //
  323. // Traversing into another volume, get it's state
  324. //
  325. CFsdVolumeState *pcNewFsdVolState;
  326. DWORD dwRet;
  327. dwRet = pcFsdVolStateManager->GetVolumeState( cwsTraversePath, &pcNewFsdVolState );
  328. if ( dwRet == ERROR_ALREADY_EXISTS )
  329. {
  330. //
  331. // Mountpoint cycle, stop traversing. Need to print the fully qualified
  332. // path if the traversal mountpoint is the same as the mountpoint
  333. // we started with, otherwise we AV.
  334. //
  335. INT cVolStateSpecLength;
  336. cVolStateSpecLength = ( ::wcslen( pcNewFsdVolState->GetVolumePath() ) <= (size_t)cDirFileSpecLength )
  337. ? 0 : cDirFileSpecLength;
  338. m_pcParams->DumpPrint( L"'%s' - Not traversing, already traversed through '%s' mountpoint",
  339. cwsTraversePath.c_str() + cDirFileSpecLength, pcNewFsdVolState->GetVolumePath() + cVolStateSpecLength );
  340. }
  341. else if ( dwRet == ERROR_SUCCESS )
  342. {
  343. ProcessDir(
  344. pcFsdVolStateManager,
  345. pcNewFsdVolState,
  346. cwsTraversePath,
  347. cDirFileSpecLength,
  348. ::wcslen( pcNewFsdVolState->GetVolumePath() ) );
  349. }
  350. else
  351. {
  352. //
  353. // Error message already printed out
  354. //
  355. }
  356. }
  357. else
  358. {
  359. ProcessDir(
  360. pcFsdVolStateManager,
  361. pcFsdVolState,
  362. cwsTraversePath,
  363. cDirFileSpecLength,
  364. cVolMountPointOffset );
  365. }
  366. }
  367. }
  368. delete pDirListIter;
  369. }
  370. catch ( DWORD dwRet )
  371. {
  372. m_pcParams->ErrPrint( L"ProcessDir: Error trying to process '%s' directory, dwRet: %d", cwsDirPath.c_str(), dwRet );
  373. }
  374. catch ( ... )
  375. {
  376. m_pcParams->ErrPrint( L"ProcessDir() Caught an unexpected exception processing dir: '%s', Last dwRet: %d",
  377. cwsDirPath.c_str(), ::GetLastError() );
  378. }
  379. return 0;
  380. }
  381. //
  382. // printf style format strings which format each line
  383. //
  384. #define DIR_STR L"<DIR>"
  385. #define JUNCTION_STR L"<JUNCTION>"
  386. #define FMT_DIR_STR_HEX L" %s %s %-16s %04x %-32s %-12s %4d %4d %04x -------- %4d %8I64x %s %4d %s %6hx %s %s %8hx %s %8hx %s %4d %36s %s %%s/%s"
  387. #define FMT_DIR_STR L" %s %s %-16s %04x %-32s %-12s %4d %4d %04x -------- %4d %8I64d %s %4d %s %6hu %s %s %8hd %s %8hd %s %4d %36s %s %s/%s"
  388. #define FMT_FILE_STR_HEX L" %s %s %16I64x %04x %-32s %-12s %4d %4d %04x %s %4d %8I64x %s %4d %s %6hx %s %s %8hx %s %8hx %s %4d %36s %s %s/%s"
  389. #define FMT_FILE_STR L" %s %s %16I64d %04x %-32s %-12s %4d %4d %04x %s %4d %8I64d %s %4d %s %6hu %s %s %8hd %s %8hd %s %4d %36s %s %s/%s"
  390. #define BLANKTIMESTAMPWITHOUTMS L" "
  391. #define BLANKTIMESTAMPWITHMS L" "
  392. #define FMT_CSV_DIR_STR L"\"'%s%s\\'\",%s,%s,%s,%s,0x%04x,%d,%d,0x%04x,,%d,%I64d,%s,%d,%s,%hu,%s,%s,%hd,%s,%hd,%s,%d,%s,%s,%s,%s,%s"
  393. #define FMT_CSV_FILE_STR L"\"'%s%s'\",%s,%s,%s,%I64d,0x%04x,%d,%d,0x%04x,%s,%d,%I64d,%s,%d,%s,%hu,%s,%s,%hd,%s,%hd,%s,%d,%s,%s,%s,%s,%s"
  394. /*++
  395. Routine Description:
  396. Prints out all the information about one directory entry.
  397. Arguments:
  398. cwsDirPath - The path leading up to the entry
  399. psDirEntry - The directory entry information
  400. Return Value:
  401. NONE
  402. --*/
  403. VOID
  404. CDumpEngine::PrintEntry(
  405. IN CFsdVolumeState *pcFsdVolState,
  406. IN const CBsString& cwsDirPath,
  407. IN INT cDirFileSpecLength,
  408. IN SDirectoryEntry *psDirEntry,
  409. IN BOOL bSingleEntryOutput
  410. )
  411. {
  412. WIN32_FILE_ATTRIBUTE_DATA *pFD = &psDirEntry->m_sFindData;
  413. LPWSTR pwszFmtStr;
  414. WCHAR wszCreationTime[32];
  415. WCHAR wszLastWriteTime[32];
  416. //
  417. // Get the additional information about the file/dir
  418. //
  419. SFileExtendedInfo sExtendedInfo;
  420. ::GetExtendedFileInfo( m_pcParams, pcFsdVolState, cwsDirPath, bSingleEntryOutput, psDirEntry, &sExtendedInfo );
  421. //
  422. // Convert the timestamps into formatted strings
  423. //
  424. if ( pFD->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
  425. && m_pcParams->m_bDontShowDirectoryTimestamps )
  426. {
  427. if ( m_pcParams->m_bDumpCommaDelimited )
  428. {
  429. wszCreationTime[0] = L'\0';
  430. wszLastWriteTime[0] = L'\0';
  431. }
  432. else if ( m_pcParams->m_bAddMillisecsToTimestamps )
  433. {
  434. ::wcscpy( wszCreationTime, BLANKTIMESTAMPWITHMS );
  435. ::wcscpy( wszLastWriteTime, BLANKTIMESTAMPWITHMS );
  436. }
  437. else
  438. {
  439. ::wcscpy( wszCreationTime, BLANKTIMESTAMPWITHOUTMS );
  440. ::wcscpy( wszLastWriteTime, BLANKTIMESTAMPWITHOUTMS );
  441. }
  442. }
  443. else
  444. {
  445. TimeString( &psDirEntry->m_sFindData.ftCreationTime,
  446. m_pcParams->m_bAddMillisecsToTimestamps,
  447. wszCreationTime );
  448. TimeString( &psDirEntry->m_sFindData.ftLastWriteTime,
  449. m_pcParams->m_bAddMillisecsToTimestamps,
  450. wszLastWriteTime );
  451. }
  452. //
  453. // Mask out the requested file attribute bits
  454. //
  455. pFD->dwFileAttributes &= ~m_pcParams->m_dwFileAttributesMask;
  456. m_ullNumBytesChecksummed += sExtendedInfo.ullTotalBytesChecksummed;
  457. m_ullNumBytesTotalNamedDataStream += sExtendedInfo.ullTotalBytesNamedDataStream;
  458. if ( sExtendedInfo.lNumberOfLinks > 1 )
  459. ++m_ullNumHardLinks;
  460. if ( sExtendedInfo.lNumDACEs != -1 )
  461. m_ullNumDiscreteDACEs += sExtendedInfo.lNumDACEs;
  462. if ( sExtendedInfo.lNumSACEs != -1 )
  463. m_ullNumDiscreteSACEs += sExtendedInfo.lNumSACEs;
  464. if ( !sExtendedInfo.cwsObjectId.IsEmpty() )
  465. ++m_ullNumFilesWithObjectIds;
  466. WCHAR wszReparsePointTag[32];
  467. if ( sExtendedInfo.ulReparsePointTag == 0 )
  468. {
  469. if ( m_pcParams->m_bDumpCommaDelimited )
  470. wszReparsePointTag[0] = L'\0';
  471. else
  472. ::memcpy( wszReparsePointTag, L"--------", sizeof( WCHAR ) * 9 );
  473. }
  474. else
  475. {
  476. wsprintf( wszReparsePointTag, m_pcParams->m_pwszULongHexFmt, sExtendedInfo.ulReparsePointTag );
  477. }
  478. if ( pFD->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  479. {
  480. LPWSTR pwszDirType;
  481. if ( pFD->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  482. pwszDirType = JUNCTION_STR;
  483. else
  484. pwszDirType = DIR_STR;
  485. if ( m_pcParams->m_bDumpCommaDelimited )
  486. {
  487. //
  488. // If single file output mode, then processing the root directory
  489. //
  490. if ( bSingleEntryOutput )
  491. psDirEntry->m_cwsFileName = L".";
  492. CBsString cwsFixedShortName;
  493. if ( !psDirEntry->GetShortName().IsEmpty() )
  494. {
  495. cwsFixedShortName = L"\"'" + psDirEntry->GetShortName() + L"'\"";
  496. }
  497. m_pcParams->DumpPrintAlways( FMT_CSV_DIR_STR,
  498. cwsDirPath.c_str() + cDirFileSpecLength,
  499. LPCWSTR( psDirEntry->GetFileName() ),
  500. LPCWSTR( cwsFixedShortName ),
  501. wszCreationTime,
  502. wszLastWriteTime,
  503. pwszDirType,
  504. pFD->dwFileAttributes,
  505. sExtendedInfo.lNumDACEs,
  506. sExtendedInfo.lNumSACEs,
  507. sExtendedInfo.wSecurityDescriptorControl,
  508. sExtendedInfo.lNumNamedDataStreams,
  509. sExtendedInfo.ullTotalBytesNamedDataStream,
  510. sExtendedInfo.cwsNamedDataStreamChecksum.c_str(),
  511. sExtendedInfo.lNumPropertyStreams,
  512. wszReparsePointTag,
  513. sExtendedInfo.wReparsePointDataSize,
  514. sExtendedInfo.cwsReparsePointDataChecksum.c_str(),
  515. sExtendedInfo.cwsEncryptedRawDataChecksum.c_str(),
  516. sExtendedInfo.wDACLSize,
  517. sExtendedInfo.cwsDACLChecksum.c_str(),
  518. sExtendedInfo.wSACLSize,
  519. sExtendedInfo.cwsSACLChecksum.c_str(),
  520. sExtendedInfo.lNumberOfLinks,
  521. sExtendedInfo.cwsObjectId.c_str(),
  522. sExtendedInfo.cwsObjectIdExtendedDataChecksum.c_str(),
  523. pcFsdVolState->GetFileSystemName(),
  524. sExtendedInfo.cwsOwnerSid.c_str(),
  525. sExtendedInfo.cwsGroupSid.c_str() );
  526. }
  527. else
  528. {
  529. //
  530. // If single file output mode, then processing the root directory
  531. //
  532. if ( bSingleEntryOutput )
  533. psDirEntry->m_cwsFileName = L".";
  534. //
  535. // Print with quotes around the file name
  536. //
  537. WCHAR wszNameWithQuotes[ MAX_PATH + 2 ];
  538. wszNameWithQuotes[ 0 ] = L'\'';
  539. ::wcscpy( wszNameWithQuotes + 1, psDirEntry->GetFileName() );
  540. ::wcscat( wszNameWithQuotes, L"\\\'" );
  541. if ( m_pcParams->m_bHex )
  542. pwszFmtStr = FMT_DIR_STR_HEX;
  543. else
  544. pwszFmtStr = FMT_DIR_STR;
  545. m_pcParams->DumpPrintAlways( pwszFmtStr,
  546. wszCreationTime,
  547. wszLastWriteTime,
  548. pwszDirType,
  549. pFD->dwFileAttributes,
  550. wszNameWithQuotes,
  551. LPCWSTR( psDirEntry->GetShortName() ),
  552. sExtendedInfo.lNumDACEs,
  553. sExtendedInfo.lNumSACEs,
  554. sExtendedInfo.wSecurityDescriptorControl,
  555. sExtendedInfo.lNumNamedDataStreams,
  556. sExtendedInfo.ullTotalBytesNamedDataStream,
  557. sExtendedInfo.cwsNamedDataStreamChecksum.c_str(),
  558. sExtendedInfo.lNumPropertyStreams,
  559. wszReparsePointTag,
  560. sExtendedInfo.wReparsePointDataSize,
  561. sExtendedInfo.cwsReparsePointDataChecksum.c_str(),
  562. sExtendedInfo.cwsEncryptedRawDataChecksum.c_str(),
  563. sExtendedInfo.wDACLSize,
  564. sExtendedInfo.cwsDACLChecksum.c_str(),
  565. sExtendedInfo.wSACLSize,
  566. sExtendedInfo.cwsSACLChecksum.c_str(),
  567. sExtendedInfo.lNumberOfLinks,
  568. sExtendedInfo.cwsObjectId.c_str(),
  569. sExtendedInfo.cwsObjectIdExtendedDataChecksum.c_str(),
  570. sExtendedInfo.cwsOwnerSid.c_str(),
  571. sExtendedInfo.cwsGroupSid.c_str() );
  572. }
  573. }
  574. else
  575. {
  576. ULONGLONG ullFileSize = ( ( (ULONGLONG)pFD->nFileSizeHigh ) << 32 ) + pFD->nFileSizeLow;
  577. if ( m_pcParams->m_bDumpCommaDelimited )
  578. {
  579. CBsString cwsFixedShortName;
  580. if ( !psDirEntry->GetShortName().IsEmpty() )
  581. {
  582. cwsFixedShortName = L"\"'" + psDirEntry->GetShortName() + L"'\"";
  583. }
  584. m_pcParams->DumpPrintAlways( FMT_CSV_FILE_STR,
  585. cwsDirPath.c_str() + cDirFileSpecLength,
  586. LPCWSTR( psDirEntry->GetFileName() ),
  587. LPCWSTR( cwsFixedShortName ),
  588. wszCreationTime,
  589. wszLastWriteTime,
  590. ullFileSize,
  591. pFD->dwFileAttributes,
  592. sExtendedInfo.lNumDACEs,
  593. sExtendedInfo.lNumSACEs,
  594. sExtendedInfo.wSecurityDescriptorControl,
  595. sExtendedInfo.cwsUnnamedStreamChecksum.c_str(),
  596. sExtendedInfo.lNumNamedDataStreams,
  597. sExtendedInfo.ullTotalBytesNamedDataStream,
  598. sExtendedInfo.cwsNamedDataStreamChecksum.c_str(),
  599. sExtendedInfo.lNumPropertyStreams,
  600. wszReparsePointTag,
  601. sExtendedInfo.wReparsePointDataSize,
  602. sExtendedInfo.cwsReparsePointDataChecksum.c_str(),
  603. sExtendedInfo.cwsEncryptedRawDataChecksum.c_str(),
  604. sExtendedInfo.wDACLSize,
  605. sExtendedInfo.cwsDACLChecksum.c_str(),
  606. sExtendedInfo.wSACLSize,
  607. sExtendedInfo.cwsSACLChecksum.c_str(),
  608. sExtendedInfo.lNumberOfLinks,
  609. sExtendedInfo.cwsObjectId.c_str(),
  610. sExtendedInfo.cwsObjectIdExtendedDataChecksum.c_str(),
  611. pcFsdVolState->GetFileSystemName(),
  612. sExtendedInfo.cwsOwnerSid.c_str(),
  613. sExtendedInfo.cwsGroupSid.c_str() );
  614. }
  615. else
  616. {
  617. //
  618. // Print with quotes around the file name
  619. //
  620. WCHAR wszNameWithQuotes[ MAX_PATH + 2 ];
  621. wszNameWithQuotes[ 0 ] = L'\'';
  622. ::wcscpy( wszNameWithQuotes + 1, psDirEntry->GetFileName() );
  623. ::wcscat( wszNameWithQuotes, L"\'" );
  624. if ( m_pcParams->m_bHex )
  625. pwszFmtStr = FMT_FILE_STR_HEX;
  626. else
  627. pwszFmtStr = FMT_FILE_STR;
  628. m_pcParams->DumpPrintAlways( pwszFmtStr,
  629. wszCreationTime,
  630. wszLastWriteTime,
  631. ullFileSize,
  632. pFD->dwFileAttributes,
  633. wszNameWithQuotes,
  634. LPCWSTR( psDirEntry->GetShortName() ),
  635. sExtendedInfo.lNumDACEs,
  636. sExtendedInfo.lNumSACEs,
  637. sExtendedInfo.wSecurityDescriptorControl,
  638. sExtendedInfo.cwsUnnamedStreamChecksum.c_str(),
  639. sExtendedInfo.lNumNamedDataStreams,
  640. sExtendedInfo.ullTotalBytesNamedDataStream,
  641. sExtendedInfo.cwsNamedDataStreamChecksum.c_str(),
  642. sExtendedInfo.lNumPropertyStreams,
  643. wszReparsePointTag,
  644. sExtendedInfo.wReparsePointDataSize,
  645. sExtendedInfo.cwsReparsePointDataChecksum.c_str(),
  646. sExtendedInfo.cwsEncryptedRawDataChecksum.c_str(),
  647. sExtendedInfo.wDACLSize,
  648. sExtendedInfo.cwsDACLChecksum.c_str(),
  649. sExtendedInfo.wSACLSize,
  650. sExtendedInfo.cwsSACLChecksum.c_str(),
  651. sExtendedInfo.lNumberOfLinks,
  652. sExtendedInfo.cwsObjectId.c_str(),
  653. sExtendedInfo.cwsObjectIdExtendedDataChecksum.c_str(),
  654. sExtendedInfo.cwsOwnerSid.c_str(),
  655. sExtendedInfo.cwsGroupSid.c_str() );
  656. }
  657. }
  658. }
  659. /*++
  660. Routine Description:
  661. Formats dates into a common string format.
  662. Arguments:
  663. Return Value:
  664. <Enter return values here>
  665. --*/
  666. static VOID
  667. TimeString(
  668. IN FILETIME *pFileTime,
  669. IN BOOL bAddMillisecsToTimestamps,
  670. OUT LPWSTR pwszTimeStr
  671. )
  672. {
  673. SYSTEMTIME szTime;
  674. ::FileTimeToSystemTime( pFileTime, &szTime );
  675. if ( bAddMillisecsToTimestamps )
  676. {
  677. wsprintf( pwszTimeStr,
  678. L"%02d/%02d/%02d %02d:%02d:%02d.%03d",
  679. szTime.wMonth,
  680. szTime.wDay,
  681. szTime.wYear,
  682. szTime.wHour,
  683. szTime.wMinute,
  684. szTime.wSecond,
  685. szTime.wMilliseconds );
  686. }
  687. else
  688. {
  689. wsprintf( pwszTimeStr,
  690. L"%02d/%02d/%02d %02d:%02d:%02d",
  691. szTime.wMonth,
  692. szTime.wDay,
  693. szTime.wYear,
  694. szTime.wHour,
  695. szTime.wMinute,
  696. szTime.wSecond );
  697. }
  698. }
  699. LPCSTR
  700. CDumpEngine::GetHeaderInformation()
  701. {
  702. LPSTR pszHeaderInfo =
  703. "Creation date - Creation date of the file/dir\n"
  704. "Last mod. date - Last modification date of the file/dir\n"
  705. "FileSize - Size of the unnamed data stream if a file\n"
  706. "Attr - File attributes with Archive and Normal bits masked by\n"
  707. " default (hex)\n"
  708. "FileName - Name of the file in single quotes\n"
  709. "ShortName - The classic 8.3 file name. If <->, FileName is in\n"
  710. " classic format\n"
  711. "DACE - Number of discretionary ACL entries\n"
  712. "SACE - Number of system ACL entries\n"
  713. "SDCtl - Security Descripter control word (hex)\n"
  714. "UNamChkS - Data checksum of the unnamed data stream (hex)\n"
  715. "DStr - Number of named data streams\n"
  716. "DStrSize - Size of all of the named data streams\n"
  717. "DStrChkS - Data checksum of all named data streams including their\n"
  718. " names (hex)\n"
  719. "Prop - Number of property data streams\n"
  720. "RPTag - Reparse point tag value (hex)\n"
  721. "RPSize - Size of reparse point data\n"
  722. "RPChkS - Checksum of the reparse point data (hex)\n"
  723. "EncrChkS - Raw encrypted data checksum (hex)\n"
  724. "DACLSize - Size of the complete discretionary ACL\n"
  725. "DACLChkS - Checksum of the complete discretionary ACL (hex)\n"
  726. "SACLSize - Size of the complete system ACL\n"
  727. "SACLChkS - Checksum of the complete system ACL (hex)\n"
  728. "NLnk - Number of hard links\n"
  729. "ObjectId - Object Id GUID on the file if it has one\n"
  730. "OIDChkS - Object Id extended data checksum\n"
  731. "FS - Type of file system (in CSV format only)\n"
  732. "OwnerSid/GroupSid - The owner and group sid values\n";
  733. return pszHeaderInfo;
  734. }