1 // Copyright (c) 1998 Mark Russinovich
3 // http://www.sysinternals.com
14 BOOL QuickFormat
= FALSE
;
15 DWORD ClusterSize
= 0;
16 BOOL CompressDrive
= FALSE
;
17 BOOL GotALabel
= FALSE
;
20 PWCHAR Format
= L
"FAT";
22 WCHAR RootDirectory
[MAX_PATH
];
23 WCHAR LabelString
[12];
31 } SIZEDEFINITION
, *PSIZEDEFINITION
;
33 SIZEDEFINITION LegalSizes
[] = {
42 { L
"128K", 65536 * 2 },
43 { L
"256K", 65536 * 4 },
48 //----------------------------------------------------------------------
52 // Takes the win32 error code and prints the text version.
54 //----------------------------------------------------------------------
55 void PrintWin32Error( PWCHAR Message
, DWORD ErrorCode
)
59 FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
61 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
62 (PWCHAR
) &lpMsgBuf
, 0, NULL
);
63 printf("%S: %S\n", Message
, lpMsgBuf
);
64 LocalFree( lpMsgBuf
);
68 //----------------------------------------------------------------------
72 // Tell the user how to use the program
74 //----------------------------------------------------------------------
75 VOID
Usage( PWCHAR ProgramName
)
77 printf("Usage: %S drive: [-FS:file-system] [-V:label] [-Q] [-A:size] [-C]\n\n", ProgramName
);
78 printf(" [drive:] Specifies the drive to format.\n");
79 printf(" -FS:file-system Specifies the type of file system (e.g. FAT).\n");
80 printf(" -V:label Specifies volume label.\n");
81 printf(" -Q Performs a quick format.\n");
82 printf(" -A:size Overrides the default allocation unit size. Default settings\n");
83 printf(" are strongly recommended for general use\n");
84 printf(" NTFS supports 512, 1024, 2048, 4096, 8192, 16K, 32K, 64K.\n");
85 printf(" FAT supports 8192, 16K, 32K, 64K, 128K, 256K.\n");
86 printf(" NTFS compression is not supported for allocation unit sizes\n");
87 printf(" above 4096.\n");
88 printf(" -C Files created on the new volume will be compressed by\n");
89 printf(" default.\n");
94 //----------------------------------------------------------------------
100 //----------------------------------------------------------------------
101 int ParseCommandLine( int argc
, WCHAR
*argv
[] )
104 BOOLEAN gotFormat
= FALSE
;
105 BOOLEAN gotQuick
= FALSE
;
106 BOOLEAN gotSize
= FALSE
;
107 BOOLEAN gotLabel
= FALSE
;
108 BOOLEAN gotCompressed
= FALSE
;
111 for( i
= 1; i
< argc
; i
++ ) {
113 switch( argv
[i
][0] ) {
118 if( !wcsnicmp( &argv
[i
][1], L
"FS:", 3 )) {
120 if( gotFormat
) return -1;
121 Format
= &argv
[i
][4];
125 } else if( !wcsnicmp( &argv
[i
][1], L
"A:", 2 )) {
127 if( gotSize
) return -1;
129 while( LegalSizes
[j
].ClusterSize
&&
130 wcsicmp( LegalSizes
[j
].SizeString
, &argv
[i
][3] )) j
++;
132 if( !LegalSizes
[j
].ClusterSize
) return i
;
133 ClusterSize
= LegalSizes
[j
].ClusterSize
;
136 } else if( !wcsnicmp( &argv
[i
][1], L
"V:", 2 )) {
138 if( gotLabel
) return -1;
143 } else if( !wcsicmp( &argv
[i
][1], L
"Q" )) {
145 if( gotQuick
) return -1;
149 } else if( !wcsicmp( &argv
[i
][1], L
"C" )) {
151 if( gotCompressed
) return -1;
152 CompressDrive
= TRUE
;
153 gotCompressed
= TRUE
;
160 if( Drive
) return i
;
161 if( argv
[i
][1] != L
':' ) return i
;
170 //----------------------------------------------------------------------
174 // The file system library will call us back with commands that we
175 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
177 //----------------------------------------------------------------------
178 BOOL __stdcall
FormatExCallback( CALLBACKCOMMAND Command
, DWORD Modifier
, PVOID Argument
)
185 // We get other types of commands, but we don't have to pay attention to them
190 percent
= (PDWORD
) Argument
;
191 printf("%lu percent completed.\r", *percent
);
195 output
= (PTEXTOUTPUT
) Argument
;
196 fprintf(stdout
, "%s", output
->Output
);
200 status
= (PBOOLEAN
) Argument
;
201 if( *status
== FALSE
) {
203 printf("FormatEx was unable to complete successfully.\n\n");
207 case DONEWITHSTRUCTURE
:
212 case INSUFFICIENTRIGHTS
:
219 case STRUCTUREPROGRESS
:
220 printf("Operation Not Supported");
227 //----------------------------------------------------------------------
229 // LoadFMIFSEntryPoints
231 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
233 //----------------------------------------------------------------------
234 BOOLEAN
LoadFMIFSEntryPoints()
236 LoadLibrary( "fmifs.dll" );
237 if( !(void*) GetProcAddress( GetModuleHandle( "fmifs.dll"), "FormatEx" ) ) {
242 if( !((void *) GetProcAddress( GetModuleHandle( "fmifs.dll"),
243 "EnableVolumeCompression" )) ) {
250 //----------------------------------------------------------------------
254 // Engine. Just get command line switches and fire off a format. This
255 // could also be done in a GUI like Explorer does when you select a
256 // drive and run a check on it.
258 // We do this in UNICODE because the chkdsk command expects PWCHAR
261 //----------------------------------------------------------------------
262 int wmain( int argc
, WCHAR
*argv
[] )
267 WCHAR fileSystem
[1024];
268 WCHAR volumeName
[1024];
271 DWORD flags
, maxComponent
;
272 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
275 // Get function pointers
277 if( !LoadFMIFSEntryPoints()) {
279 printf("Could not located FMIFS entry points.\n\n");
284 // Parse command line
286 if( (badArg
= ParseCommandLine( argc
, argv
))) {
288 printf("Unknown argument: %S\n", argv
[badArg
] );
295 // Get the drive's format
299 printf("Required drive parameter is missing.\n\n");
305 wcscpy( RootDirectory
, Drive
);
307 RootDirectory
[2] = L
'\\';
308 RootDirectory
[3] = (WCHAR
) 0;
311 // See if the drive is removable or not
313 driveType
= GetDriveTypeW( RootDirectory
);
315 if( driveType
== 0 ) {
316 PrintWin32Error( L
"Could not get drive type", GetLastError());
320 if( driveType
!= DRIVE_FIXED
) {
322 printf("Insert a new floppy in drive %C:\nand press Enter when ready...",
324 fgetws( input
, sizeof(input
)/2, stdin
);
326 media
= FMIFS_FLOPPY
;
329 driveType
= DRIVE_FIXED
;
330 media
= FMIFS_HARDDISK
;
336 // Determine the drive's file system format
338 if( !GetVolumeInformationW( RootDirectory
,
339 volumeName
, sizeof(volumeName
)/2,
340 &serialNumber
, &maxComponent
, &flags
,
341 fileSystem
, sizeof(fileSystem
)/2)) {
343 PrintWin32Error( L
"Could not query volume", GetLastError());
347 if( !GetDiskFreeSpaceExW( RootDirectory
,
348 &freeBytesAvailableToCaller
,
350 &totalNumberOfFreeBytes
)) {
352 PrintWin32Error( L
"Could not query volume size", GetLastError());
355 printf("The type of the file system is %S.\n", fileSystem
);
358 // Make sure they want to do this
360 if( driveType
== DRIVE_FIXED
) {
362 if( volumeName
[0] ) {
366 printf("Enter current volume label for drive %C: ", RootDirectory
[0] );
367 fgetws( input
, sizeof(input
)/2, stdin
);
368 input
[ wcslen( input
) - 1] = 0;
370 if( !wcsicmp( input
, volumeName
)) {
374 printf("An incorrect volume label was entered for this drive.\n");
380 printf("\nWARNING, ALL DATA ON NON_REMOVABLE DISK\n");
381 printf("DRIVE %C: WILL BE LOST!\n", RootDirectory
[0] );
382 printf("Proceed with Format (Y/N)? " );
383 fgetws( input
, sizeof(input
)/2, stdin
);
385 if( input
[0] == L
'Y' || input
[0] == L
'y' ) break;
387 if( input
[0] == L
'N' || input
[0] == L
'n' ) {
393 media
= FMIFS_HARDDISK
;
397 // Tell the user we're doing a long format if appropriate
401 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
403 printf("Verifying %luM\n", (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
407 printf("Verifying %.1fM\n",
408 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
412 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
414 printf("QuickFormatting %luM\n", (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
418 printf("QuickFormatting %.2fM\n",
419 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
421 printf("Creating file system structures.\n");
427 FormatEx( RootDirectory
, media
, Format
, Label
, QuickFormat
,
428 ClusterSize
, FormatExCallback
);
429 if( Error
) return -1;
430 printf("Format complete.\n");
433 // Enable compression if desired
435 if( CompressDrive
) {
437 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
439 printf("Volume does not support compression.\n");
444 // Get the label if we don't have it
448 printf("Volume Label (11 characters, Enter for none)? " );
449 fgetws( input
, sizeof(LabelString
)/2, stdin
);
451 input
[ wcslen(input
)-1] = 0;
452 if( !SetVolumeLabelW( RootDirectory
, input
)) {
454 PrintWin32Error(L
"Could not label volume", GetLastError());
459 if( !GetVolumeInformationW( RootDirectory
,
460 volumeName
, sizeof(volumeName
)/2,
461 &serialNumber
, &maxComponent
, &flags
,
462 fileSystem
, sizeof(fileSystem
)/2)) {
464 PrintWin32Error( L
"Could not query volume", GetLastError());
469 // Print out some stuff including the formatted size
471 if( !GetDiskFreeSpaceExW( RootDirectory
,
472 &freeBytesAvailableToCaller
,
474 &totalNumberOfFreeBytes
)) {
476 PrintWin32Error( L
"Could not query volume size", GetLastError());
480 printf("\n%I64d bytes total disk space.\n", totalNumberOfBytes
.QuadPart
);
481 printf("%I64d bytes available on disk.\n", totalNumberOfFreeBytes
.QuadPart
);
484 // Get the drive's serial number
486 if( !GetVolumeInformationW( RootDirectory
,
487 volumeName
, sizeof(volumeName
)/2,
488 &serialNumber
, &maxComponent
, &flags
,
489 fileSystem
, sizeof(fileSystem
)/2)) {
491 PrintWin32Error( L
"Could not query volume", GetLastError());
494 printf("\nVolume Serial Number is %04X-%04X\n", (unsigned int)(serialNumber
>> 16),
495 (unsigned int)(serialNumber
& 0xFFFF) );
500 int main(int argc
, char* argv
[])
508 wargv
= (PWCHAR
*) RtlAllocateHeap(RtlGetProcessHeap(), 0, argc
* sizeof(PWCHAR
));
510 for (i
= 0; i
< argc
; i
++)
512 RtlInitAnsiString(&arg
, argv
[i
]);
513 status
= RtlAnsiStringToUnicodeString(&warg
, &arg
, TRUE
);
514 if (!NT_SUCCESS (status
))
516 printf("Not enough free memory.\n");
519 wargv
[i
] = (PWCHAR
) warg
.Buffer
;
524 for (i
= 0; i
< argc
; i
++)
526 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv
[i
]);
528 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv
);