1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS FS utility tool
4  * FILE:            base/applications/cmdutils/volume.c
5  * PURPOSE:         FSutil volumes management
6  * PROGRAMMERS:     Pierre Schweitzer <pierre@reactos.org>
7  */
8 
9 #include "fsutil.h"
10 
11 /* Add handlers here for subcommands */
12 static HandlerProc DismountMain;
13 static HandlerProc DiskFreeMain;
14 static HandlerItem HandlersList[] =
15 {
16     /* Proc, name, help */
17     { DismountMain, _T("dismount"), _T("Dismounts a volume") },
18     { DiskFreeMain, _T("diskfree"), _T("Prints free space on a volume") },
19 };
20 
21 static int
22 LockOrUnlockVolume(HANDLE Volume, BOOLEAN Lock)
23 {
24     DWORD Operation;
25     ULONG BytesRead;
26 
27     Operation = (Lock ? FSCTL_LOCK_VOLUME : FSCTL_UNLOCK_VOLUME);
28     if (DeviceIoControl(Volume, Operation, NULL, 0, NULL, 0,
29                         &BytesRead, NULL) == FALSE)
30     {
31         PrintErrorMessage(GetLastError());
32         return 1;
33     }
34 
35     return 0;
36 }
37 
38 static int
39 DismountMain(int argc, const TCHAR *argv[])
40 {
41     HANDLE Volume;
42     ULONG BytesRead;
43 
44     /* We need a volume (letter or GUID) */
45     if (argc < 2)
46     {
47         _ftprintf(stderr, _T("Usage: fsutil volume dismount <volume>\n"));
48         _ftprintf(stderr, _T("\tFor example: fsutil volume dismount d:\n"));
49         return 1;
50     }
51 
52     /* Get a handle for the volume */
53     Volume = OpenVolume(argv[1], FALSE, FALSE);
54     if (Volume == INVALID_HANDLE_VALUE)
55     {
56         return 1;
57     }
58 
59     /* Attempt to lock the volume */
60     if (LockOrUnlockVolume(Volume, TRUE))
61     {
62         CloseHandle(Volume);
63         return 1;
64     }
65 
66     /* Issue the dismount command */
67     if (DeviceIoControl(Volume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL,
68                         0, &BytesRead, NULL) == FALSE)
69     {
70         PrintErrorMessage(GetLastError());
71         LockOrUnlockVolume(Volume, FALSE);
72         CloseHandle(Volume);
73         return 1;
74     }
75 
76     /* Unlock and quit */
77     LockOrUnlockVolume(Volume, FALSE);
78     CloseHandle(Volume);
79 
80     _ftprintf(stdout, _T("The %s volume has been dismounted\n"), argv[1]);
81 
82     return 0;
83 }
84 
85 static int
86 DiskFreeMain(int argc, const TCHAR *argv[])
87 {
88     ULARGE_INTEGER FreeAvail, TotalNumber, TotalNumberFree;
89 
90     /* We need a path */
91     if (argc < 2)
92     {
93         _ftprintf(stderr, _T("Usage: fsutil volume diskfree <volume path>\n"));
94         _ftprintf(stderr, _T("\tFor example: fsutil volume diskfree c:\n"));
95         return 1;
96     }
97 
98     if (!GetDiskFreeSpaceEx(argv[1], &FreeAvail, &TotalNumber, &TotalNumberFree))
99     {
100         PrintErrorMessage(GetLastError());
101         return 1;
102     }
103 
104     _ftprintf(stdout, _T("Total free bytes\t\t: %I64i\n"), TotalNumberFree.QuadPart);
105     _ftprintf(stdout, _T("Total bytes\t\t\t: %I64i\n"), TotalNumber.QuadPart);
106     _ftprintf(stdout, _T("Total free available bytes\t: %I64i\n"), FreeAvail.QuadPart);
107 
108     return 0;
109 }
110 
111 static void
112 PrintUsage(const TCHAR * Command)
113 {
114     PrintDefaultUsage(_T(" VOLUME "), Command, (HandlerItem *)&HandlersList,
115                       (sizeof(HandlersList) / sizeof(HandlersList[0])));
116 }
117 
118 int
119 VolumeMain(int argc, const TCHAR *argv[])
120 {
121     return FindHandler(argc, argv, (HandlerItem *)&HandlersList,
122                        (sizeof(HandlersList) / sizeof(HandlersList[0])),
123                        PrintUsage);
124 }
125