remove whitespace from end of lines
[reactos.git] / reactos / subsys / system / format / format.c
1 // Copyright (c) 1998 Mark Russinovich
2 // Systems Internals
3 // http://www.sysinternals.com
4 #include <stdio.h>
5 #include <string.h>
6 #define NTOS_MODE_USER
7 #include <ntos.h>
8 #include <fmifs.h>
9
10 // Globals
11 BOOL Error = FALSE;
12
13 // switches
14 BOOL QuickFormat = FALSE;
15 DWORD ClusterSize = 0;
16 BOOL CompressDrive = FALSE;
17 BOOL GotALabel = FALSE;
18 PWCHAR Label = L"";
19 PWCHAR Drive = NULL;
20 PWCHAR Format = L"FAT";
21
22 WCHAR RootDirectory[MAX_PATH];
23 WCHAR LabelString[12];
24
25 //
26 // Size array
27 //
28 typedef struct {
29 WCHAR SizeString[16];
30 DWORD ClusterSize;
31 } SIZEDEFINITION, *PSIZEDEFINITION;
32
33 SIZEDEFINITION LegalSizes[] = {
34 { L"512", 512 },
35 { L"1024", 1024 },
36 { L"2048", 2048 },
37 { L"4096", 4096 },
38 { L"8192", 8192 },
39 { L"16K", 16384 },
40 { L"32K", 32768 },
41 { L"64K", 65536 },
42 { L"128K", 65536 * 2 },
43 { L"256K", 65536 * 4 },
44 { L"", 0 },
45 };
46
47
48 //----------------------------------------------------------------------
49 //
50 // PrintWin32Error
51 //
52 // Takes the win32 error code and prints the text version.
53 //
54 //----------------------------------------------------------------------
55 void PrintWin32Error( PWCHAR Message, DWORD ErrorCode )
56 {
57 LPWSTR lpMsgBuf;
58
59 FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
60 NULL, ErrorCode,
61 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
62 (PWCHAR) &lpMsgBuf, 0, NULL );
63 printf("%S: %S\n", Message, lpMsgBuf );
64 LocalFree( lpMsgBuf );
65 }
66
67
68 //----------------------------------------------------------------------
69 //
70 // Usage
71 //
72 // Tell the user how to use the program
73 //
74 //----------------------------------------------------------------------
75 VOID Usage( PWCHAR ProgramName )
76 {
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");
90 printf("\n");
91 }
92
93
94 //----------------------------------------------------------------------
95 //
96 // ParseCommandLine
97 //
98 // Get the switches.
99 //
100 //----------------------------------------------------------------------
101 int ParseCommandLine( int argc, WCHAR *argv[] )
102 {
103 int i, j;
104 BOOLEAN gotFormat = FALSE;
105 BOOLEAN gotQuick = FALSE;
106 BOOLEAN gotSize = FALSE;
107 BOOLEAN gotLabel = FALSE;
108 BOOLEAN gotCompressed = FALSE;
109
110
111 for( i = 1; i < argc; i++ ) {
112
113 switch( argv[i][0] ) {
114
115 case '-':
116 case '/':
117
118 if( !wcsnicmp( &argv[i][1], L"FS:", 3 )) {
119
120 if( gotFormat) return -1;
121 Format = &argv[i][4];
122 gotFormat = TRUE;
123
124
125 } else if( !wcsnicmp( &argv[i][1], L"A:", 2 )) {
126
127 if( gotSize ) return -1;
128 j = 0;
129 while( LegalSizes[j].ClusterSize &&
130 wcsicmp( LegalSizes[j].SizeString, &argv[i][3] )) j++;
131
132 if( !LegalSizes[j].ClusterSize ) return i;
133 ClusterSize = LegalSizes[j].ClusterSize;
134 gotSize = TRUE;
135
136 } else if( !wcsnicmp( &argv[i][1], L"V:", 2 )) {
137
138 if( gotLabel ) return -1;
139 Label = &argv[i][3];
140 gotLabel = TRUE;
141 GotALabel = TRUE;
142
143 } else if( !wcsicmp( &argv[i][1], L"Q" )) {
144
145 if( gotQuick ) return -1;
146 QuickFormat = TRUE;
147 gotQuick = TRUE;
148
149 } else if( !wcsicmp( &argv[i][1], L"C" )) {
150
151 if( gotCompressed ) return -1;
152 CompressDrive = TRUE;
153 gotCompressed = TRUE;
154
155 } else return i;
156 break;
157
158 default:
159
160 if( Drive ) return i;
161 if( argv[i][1] != L':' ) return i;
162
163 Drive = argv[i];
164 break;
165 }
166 }
167 return 0;
168 }
169
170 //----------------------------------------------------------------------
171 //
172 // FormatExCallback
173 //
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.
176 //
177 //----------------------------------------------------------------------
178 BOOLEAN STDCALL
179 FormatExCallback (CALLBACKCOMMAND Command,
180 ULONG Modifier,
181 PVOID Argument)
182 {
183 PDWORD percent;
184 PTEXTOUTPUT output;
185 PBOOLEAN status;
186
187 //
188 // We get other types of commands, but we don't have to pay attention to them
189 //
190 switch( Command ) {
191
192 case PROGRESS:
193 percent = (PDWORD) Argument;
194 printf("%lu percent completed.\r", *percent);
195 break;
196
197 case OUTPUT:
198 output = (PTEXTOUTPUT) Argument;
199 fprintf(stdout, "%s", output->Output);
200 break;
201
202 case DONE:
203 status = (PBOOLEAN) Argument;
204 if( *status == FALSE ) {
205
206 printf("FormatEx was unable to complete successfully.\n\n");
207 Error = TRUE;
208 }
209 break;
210 case DONEWITHSTRUCTURE:
211 case UNKNOWN2:
212 case UNKNOWN3:
213 case UNKNOWN4:
214 case UNKNOWN5:
215 case INSUFFICIENTRIGHTS:
216 case UNKNOWN7:
217 case UNKNOWN8:
218 case UNKNOWN9:
219 case UNKNOWNA:
220 case UNKNOWNC:
221 case UNKNOWND:
222 case STRUCTUREPROGRESS:
223 printf("Operation Not Supported");
224 return FALSE;
225 }
226 return TRUE;
227 }
228
229
230 //----------------------------------------------------------------------
231 //
232 // LoadFMIFSEntryPoints
233 //
234 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
235 //
236 //----------------------------------------------------------------------
237 BOOLEAN LoadFMIFSEntryPoints()
238 {
239 LoadLibrary( "fmifs.dll" );
240 if( !(void*) GetProcAddress( GetModuleHandle( "fmifs.dll"), "FormatEx" ) ) {
241
242 return FALSE;
243 }
244
245 if( !((void *) GetProcAddress( GetModuleHandle( "fmifs.dll"),
246 "EnableVolumeCompression" )) ) {
247
248 return FALSE;
249 }
250 return TRUE;
251 }
252
253 //----------------------------------------------------------------------
254 //
255 // WMain
256 //
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.
260 //
261 // We do this in UNICODE because the chkdsk command expects PWCHAR
262 // arguments.
263 //
264 //----------------------------------------------------------------------
265 int wmain( int argc, WCHAR *argv[] )
266 {
267 int badArg;
268 DWORD media = FMIFS_HARDDISK;
269 DWORD driveType;
270 WCHAR fileSystem[1024];
271 WCHAR volumeName[1024];
272 WCHAR input[1024];
273 DWORD serialNumber;
274 DWORD flags, maxComponent;
275 ULARGE_INTEGER freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes;
276
277 //
278 // Get function pointers
279 //
280 if( !LoadFMIFSEntryPoints()) {
281
282 printf("Could not located FMIFS entry points.\n\n");
283 return -1;
284 }
285
286 //
287 // Parse command line
288 //
289 if( (badArg = ParseCommandLine( argc, argv ))) {
290
291 printf("Unknown argument: %S\n", argv[badArg] );
292
293 Usage(argv[0]);
294 return -1;
295 }
296
297 //
298 // Get the drive's format
299 //
300 if( !Drive ) {
301
302 printf("Required drive parameter is missing.\n\n");
303 Usage( argv[0] );
304 return -1;
305
306 } else {
307
308 wcscpy( RootDirectory, Drive );
309 }
310 RootDirectory[2] = L'\\';
311 RootDirectory[3] = (WCHAR) 0;
312
313 //
314 // See if the drive is removable or not
315 //
316 driveType = GetDriveTypeW( RootDirectory );
317
318 if( driveType == 0 ) {
319 PrintWin32Error( L"Could not get drive type", GetLastError());
320 return -1;
321 }
322
323 if( driveType != DRIVE_FIXED ) {
324 printf("Insert a new floppy in drive %C:\nand press Enter when ready...",
325 RootDirectory[0] );
326 fgetws( input, sizeof(input)/2, stdin );
327
328 media = FMIFS_FLOPPY;
329 }
330
331 //
332 // Determine the drive's file system format
333 //
334 if( !GetVolumeInformationW( RootDirectory,
335 volumeName, sizeof(volumeName)/2,
336 &serialNumber, &maxComponent, &flags,
337 fileSystem, sizeof(fileSystem)/2)) {
338
339 PrintWin32Error( L"Could not query volume", GetLastError());
340 return -1;
341 }
342
343 if( !GetDiskFreeSpaceExW( RootDirectory,
344 &freeBytesAvailableToCaller,
345 &totalNumberOfBytes,
346 &totalNumberOfFreeBytes )) {
347
348 PrintWin32Error( L"Could not query volume size", GetLastError());
349 return -1;
350 }
351 printf("The type of the file system is %S.\n", fileSystem );
352
353 //
354 // Make sure they want to do this
355 //
356 if( driveType == DRIVE_FIXED ) {
357
358 if( volumeName[0] ) {
359
360 while(1 ) {
361
362 printf("Enter current volume label for drive %C: ", RootDirectory[0] );
363 fgetws( input, sizeof(input)/2, stdin );
364 input[ wcslen( input ) - 1] = 0;
365
366 if( !wcsicmp( input, volumeName )) {
367
368 break;
369 }
370 printf("An incorrect volume label was entered for this drive.\n");
371 }
372 }
373
374 while( 1 ) {
375
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 );
380
381 if( input[0] == L'Y' || input[0] == L'y' ) break;
382
383 if( input[0] == L'N' || input[0] == L'n' ) {
384
385 printf("\n");
386 return 0;
387 }
388 }
389 media = FMIFS_HARDDISK;
390 }
391
392 //
393 // Tell the user we're doing a long format if appropriate
394 //
395 if( !QuickFormat ) {
396
397 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
398
399 printf("Verifying %luM\n", (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
400
401 } else {
402
403 printf("Verifying %.1fM\n",
404 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
405 }
406 } else {
407
408 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
409
410 printf("QuickFormatting %luM\n", (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
411
412 } else {
413
414 printf("QuickFormatting %.2fM\n",
415 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
416 }
417 printf("Creating file system structures.\n");
418 }
419
420 //
421 // Format away!
422 //
423 FormatEx( RootDirectory, media, Format, Label, QuickFormat,
424 ClusterSize, FormatExCallback );
425 if( Error ) return -1;
426 printf("Format complete.\n");
427
428 //
429 // Enable compression if desired
430 //
431 if( CompressDrive ) {
432
433 if( !EnableVolumeCompression( RootDirectory, TRUE )) {
434
435 printf("Volume does not support compression.\n");
436 }
437 }
438
439 //
440 // Get the label if we don't have it
441 //
442 if( !GotALabel ) {
443
444 printf("Volume Label (11 characters, Enter for none)? " );
445 fgetws( input, sizeof(LabelString)/2, stdin );
446
447 input[ wcslen(input)-1] = 0;
448 if( !SetVolumeLabelW( RootDirectory, input )) {
449
450 PrintWin32Error(L"Could not label volume", GetLastError());
451 return -1;
452 }
453 }
454
455 if( !GetVolumeInformationW( RootDirectory,
456 volumeName, sizeof(volumeName)/2,
457 &serialNumber, &maxComponent, &flags,
458 fileSystem, sizeof(fileSystem)/2)) {
459
460 PrintWin32Error( L"Could not query volume", GetLastError());
461 return -1;
462 }
463
464 //
465 // Print out some stuff including the formatted size
466 //
467 if( !GetDiskFreeSpaceExW( RootDirectory,
468 &freeBytesAvailableToCaller,
469 &totalNumberOfBytes,
470 &totalNumberOfFreeBytes )) {
471
472 PrintWin32Error( L"Could not query volume size", GetLastError());
473 return -1;
474 }
475
476 printf("\n%I64d bytes total disk space.\n", totalNumberOfBytes.QuadPart );
477 printf("%I64d bytes available on disk.\n", totalNumberOfFreeBytes.QuadPart );
478
479 //
480 // Get the drive's serial number
481 //
482 if( !GetVolumeInformationW( RootDirectory,
483 volumeName, sizeof(volumeName)/2,
484 &serialNumber, &maxComponent, &flags,
485 fileSystem, sizeof(fileSystem)/2)) {
486
487 PrintWin32Error( L"Could not query volume", GetLastError());
488 return -1;
489 }
490 printf("\nVolume Serial Number is %04X-%04X\n", (unsigned int)(serialNumber >> 16),
491 (unsigned int)(serialNumber & 0xFFFF) );
492
493 return 0;
494 }
495
496 int main(int argc, char* argv[])
497 {
498 UNICODE_STRING warg;
499 ANSI_STRING arg;
500 NTSTATUS status;
501 PWCHAR *wargv;
502 int i;
503
504 wargv = (PWCHAR *) RtlAllocateHeap(RtlGetProcessHeap(), 0, argc * sizeof(PWCHAR));
505
506 for (i = 0; i < argc; i++)
507 {
508 RtlInitAnsiString(&arg, argv[i]);
509 status = RtlAnsiStringToUnicodeString(&warg, &arg, TRUE);
510 if (!NT_SUCCESS (status))
511 {
512 printf("Not enough free memory.\n");
513 return 1;
514 }
515 wargv[i] = (PWCHAR) warg.Buffer;
516 }
517
518 wmain(argc, wargv);
519
520 for (i = 0; i < argc; i++)
521 {
522 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv[i]);
523 }
524 RtlFreeHeap(RtlGetProcessHeap(), 0, wargv);
525
526 return 0;
527 }