1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:         ReactOS FS utility tool
4c2c66affSColin Finck  * FILE:            base/applications/cmdutils/fsinfo.c
5c2c66affSColin Finck  * PURPOSE:         FSutil file systems information
6c2c66affSColin Finck  * PROGRAMMERS:     Pierre Schweitzer <pierre@reactos.org>
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck #include "fsutil.h"
10c2c66affSColin Finck 
11c2c66affSColin Finck /* Add handlers here for subcommands */
12c2c66affSColin Finck static HandlerProc DrivesMain;
13c2c66affSColin Finck static HandlerProc DriveTypeMain;
14c2c66affSColin Finck static HandlerProc VolumeInfoMain;
15c2c66affSColin Finck static HandlerProc NtfsInfoMain;
16c2c66affSColin Finck static HandlerProc StatisticsMain;
17c2c66affSColin Finck static HandlerItem HandlersList[] =
18c2c66affSColin Finck {
19c2c66affSColin Finck     /* Proc, name, help */
20c2c66affSColin Finck     { DrivesMain, _T("drives"), _T("Enumerates the drives") },
21c2c66affSColin Finck     { DriveTypeMain, _T("drivetype"), _T("Provides the type of a drive") },
22c2c66affSColin Finck     { VolumeInfoMain, _T("volumeinfo"), _T("Provides informations about a volume") },
23c2c66affSColin Finck     { NtfsInfoMain, _T("ntfsinfo"), _T("Displays informations about a NTFS volume") },
24c2c66affSColin Finck     { StatisticsMain, _T("statistics"), _T("Displays volume statistics") },
25c2c66affSColin Finck };
26c2c66affSColin Finck 
27c2c66affSColin Finck static int
DrivesMain(int argc,const TCHAR * argv[])28c2c66affSColin Finck DrivesMain(int argc, const TCHAR *argv[])
29c2c66affSColin Finck {
30c2c66affSColin Finck     UINT i;
31c2c66affSColin Finck     DWORD Drives;
32c2c66affSColin Finck 
33c2c66affSColin Finck     /* Get the drives bitmap */
34c2c66affSColin Finck     Drives = GetLogicalDrives();
35c2c66affSColin Finck     if (Drives == 0)
36c2c66affSColin Finck     {
37c2c66affSColin Finck         PrintErrorMessage(GetLastError());
38c2c66affSColin Finck         return 1;
39c2c66affSColin Finck     }
40c2c66affSColin Finck 
41c2c66affSColin Finck     /* And output any found drive */
42c2c66affSColin Finck     _ftprintf(stdout, _T("Drives:"));
43c2c66affSColin Finck     for (i = 0; i < 26; i++)
44c2c66affSColin Finck     {
45c2c66affSColin Finck         if (Drives & (1 << i))
46c2c66affSColin Finck         {
47c2c66affSColin Finck             _ftprintf(stdout, _T(" %c:\\"), 'A' + i);
48c2c66affSColin Finck         }
49c2c66affSColin Finck     }
50c2c66affSColin Finck     _ftprintf(stdout, _T("\n"));
51c2c66affSColin Finck 
52c2c66affSColin Finck     return 0;
53c2c66affSColin Finck }
54c2c66affSColin Finck 
55c2c66affSColin Finck static int
DriveTypeMain(int argc,const TCHAR * argv[])56c2c66affSColin Finck DriveTypeMain(int argc, const TCHAR *argv[])
57c2c66affSColin Finck {
58c2c66affSColin Finck     UINT Type;
59c2c66affSColin Finck 
60c2c66affSColin Finck     /* We need a volume (letter) */
61c2c66affSColin Finck     if (argc < 2)
62c2c66affSColin Finck     {
63c2c66affSColin Finck         _ftprintf(stderr, _T("Usage: fsutil fsinfo drivetype <volume>\n"));
64c2c66affSColin Finck         _ftprintf(stderr, _T("\tFor example: fsutil fsinfo drivetype c:\n"));
65c2c66affSColin Finck         return 1;
66c2c66affSColin Finck     }
67c2c66affSColin Finck 
68c2c66affSColin Finck     /* Get its drive type and make it readable */
69c2c66affSColin Finck     Type = GetDriveType(argv[1]);
70c2c66affSColin Finck     switch (Type)
71c2c66affSColin Finck     {
72c2c66affSColin Finck         case DRIVE_UNKNOWN:
73c2c66affSColin Finck             _ftprintf(stdout, _T("%s - unknown drive type\n"), argv[1]);
74c2c66affSColin Finck             break;
75c2c66affSColin Finck 
76c2c66affSColin Finck         case DRIVE_NO_ROOT_DIR:
77c2c66affSColin Finck             _ftprintf(stdout, _T("%s - not a root directory\n"), argv[1]);
78c2c66affSColin Finck             break;
79c2c66affSColin Finck 
80c2c66affSColin Finck         case DRIVE_REMOVABLE:
81c2c66affSColin Finck             _ftprintf(stdout, _T("%s - removable drive\n"), argv[1]);
82c2c66affSColin Finck             break;
83c2c66affSColin Finck 
84c2c66affSColin Finck         case DRIVE_FIXED:
85c2c66affSColin Finck             _ftprintf(stdout, _T("%s - fixed drive\n"), argv[1]);
86c2c66affSColin Finck             break;
87c2c66affSColin Finck 
88c2c66affSColin Finck         case DRIVE_REMOTE:
89c2c66affSColin Finck             _ftprintf(stdout, _T("%s - remote or network drive\n"), argv[1]);
90c2c66affSColin Finck             break;
91c2c66affSColin Finck 
92c2c66affSColin Finck         case DRIVE_CDROM:
93c2c66affSColin Finck             _ftprintf(stdout, _T("%s - CD-ROM drive\n"), argv[1]);
94c2c66affSColin Finck             break;
95c2c66affSColin Finck 
96c2c66affSColin Finck         case DRIVE_RAMDISK:
97c2c66affSColin Finck             _ftprintf(stdout, _T("%s - RAM disk drive\n"), argv[1]);
98c2c66affSColin Finck             break;
99c2c66affSColin Finck     }
100c2c66affSColin Finck 
101c2c66affSColin Finck     return 0;
102c2c66affSColin Finck }
103c2c66affSColin Finck 
104c2c66affSColin Finck static int
VolumeInfoMain(int argc,const TCHAR * argv[])105c2c66affSColin Finck VolumeInfoMain(int argc, const TCHAR *argv[])
106c2c66affSColin Finck {
107c2c66affSColin Finck     DWORD Serial, MaxComponentLen, Flags;
108c2c66affSColin Finck     TCHAR VolumeName[MAX_PATH + 1], FileSystem[MAX_PATH + 1];
109c2c66affSColin Finck 
110c2c66affSColin Finck #define HANDLE_FLAG(Flags, Flag, Desc) \
111c2c66affSColin Finck     if (Flags & Flag)                  \
112c2c66affSColin Finck         _ftprintf(stdout, Desc)
113c2c66affSColin Finck 
114c2c66affSColin Finck     /* We need a volume (path) */
115c2c66affSColin Finck     if (argc < 2)
116c2c66affSColin Finck     {
117c2c66affSColin Finck         _ftprintf(stderr, _T("Usage: fsutil fsinfo volumeinfo <volume_path>\n"));
118c2c66affSColin Finck         _ftprintf(stderr, _T("\tFor example: fsutil fsinfo volumeinfo c:\\\n"));
119c2c66affSColin Finck         return 1;
120c2c66affSColin Finck     }
121c2c66affSColin Finck 
122c2c66affSColin Finck     /* Gather information */
123c2c66affSColin Finck     if (!GetVolumeInformation(argv[1], VolumeName,  MAX_PATH + 1, &Serial,
124c2c66affSColin Finck                               &MaxComponentLen, &Flags, FileSystem, MAX_PATH + 1))
125c2c66affSColin Finck     {
126c2c66affSColin Finck         PrintErrorMessage(GetLastError());
127c2c66affSColin Finck         return 1;
128c2c66affSColin Finck     }
129c2c66affSColin Finck 
130c2c66affSColin Finck     /* Display general information */
131c2c66affSColin Finck     _ftprintf(stdout, _T("Volume name: %s\n"), VolumeName);
132c2c66affSColin Finck     _ftprintf(stdout, _T("Volume serial number: 0x%x\n"), Serial);
133c2c66affSColin Finck     _ftprintf(stdout, _T("Maximum component length: %u\n"), MaxComponentLen);
134c2c66affSColin Finck     _ftprintf(stdout, _T("File system name: %s\n"), FileSystem);
135c2c66affSColin Finck 
136c2c66affSColin Finck     /* Display specific flags */
137c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_CASE_SENSITIVE_SEARCH, _T("Supports case-sensitive file names\n"));
138c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_CASE_PRESERVED_NAMES, _T("Supports preserved case of file names\n"));
139c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_UNICODE_ON_DISK, _T("Supports unicode file names\n"));
140c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_PERSISTENT_ACLS, _T("Preserves and applies ACLs\n"));
141c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_FILE_COMPRESSION, _T("Supports compression per file\n"));
142c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_VOLUME_QUOTAS, _T("Supports disk quotas\n"));
143c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_SPARSE_FILES, _T("Supports sparse files\n"));
144c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_REPARSE_POINTS, _T("Supports reparse points\n"));
145c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_VOLUME_IS_COMPRESSED, _T("Is a compressed volume\n"));
146c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_OBJECT_IDS, _T("Supports object identifiers\n"));
147c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_ENCRYPTION, _T("Supports the Encrypted File System (EFS)\n"));
148c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_NAMED_STREAMS, _T("Supports named streams\n"));
149c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_READ_ONLY_VOLUME, _T("Is a read-only volume\n"));
150c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SEQUENTIAL_WRITE_ONCE, _T("Supports a single sequential write\n"));
151c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_TRANSACTIONS, _T("Supports transactions\n"));
152c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_HARD_LINKS, _T("Supports hard links\n"));
153c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_EXTENDED_ATTRIBUTES, _T("Supports extended attributes\n"));
154c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_OPEN_BY_FILE_ID, _T("Supports opening files per file identifier\n"));
155c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_SUPPORTS_USN_JOURNAL, _T("Supports Update Sequence Number (USN) journals\n"));
156c2c66affSColin Finck     HANDLE_FLAG(Flags, FILE_DAX_VOLUME, _T("Is a direct access volume\n"));
157c2c66affSColin Finck 
158c2c66affSColin Finck #undef HANDLE_FLAGS
159c2c66affSColin Finck 
160c2c66affSColin Finck     return 0;
161c2c66affSColin Finck }
162c2c66affSColin Finck 
163c2c66affSColin Finck static int
NtfsInfoMain(int argc,const TCHAR * argv[])164c2c66affSColin Finck NtfsInfoMain(int argc, const TCHAR *argv[])
165c2c66affSColin Finck {
166c2c66affSColin Finck     HANDLE Volume;
167c2c66affSColin Finck     DWORD BytesRead;
168c2c66affSColin Finck     struct
169c2c66affSColin Finck     {
170c2c66affSColin Finck         NTFS_VOLUME_DATA_BUFFER;
171c2c66affSColin Finck         NTFS_EXTENDED_VOLUME_DATA;
172c2c66affSColin Finck     } Data;
173c2c66affSColin Finck 
174c2c66affSColin Finck     /* We need a volume (letter or GUID) */
175c2c66affSColin Finck     if (argc < 2)
176c2c66affSColin Finck     {
177c2c66affSColin Finck         _ftprintf(stderr, _T("Usage: fsutil fsinfo ntfsinfo <volume>\n"));
178c2c66affSColin Finck         _ftprintf(stderr, _T("\tFor example: fsutil fsinfo ntfsinfo c:\n"));
179c2c66affSColin Finck         return 1;
180c2c66affSColin Finck     }
181c2c66affSColin Finck 
182c2c66affSColin Finck     /* Get a handle for the volume */
183c2c66affSColin Finck     Volume = OpenVolume(argv[1], FALSE, TRUE);
184c2c66affSColin Finck     if (Volume == INVALID_HANDLE_VALUE)
185c2c66affSColin Finck     {
186c2c66affSColin Finck         return 1;
187c2c66affSColin Finck     }
188c2c66affSColin Finck 
189c2c66affSColin Finck     /* And query the NTFS data */
190c2c66affSColin Finck     if (DeviceIoControl(Volume, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &Data,
191c2c66affSColin Finck                         sizeof(Data), &BytesRead, NULL) == FALSE)
192c2c66affSColin Finck     {
193c2c66affSColin Finck         PrintErrorMessage(GetLastError());
194c2c66affSColin Finck         CloseHandle(Volume);
195c2c66affSColin Finck         return 1;
196c2c66affSColin Finck     }
197c2c66affSColin Finck 
198c2c66affSColin Finck     /* We no longer need the volume */
199c2c66affSColin Finck     CloseHandle(Volume);
200c2c66affSColin Finck 
201c2c66affSColin Finck     /* Dump data */
202c2c66affSColin Finck     _ftprintf(stdout, _T("NTFS volume serial number:\t\t0x%0.16I64x\n"), Data.VolumeSerialNumber.QuadPart);
203c2c66affSColin Finck     /* Only print version if extended structure was returned */
204c2c66affSColin Finck     if (BytesRead > sizeof(NTFS_VOLUME_DATA_BUFFER))
205c2c66affSColin Finck     {
206c2c66affSColin Finck         _ftprintf(stdout, _T("Version:\t\t\t\t%u.%u\n"), Data.MajorVersion, Data.MinorVersion);
207c2c66affSColin Finck     }
208c2c66affSColin Finck     _ftprintf(stdout, _T("Number of sectors:\t\t\t0x%0.16I64x\n"), Data.NumberSectors.QuadPart);
209c2c66affSColin Finck     _ftprintf(stdout, _T("Total number of clusters:\t\t0x%0.16I64x\n"), Data.TotalClusters.QuadPart);
210c2c66affSColin Finck     _ftprintf(stdout, _T("Free clusters:\t\t\t\t0x%0.16I64x\n"), Data.FreeClusters.QuadPart);
211c2c66affSColin Finck     _ftprintf(stdout, _T("Total number of reserved clusters:\t0x%0.16I64x\n"), Data.TotalReserved.QuadPart);
212c2c66affSColin Finck     _ftprintf(stdout, _T("Bytes per sector:\t\t\t%d\n"), Data.BytesPerSector);
213c2c66affSColin Finck     _ftprintf(stdout, _T("Bytes per cluster:\t\t\t%d\n"), Data.BytesPerCluster);
214c2c66affSColin Finck     _ftprintf(stdout, _T("Bytes per file record segment:\t\t%d\n"), Data.BytesPerFileRecordSegment);
215c2c66affSColin Finck     _ftprintf(stdout, _T("Clusters per file record segment:\t%d\n"), Data.ClustersPerFileRecordSegment);
216c2c66affSColin Finck     _ftprintf(stdout, _T("MFT valid data length:\t\t\t0x%0.16I64x\n"), Data.MftValidDataLength.QuadPart);
217c2c66affSColin Finck     _ftprintf(stdout, _T("MFT start LCN:\t\t\t\t0x%0.16I64x\n"), Data.MftStartLcn.QuadPart);
218c2c66affSColin Finck     _ftprintf(stdout, _T("MFT2 start LCN:\t\t\t\t0x%0.16I64x\n"), Data.Mft2StartLcn.QuadPart);
219c2c66affSColin Finck     _ftprintf(stdout, _T("MFT zone start:\t\t\t\t0x%0.16I64x\n"), Data.MftZoneStart.QuadPart);
220c2c66affSColin Finck     _ftprintf(stdout, _T("MFT zone end:\t\t\t\t0x%0.16I64x\n"), Data.MftZoneEnd.QuadPart);
221c2c66affSColin Finck 
222c2c66affSColin Finck     return 0;
223c2c66affSColin Finck }
224c2c66affSColin Finck 
225c2c66affSColin Finck #define DUMP_VALUE(stats, value) fprintf(stdout, "%s: %lu\n", #value, stats->value)
226c2c66affSColin Finck 
227c2c66affSColin Finck static void
DumpBase(PFILESYSTEM_STATISTICS Base,TCHAR * Name)228c2c66affSColin Finck DumpBase(PFILESYSTEM_STATISTICS Base, TCHAR * Name)
229c2c66affSColin Finck {
230c2c66affSColin Finck     /* Print FS name */
231c2c66affSColin Finck     _ftprintf(stdout, _T("File system type: %s\n\n"), Name);
232c2c66affSColin Finck 
233c2c66affSColin Finck     /* And then, dump any base stat */
234c2c66affSColin Finck     DUMP_VALUE(Base, UserFileReads);
235c2c66affSColin Finck     DUMP_VALUE(Base, UserFileReadBytes);
236c2c66affSColin Finck     DUMP_VALUE(Base, UserDiskReads);
237c2c66affSColin Finck     DUMP_VALUE(Base, UserFileWrites);
238c2c66affSColin Finck     DUMP_VALUE(Base, UserFileWriteBytes);
239c2c66affSColin Finck     DUMP_VALUE(Base, UserDiskWrites);
240c2c66affSColin Finck     DUMP_VALUE(Base, MetaDataReads);
241c2c66affSColin Finck     DUMP_VALUE(Base, MetaDataReadBytes);
242c2c66affSColin Finck     DUMP_VALUE(Base, MetaDataDiskReads);
243c2c66affSColin Finck     DUMP_VALUE(Base, MetaDataWrites);
244c2c66affSColin Finck     DUMP_VALUE(Base, MetaDataWriteBytes);
245c2c66affSColin Finck     DUMP_VALUE(Base, MetaDataDiskWrites);
246c2c66affSColin Finck 
247c2c66affSColin Finck     _ftprintf(stdout, _T("\n"));
248c2c66affSColin Finck }
249c2c66affSColin Finck 
250c2c66affSColin Finck static void
DumpExFat(PVOID Statistics,PVOID Specific)251c2c66affSColin Finck DumpExFat(PVOID Statistics, PVOID Specific)
252c2c66affSColin Finck {
253c2c66affSColin Finck     PEXFAT_STATISTICS ExFat;
254c2c66affSColin Finck     PFILESYSTEM_STATISTICS Base;
255c2c66affSColin Finck 
256c2c66affSColin Finck     Base = Statistics;
257c2c66affSColin Finck     ExFat = Specific;
258c2c66affSColin Finck 
259c2c66affSColin Finck     /* First, display the generic stats */
260c2c66affSColin Finck     DumpBase(Base, _T("EXFAT"));
261c2c66affSColin Finck 
262c2c66affSColin Finck     /* Then, display the EXFAT specific ones */
263c2c66affSColin Finck     DUMP_VALUE(ExFat, CreateHits);
264c2c66affSColin Finck     DUMP_VALUE(ExFat, SuccessfulCreates);
265c2c66affSColin Finck     DUMP_VALUE(ExFat, FailedCreates);
266c2c66affSColin Finck     DUMP_VALUE(ExFat, NonCachedReads);
267c2c66affSColin Finck     DUMP_VALUE(ExFat, NonCachedReadBytes);
268c2c66affSColin Finck     DUMP_VALUE(ExFat, NonCachedWrites);
269c2c66affSColin Finck     DUMP_VALUE(ExFat, NonCachedWriteBytes);
270c2c66affSColin Finck     DUMP_VALUE(ExFat, NonCachedDiskReads);
271c2c66affSColin Finck     DUMP_VALUE(ExFat, NonCachedDiskWrites);
272c2c66affSColin Finck }
273c2c66affSColin Finck 
274c2c66affSColin Finck static void
DumpFat(PVOID Statistics,PVOID Specific)275c2c66affSColin Finck DumpFat(PVOID Statistics, PVOID Specific)
276c2c66affSColin Finck {
277c2c66affSColin Finck     PFAT_STATISTICS Fat;
278c2c66affSColin Finck     PFILESYSTEM_STATISTICS Base;
279c2c66affSColin Finck 
280c2c66affSColin Finck     Base = Statistics;
281c2c66affSColin Finck     Fat = Specific;
282c2c66affSColin Finck 
283c2c66affSColin Finck     /* First, display the generic stats */
284c2c66affSColin Finck     DumpBase(Base, _T("FAT"));
285c2c66affSColin Finck 
286c2c66affSColin Finck     /* Then, display the FAT specific ones */
287c2c66affSColin Finck     DUMP_VALUE(Fat, CreateHits);
288c2c66affSColin Finck     DUMP_VALUE(Fat, SuccessfulCreates);
289c2c66affSColin Finck     DUMP_VALUE(Fat, FailedCreates);
290c2c66affSColin Finck     DUMP_VALUE(Fat, NonCachedReads);
291c2c66affSColin Finck     DUMP_VALUE(Fat, NonCachedReadBytes);
292c2c66affSColin Finck     DUMP_VALUE(Fat, NonCachedWrites);
293c2c66affSColin Finck     DUMP_VALUE(Fat, NonCachedWriteBytes);
294c2c66affSColin Finck     DUMP_VALUE(Fat, NonCachedDiskReads);
295c2c66affSColin Finck     DUMP_VALUE(Fat, NonCachedDiskWrites);
296c2c66affSColin Finck }
297c2c66affSColin Finck 
298c2c66affSColin Finck static void
DumpNtfs(PVOID Statistics,PVOID Specific)299c2c66affSColin Finck DumpNtfs(PVOID Statistics, PVOID Specific)
300c2c66affSColin Finck {
301c2c66affSColin Finck     PNTFS_STATISTICS Ntfs;
302c2c66affSColin Finck     PFILESYSTEM_STATISTICS Base;
303c2c66affSColin Finck 
304c2c66affSColin Finck     Base = Statistics;
305c2c66affSColin Finck     Ntfs = Specific;
306c2c66affSColin Finck 
307c2c66affSColin Finck     /* First, display the generic stats */
308c2c66affSColin Finck     DumpBase(Base, _T("NTFS"));
309c2c66affSColin Finck 
310c2c66affSColin Finck     /* Then, display the NTFS specific ones */
311c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftReads);
312c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftReadBytes);
313c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftWrites);
314c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftWriteBytes);
315c2c66affSColin Finck     DUMP_VALUE(Ntfs, Mft2Writes);
316c2c66affSColin Finck     DUMP_VALUE(Ntfs, Mft2WriteBytes);
317c2c66affSColin Finck     DUMP_VALUE(Ntfs, RootIndexReads);
318c2c66affSColin Finck     DUMP_VALUE(Ntfs, RootIndexReadBytes);
319c2c66affSColin Finck     DUMP_VALUE(Ntfs, RootIndexWrites);
320c2c66affSColin Finck     DUMP_VALUE(Ntfs, RootIndexWriteBytes);
321c2c66affSColin Finck     DUMP_VALUE(Ntfs, BitmapReads);
322c2c66affSColin Finck     DUMP_VALUE(Ntfs, BitmapReadBytes);
323c2c66affSColin Finck     DUMP_VALUE(Ntfs, BitmapWrites);
324c2c66affSColin Finck     DUMP_VALUE(Ntfs, BitmapWriteBytes);
325c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftBitmapReads);
326c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftBitmapReadBytes);
327c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftBitmapWrites);
328c2c66affSColin Finck     DUMP_VALUE(Ntfs, MftBitmapWriteBytes);
329c2c66affSColin Finck     DUMP_VALUE(Ntfs, UserIndexReads);
330c2c66affSColin Finck     DUMP_VALUE(Ntfs, UserIndexReadBytes);
331c2c66affSColin Finck     DUMP_VALUE(Ntfs, UserIndexWrites);
332c2c66affSColin Finck     DUMP_VALUE(Ntfs, UserIndexWriteBytes);
333c2c66affSColin Finck     DUMP_VALUE(Ntfs, LogFileReads);
334c2c66affSColin Finck     DUMP_VALUE(Ntfs, LogFileReadBytes);
335c2c66affSColin Finck     DUMP_VALUE(Ntfs, LogFileWrites);
336c2c66affSColin Finck     DUMP_VALUE(Ntfs, LogFileWriteBytes);
337c2c66affSColin Finck }
338c2c66affSColin Finck 
339c2c66affSColin Finck #define GET_NEXT(stats, length, iter, type) (type)((ULONG_PTR)stats + (length * iter))
340c2c66affSColin Finck #define SUM_VALUE(stats, new, value) stats->value += new->value
341c2c66affSColin Finck 
342*8649ed90SHervé Poussineau static inline int
ValidateSizes(ULONG Length,DWORD ProcCount,DWORD BytesRead,DWORD SpecificSize)343c2c66affSColin Finck ValidateSizes(ULONG Length, DWORD ProcCount, DWORD BytesRead, DWORD SpecificSize)
344c2c66affSColin Finck {
345c2c66affSColin Finck     /* Check whether we could read our base length for every processor */
346c2c66affSColin Finck     if (Length * ProcCount > BytesRead)
347c2c66affSColin Finck     {
348c2c66affSColin Finck         _ftprintf(stderr, _T("Only performed a partial read: %lu (expected: %lu)\n"), BytesRead, Length * ProcCount);
349c2c66affSColin Finck         return 1;
350c2c66affSColin Finck     }
351c2c66affSColin Finck 
352c2c66affSColin Finck     /* Check whether this covers a specific entry and a generic entry for every processor */
353c2c66affSColin Finck     if ((sizeof(FILESYSTEM_STATISTICS) + SpecificSize) * ProcCount > BytesRead)
354c2c66affSColin Finck     {
35558588b76STimo Kreuzer         _ftprintf(stderr, _T("Only performed a partial read: %lu (expected: %Iu)\n"), BytesRead, (sizeof(FILESYSTEM_STATISTICS) + SpecificSize));
356c2c66affSColin Finck         return 1;
357c2c66affSColin Finck     }
358c2c66affSColin Finck 
359c2c66affSColin Finck     return 0;
360c2c66affSColin Finck }
361c2c66affSColin Finck 
362*8649ed90SHervé Poussineau static inline void
SumBase(PFILESYSTEM_STATISTICS Base,PFILESYSTEM_STATISTICS NextBase)363c2c66affSColin Finck SumBase(PFILESYSTEM_STATISTICS Base, PFILESYSTEM_STATISTICS NextBase)
364c2c66affSColin Finck {
365c2c66affSColin Finck     /* Sum any entry in the generic structures */
366c2c66affSColin Finck     SUM_VALUE(Base, NextBase, UserFileReads);
367c2c66affSColin Finck     SUM_VALUE(Base, NextBase, UserFileReadBytes);
368c2c66affSColin Finck     SUM_VALUE(Base, NextBase, UserDiskReads);
369c2c66affSColin Finck     SUM_VALUE(Base, NextBase, UserFileWrites);
370c2c66affSColin Finck     SUM_VALUE(Base, NextBase, UserFileWriteBytes);
371c2c66affSColin Finck     SUM_VALUE(Base, NextBase, UserDiskWrites);
372c2c66affSColin Finck     SUM_VALUE(Base, NextBase, MetaDataReads);
373c2c66affSColin Finck     SUM_VALUE(Base, NextBase, MetaDataReadBytes);
374c2c66affSColin Finck     SUM_VALUE(Base, NextBase, MetaDataDiskReads);
375c2c66affSColin Finck     SUM_VALUE(Base, NextBase, MetaDataWrites);
376c2c66affSColin Finck     SUM_VALUE(Base, NextBase, MetaDataWriteBytes);
377c2c66affSColin Finck     SUM_VALUE(Base, NextBase, MetaDataDiskWrites);
378c2c66affSColin Finck }
379c2c66affSColin Finck 
380c2c66affSColin Finck static int
SumExFat(PVOID Statistics,PVOID Specific,ULONG Length,DWORD ProcCount,DWORD BytesRead)381c2c66affSColin Finck SumExFat(PVOID Statistics, PVOID Specific, ULONG Length, DWORD ProcCount, DWORD BytesRead)
382c2c66affSColin Finck {
383c2c66affSColin Finck     DWORD i;
384c2c66affSColin Finck     PEXFAT_STATISTICS ExFat;
385c2c66affSColin Finck     PFILESYSTEM_STATISTICS Base;
386c2c66affSColin Finck 
387c2c66affSColin Finck     /* First, validate we won't read beyond allocation */
388c2c66affSColin Finck     if (ValidateSizes(Length, ProcCount, BytesRead, sizeof(EXFAT_STATISTICS)))
389c2c66affSColin Finck     {
390c2c66affSColin Finck         return 1;
391c2c66affSColin Finck     }
392c2c66affSColin Finck 
393c2c66affSColin Finck     Base = Statistics;
394c2c66affSColin Finck     ExFat = Specific;
395c2c66affSColin Finck 
396c2c66affSColin Finck     /* And for every processor, sum every relevant value in first entry */
397c2c66affSColin Finck     for (i = 1; i < ProcCount; ++i)
398c2c66affSColin Finck     {
399c2c66affSColin Finck         PEXFAT_STATISTICS NextExFat;
400c2c66affSColin Finck         PFILESYSTEM_STATISTICS NextBase;
401c2c66affSColin Finck 
402c2c66affSColin Finck         NextBase = GET_NEXT(Base, Length, i, PFILESYSTEM_STATISTICS);
403c2c66affSColin Finck         NextExFat = GET_NEXT(ExFat, Length, i, PEXFAT_STATISTICS);
404c2c66affSColin Finck 
405c2c66affSColin Finck         /* Generic first */
406c2c66affSColin Finck         SumBase(Base, NextBase);
407c2c66affSColin Finck         /* Specific then */
408c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, CreateHits);
409c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, SuccessfulCreates);
410c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, FailedCreates);
411c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, NonCachedReads);
412c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, NonCachedReadBytes);
413c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, NonCachedWrites);
414c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, NonCachedWriteBytes);
415c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, NonCachedDiskReads);
416c2c66affSColin Finck         SUM_VALUE(ExFat, NextExFat, NonCachedDiskWrites);
417c2c66affSColin Finck     }
418c2c66affSColin Finck 
419c2c66affSColin Finck     return 0;
420c2c66affSColin Finck }
421c2c66affSColin Finck 
422c2c66affSColin Finck static int
SumFat(PVOID Statistics,PVOID Specific,ULONG Length,DWORD ProcCount,DWORD BytesRead)423c2c66affSColin Finck SumFat(PVOID Statistics, PVOID Specific, ULONG Length, DWORD ProcCount, DWORD BytesRead)
424c2c66affSColin Finck {
425c2c66affSColin Finck     DWORD i;
426c2c66affSColin Finck     PFAT_STATISTICS Fat;
427c2c66affSColin Finck     PFILESYSTEM_STATISTICS Base;
428c2c66affSColin Finck 
429c2c66affSColin Finck     /* First, validate we won't read beyond allocation */
430c2c66affSColin Finck     if (ValidateSizes(Length, ProcCount, BytesRead, sizeof(FAT_STATISTICS)))
431c2c66affSColin Finck     {
432c2c66affSColin Finck         return 1;
433c2c66affSColin Finck     }
434c2c66affSColin Finck 
435c2c66affSColin Finck     Base = Statistics;
436c2c66affSColin Finck     Fat = Specific;
437c2c66affSColin Finck 
438c2c66affSColin Finck     /* And for every processor, sum every relevant value in first entry */
439c2c66affSColin Finck     for (i = 1; i < ProcCount; ++i)
440c2c66affSColin Finck     {
441c2c66affSColin Finck         PFAT_STATISTICS NextFat;
442c2c66affSColin Finck         PFILESYSTEM_STATISTICS NextBase;
443c2c66affSColin Finck 
444c2c66affSColin Finck         NextBase = GET_NEXT(Base, Length, i, PFILESYSTEM_STATISTICS);
445c2c66affSColin Finck         NextFat = GET_NEXT(Fat, Length, i, PFAT_STATISTICS);
446c2c66affSColin Finck 
447c2c66affSColin Finck         /* Generic first */
448c2c66affSColin Finck         SumBase(Base, NextBase);
449c2c66affSColin Finck         /* Specific then */
450c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, CreateHits);
451c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, SuccessfulCreates);
452c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, FailedCreates);
453c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, NonCachedReads);
454c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, NonCachedReadBytes);
455c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, NonCachedWrites);
456c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, NonCachedWriteBytes);
457c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, NonCachedDiskReads);
458c2c66affSColin Finck         SUM_VALUE(Fat, NextFat, NonCachedDiskWrites);
459c2c66affSColin Finck     }
460c2c66affSColin Finck 
461c2c66affSColin Finck     return 0;
462c2c66affSColin Finck }
463c2c66affSColin Finck 
464c2c66affSColin Finck static int
SumNtfs(PVOID Statistics,PVOID Specific,ULONG Length,DWORD ProcCount,DWORD BytesRead)465c2c66affSColin Finck SumNtfs(PVOID Statistics, PVOID Specific, ULONG Length, DWORD ProcCount, DWORD BytesRead)
466c2c66affSColin Finck {
467c2c66affSColin Finck     DWORD i;
468c2c66affSColin Finck     PNTFS_STATISTICS Ntfs;
469c2c66affSColin Finck     PFILESYSTEM_STATISTICS Base;
470c2c66affSColin Finck 
471c2c66affSColin Finck     /* First, validate we won't read beyond allocation */
472c2c66affSColin Finck     if (ValidateSizes(Length, ProcCount, BytesRead, sizeof(NTFS_STATISTICS)))
473c2c66affSColin Finck     {
474c2c66affSColin Finck         return 1;
475c2c66affSColin Finck     }
476c2c66affSColin Finck 
477c2c66affSColin Finck     Base = Statistics;
478c2c66affSColin Finck     Ntfs = Specific;
479c2c66affSColin Finck 
480c2c66affSColin Finck     /* And for every processor, sum every relevant value in first entry */
481c2c66affSColin Finck     for (i = 1; i < ProcCount; ++i)
482c2c66affSColin Finck     {
483c2c66affSColin Finck         PNTFS_STATISTICS NextNtfs;
484c2c66affSColin Finck         PFILESYSTEM_STATISTICS NextBase;
485c2c66affSColin Finck 
486c2c66affSColin Finck         NextBase = GET_NEXT(Base, Length, i, PFILESYSTEM_STATISTICS);
487c2c66affSColin Finck         NextNtfs = GET_NEXT(Ntfs, Length, i, PNTFS_STATISTICS);
488c2c66affSColin Finck 
489c2c66affSColin Finck         /* Generic first */
490c2c66affSColin Finck         SumBase(Base, NextBase);
491c2c66affSColin Finck         /* Specific then */
492c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftReads);
493c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftReadBytes);
494c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftWrites);
495c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftWriteBytes);
496c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, Mft2Writes);
497c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, Mft2WriteBytes);
498c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, RootIndexReads);
499c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, RootIndexReadBytes);
500c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, RootIndexWrites);
501c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, RootIndexWriteBytes);
502c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, BitmapReads);
503c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, BitmapReadBytes);
504c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, BitmapWrites);
505c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, BitmapWriteBytes);
506c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftBitmapReads);
507c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftBitmapReadBytes);
508c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftBitmapWrites);
509c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, MftBitmapWriteBytes);
510c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, UserIndexReads);
511c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, UserIndexReadBytes);
512c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, UserIndexWrites);
513c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, UserIndexWriteBytes);
514c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, LogFileReads);
515c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, LogFileReadBytes);
516c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, LogFileWrites);
517c2c66affSColin Finck         SUM_VALUE(Ntfs, NextNtfs, LogFileWriteBytes);
518c2c66affSColin Finck     }
519c2c66affSColin Finck 
520c2c66affSColin Finck     return 0;
521c2c66affSColin Finck }
522c2c66affSColin Finck 
523c2c66affSColin Finck static int
StatisticsMain(int argc,const TCHAR * argv[])524c2c66affSColin Finck StatisticsMain(int argc, const TCHAR *argv[])
525c2c66affSColin Finck {
526c2c66affSColin Finck     HANDLE Volume;
527c2c66affSColin Finck     SYSTEM_INFO SystemInfo;
528c2c66affSColin Finck     FILESYSTEM_STATISTICS Buffer;
529c2c66affSColin Finck     PFILESYSTEM_STATISTICS Statistics;
530c2c66affSColin Finck     DWORD BytesRead, Length, ProcCount;
531c2c66affSColin Finck     /* +1 because 0 isn't assigned to a filesystem */
532c2c66affSColin Finck     void (*DumpFct[FILESYSTEM_STATISTICS_TYPE_EXFAT + 1])(PVOID, PVOID) = { NULL, DumpNtfs, DumpFat, DumpExFat };
533c2c66affSColin Finck     int (*SumFct[FILESYSTEM_STATISTICS_TYPE_EXFAT + 1])(PVOID, PVOID, ULONG, DWORD, DWORD) = { NULL, SumNtfs, SumFat, SumExFat };
534c2c66affSColin Finck 
535c2c66affSColin Finck     /* We need a volume (letter or GUID) */
536c2c66affSColin Finck     if (argc < 2)
537c2c66affSColin Finck     {
538c2c66affSColin Finck         _ftprintf(stderr, _T("Usage: fsutil fsinfo statistics <volume>\n"));
539c2c66affSColin Finck         _ftprintf(stderr, _T("\tFor example: fsutil fsinfo statistics c:\n"));
540c2c66affSColin Finck         return 1;
541c2c66affSColin Finck     }
542c2c66affSColin Finck 
543c2c66affSColin Finck     /* Get a handle for the volume */
544c2c66affSColin Finck     Volume = OpenVolume(argv[1], FALSE, FALSE);
545c2c66affSColin Finck     if (Volume == INVALID_HANDLE_VALUE)
546c2c66affSColin Finck     {
547c2c66affSColin Finck         return 1;
548c2c66affSColin Finck     }
549c2c66affSColin Finck 
550c2c66affSColin Finck     /* And query the statistics status - this call is expected to fail */
551c2c66affSColin Finck     Statistics = &Buffer;
552c2c66affSColin Finck     Length = sizeof(Buffer);
553c2c66affSColin Finck     /* Assume we have a single proc for now */
554c2c66affSColin Finck     ProcCount = 1;
555c2c66affSColin Finck     if (DeviceIoControl(Volume, FSCTL_FILESYSTEM_GET_STATISTICS, NULL, 0, Statistics,
556c2c66affSColin Finck                         Length, &BytesRead, NULL) == FALSE)
557c2c66affSColin Finck     {
558c2c66affSColin Finck         DWORD Error;
559c2c66affSColin Finck 
560c2c66affSColin Finck         /* Check we failed because we provided a too small buffer */
561c2c66affSColin Finck         Error = GetLastError();
562c2c66affSColin Finck         if (Error == ERROR_MORE_DATA)
563c2c66affSColin Finck         {
564c2c66affSColin Finck             /* Get proc count */
565c2c66affSColin Finck             GetSystemInfo(&SystemInfo);
566c2c66affSColin Finck             ProcCount = SystemInfo.dwNumberOfProcessors;
567c2c66affSColin Finck             /* Get the maximum size to allocate: it's the total size (generic + specific) for every proc */
568c2c66affSColin Finck             Length = Statistics->SizeOfCompleteStructure * ProcCount;
569c2c66affSColin Finck 
570c2c66affSColin Finck             Statistics = LocalAlloc(LPTR, Length);
571c2c66affSColin Finck             if (Statistics == NULL)
572c2c66affSColin Finck             {
573c2c66affSColin Finck                 _ftprintf(stderr, _T("Failed to allocate memory!\n"));
574c2c66affSColin Finck                 CloseHandle(Volume);
575c2c66affSColin Finck                 return 1;
576c2c66affSColin Finck             }
577c2c66affSColin Finck 
578c2c66affSColin Finck             /* Reissue the FSCTL, it's supposed to succeed now! */
579c2c66affSColin Finck             if (DeviceIoControl(Volume, FSCTL_FILESYSTEM_GET_STATISTICS, NULL, 0, Statistics,
580c2c66affSColin Finck                                 Length, &BytesRead, NULL) == FALSE)
581c2c66affSColin Finck             {
582c2c66affSColin Finck                 PrintErrorMessage(GetLastError());
583c2c66affSColin Finck                 LocalFree(Statistics);
584c2c66affSColin Finck                 CloseHandle(Volume);
585c2c66affSColin Finck                 return 1;
586c2c66affSColin Finck             }
587c2c66affSColin Finck         }
588c2c66affSColin Finck         else
589c2c66affSColin Finck         {
590c2c66affSColin Finck             PrintErrorMessage(Error);
591c2c66affSColin Finck             CloseHandle(Volume);
592c2c66affSColin Finck             return 1;
593c2c66affSColin Finck         }
594c2c66affSColin Finck     }
595c2c66affSColin Finck 
596c2c66affSColin Finck     /* No need to deal with the volume any longer */
597c2c66affSColin Finck     CloseHandle(Volume);
598c2c66affSColin Finck 
599c2c66affSColin Finck     /* We only support FAT, EXFAT and NTFS for now */
600c2c66affSColin Finck     if (Statistics->FileSystemType > FILESYSTEM_STATISTICS_TYPE_EXFAT || Statistics->FileSystemType < FILESYSTEM_STATISTICS_TYPE_NTFS)
601c2c66affSColin Finck     {
602c2c66affSColin Finck         _ftprintf(stderr, _T("Unrecognized file system type: %d\n"), Statistics->FileSystemType);
603c2c66affSColin Finck         if (Statistics != &Buffer)
604c2c66affSColin Finck         {
605c2c66affSColin Finck             LocalFree(Statistics);
606c2c66affSColin Finck         }
607c2c66affSColin Finck 
608c2c66affSColin Finck         return 1;
609c2c66affSColin Finck     }
610c2c66affSColin Finck 
611c2c66affSColin Finck     /* Sum all the statistics (both generic and specific) from all the processors in the first entry */
612c2c66affSColin Finck     if (SumFct[Statistics->FileSystemType](Statistics, (PVOID)((ULONG_PTR)Statistics + sizeof(FILESYSTEM_STATISTICS)),
613c2c66affSColin Finck                                            Statistics->SizeOfCompleteStructure, ProcCount, BytesRead))
614c2c66affSColin Finck     {
615c2c66affSColin Finck         if (Statistics != &Buffer)
616c2c66affSColin Finck         {
617c2c66affSColin Finck             LocalFree(Statistics);
618c2c66affSColin Finck         }
619c2c66affSColin Finck 
620c2c66affSColin Finck         return 1;
621c2c66affSColin Finck     }
622c2c66affSColin Finck 
623c2c66affSColin Finck     /* And finally, display the statistics (both generic and specific) */
624c2c66affSColin Finck     DumpFct[Statistics->FileSystemType](Statistics, (PVOID)((ULONG_PTR)Statistics + sizeof(FILESYSTEM_STATISTICS)));
625c2c66affSColin Finck 
626c2c66affSColin Finck     /* If we allocated memory, release it */
627c2c66affSColin Finck     if (Statistics != &Buffer)
628c2c66affSColin Finck     {
629c2c66affSColin Finck         LocalFree(Statistics);
630c2c66affSColin Finck     }
631c2c66affSColin Finck 
632c2c66affSColin Finck     return 0;
633c2c66affSColin Finck }
634c2c66affSColin Finck 
635c2c66affSColin Finck static void
PrintUsage(const TCHAR * Command)636c2c66affSColin Finck PrintUsage(const TCHAR * Command)
637c2c66affSColin Finck {
638c2c66affSColin Finck     PrintDefaultUsage(_T(" FSINFO "), Command, (HandlerItem *)&HandlersList,
639c2c66affSColin Finck                       (sizeof(HandlersList) / sizeof(HandlersList[0])));
640c2c66affSColin Finck }
641c2c66affSColin Finck 
642c2c66affSColin Finck int
FsInfoMain(int argc,const TCHAR * argv[])643c2c66affSColin Finck FsInfoMain(int argc, const TCHAR *argv[])
644c2c66affSColin Finck {
645c2c66affSColin Finck     return FindHandler(argc, argv, (HandlerItem *)&HandlersList,
646c2c66affSColin Finck                        (sizeof(HandlersList) / sizeof(HandlersList[0])),
647c2c66affSColin Finck                        PrintUsage);
648c2c66affSColin Finck }
649