rtoss - Blame information for rev 264

Subversion Repositories:
Rev:
Rev Author Line No. Line
201 roytam 1 #include <windows.h>
2 #include <stdio.h>
263 roytam 3 #ifndef _MSC_VER
4 # include <stdint.h>
5 #else
6 #if _MSC_VER < 1200
7 // VC++ < 6.0 doesn't support unsigned int64 to double (VC5 untested)
8 typedef __int64 uint64_t;
9 #else
10 typedef unsigned __int64 uint64_t;
11 #endif
12 # define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
13 #endif
14 #ifndef INVALID_FILE_ATTRIBUTES
15 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
16 #endif
201 roytam 17 #include <string.h>
18 #include <locale.h>
19  
263 roytam 20 #ifdef _MSC_VER
21 __declspec(dllimport) HANDLE WINAPI FindFirstVolumeW(WCHAR * lpszVolumeName, DWORD cchBufferLength);
22 __declspec(dllimport) HANDLE WINAPI FindFirstVolumeMountPointW(WCHAR * lpszRootPathName, WCHAR * lpszVolumeMountPoint, DWORD cchBufferLength);
264 roytam 23 __declspec(dllimport) BOOL WINAPI GetVolumeNameForVolumeMountPointW(WCHAR ** lpszVolumeMountPoint, WCHAR * lpszVolumeName, DWORD cchBufferLength);
263 roytam 24 __declspec(dllimport) BOOL WINAPI FindNextVolumeW(HANDLE hFindVolume, WCHAR * lpszVolumeName, DWORD cchBufferLength);
25 __declspec(dllimport) BOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint, WCHAR * lpszVolumeMountPoint, DWORD cchBufferLength);
26 __declspec(dllimport) BOOL WINAPI FindVolumeClose(HANDLE hFindVolume);
27 __declspec(dllimport) BOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint);
28 #endif
29  
204 roytam 30 void vpath_pairs_append(WCHAR *volpath, WCHAR *win32path);
31 void vpath_pairs_free();
32  
33 WCHAR* FindDriveLetterFromVolumePath(WCHAR* wszVolumePath);
34  
35 BOOL ProcessVolumeMountPoint(HANDLE hPt, WCHAR *PtBuf, DWORD dwPtBufSize, WCHAR *Buf);
36 BOOL ProcessVolume(HANDLE hVol, WCHAR *Buf, DWORD iBufSize);
37 int GetMountPoint(void);
38  
201 roytam 39 void DisplayVolumePaths(PWCHAR VolumeName);
203 roytam 40 WCHAR *fdigitsW(uint64_t integer);
201 roytam 41 WCHAR *ComputerUnits(uint64_t integer, int maxdiv);
203 roytam 42 void DrawGauge(int length, int percent, int isempty);
204 roytam 43 int IsTargetDrive(int DriveType, int flgNoRemoveable, int flgIsRealFloppy);
208 roytam 44 void ShowVolume(WCHAR* VolumeName, int flgShowDevName, int flgVerbose, int flgUnit, int flgGauge, int flgNoRemoveable, uint64_t* AllTotalSize, uint64_t* AllFreeSize);
201 roytam 45  
204 roytam 46 typedef BOOL (WINAPI *PGVPNFVNW)(LPCWSTR,LPWSTR,DWORD,PDWORD);
47  
48 struct vpath_pairs{
49  WCHAR vpath[MAX_PATH];
50  WCHAR w32path[MAX_PATH];
51  struct vpath_pairs *next;
52 };
53  
54 static struct vpath_pairs *vpath = NULL;
55  
56 void vpath_pairs_append(WCHAR *volpath, WCHAR *win32path) {
257 roytam 57     struct vpath_pairs *v, *t;
58  
59     v = (struct vpath_pairs*) malloc(sizeof(struct vpath_pairs));
60     wcscpy(v->vpath, volpath);
61     wcscpy(v->w32path, win32path);
62     v->next = NULL;
63  
204 roytam 64     if(!vpath) {
257 roytam 65         vpath = v;
204 roytam 66     } else {
257 roytam 67         t = vpath;
68         while(v->next != NULL) t = t->next;
69         t->next = v;
204 roytam 70     }
71 }
72  
73 void vpath_pairs_free() {
74     struct vpath_pairs *v, *t;
75     if(vpath) {
76         v = vpath;
77         while(v->next != NULL) {
78             t = v;
79             v = v->next;
80             free(t);
81         }
82         vpath = NULL;
83     }
84 }
85  
86  
87 WCHAR* FindDriveLetterFromVolumePath(WCHAR* wszVolumePath) {
88     static WCHAR** vPathLetters = NULL;
89     static WCHAR tmp[10] = {0};
90     static int vPathFilled = 0;
91     int i = 0;
92  
93     if(wszVolumePath) {
94         wcscpy(tmp,L"A:\\");
95         if(!vPathLetters) { // malloc the 2D array
96             vPathLetters = (WCHAR**) malloc(26*sizeof(WCHAR*));
97             for (i = 0; i < 26; i++)
98                 vPathLetters[i] = (WCHAR*) malloc((MAX_PATH+1)*sizeof(WCHAR));
99         }
100         if(!vPathFilled) {
101             for(i = 0; i < 26; i++, tmp[0]++) {
102                 GetVolumeNameForVolumeMountPointW(tmp, vPathLetters[i], MAX_PATH);
103             }
104             vPathFilled = 1;
105         }
106  
107         tmp[0] = L'A';
108         for(i = 0; i < 26; i++, tmp[0]++) {
205 roytam 109             if(wcscmp(wszVolumePath, vPathLetters[i]) == 0) {
204 roytam 110                 tmp[0] = L'A' + i;
111                 return tmp;
112             }
113         }
114     } else { // free the 2D array
115         if(vPathLetters) { // avoid double free/free uninitialized
116             for (i = 0; i < 26; i++)
117                 free(vPathLetters[i]);
118             free(vPathLetters);
119         }
120         vPathLetters = NULL;
121         vPathFilled = 0;
122     }
123     return NULL;
124 }
125  
126 // *******
127 BOOL ProcessVolumeMountPoint(HANDLE hPt, WCHAR *PtBuf, DWORD dwPtBufSize, WCHAR *Buf) {
128     BOOL bFlag;
129     WCHAR Path[MAX_PATH];
130     WCHAR Target[MAX_PATH];
131  
132     wcscpy(Path, Buf);
133     wcscat(Path, PtBuf);
134  
135     bFlag = GetVolumeNameForVolumeMountPointW(Path,Target,MAX_PATH);
136  
137     if (bFlag) {
138         wcscpy(Path, FindDriveLetterFromVolumePath(Buf));
139         wcscat(Path, PtBuf);
140         vpath_pairs_append(Target, Path);
141     }
142  
143     bFlag = FindNextVolumeMountPointW(hPt,PtBuf,dwPtBufSize);
144     return (bFlag);
145 }
146  
147 BOOL ProcessVolume(HANDLE hVol, WCHAR *Buf, DWORD iBufSize) {
148     BOOL bFlag;
149     HANDLE hPt;
150     WCHAR PtBuf[MAX_PATH];
151     DWORD dwSysFlags;
152     WCHAR FileSysNameBuf[MAX_PATH];
153  
154     // is NTFS?
155     GetVolumeInformationW( Buf, NULL, 0, NULL, NULL, &dwSysFlags, FileSysNameBuf, MAX_PATH);
156  
157     if ((dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS)) {
158         hPt = FindFirstVolumeMountPointW(Buf, PtBuf, MAX_PATH);
159  
160         if (hPt != INVALID_HANDLE_VALUE) {
161             bFlag = ProcessVolumeMountPoint(hPt, PtBuf, MAX_PATH, Buf);
162             while (bFlag)
163                 bFlag = ProcessVolumeMountPoint (hPt, PtBuf, MAX_PATH, Buf);
164             FindVolumeMountPointClose(hPt);
165         }
166     }
167  
168     bFlag = FindNextVolumeW(hVol, Buf, iBufSize);
169     return (bFlag);
170 }
171 int GetMountPoint(void) {
172     WCHAR buf[MAX_PATH];
173     HANDLE hVol;
174     BOOL bFlag;
175  
176     hVol = FindFirstVolumeW(buf, MAX_PATH);
177     if (hVol == INVALID_HANDLE_VALUE) {
178        return (-1);
179     }
180  
181     bFlag = ProcessVolume(hVol, buf, MAX_PATH);
182     while (bFlag) {
183        bFlag = ProcessVolume(hVol, buf, MAX_PATH);
184     }
185  
186     bFlag = FindVolumeClose( hVol );
187     return (bFlag);
188 }
189 // *******
190  
201 roytam 191 void DisplayVolumePaths(PWCHAR VolumeName) {
192     DWORD  CharCount = MAX_PATH + 1;
193     PWCHAR Names     = NULL;
194     PWCHAR NameIdx   = NULL;
195     BOOL   Success   = FALSE;
204 roytam 196     HANDLE hFvn      = NULL;
201 roytam 197  
204 roytam 198     struct vpath_pairs* v;
201 roytam 199  
204 roytam 200     PGVPNFVNW pGVPNFVNW;
201     pGVPNFVNW = (PGVPNFVNW) GetProcAddress(
202         GetModuleHandle("kernel32.dll"),
203         "GetVolumePathNamesForVolumeNameW");
204  
205     if(pGVPNFVNW) {
206         for (;;) {
201 roytam 207             //
204 roytam 208             //  Allocate a buffer to hold the paths.
209             Names = (PWCHAR) malloc(CharCount * sizeof(WCHAR));
210  
211             if ( !Names ) {
212                 //
213                 //  If memory can't be allocated, return.
214                 return;
215             }
216  
217             //
218             //  Obtain all of the paths
219             //  for this volume.
220             Success = pGVPNFVNW(VolumeName, Names, CharCount, &CharCount);
221  
222             if ( Success ) {
223                 break;
224             }
225  
226             if ( GetLastError() != ERROR_MORE_DATA ) {
227                 break;
228             }
229  
230             //
231             //  Try again with the
232             //  new suggested size.
233             free(Names);
234             Names = NULL;
201 roytam 235         }
236  
237         if ( Success ) {
204 roytam 238             //
239             //  Display the various paths.
240             for ( NameIdx = Names;
241                   NameIdx[0] != L'\0';
242                   NameIdx += wcslen(NameIdx) + 1 ) {
243                 wprintf(L"  %s", NameIdx);
244             }
245             //wprintf(L"\n");
201 roytam 246         }
247  
204 roytam 248         if ( Names != NULL ) {
249             free(Names);
250             Names = NULL;
201 roytam 251         }
204 roytam 252     } else {
253         // GetVolumePathNamesForVolumeNameW cannot be used (Win2000)
201 roytam 254  
204 roytam 255         // print drive letter first
256         Names = FindDriveLetterFromVolumePath(VolumeName);
205 roytam 257         if(Names) wprintf(L"  %s", Names);
201 roytam 258  
204 roytam 259         // then mountpoints
260         GetMountPoint();
261         if(vpath) {
262             v = vpath;
263             while(v != NULL) {
264                 if(wcsicmp(v->vpath, VolumeName) == 0) {
265                     wprintf(L"  %s", v->w32path);
266                 }
267                 v = v->next;
268             }
201 roytam 269         }
270  
271     }
272  
273     return;
274 }
275  
204 roytam 276 #define MAX_PLACES 64
201 roytam 277 WCHAR *fdigitsW(uint64_t integer) {
278     static WCHAR fdigits[MAX_PLACES + (MAX_PLACES / 3) + 1];
279     WCHAR digits[MAX_PLACES + 1];
280     WCHAR *dgt = digits, *fdgt = fdigits;
281     int places;
282  
283     places = swprintf(digits, L"%I64u", integer); /* convert integer to string */
284     /* places = digits in string */
285     while (*fdgt++ = *dgt++) /* while there are more digits*/
286         if (--places) /* if places-1 > 0 */
287             if ( !(places % 3) ) /* if places is multiple of 3 */
288                 *fdgt++ = L','; /* insert a comma here */
289  
290     return fdigits;
291 }
292  
293 WCHAR *ComputerUnits(uint64_t integer, int maxdiv) {
294     static WCHAR fdigits[MAX_PLACES + (MAX_PLACES / 3) + 1];
295     WCHAR *units[] = {L"B",L"KB",L"MB",L"GB",L"TB",L"PB",L"EB", NULL};
204 roytam 296     WCHAR tmp[10] = {0};
201 roytam 297     int count = 0;
298     double smallfloat;
299     uint64_t smallint;
300  
203 roytam 301     for(smallint = smallfloat = integer; smallint > 1024 && count < maxdiv;) {
201 roytam 302         count++;
303         smallint /= 1024;
304         smallfloat /= 1024;
305     }
306  
206 roytam 307     if(count) {
308         swprintf(tmp, L"%.3f", smallfloat-smallint);
309         tmp[4] = 0; // truncate
310     }
203 roytam 311  
201 roytam 312     swprintf(fdigits, L"%s%s %s", fdigitsW(smallint), tmp+1, units[count]); /* convert integer to string */
313  
314     return fdigits;
315 }
316  
317 void DrawGauge(int length, int percent, int isempty) {
318     int i,barlong,remain;
319     char tmp[100];
320  
321     barlong = (length-2)*percent/100;
322     remain = (length-2)-barlong;
323     putchar('|');
324     if(!isempty) {
325         for(i=0; i<barlong; ++i)
326             putchar('.');
327         for(i=0; i<remain; ++i)
328             putchar('#');
329     } else {
330         sprintf(tmp,"%%%ds",length-2);
331         printf(tmp,"");
332     }
333     putchar('|');
334 }
335  
204 roytam 336 int IsTargetDrive(int DriveType, int flgRemoveable, int flgIsRealFloppy) {
206 roytam 337     int ret = 0;
203 roytam 338     if(!flgRemoveable)
206 roytam 339         ret = DriveType > 1 && DriveType != 2 && DriveType != 5;
340     if(flgRemoveable & 1)
341         ret |= DriveType > 1 && !flgIsRealFloppy;
342     if(flgRemoveable & 2)
343         ret |= DriveType > 1;
344     return ret;
203 roytam 345 }
201 roytam 346  
208 roytam 347 void ShowVolume(WCHAR* VolumeName, int flgShowDevName, int flgVerbose, int flgUnit, int flgGauge, int flgRemoveable, uint64_t* AllTotalSize, uint64_t* AllFreeSize) {
203 roytam 348     DWORD  Error                = ERROR_SUCCESS;
201 roytam 349     DWORD  CharCount            = 0;
203 roytam 350     WCHAR  tmp[MAX_PATH]        = L"";
201 roytam 351     WCHAR  DeviceName[MAX_PATH] = L"";
352     WCHAR* VolumeTypeName       = 0;
353     UINT   VolumeType           = 0;
203 roytam 354     size_t Index                = 0;
201 roytam 355     DWORD  SectorsPerCluster    = 0;
356     DWORD  BytesPerSector       = 0;
357     DWORD  NumberOfFreeClusters = 0;
358     DWORD  TotalNumberOfClusters= 0;
359     uint64_t TotalSize          = 0;
360     uint64_t FreeSize           = 0;
361  
204 roytam 362     UINT   flgIsRealFloppy      = 0;
363  
203 roytam 364     double den                  = 0.0f;
365     double percent              = 0.0f;
201 roytam 366  
203 roytam 367     wcscpy(tmp, VolumeName);
201 roytam 368  
203 roytam 369     if(flgShowDevName) {
201 roytam 370         //
371         //  Skip the \\?\ prefix and remove the trailing backslash.
203 roytam 372         Index = wcslen(tmp) - 1;
201 roytam 373  
203 roytam 374         if (tmp[0]     != L'\\' ||
375             tmp[1]     != L'\\' ||
376             tmp[2]     != L'?'  ||
377             tmp[3]     != L'\\' ||
378             tmp[Index] != L'\\')
201 roytam 379         {
380             Error = ERROR_BAD_PATHNAME;
203 roytam 381             wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %s\n", tmp);
382             return;
201 roytam 383         }
384  
385         //
386         //  QueryDosDeviceW does not allow a trailing backslash,
387         //  so temporarily remove it.
203 roytam 388         tmp[Index] = L'\0';
201 roytam 389  
203 roytam 390         CharCount = QueryDosDeviceW(&tmp[4], DeviceName, ARRAYSIZE(DeviceName));
201 roytam 391  
203 roytam 392         tmp[Index] = L'\\';
201 roytam 393  
203 roytam 394         if ( CharCount == 0 ) {
201 roytam 395             Error = GetLastError();
396             wprintf(L"QueryDosDeviceW failed with error code %d\n", Error);
203 roytam 397             return;
201 roytam 398         }
204 roytam 399  
400         if(flgRemoveable == 1) {
401             flgIsRealFloppy = (wcsstr(DeviceName, L"Floppy") != NULL);
402         }
403  
203 roytam 404     }
201 roytam 405  
203 roytam 406     VolumeType = GetDriveTypeW(tmp);
407     switch(VolumeType) {
408         case 0:
409             VolumeTypeName = L"(Unknown)";
410             break;
411         case 1:
412             VolumeTypeName = L"(invalid root path)";
413             break;
414         case 2:
415             VolumeTypeName = L"(Removable)";
416             break;
417         case 3:
418             VolumeTypeName = L"(Fixed)";
419             break;
420         case 4:
421             VolumeTypeName = L"(Remote)";
422             break;
423         case 5:
424             VolumeTypeName = L"(CD-ROM)";
425             break;
426         case 6:
427             VolumeTypeName = L"(RAM Disk)";
428             break;
429     }
201 roytam 430  
204 roytam 431     if(!flgVerbose && !IsTargetDrive(VolumeType,1,0)) return;
203 roytam 432     // get free space information
204 roytam 433     if(IsTargetDrive(VolumeType,flgRemoveable,flgIsRealFloppy)) {
203 roytam 434         GetDiskFreeSpaceW(tmp, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
435         FreeSize = TotalSize = SectorsPerCluster;
436         FreeSize *= BytesPerSector;
437         TotalSize *= BytesPerSector;
438         FreeSize *= NumberOfFreeClusters;
439         TotalSize *= TotalNumberOfClusters;
208 roytam 440  
441         if(VolumeType == 3) {
442             *AllTotalSize += TotalSize;
443             *AllFreeSize += FreeSize;
444         }
445  
203 roytam 446         den = TotalSize;
447         percent = FreeSize;
448         percent /= den;
449         percent *= 100;
450     }
201 roytam 451  
203 roytam 452     if(flgVerbose) {
453         wprintf(L"\nFound a device: %s", DeviceName);
454         wprintf(L"\nVolume name: %s %s", tmp, VolumeTypeName);
455         wprintf(L"\nPaths:");
456     }
457     else if(flgGauge) {
204 roytam 458         DrawGauge(36,(int)percent,!IsTargetDrive(VolumeType,flgRemoveable,flgIsRealFloppy)|!TotalSize);
203 roytam 459     }
201 roytam 460  
203 roytam 461     if (flgShowDevName)
462         DisplayVolumePaths(tmp);
463     else
464         wprintf(L"  %s", tmp);
201 roytam 465  
466  
204 roytam 467     if(IsTargetDrive(VolumeType,flgRemoveable,flgIsRealFloppy)) {
203 roytam 468         // VolumeName is reused here
469         wcscpy(tmp, ComputerUnits(FreeSize, flgUnit));
470  
471         // DeviceName is reused here
472         if(TotalSize)
473             swprintf(DeviceName, L"%.2f", percent);
474         else
475             wcscpy(DeviceName, L"--");
476  
477         wprintf(L" (%s / %s) %s%%", tmp, ComputerUnits(TotalSize, flgUnit), DeviceName);
478     }
479     if(!flgVerbose) {
480         if(VolumeType != 3) wprintf(L" %s", VolumeTypeName);
481     }
482     wprintf(L"\n");
483 }
484  
485  
486 int main(int argc, char **argv)
487 {
488     DWORD  Error                = ERROR_SUCCESS;
489     HANDLE FindHandle           = INVALID_HANDLE_VALUE;
490     BOOL   Found                = FALSE;
491     size_t Index                = 0;
492     BOOL   Success              = FALSE;
493     WCHAR  VolumeName[MAX_PATH] = L"";
494     DWORD  dwAttrib             = 0;
495  
208 roytam 496     uint64_t allTotal           = 0;
497     uint64_t allFree            = 0;
498     double   percent            = 0.0f;
499  
203 roytam 500     int i               = 1;
501     int flgVerbose      = 0;
502     int flgUnit         = 3;
503     int flgGauge        = 0;
504     int flgRemoveable   = 0;
505     int flgNonEnum      = 0;
204 roytam 506     int flgForceEnum    = 0;
208 roytam 507     int flgShowAllTotal = 0;
203 roytam 508     int OldMode; //a place to store the old error mode
509  
204 roytam 510     //save the old error mode and set the new mode to let us do the work:
511     OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
512  
203 roytam 513     for (; i < argc; i++) {
514         if(stricmp(argv[i],"-g") == 0) {
515             flgGauge = 1;
516         } else if(strnicmp(argv[i],"-u",2) == 0) {
517             if(argv[i][2] >= '0' && argv[i][2] <= '4')
518                 flgUnit = argv[i][2] - '0';
204 roytam 519         } else if(strnicmp(argv[i],"-r",2) == 0) {
206 roytam 520             flgRemoveable |= 1;
204 roytam 521             if(argv[i][2] == 'f')
206 roytam 522                 flgRemoveable |= 2;
203 roytam 523         } else if(stricmp(argv[i],"-v") == 0) {
524             flgVerbose = 1;
204 roytam 525         } else if(stricmp(argv[i],"-a") == 0) {
526             flgForceEnum = 1;
208 roytam 527         } else if(stricmp(argv[i],"-t") == 0) {
528             flgShowAllTotal = 1;
203 roytam 529         } else if(strcmp(argv[i],"-?") == 0) {
208 roytam 530             printf("%s [-v] [-g] [-a] [-r[f]] [-u#] [-t] [-?] [drive|path...]\n\n"
203 roytam 531                 " -v\t\tbe verbose (-g switch will be turned off)\n"
532                 " -g\t\tdraw gauge of free space\n"
204 roytam 533                 " -a\t\tappend drive|path to detected list\n"
534                 " -r[f]\t\tdetect removable device free space (-rf for real floppy drive)\n"
203 roytam 535                 " -u[num]\tuse unit # (0=byte, 1=KB, 2=MB, 3=GB, 4=TB)\n"
208 roytam 536                 " -t\t\tshow total and free of all local fixed drives\n"
203 roytam 537                 " -?\t\tshow this help and exit\n"
538                 " drive|path...\tshow individual drives\n"
539                 " \t\texample:  C: D: F:\\mountpoint\\\n", argv[0]);
540             return 0;
541         } else {
542             // assume it is a path
543             dwAttrib = GetFileAttributesA(argv[i]);
544             if(dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
545                 // yes it is valid path
204 roytam 546                 if(!flgForceEnum)
547                     flgNonEnum = 1;
203 roytam 548                 // dwAttrib is reused
549                 dwAttrib = MultiByteToWideChar(CP_ACP, 0, argv[i], -1, VolumeName, MAX_PATH);
550                 // workaround on getting free space from \\host\share
551                 if (VolumeName[dwAttrib-2] != L'\\') VolumeName[dwAttrib-1] = L'\\';
208 roytam 552                 ShowVolume(VolumeName, 0, flgVerbose, flgUnit, flgGauge, flgRemoveable, &allTotal, &allFree);
203 roytam 553             } else {
554                 printf("%s is not valid path.\n", argv[i]);
555                 return 0;
556             }
201 roytam 557         }
203 roytam 558     }
201 roytam 559  
203 roytam 560     setlocale(LC_CTYPE, ""); // reset locale
561  
562     if(!flgNonEnum) {
201 roytam 563         //
203 roytam 564         //  Enumerate all volumes in the system.
565         FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));
201 roytam 566  
203 roytam 567         if (FindHandle == INVALID_HANDLE_VALUE) {
201 roytam 568             Error = GetLastError();
203 roytam 569             wprintf(L"FindFirstVolumeW failed with error code %d\n", Error);
570             return 1;
571         }
201 roytam 572  
203 roytam 573         for (;;) {
208 roytam 574             ShowVolume(VolumeName, 1, flgVerbose, flgUnit, flgGauge, flgRemoveable, &allTotal, &allFree);
203 roytam 575  
576             //
577             //  Move on to the next volume.
578             Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));
579  
580             if ( !Success ) {
581                 Error = GetLastError();
582  
583                 if (Error != ERROR_NO_MORE_FILES) {
584                     wprintf(L"FindNextVolumeW failed with error code %d\n", Error);
585                     break;
586                 }
587  
588                 //
589                 //  Finished iterating
590                 //  through all the volumes.
591                 Error = ERROR_SUCCESS;
201 roytam 592                 break;
593             }
203 roytam 594         }
201 roytam 595  
203 roytam 596         FindVolumeClose(FindHandle);
597         FindHandle = INVALID_HANDLE_VALUE;
598  
201 roytam 599     }
600  
208 roytam 601  
602     if(flgShowAllTotal) {
603         percent = allFree;
604         percent /= allTotal;
605         percent *= 100;
606  
607         if(flgVerbose)
608             wprintf(L"\n");
609  
610         if(!flgVerbose && flgGauge) {
611             DrawGauge(36,(int)percent,0);
612         }
613         // VolumeName is reused here
614         wcscpy(VolumeName, ComputerUnits(allFree, flgUnit));
615  
616         wprintf(L"Total: (%s / %s) %.2f%%\n", VolumeName, ComputerUnits(allTotal, flgUnit), percent);
617     }
618  
203 roytam 619     SetErrorMode(OldMode); //put things back the way they were
204 roytam 620     FindDriveLetterFromVolumePath(NULL); // free the array
621     vpath_pairs_free(); // free the linked list
201 roytam 622     return 0;
623 }
624