|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
fsinfo.c
Abstract:
This file contains code for commands that affect information specific to the file system.
Author:
Wesley Witt [wesw] 1-March-2000
Revision History:
--*/
#include <precomp.h>
INT FsInfoHelp( IN INT argc, IN PWSTR argv[] ) { DisplayMsg( MSG_USAGE_FSINFO ); return EXIT_CODE_SUCCESS; }
typedef struct _NTFS_FILE_SYSTEM_STATISTICS { FILESYSTEM_STATISTICS Common; NTFS_STATISTICS Ntfs; UCHAR Pad[64-(sizeof(FILESYSTEM_STATISTICS)+sizeof(NTFS_STATISTICS))%64]; } NTFS_FILE_SYSTEM_STATISTICS, *PNTFS_FILE_SYSTEM_STATISTICS;
typedef struct _FAT_FILE_SYSTEM_STATISTICS { FILESYSTEM_STATISTICS Common; FAT_STATISTICS Fat; UCHAR Pad[64-(sizeof(FILESYSTEM_STATISTICS)+sizeof(NTFS_STATISTICS))%64]; } FAT_FILE_SYSTEM_STATISTICS, *PFAT_FILE_SYSTEM_STATISTICS;
ULONGLONG FsStat( IN PVOID FsStats, IN ULONG FsSize, IN ULONG Offset, IN ULONG NumProcs ) /*++
Routine Description:
This routine iterates through the file system statistics structure and accumulates a total amount for a given statistic field.
Note: This function assumes that the width of the field being accumulated is a ULONG. If this assumption is invalidated then a width argument should be added to this function.
Arguments:
FsStats - Pointer to an array of file system statistics structures FsSize - Size of the individual file system statistics structures in the array Offset - Offset of the desired field from the beginning of the file system statistics structure NumProcs - Number of processors on the machine where the stats were gathered
Return Value:
Accumulated total.
--*/ { ULONG i; ULONGLONG Total = 0;
for (i=0; i<NumProcs; i++) { Total += *(PULONG)((PUCHAR)FsStats + Offset); FsStats = (PVOID)((PUCHAR)FsStats + FsSize); }
return Total; }
INT ListDrives( IN INT argc, IN PWSTR argv[] ) /*++
Routine Description:
This routine lists all the drive names in the system.
Arguments:
argc - The argument count argv - Array of Strings of the form : 'fscutl lsdrv'.
Return Value:
None
--*/ { DWORD nBufferLen = MAX_PATH; DWORD Length; LPWSTR lpBuffer = NULL; int Index; INT ExitCode = EXIT_CODE_SUCCESS;
try {
if (argc != 0) { DisplayMsg( MSG_LISTDRIVES_USAGE ); ExitCode = EXIT_CODE_FAILURE; leave; }
lpBuffer = (LPWSTR) malloc( nBufferLen * sizeof(WCHAR) ); if (!lpBuffer) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
Length = GetLogicalDriveStrings( nBufferLen, lpBuffer ); if (!Length) { DisplayError(); ExitCode = EXIT_CODE_FAILURE; leave; }
OutputMessage( L"\r\n" ); DisplayMsg( MSG_DRIVES ); Index = 0; while ((Length = wcslen( &lpBuffer[Index] )) != 0) { OutputMessageLength( &lpBuffer[Index], Length ); OutputMessage( L" " ); Index += Length + 1; } OutputMessage( L"\r\n" );
} finally {
if (lpBuffer) { free( lpBuffer ); }
} return ExitCode; }
INT DriveType( IN INT argc, IN PWSTR argv[] ) /*++
Routine Description:
This routine describes the drive type of the drive passed in.
Arguments:
argc - The argument count argv - Array of Strings of the form : 'fscutl dt <drive name>' or 'fscutl drivetype <drive name>'
Return Value:
None
--*/ { if (argc != 1) { DisplayMsg( MSG_USAGE_DRIVETYPE ); if (argc != 0) { return EXIT_CODE_FAILURE; } else { return EXIT_CODE_SUCCESS; } }
switch (GetDriveType( argv[0] )) { case DRIVE_NO_ROOT_DIR: DisplayMsg( MSG_DRIVE_NO_ROOT_DIR, argv[0] ); break; case DRIVE_REMOVABLE: DisplayMsg( MSG_DRIVE_REMOVABLE, argv[0] ); break; case DRIVE_FIXED: DisplayMsg( MSG_DRIVE_FIXED, argv[0] ); break; case DRIVE_REMOTE: DisplayMsg( MSG_DRIVE_REMOTE, argv[0] ); break; case DRIVE_CDROM: DisplayMsg( MSG_DRIVE_CDROM, argv[0] ); break; case DRIVE_RAMDISK: DisplayMsg( MSG_DRIVE_RAMDISK, argv[0] ); break; case DRIVE_UNKNOWN: default: DisplayMsg( MSG_DRIVE_UNKNOWN, argv[0] ); break; } return EXIT_CODE_SUCCESS; }
INT VolumeInfo( IN INT argc, IN PWSTR argv[] ) /*++
Routine Description:
This routine provides the information about the Volume.
Arguments:
argc - The argument count argv - Array of Strings of the form : 'fscutl infov <root pathname>'.
Return Value:
None
--*/ { LPWSTR lpVolumeNameBuffer = NULL; // address of name of the volume
DWORD nVolumeNameSize; // length of lpVolumeNameBuffer
LPDWORD lpVolumeSerialNumber = NULL; // address of volume serial number
LPDWORD lpMaximumComponentLength = NULL; // address of system's maximum
// filename length
LPDWORD lpFileSystemFlags = NULL; // address of file system flags
LPWSTR lpFileSystemNameBuffer = NULL; // address of name of file system
DWORD nFileSystemNameSize; // length of lpFileSystemNameBuffer
BOOL Status; // return status
DWORD dwMask; // FileSystem Flag Mask
DWORD Index; DWORD FsFlag; INT ExitCode = EXIT_CODE_SUCCESS;
try {
if (argc != 1) { DisplayMsg( MSG_USAGE_INFOV ); if (argc != 0) { ExitCode = EXIT_CODE_FAILURE; } leave ; }
nVolumeNameSize = MAX_PATH;
lpVolumeNameBuffer = (LPWSTR) malloc ( MAX_PATH * sizeof(WCHAR) ); if (lpVolumeNameBuffer == NULL) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
lpVolumeSerialNumber = (LPDWORD) malloc( sizeof(DWORD) ); if (lpVolumeSerialNumber == NULL) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
lpFileSystemFlags = (LPDWORD) malloc ( sizeof(DWORD) ); if (lpFileSystemFlags == NULL) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
lpMaximumComponentLength = (LPDWORD) malloc ( sizeof(DWORD) ); if (lpMaximumComponentLength == NULL) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
nFileSystemNameSize = MAX_PATH; lpFileSystemNameBuffer = (LPWSTR) malloc ( MAX_PATH * sizeof(WCHAR) ); if (lpFileSystemNameBuffer == NULL) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
Status = GetVolumeInformation ( argv[0], lpVolumeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize ); if (!Status) { DisplayError(); ExitCode = EXIT_CODE_FAILURE; leave; }
DisplayMsg( MSG_VOLNAME, lpVolumeNameBuffer ); DisplayMsg( MSG_SERIALNO, *lpVolumeSerialNumber ); DisplayMsg( MSG_MAX_COMP_LEN, *lpMaximumComponentLength ); DisplayMsg( MSG_FS_NAME, lpFileSystemNameBuffer );
dwMask = 1 ; FsFlag = *lpFileSystemFlags;
for ( Index=0 ; Index<32 ; Index++ ) { switch (FsFlag & dwMask) { case FILE_CASE_SENSITIVE_SEARCH: DisplayMsg( MSG_FILE_CASE_SENSITIVE_SEARCH ); break;
case FILE_CASE_PRESERVED_NAMES: DisplayMsg( MSG_FILE_CASE_PRESERVED_NAMES ); break;
case FILE_UNICODE_ON_DISK: DisplayMsg( MSG_FILE_UNICODE_ON_DISK ); break;
case FILE_PERSISTENT_ACLS: DisplayMsg( MSG_FILE_PERSISTENT_ACLS ); break;
case FILE_FILE_COMPRESSION: DisplayMsg( MSG_FILE_FILE_COMPRESSION ); break;
case FILE_VOLUME_QUOTAS: DisplayMsg( MSG_FILE_VOLUME_QUOTAS ); break;
case FILE_SUPPORTS_SPARSE_FILES: DisplayMsg( MSG_FILE_SUPPORTS_SPARSE_FILES ); break;
case FILE_SUPPORTS_REPARSE_POINTS: DisplayMsg( MSG_FILE_SUPPORTS_REPARSE_POINTS ); break;
case FILE_SUPPORTS_REMOTE_STORAGE: DisplayMsg( MSG_FILE_SUPPORTS_REMOTE_STORAGE ); break;
case FILE_VOLUME_IS_COMPRESSED: DisplayMsg( MSG_FILE_VOLUME_IS_COMPRESSED ); break;
case FILE_SUPPORTS_OBJECT_IDS: DisplayMsg( MSG_FILE_SUPPORTS_OBJECT_IDS ); break;
case FILE_SUPPORTS_ENCRYPTION: DisplayMsg( MSG_FILE_SUPPORTS_ENCRYPTION ); break;
case FILE_NAMED_STREAMS: DisplayMsg( MSG_FILE_NAMED_STREAMS ); break; } dwMask <<= 1; }
} finally {
free( lpVolumeNameBuffer ); free( lpVolumeSerialNumber ); free( lpFileSystemFlags ); free( lpMaximumComponentLength ); free( lpFileSystemNameBuffer ); }
return ExitCode; }
INT GetNtfsVolumeData( IN INT argc, IN PWSTR argv[] ) /*++
Routine Description:
This routine gets the NTFS volume data for the volume specified.
Arguments:
argc - The argument count. argv - Array of Strings of the form : ' fscutl getntfsdv <volume pathname>'.
Return Value:
None
--*/ { HANDLE FileHandle = INVALID_HANDLE_VALUE; WCHAR FileName[MAX_PATH]; BOOL Status; BYTE Buffer[sizeof( NTFS_VOLUME_DATA_BUFFER ) + sizeof( NTFS_EXTENDED_VOLUME_DATA )]; PNTFS_VOLUME_DATA_BUFFER pvdb = (PNTFS_VOLUME_DATA_BUFFER)Buffer; PNTFS_EXTENDED_VOLUME_DATA pevd = (PNTFS_EXTENDED_VOLUME_DATA)(pvdb + 1); DWORD BytesReturned; INT ExitCode = EXIT_CODE_SUCCESS;
try {
if (argc != 1) { DisplayMsg( MSG_USAGE_NTFSINFO ); if (argc != 0) { ExitCode = EXIT_CODE_FAILURE; } leave; }
if (!IsVolumeLocalNTFS( argv[0][0] )) { DisplayMsg( MSG_NTFS_REQUIRED ); ExitCode = EXIT_CODE_FAILURE; leave; }
if (wcslen( DotPrefix ) + wcslen( argv[0] ) + 1 > MAX_PATH) { DisplayMsg( MSG_FILENAME_TOO_LONG ); ExitCode = EXIT_CODE_FAILURE; leave; } wcscpy( FileName, DotPrefix ); wcscat( FileName, argv[0] );
FileHandle = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (FileHandle == INVALID_HANDLE_VALUE) { DisplayError(); ExitCode = EXIT_CODE_FAILURE; leave; }
Status = DeviceIoControl( FileHandle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, pvdb, sizeof( Buffer ), &BytesReturned, (LPOVERLAPPED)NULL ); if (!Status) { DisplayError(); ExitCode = EXIT_CODE_FAILURE; leave; }
DisplayMsg( MSG_NTFSINFO_STATS, QuadToPaddedHexText( pvdb->VolumeSerialNumber.QuadPart ), // Serial number in hex
pevd->MajorVersion, pevd->MinorVersion, QuadToPaddedHexText( pvdb->NumberSectors.QuadPart ), QuadToPaddedHexText( pvdb->TotalClusters.QuadPart ), QuadToPaddedHexText( pvdb->FreeClusters.QuadPart ), QuadToPaddedHexText( pvdb->TotalReserved.QuadPart ), pvdb->BytesPerSector, pvdb->BytesPerCluster, pvdb->BytesPerFileRecordSegment, pvdb->ClustersPerFileRecordSegment, QuadToPaddedHexText( pvdb->MftValidDataLength.QuadPart ), QuadToPaddedHexText( pvdb->MftStartLcn.QuadPart ), QuadToPaddedHexText( pvdb->Mft2StartLcn.QuadPart ), QuadToPaddedHexText( pvdb->MftZoneStart.QuadPart ), QuadToPaddedHexText( pvdb->MftZoneEnd.QuadPart ) );
} finally {
if (FileHandle != INVALID_HANDLE_VALUE) { CloseHandle( FileHandle ); }
} return ExitCode; }
INT GetFileSystemStatistics( IN INT argc, IN PWSTR argv[] ) /*++
Routine Description:
This routine gets the file system statistics for the volume specified.
Arguments:
argc - The argument count. argv - Array of Strings of the form : ' fscutl getfss <volume pathname>'.
Return Value:
None
--*/ { #define FS_STAT(_f) FsStat( FsStats, StrucSize, offsetof(FILESYSTEM_STATISTICS,_f), SysInfo.dwNumberOfProcessors )
#define FAT_STAT(_f) FsStat( FatFsStats, StrucSize, offsetof(FAT_FILE_SYSTEM_STATISTICS,_f), SysInfo.dwNumberOfProcessors )
#define NTFS_STAT(_f) FsStat( NtfsFsStats, StrucSize, offsetof(NTFS_FILE_SYSTEM_STATISTICS,_f), SysInfo.dwNumberOfProcessors )
BOOL Status; HANDLE FileHandle = INVALID_HANDLE_VALUE; WCHAR FileName[MAX_PATH]; PFILESYSTEM_STATISTICS FsStats = NULL; DWORD OutBufferSize; DWORD BytesReturned; SYSTEM_INFO SysInfo; PNTFS_FILE_SYSTEM_STATISTICS NtfsFsStats = NULL; PFAT_FILE_SYSTEM_STATISTICS FatFsStats = NULL; ULONG StrucSize; INT ExitCode = EXIT_CODE_SUCCESS;
try {
if (argc != 1) { DisplayMsg( MSG_USAGE_GETFSS ); if (argc != 0) { ExitCode = EXIT_CODE_FAILURE; } leave; }
if (!IsVolumeLocalNTFS( argv[0][0] )) { DisplayMsg( MSG_NTFS_REQUIRED ); ExitCode = EXIT_CODE_FAILURE; leave; }
if (wcslen( DotPrefix ) + wcslen( argv[0] ) + 1 > MAX_PATH) { DisplayMsg( MSG_FILENAME_TOO_LONG ); ExitCode = EXIT_CODE_FAILURE; leave; } wcscpy( FileName, DotPrefix ); wcscat( FileName, argv[0] );
FileHandle = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (FileHandle == INVALID_HANDLE_VALUE) { DisplayError(); ExitCode = EXIT_CODE_FAILURE; leave; }
GetSystemInfo( &SysInfo );
OutBufferSize = max(sizeof(NTFS_FILE_SYSTEM_STATISTICS),sizeof(FAT_FILE_SYSTEM_STATISTICS)) * SysInfo.dwNumberOfProcessors;
FsStats = (PFILESYSTEM_STATISTICS) malloc ( OutBufferSize ); if (FsStats == NULL) { DisplayErrorMsg( ERROR_NOT_ENOUGH_MEMORY ); ExitCode = EXIT_CODE_FAILURE; leave; }
Status = DeviceIoControl( FileHandle, FSCTL_FILESYSTEM_GET_STATISTICS, NULL, 0, FsStats, OutBufferSize, &BytesReturned, (LPOVERLAPPED)NULL ); if (!Status) { DisplayError(); ExitCode = EXIT_CODE_FAILURE; leave; }
switch (FsStats->FileSystemType) { case FILESYSTEM_STATISTICS_TYPE_NTFS: DisplayMsg( MSG_FSTYPE_NTFS ); NtfsFsStats = (PNTFS_FILE_SYSTEM_STATISTICS) FsStats; StrucSize = sizeof(NTFS_FILE_SYSTEM_STATISTICS); break;
case FILESYSTEM_STATISTICS_TYPE_FAT: DisplayMsg( MSG_FSTYPE_FAT ); FatFsStats = (PFAT_FILE_SYSTEM_STATISTICS) FsStats; StrucSize = sizeof(FAT_FILE_SYSTEM_STATISTICS); break; }
DisplayMsg( MSG_GENERAL_FSSTAT, QuadToDecimalText( FS_STAT(UserFileReads)), QuadToDecimalText( FS_STAT(UserFileReadBytes)), QuadToDecimalText( FS_STAT(UserDiskReads)), QuadToDecimalText( FS_STAT(UserFileWrites)), QuadToDecimalText( FS_STAT(UserFileWriteBytes)), QuadToDecimalText( FS_STAT(UserDiskWrites)), QuadToDecimalText( FS_STAT(MetaDataReads)), QuadToDecimalText( FS_STAT(MetaDataReadBytes)), QuadToDecimalText( FS_STAT(MetaDataDiskReads)), QuadToDecimalText( FS_STAT(MetaDataWrites)), QuadToDecimalText( FS_STAT(MetaDataWriteBytes)), QuadToDecimalText( FS_STAT(MetaDataDiskWrites)) );
//
// Print FileSystem specific data
//
switch (FsStats->FileSystemType) { case FILESYSTEM_STATISTICS_TYPE_FAT: DisplayMsg( MSG_FAT_FSSTA, QuadToDecimalText( FAT_STAT(Fat.CreateHits)), QuadToDecimalText( FAT_STAT(Fat.SuccessfulCreates)), QuadToDecimalText( FAT_STAT(Fat.FailedCreates)), QuadToDecimalText( FAT_STAT(Fat.NonCachedReads)), QuadToDecimalText( FAT_STAT(Fat.NonCachedReadBytes)), QuadToDecimalText( FAT_STAT(Fat.NonCachedWrites)), QuadToDecimalText( FAT_STAT(Fat.NonCachedWriteBytes)), QuadToDecimalText( FAT_STAT(Fat.NonCachedDiskReads)), QuadToDecimalText( FAT_STAT(Fat.NonCachedDiskWrites)) ); break;
case FILESYSTEM_STATISTICS_TYPE_NTFS: DisplayMsg( MSG_NTFS_FSSTA, QuadToDecimalText( NTFS_STAT(Ntfs.MftReads)), QuadToDecimalText( NTFS_STAT(Ntfs.MftReadBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.MftWrites)), QuadToDecimalText( NTFS_STAT(Ntfs.MftWriteBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.Mft2Writes)), QuadToDecimalText( NTFS_STAT(Ntfs.Mft2WriteBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.RootIndexReads)), QuadToDecimalText( NTFS_STAT(Ntfs.RootIndexReadBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.RootIndexWrites)), QuadToDecimalText( NTFS_STAT(Ntfs.RootIndexWriteBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.BitmapReads)), QuadToDecimalText( NTFS_STAT(Ntfs.BitmapReadBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.BitmapWrites)), QuadToDecimalText( NTFS_STAT(Ntfs.BitmapWriteBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.MftBitmapReads)), QuadToDecimalText( NTFS_STAT(Ntfs.MftBitmapReadBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.MftBitmapWrites)), QuadToDecimalText( NTFS_STAT(Ntfs.MftBitmapWriteBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.UserIndexReads)), QuadToDecimalText( NTFS_STAT(Ntfs.UserIndexReadBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.UserIndexWrites)), QuadToDecimalText( NTFS_STAT(Ntfs.UserIndexWriteBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.LogFileReads)), QuadToDecimalText( NTFS_STAT(Ntfs.LogFileReadBytes)), QuadToDecimalText( NTFS_STAT(Ntfs.LogFileWrites)), QuadToDecimalText( NTFS_STAT(Ntfs.LogFileWriteBytes)) );
//
// Still some more fields left
//
break; }
} finally {
if (FileHandle != INVALID_HANDLE_VALUE) { CloseHandle( FileHandle ); } if (FsStats) { free( FsStats ); }
} return ExitCode; }
|