310 lines
9.4 KiB
C++
310 lines
9.4 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999.
|
|
//
|
|
// File: usnmon.cxx
|
|
//
|
|
// Contents: USN monitor
|
|
//
|
|
// History: 18 Nov 1998 DLee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifndef _WIN32_WINNT
|
|
#define _WIN32_WINNT 0x0500
|
|
#endif
|
|
|
|
extern "C"
|
|
{
|
|
#include <nt.h>
|
|
#include <ntioapi.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntexapi.h>
|
|
}
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <process.h>
|
|
|
|
#define MAX_PATH_WCHARS (MAX_PATH * 4 )
|
|
|
|
BOOL fVerbose = FALSE;
|
|
|
|
void usage()
|
|
{
|
|
printf( "usage: usnmon x: [-verbose]\n" );
|
|
printf( "You must be an administrator to run this application.\n" );
|
|
exit( 1 );
|
|
} //usage
|
|
|
|
void IdToPath(
|
|
HANDLE hVol,
|
|
LONGLONG ll,
|
|
WCHAR wcVol,
|
|
WCHAR * pwcPath )
|
|
{
|
|
*pwcPath = 0;
|
|
|
|
UNICODE_STRING uScope;
|
|
uScope.Buffer = (WCHAR *) ≪
|
|
uScope.Length = sizeof ll;
|
|
uScope.MaximumLength = sizeof ll;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttr;
|
|
InitializeObjectAttributes( &ObjectAttr, // Structure
|
|
&uScope, // Name
|
|
OBJ_CASE_INSENSITIVE, // Attributes
|
|
hVol, // Root
|
|
0 ); // Security
|
|
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE h = INVALID_HANDLE_VALUE;
|
|
NTSTATUS Status = NtOpenFile( &h,
|
|
FILE_READ_ATTRIBUTES,
|
|
&ObjectAttr,
|
|
&IoStatus,
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
FILE_OPEN_BY_FILE_ID );
|
|
if ( NT_ERROR( Status ) )
|
|
return;
|
|
|
|
static BYTE abFileNameInformation[ MAX_PATH_WCHARS * sizeof WCHAR +
|
|
sizeof FILE_NAME_INFORMATION ];
|
|
|
|
ULONG cbMax = sizeof abFileNameInformation;
|
|
|
|
PFILE_NAME_INFORMATION FileName = (PFILE_NAME_INFORMATION) abFileNameInformation;
|
|
FileName->FileNameLength = cbMax - sizeof FILE_NAME_INFORMATION;
|
|
|
|
Status = NtQueryInformationFile( h,
|
|
&IoStatus,
|
|
FileName,
|
|
cbMax,
|
|
FileNameInformation );
|
|
NtClose( h );
|
|
|
|
if ( NT_ERROR( Status ) )
|
|
return;
|
|
|
|
// This is actually the full path, not the filename
|
|
|
|
FileName->FileName[ FileName->FileNameLength / sizeof WCHAR ] = 0;
|
|
|
|
pwcPath[0] = wcVol;
|
|
pwcPath[1] = ':';
|
|
wcscpy( pwcPath + 2, FileName->FileName );
|
|
} //IdToPath
|
|
|
|
USN PrintUsnRecords(
|
|
HANDLE hVol,
|
|
WCHAR wcVol,
|
|
IO_STATUS_BLOCK * pIoSB,
|
|
void * pBuffer,
|
|
USN usnPrev )
|
|
{
|
|
USN usnNextStart;
|
|
USN_RECORD * pUsnRec;
|
|
|
|
ULONG_PTR dwByteCount = pIoSB->Information;
|
|
if ( 0 != dwByteCount )
|
|
{
|
|
usnNextStart = *(USN *)pBuffer;
|
|
pUsnRec = (USN_RECORD *)((PCHAR)pBuffer + sizeof(USN));
|
|
dwByteCount -= sizeof(USN);
|
|
}
|
|
else
|
|
{
|
|
usnNextStart = usnPrev;
|
|
}
|
|
|
|
while ( 0 != dwByteCount )
|
|
{
|
|
if ( fVerbose )
|
|
printf( "usn %#I64x id %#I64x ",
|
|
pUsnRec->Usn,
|
|
pUsnRec->FileReferenceNumber );
|
|
|
|
static WCHAR awcPath[ MAX_PATH_WCHARS ];
|
|
|
|
IdToPath( hVol, pUsnRec->FileReferenceNumber, wcVol, awcPath );
|
|
|
|
ULONG r = pUsnRec->Reason;
|
|
|
|
if ( 0 == awcPath[0] || ( r & USN_REASON_RENAME_OLD_NAME ) )
|
|
{
|
|
IdToPath( hVol, pUsnRec->ParentFileReferenceNumber, wcVol, awcPath );
|
|
|
|
// If the parent directory has already been deleted, just
|
|
// print the filename.
|
|
|
|
if ( 0 == awcPath[0] )
|
|
printf( "(%.*ws) ",
|
|
pUsnRec->FileNameLength / sizeof WCHAR,
|
|
&pUsnRec->FileName );
|
|
else
|
|
printf( "%ws\\%.*ws ",
|
|
awcPath,
|
|
pUsnRec->FileNameLength / sizeof WCHAR,
|
|
&pUsnRec->FileName );
|
|
}
|
|
else
|
|
printf( "%ws ", awcPath );
|
|
|
|
if ( r & USN_REASON_DATA_OVERWRITE )
|
|
printf( "DATA_OVERWRITE " );
|
|
if ( r & USN_REASON_DATA_EXTEND )
|
|
printf( "DATA_EXTEND " );
|
|
if ( r & USN_REASON_DATA_TRUNCATION )
|
|
printf( "DATA_TRUNCATION " );
|
|
if ( r & USN_REASON_NAMED_DATA_OVERWRITE )
|
|
printf( "NAMED_DATA_OVERWRITE " );
|
|
if ( r & USN_REASON_NAMED_DATA_EXTEND )
|
|
printf( "NAMED_DATA_EXTEND " );
|
|
if ( r & USN_REASON_NAMED_DATA_TRUNCATION )
|
|
printf( "NAMED_DATA_TRUNCATION " );
|
|
if ( r & USN_REASON_FILE_CREATE )
|
|
printf( "FILE_CREATE " );
|
|
if ( r & USN_REASON_FILE_DELETE )
|
|
printf( "FILE_DELETE " );
|
|
if ( r & USN_REASON_EA_CHANGE )
|
|
printf( "EA_CHANGE " );
|
|
if ( r & USN_REASON_SECURITY_CHANGE )
|
|
printf( "SECURITY_CHANGE " );
|
|
if ( r & USN_REASON_RENAME_OLD_NAME )
|
|
printf( "RENAME_OLD_NAME " );
|
|
if ( r & USN_REASON_RENAME_NEW_NAME )
|
|
printf( "RENAME_NEW_NAME " );
|
|
if ( r & USN_REASON_INDEXABLE_CHANGE )
|
|
printf( "INDEXABLE_CHANGE " );
|
|
if ( r & USN_REASON_BASIC_INFO_CHANGE )
|
|
printf( "BASIC_INFO_CHANGE " );
|
|
if ( r & USN_REASON_HARD_LINK_CHANGE )
|
|
printf( "HARD_LINK_CHANGE " );
|
|
if ( r & USN_REASON_COMPRESSION_CHANGE )
|
|
printf( "COMPRESSION_CHANGE " );
|
|
if ( r & USN_REASON_ENCRYPTION_CHANGE )
|
|
printf( "ENCRYPTION_CHANGE " );
|
|
if ( r & USN_REASON_OBJECT_ID_CHANGE )
|
|
printf( "OBJECT_ID_CHANGE " );
|
|
if ( r & USN_REASON_REPARSE_POINT_CHANGE )
|
|
printf( "REPARSE_POINT_CHANGE " );
|
|
if ( r & USN_REASON_STREAM_CHANGE )
|
|
printf( "STREAM_CHANGE " );
|
|
if ( r & USN_REASON_CLOSE )
|
|
printf( "CLOSE " );
|
|
|
|
printf( "\n" );
|
|
|
|
if ( pUsnRec->RecordLength <= dwByteCount )
|
|
{
|
|
dwByteCount -= pUsnRec->RecordLength;
|
|
pUsnRec = (USN_RECORD *) ((PCHAR) pUsnRec + pUsnRec->RecordLength );
|
|
}
|
|
else
|
|
{
|
|
printf( "Usn read fsctl returned bogus dwByteCount %#x\n", dwByteCount );
|
|
exit( -1 );
|
|
}
|
|
}
|
|
|
|
return usnNextStart;
|
|
} //PrintUsnRecords
|
|
|
|
int __cdecl main(
|
|
int argc,
|
|
char * argv[] )
|
|
{
|
|
if ( 2 != argc && 3 != argc )
|
|
usage();
|
|
|
|
if ( 3 == argc && argv[2][1] == 'v' )
|
|
fVerbose = TRUE;
|
|
|
|
WCHAR wcVol = argv[1][0];
|
|
|
|
WCHAR wszVolumePath[] = L"\\\\.\\a:";
|
|
wszVolumePath[4] = wcVol;
|
|
HANDLE hVolume = CreateFile( wszVolumePath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL );
|
|
|
|
if ( INVALID_HANDLE_VALUE == hVolume )
|
|
{
|
|
printf( "Usn volume open failed %d, check for admin privileges\n", GetLastError() );
|
|
usage();
|
|
}
|
|
|
|
HANDLE hEvent = CreateEvent( 0, TRUE, FALSE, 0 );
|
|
|
|
//
|
|
// Get the Journal ID
|
|
//
|
|
|
|
USN_JOURNAL_DATA UsnJournalInfo;
|
|
IO_STATUS_BLOCK IoSB;
|
|
|
|
NTSTATUS status = NtFsControlFile( hVolume,
|
|
hEvent,
|
|
0,
|
|
0,
|
|
&IoSB,
|
|
FSCTL_QUERY_USN_JOURNAL,
|
|
0,
|
|
0,
|
|
&UsnJournalInfo,
|
|
sizeof UsnJournalInfo );
|
|
if ( STATUS_PENDING == status )
|
|
WaitForSingleObject( hEvent, INFINITE );
|
|
|
|
if ( !NT_SUCCESS(status) || !NT_SUCCESS(IoSB.Status) )
|
|
{
|
|
printf( "Error %#x / %#x returned from QUERY_USN_JOURNAL\n", status, IoSB.Status );
|
|
return -1;
|
|
}
|
|
|
|
USN usnMax = UsnJournalInfo.NextUsn;
|
|
|
|
do
|
|
{
|
|
READ_USN_JOURNAL_DATA usnData = { usnMax, MAXULONG, 0, 0, 1, UsnJournalInfo.UsnJournalID };
|
|
|
|
static ULONGLONG readBuffer[2048];
|
|
|
|
status = NtFsControlFile( hVolume,
|
|
hEvent,
|
|
0,
|
|
0,
|
|
&IoSB,
|
|
FSCTL_READ_USN_JOURNAL,
|
|
&usnData,
|
|
sizeof usnData,
|
|
&readBuffer,
|
|
sizeof readBuffer );
|
|
|
|
if ( STATUS_PENDING == status )
|
|
WaitForSingleObject( hEvent, INFINITE );
|
|
|
|
if ( NT_SUCCESS( status ) )
|
|
status = IoSB.Status;
|
|
|
|
if ( !NT_SUCCESS( status ) )
|
|
{
|
|
printf( "FSCTL_READ_USN_JOURNAL failed %#x\n", status );
|
|
return -1;
|
|
}
|
|
|
|
usnMax = PrintUsnRecords( hVolume, wcVol, &IoSB, readBuffer, usnMax );
|
|
} while ( TRUE );
|
|
|
|
return 0;
|
|
} //main
|
|
|