mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
[FSUTIL]
Implement fsutil fsinfo statistics Note that compared to w2k3 one, ours really supports FAT volumes (even though our FAT doesn't support it!). svn path=/trunk/; revision=75934
This commit is contained in:
parent
a497f5aae2
commit
e54cfbd253
1 changed files with 412 additions and 0 deletions
|
@ -12,12 +12,14 @@
|
|||
static HandlerProc DrivesMain;
|
||||
static HandlerProc DriveTypeMain;
|
||||
static HandlerProc VolumeInfoMain;
|
||||
static HandlerProc StatisticsMain;
|
||||
static HandlerItem HandlersList[] =
|
||||
{
|
||||
/* Proc, name, help */
|
||||
{ DrivesMain, _T("drives"), _T("Enumerates the drives") },
|
||||
{ DriveTypeMain, _T("drivetype"), _T("Provides the type of a drive") },
|
||||
{ VolumeInfoMain, _T("volumeinfo"), _T("Provides informations about a volume") },
|
||||
{ StatisticsMain, _T("statistics"), _T("Displays volume statistics") },
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -156,6 +158,416 @@ VolumeInfoMain(int argc, const TCHAR *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define DUMP_VALUE(stats, value) fprintf(stdout, "%s: %lu\n", #value, stats->value)
|
||||
|
||||
static void
|
||||
DumpBase(PFILESYSTEM_STATISTICS Base, TCHAR * Name)
|
||||
{
|
||||
/* Print FS name */
|
||||
_ftprintf(stdout, _T("File system type: %s\n\n"), Name);
|
||||
|
||||
/* And then, dump any base stat */
|
||||
DUMP_VALUE(Base, UserFileReads);
|
||||
DUMP_VALUE(Base, UserFileReadBytes);
|
||||
DUMP_VALUE(Base, UserDiskReads);
|
||||
DUMP_VALUE(Base, UserFileWrites);
|
||||
DUMP_VALUE(Base, UserFileWriteBytes);
|
||||
DUMP_VALUE(Base, UserDiskWrites);
|
||||
DUMP_VALUE(Base, MetaDataReads);
|
||||
DUMP_VALUE(Base, MetaDataReadBytes);
|
||||
DUMP_VALUE(Base, MetaDataDiskReads);
|
||||
DUMP_VALUE(Base, MetaDataWrites);
|
||||
DUMP_VALUE(Base, MetaDataWriteBytes);
|
||||
DUMP_VALUE(Base, MetaDataDiskWrites);
|
||||
|
||||
_ftprintf(stdout, _T("\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
DumpExFat(PVOID Statistics, PVOID Specific)
|
||||
{
|
||||
PEXFAT_STATISTICS ExFat;
|
||||
PFILESYSTEM_STATISTICS Base;
|
||||
|
||||
Base = Statistics;
|
||||
ExFat = Specific;
|
||||
|
||||
/* First, display the generic stats */
|
||||
DumpBase(Base, _T("EXFAT"));
|
||||
|
||||
/* Then, display the EXFAT specific ones */
|
||||
DUMP_VALUE(ExFat, CreateHits);
|
||||
DUMP_VALUE(ExFat, SuccessfulCreates);
|
||||
DUMP_VALUE(ExFat, FailedCreates);
|
||||
DUMP_VALUE(ExFat, NonCachedReads);
|
||||
DUMP_VALUE(ExFat, NonCachedReadBytes);
|
||||
DUMP_VALUE(ExFat, NonCachedWrites);
|
||||
DUMP_VALUE(ExFat, NonCachedWriteBytes);
|
||||
DUMP_VALUE(ExFat, NonCachedDiskReads);
|
||||
DUMP_VALUE(ExFat, NonCachedDiskWrites);
|
||||
}
|
||||
|
||||
static void
|
||||
DumpFat(PVOID Statistics, PVOID Specific)
|
||||
{
|
||||
PFAT_STATISTICS Fat;
|
||||
PFILESYSTEM_STATISTICS Base;
|
||||
|
||||
Base = Statistics;
|
||||
Fat = Specific;
|
||||
|
||||
/* First, display the generic stats */
|
||||
DumpBase(Base, _T("FAT"));
|
||||
|
||||
/* Then, display the FAT specific ones */
|
||||
DUMP_VALUE(Fat, CreateHits);
|
||||
DUMP_VALUE(Fat, SuccessfulCreates);
|
||||
DUMP_VALUE(Fat, FailedCreates);
|
||||
DUMP_VALUE(Fat, NonCachedReads);
|
||||
DUMP_VALUE(Fat, NonCachedReadBytes);
|
||||
DUMP_VALUE(Fat, NonCachedWrites);
|
||||
DUMP_VALUE(Fat, NonCachedWriteBytes);
|
||||
DUMP_VALUE(Fat, NonCachedDiskReads);
|
||||
DUMP_VALUE(Fat, NonCachedDiskWrites);
|
||||
}
|
||||
|
||||
static void
|
||||
DumpNtfs(PVOID Statistics, PVOID Specific)
|
||||
{
|
||||
PNTFS_STATISTICS Ntfs;
|
||||
PFILESYSTEM_STATISTICS Base;
|
||||
|
||||
Base = Statistics;
|
||||
Ntfs = Specific;
|
||||
|
||||
/* First, display the generic stats */
|
||||
DumpBase(Base, _T("NTFS"));
|
||||
|
||||
/* Then, display the NTFS specific ones */
|
||||
DUMP_VALUE(Ntfs, MftReads);
|
||||
DUMP_VALUE(Ntfs, MftReadBytes);
|
||||
DUMP_VALUE(Ntfs, MftWrites);
|
||||
DUMP_VALUE(Ntfs, MftWriteBytes);
|
||||
DUMP_VALUE(Ntfs, Mft2Writes);
|
||||
DUMP_VALUE(Ntfs, Mft2WriteBytes);
|
||||
DUMP_VALUE(Ntfs, RootIndexReads);
|
||||
DUMP_VALUE(Ntfs, RootIndexReadBytes);
|
||||
DUMP_VALUE(Ntfs, RootIndexWrites);
|
||||
DUMP_VALUE(Ntfs, RootIndexWriteBytes);
|
||||
DUMP_VALUE(Ntfs, BitmapReads);
|
||||
DUMP_VALUE(Ntfs, BitmapReadBytes);
|
||||
DUMP_VALUE(Ntfs, BitmapWrites);
|
||||
DUMP_VALUE(Ntfs, BitmapWriteBytes);
|
||||
DUMP_VALUE(Ntfs, MftBitmapReads);
|
||||
DUMP_VALUE(Ntfs, MftBitmapReadBytes);
|
||||
DUMP_VALUE(Ntfs, MftBitmapWrites);
|
||||
DUMP_VALUE(Ntfs, MftBitmapWriteBytes);
|
||||
DUMP_VALUE(Ntfs, UserIndexReads);
|
||||
DUMP_VALUE(Ntfs, UserIndexReadBytes);
|
||||
DUMP_VALUE(Ntfs, UserIndexWrites);
|
||||
DUMP_VALUE(Ntfs, UserIndexWriteBytes);
|
||||
DUMP_VALUE(Ntfs, LogFileReads);
|
||||
DUMP_VALUE(Ntfs, LogFileReadBytes);
|
||||
DUMP_VALUE(Ntfs, LogFileWrites);
|
||||
DUMP_VALUE(Ntfs, LogFileWriteBytes);
|
||||
}
|
||||
|
||||
#define GET_NEXT(stats, length, iter, type) (type)((ULONG_PTR)stats + (length * iter))
|
||||
#define SUM_VALUE(stats, new, value) stats->value += new->value
|
||||
|
||||
inline int
|
||||
ValidateSizes(ULONG Length, DWORD ProcCount, DWORD BytesRead, DWORD SpecificSize)
|
||||
{
|
||||
/* Check whether we could read our base length for every processor */
|
||||
if (Length * ProcCount > BytesRead)
|
||||
{
|
||||
_ftprintf(stderr, _T("Only performed a partial read: %lu (expected: %lu)\n"), BytesRead, Length * ProcCount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check whether this covers a specific entry and a generic entry for every processor */
|
||||
if ((sizeof(FILESYSTEM_STATISTICS) + SpecificSize) * ProcCount > BytesRead)
|
||||
{
|
||||
_ftprintf(stderr, _T("Only performed a partial read: %lu (expected: %lu)\n"), BytesRead, (sizeof(FILESYSTEM_STATISTICS) + SpecificSize));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
SumBase(PFILESYSTEM_STATISTICS Base, PFILESYSTEM_STATISTICS NextBase)
|
||||
{
|
||||
/* Sum any entry in the generic structures */
|
||||
SUM_VALUE(Base, NextBase, UserFileReads);
|
||||
SUM_VALUE(Base, NextBase, UserFileReadBytes);
|
||||
SUM_VALUE(Base, NextBase, UserDiskReads);
|
||||
SUM_VALUE(Base, NextBase, UserFileWrites);
|
||||
SUM_VALUE(Base, NextBase, UserFileWriteBytes);
|
||||
SUM_VALUE(Base, NextBase, UserDiskWrites);
|
||||
SUM_VALUE(Base, NextBase, MetaDataReads);
|
||||
SUM_VALUE(Base, NextBase, MetaDataReadBytes);
|
||||
SUM_VALUE(Base, NextBase, MetaDataDiskReads);
|
||||
SUM_VALUE(Base, NextBase, MetaDataWrites);
|
||||
SUM_VALUE(Base, NextBase, MetaDataWriteBytes);
|
||||
SUM_VALUE(Base, NextBase, MetaDataDiskWrites);
|
||||
}
|
||||
|
||||
static int
|
||||
SumExFat(PVOID Statistics, PVOID Specific, ULONG Length, DWORD ProcCount, DWORD BytesRead)
|
||||
{
|
||||
DWORD i;
|
||||
PEXFAT_STATISTICS ExFat;
|
||||
PFILESYSTEM_STATISTICS Base;
|
||||
|
||||
/* First, validate we won't read beyond allocation */
|
||||
if (ValidateSizes(Length, ProcCount, BytesRead, sizeof(EXFAT_STATISTICS)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Base = Statistics;
|
||||
ExFat = Specific;
|
||||
|
||||
/* And for every processor, sum every relevant value in first entry */
|
||||
for (i = 1; i < ProcCount; ++i)
|
||||
{
|
||||
PEXFAT_STATISTICS NextExFat;
|
||||
PFILESYSTEM_STATISTICS NextBase;
|
||||
|
||||
NextBase = GET_NEXT(Base, Length, i, PFILESYSTEM_STATISTICS);
|
||||
NextExFat = GET_NEXT(ExFat, Length, i, PEXFAT_STATISTICS);
|
||||
|
||||
/* Generic first */
|
||||
SumBase(Base, NextBase);
|
||||
/* Specific then */
|
||||
SUM_VALUE(ExFat, NextExFat, CreateHits);
|
||||
SUM_VALUE(ExFat, NextExFat, SuccessfulCreates);
|
||||
SUM_VALUE(ExFat, NextExFat, FailedCreates);
|
||||
SUM_VALUE(ExFat, NextExFat, NonCachedReads);
|
||||
SUM_VALUE(ExFat, NextExFat, NonCachedReadBytes);
|
||||
SUM_VALUE(ExFat, NextExFat, NonCachedWrites);
|
||||
SUM_VALUE(ExFat, NextExFat, NonCachedWriteBytes);
|
||||
SUM_VALUE(ExFat, NextExFat, NonCachedDiskReads);
|
||||
SUM_VALUE(ExFat, NextExFat, NonCachedDiskWrites);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
SumFat(PVOID Statistics, PVOID Specific, ULONG Length, DWORD ProcCount, DWORD BytesRead)
|
||||
{
|
||||
DWORD i;
|
||||
PFAT_STATISTICS Fat;
|
||||
PFILESYSTEM_STATISTICS Base;
|
||||
|
||||
/* First, validate we won't read beyond allocation */
|
||||
if (ValidateSizes(Length, ProcCount, BytesRead, sizeof(FAT_STATISTICS)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Base = Statistics;
|
||||
Fat = Specific;
|
||||
|
||||
/* And for every processor, sum every relevant value in first entry */
|
||||
for (i = 1; i < ProcCount; ++i)
|
||||
{
|
||||
PFAT_STATISTICS NextFat;
|
||||
PFILESYSTEM_STATISTICS NextBase;
|
||||
|
||||
NextBase = GET_NEXT(Base, Length, i, PFILESYSTEM_STATISTICS);
|
||||
NextFat = GET_NEXT(Fat, Length, i, PFAT_STATISTICS);
|
||||
|
||||
/* Generic first */
|
||||
SumBase(Base, NextBase);
|
||||
/* Specific then */
|
||||
SUM_VALUE(Fat, NextFat, CreateHits);
|
||||
SUM_VALUE(Fat, NextFat, SuccessfulCreates);
|
||||
SUM_VALUE(Fat, NextFat, FailedCreates);
|
||||
SUM_VALUE(Fat, NextFat, NonCachedReads);
|
||||
SUM_VALUE(Fat, NextFat, NonCachedReadBytes);
|
||||
SUM_VALUE(Fat, NextFat, NonCachedWrites);
|
||||
SUM_VALUE(Fat, NextFat, NonCachedWriteBytes);
|
||||
SUM_VALUE(Fat, NextFat, NonCachedDiskReads);
|
||||
SUM_VALUE(Fat, NextFat, NonCachedDiskWrites);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
SumNtfs(PVOID Statistics, PVOID Specific, ULONG Length, DWORD ProcCount, DWORD BytesRead)
|
||||
{
|
||||
DWORD i;
|
||||
PNTFS_STATISTICS Ntfs;
|
||||
PFILESYSTEM_STATISTICS Base;
|
||||
|
||||
/* First, validate we won't read beyond allocation */
|
||||
if (ValidateSizes(Length, ProcCount, BytesRead, sizeof(NTFS_STATISTICS)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Base = Statistics;
|
||||
Ntfs = Specific;
|
||||
|
||||
/* And for every processor, sum every relevant value in first entry */
|
||||
for (i = 1; i < ProcCount; ++i)
|
||||
{
|
||||
PNTFS_STATISTICS NextNtfs;
|
||||
PFILESYSTEM_STATISTICS NextBase;
|
||||
|
||||
NextBase = GET_NEXT(Base, Length, i, PFILESYSTEM_STATISTICS);
|
||||
NextNtfs = GET_NEXT(Ntfs, Length, i, PNTFS_STATISTICS);
|
||||
|
||||
/* Generic first */
|
||||
SumBase(Base, NextBase);
|
||||
/* Specific then */
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftReads);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftReadBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftWrites);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftWriteBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, Mft2Writes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, Mft2WriteBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, RootIndexReads);
|
||||
SUM_VALUE(Ntfs, NextNtfs, RootIndexReadBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, RootIndexWrites);
|
||||
SUM_VALUE(Ntfs, NextNtfs, RootIndexWriteBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, BitmapReads);
|
||||
SUM_VALUE(Ntfs, NextNtfs, BitmapReadBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, BitmapWrites);
|
||||
SUM_VALUE(Ntfs, NextNtfs, BitmapWriteBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftBitmapReads);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftBitmapReadBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftBitmapWrites);
|
||||
SUM_VALUE(Ntfs, NextNtfs, MftBitmapWriteBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, UserIndexReads);
|
||||
SUM_VALUE(Ntfs, NextNtfs, UserIndexReadBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, UserIndexWrites);
|
||||
SUM_VALUE(Ntfs, NextNtfs, UserIndexWriteBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, LogFileReads);
|
||||
SUM_VALUE(Ntfs, NextNtfs, LogFileReadBytes);
|
||||
SUM_VALUE(Ntfs, NextNtfs, LogFileWrites);
|
||||
SUM_VALUE(Ntfs, NextNtfs, LogFileWriteBytes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
StatisticsMain(int argc, const TCHAR *argv[])
|
||||
{
|
||||
HANDLE Volume;
|
||||
SYSTEM_INFO SystemInfo;
|
||||
FILESYSTEM_STATISTICS Buffer;
|
||||
PFILESYSTEM_STATISTICS Statistics;
|
||||
DWORD BytesRead, Length, ProcCount;
|
||||
/* +1 because 0 isn't assigned to a filesystem */
|
||||
void (*DumpFct[FILESYSTEM_STATISTICS_TYPE_EXFAT + 1])(PVOID, PVOID) = { NULL, DumpNtfs, DumpFat, DumpExFat };
|
||||
int (*SumFct[FILESYSTEM_STATISTICS_TYPE_EXFAT + 1])(PVOID, PVOID, ULONG, DWORD, DWORD) = { NULL, SumNtfs, SumFat, SumExFat };
|
||||
|
||||
/* We need a volume (letter or GUID) */
|
||||
if (argc < 2)
|
||||
{
|
||||
_ftprintf(stderr, _T("Usage: fsutil fsinfo statistics <volume>\n"));
|
||||
_ftprintf(stderr, _T("\tFor example: fsutil fsinfo statistics c:\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get a handle for the volume */
|
||||
Volume = OpenVolume(argv[1], FALSE);
|
||||
if (Volume == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* And query the statistics status - this call is expected to fail */
|
||||
Statistics = &Buffer;
|
||||
Length = sizeof(Buffer);
|
||||
/* Assume we have a single proc for now */
|
||||
ProcCount = 1;
|
||||
if (DeviceIoControl(Volume, FSCTL_FILESYSTEM_GET_STATISTICS, NULL, 0, Statistics,
|
||||
Length, &BytesRead, NULL) == FALSE)
|
||||
{
|
||||
DWORD Error;
|
||||
|
||||
/* Check we failed because we provided a too small buffer */
|
||||
Error = GetLastError();
|
||||
if (Error == ERROR_MORE_DATA)
|
||||
{
|
||||
/* Get proc count */
|
||||
GetSystemInfo(&SystemInfo);
|
||||
ProcCount = SystemInfo.dwNumberOfProcessors;
|
||||
/* Get the maximum size to allocate: it's the total size (generic + specific) for every proc */
|
||||
Length = Statistics->SizeOfCompleteStructure * ProcCount;
|
||||
|
||||
Statistics = LocalAlloc(LPTR, Length);
|
||||
if (Statistics == NULL)
|
||||
{
|
||||
_ftprintf(stderr, _T("Failed to allocate memory!\n"));
|
||||
CloseHandle(Volume);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reissue the FSCTL, it's supposed to succeed now! */
|
||||
if (DeviceIoControl(Volume, FSCTL_FILESYSTEM_GET_STATISTICS, NULL, 0, Statistics,
|
||||
Length, &BytesRead, NULL) == FALSE)
|
||||
{
|
||||
PrintErrorMessage(GetLastError());
|
||||
LocalFree(Statistics);
|
||||
CloseHandle(Volume);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintErrorMessage(GetLastError());
|
||||
CloseHandle(Volume);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* No need to deal with the volume any longer */
|
||||
CloseHandle(Volume);
|
||||
|
||||
/* We only support FAT, EXFAT and NTFS for now */
|
||||
if (Statistics->FileSystemType > FILESYSTEM_STATISTICS_TYPE_EXFAT || Statistics->FileSystemType < FILESYSTEM_STATISTICS_TYPE_NTFS)
|
||||
{
|
||||
_ftprintf(stderr, _T("Unrecognized file system type: %d\n"), Statistics->FileSystemType);
|
||||
if (Statistics != &Buffer)
|
||||
{
|
||||
LocalFree(Statistics);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sum all the statistics (both generic and specific) from all the processors in the first entry */
|
||||
if (SumFct[Statistics->FileSystemType](Statistics, (PVOID)((ULONG_PTR)Statistics + sizeof(FILESYSTEM_STATISTICS)),
|
||||
Statistics->SizeOfCompleteStructure, ProcCount, BytesRead))
|
||||
{
|
||||
if (Statistics != &Buffer)
|
||||
{
|
||||
LocalFree(Statistics);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* And finally, display the statistics (both generic and specific) */
|
||||
DumpFct[Statistics->FileSystemType](Statistics, (PVOID)((ULONG_PTR)Statistics + sizeof(FILESYSTEM_STATISTICS)));
|
||||
|
||||
/* If we allocated memory, release it */
|
||||
if (Statistics != &Buffer)
|
||||
{
|
||||
LocalFree(Statistics);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
PrintUsage(const TCHAR * Command)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue