1 // Copyright (c) 1998 Mark Russinovich
3 // http://www.sysinternals.com
16 BOOL QuickFormat
= FALSE
;
17 DWORD ClusterSize
= 0;
18 BOOL CompressDrive
= FALSE
;
19 BOOL GotALabel
= FALSE
;
20 LPTSTR Label
= _T("");
22 LPTSTR Format
= _T("FAT");
24 TCHAR RootDirectory
[MAX_PATH
];
25 TCHAR LabelString
[12];
33 } SIZEDEFINITION
, *PSIZEDEFINITION
;
35 SIZEDEFINITION LegalSizes
[] = {
44 { _T("128K"), 65536 * 2 },
45 { _T("256K"), 65536 * 4 },
50 //----------------------------------------------------------------------
54 // Takes the win32 error code and prints the text version.
56 //----------------------------------------------------------------------
57 static VOID
PrintWin32Error( LPTSTR Message
, DWORD ErrorCode
)
61 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
63 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
64 (LPTSTR
)&lpMsgBuf
, 0, NULL
);
66 _tprintf(_T("%S: %S\n"), Message
, lpMsgBuf
);
67 LocalFree( lpMsgBuf
);
71 //----------------------------------------------------------------------
75 // Tell the user how to use the program
77 //----------------------------------------------------------------------
78 static VOID
Usage( LPTSTR ProgramName
)
80 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
81 LoadString( GetModuleHandle(NULL
), STRING_HELP
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
82 _tprintf(szMsg
, ProgramName
);
86 //----------------------------------------------------------------------
92 //----------------------------------------------------------------------
93 static int ParseCommandLine( int argc
, TCHAR
*argv
[] )
96 BOOLEAN gotFormat
= FALSE
;
97 BOOLEAN gotQuick
= FALSE
;
98 BOOLEAN gotSize
= FALSE
;
99 BOOLEAN gotLabel
= FALSE
;
100 BOOLEAN gotCompressed
= FALSE
;
103 for( i
= 1; i
< argc
; i
++ ) {
105 switch( argv
[i
][0] ) {
110 if( !_tcsnicmp( &argv
[i
][1], _T("FS:"), 3 )) {
112 if( gotFormat
) return -1;
113 Format
= &argv
[i
][4];
117 } else if( !_tcsnicmp( &argv
[i
][1], _T("A:"), 2 )) {
119 if( gotSize
) return -1;
121 while( LegalSizes
[j
].ClusterSize
&&
122 _tcsicmp( LegalSizes
[j
].SizeString
, &argv
[i
][3] )) j
++;
124 if( !LegalSizes
[j
].ClusterSize
) return i
;
125 ClusterSize
= LegalSizes
[j
].ClusterSize
;
128 } else if( ! _tcsnicmp( &argv
[i
][1], _T("V:"), 2 )) {
130 if( gotLabel
) return -1;
135 } else if( !_tcsicmp( &argv
[i
][1], _T("Q") )) {
137 if( gotQuick
) return -1;
141 } else if( !_tcsicmp( &argv
[i
][1], _T("C") )) {
143 if( gotCompressed
) return -1;
144 CompressDrive
= TRUE
;
145 gotCompressed
= TRUE
;
152 if( Drive
) return i
;
153 if( argv
[i
][1] != _T(':') ) return i
;
162 //----------------------------------------------------------------------
166 // The file system library will call us back with commands that we
167 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
169 //----------------------------------------------------------------------
171 FormatExCallback (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 LoadString( 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 LoadString( GetModuleHandle(NULL
), STRING_FORMAT_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
205 case DONEWITHSTRUCTURE
:
210 case INSUFFICIENTRIGHTS
:
217 case STRUCTUREPROGRESS
:
218 LoadString( GetModuleHandle(NULL
), STRING_NO_SUPPORT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
226 //----------------------------------------------------------------------
228 // LoadFMIFSEntryPoints
230 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
232 //----------------------------------------------------------------------
233 BOOLEAN
LoadFMIFSEntryPoints()
235 HMODULE hFmifs
= LoadLibrary( _T("fmifs.dll") );
236 if( !(void*) GetProcAddress( hFmifs
, "FormatEx" ) ) {
241 if( !((void *) GetProcAddress( hFmifs
,
242 "EnableVolumeCompression" )) ) {
249 //----------------------------------------------------------------------
253 // Engine. Just get command line switches and fire off a format. This
254 // could also be done in a GUI like Explorer does when you select a
255 // drive and run a check on it.
257 // We do this in UNICODE because the chkdsk command expects PWCHAR
260 //----------------------------------------------------------------------
262 _tmain(int argc
, TCHAR
*argv
[])
265 DWORD media
= FMIFS_HARDDISK
;
267 TCHAR fileSystem
[1024];
268 TCHAR volumeName
[1024];
271 DWORD flags
, maxComponent
;
272 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
274 WCHAR RootDirectoryW
[MAX_PATH
], FormatW
[MAX_PATH
], LabelW
[MAX_PATH
];
276 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
279 // Get function pointers
281 if( !LoadFMIFSEntryPoints()) {
283 LoadString( GetModuleHandle(NULL
), STRING_FMIFS_FAIL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
289 // Parse command line
291 if( (badArg
= ParseCommandLine( argc
, argv
))) {
293 LoadString( GetModuleHandle(NULL
), STRING_UNKNOW_ARG
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
294 _tprintf(szMsg
, argv
[badArg
] );
301 // Get the drive's format
305 LoadString( GetModuleHandle(NULL
), STRING_DRIVE_PARM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
312 _tcscpy( RootDirectory
, Drive
);
314 RootDirectory
[2] = _T('\\');
315 RootDirectory
[3] = _T('\0');
318 // See if the drive is removable or not
320 driveType
= GetDriveType( RootDirectory
);
322 if( driveType
== 0 ) {
323 LoadString( GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
324 PrintWin32Error( szMsg
, GetLastError());
328 if( driveType
!= DRIVE_FIXED
) {
329 LoadString( GetModuleHandle(NULL
), STRING_INSERT_DISK
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
330 _tprintf(szMsg
, RootDirectory
[0] );
331 _fgetts( input
, sizeof(input
)/2, stdin
);
333 media
= FMIFS_FLOPPY
;
337 // Determine the drive's file system format
339 if( !GetVolumeInformation( RootDirectory
,
340 volumeName
, sizeof(volumeName
)/2,
341 &serialNumber
, &maxComponent
, &flags
,
342 fileSystem
, sizeof(fileSystem
)/2)) {
344 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
345 PrintWin32Error( szMsg
, GetLastError());
349 if( !GetDiskFreeSpaceEx( RootDirectory
,
350 &freeBytesAvailableToCaller
,
352 &totalNumberOfFreeBytes
)) {
354 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
355 PrintWin32Error( szMsg
, GetLastError());
358 LoadString( GetModuleHandle(NULL
), STRING_FILESYSTEM
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
359 _tprintf(szMsg
, fileSystem
);
362 // Make sure they want to do this
364 if( driveType
== DRIVE_FIXED
) {
366 if( volumeName
[0] ) {
370 LoadString( GetModuleHandle(NULL
), STRING_LABEL_NAME_EDIT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
371 _tprintf(szMsg
, RootDirectory
[0] );
372 _fgetts( input
, sizeof(input
)/2, stdin
);
373 input
[ _tcslen( input
) - 1] = 0;
375 if( !_tcsicmp( input
, volumeName
)) {
379 LoadString( GetModuleHandle(NULL
), STRING_ERROR_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
386 LoadString( GetModuleHandle(NULL
), STRING_YN_FORMAT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
387 _tprintf(szMsg
, RootDirectory
[0] );
390 LoadString( GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
392 if( _strnicmp(&input
[0],&szMsg
[0],1)) break;
394 if( _strnicmp(&input
[0],&szMsg
[1],1) ) {
400 media
= FMIFS_HARDDISK
;
404 // Tell the user we're doing a long format if appropriate
408 LoadString( GetModuleHandle(NULL
), STRING_VERIFYING
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
410 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
412 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
416 _tprintf(_T("%s %.1fM\n"),szMsg
,
417 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
421 LoadString( GetModuleHandle(NULL
), STRING_FAST_FMT
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
422 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
424 _tprintf(_T("%s %luM\n"),szMsg
, (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
428 _tprintf(_T("%s %.2fM\n"),szMsg
,
429 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
431 LoadString( GetModuleHandle(NULL
), STRING_CREATE_FSYS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
439 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
440 MultiByteToWideChar(CP_ACP
, 0, Format
, -1, FormatW
, MAX_PATH
);
441 MultiByteToWideChar(CP_ACP
, 0, Label
, -1, LabelW
, MAX_PATH
);
442 FormatEx( RootDirectoryW
, media
, FormatW
, LabelW
, QuickFormat
,
443 ClusterSize
, FormatExCallback
);
445 FormatEx( RootDirectory
, media
, Format
, Label
, QuickFormat
,
446 ClusterSize
, FormatExCallback
);
448 if( Error
) return -1;
449 LoadString( GetModuleHandle(NULL
), STRING_FMT_COMPLETE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
453 // Enable compression if desired
455 if( CompressDrive
) {
458 MultiByteToWideChar(CP_ACP
, 0, RootDirectory
, -1, RootDirectoryW
, MAX_PATH
);
459 if( !EnableVolumeCompression( RootDirectoryW
, TRUE
)) {
461 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
464 LoadString( GetModuleHandle(NULL
), STRING_VOL_COMPRESS
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
470 // Get the label if we don't have it
474 LoadString( GetModuleHandle(NULL
), STRING_ENTER_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
476 _fgetts( input
, sizeof(LabelString
)/2, stdin
);
478 input
[ _tcslen(input
)-1] = 0;
479 if( !SetVolumeLabel( RootDirectory
, input
)) {
481 LoadString( GetModuleHandle(NULL
), STRING_NO_LABEL
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
482 PrintWin32Error(szMsg
, GetLastError());
487 if( !GetVolumeInformation( RootDirectory
,
488 volumeName
, sizeof(volumeName
)/2,
489 &serialNumber
, &maxComponent
, &flags
,
490 fileSystem
, sizeof(fileSystem
)/2)) {
492 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
493 PrintWin32Error( szMsg
, GetLastError());
498 // Print out some stuff including the formatted size
500 if( !GetDiskFreeSpaceEx( RootDirectory
,
501 &freeBytesAvailableToCaller
,
503 &totalNumberOfFreeBytes
)) {
505 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
506 PrintWin32Error(szMsg
, GetLastError());
510 LoadString( GetModuleHandle(NULL
), STRING_FREE_SPACE
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
511 _tprintf(szMsg
, totalNumberOfBytes
.QuadPart
, totalNumberOfFreeBytes
.QuadPart
);
514 // Get the drive's serial number
516 if( !GetVolumeInformation( RootDirectory
,
517 volumeName
, sizeof(volumeName
)/2,
518 &serialNumber
, &maxComponent
, &flags
,
519 fileSystem
, sizeof(fileSystem
)/2)) {
521 LoadString( GetModuleHandle(NULL
), STRING_NO_VOLUME
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
522 PrintWin32Error( szMsg
, GetLastError());
525 LoadString( GetModuleHandle(NULL
), STRING_SERIAL_NUMBER
, (LPTSTR
) szMsg
,RC_STRING_MAX_SIZE
);
526 _tprintf(szMsg
, (unsigned int)(serialNumber
>> 16),
527 (unsigned int)(serialNumber
& 0xFFFF) );