#include "std.hxx" class CException { protected: CException( PCTSTR pcszDescription, PCTSTR pcszFile, const DWORD dwLine) : m_pcszDescription(pcszDescription), m_pcszFile(pcszFile), m_dwLine(dwLine) {} public: PCTSTR GetDescription() { return m_pcszDescription; } PCTSTR GetFile() { return m_pcszFile; } DWORD GetLine() { return m_dwLine; } virtual void Throw() = 0; protected: PCTSTR m_pcszDescription; PCTSTR m_pcszFile; DWORD m_dwLine; }; class CMemoryException : public CException { public: CMemoryException( DWORD dwSize, PCTSTR pcszDescription, PCTSTR pcszFile, DWORD dwLine) : CException(pcszDescription, pcszFile, dwLine), m_dwSize(dwSize) {} public: DWORD GetSize() { return m_dwSize; } void Throw() { throw *this; } protected: DWORD m_dwSize; }; class CApiException : public CException { public: CApiException( DWORD dwGleCode, PCTSTR pcszDescription, PCTSTR pcszFile, DWORD dwLine) : CException(pcszDescription, pcszFile, dwLine), m_dwGleCode(dwGleCode) {} public: DWORD GetError() { return m_dwGleCode; } void Throw() { throw *this; } protected: DWORD m_dwGleCode; }; #define THROW_API_EXCEPTION(description) \ throw CApiException( \ GetLastError(), \ description, \ _T(__FILE__), \ __LINE__) void CountReparsePoints(PCTSTR pcszInput); void xGetRootDirectory(PCTSTR pcszInput, PTSTR* pszRootDir); HANDLE xOpenReparseIndex(PCTSTR pcszVolume); BOOL xGetNextReparseRecord( HANDLE hIndex, PFILE_REPARSE_POINT_INFORMATION ReparseInfo); HANDLE xOpenVolume(PCTSTR pcszVolume); void DisplayFileName( PTSTR pszVolume, HANDLE hVolume, LONGLONG llFileId); extern "C" void __cdecl _tmain(int argc, PTSTR argv[], PTSTR envv[]) { if (argc==2) { CountReparsePoints( argv[1]); } else { _tprintf( _T("sisenum: Enumerates and lists all SIS files on a given volume.\n") _T("Usage: sisenum ")); } } void CountReparsePoints(PCTSTR pcszInput) { PTSTR pszVolume = NULL; DWORD dwCount = 0; HANDLE hIndex = INVALID_HANDLE_VALUE; HANDLE hVolume = INVALID_HANDLE_VALUE; FILE_REPARSE_POINT_INFORMATION ReparseInfo; try { xGetRootDirectory( pcszInput, &pszVolume); hIndex = xOpenReparseIndex( pszVolume); hVolume = xOpenVolume( pszVolume); BOOL fDone = xGetNextReparseRecord( hIndex, &ReparseInfo); while (!fDone) { if (IO_REPARSE_TAG_SIS==ReparseInfo.Tag) { dwCount++; DisplayFileName( pszVolume, hVolume, ReparseInfo.FileReference); } fDone = xGetNextReparseRecord( hIndex, &ReparseInfo); } CloseHandle(hIndex); hIndex = INVALID_HANDLE_VALUE; _tprintf( _T("This volume (%s) contains %u SIS files.\n"), pszVolume, dwCount); } catch (CApiException& e) { _tprintf( _T("Failure: %s\nFile: %s\nLine: %u\nError: %u"), e.GetDescription(), e.GetFile(), e.GetLine(), e.GetError()); } catch (CMemoryException& e) { _tprintf( _T("Out of memory.\n")); } if (hIndex!=INVALID_HANDLE_VALUE) { CloseHandle( hIndex); } if (hVolume!=INVALID_HANDLE_VALUE) { CloseHandle( hVolume); } delete []pszVolume; } void xGetRootDirectory(PCTSTR pcszInput, PTSTR* pszRootDir) { DWORD dwBufferSize = MAX_PATH; PTSTR pszTemp; *pszRootDir = NULL; BOOL bResult; DWORD dwGleCode; do { pszTemp = new TCHAR[dwBufferSize]; bResult = GetVolumePathName( pcszInput, pszTemp, dwBufferSize); if (!bResult) { delete []pszTemp; dwGleCode = GetLastError(); if (ERROR_BUFFER_OVERFLOW==dwGleCode) { dwBufferSize *= 2; } else { THROW_API_EXCEPTION(_T("GetVolumePathName failed.")); } } } while (!bResult); *pszRootDir = pszTemp; } HANDLE xOpenReparseIndex(PCTSTR pcszVolume) { HANDLE hReparseIndex; PTSTR pszReparseIndex = NULL; pszReparseIndex = new TCHAR[_tcslen(pcszVolume)+64]; _tcscpy( pszReparseIndex, pcszVolume); PathAddBackslash(pszReparseIndex); _tcscat( pszReparseIndex, _T("$Extend\\$Reparse:$R:$INDEX_ALLOCATION")); hReparseIndex = CreateFile( pszReparseIndex, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION, NULL); delete []pszReparseIndex; if (INVALID_HANDLE_VALUE == hReparseIndex) { THROW_API_EXCEPTION(_T("Unable to open reparse index.")); } return hReparseIndex; } HANDLE xOpenVolume(PCTSTR pcszVolume) { HANDLE hVolume = INVALID_HANDLE_VALUE; PTSTR pszVolumeName = NULL; pszVolumeName = new TCHAR[MAX_PATH]; BOOL bResult = GetVolumeNameForVolumeMountPoint( pcszVolume, pszVolumeName, MAX_PATH); if (bResult) { hVolume = CreateFile( pszVolumeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION, NULL); } delete []pszVolumeName; if (INVALID_HANDLE_VALUE == hVolume) { THROW_API_EXCEPTION(_T("Unable to open volume.")); } return hVolume; } BOOL xGetNextReparseRecord( HANDLE hIndex, PFILE_REPARSE_POINT_INFORMATION ReparseInfo) { BOOL bResult = FALSE; IO_STATUS_BLOCK ioStatus; NTSTATUS status = NtQueryDirectoryFile(hIndex, NULL, NULL, NULL, &ioStatus, ReparseInfo, sizeof(FILE_REPARSE_POINT_INFORMATION), FileReparsePointInformation, TRUE, NULL, FALSE); if (!NT_SUCCESS(status)) { SetLastError(RtlNtStatusToDosError(status)); if (GetLastError() != ERROR_NO_MORE_FILES) { THROW_API_EXCEPTION(_T("Unable to open reparse index.")); } bResult = TRUE; } return bResult; } void DisplayFileName( PTSTR pszVolume, HANDLE hVolume, LONGLONG llFileId) { UNICODE_STRING usIdString; NTSTATUS status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE hFile = INVALID_HANDLE_VALUE; IO_STATUS_BLOCK IoStatusBlock; struct { FILE_NAME_INFORMATION FileInformation; WCHAR FileName[MAX_PATH]; } NameFile; ZeroMemory( &NameFile, sizeof(NameFile)); usIdString.Length = sizeof(LONGLONG); usIdString.MaximumLength = sizeof(LONGLONG); usIdString.Buffer = (PWCHAR)&llFileId; InitializeObjectAttributes( &ObjectAttributes, &usIdString, OBJ_CASE_INSENSITIVE, hVolume, NULL); // security descriptor status = NtCreateFile( &hFile, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, // allocation size FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_OPEN_BY_FILE_ID, NULL, // EA buffer 0); // EA length if (NT_SUCCESS(status)) { status = NtQueryInformationFile( hFile, &IoStatusBlock, &(NameFile.FileInformation), sizeof(NameFile), FileNameInformation); if (NT_SUCCESS(status)) { wprintf(L"%s\n",NameFile.FileInformation.FileName); } else { _tprintf(_T("Unable to query file name.\n")); } } else { _tprintf(_T("Unable to open file by ID.\n")); } if (hFile!=INVALID_HANDLE_VALUE) { CloseHandle(hFile); } }