457a79961d48d94f7811d1bb6d6d63675cc644cf
[reactos.git] / rosapps / sysutils / format.c
1 //======================================================================
2 //
3 // $Id: format.c,v 1.1 1999/05/16 07:27:35 ea Exp $
4 //
5 // Formatx
6 //
7 // Copyright (c) 1998 Mark Russinovich
8 // Systems Internals
9 // http://www.sysinternals.com/
10 //
11 // This software is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Library General Public License as
13 // published by the Free Software Foundation; either version 2 of the
14 // License, or (at your option) any later version.
15 //
16 // This software is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public
22 // License along with this software; see the file COPYING.LIB. If
23 // not, write to the Free Software Foundation, Inc., 675 Mass Ave,
24 // Cambridge, MA 02139, USA.
25 //
26 // ---------------------------------------------------------------------
27 // Format clone that demonstrates the use of the FMIFS file system
28 // utility library.
29 //
30 // 1999 February (Emanuele Aliberti)
31 // Adapted for ReactOS and lcc-win32.
32 //
33 // 1999 April (Emanuele Aliberti)
34 // Adapted for ReactOS and egcs.
35 //
36 //======================================================================
37 #define UNICODE 1
38 #define _UNICODE 1
39 #include <windows.h>
40 #include <stdio.h>
41 #include "fmifs.h"
42 //#include <tchar.h>
43 #include "win32err.h"
44 #include "config.h"
45
46 #define WBUFSIZE(b) (sizeof(b) / sizeof (wchar_t))
47
48
49 //
50 // Globals
51 //
52 BOOL Error = FALSE;
53
54 // switches
55 BOOL QuickFormat = FALSE;
56 DWORD ClusterSize = 0;
57 BOOL CompressDrive = FALSE;
58 BOOL GotALabel = FALSE;
59 PWCHAR Label = L"";
60 PWCHAR Drive = NULL;
61 PWCHAR Format = L"FAT";
62
63 WCHAR RootDirectory [MAX_PATH];
64 WCHAR LabelString [12];
65
66 #ifndef FMIFS_IMPORT_DLL
67 //
68 // Functions in FMIFS.DLL
69 //
70 PFORMATEX FormatEx;
71 PENABLEVOLUMECOMPRESSION EnableVolumeCompression;
72 #endif /* ndef FMIFS_IMPORT_DLL */
73
74 //
75 // Size array
76 //
77 typedef
78 struct
79 {
80 WCHAR SizeString [16];
81 DWORD ClusterSize;
82
83 } SIZEDEFINITION, *PSIZEDEFINITION;
84
85
86 SIZEDEFINITION
87 LegalSizes [] =
88 {
89 { L"512", 512 },
90 { L"1024", 1024 },
91 { L"2048", 2048 },
92 { L"4096", 4096 },
93 { L"8192", 8192 },
94 { L"16K", 16384 },
95 { L"32K", 32768 },
96 { L"64K", 65536 },
97 { L"128K", 65536 * 2 },
98 { L"256K", 65536 * 4 },
99 { L"", 0 },
100 };
101
102
103 //----------------------------------------------------------------------
104 //
105 // Usage
106 //
107 // Tell the user how to use the program
108 //
109 // 1990218 EA ProgramName missing in wprintf arg list
110 //
111 //----------------------------------------------------------------------
112 VOID
113 Usage( PWCHAR ProgramName )
114 {
115 wprintf(
116 L"\
117 Usage: %s drive: [-FS:file-system] [-V:label] [-Q] [-A:size] [-C]\n\n\
118 [drive:] Specifies the drive to format.\n\
119 -FS:file-system Specifies the type of file system (e.g. FAT).\n\
120 -V:label Specifies volume label.\n\
121 -Q Performs a quick format.\n\
122 -A:size Overrides the default allocation unit size. Default settings\n\
123 are strongly recommended for general use\n\
124 NTFS supports 512, 1024, 2048, 4096, 8192, 16K, 32K, 64K.\n\
125 FAT supports 8192, 16K, 32K, 64K, 128K, 256K.\n\
126 NTFS compression is not supported for allocation unit sizes\n\
127 above 4096.\n\
128 -C Files created on the new volume will be compressed by\n\
129 default.\n\n",
130 ProgramName
131 );
132 }
133
134
135 //----------------------------------------------------------------------
136 //
137 // ParseCommandLine
138 //
139 // Get the switches.
140 //
141 // 19990218 EA switch characters '-' and '/' are wide
142 //
143 //----------------------------------------------------------------------
144 int
145 ParseCommandLine(
146 int argc,
147 WCHAR *argv []
148 )
149 {
150 int i,
151 j;
152 BOOLEAN gotFormat = FALSE;
153 BOOLEAN gotQuick = FALSE;
154 BOOLEAN gotSize = FALSE;
155 BOOLEAN gotLabel = FALSE;
156 BOOLEAN gotCompressed = FALSE;
157
158
159 for (
160 i = 1;
161 (i < argc);
162 i++
163 ) {
164 switch ( argv[i][0] )
165 {
166
167 case L'-':
168 case L'/':
169
170 if( !wcsnicmp( & argv[i][1], L"FS:", 3 ))
171 {
172 if( gotFormat) return -1;
173 Format = & argv[i][4];
174 gotFormat = TRUE;
175 }
176 else if( !wcsnicmp( & argv[i][1], L"A:", 2 ))
177 {
178 if ( gotSize ) return -1;
179 j = 0;
180 while ( LegalSizes[j].ClusterSize &&
181 wcsicmp(
182 LegalSizes[j].SizeString,
183 & argv[i][3]
184 )
185 ) {
186 j++;
187 }
188 if( !LegalSizes[j].ClusterSize ) return i;
189 ClusterSize = LegalSizes[j].ClusterSize;
190 gotSize = TRUE;
191 }
192 else if( !wcsnicmp( & argv[i][1], L"V:", 2 ))
193 {
194 if( gotLabel ) return -1;
195 Label = & argv[i][3];
196 gotLabel = TRUE;
197 GotALabel = TRUE;
198 }
199 else if ( !wcsicmp( & argv[i][1], L"Q" ))
200 {
201 if( gotQuick ) return -1;
202 QuickFormat = TRUE;
203 gotQuick = TRUE;
204 }
205 else if ( !wcsicmp( & argv[i][1], L"C" ))
206 {
207 if( gotCompressed ) return -1;
208 CompressDrive = TRUE;
209 gotCompressed = TRUE;
210 }
211 else
212 {
213 return i;
214 }
215 break;
216
217 default:
218
219 if ( Drive ) return i;
220 if ( argv[i][1] != L':' ) return i;
221
222 Drive = argv[i];
223 break;
224 }
225 }
226 return 0;
227 }
228
229
230 //----------------------------------------------------------------------
231 //
232 // FormatExCallback
233 //
234 // The file system library will call us back with commands that we
235 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
236 //
237 //----------------------------------------------------------------------
238 BOOLEAN
239 __stdcall
240 FormatExCallback(
241 CALLBACKCOMMAND Command,
242 DWORD Modifier,
243 PVOID Argument
244 )
245 {
246 PDWORD percent;
247 PTEXTOUTPUT output;
248 PBOOLEAN status;
249 //static createStructures = FALSE;
250
251 //
252 // We get other types of commands, but we don't have to pay attention to them
253 //
254 switch ( Command )
255 {
256 case PROGRESS:
257 percent = (PDWORD) Argument;
258 wprintf(L"%d percent completed.\r", *percent);
259 break;
260
261 case OUTPUT:
262 output = (PTEXTOUTPUT) Argument;
263 fprintf(stdout, "%s", output->Output);
264 break;
265
266 case DONE:
267 status = (PBOOLEAN) Argument;
268 if ( *status == FALSE )
269 {
270 wprintf(L"FormatEx was unable to complete successfully.\n\n");
271 Error = TRUE;
272 }
273 break;
274 }
275 return TRUE;
276 }
277
278
279 #ifndef FMIFS_IMPORT_DLL
280 //----------------------------------------------------------------------
281 //
282 // LoadFMIFSEntryPoints
283 //
284 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
285 //
286 // 19990216 EA ANSI strings in LoadFMIFSEntryPoints should be
287 // wide strings
288 //
289 //----------------------------------------------------------------------
290 BOOLEAN
291 LoadFMIFSEntryPoints(VOID)
292 {
293 LoadLibraryW( L"fmifs.dll" );
294
295 if ( !(FormatEx =
296 (void *) GetProcAddress(
297 GetModuleHandleW( L"fmifs.dll"),
298 "FormatEx"
299 )
300 )
301 ) {
302 return FALSE;
303 }
304 if ( !(EnableVolumeCompression =
305 (void *) GetProcAddress(
306 GetModuleHandleW( L"fmifs.dll"),
307 "EnableVolumeCompression"
308 )
309 )
310 ) {
311 return FALSE;
312 }
313 return TRUE;
314 }
315 #endif /* ndef FMIFS_IMPORT_DLL */
316
317
318 //----------------------------------------------------------------------
319 //
320 // WMain
321 //
322 // Engine. Just get command line switches and fire off a format. This
323 // could also be done in a GUI like Explorer does when you select a
324 // drive and run a check on it.
325 //
326 // We do this in UNICODE because the chkdsk command expects PWCHAR
327 // arguments.
328 //
329 //----------------------------------------------------------------------
330 int
331 wmain( int argc, WCHAR *argv[] )
332 {
333 int badArg;
334
335 DWORD media;
336 DWORD driveType;
337
338 WCHAR fileSystem [1024];
339 WCHAR volumeName [1024];
340 WCHAR input [1024];
341
342 DWORD serialNumber;
343 DWORD flags,
344 maxComponent;
345
346 ULARGE_INTEGER freeBytesAvailableToCaller,
347 totalNumberOfBytes,
348 totalNumberOfFreeBytes;
349
350
351 wprintf( L"\
352 \nFormatx v1.0 by Mark Russinovich\n\
353 Systems Internals - http://www.sysinternals.com\n\
354 ReactOs adaptation 1999 by Emanuele Aliberti\n\n"
355 );
356
357 #ifndef FMIFS_IMPORT_DLL
358 //
359 // Get function pointers
360 //
361 if( !LoadFMIFSEntryPoints())
362 {
363 wprintf(L"Could not located FMIFS entry points.\n\n");
364 return -1;
365 }
366 #endif /* ndef FMIFS_IMPORT_DLL */
367 //
368 // Parse command line
369 //
370 if( (badArg = ParseCommandLine( argc, argv )))
371 {
372 wprintf(
373 L"Unknown argument: %s\n",
374 argv[badArg]
375 );
376 Usage(argv[0]);
377 return -1;
378 }
379 //
380 // Get the drive's format
381 //
382 if( !Drive )
383 {
384 wprintf(L"Required drive parameter is missing.\n\n");
385 Usage( argv[0] );
386 return -1;
387 }
388 else
389 {
390 wcscpy( RootDirectory, Drive );
391 }
392 RootDirectory[2] = L'\\';
393 RootDirectory[3] = L'\0';
394 //
395 // See if the drive is removable or not
396 //
397 driveType = GetDriveTypeW( RootDirectory );
398 if ( driveType != DRIVE_FIXED )
399 {
400 wprintf(
401 L"Insert a new floppy in drive %C:\nand press Enter when ready...",
402 RootDirectory[0]
403 );
404 fgetws(
405 input,
406 WBUFSIZE(input),
407 stdin
408 );
409 media = FMIFS_FLOPPY;
410 }
411 //
412 // Determine the drive's file system format
413 //
414 if ( !GetVolumeInformationW(
415 RootDirectory,
416 volumeName,
417 WBUFSIZE(volumeName),
418 & serialNumber,
419 & maxComponent,
420 & flags,
421 fileSystem,
422 WBUFSIZE(fileSystem) )
423 ) {
424 PrintWin32Error(
425 L"Could not query volume",
426 GetLastError()
427 );
428 return -1;
429 }
430 if( !GetDiskFreeSpaceExW(
431 RootDirectory,
432 & freeBytesAvailableToCaller,
433 & totalNumberOfBytes,
434 & totalNumberOfFreeBytes )
435 )
436 {
437 PrintWin32Error(
438 L"Could not query volume size",
439 GetLastError()
440 );
441 return -1;
442 }
443 wprintf(
444 L"The type of the file system is %s.\n",
445 fileSystem
446 );
447 //
448 // Make sure they want to do this
449 //
450 if ( driveType == DRIVE_FIXED )
451 {
452 if ( volumeName[0] )
453 {
454 while (1)
455 {
456 wprintf(
457 L"Enter current volume label for drive %C: ",
458 RootDirectory[0]
459 );
460 fgetws(
461 input,
462 WBUFSIZE(input),
463 stdin
464 );
465 input[ wcslen( input ) - 1 ] = 0;
466
467 if ( !wcsicmp( input, volumeName ))
468 {
469 break;
470 }
471 wprintf(L"An incorrect volume label was entered for this drive.\n");
472 }
473 }
474 while ( 1 )
475 {
476 wprintf(L"\nWARNING, ALL DATA ON NON_REMOVABLE DISK\n");
477 wprintf(L"DRIVE %C: WILL BE LOST!\n", RootDirectory[0] );
478 wprintf(L"Proceed with Format (Y/N)? " );
479 fgetws(
480 input,
481 WBUFSIZE(input),
482 stdin
483 );
484 if ( (input[0] == L'Y') || (input[0] == L'y') ) break;
485
486 if ( (input[0] == L'N') || (input[0] == L'n') )
487 {
488 wprintf(L"\n");
489 return 0;
490 }
491 }
492 media = FMIFS_HARDDISK;
493 }
494 //
495 // Tell the user we're doing a long format if appropriate
496 //
497 if ( !QuickFormat )
498 {
499 if ( totalNumberOfBytes.QuadPart > 1024*1024*10 )
500 {
501
502 wprintf(
503 L"Verifying %dM\n",
504 (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024))
505 );
506 }
507 else
508 {
509 wprintf(
510 L"Verifying %.1fM\n",
511 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0)
512 );
513 }
514 }
515 else
516 {
517 if ( totalNumberOfBytes.QuadPart > 1024*1024*10 )
518 {
519 wprintf(
520 L"QuickFormatting %dM\n",
521 (DWORD) (totalNumberOfBytes.QuadPart / (1024 * 1024))
522 );
523 }
524 else
525 {
526 wprintf(
527 L"QuickFormatting %.2fM\n",
528 ((float)(LONGLONG)totalNumberOfBytes.QuadPart) / (float)(1024.0*1024.0)
529 );
530 }
531 wprintf(L"Creating file system structures.\n");
532 }
533 //
534 // Format away!
535 //
536 FormatEx(
537 RootDirectory,
538 media,
539 Format,
540 Label,
541 QuickFormat,
542 ClusterSize,
543 FormatExCallback
544 );
545 if ( Error ) return -1;
546 wprintf(L"Format complete.\n");
547 //
548 // Enable compression if desired
549 //
550 if ( CompressDrive )
551 {
552 if( !EnableVolumeCompression( RootDirectory, TRUE ))
553 {
554 wprintf(L"Volume does not support compression.\n");
555 }
556 }
557 //
558 // Get the label if we don't have it
559 //
560 if( !GotALabel )
561 {
562 wprintf(L"Volume Label (11 characters, Enter for none)? " );
563 fgetws(
564 input,
565 WBUFSIZE(LabelString),
566 stdin
567 );
568
569 input[ wcslen(input) - 1 ] = 0;
570 if( !SetVolumeLabelW( RootDirectory, input ))
571 {
572 PrintWin32Error(
573 L"Could not label volume",
574 GetLastError()
575 );
576 return -1;
577 }
578 }
579 if ( !GetVolumeInformationW(
580 RootDirectory,
581 volumeName,
582 WBUFSIZE(volumeName),
583 & serialNumber,
584 & maxComponent,
585 & flags,
586 fileSystem,
587 WBUFSIZE(fileSystem) )
588 ) {
589 PrintWin32Error(
590 L"Could not query volume",
591 GetLastError()
592 );
593 return -1;
594 }
595 //
596 // Print out some stuff including the formatted size
597 //
598 if ( !GetDiskFreeSpaceExW(
599 RootDirectory,
600 & freeBytesAvailableToCaller,
601 & totalNumberOfBytes,
602 & totalNumberOfFreeBytes )
603 ) {
604 PrintWin32Error(
605 L"Could not query volume size",
606 GetLastError()
607 );
608 return -1;
609 }
610 wprintf(
611 L"\n%I64d bytes total disk space.\n",
612 totalNumberOfBytes.QuadPart
613 );
614 wprintf(
615 L"%I64d bytes available on disk.\n",
616 totalNumberOfFreeBytes.QuadPart
617 );
618 //
619 // Get the drive's serial number
620 //
621 if ( !GetVolumeInformationW(
622 RootDirectory,
623 volumeName,
624 WBUFSIZE(volumeName),
625 & serialNumber,
626 & maxComponent,
627 & flags,
628 fileSystem,
629 WBUFSIZE(fileSystem) )
630 ) {
631 PrintWin32Error(
632 L"Could not query volume",
633 GetLastError()
634 );
635 return -1;
636 }
637 wprintf(
638 L"\nVolume Serial Number is %04X-%04X\n",
639 serialNumber >> 16,
640 serialNumber & 0xFFFF
641 );
642 return 0;
643 }
644
645
646 /* EOF */