remove empty dir
[reactos.git] / rosapps / sysutils / format.c
1 //======================================================================
2 //
3 // $Id$
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 "../../reactos/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 default:
275 break;
276 }
277 return TRUE;
278 }
279
280
281 #ifndef FMIFS_IMPORT_DLL
282 //----------------------------------------------------------------------
283 //
284 // LoadFMIFSEntryPoints
285 //
286 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
287 //
288 // 19990216 EA ANSI strings in LoadFMIFSEntryPoints should be
289 // wide strings
290 //
291 //----------------------------------------------------------------------
292 BOOLEAN
293 LoadFMIFSEntryPoints(VOID)
294 {
295 LoadLibraryW( L"fmifs.dll" );
296
297 if ( !(FormatEx =
298 (void *) GetProcAddress(
299 GetModuleHandleW( L"fmifs.dll"),
300 "FormatEx"
301 )
302 )
303 ) {
304 return FALSE;
305 }
306 if ( !(EnableVolumeCompression =
307 (void *) GetProcAddress(
308 GetModuleHandleW( L"fmifs.dll"),
309 "EnableVolumeCompression"
310 )
311 )
312 ) {
313 return FALSE;
314 }
315 return TRUE;
316 }
317 #endif /* ndef FMIFS_IMPORT_DLL */
318
319
320 //----------------------------------------------------------------------
321 //
322 // WMain
323 //
324 // Engine. Just get command line switches and fire off a format. This
325 // could also be done in a GUI like Explorer does when you select a
326 // drive and run a check on it.
327 //
328 // We do this in UNICODE because the chkdsk command expects PWCHAR
329 // arguments.
330 //
331 //----------------------------------------------------------------------
332 int
333 wmain( int argc, WCHAR *argv[] )
334 {
335 int badArg;
336
337 DWORD media = 0;
338 DWORD driveType;
339
340 WCHAR fileSystem [1024];
341 WCHAR volumeName [1024];
342 WCHAR input [1024];
343
344 DWORD serialNumber;
345 DWORD flags,
346 maxComponent;
347
348 ULARGE_INTEGER freeBytesAvailableToCaller,
349 totalNumberOfBytes,
350 totalNumberOfFreeBytes;
351
352
353 wprintf( L"\
354 \nFormatx v1.0 by Mark Russinovich\n\
355 Systems Internals - http://www.sysinternals.com\n\
356 ReactOs adaptation 1999 by Emanuele Aliberti\n\n"
357 );
358
359 #ifndef FMIFS_IMPORT_DLL
360 //
361 // Get function pointers
362 //
363 if( !LoadFMIFSEntryPoints())
364 {
365 wprintf(L"Could not located FMIFS entry points.\n\n");
366 return -1;
367 }
368 #endif /* ndef FMIFS_IMPORT_DLL */
369 //
370 // Parse command line
371 //
372 if( (badArg = ParseCommandLine( argc, argv )))
373 {
374 wprintf(
375 L"Unknown argument: %s\n",
376 argv[badArg]
377 );
378 Usage(argv[0]);
379 return -1;
380 }
381 //
382 // Get the drive's format
383 //
384 if( !Drive )
385 {
386 wprintf(L"Required drive parameter is missing.\n\n");
387 Usage( argv[0] );
388 return -1;
389 }
390 else
391 {
392 wcscpy( RootDirectory, Drive );
393 }
394 RootDirectory[2] = L'\\';
395 RootDirectory[3] = L'\0';
396 //
397 // See if the drive is removable or not
398 //
399 driveType = GetDriveTypeW( RootDirectory );
400 if ( driveType != DRIVE_FIXED )
401 {
402 wprintf(
403 L"Insert a new floppy in drive %C:\nand press Enter when ready...",
404 RootDirectory[0]
405 );
406 fgetws(
407 input,
408 WBUFSIZE(input),
409 stdin
410 );
411 media = FMIFS_FLOPPY;
412 }
413 //
414 // Determine the drive's file system format
415 //
416 if ( !GetVolumeInformationW(
417 RootDirectory,
418 volumeName,
419 WBUFSIZE(volumeName),
420 & serialNumber,
421 & maxComponent,
422 & flags,
423 fileSystem,
424 WBUFSIZE(fileSystem) )
425 ) {
426 PrintWin32Error(
427 L"Could not query volume",
428 GetLastError()
429 );
430 return -1;
431 }
432 if( !GetDiskFreeSpaceExW(
433 RootDirectory,
434 & freeBytesAvailableToCaller,
435 & totalNumberOfBytes,
436 & totalNumberOfFreeBytes )
437 )
438 {
439 PrintWin32Error(
440 L"Could not query volume size",
441 GetLastError()
442 );
443 return -1;
444 }
445 wprintf(
446 L"The type of the file system is %s.\n",
447 fileSystem
448 );
449 //
450 // Make sure they want to do this
451 //
452 if ( driveType == DRIVE_FIXED )
453 {
454 if ( volumeName[0] )
455 {
456 while (1)
457 {
458 wprintf(
459 L"Enter current volume label for drive %C: ",
460 RootDirectory[0]
461 );
462 fgetws(
463 input,
464 WBUFSIZE(input),
465 stdin
466 );
467 input[ wcslen( input ) - 1 ] = 0;
468
469 if ( !wcsicmp( input, volumeName ))
470 {
471 break;
472 }
473 wprintf(L"An incorrect volume label was entered for this drive.\n");
474 }
475 }
476 while ( 1 )
477 {
478 wprintf(L"\nWARNING, ALL DATA ON NON_REMOVABLE DISK\n");
479 wprintf(L"DRIVE %C: WILL BE LOST!\n", RootDirectory[0] );
480 wprintf(L"Proceed with Format (Y/N)? " );
481 fgetws(
482 input,
483 WBUFSIZE(input),
484 stdin
485 );
486 if ( (input[0] == L'Y') || (input[0] == L'y') ) break;
487
488 if ( (input[0] == L'N') || (input[0] == L'n') )
489 {
490 wprintf(L"\n");
491 return 0;
492 }
493 }
494 media = FMIFS_HARDDISK;
495 }
496 //
497 // Tell the user we're doing a long format if appropriate
498 //
499 if ( !QuickFormat )
500 {
501 if ( totalNumberOfBytes.QuadPart > 1024*1024*10 )
502 {
503
504 wprintf(
505 L"Verifying %dM\n",
506 (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024))
507 );
508 }
509 else
510 {
511 wprintf(
512 L"Verifying %.1fM\n",
513 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0)
514 );
515 }
516 }
517 else
518 {
519 if ( totalNumberOfBytes.QuadPart > 1024*1024*10 )
520 {
521 wprintf(
522 L"QuickFormatting %dM\n",
523 (DWORD) (totalNumberOfBytes.QuadPart / (1024 * 1024))
524 );
525 }
526 else
527 {
528 wprintf(
529 L"QuickFormatting %.2fM\n",
530 ((float)(LONGLONG)totalNumberOfBytes.QuadPart) / (float)(1024.0*1024.0)
531 );
532 }
533 wprintf(L"Creating file system structures.\n");
534 }
535 //
536 // Format away!
537 //
538 FormatEx(
539 RootDirectory,
540 media,
541 Format,
542 Label,
543 QuickFormat,
544 ClusterSize,
545 FormatExCallback
546 );
547 if ( Error ) return -1;
548 wprintf(L"Format complete.\n");
549 //
550 // Enable compression if desired
551 //
552 if ( CompressDrive )
553 {
554 if( !EnableVolumeCompression( RootDirectory, TRUE ))
555 {
556 wprintf(L"Volume does not support compression.\n");
557 }
558 }
559 //
560 // Get the label if we don't have it
561 //
562 if( !GotALabel )
563 {
564 wprintf(L"Volume Label (11 characters, Enter for none)? " );
565 fgetws(
566 input,
567 WBUFSIZE(LabelString),
568 stdin
569 );
570
571 input[ wcslen(input) - 1 ] = 0;
572 if( !SetVolumeLabelW( RootDirectory, input ))
573 {
574 PrintWin32Error(
575 L"Could not label volume",
576 GetLastError()
577 );
578 return -1;
579 }
580 }
581 if ( !GetVolumeInformationW(
582 RootDirectory,
583 volumeName,
584 WBUFSIZE(volumeName),
585 & serialNumber,
586 & maxComponent,
587 & flags,
588 fileSystem,
589 WBUFSIZE(fileSystem) )
590 ) {
591 PrintWin32Error(
592 L"Could not query volume",
593 GetLastError()
594 );
595 return -1;
596 }
597 //
598 // Print out some stuff including the formatted size
599 //
600 if ( !GetDiskFreeSpaceExW(
601 RootDirectory,
602 & freeBytesAvailableToCaller,
603 & totalNumberOfBytes,
604 & totalNumberOfFreeBytes )
605 ) {
606 PrintWin32Error(
607 L"Could not query volume size",
608 GetLastError()
609 );
610 return -1;
611 }
612 wprintf(
613 L"\n%I64d bytes total disk space.\n",
614 totalNumberOfBytes.QuadPart
615 );
616 wprintf(
617 L"%I64d bytes available on disk.\n",
618 totalNumberOfFreeBytes.QuadPart
619 );
620 //
621 // Get the drive's serial number
622 //
623 if ( !GetVolumeInformationW(
624 RootDirectory,
625 volumeName,
626 WBUFSIZE(volumeName),
627 & serialNumber,
628 & maxComponent,
629 & flags,
630 fileSystem,
631 WBUFSIZE(fileSystem) )
632 ) {
633 PrintWin32Error(
634 L"Could not query volume",
635 GetLastError()
636 );
637 return -1;
638 }
639 wprintf(
640 L"\nVolume Serial Number is %04X-%04X\n",
641 serialNumber >> 16,
642 serialNumber & 0xFFFF
643 );
644 return 0;
645 }
646
647
648 /* EOF */