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
);
374 if( driveType
== 0 ) {
375 LoadStringAndOem( GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
376 PrintWin32Error( szMsg
, GetLastError());
379 else if ( driveType
== 1 )
381 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
382 PrintWin32Error( szMsg
, GetLastError());
386 if( driveType
!= DRIVE_FIXED
) {
387 LoadStringAndOem( GetModuleHandle(NULL
), STRING_INSERT_DISK
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
388 _tprintf(szMsg
, RootDirectory
[0] );
389 _fgetts( input
, sizeof(input
)/2, stdin
);
391 media
= FMIFS_FLOPPY
;
395 // Determine the drive's file system format
397 if( !GetVolumeInformation( RootDirectory
,
398 volumeName
, sizeof(volumeName
)/2,
399 &serialNumber
, &maxComponent
, &flags
,
400 fileSystem
, sizeof(fileSystem
)/2)) {
402 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
403 PrintWin32Error( szMsg
, GetLastError());
407 if( !GetDiskFreeSpaceEx( RootDirectory
,
408 &freeBytesAvailableToCaller
,
410 &totalNumberOfFreeBytes
)) {
412 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
413 PrintWin32Error( szMsg
, GetLastError());
416 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FILESYSTEM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
417 _tprintf(szMsg
, fileSystem
);
420 // Make sure they want to do this
422 if( driveType
== DRIVE_FIXED
) {
424 if( volumeName
[0] ) {
428 LoadStringAndOem( GetModuleHandle(NULL
), STRING_LABEL_NAME_EDIT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
429 _tprintf(szMsg
, RootDirectory
[0] );
430 _fgetts( input
, sizeof(input
)/2, stdin
);
431 input
[ _tcslen( input
) - 1] = 0;
433 if( !_tcsicmp( input
, volumeName
)) {
437 LoadStringAndOem( GetModuleHandle(NULL
), STRING_ERROR_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
438 _tprintf("%s", szMsg
);
442 LoadStringAndOem( GetModuleHandle(NULL
), STRING_YN_FORMAT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
443 _tprintf(szMsg
, RootDirectory
[0] );
445 LoadStringAndOem( GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
448 _fgetts( input
, sizeof(input
)/2, stdin
);
449 if(_strnicmp(&input
[0],&szMsg
[0],1) == 0) break;
450 if(_strnicmp(&input
[0],&szMsg
[1],1) == 0) {
455 media
= FMIFS_HARDDISK
;
459 // Tell the user we're doing a long format if appropriate
463 LoadString( GetModuleHandle(NULL
), STRING_VERIFYING
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
465 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
467 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
471 _tprintf(_T("%s %.1fM\n"),szMsg
,
472 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
476 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FAST_FMT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
477 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
479 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
483 _tprintf(_T("%s %.2fM\n"),szMsg
,
484 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
486 LoadStringAndOem( GetModuleHandle(NULL
), STRING_CREATE_FSYS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
487 _tprintf("%s", szMsg
);
494 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
495 MultiByteToWideChar(CP_ACP
, 0, Format
, -1, FormatW
, MAX_PATH
);
496 MultiByteToWideChar(CP_ACP
, 0, Label
, -1, LabelW
, MAX_PATH
);
497 FormatEx( RootDirectoryW
, media
, FormatW
, LabelW
, QuickFormat
,
498 ClusterSize
, FormatExCallback
);
500 FormatEx( RootDirectory
, media
, Format
, Label
, QuickFormat
,
501 ClusterSize
, FormatExCallback
);
503 if( Error
) return -1;
504 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FMT_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
505 _tprintf("%s", szMsg
);
508 // Enable compression if desired
510 if( CompressDrive
) {
513 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
514 if( !EnableVolumeCompression( RootDirectoryW
, TRUE
)) {
516 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
519 LoadStringAndOem( GetModuleHandle(NULL
), STRING_VOL_COMPRESS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
520 _tprintf("%s", szMsg
);
525 // Get the label if we don't have it
529 LoadString( GetModuleHandle(NULL
), STRING_ENTER_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
530 _tprintf("%s", szMsg
);
531 _fgetts( input
, sizeof(LabelString
)/2, stdin
);
533 input
[ _tcslen(input
)-1] = 0;
534 if( !SetVolumeLabel( RootDirectory
, input
)) {
536 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
537 PrintWin32Error(szMsg
, GetLastError());
542 if( !GetVolumeInformation( RootDirectory
,
543 volumeName
, sizeof(volumeName
)/2,
544 &serialNumber
, &maxComponent
, &flags
,
545 fileSystem
, sizeof(fileSystem
)/2)) {
547 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
548 PrintWin32Error( szMsg
, GetLastError());
553 // Print out some stuff including the formatted size
555 if( !GetDiskFreeSpaceEx( RootDirectory
,
556 &freeBytesAvailableToCaller
,
558 &totalNumberOfFreeBytes
)) {
560 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
561 PrintWin32Error(szMsg
, GetLastError());
565 LoadStringAndOem( GetModuleHandle(NULL
), STRING_FREE_SPACE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
566 _tprintf(szMsg
, totalNumberOfBytes
.QuadPart
, totalNumberOfFreeBytes
.QuadPart
);
569 // Get the drive's serial number
571 if( !GetVolumeInformation( RootDirectory
,
572 volumeName
, sizeof(volumeName
)/2,
573 &serialNumber
, &maxComponent
, &flags
,
574 fileSystem
, sizeof(fileSystem
)/2)) {
576 LoadStringAndOem( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
577 PrintWin32Error( szMsg
, GetLastError());
580 LoadStringAndOem( GetModuleHandle(NULL
), STRING_SERIAL_NUMBER
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
581 _tprintf(szMsg
, (unsigned int)(serialNumber
>> 16),
582 (unsigned int)(serialNumber
& 0xFFFF) );