//====================================================================== // // Formatx // // Copyright (c) 1998 Mark Russinovich // Systems Internals // http://www.sysinternals.com // // Format clone that demonstrates the use of the FMIFS file system // utility library. // // -------------------------------------------------------------------- // // This software is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this software; see the file COPYING.LIB. If // not, write to the Free Software Foundation, Inc., 675 Mass Ave, // Cambridge, MA 02139, USA. // // -------------------------------------------------------------------- // // 1999 February (Emanuele Aliberti) // Adapted for ReactOS and lcc-win32. // // 1999 April (Emanuele Aliberti) // Adapted for ReactOS and egcs. // // 2003 April (Casper S. Hornstrup) // Reintegration. // //====================================================================== #include #include /* PSDK/NDK Headers */ #define WIN32_NO_STATUS #include #include #include #define NTOS_MODE_USER #include /* FMIFS Public Header */ #include #include "resource.h" #define FMIFS_IMPORT_DLL // Globals BOOL Error = FALSE; // Switches BOOL QuickFormat = FALSE; DWORD ClusterSize = 0; BOOL CompressDrive = FALSE; BOOL GotALabel = FALSE; PWCHAR Label = L""; PWCHAR Drive = NULL; PWCHAR FileSystem = L"FAT"; WCHAR RootDirectory[MAX_PATH]; WCHAR LabelString[12]; #ifndef FMIFS_IMPORT_DLL // // Functions in FMIFS.DLL // PFORMATEX FormatEx; PENABLEVOLUMECOMPRESSION EnableVolumeCompression; PQUERYAVAILABLEFILESYSTEMFORMAT QueryAvailableFileSystemFormat; #endif // // Size array // typedef struct { WCHAR SizeString[16]; DWORD ClusterSize; } SIZEDEFINITION, *PSIZEDEFINITION; SIZEDEFINITION LegalSizes[] = { { L"512", 512 }, { L"1024", 1024 }, { L"2048", 2048 }, { L"4096", 4096 }, { L"8192", 8192 }, { L"16K", 16384 }, { L"32K", 32768 }, { L"64K", 65536 }, { L"128K", 65536 * 2 }, { L"256K", 65536 * 4 }, { L"", 0 }, }; //---------------------------------------------------------------------- // // PrintWin32Error // // Takes the win32 error code and prints the text version. // //---------------------------------------------------------------------- static VOID PrintWin32Error(LPWSTR Message, DWORD ErrorCode) { ConPrintf(StdErr, L"%s: ", Message); ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrorCode, LANG_USER_DEFAULT); ConPuts(StdErr, L"\n"); } //---------------------------------------------------------------------- // // ParseCommandLine // // Get the switches. // //---------------------------------------------------------------------- static int ParseCommandLine(int argc, WCHAR *argv[]) { int i, j; BOOLEAN gotFormat = FALSE; BOOLEAN gotQuick = FALSE; BOOLEAN gotSize = FALSE; BOOLEAN gotLabel = FALSE; BOOLEAN gotCompressed = FALSE; for (i = 1; i < argc; i++) { switch (argv[i][0]) { case L'-': case L'/': if (!_wcsnicmp(&argv[i][1], L"FS:", 3)) { if (gotFormat) return -1; FileSystem = &argv[i][4]; gotFormat = TRUE; } else if (!_wcsnicmp(&argv[i][1], L"A:", 2)) { if (gotSize) return -1; j = 0; while (LegalSizes[j].ClusterSize && wcsicmp(LegalSizes[j].SizeString, &argv[i][3])) { j++; } if (!LegalSizes[j].ClusterSize) return i; ClusterSize = LegalSizes[j].ClusterSize; gotSize = TRUE; } else if (!_wcsnicmp(&argv[i][1], L"V:", 2)) { if (gotLabel) return -1; Label = &argv[i][3]; gotLabel = TRUE; GotALabel = TRUE; } else if (!wcsicmp(&argv[i][1], L"Q")) { if (gotQuick) return -1; QuickFormat = TRUE; gotQuick = TRUE; } else if (!wcsicmp(&argv[i][1], L"C")) { if (gotCompressed) return -1; CompressDrive = TRUE; gotCompressed = TRUE; } else { return i; } break; default: { if (Drive) return i; if (argv[i][1] != L':') return i; Drive = argv[i]; break; } } } return 0; } //---------------------------------------------------------------------- // // FormatExCallback // // The file system library will call us back with commands that we // can interpret. If we wanted to halt the chkdsk we could return FALSE. // //---------------------------------------------------------------------- BOOLEAN WINAPI FormatExCallback( CALLBACKCOMMAND Command, ULONG Modifier, PVOID Argument) { PDWORD percent; PTEXTOUTPUT output; PBOOLEAN status; // // We get other types of commands, but we don't have to pay attention to them // switch (Command) { case PROGRESS: percent = (PDWORD)Argument; ConResPrintf(StdOut, STRING_COMPLETE, *percent); break; case OUTPUT: output = (PTEXTOUTPUT)Argument; ConPrintf(StdOut, L"%S\n", output->Output); break; case DONE: status = (PBOOLEAN)Argument; if (*status == FALSE) { ConResPuts(StdOut, STRING_FORMAT_FAIL); Error = TRUE; } break; case DONEWITHSTRUCTURE: case UNKNOWN2: case UNKNOWN3: case UNKNOWN4: case UNKNOWN5: case INSUFFICIENTRIGHTS: case FSNOTSUPPORTED: case VOLUMEINUSE: case UNKNOWN9: case UNKNOWNA: case UNKNOWNC: case UNKNOWND: case STRUCTUREPROGRESS: case CLUSTERSIZETOOSMALL: ConResPuts(StdOut, STRING_NO_SUPPORT); return FALSE; } return TRUE; } #ifndef FMIFS_IMPORT_DLL //---------------------------------------------------------------------- // // LoadFMIFSEntryPoints // // Loads FMIFS.DLL and locates the entry point(s) we are going to use // //---------------------------------------------------------------------- static BOOLEAN LoadFMIFSEntryPoints(VOID) { HMODULE hFmifs = LoadLibraryW( L"fmifs.dll"); if (hFmifs == NULL) return FALSE; FormatEx = (PFORMATEX)GetProcAddress(hFmifs, "FormatEx"); if (!FormatEx) { FreeLibrary(hFmifs); return FALSE; } EnableVolumeCompression = (PENABLEVOLUMECOMPRESSION)GetProcAddress(hFmifs, "EnableVolumeCompression"); if (!EnableVolumeCompression) { FreeLibrary(hFmifs); return FALSE; } QueryAvailableFileSystemFormat = (PQUERYAVAILABLEFILESYSTEMFORMAT)GetProcAddress(hFmifs, "QueryAvailableFileSystemFormat"); if (!QueryAvailableFileSystemFormat) { FreeLibrary(hFmifs); return FALSE; } return TRUE; } #endif //---------------------------------------------------------------------- // // Usage // // Tell the user how to use the program // //---------------------------------------------------------------------- static VOID Usage(LPWSTR ProgramName) { WCHAR szMsg[RC_STRING_MAX_SIZE]; WCHAR szFormats[MAX_PATH]; WCHAR szFormatW[MAX_PATH]; DWORD Index = 0; BYTE dummy; BOOLEAN latestVersion; K32LoadStringW(GetModuleHandle(NULL), STRING_HELP, szMsg, ARRAYSIZE(szMsg)); #ifndef FMIFS_IMPORT_DLL if (!LoadFMIFSEntryPoints()) { ConPrintf(StdOut, szMsg, ProgramName, L""); return; } #endif szFormats[0] = 0; while (QueryAvailableFileSystemFormat(Index++, szFormatW, &dummy, &dummy, &latestVersion)) { if (!latestVersion) continue; if (szFormats[0]) wcscat(szFormats, L", "); wcscat(szFormats, szFormatW); } ConPrintf(StdOut, szMsg, ProgramName, szFormats); } //---------------------------------------------------------------------- // // WMain // // Engine. Just get command line switches and fire off a format. This // could also be done in a GUI like Explorer does when you select a // drive and run a check on it. // // We do this in UNICODE because the chkdsk command expects PWCHAR // arguments. // //---------------------------------------------------------------------- int wmain(int argc, WCHAR *argv[]) { int badArg; FMIFS_MEDIA_FLAG media = FMIFS_HARDDISK; DWORD driveType; WCHAR fileSystem[1024]; WCHAR volumeName[1024]; WCHAR input[1024]; DWORD serialNumber; DWORD flags, maxComponent; ULARGE_INTEGER freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes; WCHAR szMsg[RC_STRING_MAX_SIZE]; /* Initialize the Console Standard Streams */ ConInitStdStreams(); ConPuts(StdOut, L"\n" L"Formatx v1.0 by Mark Russinovich\n" L"Systems Internals - http://www.sysinternals.com\n" L"ReactOS adaptation 1999 by Emanuele Aliberti\n\n"); #ifndef FMIFS_IMPORT_DLL // // Get function pointers // if (!LoadFMIFSEntryPoints()) { ConResPuts(StdErr, STRING_FMIFS_FAIL); return -1; } #endif // // Parse command line // badArg = ParseCommandLine(argc, argv); if (badArg) { ConResPrintf(StdErr, STRING_UNKNOW_ARG, argv[badArg]); Usage(argv[0]); return -1; } // // Get the drive's format // if (!Drive) { ConResPuts(StdErr, STRING_DRIVE_PARM); Usage(argv[0]); return -1; } else { wcscpy(RootDirectory, Drive); } RootDirectory[2] = L'\\'; RootDirectory[3] = L'\0'; // // See if the drive is removable or not // driveType = GetDriveTypeW(RootDirectory); switch (driveType) { case DRIVE_UNKNOWN : K32LoadStringW(GetModuleHandle(NULL), STRING_ERROR_DRIVE_TYPE, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; case DRIVE_REMOTE: case DRIVE_CDROM: ConResPuts(StdOut, STRING_NO_SUPPORT); return -1; case DRIVE_NO_ROOT_DIR: K32LoadStringW(GetModuleHandle(NULL), STRING_NO_VOLUME, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; case DRIVE_REMOVABLE: ConResPrintf(StdOut, STRING_INSERT_DISK, RootDirectory[0]); fgetws(input, ARRAYSIZE(input), stdin); media = FMIFS_FLOPPY; break; case DRIVE_FIXED: case DRIVE_RAMDISK: media = FMIFS_HARDDISK; break; } // Reject attempts to format the system drive { WCHAR path[MAX_PATH + 1]; UINT rc; rc = GetWindowsDirectoryW(path, MAX_PATH); if (rc == 0 || rc > MAX_PATH) // todo: Report "Unable to query system directory" return -1; if (towlower(path[0]) == towlower(Drive[0])) { // todo: report "Cannot format system drive" ConResPuts(StdOut, STRING_NO_SUPPORT); return -1; } } // // Determine the drive's file system format // if (!GetVolumeInformationW(RootDirectory, volumeName, ARRAYSIZE(volumeName), &serialNumber, &maxComponent, &flags, fileSystem, ARRAYSIZE(fileSystem))) { K32LoadStringW(GetModuleHandle(NULL), STRING_NO_VOLUME, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; } if (!GetDiskFreeSpaceExW(RootDirectory, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { K32LoadStringW(GetModuleHandle(NULL), STRING_NO_VOLUME_SIZE, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; } ConResPrintf(StdOut, STRING_FILESYSTEM, fileSystem); // // Make sure they want to do this // if (driveType == DRIVE_FIXED) { if (volumeName[0]) { while (TRUE) { ConResPrintf(StdOut, STRING_LABEL_NAME_EDIT, RootDirectory[0]); fgetws(input, ARRAYSIZE(input), stdin); input[wcslen(input) - 1] = 0; if (!wcsicmp(input, volumeName)) break; ConResPuts(StdOut, STRING_ERROR_LABEL); } } ConResPrintf(StdOut, STRING_YN_FORMAT, RootDirectory[0]); K32LoadStringW(GetModuleHandle(NULL), STRING_YES_NO_FAQ, szMsg, ARRAYSIZE(szMsg)); while (TRUE) { fgetws(input, ARRAYSIZE(input), stdin); if (_wcsnicmp(&input[0], &szMsg[0], 1) == 0) break; if (_wcsnicmp(&input[0], &szMsg[1], 1) == 0) { ConPuts(StdOut, L"\n"); return 0; } } } // // Tell the user we're doing a long format if appropriate // if (!QuickFormat) { K32LoadStringW(GetModuleHandle(NULL), STRING_VERIFYING, szMsg, ARRAYSIZE(szMsg)); if (totalNumberOfBytes.QuadPart > 1024*1024*10) { ConPrintf(StdOut, L"%s %luM\n", szMsg, (DWORD)(totalNumberOfBytes.QuadPart/(1024*1024))); } else { ConPrintf(StdOut, L"%s %.1fM\n", szMsg, ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0)); } } else { K32LoadStringW(GetModuleHandle(NULL), STRING_FAST_FMT, szMsg, ARRAYSIZE(szMsg)); if (totalNumberOfBytes.QuadPart > 1024*1024*10) { ConPrintf(StdOut, L"%s %luM\n", szMsg, (DWORD)(totalNumberOfBytes.QuadPart/(1024*1024))); } else { ConPrintf(StdOut, L"%s %.2fM\n", szMsg, ((float)(LONGLONG)totalNumberOfBytes.QuadPart)/(float)(1024.0*1024.0)); } ConResPuts(StdOut, STRING_CREATE_FSYS); } // // Format away! // FormatEx(RootDirectory, media, FileSystem, Label, QuickFormat, ClusterSize, FormatExCallback); if (Error) return -1; ConResPuts(StdOut, STRING_FMT_COMPLETE); // // Enable compression if desired // if (CompressDrive) { if (!EnableVolumeCompression(RootDirectory, TRUE)) ConResPuts(StdOut, STRING_VOL_COMPRESS); } // // Get the label if we don't have it // if (!GotALabel) { ConResPuts(StdOut, STRING_ENTER_LABEL); fgetws(input, ARRAYSIZE(LabelString), stdin); input[wcslen(input) - 1] = 0; if (!SetVolumeLabelW(RootDirectory, input)) { K32LoadStringW(GetModuleHandle(NULL), STRING_NO_LABEL, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; } } if (!GetVolumeInformationW(RootDirectory, volumeName, ARRAYSIZE(volumeName), &serialNumber, &maxComponent, &flags, fileSystem, ARRAYSIZE(fileSystem))) { K32LoadStringW(GetModuleHandle(NULL), STRING_NO_VOLUME, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; } // // Print out some stuff including the formatted size // if (!GetDiskFreeSpaceExW(RootDirectory, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { K32LoadStringW(GetModuleHandle(NULL), STRING_NO_VOLUME_SIZE, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; } ConResPrintf(StdOut, STRING_FREE_SPACE, totalNumberOfBytes.QuadPart, totalNumberOfFreeBytes.QuadPart); // // Get the drive's serial number // if (!GetVolumeInformationW(RootDirectory, volumeName, ARRAYSIZE(volumeName), &serialNumber, &maxComponent, &flags, fileSystem, ARRAYSIZE(fileSystem))) { K32LoadStringW(GetModuleHandle(NULL), STRING_NO_VOLUME, szMsg, ARRAYSIZE(szMsg)); PrintWin32Error(szMsg, GetLastError()); return -1; } ConResPrintf(StdOut, STRING_SERIAL_NUMBER, (unsigned int)(serialNumber >> 16), (unsigned int)(serialNumber & 0xFFFF)); return 0; } /* EOF */