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 //----------------------------------------------------------------------
179 FormatExCallback (CALLBACKCOMMAND Command
,
188 // We get other types of commands, but we don't have to pay attention to them
193 percent
= (PDWORD
) Argument
;
194 printf("%lu percent completed.\r", *percent
);
198 output
= (PTEXTOUTPUT
) Argument
;
199 fprintf(stdout
, "%s", output
->Output
);
203 status
= (PBOOLEAN
) Argument
;
204 if( *status
== FALSE
) {
206 printf("FormatEx was unable to complete successfully.\n\n");
210 case DONEWITHSTRUCTURE
:
215 case INSUFFICIENTRIGHTS
:
222 case STRUCTUREPROGRESS
:
223 printf("Operation Not Supported");
230 //----------------------------------------------------------------------
232 // LoadFMIFSEntryPoints
234 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
236 //----------------------------------------------------------------------
237 BOOLEAN
LoadFMIFSEntryPoints()
239 LoadLibrary( "fmifs.dll" );
240 if( !(void*) GetProcAddress( GetModuleHandle( "fmifs.dll"), "FormatEx" ) ) {
245 if( !((void *) GetProcAddress( GetModuleHandle( "fmifs.dll"),
246 "EnableVolumeCompression" )) ) {
253 //----------------------------------------------------------------------
257 // Engine. Just get command line switches and fire off a format. This
258 // could also be done in a GUI like Explorer does when you select a
259 // drive and run a check on it.
261 // We do this in UNICODE because the chkdsk command expects PWCHAR
264 //----------------------------------------------------------------------
265 int wmain( int argc
, WCHAR
*argv
[] )
268 DWORD media
= FMIFS_HARDDISK
;
270 WCHAR fileSystem
[1024];
271 WCHAR volumeName
[1024];
274 DWORD flags
, maxComponent
;
275 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
278 // Get function pointers
280 if( !LoadFMIFSEntryPoints()) {
282 printf("Could not located FMIFS entry points.\n\n");
287 // Parse command line
289 if( (badArg
= ParseCommandLine( argc
, argv
))) {
291 printf("Unknown argument: %S\n", argv
[badArg
] );
298 // Get the drive's format
302 printf("Required drive parameter is missing.\n\n");
308 wcscpy( RootDirectory
, Drive
);
310 RootDirectory
[2] = L
'\\';
311 RootDirectory
[3] = (WCHAR
) 0;
314 // See if the drive is removable or not
316 driveType
= GetDriveTypeW( RootDirectory
);
318 if( driveType
== 0 ) {
319 PrintWin32Error( L
"Could not get drive type", GetLastError());
323 if( driveType
!= DRIVE_FIXED
) {
324 printf("Insert a new floppy in drive %C:\nand press Enter when ready...",
326 fgetws( input
, sizeof(input
)/2, stdin
);
328 media
= FMIFS_FLOPPY
;
332 // Determine the drive's file system format
334 if( !GetVolumeInformationW( RootDirectory
,
335 volumeName
, sizeof(volumeName
)/2,
336 &serialNumber
, &maxComponent
, &flags
,
337 fileSystem
, sizeof(fileSystem
)/2)) {
339 PrintWin32Error( L
"Could not query volume", GetLastError());
343 if( !GetDiskFreeSpaceExW( RootDirectory
,
344 &freeBytesAvailableToCaller
,
346 &totalNumberOfFreeBytes
)) {
348 PrintWin32Error( L
"Could not query volume size", GetLastError());
351 printf("The type of the file system is %S.\n", fileSystem
);
354 // Make sure they want to do this
356 if( driveType
== DRIVE_FIXED
) {
358 if( volumeName
[0] ) {
362 printf("Enter current volume label for drive %C: ", RootDirectory
[0] );
363 fgetws( input
, sizeof(input
)/2, stdin
);
364 input
[ wcslen( input
) - 1] = 0;
366 if( !wcsicmp( input
, volumeName
)) {
370 printf("An incorrect volume label was entered for this drive.\n");
376 printf("\nWARNING, ALL DATA ON NON_REMOVABLE DISK\n");
377 printf("DRIVE %C: WILL BE LOST!\n", RootDirectory
[0] );
378 printf("Proceed with Format (Y/N)? " );
379 fgetws( input
, sizeof(input
)/2, stdin
);
381 if( input
[0] == L
'Y' || input
[0] == L
'y' ) break;
383 if( input
[0] == L
'N' || input
[0] == L
'n' ) {
389 media
= FMIFS_HARDDISK
;
393 // Tell the user we're doing a long format if appropriate
397 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
399 printf("Verifying %luM\n", (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
403 printf("Verifying %.1fM\n",
404 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
408 if( totalNumberOfBytes
.QuadPart
> 1024*1024*10 ) {
410 printf("QuickFormatting %luM\n", (DWORD
) (totalNumberOfBytes
.QuadPart
/(1024*1024)));
414 printf("QuickFormatting %.2fM\n",
415 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
417 printf("Creating file system structures.\n");
423 FormatEx( RootDirectory
, media
, Format
, Label
, QuickFormat
,
424 ClusterSize
, FormatExCallback
);
425 if( Error
) return -1;
426 printf("Format complete.\n");
429 // Enable compression if desired
431 if( CompressDrive
) {
433 if( !EnableVolumeCompression( RootDirectory
, TRUE
)) {
435 printf("Volume does not support compression.\n");
440 // Get the label if we don't have it
444 printf("Volume Label (11 characters, Enter for none)? " );
445 fgetws( input
, sizeof(LabelString
)/2, stdin
);
447 input
[ wcslen(input
)-1] = 0;
448 if( !SetVolumeLabelW( RootDirectory
, input
)) {
450 PrintWin32Error(L
"Could not label volume", GetLastError());
455 if( !GetVolumeInformationW( RootDirectory
,
456 volumeName
, sizeof(volumeName
)/2,
457 &serialNumber
, &maxComponent
, &flags
,
458 fileSystem
, sizeof(fileSystem
)/2)) {
460 PrintWin32Error( L
"Could not query volume", GetLastError());
465 // Print out some stuff including the formatted size
467 if( !GetDiskFreeSpaceExW( RootDirectory
,
468 &freeBytesAvailableToCaller
,
470 &totalNumberOfFreeBytes
)) {
472 PrintWin32Error( L
"Could not query volume size", GetLastError());
476 printf("\n%I64d bytes total disk space.\n", totalNumberOfBytes
.QuadPart
);
477 printf("%I64d bytes available on disk.\n", totalNumberOfFreeBytes
.QuadPart
);
480 // Get the drive's serial number
482 if( !GetVolumeInformationW( RootDirectory
,
483 volumeName
, sizeof(volumeName
)/2,
484 &serialNumber
, &maxComponent
, &flags
,
485 fileSystem
, sizeof(fileSystem
)/2)) {
487 PrintWin32Error( L
"Could not query volume", GetLastError());
490 printf("\nVolume Serial Number is %04X-%04X\n", (unsigned int)(serialNumber
>> 16),
491 (unsigned int)(serialNumber
& 0xFFFF) );
496 int main(int argc
, char* argv
[])
504 wargv
= (PWCHAR
*) RtlAllocateHeap(RtlGetProcessHeap(), 0, argc
* sizeof(PWCHAR
));
506 for (i
= 0; i
< argc
; i
++)
508 RtlInitAnsiString(&arg
, argv
[i
]);
509 status
= RtlAnsiStringToUnicodeString(&warg
, &arg
, TRUE
);
510 if (!NT_SUCCESS (status
))
512 printf("Not enough free memory.\n");
515 wargv
[i
] = (PWCHAR
) warg
.Buffer
;
520 for (i
= 0; i
< argc
; i
++)
522 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv
[i
]);
524 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv
);