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