- Synchronize up to trunk's revision r57864.
[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 switch (driveType)
374 {
375 case DRIVE_UNKNOWN :
376 LoadStringAndOem( GetModuleHandle(NULL), STRING_ERROR_DRIVE_TYPE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
377 PrintWin32Error( szMsg, GetLastError());
378 return -1;
379
380 case DRIVE_REMOTE:
381 case DRIVE_CDROM:
382 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_SUPPORT, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
383 _tprintf(szMsg);
384 return -1;
385
386 case DRIVE_NO_ROOT_DIR:
387 LoadString( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
388 PrintWin32Error( szMsg, GetLastError());
389 return -1;
390
391 case DRIVE_REMOVABLE:
392 LoadStringAndOem( GetModuleHandle(NULL), STRING_INSERT_DISK, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
393 _tprintf(szMsg, RootDirectory[0] );
394 _fgetts( input, sizeof(input)/2, stdin );
395 media = FMIFS_FLOPPY;
396 break;
397
398 case DRIVE_FIXED:
399 case DRIVE_RAMDISK:
400 media = FMIFS_HARDDISK;
401 break;
402 }
403
404 // Reject attempts to format the system drive
405 {
406 TCHAR path[MAX_PATH + 1];
407 UINT rc;
408 rc = GetWindowsDirectory(path, MAX_PATH);
409 if (rc == 0 || rc > MAX_PATH)
410 // todo: Report "Unable to query system directory"
411 return -1;
412 if (_totlower(path[0]) == _totlower(Drive[0]))
413 {
414 // todo: report "Cannot format system drive"
415 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_SUPPORT, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
416 _tprintf(szMsg);
417 return -1;
418 }
419 }
420
421 //
422 // Determine the drive's file system format
423 //
424 if( !GetVolumeInformation( RootDirectory,
425 volumeName, sizeof(volumeName)/2,
426 &serialNumber, &maxComponent, &flags,
427 fileSystem, sizeof(fileSystem)/2)) {
428
429 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
430 PrintWin32Error( szMsg, GetLastError());
431 return -1;
432 }
433
434 if( !GetDiskFreeSpaceEx( RootDirectory,
435 &freeBytesAvailableToCaller,
436 &totalNumberOfBytes,
437 &totalNumberOfFreeBytes )) {
438
439 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME_SIZE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
440 PrintWin32Error( szMsg, GetLastError());
441 return -1;
442 }
443 LoadStringAndOem( GetModuleHandle(NULL), STRING_FILESYSTEM, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
444 _tprintf(szMsg, fileSystem );
445
446 //
447 // Make sure they want to do this
448 //
449 if( driveType == DRIVE_FIXED ) {
450
451 if( volumeName[0] ) {
452
453 while(1 ) {
454
455 LoadStringAndOem( GetModuleHandle(NULL), STRING_LABEL_NAME_EDIT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
456 _tprintf(szMsg, RootDirectory[0] );
457 _fgetts( input, sizeof(input)/2, stdin );
458 input[ _tcslen( input ) - 1] = 0;
459
460 if( !_tcsicmp( input, volumeName )) {
461
462 break;
463 }
464 LoadStringAndOem( GetModuleHandle(NULL), STRING_ERROR_LABEL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
465 _tprintf("%s", szMsg);
466 }
467 }
468
469 LoadStringAndOem( GetModuleHandle(NULL), STRING_YN_FORMAT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
470 _tprintf(szMsg, RootDirectory[0] );
471
472 LoadStringAndOem( GetModuleHandle(NULL), STRING_YES_NO_FAQ, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
473
474 while( 1 ) {
475 _fgetts( input, sizeof(input)/2, stdin );
476 if(_strnicmp(&input[0],&szMsg[0],1) == 0) break;
477 if(_strnicmp(&input[0],&szMsg[1],1) == 0) {
478 _tprintf(_T("\n"));
479 return 0;
480 }
481 }
482 }
483
484 //
485 // Tell the user we're doing a long format if appropriate
486 //
487 if( !QuickFormat ) {
488
489 LoadString( GetModuleHandle(NULL), STRING_VERIFYING, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
490
491 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
492
493 _tprintf(_T("%s %luM\n"),szMsg, (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
494
495 } else {
496
497 _tprintf(_T("%s %.1fM\n"),szMsg,
498 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
499 }
500 } else {
501
502 LoadStringAndOem( GetModuleHandle(NULL), STRING_FAST_FMT, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
503 if( totalNumberOfBytes.QuadPart > 1024*1024*10 ) {
504
505 _tprintf(_T("%s %luM\n"),szMsg, (DWORD) (totalNumberOfBytes.QuadPart/(1024*1024)));
506
507 } else {
508
509 _tprintf(_T("%s %.2fM\n"),szMsg,
510 ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0));
511 }
512 LoadStringAndOem( GetModuleHandle(NULL), STRING_CREATE_FSYS, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
513 _tprintf("%s", szMsg);
514 }
515
516 //
517 // Format away!
518 //
519 #ifndef UNICODE
520 MultiByteToWideChar(CP_ACP, 0, RootDirectory, -1, RootDirectoryW, MAX_PATH);
521 MultiByteToWideChar(CP_ACP, 0, Format, -1, FormatW, MAX_PATH);
522 MultiByteToWideChar(CP_ACP, 0, Label, -1, LabelW, MAX_PATH);
523 FormatEx( RootDirectoryW, media, FormatW, LabelW, QuickFormat,
524 ClusterSize, FormatExCallback );
525 #else
526 FormatEx( RootDirectory, media, Format, Label, QuickFormat,
527 ClusterSize, FormatExCallback );
528 #endif
529 if( Error ) return -1;
530 LoadStringAndOem( GetModuleHandle(NULL), STRING_FMT_COMPLETE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
531 _tprintf("%s", szMsg);
532
533 //
534 // Enable compression if desired
535 //
536 if( CompressDrive ) {
537
538 #ifndef UNICODE
539 MultiByteToWideChar(CP_ACP, 0, RootDirectory, -1, RootDirectoryW, MAX_PATH);
540 if( !EnableVolumeCompression( RootDirectoryW, TRUE )) {
541 #else
542 if( !EnableVolumeCompression( RootDirectory, TRUE )) {
543 #endif
544
545 LoadStringAndOem( GetModuleHandle(NULL), STRING_VOL_COMPRESS, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
546 _tprintf("%s", szMsg);
547 }
548 }
549
550 //
551 // Get the label if we don't have it
552 //
553 if( !GotALabel ) {
554
555 LoadString( GetModuleHandle(NULL), STRING_ENTER_LABEL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
556 _tprintf("%s", szMsg);
557 _fgetts( input, sizeof(LabelString)/2, stdin );
558
559 input[ _tcslen(input)-1] = 0;
560 if( !SetVolumeLabel( RootDirectory, input )) {
561
562 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_LABEL, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
563 PrintWin32Error(szMsg, GetLastError());
564 return -1;
565 }
566 }
567
568 if( !GetVolumeInformation( RootDirectory,
569 volumeName, sizeof(volumeName)/2,
570 &serialNumber, &maxComponent, &flags,
571 fileSystem, sizeof(fileSystem)/2)) {
572
573 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
574 PrintWin32Error( szMsg, GetLastError());
575 return -1;
576 }
577
578 //
579 // Print out some stuff including the formatted size
580 //
581 if( !GetDiskFreeSpaceEx( RootDirectory,
582 &freeBytesAvailableToCaller,
583 &totalNumberOfBytes,
584 &totalNumberOfFreeBytes )) {
585
586 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME_SIZE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
587 PrintWin32Error(szMsg, GetLastError());
588 return -1;
589 }
590
591 LoadStringAndOem( GetModuleHandle(NULL), STRING_FREE_SPACE, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
592 _tprintf(szMsg, totalNumberOfBytes.QuadPart, totalNumberOfFreeBytes.QuadPart );
593
594 //
595 // Get the drive's serial number
596 //
597 if( !GetVolumeInformation( RootDirectory,
598 volumeName, sizeof(volumeName)/2,
599 &serialNumber, &maxComponent, &flags,
600 fileSystem, sizeof(fileSystem)/2)) {
601
602 LoadStringAndOem( GetModuleHandle(NULL), STRING_NO_VOLUME, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
603 PrintWin32Error( szMsg, GetLastError());
604 return -1;
605 }
606 LoadStringAndOem( GetModuleHandle(NULL), STRING_SERIAL_NUMBER, (LPTSTR) szMsg,RC_STRING_MAX_SIZE);
607 _tprintf(szMsg, (unsigned int)(serialNumber >> 16),
608 (unsigned int)(serialNumber & 0xFFFF) );
609
610 return 0;
611 }
612