1 // Copyright (c) 1998 Mark Russinovich
3 // http://www.sysinternals.com
13 BOOL QuickFormat = FALSE;
14 DWORD ClusterSize = 0;
15 BOOL CompressDrive = FALSE;
16 BOOL GotALabel = FALSE;
19 PWCHAR Format = L"FAT";
21 WCHAR RootDirectory[MAX_PATH];
22 WCHAR LabelString[12];
30 } SIZEDEFINITION, *PSIZEDEFINITION;
32 SIZEDEFINITION LegalSizes[] = {
41 { L"128K", 65536 * 2 },
42 { L"256K", 65536 * 4 },
47 //----------------------------------------------------------------------
51 // Takes the win32 error code and prints the text version.
53 //----------------------------------------------------------------------
54 void PrintWin32Error( PWCHAR Message, DWORD ErrorCode )
58 FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
60 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
61 (PWCHAR) &lpMsgBuf, 0, NULL );
62 printf("%S: %S\n", Message, lpMsgBuf );
63 LocalFree( lpMsgBuf );
67 //----------------------------------------------------------------------
71 // Tell the user how to use the program
73 //----------------------------------------------------------------------
74 VOID Usage( PWCHAR ProgramName )
76 printf("Usage: %S drive: [-FS:file-system] [-V:label] [-Q] [-A:size] [-C]\n\n", ProgramName);
77 printf(" [drive:] Specifies the drive to format.\n");
78 printf(" -FS:file-system Specifies the type of file system (e.g. FAT).\n");
79 printf(" -V:label Specifies volume label.\n");
80 printf(" -Q Performs a quick format.\n");
81 printf(" -A:size Overrides the default allocation unit size. Default settings\n");
82 printf(" are strongly recommended for general use\n");
83 printf(" NTFS supports 512, 1024, 2048, 4096, 8192, 16K, 32K, 64K.\n");
84 printf(" FAT supports 8192, 16K, 32K, 64K, 128K, 256K.\n");
85 printf(" NTFS compression is not supported for allocation unit sizes\n");
86 printf(" above 4096.\n");
87 printf(" -C Files created on the new volume will be compressed by\n");
88 printf(" default.\n");
93 //----------------------------------------------------------------------
99 //----------------------------------------------------------------------
100 int ParseCommandLine( int argc, WCHAR *argv[] )
103 BOOLEAN gotFormat = FALSE;
104 BOOLEAN gotQuick = FALSE;
105 BOOLEAN gotSize = FALSE;
106 BOOLEAN gotLabel = FALSE;
107 BOOLEAN gotCompressed = FALSE;
110 for( i = 1; i < argc; i++ ) {
112 switch( argv[i][0] ) {
117 if( !wcsnicmp( &argv[i][1], L"FS:", 3 )) {
119 if( gotFormat) return -1;
120 Format = &argv[i][4];
124 } else if( !wcsnicmp( &argv[i][1], L"A:", 2 )) {
126 if( gotSize ) return -1;
128 while( LegalSizes[j].ClusterSize &&
129 wcsicmp( LegalSizes[j].SizeString, &argv[i][3] )) j++;
131 if( !LegalSizes[j].ClusterSize ) return i;
132 ClusterSize = LegalSizes[j].ClusterSize;
135 } else if( !wcsnicmp( &argv[i][1], L"V:", 2 )) {
137 if( gotLabel ) return -1;
142 } else if( !wcsicmp( &argv[i][1], L"Q" )) {
144 if( gotQuick ) return -1;
148 } else if( !wcsicmp( &argv[i][1], L"C" )) {
150 if( gotCompressed ) return -1;
151 CompressDrive = TRUE;
152 gotCompressed = TRUE;
159 if( Drive ) return i;
160 if( argv[i][1] != L':' ) return i;
169 //----------------------------------------------------------------------
173 // The file system library will call us back with commands that we
174 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
176 //----------------------------------------------------------------------
177 BOOL __stdcall FormatExCallback( CALLBACKCOMMAND Command, DWORD Modifier, PVOID Argument )
182 static createStructures = FALSE;
185 // We get other types of commands, but we don't have to pay attention to them
190 percent = (PDWORD) Argument;
191 printf("%d 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");
212 //----------------------------------------------------------------------
214 // LoadFMIFSEntryPoints
216 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
218 //----------------------------------------------------------------------
219 BOOLEAN LoadFMIFSEntryPoints()
221 LoadLibrary( "fmifs.dll" );
222 if( !(void*) GetProcAddress( GetModuleHandle( "fmifs.dll"), "FormatEx" ) ) {
227 if( !((void *) GetProcAddress( GetModuleHandle( "fmifs.dll"),
228 "EnableVolumeCompression" )) ) {
235 //----------------------------------------------------------------------
239 // Engine. Just get command line switches and fire off a format. This
240 // could also be done in a GUI like Explorer does when you select a
241 // drive and run a check on it.
243 // We do this in UNICODE because the chkdsk command expects PWCHAR
246 //----------------------------------------------------------------------
247 int wmain( int argc, WCHAR *argv[] )
252 WCHAR fileSystem[1024];
253 WCHAR volumeName[1024];
256 DWORD flags, maxComponent;
257 ULARGE_INTEGER freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes;
260 // Get function pointers
262 if( !LoadFMIFSEntryPoints()) {
264 printf("Could not located FMIFS entry points.\n\n");
269 // Parse command line
271 if( (badArg = ParseCommandLine( argc, argv ))) {
273 printf("Unknown argument: %S\n", argv[badArg] );
280 // Get the drive's format
284 printf("Required drive parameter is missing.\n\n");
290 wcscpy( RootDirectory, Drive );
292 RootDirectory[2] = L'\\';
293 RootDirectory[3] = (WCHAR) 0;
296 // See if the drive is removable or not
298 driveType = GetDriveTypeW( RootDirectory );
300 if( driveType == 0 ) {
301 PrintWin32Error( L"Could not get drive type", GetLastError());
305 if( driveType != DRIVE_FIXED ) {
307 printf("Insert a new floppy in drive %C:\nand press Enter when ready...",
309 fgetws( input, sizeof(input)/2, stdin );
311 media = FMIFS_FLOPPY;
314 driveType = DRIVE_FIXED;
315 media = FMIFS_HARDDISK;
321 // Determine the drive's file system format
323 if( !GetVolumeInformationW( RootDirectory,
324 volumeName, sizeof(volumeName)/2,
325 &serialNumber, &maxComponent, &flags,
326 fileSystem, sizeof(fileSystem)/2)) {
328 PrintWin32Error( L"Could not query volume", GetLastError());
332 if( !GetDiskFreeSpaceExW( RootDirectory,
333 &freeBytesAvailableToCaller,
335 &totalNumberOfFreeBytes )) {
337 PrintWin32Error( L"Could not query volume size", GetLastError());
340 printf("The type of the file system is %S.\n", fileSystem );
343 // Make sure they want to do this
345 if( driveType == DRIVE_FIXED ) {
347 if( volumeName[0] ) {
351 printf("Enter current volume label for drive %C: ", RootDirectory[0] );
352 fgetws( input, sizeof(input)/2, stdin );
353 input[ wcslen( input ) - 1] = 0;
355 if( !wcsicmp( input, volumeName )) {
359 printf("An incorrect volume label was entered for this drive.\n");
365 printf("\nWARNING, ALL DATA ON NON_REMOVABLE DISK\n");
366 printf("DRIVE %C: WILL BE LOST!\n", RootDirectory[0] );
367 printf("Proceed with Format (Y/N)? " );
368 fgetws( input, sizeof(input)/2, stdin );
370 if( input[0] == L'Y' || input[0] == L'y' ) break;
372 if( input[0] == L'N' || input[0] == L'n' ) {
378 media = FMIFS_HARDDISK;
382 // Tell the user we're doing a long format if appropriate
386 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
388 printf("Verifying %dM\n", (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
392 printf("Verifying %.1fM\n",
393 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
397 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
399 printf("QuickFormatting %dM\n", (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
403 printf("QuickFormatting %.2fM\n",
404 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
406 printf("Creating file system structures.\n");
412 FormatEx( RootDirectory, media, Format, Label, QuickFormat,
413 ClusterSize, FormatExCallback );
414 if( Error ) return -1;
415 printf("Format complete.\n");
418 // Enable compression if desired
420 if( CompressDrive ) {
422 if( !EnableVolumeCompression( RootDirectory, TRUE )) {
424 printf("Volume does not support compression.\n");
429 // Get the label if we don't have it
433 printf("Volume Label (11 characters, Enter for none)? " );
434 fgetws( input, sizeof(LabelString)/2, stdin );
436 input[ wcslen(input)-1] = 0;
437 if( !SetVolumeLabelW( RootDirectory, input )) {
439 PrintWin32Error(L"Could not label volume", GetLastError());
444 if( !GetVolumeInformationW( RootDirectory,
445 volumeName, sizeof(volumeName)/2,
446 &serialNumber, &maxComponent, &flags,
447 fileSystem, sizeof(fileSystem)/2)) {
449 PrintWin32Error( L"Could not query volume", GetLastError());
454 // Print out some stuff including the formatted size
456 if( !GetDiskFreeSpaceExW( RootDirectory,
457 &freeBytesAvailableToCaller,
459 &totalNumberOfFreeBytes )) {
461 PrintWin32Error( L"Could not query volume size", GetLastError());
465 printf("\n%I64d bytes total disk space.\n", totalNumberOfBytes.QuadPart );
466 printf("%I64d bytes available on disk.\n", totalNumberOfFreeBytes.QuadPart );
469 // Get the drive's serial number
471 if( !GetVolumeInformationW( RootDirectory,
472 volumeName, sizeof(volumeName)/2,
473 &serialNumber, &maxComponent, &flags,
474 fileSystem, sizeof(fileSystem)/2)) {
476 PrintWin32Error( L"Could not query volume", GetLastError());
479 printf("\nVolume Serial Number is %04X-%04X\n", serialNumber >> 16,
480 serialNumber & 0xFFFF );
485 int main(int argc, char* argv[])
493 wargv = (PWCHAR *) RtlAllocateHeap(RtlGetProcessHeap(), 0, argc * sizeof(PWCHAR));
495 for (i = 0; i < argc; i++)
497 RtlInitAnsiString(&arg, argv[i]);
498 status = RtlAnsiStringToUnicodeString(&warg, &arg, TRUE);
499 if (!NT_SUCCESS (status))
501 printf("Not enough free memory.\n");
504 wargv[i] = (PWCHAR) warg.Buffer;
509 for (i = 0; i < argc; i++)
511 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv[i]);
513 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv);