home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2006 May / PCpro_2006_05.ISO / files / praxis / Streams.exe / Streams.exe / streams.c < prev    next >
Encoding:
C/C++ Source or Header  |  2005-08-15  |  13.3 KB  |  517 lines

  1. #define UNICODE 1
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include "streams.h"
  5.  
  6.  
  7. //
  8. // Native functions we use
  9. //
  10. NTSTATUS (__stdcall *NtQueryInformationFile)( 
  11.     IN HANDLE FileHandle,
  12.     OUT PIO_STATUS_BLOCK IoStatusBlock,
  13.     OUT PVOID FileInformation,
  14.     IN ULONG Length,
  15.     IN FILE_INFORMATION_CLASS FileInformationClass
  16.     );
  17.  
  18. ULONG (__stdcall *RtlNtStatusToDosError) (
  19.         IN NTSTATUS Status
  20.         );
  21.  
  22. //
  23. // Globals
  24. //
  25. ULONG FilesWithStreams = 0;
  26. ULONG FilesProcessed = 0;
  27. ULONG DotsPrinted = 0;
  28. BOOLEAN PrintDirectoryOpenErrors = FALSE;
  29.  
  30. //----------------------------------------------------------------------
  31. //
  32. // PrintNtError
  33. //
  34. // Formats an error message for the last native error.
  35. //
  36. //----------------------------------------------------------------------
  37. void PrintNtError( NTSTATUS status )
  38. {
  39.     WCHAR *errMsg;
  40.  
  41.     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  42.             NULL, RtlNtStatusToDosError( status ), 
  43.             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
  44.             (LPTSTR) &errMsg, 0, NULL );
  45.     wprintf(L"%s\n", errMsg );
  46.     LocalFree( errMsg );
  47. }
  48.  
  49. //--------------------------------------------------------------------
  50. //
  51. // PrintWin32Error
  52. // 
  53. // Translates a Win32 error into a text equivalent
  54. //
  55. //--------------------------------------------------------------------
  56. void PrintWin32Error( DWORD ErrorCode )
  57. {
  58.     LPVOID lpMsgBuf;
  59.  
  60.     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  61.                     NULL, ErrorCode, 
  62.                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  63.                     (LPTSTR) &lpMsgBuf, 0, NULL );
  64.     wprintf(L"%s\n", lpMsgBuf );
  65.     LocalFree( lpMsgBuf );
  66. }
  67.  
  68. //----------------------------------------------------------------------
  69. //
  70. // EnableTokenPrivilege
  71. //
  72. // Enables the load driver privilege
  73. //
  74. //----------------------------------------------------------------------
  75. BOOL EnableTokenPrivilege( PTCHAR PrivilegeName )
  76. {
  77.     TOKEN_PRIVILEGES tp;
  78.     LUID luid;
  79.     HANDLE    hToken;
  80.     TOKEN_PRIVILEGES tpPrevious;
  81.     DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
  82.  
  83.     //
  84.     // Get debug privilege
  85.     //
  86.     if(!OpenProcessToken( GetCurrentProcess(),
  87.                 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  88.                 &hToken )) {
  89.     
  90.         return FALSE;
  91.     }
  92.     
  93.     if(!LookupPrivilegeValue( NULL, PrivilegeName, &luid )) return FALSE;
  94.  
  95.     //
  96.     // first pass.  get current privilege setting
  97.     //
  98.     tp.PrivilegeCount           = 1;
  99.     tp.Privileges[0].Luid       = luid;
  100.     tp.Privileges[0].Attributes = 0;
  101.  
  102.     AdjustTokenPrivileges(
  103.             hToken,
  104.             FALSE,
  105.             &tp,
  106.             sizeof(TOKEN_PRIVILEGES),
  107.             &tpPrevious,
  108.             &cbPrevious
  109.             );
  110.  
  111.     if (GetLastError() != ERROR_SUCCESS) return FALSE;
  112.  
  113.     //
  114.     // second pass.  set privilege based on previous setting
  115.     //
  116.     tpPrevious.PrivilegeCount       = 1;
  117.     tpPrevious.Privileges[0].Luid   = luid;
  118.     tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  119.     AdjustTokenPrivileges(
  120.             hToken,
  121.             FALSE,
  122.             &tpPrevious,
  123.             cbPrevious,
  124.             NULL,
  125.             NULL
  126.             );
  127.  
  128.     return GetLastError() == ERROR_SUCCESS;
  129. }
  130.  
  131.  
  132. //--------------------------------------------------------------------
  133. //
  134. // ProcessFile
  135. //
  136. // Queries a file to obtain stream information.
  137. //
  138. //--------------------------------------------------------------------
  139. VOID ProcessFile( WCHAR *FileName, BOOLEAN IsDirectory, BOOLEAN Delete )
  140. {
  141.     PFILE_STREAM_INFORMATION  streamInfo, streamInfoPtr;
  142.     ULONG    streamInfoSize = 0;
  143.     BOOLEAN  printedFile = FALSE;
  144.     NTSTATUS status;
  145.     HANDLE   fileHandle;
  146.     WCHAR    streamName[MAX_PATH];
  147.     WCHAR    fullStreamName[MAX_PATH];
  148.     IO_STATUS_BLOCK ioStatus;
  149.  
  150.     //
  151.     // Open the file
  152.     //
  153.     fileHandle = CreateFile( FileName, GENERIC_READ,
  154.                     FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, 
  155.                     OPEN_EXISTING, 
  156.                     FILE_FLAG_BACKUP_SEMANTICS, 0 );
  157.     if( fileHandle == INVALID_HANDLE_VALUE ) {
  158.  
  159.         if( !IsDirectory || PrintDirectoryOpenErrors ) {
  160.  
  161.             wprintf(L"\rError opening %s:\n", FileName );
  162.             PrintWin32Error( GetLastError() );
  163.         }
  164.         return;
  165.     }
  166.  
  167.     if( !(++FilesProcessed % 500)) {
  168.  
  169.         if( DotsPrinted == 3 ) {
  170.  
  171.             wprintf(L"\r     \r");
  172.             DotsPrinted = 0;
  173.  
  174.         } else {
  175.             DotsPrinted++;
  176.             wprintf(L".");
  177.         }
  178.         fflush( stdout );
  179.     }
  180.     
  181.     streamInfoSize = 16384;
  182.     streamInfo = malloc( streamInfoSize );
  183.     status = STATUS_BUFFER_OVERFLOW;
  184.     while( status == STATUS_BUFFER_OVERFLOW ) {
  185.  
  186.         status = NtQueryInformationFile( fileHandle, &ioStatus,
  187.                                          streamInfo, streamInfoSize,
  188.                                          FileStreamInformation );
  189.         if( status == STATUS_BUFFER_OVERFLOW ) {
  190.  
  191.             free( streamInfo );
  192.             streamInfoSize += 16384;
  193.             streamInfo = malloc( streamInfoSize );
  194.  
  195.         } else {
  196.  
  197.             break;
  198.         }
  199.     }
  200.  
  201.     //
  202.     // If success, dump the contents
  203.     //
  204.     if( NT_SUCCESS( status ) && ioStatus.Information ) {
  205.  
  206.         streamInfoPtr = streamInfo;
  207.         while( 1 ) {
  208.             
  209.             memcpy( streamName, 
  210.                      streamInfoPtr->Name, 
  211.                      streamInfoPtr->NameLength );
  212.             streamName[ streamInfoPtr->NameLength/2 ] = 0;
  213.  
  214.             //
  215.             // Skip the standard Data stream
  216.             //
  217.             if( wcsicmp( streamName, L"::$DATA" )) {
  218.  
  219.                 if( !printedFile ) {
  220.                     wprintf(L"\r%s:\n", FileName );
  221.                     printedFile = TRUE;
  222.                 }
  223.  
  224.                 if( Delete ) {
  225.  
  226.                     swprintf( fullStreamName, L"%s%s", FileName, streamName );
  227.                     if( !DeleteFile( fullStreamName )) {
  228.  
  229.                         wprintf(L"   Error deleting %s:\n", streamName );
  230.                         PrintWin32Error( GetLastError());
  231.                     } else {
  232.  
  233.                         wprintf(L"   Deleted %s\n", streamName );
  234.                     }
  235.                 } else {
  236.  
  237.                     wprintf(L"   %20s\t%I64d\n", streamName, streamInfoPtr->Size.QuadPart );
  238.                 }
  239.             }
  240.  
  241.             if( !streamInfoPtr->NextEntry ) break;
  242.  
  243.             FilesWithStreams++;
  244.             streamInfoPtr = (PFILE_STREAM_INFORMATION) ((char *) streamInfoPtr + 
  245.                                                      streamInfoPtr->NextEntry );
  246.         }
  247.  
  248.     } else if( !NT_SUCCESS( status )) {
  249.  
  250.         wprintf(L"\rError on %s: ", FileName );
  251.         PrintNtError( status );
  252.     }
  253.     free( streamInfo );
  254.     CloseHandle( fileHandle );
  255. }
  256.  
  257.  
  258.  
  259. //--------------------------------------------------------------------
  260. //
  261. // ProcessDirectory
  262. // 
  263. // Recursive routine that passes files to the stream analyzing 
  264. // function.
  265. //
  266. //--------------------------------------------------------------------
  267. void ProcessDirectory( WCHAR *PathName, WCHAR *SearchPattern, 
  268.                        BOOLEAN Recurse, BOOLEAN Delete )
  269. {
  270.     WCHAR            subName[MAX_PATH], fileSearchName[MAX_PATH], searchName[MAX_PATH];
  271.     HANDLE            dirHandle, patternHandle;
  272.     static BOOLEAN    firstCall = TRUE;
  273.     WIN32_FIND_DATA foundFile;
  274.  
  275.     //
  276.     // Scan the files and/or directories if this is a directory
  277.     //
  278.     if( firstCall ) {
  279.  
  280.         if( PathName[ wcslen( PathName ) - 1] == L'\\' ) {
  281.  
  282.             PathName[ wcslen( PathName ) - 1] = 0;
  283.         }
  284.  
  285.         if( wcsrchr( PathName, '*' ) ) {
  286.     
  287.             if( wcsrchr( PathName, '\\' ) ) {
  288.  
  289.                 swprintf( SearchPattern, wcsrchr( PathName, '\\' )+1 );
  290.                 wcscpy( searchName, PathName );
  291.                 wcscpy( wcsrchr( searchName, '\\')+1, L"*.*" );
  292.  
  293.             } else {
  294.                 
  295.                 swprintf( SearchPattern, PathName );
  296.                 wcscpy( searchName, PathName );
  297.             }
  298.             swprintf( fileSearchName, L"%s", PathName );
  299.  
  300.         } else {
  301.  
  302.             swprintf( SearchPattern, L"*.*" );
  303.             if( Recurse ) {
  304.  
  305.                 swprintf( searchName, L"%s\\*.*", PathName );
  306.                 swprintf( fileSearchName, L"%s\\*.*", PathName );
  307.             } else {
  308.  
  309.                 swprintf( searchName, L"%s", PathName );
  310.                 swprintf( fileSearchName, L"%s", PathName );
  311.             }
  312.         }
  313.  
  314.     } else {
  315.  
  316.         swprintf( searchName, L"%s\\*.*", PathName );
  317.         swprintf( fileSearchName, L"%s\\%s", PathName, SearchPattern );
  318.     }
  319.  
  320.     //
  321.     // Process all the files, according to the search pattern
  322.     //
  323.     if( (patternHandle = FindFirstFile( fileSearchName, &foundFile )) != 
  324.         INVALID_HANDLE_VALUE  ) {
  325.  
  326.         do {
  327.  
  328.             if( firstCall || (wcscmp( foundFile.cFileName, L"." ) &&
  329.                 wcscmp( foundFile.cFileName, L".." ))) {
  330.  
  331.                 wcscpy( subName, searchName );
  332.                 if( wcsrchr( subName, '\\' ) ) 
  333.                     wcscpy( wcsrchr( subName, '\\')+1, foundFile.cFileName );
  334.                 else
  335.                     wcscpy( subName, foundFile.cFileName );
  336.  
  337.                 //
  338.                 // Do this file/directory
  339.                 //
  340.                 ProcessFile( subName, 
  341.                              (BOOLEAN) (foundFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY), 
  342.                              Delete );
  343.             }
  344.         } while( FindNextFile( patternHandle, &foundFile ));
  345.         FindClose( patternHandle );
  346.     }
  347.  
  348.     //
  349.     // Now recurse if we're supposed to
  350.     //
  351.     if( Recurse ) {
  352.  
  353.         if( firstCall && !wcsrchr( searchName, L'\\') ) {
  354.  
  355.             if( wcsrchr( searchName, L'*' )) {
  356.  
  357.                 if( (dirHandle = FindFirstFile( L"*.*", &foundFile )) == 
  358.                     INVALID_HANDLE_VALUE  ) {
  359.  
  360.                     //
  361.                     // Nothing to process
  362.                     //
  363.                     return;
  364.                 }
  365.             } else {
  366.  
  367.                 if( (dirHandle = FindFirstFile( searchName, &foundFile )) == 
  368.                     INVALID_HANDLE_VALUE  ) {
  369.  
  370.                     //
  371.                     // Nothing to process
  372.                     //
  373.                     return;
  374.                 }
  375.             }
  376.         } else {
  377.  
  378.             if( (dirHandle = FindFirstFile( searchName, &foundFile )) == 
  379.                 INVALID_HANDLE_VALUE  ) {
  380.  
  381.                 //
  382.                 // Nothing to process
  383.                 //
  384.                 return;
  385.             }
  386.         }
  387.         firstCall = FALSE;
  388.  
  389.         do {
  390.  
  391.             if( (foundFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  392.                 wcscmp( foundFile.cFileName, L"." ) &&
  393.                 wcscmp( foundFile.cFileName, L".." )) {
  394.  
  395.                 wcscpy( subName, searchName );
  396.                 if( wcsrchr( subName, '\\' ) ) 
  397.                     wcscpy( wcsrchr( subName, '\\')+1, foundFile.cFileName );
  398.                 else
  399.                     wcscpy( subName, foundFile.cFileName );
  400.  
  401.                 //
  402.                 // Go into this directory
  403.                 //
  404.                 ProcessDirectory( subName, SearchPattern, Recurse, Delete );
  405.  
  406.             }
  407.         } while( FindNextFile( dirHandle, &foundFile ));
  408.     }
  409.  
  410.     FindClose( dirHandle );
  411. }
  412.  
  413.  
  414. int Usage( WCHAR *ProgramName ) 
  415. {
  416.     wprintf(L"usage: %s [-s] [-d] <file or directory>\n", ProgramName );
  417.     wprintf(L"-s     Recurse subdirectories\n");
  418.     wprintf(L"-d     Delete streams\n\n");
  419.     return -1;
  420. }
  421.  
  422.  
  423. int wmain( int argc, WCHAR *argv[] ) 
  424. {
  425.     BOOLEAN     recurse = FALSE, delete = FALSE;
  426.     PWCHAR      filePart;
  427.     WCHAR        volume[] = L"C:\\";
  428.     DWORD        fsFlags;
  429.     WCHAR       searchPattern[MAX_PATH];
  430.     WCHAR        searchPath[MAX_PATH];
  431.     int         i;
  432.  
  433.     //
  434.     // Print banner and perform parameter check
  435.     //
  436.     wprintf(L"\nStreams v1.53 - Enumerate alternate NTFS data streams\n" );
  437.     wprintf(L"Copyright (C) 1999-2005 Mark Russinovich\n");
  438.     wprintf(L"Sysinternals - www.sysinternals.com\n\n");
  439.  
  440.     if( argc > 1 ) {
  441.         
  442.         for( i = 1; i < argc; i++ ) {
  443.  
  444.             if( argv[i][0] != L'/' && argv[i][0] != L'-' ) {
  445.  
  446.                 if( i != argc-1 ) {
  447.  
  448.                     wprintf( argv[i] );
  449.                     return Usage( argv[0] );
  450.                 }
  451.                 continue;
  452.             }
  453.  
  454.             if( argv[i][1] == L's' || argv[i][1] == L'S' ) {
  455.  
  456.                 recurse = TRUE;
  457.  
  458.             } else if( argv[i][1] == L'd' || argv[i][1] == 'D' ) {
  459.  
  460.                 delete = TRUE;
  461.  
  462.             } else return Usage( argv[0] );
  463.         }
  464.     } else {
  465.  
  466.         return Usage( argv[0] );
  467.     }
  468.  
  469.     //
  470.     // Enable backup privilege if we can
  471.     //
  472.     if( EnableTokenPrivilege( SE_BACKUP_NAME )) {
  473.  
  474.         PrintDirectoryOpenErrors = TRUE;
  475.     }
  476.  
  477.     //
  478.     // Load the NTDLL entry point we need
  479.     //
  480.     if( !(NtQueryInformationFile = (void *) GetProcAddress( GetModuleHandle(L"ntdll.dll"),
  481.             "NtQueryInformationFile" )) ) {
  482.  
  483.         wprintf(L"\nCould not find NtQueryInformationFile entry point in NTDLL.DLL\n");
  484.         exit(1);
  485.     }
  486.     if( !(RtlNtStatusToDosError = (void *) GetProcAddress( GetModuleHandle(L"ntdll.dll"),
  487.                             "RtlNtStatusToDosError" )) ) {
  488.  
  489.         wprintf(L"\nCould not find RtlNtStatusToDosError entry point in NTDLL.DLL\n");
  490.         exit(1);
  491.     }
  492.     GetFullPathName( argv[argc-1], MAX_PATH, searchPath, &filePart );
  493.  
  494.     //
  495.     // Make sure that its a FAT volume
  496.     //
  497.     if( searchPath[1] == L':' ) {
  498.  
  499.         fsFlags = 0;
  500.         volume[0] = searchPath[0];
  501.         GetVolumeInformation( volume, NULL, 0, NULL, NULL, &fsFlags, NULL, 0 );
  502.         if( !(fsFlags & FILE_NAMED_STREAMS )) {
  503.  
  504.             wprintf(L"\nThe specified volume does not support streams.\n\n");
  505.             exit(2);
  506.         }
  507.     }
  508.     
  509.     //
  510.     // Now go and process directories
  511.     //
  512.     ProcessDirectory( searchPath, searchPattern, recurse, delete );
  513.  
  514.     if( !FilesWithStreams ) wprintf(L"No files with streams found.\n\n");
  515.     return 0;
  516. }
  517.