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 //----------------------------------------------------------------------
55 // Takes the win32 error code and prints the text version.
57 //----------------------------------------------------------------------
58 static VOID
PrintWin32Error( LPTSTR Message
, DWORD ErrorCode
)
62 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
64 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
65 (LPTSTR
)&lpMsgBuf
, 0, NULL
);
67 _tprintf(_T("%s: %s\n"), Message
, lpMsgBuf
);
68 LocalFree( lpMsgBuf
);
72 //----------------------------------------------------------------------
78 //----------------------------------------------------------------------
79 static int ParseCommandLine( int argc
, TCHAR
*argv
[] )
82 BOOLEAN gotFormat
= FALSE
;
83 BOOLEAN gotQuick
= FALSE
;
84 BOOLEAN gotSize
= FALSE
;
85 BOOLEAN gotLabel
= FALSE
;
86 BOOLEAN gotCompressed
= FALSE
;
89 for( i
= 1; i
< argc
; i
++ ) {
91 switch( argv
[i
][0] ) {
96 if( !_tcsnicmp( &argv
[i
][1], _T("FS:"), 3 )) {
98 if( gotFormat
) return -1;
103 } else if( !_tcsnicmp( &argv
[i
][1], _T("A:"), 2 )) {
105 if( gotSize
) return -1;
107 while( LegalSizes
[j
].ClusterSize
&&
108 _tcsicmp( LegalSizes
[j
].SizeString
, &argv
[i
][3] )) j
++;
110 if( !LegalSizes
[j
].ClusterSize
) return i
;
111 ClusterSize
= LegalSizes
[j
].ClusterSize
;
114 } else if( ! _tcsnicmp( &argv
[i
][1], _T("V:"), 2 )) {
116 if( gotLabel
) return -1;
121 } else if( !_tcsicmp( &argv
[i
][1], _T("Q") )) {
123 if( gotQuick
) return -1;
127 } else if( !_tcsicmp( &argv
[i
][1], _T("C") )) {
129 if( gotCompressed
) return -1;
130 CompressDrive
= TRUE
;
131 gotCompressed
= TRUE
;
138 if( Drive
) return i
;
139 if( argv
[i
][1] != _T(':') ) return i
;
148 //----------------------------------------------------------------------
152 // The file system library will call us back with commands that we
153 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
155 //----------------------------------------------------------------------
158 CALLBACKCOMMAND Command
,
165 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
168 // We get other types of commands, but we don't have to pay attention to them
173 percent
= (PDWORD
) Argument
;
174 LoadString( GetModuleHandle(NULL
), STRING_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
175 _tprintf(szMsg
, *percent
);
179 output
= (PTEXTOUTPUT
) Argument
;
180 fprintf(stdout
, "%s", output
->Output
);
184 status
= (PBOOLEAN
) Argument
;
185 if( *status
== FALSE
) {
187 LoadString( GetModuleHandle(NULL
), STRING_FORMAT_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
188 _tprintf("%s", szMsg
);
192 case DONEWITHSTRUCTURE
:
197 case INSUFFICIENTRIGHTS
:
204 case STRUCTUREPROGRESS
:
205 case CLUSTERSIZETOOSMALL
:
206 LoadString( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
207 _tprintf("%s", szMsg
);
214 //----------------------------------------------------------------------
216 // LoadFMIFSEntryPoints
218 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
220 //----------------------------------------------------------------------
221 BOOLEAN
LoadFMIFSEntryPoints()
223 HMODULE hFmifs
= LoadLibrary( _T("fmifs.dll") );
224 if( !(void*) GetProcAddress( hFmifs
, "FormatEx" ) ) {
229 if( !((void *) GetProcAddress( hFmifs
,
230 "EnableVolumeCompression" )) ) {
235 if( !((void *) GetProcAddress( hFmifs
,
236 "QueryAvailableFileSystemFormat" )) ) {
245 //----------------------------------------------------------------------
249 // Tell the user how to use the program
251 //----------------------------------------------------------------------
252 static VOID
Usage( LPTSTR ProgramName
)
254 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
255 TCHAR szFormats
[MAX_PATH
];
257 TCHAR szFormatA
[MAX_PATH
];
259 WCHAR szFormatW
[MAX_PATH
];
262 BOOLEAN lastestVersion
;
264 LoadString( GetModuleHandle(NULL
), STRING_HELP
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
265 if (!LoadFMIFSEntryPoints())
267 _tprintf(szMsg
, ProgramName
, _T(""));
272 while (QueryAvailableFileSystemFormat(Index
++, szFormatW
, &dummy
, &dummy
, &lastestVersion
))
277 _tcscat(szFormats
, _T(", "));
279 _tcscat(szFormats
, szFormatW
);
281 if (0 != WideCharToMultiByte(CP_ACP
, 0, szFormatW
, -1, szFormatA
, sizeof(szFormatA
), NULL
, NULL
))
282 _tcscat(szFormats
, szFormatA
);
285 _tprintf(szMsg
, ProgramName
, szFormats
);
289 //----------------------------------------------------------------------
293 // Engine. Just get command line switches and fire off a format. This
294 // could also be done in a GUI like Explorer does when you select a
295 // drive and run a check on it.
297 // We do this in UNICODE because the chkdsk command expects PWCHAR
300 //----------------------------------------------------------------------
302 _tmain(int argc
, TCHAR
*argv
[])
305 DWORD media
= FMIFS_HARDDISK
;
307 TCHAR fileSystem
[1024];
308 TCHAR volumeName
[1024];
311 DWORD flags
, maxComponent
;
312 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
314 WCHAR RootDirectoryW
[MAX_PATH
], FormatW
[MAX_PATH
], LabelW
[MAX_PATH
];
316 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
319 // Get function pointers
321 if( !LoadFMIFSEntryPoints()) {
322 LoadString( GetModuleHandle(NULL
), STRING_FMIFS_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
323 _tprintf("%s", szMsg
);
328 // Parse command line
330 if( (badArg
= ParseCommandLine( argc
, argv
))) {
332 LoadString( GetModuleHandle(NULL
), STRING_UNKNOW_ARG
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
333 _tprintf(szMsg
, argv
[badArg
] );
340 // Get the drive's format
344 LoadString( GetModuleHandle(NULL
), STRING_DRIVE_PARM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
351 _tcscpy( RootDirectory
, Drive
);
353 RootDirectory
[2] = _T('\\');
354 RootDirectory
[3] = _T('\0');
357 // See if the drive is removable or not
359 driveType
= GetDriveType( RootDirectory
);
361 if( driveType
== 0 ) {
362 LoadString( GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
363 PrintWin32Error( szMsg
, GetLastError());
366 else if ( driveType
== 1 )
368 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
369 PrintWin32Error( szMsg
, GetLastError());
373 if( driveType
!= DRIVE_FIXED
) {
374 LoadString( GetModuleHandle(NULL
), STRING_INSERT_DISK
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
375 _tprintf(szMsg
, RootDirectory
[0] );
376 _fgetts( input
, sizeof(input
)/2, stdin
);
378 media
= FMIFS_FLOPPY
;
382 // Determine the drive's file system format
384 if( !GetVolumeInformation( RootDirectory
,
385 volumeName
, sizeof(volumeName
)/2,
386 &serialNumber
, &maxComponent
, &flags
,
387 fileSystem
, sizeof(fileSystem
)/2)) {
389 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
390 PrintWin32Error( szMsg
, GetLastError());
394 if( !GetDiskFreeSpaceEx( RootDirectory
,
395 &freeBytesAvailableToCaller
,
397 &totalNumberOfFreeBytes
)) {
399 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
400 PrintWin32Error( szMsg
, GetLastError());
403 LoadString( GetModuleHandle(NULL
), STRING_FILESYSTEM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
404 _tprintf(szMsg
, fileSystem
);
407 // Make sure they want to do this
409 if( driveType
== DRIVE_FIXED
) {
411 if( volumeName
[0] ) {
415 LoadString( GetModuleHandle(NULL
), STRING_LABEL_NAME_EDIT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
416 _tprintf(szMsg
, RootDirectory
[0] );
417 _fgetts( input
, sizeof(input
)/2, stdin
);
418 input
[ _tcslen( input
) - 1] = 0;
420 if( !_tcsicmp( input
, volumeName
)) {
424 LoadString( GetModuleHandle(NULL
), STRING_ERROR_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
425 _tprintf("%s", szMsg
);
429 LoadString( GetModuleHandle(NULL
), STRING_YN_FORMAT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
430 _tprintf(szMsg
, RootDirectory
[0] );
432 LoadString( GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
435 _fgetts( input
, sizeof(input
)/2, stdin
);
436 if(_strnicmp(&input
[0],&szMsg
[0],1) == 0) break;
437 if(_strnicmp(&input
[0],&szMsg
[1],1) == 0) {
442 media
= FMIFS_HARDDISK
;
446 // Tell the user we're doing a long format if appropriate
450 LoadString( GetModuleHandle(NULL
), STRING_VERIFYING
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
452 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
454 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
458 _tprintf(_T("%s %.1fM\n"),szMsg
,
459 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
463 LoadString( GetModuleHandle(NULL
), STRING_FAST_FMT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
464 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
466 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
470 _tprintf(_T("%s %.2fM\n"),szMsg
,
471 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
473 LoadString( GetModuleHandle(NULL
), STRING_CREATE_FSYS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
474 _tprintf("%s", szMsg
);
481 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
482 MultiByteToWideChar(CP_ACP
, 0, Format
, -1, FormatW
, MAX_PATH
);
483 MultiByteToWideChar(CP_ACP
, 0, Label
, -1, LabelW
, MAX_PATH
);
484 FormatEx( RootDirectoryW
, media
, FormatW
, LabelW
, QuickFormat
,
485 ClusterSize
, FormatExCallback
);
487 FormatEx( RootDirectory
, media
, Format
, Label
, QuickFormat
,
488 ClusterSize
, FormatExCallback
);
490 if( Error
) return -1;
491 LoadString( GetModuleHandle(NULL
), STRING_FMT_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
492 _tprintf("%s", szMsg
);
495 // Enable compression if desired
497 if( CompressDrive
) {
500 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
501 if( !EnableVolumeCompression( RootDirectoryW
, TRUE
)) {
503 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
506 LoadString( GetModuleHandle(NULL
), STRING_VOL_COMPRESS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
507 _tprintf("%s", szMsg
);
512 // Get the label if we don't have it
516 LoadString( GetModuleHandle(NULL
), STRING_ENTER_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
517 _tprintf("%s", szMsg
);
518 _fgetts( input
, sizeof(LabelString
)/2, stdin
);
520 input
[ _tcslen(input
)-1] = 0;
521 if( !SetVolumeLabel( RootDirectory
, input
)) {
523 LoadString( GetModuleHandle(NULL
), STRING_NO_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
524 PrintWin32Error(szMsg
, GetLastError());
529 if( !GetVolumeInformation( RootDirectory
,
530 volumeName
, sizeof(volumeName
)/2,
531 &serialNumber
, &maxComponent
, &flags
,
532 fileSystem
, sizeof(fileSystem
)/2)) {
534 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
535 PrintWin32Error( szMsg
, GetLastError());
540 // Print out some stuff including the formatted size
542 if( !GetDiskFreeSpaceEx( RootDirectory
,
543 &freeBytesAvailableToCaller
,
545 &totalNumberOfFreeBytes
)) {
547 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
548 PrintWin32Error(szMsg
, GetLastError());
552 LoadString( GetModuleHandle(NULL
), STRING_FREE_SPACE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
553 _tprintf(szMsg
, totalNumberOfBytes
.QuadPart
, totalNumberOfFreeBytes
.QuadPart
);
556 // Get the drive's serial number
558 if( !GetVolumeInformation( RootDirectory
,
559 volumeName
, sizeof(volumeName
)/2,
560 &serialNumber
, &maxComponent
, &flags
,
561 fileSystem
, sizeof(fileSystem
)/2)) {
563 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
564 PrintWin32Error( szMsg
, GetLastError());
567 LoadString( GetModuleHandle(NULL
), STRING_SERIAL_NUMBER
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
568 _tprintf(szMsg
, (unsigned int)(serialNumber
>> 16),
569 (unsigned int)(serialNumber
& 0xFFFF) );