1 // Copyright (c) 1998 Mark Russinovich
3 // http://www.sysinternals.com
9 #include <fmifs/fmifs.h>
17 BOOL QuickFormat
= FALSE
;
18 DWORD ClusterSize
= 0;
19 BOOL CompressDrive
= FALSE
;
20 BOOL GotALabel
= FALSE
;
21 LPTSTR Label
= _T("");
23 LPTSTR Format
= _T("FAT");
25 TCHAR RootDirectory
[MAX_PATH
];
26 TCHAR LabelString
[12];
34 } SIZEDEFINITION
, *PSIZEDEFINITION
;
36 SIZEDEFINITION LegalSizes
[] = {
45 { _T("128K"), 65536 * 2 },
46 { _T("256K"), 65536 * 4 },
51 int LoadStringAndOem(HINSTANCE hInst
,
57 TCHAR szTmp
[RC_STRING_MAX_SIZE
];
58 int res
= LoadString(hInst
, uID
, szTmp
, sizeof(szTmp
));
59 CharToOem(szTmp
, szStr
);
64 //----------------------------------------------------------------------
68 // Takes the win32 error code and prints the text version.
70 //----------------------------------------------------------------------
71 static VOID
PrintWin32Error( LPTSTR Message
, DWORD ErrorCode
)
75 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
77 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
78 (LPTSTR
)&lpMsgBuf
, 0, NULL
);
80 _tprintf(_T("%s: %s\n"), Message
, lpMsgBuf
);
81 LocalFree( lpMsgBuf
);
85 //----------------------------------------------------------------------
91 //----------------------------------------------------------------------
92 static int ParseCommandLine( int argc
, TCHAR
*argv
[] )
95 BOOLEAN gotFormat
= FALSE
;
96 BOOLEAN gotQuick
= FALSE
;
97 BOOLEAN gotSize
= FALSE
;
98 BOOLEAN gotLabel
= FALSE
;
99 BOOLEAN gotCompressed
= FALSE
;
102 for( i
= 1; i
< argc
; i
++ ) {
104 switch( argv
[i
][0] ) {
109 if( !_tcsnicmp( &argv
[i
][1], _T("FS:"), 3 )) {
111 if( gotFormat
) return -1;
112 Format
= &argv
[i
][4];
116 } else if( !_tcsnicmp( &argv
[i
][1], _T("A:"), 2 )) {
118 if( gotSize
) return -1;
120 while( LegalSizes
[j
].ClusterSize
&&
121 _tcsicmp( LegalSizes
[j
].SizeString
, &argv
[i
][3] )) j
++;
123 if( !LegalSizes
[j
].ClusterSize
) return i
;
124 ClusterSize
= LegalSizes
[j
].ClusterSize
;
127 } else if( ! _tcsnicmp( &argv
[i
][1], _T("V:"), 2 )) {
129 if( gotLabel
) return -1;
134 } else if( !_tcsicmp( &argv
[i
][1], _T("Q") )) {
136 if( gotQuick
) return -1;
140 } else if( !_tcsicmp( &argv
[i
][1], _T("C") )) {
142 if( gotCompressed
) return -1;
143 CompressDrive
= TRUE
;
144 gotCompressed
= TRUE
;
151 if( Drive
) return i
;
152 if( argv
[i
][1] != _T(':') ) return i
;
161 //----------------------------------------------------------------------
165 // The file system library will call us back with commands that we
166 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
168 //----------------------------------------------------------------------
171 CALLBACKCOMMAND Command
,
178 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
181 // We get other types of commands, but we don't have to pay attention to them
186 percent
= (PDWORD
) Argument
;
187 LoadStringAndOem( GetModuleHandle(NULL
), STRING_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
188 _tprintf(szMsg
, *percent
);
192 output
= (PTEXTOUTPUT
) Argument
;
193 fprintf(stdout
, "%s", output
->Output
);
197 status
= (PBOOLEAN
) Argument
;
198 if( *status
== FALSE
) {
200 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FORMAT_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
201 _tprintf("%s", szMsg
);
205 case DONEWITHSTRUCTURE
:
210 case INSUFFICIENTRIGHTS
:
217 case STRUCTUREPROGRESS
:
218 case CLUSTERSIZETOOSMALL
:
219 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
220 _tprintf("%s", szMsg
);
227 //----------------------------------------------------------------------
229 // LoadFMIFSEntryPoints
231 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
233 //----------------------------------------------------------------------
234 BOOLEAN
LoadFMIFSEntryPoints()
236 HMODULE hFmifs
= LoadLibrary( _T("fmifs.dll") );
237 if( !(void*) GetProcAddress( hFmifs
, "FormatEx" ) ) {
242 if( !((void *) GetProcAddress( hFmifs
,
243 "EnableVolumeCompression" )) ) {
248 if( !((void *) GetProcAddress( hFmifs
,
249 "QueryAvailableFileSystemFormat" )) ) {
258 //----------------------------------------------------------------------
262 // Tell the user how to use the program
264 //----------------------------------------------------------------------
265 static VOID
Usage( LPTSTR ProgramName
)
267 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
268 TCHAR szFormats
[MAX_PATH
];
270 TCHAR szFormatA
[MAX_PATH
];
272 WCHAR szFormatW
[MAX_PATH
];
275 BOOLEAN lastestVersion
;
277 LoadStringAndOem( GetModuleHandle(NULL
), STRING_HELP
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
278 if (!LoadFMIFSEntryPoints())
280 _tprintf(szMsg
, ProgramName
, _T(""));
285 while (QueryAvailableFileSystemFormat(Index
++, szFormatW
, &dummy
, &dummy
, &lastestVersion
))
290 _tcscat(szFormats
, _T(", "));
292 _tcscat(szFormats
, szFormatW
);
294 if (0 != WideCharToMultiByte(CP_ACP
, 0, szFormatW
, -1, szFormatA
, sizeof(szFormatA
), NULL
, NULL
))
295 _tcscat(szFormats
, szFormatA
);
298 _tprintf(szMsg
, ProgramName
, szFormats
);
302 //----------------------------------------------------------------------
306 // Engine. Just get command line switches and fire off a format. This
307 // could also be done in a GUI like Explorer does when you select a
308 // drive and run a check on it.
310 // We do this in UNICODE because the chkdsk command expects PWCHAR
313 //----------------------------------------------------------------------
315 _tmain(int argc
, TCHAR
*argv
[])
318 DWORD media
= FMIFS_HARDDISK
;
320 TCHAR fileSystem
[1024];
321 TCHAR volumeName
[1024];
324 DWORD flags
, maxComponent
;
325 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
327 WCHAR RootDirectoryW
[MAX_PATH
], FormatW
[MAX_PATH
], LabelW
[MAX_PATH
];
329 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
332 // Get function pointers
334 if( !LoadFMIFSEntryPoints()) {
335 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FMIFS_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
336 _tprintf("%s", szMsg
);
341 // Parse command line
343 if( (badArg
= ParseCommandLine( argc
, argv
))) {
345 LoadStringAndOem( GetModuleHandle(NULL
), STRING_UNKNOW_ARG
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
346 _tprintf(szMsg
, argv
[badArg
] );
353 // Get the drive's format
357 LoadStringAndOem( GetModuleHandle(NULL
), STRING_DRIVE_PARM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
364 _tcscpy( RootDirectory
, Drive
);
366 RootDirectory
[2] = _T('\\');
367 RootDirectory
[3] = _T('\0');
370 // See if the drive is removable or not
372 driveType
= GetDriveType( RootDirectory
);
376 LoadStringAndOem( GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
377 PrintWin32Error( szMsg
, GetLastError());
382 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
, RC_STRING_MAX_SIZE
);
386 case DRIVE_NO_ROOT_DIR
:
387 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
388 PrintWin32Error( szMsg
, GetLastError());
391 case DRIVE_REMOVABLE
:
392 LoadStringAndOem( GetModuleHandle(NULL
), STRING_INSERT_DISK
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
393 _tprintf(szMsg
, RootDirectory
[0] );
394 _fgetts( input
, sizeof(input
)/2, stdin
);
395 media
= FMIFS_FLOPPY
;
400 media
= FMIFS_HARDDISK
;
404 // Reject attempts to format the system drive
406 TCHAR path
[MAX_PATH
+ 1];
408 rc
= GetWindowsDirectory(path
, MAX_PATH
);
409 if (rc
== 0 || rc
> MAX_PATH
)
410 // todo: Report "Unable to query system directory"
412 if (_totlower(path
[0]) == _totlower(Drive
[0]))
414 // todo: report "Cannot format system drive"
415 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
, RC_STRING_MAX_SIZE
);
422 // Determine the drive's file system format
424 if( !GetVolumeInformation( RootDirectory
,
425 volumeName
, sizeof(volumeName
)/2,
426 &serialNumber
, &maxComponent
, &flags
,
427 fileSystem
, sizeof(fileSystem
)/2)) {
429 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
430 PrintWin32Error( szMsg
, GetLastError());
434 if( !GetDiskFreeSpaceEx( RootDirectory
,
435 &freeBytesAvailableToCaller
,
437 &totalNumberOfFreeBytes
)) {
439 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
440 PrintWin32Error( szMsg
, GetLastError());
443 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FILESYSTEM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
444 _tprintf(szMsg
, fileSystem
);
447 // Make sure they want to do this
449 if( driveType
== DRIVE_FIXED
) {
451 if( volumeName
[0] ) {
455 LoadStringAndOem( GetModuleHandle(NULL
), STRING_LABEL_NAME_EDIT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
456 _tprintf(szMsg
, RootDirectory
[0] );
457 _fgetts( input
, sizeof(input
)/2, stdin
);
458 input
[ _tcslen( input
) - 1] = 0;
460 if( !_tcsicmp( input
, volumeName
)) {
464 LoadStringAndOem( GetModuleHandle(NULL
), STRING_ERROR_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
465 _tprintf("%s", szMsg
);
469 LoadStringAndOem( GetModuleHandle(NULL
), STRING_YN_FORMAT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
470 _tprintf(szMsg
, RootDirectory
[0] );
472 LoadStringAndOem( GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
475 _fgetts( input
, sizeof(input
)/2, stdin
);
476 if(_strnicmp(&input
[0],&szMsg
[0],1) == 0) break;
477 if(_strnicmp(&input
[0],&szMsg
[1],1) == 0) {
485 // Tell the user we're doing a long format if appropriate
489 LoadString( GetModuleHandle(NULL
), STRING_VERIFYING
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
491 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
493 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
497 _tprintf(_T("%s %.1fM\n"),szMsg
,
498 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
502 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FAST_FMT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
503 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
505 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
509 _tprintf(_T("%s %.2fM\n"),szMsg
,
510 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
512 LoadStringAndOem( GetModuleHandle(NULL
), STRING_CREATE_FSYS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
513 _tprintf("%s", szMsg
);
520 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
521 MultiByteToWideChar(CP_ACP
, 0, Format
, -1, FormatW
, MAX_PATH
);
522 MultiByteToWideChar(CP_ACP
, 0, Label
, -1, LabelW
, MAX_PATH
);
523 FormatEx( RootDirectoryW
, media
, FormatW
, LabelW
, QuickFormat
,
524 ClusterSize
, FormatExCallback
);
526 FormatEx( RootDirectory
, media
, Format
, Label
, QuickFormat
,
527 ClusterSize
, FormatExCallback
);
529 if( Error
) return -1;
530 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FMT_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
531 _tprintf("%s", szMsg
);
534 // Enable compression if desired
536 if( CompressDrive
) {
539 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
540 if( !EnableVolumeCompression( RootDirectoryW
, TRUE
)) {
542 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
545 LoadStringAndOem( GetModuleHandle(NULL
), STRING_VOL_COMPRESS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
546 _tprintf("%s", szMsg
);
551 // Get the label if we don't have it
555 LoadString( GetModuleHandle(NULL
), STRING_ENTER_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
556 _tprintf("%s", szMsg
);
557 _fgetts( input
, sizeof(LabelString
)/2, stdin
);
559 input
[ _tcslen(input
)-1] = 0;
560 if( !SetVolumeLabel( RootDirectory
, input
)) {
562 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
563 PrintWin32Error(szMsg
, GetLastError());
568 if( !GetVolumeInformation( RootDirectory
,
569 volumeName
, sizeof(volumeName
)/2,
570 &serialNumber
, &maxComponent
, &flags
,
571 fileSystem
, sizeof(fileSystem
)/2)) {
573 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
574 PrintWin32Error( szMsg
, GetLastError());
579 // Print out some stuff including the formatted size
581 if( !GetDiskFreeSpaceEx( RootDirectory
,
582 &freeBytesAvailableToCaller
,
584 &totalNumberOfFreeBytes
)) {
586 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
587 PrintWin32Error(szMsg
, GetLastError());
591 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FREE_SPACE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
592 _tprintf(szMsg
, totalNumberOfBytes
.QuadPart
, totalNumberOfFreeBytes
.QuadPart
);
595 // Get the drive's serial number
597 if( !GetVolumeInformation( RootDirectory
,
598 volumeName
, sizeof(volumeName
)/2,
599 &serialNumber
, &maxComponent
, &flags
,
600 fileSystem
, sizeof(fileSystem
)/2)) {
602 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
603 PrintWin32Error( szMsg
, GetLastError());
606 LoadStringAndOem( GetModuleHandle(NULL
), STRING_SERIAL_NUMBER
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
607 _tprintf(szMsg
, (unsigned int)(serialNumber
>> 16),
608 (unsigned int)(serialNumber
& 0xFFFF) );