Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

488 lines
12 KiB

  1. /*++
  2. Copyright (c) 1991-2001 Microsoft Corporation
  3. Module Name:
  4. autofmt.cxx
  5. Abstract:
  6. This is the main program for the autofmt version of format.
  7. Author:
  8. Matthew Bradburn (mattbr) 13-Dec-94
  9. --*/
  10. #include "ulib.hxx"
  11. #include "wstring.hxx"
  12. #include "achkmsg.hxx"
  13. #include "spackmsg.hxx"
  14. #include "tmackmsg.hxx"
  15. #include "ifssys.hxx"
  16. #include "rtmsg.h"
  17. #include "ifsentry.hxx"
  18. #include "fatvol.hxx"
  19. #include "ntfsvol.hxx"
  20. #include "autoreg.hxx"
  21. #include "autoentr.hxx"
  22. #include "arg.hxx"
  23. extern "C" BOOLEAN
  24. InitializeUfat(
  25. PVOID DllHandle,
  26. ULONG Reason,
  27. PCONTEXT Context
  28. );
  29. extern "C" BOOLEAN
  30. InitializeUhpfs(
  31. PVOID DllHandle,
  32. ULONG Reason,
  33. PCONTEXT Context
  34. );
  35. extern "C" BOOLEAN
  36. InitializeUntfs(
  37. PVOID DllHandle,
  38. ULONG Reason,
  39. PCONTEXT Context
  40. );
  41. extern "C" BOOLEAN
  42. InitializeIfsUtil(
  43. PVOID DllHandle,
  44. ULONG Reason,
  45. PCONTEXT Context
  46. );
  47. BOOLEAN
  48. DeRegister(
  49. int argc,
  50. char** argv
  51. );
  52. BOOLEAN
  53. SavemessageLog(
  54. IN OUT PMESSAGE message,
  55. IN PCWSTRING drive_name
  56. );
  57. int __cdecl
  58. main(
  59. int argc,
  60. char** argv,
  61. char** envp,
  62. ULONG DebugParameter
  63. )
  64. /*++
  65. Routine Description:
  66. This routine is the main program for AutoFmt
  67. Arguments:
  68. argc, argv - Supplies the fully qualified NT path name of the
  69. the drive to check. The syntax of the autofmt
  70. command line is:
  71. AUTOFMT drive-name /FS:target-file-system [/V:label] [/Q] [/A:size] [/C]
  72. [/S]
  73. Return Value:
  74. 0 - Success.
  75. 1 - Failure.
  76. --*/
  77. {
  78. if (!InitializeUlib( NULL, ! DLL_PROCESS_DETACH, NULL ) ||
  79. !InitializeIfsUtil(NULL, ! DLL_PROCESS_DETACH, NULL) ||
  80. !InitializeUfat(NULL, ! DLL_PROCESS_DETACH, NULL) ||
  81. !InitializeUntfs(NULL, ! DLL_PROCESS_DETACH, NULL)
  82. ) {
  83. return 1;
  84. }
  85. PFAT_VOL fat_volume;
  86. PNTFS_VOL ntfs_volume;
  87. PDP_DRIVE dp_drive;
  88. PAUTOCHECK_MESSAGE message;
  89. DSTRING drive_name;
  90. DSTRING file_system_name;
  91. DSTRING label;
  92. DSTRING fat_name;
  93. DSTRING ntfs_name;
  94. DSTRING fat32_name;
  95. BOOLEAN quick = FALSE;
  96. BOOLEAN compress = FALSE;
  97. BOOLEAN error;
  98. FORMAT_ERROR_CODE success;
  99. BOOLEAN setup_output = FALSE;
  100. BOOLEAN textmode_output = FALSE;
  101. BIG_INT bigint;
  102. ULONG cluster_size = 0;
  103. int i;
  104. LARGE_INTEGER delay_interval;
  105. if (!file_system_name.Initialize()) {
  106. return 1;
  107. }
  108. if (!label.Initialize() || NULL == (dp_drive = NEW DP_DRIVE)) {
  109. return 1;
  110. }
  111. //
  112. // Parse the arguments.
  113. //
  114. if ( argc < 2 ) {
  115. return 1;
  116. }
  117. //
  118. // First argument is drive
  119. //
  120. if ( !drive_name.Initialize( argv[1] ) ) {
  121. return 1;
  122. }
  123. DebugPrintTrace(("drive name: %ws\n", drive_name.GetWSTR()));
  124. //
  125. // The rest of the arguments are flags.
  126. //
  127. for (i = 2; i < argc; i++) {
  128. if ((argv[i][0] == '/' || argv[i][0] == '-') &&
  129. (argv[i][1] == 'f' || argv[i][1] == 'F') &&
  130. (argv[i][2] == 's' || argv[i][2] == 'S') &&
  131. (argv[i][3] == ':')) {
  132. if (!file_system_name.Initialize(&argv[i][4])) {
  133. return 1;
  134. }
  135. DebugPrintTrace(("fsname: %ws\n", file_system_name.GetWSTR()));
  136. continue;
  137. }
  138. if ((argv[i][0] == '/' || argv[i][0] == '-') &&
  139. (argv[i][1] == 'v' || argv[i][1] == 'V') &&
  140. (argv[i][2] == ':')) {
  141. if (!label.Initialize(&argv[i][3])) {
  142. return 1;
  143. }
  144. continue;
  145. }
  146. if ((argv[i][0] == '/' || argv[i][0] == '-') &&
  147. (argv[i][1] == 'a' || argv[i][1] == 'A') &&
  148. (argv[i][2] == ':')) {
  149. cluster_size = atoi(&argv[i][3]);
  150. continue;
  151. }
  152. if (0 == _stricmp(argv[i], "/Q") || 0 == _stricmp(argv[i], "-Q")) {
  153. quick = TRUE;
  154. continue;
  155. }
  156. if (0 == _stricmp(argv[i], "/C") || 0 == _stricmp(argv[i], "-C")) {
  157. compress = TRUE;
  158. continue;
  159. }
  160. if (0 == _stricmp(argv[i], "/S") || 0 == _stricmp(argv[i], "-S")) {
  161. setup_output = TRUE;
  162. }
  163. if (0 == _stricmp(argv[i], "/T") || 0 == _stricmp(argv[i], "-T")) {
  164. textmode_output = TRUE;
  165. }
  166. }
  167. if (textmode_output) {
  168. message = NEW TM_AUTOCHECK_MESSAGE;
  169. } else if (setup_output) {
  170. message = NEW SP_AUTOCHECK_MESSAGE;
  171. DebugPrintTrace(("Using setup output\n"));
  172. } else {
  173. DebugPrintTrace(("Not using setup output\n"));
  174. message = NEW AUTOCHECK_MESSAGE;
  175. }
  176. if (NULL == message || !message->Initialize()) {
  177. return 1;
  178. }
  179. #if 0 // Shouldn't limit the cluster size as long as it is reasonable.
  180. if (cluster_size != 0 && cluster_size != 512 && cluster_size != 1024 &&
  181. cluster_size != 2048 && cluster_size != 4096) {
  182. message->Set(MSG_UNSUPPORTED_PARAMETER);
  183. message->Display();
  184. DeRegister( argc, argv );
  185. return 1;
  186. }
  187. #endif
  188. if (0 == file_system_name.QueryChCount()) {
  189. // attempt to get the current filesystem type from disk
  190. if (!IFS_SYSTEM::QueryFileSystemName(&drive_name, &file_system_name)) {
  191. message->Set( MSG_FS_NOT_DETERMINED );
  192. message->Display( "%W", &drive_name );
  193. DeRegister( argc, argv );
  194. return 1;
  195. }
  196. file_system_name.Strupr();
  197. }
  198. if (!fat_name.Initialize("FAT") ||
  199. !ntfs_name.Initialize("NTFS") ||
  200. !fat32_name.Initialize("FAT32")) {
  201. return 1;
  202. }
  203. file_system_name.Strupr();
  204. //
  205. // If compression is requested, make sure it's available.
  206. //
  207. if (compress && file_system_name != ntfs_name) {
  208. message->Set(MSG_COMPRESSION_NOT_AVAILABLE);
  209. message->Display("%W", &file_system_name);
  210. DeRegister( argc, argv );
  211. return 1;
  212. }
  213. // Since autoformat will often be put in place by Setup
  214. // to run after AutoSetp, delay for 3 seconds to give the
  215. // file system time to clean up detritus of deleted files.
  216. //
  217. delay_interval = RtlConvertLongToLargeInteger( -30000000 );
  218. NtDelayExecution( TRUE, &delay_interval );
  219. if (!dp_drive->Initialize(&drive_name, message)) {
  220. DeRegister( argc, argv );
  221. return 1;
  222. }
  223. if (dp_drive->IsFloppy()) {
  224. // MJB: refuse to format
  225. DeRegister( argc, argv );
  226. return 1;
  227. }
  228. switch (dp_drive->QueryDriveType()) {
  229. case UnknownDrive:
  230. message->Set(MSG_NONEXISTENT_DRIVE);
  231. message->Display("");
  232. DeRegister( argc, argv );
  233. return 1;
  234. case RemoteDrive: // it probably won't get that far
  235. message->Set(MSG_FORMAT_NO_NETWORK);
  236. message->Display("");
  237. DeRegister( argc, argv );
  238. return 1;
  239. case RamDiskDrive: // it probably won't get that far
  240. message->Set(MSG_FORMAT_NO_RAMDISK);
  241. message->Display("");
  242. DeRegister( argc, argv );
  243. return 1;
  244. default:
  245. break;
  246. }
  247. //
  248. // Print the "formatting <size>" message.
  249. //
  250. if (quick) {
  251. message->Set(MSG_QUICKFORMATTING_MB);
  252. } else {
  253. message->Set(MSG_FORMATTING_MB);
  254. }
  255. bigint = dp_drive->QuerySectors() * dp_drive->QuerySectorSize() /
  256. 1048576;
  257. DebugAssert(bigint.GetHighPart() == 0);
  258. message->Display("%d", bigint.GetLowPart());
  259. if (file_system_name == fat_name || file_system_name == fat32_name) {
  260. BOOLEAN old_fat_vol = TRUE;
  261. if( file_system_name == fat32_name ) {
  262. old_fat_vol = FALSE;
  263. }
  264. if( !(fat_volume = NEW FAT_VOL) ||
  265. NoError != fat_volume->Initialize( &drive_name, message, FALSE, !quick,
  266. Unknown )) {
  267. DeRegister( argc, argv );
  268. return 1;
  269. }
  270. success = fat_volume->Format(&label,
  271. message,
  272. old_fat_vol ? FORMAT_BACKWARD_COMPATIBLE : 0,
  273. cluster_size);
  274. DebugPrintTrace(("Format return code: %d\n", success));
  275. DELETE( fat_volume );
  276. } else if (file_system_name == ntfs_name) {
  277. if (dp_drive->QueryDriveType() == CdRomDrive) {
  278. message->Set(MSG_FMT_NO_NTFS_ALLOWED);
  279. message->Display();
  280. DeRegister( argc, argv );
  281. return 1;
  282. }
  283. if( !(ntfs_volume = NEW NTFS_VOL) ||
  284. NoError != ntfs_volume->Initialize( &drive_name, message, FALSE, !quick,
  285. Unknown )) {
  286. DeRegister( argc, argv );
  287. return 1;
  288. }
  289. success = ntfs_volume->Format(&label,
  290. message,
  291. 0,
  292. cluster_size);
  293. DebugPrintTrace(("Format return code: %d\n", success));
  294. DELETE( ntfs_volume );
  295. } else {
  296. message->Set( MSG_FS_NOT_SUPPORTED );
  297. message->Display( "%s%W", "AUTOFMT", &file_system_name);
  298. DeRegister( argc, argv );
  299. return 1;
  300. }
  301. // Truncate "fat32" back to "fat"...yuck..
  302. if (file_system_name == fat32_name) {
  303. if (!file_system_name.Initialize("FAT")) {
  304. DeRegister( argc, argv );
  305. return 1;
  306. }
  307. }
  308. // Make sure the file system is installed.
  309. if (!IFS_SYSTEM::IsFileSystemEnabled(&file_system_name)) {
  310. message->Set(MSG_FMT_INSTALL_FILE_SYSTEM);
  311. message->Display("%W", &file_system_name);
  312. if (!IFS_SYSTEM::EnableFileSystem(&file_system_name)) {
  313. message->Set(MSG_FMT_CANT_INSTALL_FILE_SYSTEM);
  314. message->Display();
  315. return 1;
  316. }
  317. message->Set(MSG_FMT_FILE_SYSTEM_INSTALLED);
  318. message->Display();
  319. }
  320. if (compress && !IFS_SYSTEM::EnableVolumeCompression(&drive_name)) {
  321. message->Set(MSG_CANNOT_ENABLE_COMPRESSION);
  322. message->Display();
  323. DeRegister( argc, argv );
  324. return 1;
  325. }
  326. DeRegister( argc, argv );
  327. return (success != NoError);
  328. }
  329. BOOLEAN
  330. DeRegister(
  331. int argc,
  332. char** argv
  333. )
  334. /*++
  335. Routine Description:
  336. This function removes the registry entry which triggered
  337. autoconvert.
  338. Arguments:
  339. argc -- Supplies the number of arguments given to autoconv
  340. argv -- supplies the arguments given to autoconv
  341. Return Value:
  342. TRUE upon successful completion.
  343. --*/
  344. {
  345. DSTRING CommandLineString1,
  346. CommandLineString2,
  347. CurrentArgString,
  348. OneSpace;
  349. int i;
  350. // Reconstruct the command line and remove it from
  351. // the registry. First, reconstruct the primary
  352. // string, which is "autoconv arg1 arg2...".
  353. //
  354. if( !CommandLineString1.Initialize( L"autofmt" ) ||
  355. !OneSpace.Initialize( L" " ) ) {
  356. return FALSE;
  357. }
  358. for( i = 1; i < argc; i++ ) {
  359. if( !CurrentArgString.Initialize( argv[i] ) ||
  360. !CommandLineString1.Strcat( &OneSpace ) ||
  361. !CommandLineString1.Strcat( &CurrentArgString ) ) {
  362. return FALSE;
  363. }
  364. }
  365. // Now construct the secondary string, which is
  366. // "autocheck arg0 arg1 arg2..."
  367. //
  368. if( !CommandLineString2.Initialize( "autocheck " ) ||
  369. !CommandLineString2.Strcat( &CommandLineString1 ) ) {
  370. return FALSE;
  371. }
  372. return( AUTOREG::DeleteEntry( &CommandLineString1 ) &&
  373. AUTOREG::DeleteEntry( &CommandLineString2 ) );
  374. }