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 VOID
PrintStringV(LPWSTR szStr
, va_list args
)
112 WCHAR bufFormatted
[RC_STRING_MAX_SIZE
];
113 CHAR bufFormattedOem
[RC_STRING_MAX_SIZE
];
115 _vsnwprintf(bufFormatted
, ARRAYSIZE(bufFormatted
), szStr
, args
);
117 CharToOemW(bufFormatted
, bufFormattedOem
);
118 puts(bufFormattedOem
);
121 VOID
PrintString(LPWSTR szStr
, ...)
125 va_start(args
, szStr
);
126 PrintStringV(szStr
, args
);
130 VOID
PrintResourceString(UINT uID
, ...)
132 WCHAR bufSrc
[RC_STRING_MAX_SIZE
];
135 LoadStringW(GetModuleHandleW(NULL
), uID
, bufSrc
, ARRAYSIZE(bufSrc
));
138 PrintStringV(bufSrc
, args
);
143 //----------------------------------------------------------------------
147 // Takes the win32 error code and prints the text version.
149 //----------------------------------------------------------------------
150 static VOID
PrintWin32Error(LPWSTR Message
, DWORD ErrorCode
)
154 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
156 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
157 (LPWSTR
)&lpMsgBuf
, 0, NULL
);
159 PrintString(L
"%s: %s\n", Message
, lpMsgBuf
);
164 //----------------------------------------------------------------------
170 //----------------------------------------------------------------------
171 static int ParseCommandLine(int argc
, WCHAR
*argv
[])
174 BOOLEAN gotFormat
= FALSE
;
175 BOOLEAN gotQuick
= FALSE
;
176 BOOLEAN gotSize
= FALSE
;
177 BOOLEAN gotLabel
= FALSE
;
178 BOOLEAN gotCompressed
= FALSE
;
180 for (i
= 1; i
< argc
; i
++)
184 case L
'-': case L
'/':
186 if (!_wcsnicmp(&argv
[i
][1], L
"FS:", 3))
188 if (gotFormat
) return -1;
189 FileSystem
= &argv
[i
][4];
192 else if (!_wcsnicmp(&argv
[i
][1], L
"A:", 2))
194 if (gotSize
) return -1;
196 while (LegalSizes
[j
].ClusterSize
&&
197 wcsicmp(LegalSizes
[j
].SizeString
, &argv
[i
][3]))
202 if (!LegalSizes
[j
].ClusterSize
) return i
;
203 ClusterSize
= LegalSizes
[j
].ClusterSize
;
206 else if (!_wcsnicmp(&argv
[i
][1], L
"V:", 2))
208 if (gotLabel
) return -1;
213 else if (!wcsicmp(&argv
[i
][1], L
"Q"))
215 if (gotQuick
) return -1;
219 else if (!wcsicmp(&argv
[i
][1], L
"C"))
221 if (gotCompressed
) return -1;
222 CompressDrive
= TRUE
;
223 gotCompressed
= TRUE
;
234 if (argv
[i
][1] != L
':') return i
;
244 //----------------------------------------------------------------------
248 // The file system library will call us back with commands that we
249 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
251 //----------------------------------------------------------------------
254 CALLBACKCOMMAND Command
,
263 // We get other types of commands, but we don't have to pay attention to them
268 percent
= (PDWORD
)Argument
;
269 PrintResourceString(STRING_COMPLETE
, *percent
);
273 output
= (PTEXTOUTPUT
)Argument
;
274 wprintf(L
"%S", output
->Output
);
278 status
= (PBOOLEAN
)Argument
;
279 if (*status
== FALSE
)
281 PrintResourceString(STRING_FORMAT_FAIL
);
286 case DONEWITHSTRUCTURE
:
291 case INSUFFICIENTRIGHTS
:
298 case STRUCTUREPROGRESS
:
299 case CLUSTERSIZETOOSMALL
:
300 PrintResourceString(STRING_NO_SUPPORT
);
306 #ifndef FMIFS_IMPORT_DLL
307 //----------------------------------------------------------------------
309 // LoadFMIFSEntryPoints
311 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
313 //----------------------------------------------------------------------
314 static BOOLEAN
LoadFMIFSEntryPoints(VOID
)
316 HMODULE hFmifs
= LoadLibraryW( L
"fmifs.dll");
320 FormatEx
= (PFORMATEX
)GetProcAddress(hFmifs
, "FormatEx");
327 EnableVolumeCompression
= (PENABLEVOLUMECOMPRESSION
)GetProcAddress(hFmifs
, "EnableVolumeCompression");
328 if (!EnableVolumeCompression
)
334 QueryAvailableFileSystemFormat
= (PQUERYAVAILABLEFILESYSTEMFORMAT
)GetProcAddress(hFmifs
, "QueryAvailableFileSystemFormat");
335 if (!QueryAvailableFileSystemFormat
)
346 //----------------------------------------------------------------------
350 // Tell the user how to use the program
352 //----------------------------------------------------------------------
353 static VOID
Usage(LPWSTR ProgramName
)
355 WCHAR szMsg
[RC_STRING_MAX_SIZE
];
356 WCHAR szFormats
[MAX_PATH
];
357 WCHAR szFormatW
[MAX_PATH
];
360 BOOLEAN latestVersion
;
362 LoadStringW(GetModuleHandle(NULL
), STRING_HELP
, szMsg
, ARRAYSIZE(szMsg
));
364 #ifndef FMIFS_IMPORT_DLL
365 if (!LoadFMIFSEntryPoints())
367 PrintString(szMsg
, ProgramName
, L
"");
373 while (QueryAvailableFileSystemFormat(Index
++, szFormatW
, &dummy
, &dummy
, &latestVersion
))
378 wcscat(szFormats
, L
", ");
380 wcscat(szFormats
, szFormatW
);
382 PrintString(szMsg
, ProgramName
, szFormats
);
386 //----------------------------------------------------------------------
390 // Engine. Just get command line switches and fire off a format. This
391 // could also be done in a GUI like Explorer does when you select a
392 // drive and run a check on it.
394 // We do this in UNICODE because the chkdsk command expects PWCHAR
397 //----------------------------------------------------------------------
398 int wmain(int argc
, WCHAR
*argv
[])
401 DWORD media
= FMIFS_HARDDISK
;
403 WCHAR fileSystem
[1024];
404 WCHAR volumeName
[1024];
407 DWORD flags
, maxComponent
;
408 ULARGE_INTEGER freeBytesAvailableToCaller
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
409 WCHAR szMsg
[RC_STRING_MAX_SIZE
];
412 L
"Formatx v1.0 by Mark Russinovich\n"
413 L
"Systems Internals - http://www.sysinternals.com\n"
414 L
"ReactOS adaptation 1999 by Emanuele Aliberti\n\n");
416 #ifndef FMIFS_IMPORT_DLL
418 // Get function pointers
420 if (!LoadFMIFSEntryPoints())
422 PrintResourceString(STRING_FMIFS_FAIL
);
428 // Parse command line
430 badArg
= ParseCommandLine(argc
, argv
);
433 PrintResourceString(STRING_UNKNOW_ARG
, argv
[badArg
]);
439 // Get the drive's format
443 PrintResourceString(STRING_DRIVE_PARM
);
449 wcscpy(RootDirectory
, Drive
);
451 RootDirectory
[2] = L
'\\';
452 RootDirectory
[3] = L
'\0';
455 // See if the drive is removable or not
457 driveType
= GetDriveTypeW(RootDirectory
);
461 LoadStringW(GetModuleHandle(NULL
), STRING_ERROR_DRIVE_TYPE
, szMsg
, ARRAYSIZE(szMsg
));
462 PrintWin32Error(szMsg
, GetLastError());
467 PrintResourceString(STRING_NO_SUPPORT
);
470 case DRIVE_NO_ROOT_DIR
:
471 LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
472 PrintWin32Error(szMsg
, GetLastError());
475 case DRIVE_REMOVABLE
:
476 PrintResourceString(STRING_INSERT_DISK
, RootDirectory
[0]);
477 fgetws(input
, ARRAYSIZE(input
), stdin
);
478 media
= FMIFS_FLOPPY
;
483 media
= FMIFS_HARDDISK
;
487 // Reject attempts to format the system drive
489 WCHAR path
[MAX_PATH
+ 1];
491 rc
= GetWindowsDirectoryW(path
, MAX_PATH
);
492 if (rc
== 0 || rc
> MAX_PATH
)
493 // todo: Report "Unable to query system directory"
495 if (towlower(path
[0]) == towlower(Drive
[0]))
497 // todo: report "Cannot format system drive"
498 PrintResourceString(STRING_NO_SUPPORT
);
504 // Determine the drive's file system format
506 if (!GetVolumeInformationW(RootDirectory
,
507 volumeName
, ARRAYSIZE(volumeName
),
508 &serialNumber
, &maxComponent
, &flags
,
509 fileSystem
, ARRAYSIZE(fileSystem
)))
511 LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
512 PrintWin32Error(szMsg
, GetLastError());
516 if (!GetDiskFreeSpaceExW(RootDirectory
,
517 &freeBytesAvailableToCaller
,
519 &totalNumberOfFreeBytes
))
521 LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, szMsg
, ARRAYSIZE(szMsg
));
522 PrintWin32Error(szMsg
, GetLastError());
525 PrintResourceString(STRING_FILESYSTEM
, fileSystem
);
528 // Make sure they want to do this
530 if (driveType
== DRIVE_FIXED
)
536 PrintResourceString(STRING_LABEL_NAME_EDIT
, RootDirectory
[0]);
537 fgetws(input
, ARRAYSIZE(input
), stdin
);
538 input
[wcslen(input
) - 1] = 0;
540 if (!wcsicmp(input
, volumeName
))
543 PrintResourceString(STRING_ERROR_LABEL
);
547 PrintResourceString(STRING_YN_FORMAT
, RootDirectory
[0]);
549 LoadStringW(GetModuleHandle(NULL
), STRING_YES_NO_FAQ
, szMsg
, ARRAYSIZE(szMsg
));
552 fgetws(input
, ARRAYSIZE(input
), stdin
);
553 if (_wcsnicmp(&input
[0], &szMsg
[0], 1) == 0) break;
554 if (_wcsnicmp(&input
[0], &szMsg
[1], 1) == 0)
563 // Tell the user we're doing a long format if appropriate
567 LoadStringW(GetModuleHandle(NULL
), STRING_VERIFYING
, szMsg
, ARRAYSIZE(szMsg
));
568 if (totalNumberOfBytes
.QuadPart
> 1024*1024*10)
570 PrintString(L
"%s %luM\n", szMsg
, (DWORD
)(totalNumberOfBytes
.QuadPart
/(1024*1024)));
574 PrintString(L
"%s %.1fM\n", szMsg
,
575 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
580 LoadStringW(GetModuleHandle(NULL
), STRING_FAST_FMT
, szMsg
, ARRAYSIZE(szMsg
));
581 if (totalNumberOfBytes
.QuadPart
> 1024*1024*10)
583 PrintString(L
"%s %luM\n", szMsg
, (DWORD
)(totalNumberOfBytes
.QuadPart
/(1024*1024)));
587 PrintString(L
"%s %.2fM\n", szMsg
,
588 ((float)(LONGLONG
)totalNumberOfBytes
.QuadPart
)/(float)(1024.0*1024.0));
590 PrintResourceString(STRING_CREATE_FSYS
);
596 FormatEx(RootDirectory
, media
, FileSystem
, Label
, QuickFormat
,
597 ClusterSize
, FormatExCallback
);
598 if (Error
) return -1;
599 PrintResourceString(STRING_FMT_COMPLETE
);
602 // Enable compression if desired
606 if (!EnableVolumeCompression(RootDirectory
, TRUE
))
607 PrintResourceString(STRING_VOL_COMPRESS
);
611 // Get the label if we don't have it
615 PrintResourceString(STRING_ENTER_LABEL
);
616 fgetws(input
, ARRAYSIZE(LabelString
), stdin
);
618 input
[wcslen(input
) - 1] = 0;
619 if (!SetVolumeLabelW(RootDirectory
, input
))
621 LoadStringW(GetModuleHandle(NULL
), STRING_NO_LABEL
, szMsg
, ARRAYSIZE(szMsg
));
622 PrintWin32Error(szMsg
, GetLastError());
627 if (!GetVolumeInformationW(RootDirectory
,
628 volumeName
, ARRAYSIZE(volumeName
),
629 &serialNumber
, &maxComponent
, &flags
,
630 fileSystem
, ARRAYSIZE(fileSystem
)))
632 LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
633 PrintWin32Error(szMsg
, GetLastError());
638 // Print out some stuff including the formatted size
640 if (!GetDiskFreeSpaceExW(RootDirectory
,
641 &freeBytesAvailableToCaller
,
643 &totalNumberOfFreeBytes
))
645 LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME_SIZE
, szMsg
, ARRAYSIZE(szMsg
));
646 PrintWin32Error(szMsg
, GetLastError());
650 PrintResourceString(STRING_FREE_SPACE
, totalNumberOfBytes
.QuadPart
,
651 totalNumberOfFreeBytes
.QuadPart
);
654 // Get the drive's serial number
656 if (!GetVolumeInformationW(RootDirectory
,
657 volumeName
, ARRAYSIZE(volumeName
),
658 &serialNumber
, &maxComponent
, &flags
,
659 fileSystem
, ARRAYSIZE(fileSystem
)))
661 LoadStringW(GetModuleHandle(NULL
), STRING_NO_VOLUME
, szMsg
, ARRAYSIZE(szMsg
));
662 PrintWin32Error(szMsg
, GetLastError());
665 PrintResourceString(STRING_SERIAL_NUMBER
,
666 (unsigned int)(serialNumber
>> 16),
667 (unsigned int)(serialNumber
& 0xFFFF));