#include #pragma hdrstop #include #define TRKDATA_ALLOCATE #include "trkwks.hxx" DWORD g_Debug = 0; inline void WriteToSnapshot( HANDLE hFileSnapshot, const TCHAR *ptsz ) { ULONG cb, cbWritten; if( NULL != ptsz ) cb = _tcslen( ptsz ) * sizeof(TCHAR); else { cb = sizeof(TCHAR); ptsz = TEXT(""); } if( !WriteFile( hFileSnapshot, ptsz, cb, &cbWritten, NULL )) { TrkLog(( TRKDBG_ERROR, TEXT("Failed WriteFile (%lu)"), GetLastError() )); TrkRaiseLastError(); } if( cb != cbWritten ) { TrkLog(( TRKDBG_ERROR, TEXT("Not all of the data was written (%d/%d)"), cbWritten, cb )); TrkRaiseWin32Error( ERROR_WRITE_FAULT ); } } void Usage() { printf( "\n" ); printf( " Purpose: Take a snapshot of the volume ID and all object IDs for a volume\n" ); printf( " Usage: toidsnap [-g|-s] : \n" ); printf( " Where: -g indicates get (create a snapshot)\n" ); printf( " -s indicates set (from the snapshot file)\n" ); printf( " E.g.: toidsnap -g d: snapshot.txt\n" ); printf( " toidsnap -s d: snapshot.txt\n" ); return; } EXTERN_C void __cdecl _tmain( int cArg, TCHAR *rgtszArg[] ) { NTSTATUS status = 0; TCHAR tszFile[ MAX_PATH + 1 ]; TCHAR tszDir[ MAX_PATH + 1 ]; TCHAR* ptcTmp = NULL; LONG iVol; BOOL fSuccess = TRUE; BOOL fSaving = FALSE; HANDLE hFileSnapshot = INVALID_HANDLE_VALUE; HANDLE hMapping = INVALID_HANDLE_VALUE; IO_STATUS_BLOCK Iosb; TCHAR tszFileData[ 3 * MAX_PATH ]; ULONG cLine = 0; TrkDebugCreate( TRK_DBG_FLAGS_WRITE_TO_DBG, "TOidSnap" ); // ------------------------- // Validate the command-line // ------------------------- if( 4 != cArg ) { Usage(); goto Exit; } _tcslwr( rgtszArg[1] ); _tcslwr( rgtszArg[2] ); if( TEXT('-') != rgtszArg[1][0] && TEXT('/') != rgtszArg[1][0] || TEXT('g') != rgtszArg[1][1] && TEXT('s') != rgtszArg[1][1] || TEXT(':') != rgtszArg[2][1] || TEXT('a') > rgtszArg[2][0] || TEXT('z') < rgtszArg[2][0] ) { Usage(); goto Exit; } fSaving = TEXT('g') == rgtszArg[1][1]; iVol = rgtszArg[2][0] - TEXT('a'); if( !IsLocalObjectVolume( iVol )) { _tprintf( TEXT("%c: isn't an NTFS5 volume\n"), VolChar(iVol) ); goto Exit; } __try { FILE_FS_OBJECTID_INFORMATION fsobOID; EnableRestorePrivilege(); // Open the snapshot file hFileSnapshot = CreateFile( rgtszArg[3], fSaving ? GENERIC_WRITE : GENERIC_READ, 0, NULL, fSaving ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( INVALID_HANDLE_VALUE == hFileSnapshot ) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open file: %s (%lu)"), rgtszArg[3], GetLastError() )); TrkRaiseLastError(); } // ---- // Save // ---- if( fSaving ) { // Get the volid CVolumeId volid; status = QueryVolumeId( iVol, &volid ); if( STATUS_OBJECT_NAME_NOT_FOUND != status && !NT_SUCCESS(status) ) TrkRaiseNtStatus( status ); // Write the volid to the snapshot file. WriteToSnapshot( hFileSnapshot, TEXT("VolId, ") ); CStringize strVolid(volid); WriteToSnapshot( hFileSnapshot, static_cast(strVolid) ); WriteToSnapshot( hFileSnapshot, TEXT("\n") ); WriteToSnapshot( hFileSnapshot, NULL ); cLine++; CObjId objid; CDomainRelativeObjId droidBirth; CObjIdEnumerator oie; // Loop through the files with object IDs if(oie.Initialize(CVolumeDeviceName(iVol)) == TRUE) { if(oie.FindFirst(&objid, &droidBirth)) { do { // Open the file so that we can get its path HANDLE hFile; status = OpenFileById( iVol, objid, SYNCHRONIZE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, &hFile); if( !NT_SUCCESS(status) ) { TrkLog(( TRKDBG_ERROR, TEXT("Failed OpenFileById for %s"), static_cast(CStringize(objid)) )); TrkRaiseNtStatus(status); } // Get the local path status = QueryVolRelativePath( hFile, tszFileData ); if( !NT_SUCCESS(status) ) { TrkLog(( TRKDBG_ERROR, TEXT("Failed QueryVolRelativePath for %s"), static_cast(CStringize(objid)) )); TrkRaiseNtStatus(status); } // Write the path, objid, and birth ID to the snapshot file. _tcscat( tszFileData, TEXT(" = ") ); _tcscat( tszFileData, static_cast(CStringize(objid)) ); _tcscat( tszFileData, TEXT(", ") ); _tcscat( tszFileData, static_cast(CStringize(droidBirth)) ); _tcscat( tszFileData, TEXT("\n") ); // Write a line terminator to the snapshot file. WriteToSnapshot( hFileSnapshot, tszFileData ); WriteToSnapshot( hFileSnapshot, NULL ); cLine++; } while(oie.FindNext(&objid, &droidBirth)); // Write an marker to show end-of-file WriteToSnapshot( hFileSnapshot, TEXT("\n") ); WriteToSnapshot( hFileSnapshot, NULL ); } } printf( "%d IDs saved\n", cLine ); } // if fSaving // --------- // Restoring // --------- else { ULONG cCollisions = 0, cSuccess = 0; TCHAR *ptsz = NULL; // Map the snapshot file into memory. hMapping = CreateFileMapping( hFileSnapshot, NULL, PAGE_READONLY, 0, 0, NULL ); if( NULL == hMapping ) { TrkLog(( TRKDBG_ERROR, TEXT("Failed CreateFileMapping") )); TrkRaiseLastError(); } ptsz = reinterpret_cast( MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 )); if( NULL == ptsz ) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't map view of file") )); TrkRaiseLastError(); } // The file should start with the volid if( NULL == _tcsstr( ptsz, TEXT("VolId, ") )) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't find volid") )); TrkRaiseException( E_FAIL ); } // Move ptsz to the start of the stringized volid ptsz += _tcslen(TEXT("VolId, ")); // Unstringize the volid and set it on the volume. CVolumeId volid; CStringize stringize; stringize.Use( ptsz ); volid = stringize; status = SetVolId( iVol, volid ); if( !NT_SUCCESS(status) ) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't set volid") )); TrkRaiseNtStatus(status); } cSuccess++; // Move past the eol & null after the volid. ptsz = _tcschr( ptsz, TEXT('\n') ); if( NULL == ptsz || TEXT('\0') != ptsz[1] ) { TrkLog(( TRKDBG_ERROR, TEXT("Unexpected end of file") )); TrkRaiseException( E_FAIL ); } cLine++; ptsz += 2; // Past '\n' and '\0' // Init tszPath with the drive letter. TCHAR tszPath[ MAX_PATH + 1 ]; tszPath[0] = VolChar(iVol); tszPath[1] = TEXT(':'); // Loop through the object IDs in the snapshot file. // They are in the form: // // = , // // E.g. // \test = {...}, {...}{...} while( TRUE ) { // Find the separator between the file name and the objid TCHAR *ptszSep; ptszSep = _tcschr( ptsz, TEXT('=') ); if( NULL == ptszSep ) TrkRaiseException( E_FAIL ); // cch is the length of the file name ULONG cch = ptszSep - ptsz; if( 0 == cch ) TrkRaiseException( E_FAIL ); cch--; // Put the file name into tszPath _tcsncpy( &tszPath[2], ptsz, cch ); tszPath[2+cch] = TEXT('\0'); // Move ptsz to the beginning of the stringized objid ptsz = ptszSep + 1; if( TEXT(' ') != *ptsz ) TrkRaiseException( E_FAIL ); ptsz++; // Unstringize the objid stringize.Use( ptsz ); CObjId objid = stringize; // Move ptsz to the beginning of the birth ID, and unstringize it. ptsz = _tcschr( ptsz, TEXT(',') ); if( NULL == ptsz || TEXT(' ') != ptsz[1] ) TrkRaiseException( E_FAIL ); ptsz += 2; stringize.Use( ptsz ); CDomainRelativeObjId droidBirth; droidBirth = stringize; // Set the objid and birth ID status = SetObjId( tszPath, objid, droidBirth ); if( STATUS_OBJECT_NAME_COLLISION == status ) { cCollisions++; status = STATUS_SUCCESS; } else if( FAILED(status) ) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't set objid on %s"), tszPath )); TrkRaiseNtStatus( status ); } else cSuccess++; //_tprintf( TEXT("Set %s on %s\n"), static_cast(CStringize(objid)), tszPath ); // Move to the endo of the line ptsz = _tcschr( ptsz, TEXT('\n') ); if( NULL == ptsz || TEXT('\0') != ptsz[1] ) TrkRaiseException( E_FAIL ); // Move to the beginning of the next line ptsz += 2; // '\n' & '\0' // If this is an empty line, then we're at the end of the file. if( TEXT('\n') == *ptsz ) break; } // while( TRUE ) printf( "%d IDs successfully set, %d ID collisions\n", cSuccess, cCollisions ); } // if fSaving ... else } __except( EXCEPTION_EXECUTE_HANDLER ) { printf( "Error exception at line %d: %08x\n", cLine, GetExceptionCode() ); } Exit: return; } // main()