PageRenderTime 27ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/reactos/base/system/format/format.c

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