1 // Copyright (c) 1998 Mark Russinovich
3 // http://www.sysinternals.com
5 #define WIN32_NO_STATUS
12 #include <fmifs/fmifs.h>
21 BOOL QuickFormat
= FALSE
;
22 DWORD ClusterSize
= 0;
23 BOOL CompressDrive
= FALSE
;
24 BOOL GotALabel
= FALSE
;
25 LPTSTR Label
= _T("");
27 LPTSTR FileSystem
= _T("FAT");
29 TCHAR RootDirectory
[MAX_PATH
];
30 TCHAR LabelString
[12];
38 } SIZEDEFINITION
, *PSIZEDEFINITION
;
40 SIZEDEFINITION LegalSizes
[] = {
49 { _T("128K"), 65536 * 2 },
50 { _T("256K"), 65536 * 4 },
55 int LoadStringAndOem(HINSTANCE hInst
,
61 TCHAR szTmp
[RC_STRING_MAX_SIZE
];
62 int res
= LoadString(hInst
, uID
, szTmp
, sizeof(szTmp
));
63 CharToOem(szTmp
, szStr
);
68 //----------------------------------------------------------------------
72 // Takes the win32 error code and prints the text version.
74 //----------------------------------------------------------------------
75 static VOID
PrintWin32Error( LPTSTR Message
, DWORD ErrorCode
)
79 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
81 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
82 (LPTSTR
)&lpMsgBuf
, 0, NULL
);
84 _tprintf(_T("%s: %s\n"), Message
, lpMsgBuf
);
85 LocalFree( lpMsgBuf
);
89 //----------------------------------------------------------------------
95 //----------------------------------------------------------------------
96 static int ParseCommandLine( int argc
, TCHAR
*argv
[] )
99 BOOLEAN gotFormat
= FALSE
;
100 BOOLEAN gotQuick
= FALSE
;
101 BOOLEAN gotSize
= FALSE
;
102 BOOLEAN gotLabel
= FALSE
;
103 BOOLEAN gotCompressed
= FALSE
;
106 for( i
= 1; i
< argc
; i
++ ) {
108 switch( argv
[i
][0] ) {
113 if( !_tcsnicmp( &argv
[i
][1], _T("FS:"), 3 )) {
115 if( gotFormat
) return -1;
116 FileSystem
= &argv
[i
][4];
120 } else if( !_tcsnicmp( &argv
[i
][1], _T("A:"), 2 )) {
122 if( gotSize
) return -1;
124 while( LegalSizes
[j
].ClusterSize
&&
125 _tcsicmp( LegalSizes
[j
].SizeString
, &argv
[i
][3] )) j
++;
127 if( !LegalSizes
[j
].ClusterSize
) return i
;
128 ClusterSize
= LegalSizes
[j
].ClusterSize
;
131 } else if( ! _tcsnicmp( &argv
[i
][1], _T("V:"), 2 )) {
133 if( gotLabel
) return -1;
138 } else if( !_tcsicmp( &argv
[i
][1], _T("Q") )) {
140 if( gotQuick
) return -1;
144 } else if( !_tcsicmp( &argv
[i
][1], _T("C") )) {
146 if( gotCompressed
) return -1;
147 CompressDrive
= TRUE
;
148 gotCompressed
= TRUE
;
155 if( Drive
) return i
;
156 if( argv
[i
][1] != _T(':') ) return i
;
165 //----------------------------------------------------------------------
169 // The file system library will call us back with commands that we
170 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
172 //----------------------------------------------------------------------
175 CALLBACKCOMMAND Command
,
182 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
185 // We get other types of commands, but we don't have to pay attention to them
190 percent
= (PDWORD
) Argument
;
191 LoadStringAndOem( GetModuleHandle(NULL
), STRING_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
192 _tprintf(szMsg
, *percent
);
196 output
= (PTEXTOUTPUT
) Argument
;
197 fprintf(stdout
, "%s", output
->Output
);
201 status
= (PBOOLEAN
) Argument
;
202 if( *status
== FALSE
) {
204 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FORMAT_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
205 _tprintf("%s", szMsg
);
209 case DONEWITHSTRUCTURE
:
214 case INSUFFICIENTRIGHTS
:
221 case STRUCTUREPROGRESS
:
222 case CLUSTERSIZETOOSMALL
:
223 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
224 _tprintf("%s", szMsg
);
231 //----------------------------------------------------------------------
233 // LoadFMIFSEntryPoints
235 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
237 //----------------------------------------------------------------------
238 BOOLEAN
LoadFMIFSEntryPoints()
240 HMODULE hFmifs
= LoadLibrary( _T("fmifs.dll") );
241 if (hFmifs
== NULL
) {
245 if( !(void*) GetProcAddress( hFmifs
, "FormatEx" ) ) {
250 if( !((void *) GetProcAddress( hFmifs
,
251 "EnableVolumeCompression" )) ) {
256 if( !((void *) GetProcAddress( hFmifs
,
257 "QueryAvailableFileSystemFormat" )) ) {
266 //----------------------------------------------------------------------
270 // Tell the user how to use the program
272 //----------------------------------------------------------------------
273 static VOID
Usage( LPTSTR ProgramName
)
275 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
276 TCHAR szFormats
[MAX_PATH
];
278 TCHAR szFormatA
[MAX_PATH
];
280 WCHAR szFormatW
[MAX_PATH
];
283 BOOLEAN latestVersion
;
285 LoadStringAndOem( GetModuleHandle(NULL
), STRING_HELP
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
286 if (!LoadFMIFSEntryPoints())
288 _tprintf(szMsg
, ProgramName
, _T(""));
293 while (QueryAvailableFileSystemFormat(Index
++, szFormatW
, &dummy
, &dummy
, &latestVersion
))
298 _tcscat(szFormats
, _T(", "));
300 _tcscat(szFormats
, szFormatW
);
302 if (0 != WideCharToMultiByte(CP_ACP
, 0, szFormatW
, -1, szFormatA
, sizeof(szFormatA
), NULL
, NULL
))
303 _tcscat(szFormats
, szFormatA
);
306 _tprintf(szMsg
, ProgramName
, szFormats
);
310 //----------------------------------------------------------------------
314 // Engine. Just get command line switches and fire off a format. This
315 // could also be done in a GUI like Explorer does when you select a
316 // drive and run a check on it.
318 // We do this in UNICODE because the chkdsk command expects PWCHAR
321 //----------------------------------------------------------------------
323 _tmain(int argc
, TCHAR
*argv
[])
326 DWORD media
= FMIFS_HARDDISK
;
328 TCHAR fileSystem
[1024];
329 TCHAR volumeName
[1024];
332 DWORD flags
, maxComponent
;
333 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
335 WCHAR RootDirectoryW
[MAX_PATH
], FileSystemW
[MAX_PATH
], LabelW
[MAX_PATH
];
337 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
340 // Get function pointers
342 if( !LoadFMIFSEntryPoints()) {
343 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FMIFS_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
344 _tprintf("%s", szMsg
);
349 // Parse command line
351 if( (badArg
= ParseCommandLine( argc
, argv
))) {
353 LoadStringAndOem( GetModuleHandle(NULL
), STRING_UNKNOW_ARG
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
354 _tprintf(szMsg
, argv
[badArg
] );
361 // Get the drive's format
365 LoadStringAndOem( GetModuleHandle(NULL
), STRING_DRIVE_PARM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
372 _tcscpy( RootDirectory
, Drive
);
374 RootDirectory
[2] = _T('\\');
375 RootDirectory
[3] = _T('\0');
378 // See if the drive is removable or not
380 driveType
= GetDriveType( RootDirectory
);
384 LoadStringAndOem( GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
385 PrintWin32Error( szMsg
, GetLastError());
390 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
, RC_STRING_MAX_SIZE
);
394 case DRIVE_NO_ROOT_DIR
:
395 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
396 PrintWin32Error( szMsg
, GetLastError());
399 case DRIVE_REMOVABLE
:
400 LoadStringAndOem( GetModuleHandle(NULL
), STRING_INSERT_DISK
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
401 _tprintf(szMsg
, RootDirectory
[0] );
402 _fgetts( input
, sizeof(input
)/2, stdin
);
403 media
= FMIFS_FLOPPY
;
408 media
= FMIFS_HARDDISK
;
412 // Reject attempts to format the system drive
414 TCHAR path
[MAX_PATH
+ 1];
416 rc
= GetWindowsDirectory(path
, MAX_PATH
);
417 if (rc
== 0 || rc
> MAX_PATH
)
418 // todo: Report "Unable to query system directory"
420 if (_totlower(path
[0]) == _totlower(Drive
[0]))
422 // todo: report "Cannot format system drive"
423 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
, RC_STRING_MAX_SIZE
);
430 // Determine the drive's file system format
432 if( !GetVolumeInformation( RootDirectory
,
433 volumeName
, sizeof(volumeName
)/2,
434 &serialNumber
, &maxComponent
, &flags
,
435 fileSystem
, sizeof(fileSystem
)/2)) {
437 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
438 PrintWin32Error( szMsg
, GetLastError());
442 if( !GetDiskFreeSpaceEx( RootDirectory
,
443 &freeBytesAvailableToCaller
,
445 &totalNumberOfFreeBytes
)) {
447 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
448 PrintWin32Error( szMsg
, GetLastError());
451 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FILESYSTEM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
452 _tprintf(szMsg
, fileSystem
);
455 // Make sure they want to do this
457 if( driveType
== DRIVE_FIXED
) {
459 if( volumeName
[0] ) {
463 LoadStringAndOem( GetModuleHandle(NULL
), STRING_LABEL_NAME_EDIT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
464 _tprintf(szMsg
, RootDirectory
[0] );
465 _fgetts( input
, sizeof(input
)/2, stdin
);
466 input
[ _tcslen( input
) - 1] = 0;
468 if( !_tcsicmp( input
, volumeName
)) {
472 LoadStringAndOem( GetModuleHandle(NULL
), STRING_ERROR_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
473 _tprintf("%s", szMsg
);
477 LoadStringAndOem( GetModuleHandle(NULL
), STRING_YN_FORMAT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
478 _tprintf(szMsg
, RootDirectory
[0] );
480 LoadStringAndOem( GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
483 _fgetts( input
, sizeof(input
)/2, stdin
);
484 if(_strnicmp(&input
[0],&szMsg
[0],1) == 0) break;
485 if(_strnicmp(&input
[0],&szMsg
[1],1) == 0) {
493 // Tell the user we're doing a long format if appropriate
497 LoadString( GetModuleHandle(NULL
), STRING_VERIFYING
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
499 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
501 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
505 _tprintf(_T("%s %.1fM\n"),szMsg
,
506 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
510 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FAST_FMT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
511 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
513 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
517 _tprintf(_T("%s %.2fM\n"),szMsg
,
518 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
520 LoadStringAndOem( GetModuleHandle(NULL
), STRING_CREATE_FSYS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
521 _tprintf("%s", szMsg
);
528 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
529 MultiByteToWideChar(CP_ACP
, 0, FileSystem
, -1, FileSystemW
, MAX_PATH
);
530 MultiByteToWideChar(CP_ACP
, 0, Label
, -1, LabelW
, MAX_PATH
);
531 FormatEx( RootDirectoryW
, media
, FileSystemW
, LabelW
, QuickFormat
,
532 ClusterSize
, FormatExCallback
);
534 FormatEx( RootDirectory
, media
, FileSystem
, Label
, QuickFormat
,
535 ClusterSize
, FormatExCallback
);
537 if( Error
) return -1;
538 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FMT_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
539 _tprintf("%s", szMsg
);
542 // Enable compression if desired
544 if( CompressDrive
) {
547 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
548 if( !EnableVolumeCompression( RootDirectoryW
, TRUE
)) {
550 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
553 LoadStringAndOem( GetModuleHandle(NULL
), STRING_VOL_COMPRESS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
554 _tprintf("%s", szMsg
);
559 // Get the label if we don't have it
563 LoadString( GetModuleHandle(NULL
), STRING_ENTER_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
564 _tprintf("%s", szMsg
);
565 _fgetts( input
, sizeof(LabelString
)/2, stdin
);
567 input
[ _tcslen(input
)-1] = 0;
568 if( !SetVolumeLabel( RootDirectory
, input
)) {
570 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
571 PrintWin32Error(szMsg
, GetLastError());
576 if( !GetVolumeInformation( RootDirectory
,
577 volumeName
, sizeof(volumeName
)/2,
578 &serialNumber
, &maxComponent
, &flags
,
579 fileSystem
, sizeof(fileSystem
)/2)) {
581 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
582 PrintWin32Error( szMsg
, GetLastError());
587 // Print out some stuff including the formatted size
589 if( !GetDiskFreeSpaceEx( RootDirectory
,
590 &freeBytesAvailableToCaller
,
592 &totalNumberOfFreeBytes
)) {
594 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
595 PrintWin32Error(szMsg
, GetLastError());
599 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FREE_SPACE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
600 _tprintf(szMsg
, totalNumberOfBytes
.QuadPart
, totalNumberOfFreeBytes
.QuadPart
);
603 // Get the drive's serial number
605 if( !GetVolumeInformation( RootDirectory
,
606 volumeName
, sizeof(volumeName
)/2,
607 &serialNumber
, &maxComponent
, &flags
,
608 fileSystem
, sizeof(fileSystem
)/2)) {
610 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
611 PrintWin32Error( szMsg
, GetLastError());
614 LoadStringAndOem( GetModuleHandle(NULL
), STRING_SERIAL_NUMBER
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
615 _tprintf(szMsg
, (unsigned int)(serialNumber
>> 16),
616 (unsigned int)(serialNumber
& 0xFFFF) );