8c356e63e5deb431bd21ffe6778a4800fbcf574b
[reactos.git] / base / system / format / format.c
1 // Copyright (c) 1998 Mark Russinovich
2 // Systems Internals
3 // http://www.sysinternals.com
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <windows.h>
8 #include <winternl.h>
9 #include <fmifs/fmifs.h>
10 #include <tchar.h>
11 #include "resource.h"
12
13 // Globals
14 BOOL Error = FALSE;
15
16 // switches
17 BOOL QuickFormat = FALSE;
18 DWORD ClusterSize = 0;
19 BOOL CompressDrive = FALSE;
20 BOOL GotALabel = FALSE;
21 LPTSTR Label = _T("");
22 LPTSTR Drive = NULL;
23 LPTSTR Format = _T("FAT");
24
25 TCHAR RootDirectory[MAX_PATH];
26 TCHAR LabelString[12];
27
28 //
29 // Size array
30 //
31 typedef struct {
32 TCHAR SizeString[16];
33 DWORD ClusterSize;
34 } SIZEDEFINITION, *PSIZEDEFINITION;
35
36 SIZEDEFINITION LegalSizes[] = {
37 { _T("512"), 512 },
38 { _T("1024"), 1024 },
39 { _T("2048"), 2048 },
40 { _T("4096"), 4096 },
41 { _T("8192"), 8192 },
42 { _T("16K"), 16384 },
43 { _T("32K"), 32768 },
44 { _T("64K"), 65536 },
45 { _T("128K"), 65536 * 2 },
46 { _T("256K"), 65536 * 4 },
47 { _T(""), 0 },
48 };
49
50
51 int LoadStringAndOem(HINSTANCE hInst,
52 UINT uID,
53 LPTSTR szStr,
54 int Siz
55 )
56 {
57 TCHAR szTmp[RC_STRING_MAX_SIZE];
58 int res = LoadString(hInst, uID, szTmp, sizeof(szTmp));
59 CharToOem(szTmp, szStr);
60 return(res);
61 }
62
63
64 //----------------------------------------------------------------------
65 //
66 // PrintWin32Error
67 //
68 // Takes the win32 error code and prints the text version.
69 //
70 //----------------------------------------------------------------------
71 static VOID PrintWin32Error( LPTSTR Message, DWORD ErrorCode )
72 {
73 LPTSTR lpMsgBuf;
74
75 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
76 NULL, ErrorCode,
77 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
78 (LPTSTR)&lpMsgBuf, 0, NULL );
79
80 _tprintf(_T("%s: %s\n"), Message, lpMsgBuf );
81 LocalFree( lpMsgBuf );
82 }
83
84
85 //----------------------------------------------------------------------
86 //
87 // ParseCommandLine
88 //
89 // Get the switches.
90 //
91 //----------------------------------------------------------------------
92 static int ParseCommandLine( int argc, TCHAR *argv[] )
93 {
94 int i, j;
95 BOOLEAN gotFormat = FALSE;
96 BOOLEAN gotQuick = FALSE;
97 BOOLEAN gotSize = FALSE;
98 BOOLEAN gotLabel = FALSE;
99 BOOLEAN gotCompressed = FALSE;
100
101
102 for( i = 1; i < argc; i++ ) {
103
104 switch( argv[i][0] ) {
105
106 case '-':
107 case '/':
108
109 if( !_tcsnicmp( &argv[i][1], _T("FS:"), 3 )) {
110
111 if( gotFormat) return -1;
112 Format = &argv[i][4];
113 gotFormat = TRUE;
114
115
116 } else if( !_tcsnicmp( &argv[i][1], _T("A:"), 2 )) {
117
118 if( gotSize ) return -1;
119 j = 0;
120 while( LegalSizes[j].ClusterSize &&
121 _tcsicmp( LegalSizes[j].SizeString, &argv[i][3] )) j++;
122
123 if( !LegalSizes[j].ClusterSize ) return i;
124 ClusterSize = LegalSizes[j].ClusterSize;
125 gotSize = TRUE;
126
127 } else if( ! _tcsnicmp( &argv[i][1], _T("V:"), 2 )) {
128
129 if( gotLabel ) return -1;
130 Label = &argv[i][3];
131 gotLabel = TRUE;
132 GotALabel = TRUE;
133
134 } else if( !_tcsicmp( &argv[i][1], _T("Q") )) {
135
136 if( gotQuick ) return -1;
137 QuickFormat = TRUE;
138 gotQuick = TRUE;
139
140 } else if( !_tcsicmp( &argv[i][1], _T("C") )) {
141
142 if( gotCompressed ) return -1;
143 CompressDrive = TRUE;
144 gotCompressed = TRUE;
145
146 } else return i;
147 break;
148
149 default:
150
151 if( Drive ) return i;
152 if( argv[i][1] != _T(':') ) return i;
153
154 Drive = argv[i];
155 break;
156 }
157 }
158 return 0;
159 }
160
161 //----------------------------------------------------------------------
162 //
163 // FormatExCallback
164 //
165 // The file system library will call us back with commands that we
166 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
167 //
168 //----------------------------------------------------------------------
169 BOOLEAN WINAPI
170 FormatExCallback (
171 CALLBACKCOMMAND Command,
172 ULONG Modifier,
173 PVOID Argument)
174 {
175 PDWORD percent;
176 PTEXTOUTPUT output;
177 PBOOLEAN status;
178 TCHAR szMsg[RC_STRING_MAX_SIZE];
179
180 //
181 // We get other types of commands, but we don't have to pay attention to them
182 //
183 switch( Command ) {
184
185 case PROGRESS:
186 percent = (PDWORD) Argument;
187 LoadStringAndOem( GetModuleHandle(NULL), STRING_COMPLETE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
188 _tprintf(szMsg, *percent);
189 break;
190
191 case OUTPUT:
192 output = (PTEXTOUTPUT) Argument;
193 fprintf(stdout, "%s", output->Output);
194 break;
195
196 case DONE:
197 status = (PBOOLEAN) Argument;
198 if( *status == FALSE ) {
199
200 LoadStringAndOem( GetModuleHandle(NULL), STRING_FORMAT_FAIL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
201 _tprintf("%s", szMsg);
202 Error = TRUE;
203 }
204 break;
205 case DONEWITHSTRUCTURE:
206 case UNKNOWN2:
207 case UNKNOWN3:
208 case UNKNOWN4:
209 case UNKNOWN5:
210 case INSUFFICIENTRIGHTS:
211 case FSNOTSUPPORTED:
212 case VOLUMEINUSE:
213 case UNKNOWN9:
214 case UNKNOWNA:
215 case UNKNOWNC:
216 case UNKNOWND:
217 case STRUCTUREPROGRESS:
218 case CLUSTERSIZETOOSMALL:
219 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_SUPPORT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
220 _tprintf("%s", szMsg);
221 return FALSE;
222 }
223 return TRUE;
224 }
225
226
227 //----------------------------------------------------------------------
228 //
229 // LoadFMIFSEntryPoints
230 //
231 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
232 //
233 //----------------------------------------------------------------------
234 BOOLEAN LoadFMIFSEntryPoints()
235 {
236 HMODULE hFmifs = LoadLibrary( _T("fmifs.dll") );
237 if( !(void*) GetProcAddress( hFmifs, "FormatEx" ) ) {
238
239 return FALSE;
240 }
241
242 if( !((void *) GetProcAddress( hFmifs,
243 "EnableVolumeCompression" )) ) {
244
245 return FALSE;
246 }
247
248 if( !((void *) GetProcAddress( hFmifs,
249 "QueryAvailableFileSystemFormat" )) ) {
250
251 return FALSE;
252 }
253
254 return TRUE;
255 }
256
257
258 //----------------------------------------------------------------------
259 //
260 // Usage
261 //
262 // Tell the user how to use the program
263 //
264 //----------------------------------------------------------------------
265 static VOID Usage( LPTSTR ProgramName )
266 {
267 TCHAR szMsg[RC_STRING_MAX_SIZE];
268 TCHAR szFormats[MAX_PATH];
269 #ifndef UNICODE
270 TCHAR szFormatA[MAX_PATH];
271 #endif
272 WCHAR szFormatW[MAX_PATH];
273 DWORD Index = 0;
274 BYTE dummy;
275 BOOLEAN lastestVersion;
276
277 LoadStringAndOem( GetModuleHandle(NULL), STRING_HELP, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
278 if (!LoadFMIFSEntryPoints())
279 {
280 _tprintf(szMsg, ProgramName, _T(""));
281 return;
282 }
283
284 szFormats[0] = 0;
285 while (QueryAvailableFileSystemFormat(Index++, szFormatW, &dummy, &dummy, &lastestVersion))
286 {
287 if (!lastestVersion)
288 continue;
289 if (szFormats[0])
290 _tcscat(szFormats, _T(", "));
291 #ifdef UNICODE
292 _tcscat(szFormats, szFormatW);
293 #else
294 if (0 != WideCharToMultiByte(CP_ACP, 0, szFormatW, -1, szFormatA, sizeof(szFormatA), NULL, NULL))
295 _tcscat(szFormats, szFormatA);
296 #endif
297 }
298 _tprintf(szMsg, ProgramName, szFormats);
299 }
300
301
302 //----------------------------------------------------------------------
303 //
304 // WMain
305 //
306 // Engine. Just get command line switches and fire off a format. This
307 // could also be done in a GUI like Explorer does when you select a
308 // drive and run a check on it.
309 //
310 // We do this in UNICODE because the chkdsk command expects PWCHAR
311 // arguments.
312 //
313 //----------------------------------------------------------------------
314 int
315 _tmain(int argc, TCHAR *argv[])
316 {
317 int badArg;
318 DWORD media = FMIFS_HARDDISK;
319 DWORD driveType;
320 TCHAR fileSystem[1024];
321 TCHAR volumeName[1024];
322 TCHAR input[1024];
323 DWORD serialNumber;
324 DWORD flags, maxComponent;
325 ULARGE_INTEGER freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes;
326 #ifndef UNICODE
327 WCHAR RootDirectoryW[MAX_PATH], FormatW[MAX_PATH], LabelW[MAX_PATH];
328 #endif
329 TCHAR szMsg[RC_STRING_MAX_SIZE];
330
331 //
332 // Get function pointers
333 //
334 if( !LoadFMIFSEntryPoints()) {
335 LoadStringAndOem( GetModuleHandle(NULL), STRING_FMIFS_FAIL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
336 _tprintf("%s", szMsg);
337 return -1;
338 }
339
340 //
341 // Parse command line
342 //
343 if( (badArg = ParseCommandLine( argc, argv ))) {
344
345 LoadStringAndOem( GetModuleHandle(NULL), STRING_UNKNOW_ARG, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
346 _tprintf(szMsg, argv[badArg] );
347
348 Usage(argv[0]);
349 return -1;
350 }
351
352 //
353 // Get the drive's format
354 //
355 if( !Drive ) {
356
357 LoadStringAndOem( GetModuleHandle(NULL), STRING_DRIVE_PARM, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
358 _tprintf(szMsg);
359 Usage( argv[0] );
360 return -1;
361
362 } else {
363
364 _tcscpy( RootDirectory, Drive );
365 }
366 RootDirectory[2] = _T('\\');
367 RootDirectory[3] = _T('\0');
368
369 //
370 // See if the drive is removable or not
371 //
372 driveType = GetDriveType( RootDirectory );
373
374 if( driveType == 0 ) {
375 LoadStringAndOem( GetModuleHandle(NULL), STRING_ERROR_DRIVE_TYPE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
376 PrintWin32Error( szMsg, GetLastError());
377 return -1;
378 }
379 else if ( driveType == 1 )
380 {
381 LoadString( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
382 PrintWin32Error( szMsg, GetLastError());
383 return -1;
384 }
385
386 if( driveType != DRIVE_FIXED ) {
387 LoadStringAndOem( GetModuleHandle(NULL), STRING_INSERT_DISK, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
388 _tprintf(szMsg, RootDirectory[0] );
389 _fgetts( input, sizeof(input)/2, stdin );
390
391 media = FMIFS_FLOPPY;
392 }
393
394 //
395 // Determine the drive's file system format
396 //
397 if( !GetVolumeInformation( RootDirectory,
398 volumeName, sizeof(volumeName)/2,
399 &serialNumber, &maxComponent, &flags,
400 fileSystem, sizeof(fileSystem)/2)) {
401
402 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
403 PrintWin32Error( szMsg, GetLastError());
404 return -1;
405 }
406
407 if( !GetDiskFreeSpaceEx( RootDirectory,
408 &freeBytesAvailableToCaller,
409 &totalNumberOfBytes,
410 &totalNumberOfFreeBytes )) {
411
412 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME_SIZE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
413 PrintWin32Error( szMsg, GetLastError());
414 return -1;
415 }
416 LoadStringAndOem( GetModuleHandle(NULL), STRING_FILESYSTEM, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
417 _tprintf(szMsg, fileSystem );
418
419 //
420 // Make sure they want to do this
421 //
422 if( driveType == DRIVE_FIXED ) {
423
424 if( volumeName[0] ) {
425
426 while(1 ) {
427
428 LoadStringAndOem( GetModuleHandle(NULL), STRING_LABEL_NAME_EDIT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
429 _tprintf(szMsg, RootDirectory[0] );
430 _fgetts( input, sizeof(input)/2, stdin );
431 input[ _tcslen( input ) - 1] = 0;
432
433 if( !_tcsicmp( input, volumeName )) {
434
435 break;
436 }
437 LoadStringAndOem( GetModuleHandle(NULL), STRING_ERROR_LABEL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
438 _tprintf("%s", szMsg);
439 }
440 }
441
442 LoadStringAndOem( GetModuleHandle(NULL), STRING_YN_FORMAT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
443 _tprintf(szMsg, RootDirectory[0] );
444
445 LoadStringAndOem( GetModuleHandle(NULL), STRING_YES_NO_FAQ, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
446
447 while( 1 ) {
448 _fgetts( input, sizeof(input)/2, stdin );
449 if(_strnicmp(&input[0],&szMsg[0],1) == 0) break;
450 if(_strnicmp(&input[0],&szMsg[1],1) == 0) {
451 _tprintf(_T("\n"));
452 return 0;
453 }
454 }
455 media = FMIFS_HARDDISK;
456 }
457
458 //
459 // Tell the user we're doing a long format if appropriate
460 //
461 if( !QuickFormat ) {
462
463 LoadString( GetModuleHandle(NULL), STRING_VERIFYING, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
464
465 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
466
467 _tprintf(_T("%s %luM\n"),szMsg, (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
468
469 } else {
470
471 _tprintf(_T("%s %.1fM\n"),szMsg,
472 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
473 }
474 } else {
475
476 LoadStringAndOem( GetModuleHandle(NULL), STRING_FAST_FMT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
477 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
478
479 _tprintf(_T("%s %luM\n"),szMsg, (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
480
481 } else {
482
483 _tprintf(_T("%s %.2fM\n"),szMsg,
484 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
485 }
486 LoadStringAndOem( GetModuleHandle(NULL), STRING_CREATE_FSYS, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
487 _tprintf("%s", szMsg);
488 }
489
490 //
491 // Format away!
492 //
493 #ifndef UNICODE
494 MultiByteToWideChar(CP_ACP, 0, RootDirectory, -1, RootDirectoryW, MAX_PATH);
495 MultiByteToWideChar(CP_ACP, 0, Format, -1, FormatW, MAX_PATH);
496 MultiByteToWideChar(CP_ACP, 0, Label, -1, LabelW, MAX_PATH);
497 FormatEx( RootDirectoryW, media, FormatW, LabelW, QuickFormat,
498 ClusterSize, FormatExCallback );
499 #else
500 FormatEx( RootDirectory, media, Format, Label, QuickFormat,
501 ClusterSize, FormatExCallback );
502 #endif
503 if( Error ) return -1;
504 LoadStringAndOem( GetModuleHandle(NULL), STRING_FMT_COMPLETE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
505 _tprintf("%s", szMsg);
506
507 //
508 // Enable compression if desired
509 //
510 if( CompressDrive ) {
511
512 #ifndef UNICODE
513 MultiByteToWideChar(CP_ACP, 0, RootDirectory, -1, RootDirectoryW, MAX_PATH);
514 if( !EnableVolumeCompression( RootDirectoryW, TRUE )) {
515 #else
516 if( !EnableVolumeCompression( RootDirectory, TRUE )) {
517 #endif
518
519 LoadStringAndOem( GetModuleHandle(NULL), STRING_VOL_COMPRESS, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
520 _tprintf("%s", szMsg);
521 }
522 }
523
524 //
525 // Get the label if we don't have it
526 //
527 if( !GotALabel ) {
528
529 LoadString( GetModuleHandle(NULL), STRING_ENTER_LABEL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
530 _tprintf("%s", szMsg);
531 _fgetts( input, sizeof(LabelString)/2, stdin );
532
533 input[ _tcslen(input)-1] = 0;
534 if( !SetVolumeLabel( RootDirectory, input )) {
535
536 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_LABEL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
537 PrintWin32Error(szMsg, GetLastError());
538 return -1;
539 }
540 }
541
542 if( !GetVolumeInformation( RootDirectory,
543 volumeName, sizeof(volumeName)/2,
544 &serialNumber, &maxComponent, &flags,
545 fileSystem, sizeof(fileSystem)/2)) {
546
547 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
548 PrintWin32Error( szMsg, GetLastError());
549 return -1;
550 }
551
552 //
553 // Print out some stuff including the formatted size
554 //
555 if( !GetDiskFreeSpaceEx( RootDirectory,
556 &freeBytesAvailableToCaller,
557 &totalNumberOfBytes,
558 &totalNumberOfFreeBytes )) {
559
560 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME_SIZE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
561 PrintWin32Error(szMsg, GetLastError());
562 return -1;
563 }
564
565 LoadStringAndOem( GetModuleHandle(NULL), STRING_FREE_SPACE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
566 _tprintf(szMsg, totalNumberOfBytes.QuadPart, totalNumberOfFreeBytes.QuadPart );
567
568 //
569 // Get the drive's serial number
570 //
571 if( !GetVolumeInformation( RootDirectory,
572 volumeName, sizeof(volumeName)/2,
573 &serialNumber, &maxComponent, &flags,
574 fileSystem, sizeof(fileSystem)/2)) {
575
576 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
577 PrintWin32Error( szMsg, GetLastError());
578 return -1;
579 }
580 LoadStringAndOem( GetModuleHandle(NULL), STRING_SERIAL_NUMBER, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
581 _tprintf(szMsg, (unsigned int)(serialNumber >> 16),
582 (unsigned int)(serialNumber & 0xFFFF) );
583
584 return 0;
585 }
586