1 //======================================================================
5 // Copyright (c) 1998 Mark Russinovich
7 // http://www.sysinternals.com
9 // Format clone that demonstrates the use of the FMIFS file system
12 // --------------------------------------------------------------------
14 // This software is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Library General Public License as
16 // published by the Free Software Foundation; either version 2 of the
17 // License, or (at your option) any later version.
19 // This software is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Library General Public License for more details.
24 // You should have received a copy of the GNU Library General Public
25 // License along with this software; see the file COPYING.LIB. If
26 // not, write to the Free Software Foundation, Inc., 675 Mass Ave,
27 // Cambridge, MA 02139, USA.
29 // --------------------------------------------------------------------
31 // 1999 February (Emanuele Aliberti)
32 // Adapted for ReactOS and lcc-win32.
34 // 1999 April (Emanuele Aliberti)
35 // Adapted for ReactOS and egcs.
37 // 2003 April (Casper S. Hornstrup)
40 //======================================================================
45 /* PSDK/NDK Headers */
46 #define WIN32_NO_STATUS
52 #define NTOS_MODE_USER
53 #include <ndk/rtlfuncs.h>
55 /* FMIFS Public Header */
56 #include <fmifs/fmifs.h>
60 #define FMIFS_IMPORT_DLL
66 BOOL QuickFormat
= FALSE
;
67 DWORD ClusterSize
= 0;
68 BOOL CompressDrive
= FALSE
;
69 BOOL GotALabel
= FALSE
;
72 PWCHAR FileSystem
= L
"FAT";
74 WCHAR RootDirectory
[MAX_PATH
];
75 WCHAR LabelString
[12];
77 #ifndef FMIFS_IMPORT_DLL
79 // Functions in FMIFS.DLL
82 PENABLEVOLUMECOMPRESSION EnableVolumeCompression
;
83 PQUERYAVAILABLEFILESYSTEMFORMAT QueryAvailableFileSystemFormat
;
93 } SIZEDEFINITION
, *PSIZEDEFINITION
;
95 SIZEDEFINITION LegalSizes
[] = {
104 { L
"128K", 65536 * 2 },
105 { L
"256K", 65536 * 4 },
110 //----------------------------------------------------------------------
114 // Takes the win32 error code and prints the text version.
116 //----------------------------------------------------------------------
117 static VOID
PrintWin32Error(LPWSTR Message
, DWORD ErrorCode
)
119 ConPrintf(StdErr
, L
"%s: ", Message
);
120 ConMsgPuts(StdErr
, FORMAT_MESSAGE_FROM_SYSTEM
,
121 NULL
, ErrorCode
, LANG_USER_DEFAULT
);
122 ConPuts(StdErr
, L
"\n");
126 //----------------------------------------------------------------------
132 //----------------------------------------------------------------------
133 static int ParseCommandLine(int argc
, WCHAR
*argv
[])
136 BOOLEAN gotFormat
= FALSE
;
137 BOOLEAN gotQuick
= FALSE
;
138 BOOLEAN gotSize
= FALSE
;
139 BOOLEAN gotLabel
= FALSE
;
140 BOOLEAN gotCompressed
= FALSE
;
142 for (i
= 1; i
< argc
; i
++)
146 case L
'-': case L
'/':
148 if (!_wcsnicmp(&argv
[i
][1], L
"FS:", 3))
150 if (gotFormat
) return -1;
151 FileSystem
= &argv
[i
][4];
154 else if (!_wcsnicmp(&argv
[i
][1], L
"A:", 2))
156 if (gotSize
) return -1;
158 while (LegalSizes
[j
].ClusterSize
&&
159 wcsicmp(LegalSizes
[j
].SizeString
, &argv
[i
][3]))
164 if (!LegalSizes
[j
].ClusterSize
) return i
;
165 ClusterSize
= LegalSizes
[j
].ClusterSize
;
168 else if (!_wcsnicmp(&argv
[i
][1], L
"V:", 2))
170 if (gotLabel
) return -1;
175 else if (!wcsicmp(&argv
[i
][1], L
"Q"))
177 if (gotQuick
) return -1;
181 else if (!wcsicmp(&argv
[i
][1], L
"C"))
183 if (gotCompressed
) return -1;
184 CompressDrive
= TRUE
;
185 gotCompressed
= TRUE
;
196 if (argv
[i
][1] != L
':') return i
;
206 //----------------------------------------------------------------------
210 // The file system library will call us back with commands that we
211 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
213 //----------------------------------------------------------------------
216 CALLBACKCOMMAND Command
,
225 // We get other types of commands, but we don't have to pay attention to them
230 percent
= (PDWORD
)Argument
;
231 ConResPrintf(StdOut
, STRING_COMPLETE
, *percent
);
235 output
= (PTEXTOUTPUT
)Argument
;
236 ConPrintf(StdOut
, L
"%S\n", output
->Output
);
240 status
= (PBOOLEAN
)Argument
;
241 if (*status
== FALSE
)
243 ConResPuts(StdOut
, STRING_FORMAT_FAIL
);
248 case DONEWITHSTRUCTURE
:
253 case INSUFFICIENTRIGHTS
:
260 case STRUCTUREPROGRESS
:
261 case CLUSTERSIZETOOSMALL
:
262 ConResPuts(StdOut
, STRING_NO_SUPPORT
);
268 #ifndef FMIFS_IMPORT_DLL
269 //----------------------------------------------------------------------
271 // LoadFMIFSEntryPoints
273 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
275 //----------------------------------------------------------------------
276 static BOOLEAN
LoadFMIFSEntryPoints(VOID
)
278 HMODULE hFmifs
= LoadLibraryW( L
"fmifs.dll");
282 FormatEx
= (PFORMATEX
)GetProcAddress(hFmifs
, "FormatEx");
289 EnableVolumeCompression
= (PENABLEVOLUMECOMPRESSION
)GetProcAddress(hFmifs
, "EnableVolumeCompression");
290 if (!EnableVolumeCompression
)
296 QueryAvailableFileSystemFormat
= (PQUERYAVAILABLEFILESYSTEMFORMAT
)GetProcAddress(hFmifs
, "QueryAvailableFileSystemFormat");
297 if (!QueryAvailableFileSystemFormat
)
308 //----------------------------------------------------------------------
312 // Tell the user how to use the program
314 //----------------------------------------------------------------------
315 static VOID
Usage(LPWSTR ProgramName
)
317 WCHAR szMsg
[RC_STRING_MAX_SIZE
];
318 WCHAR szFormats
[MAX_PATH
];
319 WCHAR szFormatW
[MAX_PATH
];
322 BOOLEAN latestVersion
;
324 K32LoadStringW(GetModuleHandle(NULL
), STRING_HELP
, szMsg
, ARRAYSIZE(szMsg
));
326 #ifndef FMIFS_IMPORT_DLL
327 if (!LoadFMIFSEntryPoints())
329 ConPrintf(StdOut
, szMsg
, ProgramName
, L
"");
335 while (QueryAvailableFileSystemFormat(Index
++, szFormatW
, &dummy
, &dummy
, &latestVersion
))
340 wcscat(szFormats
, L
", ");
342 wcscat(szFormats
, szFormatW
);
344 ConPrintf(StdOut
, szMsg
, ProgramName
, szFormats
);
348 //----------------------------------------------------------------------
352 // Engine. Just get command line switches and fire off a format. This
353 // could also be done in a GUI like Explorer does when you select a
354 // drive and run a check on it.
356 // We do this in UNICODE because the chkdsk command expects PWCHAR
359 //----------------------------------------------------------------------
360 int wmain(int argc
, WCHAR
*argv
[])
363 DWORD media
= FMIFS_HARDDISK
;
365 WCHAR fileSystem
[1024];
366 WCHAR volumeName
[1024];
369 DWORD flags
, maxComponent
;
370 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
371 WCHAR szMsg
[RC_STRING_MAX_SIZE
];
373 /* Initialize the Console Standard Streams */
378 L
"Formatx v1.0 by Mark Russinovich\n"
379 L
"Systems Internals - http://www.sysinternals.com\n"
380 L
"ReactOS adaptation 1999 by Emanuele Aliberti\n\n");
382 #ifndef FMIFS_IMPORT_DLL
384 // Get function pointers
386 if (!LoadFMIFSEntryPoints())
388 ConResPuts(StdErr
, STRING_FMIFS_FAIL
);
394 // Parse command line
396 badArg
= ParseCommandLine(argc
, argv
);
399 ConResPrintf(StdErr
, STRING_UNKNOW_ARG
, argv
[badArg
]);
405 // Get the drive's format
409 ConResPuts(StdErr
, STRING_DRIVE_PARM
);
415 wcscpy(RootDirectory
, Drive
);
417 RootDirectory
[2] = L
'\\';
418 RootDirectory
[3] = L
'\0';
421 // See if the drive is removable or not
423 driveType
= GetDriveTypeW(RootDirectory
);
427 K32LoadStringW(GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, szMsg
, ARRAYSIZE(szMsg
));
428 PrintWin32Error(szMsg
, GetLastError());
433 ConResPuts(StdOut
, STRING_NO_SUPPORT
);
436 case DRIVE_NO_ROOT_DIR
:
437 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
438 PrintWin32Error(szMsg
, GetLastError());
441 case DRIVE_REMOVABLE
:
442 ConResPrintf(StdOut
, STRING_INSERT_DISK
, RootDirectory
[0]);
443 fgetws(input
, ARRAYSIZE(input
), stdin
);
444 media
= FMIFS_FLOPPY
;
449 media
= FMIFS_HARDDISK
;
453 // Reject attempts to format the system drive
455 WCHAR path
[MAX_PATH
+ 1];
457 rc
= GetWindowsDirectoryW(path
, MAX_PATH
);
458 if (rc
== 0 || rc
> MAX_PATH
)
459 // todo: Report "Unable to query system directory"
461 if (towlower(path
[0]) == towlower(Drive
[0]))
463 // todo: report "Cannot format system drive"
464 ConResPuts(StdOut
, STRING_NO_SUPPORT
);
470 // Determine the drive's file system format
472 if (!GetVolumeInformationW(RootDirectory
,
473 volumeName
, ARRAYSIZE(volumeName
),
474 &serialNumber
, &maxComponent
, &flags
,
475 fileSystem
, ARRAYSIZE(fileSystem
)))
477 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
478 PrintWin32Error(szMsg
, GetLastError());
482 if (!GetDiskFreeSpaceExW(RootDirectory
,
483 &freeBytesAvailableToCaller
,
485 &totalNumberOfFreeBytes
))
487 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, szMsg
, ARRAYSIZE(szMsg
));
488 PrintWin32Error(szMsg
, GetLastError());
491 ConResPrintf(StdOut
, STRING_FILESYSTEM
, fileSystem
);
494 // Make sure they want to do this
496 if (driveType
== DRIVE_FIXED
)
502 ConResPrintf(StdOut
, STRING_LABEL_NAME_EDIT
, RootDirectory
[0]);
503 fgetws(input
, ARRAYSIZE(input
), stdin
);
504 input
[wcslen(input
) - 1] = 0;
506 if (!wcsicmp(input
, volumeName
))
509 ConResPuts(StdOut
, STRING_ERROR_LABEL
);
513 ConResPrintf(StdOut
, STRING_YN_FORMAT
, RootDirectory
[0]);
515 K32LoadStringW(GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, szMsg
, ARRAYSIZE(szMsg
));
518 fgetws(input
, ARRAYSIZE(input
), stdin
);
519 if (_wcsnicmp(&input
[0], &szMsg
[0], 1) == 0) break;
520 if (_wcsnicmp(&input
[0], &szMsg
[1], 1) == 0)
522 ConPuts(StdOut
, L
"\n");
529 // Tell the user we're doing a long format if appropriate
533 K32LoadStringW(GetModuleHandle(NULL
), STRING_VERIFYING
, szMsg
, ARRAYSIZE(szMsg
));
534 if (totalNumberOfBytes
.QuadPart
> 1024*1024*10)
536 ConPrintf(StdOut
, L
"%s %luM\n", szMsg
, (DWORD
)(totalNumberOfBytes
.QuadPart
/(1024*1024)));
540 ConPrintf(StdOut
, L
"%s %.1fM\n", szMsg
,
541 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
546 K32LoadStringW(GetModuleHandle(NULL
), STRING_FAST_FMT
, szMsg
, ARRAYSIZE(szMsg
));
547 if (totalNumberOfBytes
.QuadPart
> 1024*1024*10)
549 ConPrintf(StdOut
, L
"%s %luM\n", szMsg
, (DWORD
)(totalNumberOfBytes
.QuadPart
/(1024*1024)));
553 ConPrintf(StdOut
, L
"%s %.2fM\n", szMsg
,
554 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
556 ConResPuts(StdOut
, STRING_CREATE_FSYS
);
562 FormatEx(RootDirectory
, media
, FileSystem
, Label
, QuickFormat
,
563 ClusterSize
, FormatExCallback
);
564 if (Error
) return -1;
565 ConResPuts(StdOut
, STRING_FMT_COMPLETE
);
568 // Enable compression if desired
572 if (!EnableVolumeCompression(RootDirectory
, TRUE
))
573 ConResPuts(StdOut
, STRING_VOL_COMPRESS
);
577 // Get the label if we don't have it
581 ConResPuts(StdOut
, STRING_ENTER_LABEL
);
582 fgetws(input
, ARRAYSIZE(LabelString
), stdin
);
584 input
[wcslen(input
) - 1] = 0;
585 if (!SetVolumeLabelW(RootDirectory
, input
))
587 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_LABEL
, szMsg
, ARRAYSIZE(szMsg
));
588 PrintWin32Error(szMsg
, GetLastError());
593 if (!GetVolumeInformationW(RootDirectory
,
594 volumeName
, ARRAYSIZE(volumeName
),
595 &serialNumber
, &maxComponent
, &flags
,
596 fileSystem
, ARRAYSIZE(fileSystem
)))
598 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
599 PrintWin32Error(szMsg
, GetLastError());
604 // Print out some stuff including the formatted size
606 if (!GetDiskFreeSpaceExW(RootDirectory
,
607 &freeBytesAvailableToCaller
,
609 &totalNumberOfFreeBytes
))
611 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, szMsg
, ARRAYSIZE(szMsg
));
612 PrintWin32Error(szMsg
, GetLastError());
616 ConResPrintf(StdOut
, STRING_FREE_SPACE
, totalNumberOfBytes
.QuadPart
,
617 totalNumberOfFreeBytes
.QuadPart
);
620 // Get the drive's serial number
622 if (!GetVolumeInformationW(RootDirectory
,
623 volumeName
, ARRAYSIZE(volumeName
),
624 &serialNumber
, &maxComponent
, &flags
,
625 fileSystem
, ARRAYSIZE(fileSystem
)))
627 K32LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
628 PrintWin32Error(szMsg
, GetLastError());
631 ConResPrintf(StdOut
, STRING_SERIAL_NUMBER
,
632 (unsigned int)(serialNumber
>> 16),
633 (unsigned int)(serialNumber
& 0xFFFF));