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