Source code of Windows XP (NT5)
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.

1473 lines
38 KiB

  1. /*++
  2. Copyright (c) 1991-2001 Microsoft Corporation
  3. Module Name:
  4. convert.cxx
  5. Abstract:
  6. This module contains the definition of the CONVERT class, which
  7. implements the File System Conversion Utility.
  8. Author:
  9. Ramon J. San Andres (ramonsa) sep-23-1991
  10. Environment:
  11. ULIB, User Mode
  12. --*/
  13. #define _NTAPI_ULIB_
  14. #include "ulib.hxx"
  15. #if defined(FE_SB) && defined(_X86_)
  16. #include "machine.hxx"
  17. #endif
  18. #include "ulibcl.hxx"
  19. #include "arg.hxx"
  20. #include "file.hxx"
  21. #include "smsg.hxx"
  22. #include "rtmsg.h"
  23. #include "wstring.hxx"
  24. #include "system.hxx"
  25. #include "autoreg.hxx"
  26. #include "ifssys.hxx"
  27. #include "ifsentry.hxx"
  28. #include "hmem.hxx"
  29. #include "convert.hxx"
  30. #include "supera.hxx"
  31. extern "C" {
  32. #include <stdio.h>
  33. #include "undo.h"
  34. }
  35. #include "fatofs.hxx"
  36. #define AUTOCHK_PROGRAM_NAME L"AUTOCHK.EXE"
  37. #define AUTOCONV_PROGRAM_NAME L"AUTOCONV.EXE"
  38. #define AUTOCHK_NAME L"AUTOCHK"
  39. #define AUTOCONV_NAME L"AUTOCONV"
  40. #define VALUE_NAME_PATH L"PATH"
  41. #define VALUE_NAME_ARGS L"ARGUMENTS"
  42. #define VALUE_NAME_FS L"TARGET FILESYSTEM"
  43. //
  44. // Scheduling status codes
  45. //
  46. #define CONV_STATUS_NONE 0
  47. #define CONV_STATUS_SCHEDULED 1
  48. static WCHAR NameBuffer[16]; // holds cvf name
  49. DWORD
  50. WINAPI
  51. SceConfigureConvertedFileSecurity(
  52. IN PWSTR pszDriveName,
  53. IN DWORD dwConvertDisposition
  54. );
  55. INT __cdecl
  56. main (
  57. )
  58. /*++
  59. Routine Description:
  60. Entry point for the conversion utility.
  61. Arguments:
  62. None.
  63. Return Value:
  64. One of the CONVERT exit codes.
  65. Notes:
  66. --*/
  67. {
  68. INT ExitCode = EXIT_ERROR; // Let's be pessimistic
  69. DEFINE_CLASS_DESCRIPTOR( CONVERT );
  70. {
  71. CONVERT Convert;
  72. //
  73. // Initialize the CONVERT object.
  74. //
  75. if ( Convert.Initialize( &ExitCode ) ) {
  76. //
  77. // Do the conversion
  78. //
  79. ExitCode = Convert.Convert();
  80. }
  81. }
  82. return ExitCode;
  83. }
  84. DEFINE_CONSTRUCTOR( CONVERT, PROGRAM );
  85. NONVIRTUAL
  86. VOID
  87. CONVERT::Construct (
  88. )
  89. /*++
  90. Routine Description:
  91. converts a CONVERT object
  92. Arguments:
  93. None.
  94. Return Value:
  95. None.
  96. Notes:
  97. --*/
  98. {
  99. _Autochk = NULL;
  100. _Autoconv = NULL;
  101. }
  102. NONVIRTUAL
  103. VOID
  104. CONVERT::Destroy (
  105. )
  106. /*++
  107. Routine Description:
  108. Destroys a CONVERT object
  109. Arguments:
  110. None.
  111. Return Value:
  112. None.
  113. Notes:
  114. --*/
  115. {
  116. DELETE( _Autochk );
  117. DELETE( _Autoconv );
  118. }
  119. CONVERT::~CONVERT (
  120. )
  121. /*++
  122. Routine Description:
  123. Destructs a CONVERT object
  124. Arguments:
  125. None.
  126. Return Value:
  127. None.
  128. Notes:
  129. --*/
  130. {
  131. Destroy();
  132. }
  133. BOOLEAN
  134. CONVERT::Initialize (
  135. OUT PINT ExitCode
  136. )
  137. /*++
  138. Routine Description:
  139. Initializes the CONVERT object. Initialization consist of allocating memory
  140. for certain object members and argument parsing.
  141. Arguments:
  142. ExitCode - Supplies pointer to CONVERT exit code.
  143. Return Value:
  144. BOOLEAN - TRUE if initialization succeeded, FALSE otherwise.
  145. Notes:
  146. --*/
  147. {
  148. Destroy();
  149. //
  150. // Initialize program object
  151. //
  152. if ( PROGRAM::Initialize( MSG_CONV_USAGE ) ) {
  153. //
  154. // Parse the arguments
  155. //
  156. return ParseArguments( ExitCode );
  157. }
  158. //
  159. // Could not initialize the program object.
  160. //
  161. *ExitCode = EXIT_ERROR;
  162. return FALSE;
  163. }
  164. INT
  165. CONVERT::Convert (
  166. )
  167. /*++
  168. Routine Description:
  169. Converts the file system in a volume.
  170. Depending on the current file system, it loads the appropriate
  171. conversion library and calls its conversion entry point.
  172. Arguments:
  173. None
  174. Return Value:
  175. INT - One of the CONVERT return codes
  176. Notes:
  177. --*/
  178. {
  179. DSTRING CurrentFsName; // Name of current FS in volume
  180. DSTRING LibraryName; // Name of library to load
  181. DSTRING EntryPoint; // Name of entry point in DLL
  182. DSTRING fat_name;
  183. DSTRING fat32_name;
  184. DSTRING driveletter;
  185. DSTRING user_old_label;
  186. DSTRING null_string;
  187. PWSTRING old_volume_label = NULL;
  188. PATH dos_drive_path;
  189. INT ExitCode = EXIT_SUCCESS; // CONVERT exit code
  190. CONVERT_STATUS ConvertStatus; // Conversion status
  191. NTSTATUS Status; // NT API status
  192. HANDLE FsUtilityHandle; // Handle to DLL
  193. CONVERT_FN Convert; // Pointer to entry point in DLL
  194. IS_CONVERSION_AVAIL_FN IsConversionAvailable;
  195. DWORD OldErrorMode;
  196. DRIVE_TYPE drive_type;
  197. VOL_SERIAL_NUMBER old_serial;
  198. BOOLEAN Error = FALSE;
  199. BOOLEAN Success;
  200. BOOLEAN Result;
  201. ULONG flags;
  202. #if defined(FE_SB) && defined(_X86_)
  203. if(IsPC98_N()){
  204. CONVERT Convert2;
  205. Convert2.ChangeBPB1(&_NtDrive);
  206. }
  207. #endif
  208. // Check to see if this is an ARC System Partition--if it
  209. // is, don't convert it.
  210. //
  211. if( IFS_SYSTEM::IsArcSystemPartition( &_NtDrive, &Error ) ) {
  212. DisplayMessage( MSG_CONV_ARC_SYSTEM_PARTITION, ERROR_MESSAGE );
  213. return EXIT_ERROR;
  214. }
  215. //
  216. // Ask the volume what file system it has, and use that name to
  217. // figure out what DLL to load.
  218. //
  219. if ( !IFS_SYSTEM::QueryFileSystemName( &_NtDrive,
  220. &CurrentFsName,
  221. &Status )) {
  222. if ( Status == STATUS_ACCESS_DENIED ) {
  223. DisplayMessage( MSG_DASD_ACCESS_DENIED, ERROR_MESSAGE );
  224. } else {
  225. DisplayMessage( MSG_FS_NOT_DETERMINED, ERROR_MESSAGE, "%W", &_DisplayDrive );
  226. }
  227. return EXIT_ERROR;
  228. }
  229. CurrentFsName.Strupr();
  230. _FsName.Strupr();
  231. if( CurrentFsName == _FsName ) {
  232. DisplayMessage( MSG_CONV_ALREADY_CONVERTED, ERROR_MESSAGE, "%W%W",
  233. &_DisplayDrive, &_FsName );
  234. return EXIT_ERROR;
  235. }
  236. if (!fat_name.Initialize("FAT") ||
  237. !fat32_name.Initialize("FAT32")) {
  238. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
  239. return EXIT_ERROR;
  240. }
  241. if (CurrentFsName == fat_name || CurrentFsName == fat32_name) {
  242. if ( !LibraryName.Initialize( "CNVFAT" ) ||
  243. !EntryPoint.Initialize( "IsConversionAvailable" ) ) {
  244. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  245. return( EXIT_ERROR );
  246. }
  247. //
  248. // Get pointer to the conversion entry point and convert the volume.
  249. //
  250. if (NULL == (IsConversionAvailable =
  251. (IS_CONVERSION_AVAIL_FN)SYSTEM::QueryLibraryEntryPoint(
  252. &LibraryName, &EntryPoint, &FsUtilityHandle ))) {
  253. //
  254. // There is no conversion DLL for the file system in the volume.
  255. //
  256. DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
  257. "CONVERT", &CurrentFsName );
  258. return EXIT_ERROR;
  259. }
  260. if (IsConversionAvailable(&_FsName) == -1) {
  261. DisplayMessage ( MSG_CONV_CONVERSION_NOT_AVAILABLE, ERROR_MESSAGE,
  262. "%W%W", &CurrentFsName, &_FsName );
  263. return EXIT_ERROR;
  264. }
  265. } else {
  266. DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
  267. "CONVERT", &CurrentFsName );
  268. return EXIT_ERROR;
  269. }
  270. //
  271. // Display the current file system type. (Standard in all file system utilities)
  272. //
  273. DisplayMessage( MSG_FILE_SYSTEM_TYPE, NORMAL_MESSAGE, "%W", &CurrentFsName );
  274. //
  275. // We also initialize the name of the conversion entry point in the DLL
  276. // ("Convert")
  277. //
  278. if ( !EntryPoint.Initialize( "ConvertFAT" )) {
  279. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  280. return( EXIT_ERROR );
  281. }
  282. //
  283. // Get pointer to the conversion entry point and convert the volume.
  284. //
  285. if (NULL == (Convert = (CONVERT_FN)SYSTEM::QueryLibraryEntryPoint(
  286. &LibraryName, &EntryPoint, &FsUtilityHandle ))) {
  287. //
  288. // There is no conversion DLL for the file system in the volume.
  289. //
  290. DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
  291. "CONVERT", &CurrentFsName );
  292. return EXIT_ERROR;
  293. }
  294. // If the volume has a label, prompt the user for it.
  295. // Note that if it has no label we do nothing.
  296. OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  297. drive_type = SYSTEM::QueryDriveType(&_DosDrive);
  298. if (null_string.Initialize( "" ) &&
  299. (drive_type != RemovableDrive) &&
  300. dos_drive_path.Initialize( &_DosDrive) &&
  301. (old_volume_label =
  302. SYSTEM::QueryVolumeLabel( &dos_drive_path,
  303. &old_serial )) != NULL &&
  304. old_volume_label->Stricmp( &null_string ) != 0 ) {
  305. // This drive has a label. To give the user
  306. // a bit more protection, prompt for the old label:
  307. DisplayMessage( MSG_ENTER_CURRENT_LABEL, NORMAL_MESSAGE, "%W",
  308. &_DisplayDrive );
  309. _Message.QueryStringInput( &user_old_label );
  310. if( old_volume_label->Stricmp( &user_old_label ) != 0 ) {
  311. // Re-enable hard error popups.
  312. SetErrorMode( OldErrorMode );
  313. DisplayMessage( MSG_WRONG_CURRENT_LABEL, ERROR_MESSAGE );
  314. DELETE( old_volume_label );
  315. return EXIT_ERROR;
  316. }
  317. }
  318. // Re-enable hard error popups
  319. SetErrorMode( OldErrorMode );
  320. DELETE( old_volume_label );
  321. BOOLEAN delete_uninstall_backup = FALSE;
  322. OSVERSIONINFOEX os_version_info;
  323. if (Uninstall_Valid == IsUninstallImageValid(Uninstall_FatToNtfsConversion, &os_version_info)) {
  324. DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP, NORMAL_MESSAGE );
  325. if (!_Message.IsYesResponse(FALSE)) {
  326. return EXIT_ERROR;
  327. }
  328. delete_uninstall_backup = TRUE;
  329. }
  330. flags = _Verbose ? CONVERT_VERBOSE_FLAG : 0;
  331. flags |= _NoChkdsk ? CONVERT_NOCHKDSK_FLAG : 0;
  332. flags |= _ForceDismount ? CONVERT_FORCE_DISMOUNT_FLAG : 0;
  333. flags |= _NoSecurity ? CONVERT_NOSECURITY_FLAG : 0;
  334. //
  335. // no pause flag needed since we don't want to pause
  336. //
  337. Result = Convert( &_NtDrive,
  338. &_FsName,
  339. &_CvtZoneFileName,
  340. &_Message,
  341. flags,
  342. &ConvertStatus);
  343. SYSTEM::FreeLibraryHandle( FsUtilityHandle );
  344. if ( Result ) {
  345. DWORD sce_result = NO_ERROR;
  346. ExitCode = EXIT_SUCCESS;
  347. if (!_NoSecurity && _DosDrive.QueryChCount() == 2 && _DosDrive.QueryChAt(1) == ':') {
  348. DSTRING msg;
  349. sce_result = SceConfigureConvertedFileSecurity( (PWSTR)_DosDrive.GetWSTR(), 0 );
  350. if ( sce_result != NO_ERROR ) {
  351. if ( SYSTEM::QueryWindowsErrorMessage( sce_result, &msg ) ) {
  352. DisplayMessage( MSG_CONV_SCE_FAILURE_WITH_MESSAGE, ERROR_MESSAGE, "%W", &msg );
  353. } else {
  354. DisplayMessage( MSG_CONV_SCE_SET_FAILURE, ERROR_MESSAGE, "%d", sce_result );
  355. }
  356. }
  357. }
  358. if (!NT_SUCCESS(SUPERAREA::GenerateLabelNotification(&_NtDrive))) {
  359. DisplayMessage( MSG_CONV_UNABLE_TO_NOTIFY, ERROR_MESSAGE );
  360. ExitCode = EXIT_ERROR;
  361. }
  362. if (delete_uninstall_backup && !RemoveUninstallImage()) {
  363. DWORD last_error = GetLastError();
  364. DSTRING errmsg;
  365. if (SYSTEM::QueryWindowsErrorMessage( last_error, &errmsg )) {
  366. DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%W", &errmsg );
  367. } else {
  368. DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%d", last_error );
  369. }
  370. ExitCode = EXIT_ERROR;
  371. }
  372. //
  373. // We're done.
  374. //
  375. if ( sce_result == NO_ERROR && ExitCode == EXIT_SUCCESS ) {
  376. DisplayMessage( MSG_CONV_CONVERSION_COMPLETE, NORMAL_MESSAGE );
  377. return EXIT_SUCCESS;
  378. } else {
  379. return EXIT_ERROR;
  380. }
  381. } else {
  382. //
  383. // The conversion was not successful. Determine what the problem
  384. // was and return the appropriate CONVERT exit code.
  385. //
  386. switch ( ConvertStatus ) {
  387. case CONVERT_STATUS_CONVERTED:
  388. //
  389. // This is an inconsistent state, Convert should return
  390. // TRUE if the conversion was successful!
  391. //
  392. DebugPrintTrace(( "CONVERT Error: Conversion failed, but status is success!\n" ));
  393. DebugAssert( FALSE );
  394. DisplayMessage( MSG_CONV_CONVERSION_MAYHAVE_FAILED, ERROR_MESSAGE,
  395. "%W%W", &_DisplayDrive, &_FsName );
  396. ExitCode = EXIT_ERROR;
  397. break;
  398. case CONVERT_STATUS_INVALID_FILESYSTEM:
  399. //
  400. // The conversion DLL does not recognize the target file system.
  401. //
  402. DisplayMessage( MSG_CONV_INVALID_FILESYSTEM, ERROR_MESSAGE, "%W", &_FsName );
  403. ExitCode = EXIT_UNKNOWN;
  404. break;
  405. case CONVERT_STATUS_CONVERSION_NOT_AVAILABLE:
  406. //
  407. // The target file system is valid, but the conversion is not
  408. // available.
  409. //
  410. DisplayMessage( MSG_CONV_CONVERSION_NOT_AVAILABLE, ERROR_MESSAGE,
  411. "%W%W", &CurrentFsName, &_FsName );
  412. ExitCode = EXIT_NOCANDO;
  413. break;
  414. case CONVERT_STATUS_NTFS_RESERVED_NAMES:
  415. DisplayMessage( MSG_CONV_NTFS_RESERVED_NAMES, ERROR_MESSAGE, "%W", &_DisplayDrive );
  416. ExitCode = EXIT_ERROR;
  417. break;
  418. case CONVERT_STATUS_WRITE_PROTECTED:
  419. DisplayMessage( MSG_CONV_WRITE_PROTECTED, ERROR_MESSAGE, "%W", &_DisplayDrive );
  420. ExitCode = EXIT_ERROR;
  421. break;
  422. case CONVERT_STATUS_CANNOT_LOCK_DRIVE:
  423. //
  424. // The drive cannot be locked. We must schedule ChkDsk and AutoConv
  425. // to do the job during the next system boot.
  426. //
  427. DisplayMessage( MSG_CONVERT_ON_REBOOT_PROMPT, NORMAL_MESSAGE, "%W",
  428. &_DisplayDrive );
  429. // Note that ScheduleAutoConv reports its success or
  430. // failure, so no additional messages are required.
  431. //
  432. if ( _Message.IsYesResponse( FALSE ) &&
  433. ScheduleAutoConv() ) {
  434. if (!_NoSecurity && _DosDrive.QueryChCount() == 2 && _DosDrive.QueryChAt(1) == ':') {
  435. DSTRING msg;
  436. DWORD sce_result;
  437. sce_result = SceConfigureConvertedFileSecurity( (PWSTR)_DosDrive.GetWSTR(), 1 );
  438. if ( sce_result != NO_ERROR ) {
  439. if ( SYSTEM::QueryWindowsErrorMessage( sce_result, &msg ) ) {
  440. DisplayMessage( MSG_CONV_SCE_FAILURE_WITH_MESSAGE, ERROR_MESSAGE, "%W", &msg );
  441. } else {
  442. DisplayMessage( MSG_CONV_SCE_SCHEDULE_FAILURE, ERROR_MESSAGE, "%d", sce_result );
  443. }
  444. //
  445. // error in setting up security for files
  446. //
  447. ExitCode = EXIT_ERROR;
  448. } else {
  449. ExitCode = EXIT_SCHEDULED;
  450. }
  451. } else {
  452. //
  453. // no need to worry about security and so return success
  454. //
  455. ExitCode = EXIT_SCHEDULED;
  456. }
  457. if (delete_uninstall_backup && !RemoveUninstallImage()) {
  458. DWORD last_error = GetLastError();
  459. DSTRING errmsg;
  460. if (SYSTEM::QueryWindowsErrorMessage( last_error, &errmsg )) {
  461. DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%W", &errmsg );
  462. } else {
  463. DisplayMessage( MSG_CONV_DELETE_UNINSTALL_BACKUP_ERROR, ERROR_MESSAGE, "%d", last_error );
  464. }
  465. ExitCode = EXIT_ERROR;
  466. }
  467. } else {
  468. //
  469. // Don't want to schedule a convert or scheduling failed
  470. //
  471. ExitCode = EXIT_ERROR;
  472. }
  473. break;
  474. case CONVERT_STATUS_INSUFFICIENT_FREE_SPACE:
  475. case CONVERT_STATUS_DRIVE_IS_DIRTY:
  476. case CONVERT_STATUS_ERROR:
  477. //
  478. // The conversion failed.
  479. //
  480. DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
  481. "%W%W", &_DisplayDrive, &_FsName );
  482. if(ConvertStatus == CONVERT_STATUS_INSUFFICIENT_FREE_SPACE) {
  483. ExitCode = EXIT_NOFREESPACE;
  484. } else {
  485. ExitCode = EXIT_ERROR;
  486. }
  487. break;
  488. default:
  489. //
  490. // Invalid status code
  491. //
  492. DebugPrintTrace(( "CONVERT Error: Convert status code %X invalid!\n",
  493. ConvertStatus ));
  494. DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
  495. "%W%W", &_DisplayDrive, &_FsName );
  496. ExitCode = EXIT_ERROR;
  497. break;
  498. }
  499. return ExitCode;
  500. }
  501. }
  502. PPATH
  503. CONVERT::FindSystemFile(
  504. IN PWSTR FileName
  505. )
  506. /*++
  507. Routine Description:
  508. Makes sure that the given file is in the system directory.
  509. Arguments:
  510. FileName - Supplies the name of the file to look for.
  511. Return Value:
  512. PPATH - Path to the file found
  513. --*/
  514. {
  515. DSTRING Name;
  516. PPATH Path = NULL;
  517. PFSN_FILE File = NULL;
  518. if ( !(Path = SYSTEM::QuerySystemDirectory() ) ) {
  519. DisplayMessage( MSG_CONV_CANNOT_FIND_SYSTEM_DIR, ERROR_MESSAGE );
  520. return FALSE;
  521. }
  522. if ( !Name.Initialize( FileName ) ||
  523. !Path->AppendBase( &Name ) ) {
  524. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  525. DELETE( Path );
  526. return FALSE;
  527. }
  528. if ( !(File = SYSTEM::QueryFile( Path )) ) {
  529. DisplayMessage( MSG_CONV_CANNOT_FIND_FILE, ERROR_MESSAGE, "%W", Path->GetPathString() );
  530. DELETE( Path );
  531. return FALSE;
  532. }
  533. DELETE( File );
  534. return Path;
  535. }
  536. BOOLEAN
  537. CONVERT::ParseArguments(
  538. OUT PINT ExitCode
  539. )
  540. /*++
  541. Routine Description:
  542. Parses the command line and sets the parameters used by the conversion
  543. utility.
  544. The arguments accepted are:
  545. drive: Drive to convert
  546. /fs:fsname File system to convert to
  547. /v Verbose mode
  548. /? Help
  549. /CVTAREA:filename Filename for convert zone as place holder
  550. for the $MFT, $Logfile, and Volume bitmap
  551. /NoSecurity Allow everyone access
  552. /NoChkdsk Skip chkdsk
  553. /x Force a dismount on the volume if necessary
  554. Arguments:
  555. ExitCode - Supplies pointer to CONVERT exit code
  556. Return Value:
  557. BOOLEAN - TRUE if arguments were parsed correctly and program can
  558. continue.
  559. FALSE if the program should exit. ExitCode contains the
  560. value with which the program should exit. Note that this
  561. does not necessarily means an error (e.g. user requested
  562. help).
  563. --*/
  564. {
  565. UCHAR SequenceNumber;
  566. PATH path;
  567. DSTRING drive_path_string;
  568. PATH_ANALYZE_CODE rst;
  569. DebugPtrAssert( ExitCode );
  570. //
  571. // Parse command line
  572. //
  573. if ( !ParseCommandLine( NULL, TRUE ) ) {
  574. *ExitCode = EXIT_ERROR;
  575. return FALSE;
  576. }
  577. //
  578. // If the user requested help, give it.
  579. //
  580. if ( _Help ) {
  581. DisplayMessage( MSG_CONV_USAGE );
  582. *ExitCode = EXIT_SUCCESS;
  583. return FALSE;
  584. }
  585. #ifdef DBLSPACE_ENABLED
  586. if (_Compress && !_Uncompress) {
  587. //
  588. // We don't allow you to specify /c (compress resulting
  589. // filesystem) unless the source filesystem has dblspace.
  590. //
  591. DisplayMessage(MSG_CONV_SLASH_C_INVALID, ERROR_MESSAGE);
  592. *ExitCode = EXIT_ERROR;
  593. return FALSE;
  594. }
  595. #endif // DBLSPACE_ENABLED
  596. //
  597. // If the command line did not specify a drive, we use the
  598. // current drive.
  599. //
  600. if ( _DosDrive.QueryChCount() == 0 ) {
  601. if ( !SYSTEM::QueryCurrentDosDriveName( &_DosDrive ) ) {
  602. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  603. *ExitCode = EXIT_ERROR;
  604. return FALSE;
  605. }
  606. }
  607. if ( !path.Initialize( &_DosDrive ) ) {
  608. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  609. *ExitCode = EXIT_ERROR;
  610. return FALSE;
  611. }
  612. rst = path.AnalyzePath( &_GuidDrive,
  613. &_FullPath,
  614. &drive_path_string );
  615. switch (rst) {
  616. case PATH_OK:
  617. case PATH_COULD_BE_FLOPPY:
  618. if (drive_path_string.QueryChCount() != 0) {
  619. DisplayMessage( MSG_CONV_INVALID_DRIVE_SPEC, ERROR_MESSAGE );
  620. *ExitCode = EXIT_ERROR;
  621. return FALSE;
  622. }
  623. if (path.IsGuidVolName()) {
  624. if (!_DisplayDrive.Initialize(&_GuidDrive)) {
  625. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  626. *ExitCode = EXIT_ERROR;
  627. return FALSE;
  628. }
  629. } else {
  630. if (!_DisplayDrive.Initialize(_FullPath.GetPathString())) {
  631. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  632. *ExitCode = EXIT_ERROR;
  633. return FALSE;
  634. }
  635. }
  636. if (_FullPath.GetPathString()->QueryChCount() == 2 &&
  637. _FullPath.GetPathString()->QueryChAt(1) == (WCHAR)':') {
  638. // if there is a drive letter for this drive, use it
  639. // instead of the guid volume name
  640. if (!_DosDrive.Initialize(_FullPath.GetPathString())) {
  641. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  642. *ExitCode = EXIT_ERROR;
  643. return FALSE;
  644. }
  645. } else {
  646. if (!_DosDrive.Initialize(&_GuidDrive)) {
  647. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  648. *ExitCode = EXIT_ERROR;
  649. return FALSE;
  650. }
  651. }
  652. break;
  653. case PATH_OUT_OF_MEMORY:
  654. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  655. *ExitCode = EXIT_ERROR;
  656. return FALSE;
  657. case PATH_NO_MOUNT_POINT_FOR_VOLUME_NAME_PATH:
  658. DisplayMessage( MSG_CONV_NO_MOUNT_POINT_FOR_GUID_VOLNAME_PATH, ERROR_MESSAGE );
  659. *ExitCode = EXIT_ERROR;
  660. return FALSE;
  661. default:
  662. DisplayMessage( MSG_CONV_INVALID_DRIVE_SPEC, ERROR_MESSAGE );
  663. *ExitCode = EXIT_ERROR;
  664. return FALSE;
  665. }
  666. if (!_DosDrive.Strupr()) {
  667. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  668. *ExitCode = EXIT_ERROR;
  669. return FALSE;
  670. }
  671. //
  672. // Make sure that drive is valid and is not remote.
  673. //
  674. switch ( SYSTEM::QueryDriveType( &_DosDrive ) ) {
  675. case UnknownDrive:
  676. DisplayMessage( MSG_CONV_INVALID_DRIVE_SPEC, ERROR_MESSAGE );
  677. *ExitCode = EXIT_ERROR;
  678. return FALSE;
  679. case CdRomDrive:
  680. DisplayMessage( MSG_CONV_CANT_CDROM, ERROR_MESSAGE );
  681. *ExitCode = EXIT_ERROR;
  682. return FALSE;
  683. case RemoteDrive:
  684. DisplayMessage( MSG_CONV_CANT_NETWORK, ERROR_MESSAGE );
  685. *ExitCode = EXIT_ERROR;
  686. return FALSE;
  687. default:
  688. break;
  689. }
  690. //
  691. // Make sure a target file system was specified. Note that we do not
  692. // validate the file system, we accept any string.
  693. //
  694. if ( _FsName.QueryChCount() == 0 ) {
  695. DisplayMessage( MSG_CONV_NO_FILESYSTEM_SPECIFIED, ERROR_MESSAGE );
  696. *ExitCode = EXIT_ERROR;
  697. return FALSE;
  698. }
  699. //
  700. // Set other object members.
  701. //
  702. if ( !IFS_SYSTEM::DosDriveNameToNtDriveName( &_DosDrive, &_NtDrive )) {
  703. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  704. *ExitCode = EXIT_ERROR;
  705. return FALSE;
  706. }
  707. #ifdef DBLSPACE_ENABLED
  708. //
  709. // If we're to uncompress a dblspace volume, generate the cvf name.
  710. //
  711. if (_Uncompress) {
  712. swprintf(NameBuffer, L"DBLSPACE.%03d", SequenceNumber);
  713. if ( _FullPath.GetPathString()->QueryChCount() == 0 ) {
  714. DisplayMessage( MSG_CONV_NO_MOUNT_POINT_FOR_GUID_VOLNAME_PATH, ERROR_MESSAGE );
  715. *ExitCode = EXIT_ERROR;
  716. return FALSE;
  717. }
  718. if (!_CvfName.Initialize(NameBuffer)) {
  719. DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
  720. *ExitCode = EXIT_ERROR;
  721. return FALSE;
  722. }
  723. }
  724. #endif // DBLSPACE_ENABLED
  725. *ExitCode = EXIT_SUCCESS;
  726. return TRUE;
  727. }
  728. BOOLEAN
  729. CONVERT::ParseCommandLine (
  730. IN PCWSTRING CommandLine,
  731. IN BOOLEAN Interactive
  732. )
  733. /*++
  734. Routine Description:
  735. Parses the CONVERT (AUTOCONV) command line.
  736. The arguments accepted are:
  737. drive: Drive to convert
  738. /fs:fsname File system to convert to
  739. /v Verbose mode
  740. /uncompress[:sss] Convert from dblspace
  741. /c Compress resulting filesystem
  742. /? Help
  743. /CVTAREA:filename Filename for convert zone as place holder
  744. for the $MFT, $Logfile, and Volume bitmap
  745. Arguments:
  746. CommandLine - Supplies command line to parse
  747. Interactive - Supplies Interactive flag
  748. Return Value:
  749. BOOLEAN - TRUE if arguments were parsed correctly.
  750. --*/
  751. {
  752. ARRAY ArgArray; // Array of arguments
  753. ARRAY LexArray; // Array of lexemes
  754. ARGUMENT_LEXEMIZER ArgLex; // Argument Lexemizer
  755. STRING_ARGUMENT DriveArgument; // Drive argument
  756. STRING_ARGUMENT ProgramNameArgument; // Program name argument
  757. STRING_ARGUMENT FsNameArgument; // Target FS name argument
  758. STRING_ARGUMENT ConvertZoneArgument; // Convert Zone file name
  759. FLAG_ARGUMENT HelpArgument; // Help flag argument
  760. FLAG_ARGUMENT VerboseArgument; // Verbose flag argument
  761. FLAG_ARGUMENT NoSecurityArgument; // Skip setting of security argument
  762. FLAG_ARGUMENT NoChkdskArgument; // Skip chkdsk argument
  763. FLAG_ARGUMENT ForceDismountArgument; // Force a dismount argument
  764. #ifdef DBLSPACE_ENABLED
  765. FLAG_ARGUMENT UncompressArgument; // Uncompress flag argument
  766. FLAG_ARGUMENT CompressArgument; // Compress flag argument
  767. LONG_ARGUMENT UncompressNumberArgument;// Sequence number argument
  768. #endif // DBLSPACE_ENABLED
  769. PWSTRING InvalidArg; // Invalid argument catcher
  770. //
  771. // Initialize all the argument parsing machinery.
  772. //
  773. if( !ArgArray.Initialize( 7, 1 ) ||
  774. !LexArray.Initialize( 7, 1 ) ||
  775. !ArgLex.Initialize( &LexArray ) ||
  776. !DriveArgument.Initialize( "*" ) ||
  777. !HelpArgument.Initialize( "/?" ) ||
  778. !VerboseArgument.Initialize( "/V" ) ||
  779. !NoSecurityArgument.Initialize( "/NoSecurity" ) ||
  780. !NoChkdskArgument.Initialize( "/NoChkdsk" ) ||
  781. !ForceDismountArgument.Initialize( "/X" ) ||
  782. #ifdef DBLSPACE_ENABLED
  783. !CompressArgument.Initialize( "/C" ) ||
  784. #endif // DBLSPACE_ENABLED
  785. !ProgramNameArgument.Initialize( "*" ) ||
  786. #ifdef DBLSPACE_ENABLED
  787. !UncompressArgument.Initialize( "/UNCOMPRESS" ) ||
  788. !UncompressNumberArgument.Initialize( "/UNCOMPRESS:*" ) ||
  789. #endif // DBLSPACE_ENABLED
  790. !FsNameArgument.Initialize( "/FS:*" ) ||
  791. !ConvertZoneArgument.Initialize( "/CVTAREA:*" ) ) {
  792. if ( Interactive ) {
  793. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  794. }
  795. return FALSE;
  796. }
  797. //
  798. // The conversion utility is case-insensitive
  799. //
  800. ArgLex.SetCaseSensitive( FALSE );
  801. if( !ArgArray.Put( &ProgramNameArgument ) ||
  802. !ArgArray.Put( &HelpArgument ) ||
  803. !ArgArray.Put( &DriveArgument ) ||
  804. !ArgArray.Put( &VerboseArgument ) ||
  805. !ArgArray.Put( &NoSecurityArgument ) ||
  806. !ArgArray.Put( &NoChkdskArgument ) ||
  807. !ArgArray.Put( &ForceDismountArgument ) ||
  808. #ifdef DBLSPACE_ENABLED
  809. !ArgArray.Put( &CompressArgument ) ||
  810. #endif // DBLSPACE_ENABLED
  811. #ifdef DBLSPACE_ENABLED
  812. !ArgArray.Put( &UncompressArgument ) ||
  813. !ArgArray.Put( &UncompressNumberArgument ) ||
  814. #endif // DBLSPACE_ENABLED
  815. !ArgArray.Put( &FsNameArgument ) ||
  816. !ArgArray.Put( &ConvertZoneArgument ) ) {
  817. if ( Interactive ) {
  818. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  819. }
  820. return FALSE;
  821. }
  822. //
  823. // Lexemize the command line.
  824. //
  825. if ( !ArgLex.PrepareToParse( (PWSTRING)CommandLine ) ) {
  826. if ( Interactive ) {
  827. DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
  828. }
  829. return FALSE;
  830. }
  831. //
  832. // Parse the arguments.
  833. //
  834. if( !ArgLex.DoParsing( &ArgArray ) ) {
  835. if ( Interactive ) {
  836. DisplayMessage( MSG_CONV_INVALID_PARAMETER, ERROR_MESSAGE, "%W",
  837. InvalidArg = ArgLex.QueryInvalidArgument() );
  838. DELETE( InvalidArg );
  839. }
  840. return FALSE;
  841. }
  842. _Help = HelpArgument.QueryFlag();
  843. _Verbose = VerboseArgument.QueryFlag();
  844. _NoSecurity = NoSecurityArgument.QueryFlag();
  845. _NoChkdsk = NoChkdskArgument.QueryFlag();
  846. _ForceDismount = ForceDismountArgument.QueryFlag();
  847. _Restart = FALSE; // obsolete argument
  848. #ifdef DBLSPACE_ENABLED
  849. _Compress = CompressArgument.QueryFlag();
  850. #endif // DBLSPACE_ENABLED
  851. if ( DriveArgument.IsValueSet() ) {
  852. if ( !_DosDrive.Initialize( DriveArgument.GetString() ) ) {
  853. return FALSE;
  854. }
  855. } else {
  856. if ( !_DosDrive.Initialize( L"" ) ) {
  857. return FALSE;
  858. }
  859. }
  860. if ( FsNameArgument.IsValueSet() ) {
  861. if ( !_FsName.Initialize( FsNameArgument.GetString() ) ) {
  862. return FALSE;
  863. }
  864. } else {
  865. if ( !_FsName.Initialize( L"" ) ) {
  866. return FALSE;
  867. }
  868. }
  869. if( ConvertZoneArgument.IsValueSet() ) {
  870. if( !_CvtZoneFileName.Initialize( ConvertZoneArgument.GetString() ) ) {
  871. return FALSE;
  872. }
  873. } else {
  874. _CvtZoneFileName.Initialize( L"" );
  875. }
  876. #ifdef DBLSPACE_ENABLED
  877. _SequenceNumber = 0;
  878. _Uncompress = FALSE;
  879. if (UncompressArgument.IsValueSet()) {
  880. _Uncompress = TRUE;
  881. }
  882. if (UncompressNumberArgument.IsValueSet()) {
  883. _SequenceNumber = (UCHAR)UncompressNumberArgument.QueryLong();
  884. _Uncompress = TRUE;
  885. }
  886. #endif // DBLSPACE_ENABLED
  887. return TRUE;
  888. }
  889. BOOLEAN
  890. CONVERT::Schedule (
  891. )
  892. /*++
  893. Routine Description:
  894. Schedules AutoConv
  895. Arguments:
  896. None.
  897. Return Value:
  898. BOOLEAN - TRUE if AutoConv successfully scheduled.
  899. FALSE otherwise
  900. --*/
  901. {
  902. DSTRING CommandLine;
  903. DSTRING Space;
  904. DSTRING FileSystem;
  905. DSTRING ConvertZoneFlag;
  906. DSTRING NoChkdskFlag;
  907. DSTRING VerboseFlag;
  908. DSTRING NoSecurityFlag;
  909. if( !CommandLine.Initialize( (LPWSTR)L"autocheck autoconv " ) ||
  910. !Space.Initialize( (LPWSTR)L" " ) ||
  911. !FileSystem.Initialize( (LPWSTR)L"/FS:" ) ||
  912. !CommandLine.Strcat( &_NtDrive ) ||
  913. !CommandLine.Strcat( &Space ) ||
  914. !CommandLine.Strcat( &FileSystem ) ||
  915. !CommandLine.Strcat( &_FsName ) ) {
  916. return FALSE;
  917. }
  918. if( _CvtZoneFileName.QueryChCount() &&
  919. ( !CommandLine.Strcat( &Space ) ||
  920. !ConvertZoneFlag.Initialize( L"/CVTAREA:" ) ||
  921. !CommandLine.Strcat( &ConvertZoneFlag ) ||
  922. !CommandLine.Strcat( &_CvtZoneFileName ) ) ) {
  923. return FALSE;
  924. }
  925. if( _NoChkdsk &&
  926. ( !CommandLine.Strcat( &Space ) ||
  927. !NoChkdskFlag.Initialize( L"/NoChkdsk" ) ||
  928. !CommandLine.Strcat( &NoChkdskFlag ) ) ) {
  929. return FALSE;
  930. }
  931. if( _Verbose &&
  932. ( !CommandLine.Strcat( &Space ) ||
  933. !VerboseFlag.Initialize( L"/V" ) ||
  934. !CommandLine.Strcat( &VerboseFlag ) ) ) {
  935. return FALSE;
  936. }
  937. if( _NoSecurity &&
  938. ( !CommandLine.Strcat( &Space ) ||
  939. !NoSecurityFlag.Initialize( L"/NoSecurity" ) ||
  940. !CommandLine.Strcat( &NoSecurityFlag ) ) ) {
  941. return FALSE;
  942. }
  943. //
  944. // There is no need to add options that are only for convert.exe
  945. // like /x.
  946. //
  947. return( AUTOREG::AddEntry( &CommandLine ) );
  948. }
  949. BOOLEAN
  950. CONVERT::ScheduleAutoConv(
  951. )
  952. /*++
  953. Routine Description:
  954. Schedules AutoConv to be invoked during boot the next time
  955. that the machine reboots.
  956. Arguments:
  957. None
  958. Return Value:
  959. BOOLEAN - TRUE if AutoConv successfully scheduled.
  960. FALSE otherwise
  961. --*/
  962. {
  963. BOOLEAN Ok;
  964. //
  965. // Make sure that Autoconv.exe is in the right place.
  966. //
  967. if ( !(_Autoconv = FindSystemFile( (LPWSTR)AUTOCONV_PROGRAM_NAME )) ) {
  968. DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
  969. return FALSE;
  970. }
  971. // Remove any previously scheduled conversion
  972. //
  973. if ( !RemoveScheduledAutoConv( ) ) {
  974. DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
  975. return FALSE;
  976. }
  977. //
  978. // schedule autoconvert
  979. //
  980. if ( Ok = Schedule( ) ) {
  981. DisplayMessage( MSG_CONV_WILL_CONVERT_ON_REBOOT, NORMAL_MESSAGE, "%W", &_DisplayDrive );
  982. } else {
  983. DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
  984. }
  985. return Ok;
  986. }
  987. BOOLEAN
  988. CONVERT::RemoveScheduledAutoConv(
  989. )
  990. /*++
  991. Routine Description:
  992. Remove possibly old entry of autoconv for the specified volume.
  993. Arguments:
  994. N/A
  995. Return Value:
  996. TRUE if no error.
  997. --*/
  998. {
  999. DSTRING CommandLine;
  1000. DSTRING NtDrive;
  1001. if (!CommandLine.Initialize( (LPWSTR)L"autocheck autoconv " )) {
  1002. return FALSE;
  1003. }
  1004. if (!AUTOREG::DeleteEntry(&CommandLine, &_NtDrive)) {
  1005. return FALSE;
  1006. }
  1007. if (_DosDrive.Stricmp(&_GuidDrive) == 0)
  1008. return FALSE;
  1009. DebugAssert(_DosDrive.QueryChCount() == 2);
  1010. if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&_GuidDrive, &NtDrive)) {
  1011. return FALSE;
  1012. }
  1013. if (!AUTOREG::DeleteEntry(&CommandLine, &NtDrive)) {
  1014. return FALSE;
  1015. }
  1016. return TRUE;
  1017. }
  1018. #if defined(FE_SB) && defined(_X86_)
  1019. BOOLEAN
  1020. CONVERT::ChangeBPB1(
  1021. IN PCWSTRING NtDrive
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. Change Bpb parameters Logical to Physical
  1026. Arguments:
  1027. none
  1028. Return Value:
  1029. BOOLEAN - TRUE Change OK
  1030. FALSE otherwise
  1031. --*/
  1032. {
  1033. USHORT work,work2;
  1034. ULONG work3;
  1035. BIG_INT start_sec;
  1036. ULONG sector_len;
  1037. PUCHAR Bpb_Buff;
  1038. HMEM hmem;
  1039. _NtDrive.Initialize(NtDrive);
  1040. start_sec=0;
  1041. sector_len=1;
  1042. LOG_IO_DP_DRIVE dpdrive;
  1043. //*** open
  1044. if (!dpdrive.Initialize( &_NtDrive, &_Message )) {
  1045. return FALSE;
  1046. }
  1047. if (!hmem.Acquire(2048, dpdrive.QueryAlignmentMask())) {
  1048. return(FALSE);
  1049. }
  1050. Bpb_Buff = (PUCHAR)hmem.GetBuf();
  1051. //*** read
  1052. if(!dpdrive.Read( start_sec, sector_len, Bpb_Buff)){
  1053. return FALSE;
  1054. }
  1055. work=(USHORT)dpdrive.QueryPhysicalSectorSize(); // get physical sector size
  1056. //*** change to physical from logical ***
  1057. _BytePerSec = Bpb_Buff[11]+Bpb_Buff[12]*256;
  1058. _SecPerClus = Bpb_Buff[13];
  1059. _Reserved = Bpb_Buff[14]+Bpb_Buff[15]*256;
  1060. _SectorNum = Bpb_Buff[19]+Bpb_Buff[20]*256;
  1061. _SecPerFat = Bpb_Buff[22]+Bpb_Buff[23]*256;
  1062. _LargeSector = Bpb_Buff[32]+Bpb_Buff[33]*256+Bpb_Buff[34]*256*256+Bpb_Buff[35]*256*256*256;
  1063. if (work != _BytePerSec){
  1064. Bpb_Buff[11] = (UCHAR)(work%256);
  1065. Bpb_Buff[12] = (UCHAR)(work/256);
  1066. Bpb_Buff[13]*= (UCHAR)(_BytePerSec/work);
  1067. work2 = _Reserved*_BytePerSec/work;
  1068. Bpb_Buff[14] = (UCHAR)(work2%256);
  1069. Bpb_Buff[15] = (UCHAR)(work2/256);
  1070. work2 = _SecPerFat*_BytePerSec/work;
  1071. Bpb_Buff[22] = (UCHAR)(work2%256);
  1072. Bpb_Buff[23] = (UCHAR)(work2/256);
  1073. if (_SectorNum*(_BytePerSec/work)>0xffff){
  1074. Bpb_Buff[19] = 0;
  1075. Bpb_Buff[20] = 0;
  1076. work3 = ((long)_SectorNum*(long)(_BytePerSec/work));
  1077. Bpb_Buff[32] = (UCHAR)(work3%256L);
  1078. Bpb_Buff[35] = (UCHAR)(work3/(256L*256L*256L));
  1079. Bpb_Buff[34] = (UCHAR)(work3/(256L*256L)-(ULONG)Bpb_Buff[31]*256L);
  1080. Bpb_Buff[33] = (UCHAR)(work3/256L-(ULONG)Bpb_Buff[31]*256L*256L-(ULONG)Bpb_Buff[30]*256L);
  1081. } else {
  1082. work2 = _SectorNum*(_BytePerSec/work);
  1083. Bpb_Buff[19] = (UCHAR)(work2%256);
  1084. Bpb_Buff[20] = (UCHAR)(work2/256);
  1085. work3 = _LargeSector;
  1086. Bpb_Buff[32] = (UCHAR)(work3%256L);
  1087. Bpb_Buff[35] = (UCHAR)(work3/(256L*256L*256L));
  1088. Bpb_Buff[34] = (UCHAR)(work3/(256L*256L)-(ULONG)Bpb_Buff[31]*256L);
  1089. Bpb_Buff[33] = (UCHAR)(work3/256L-(ULONG)Bpb_Buff[31]*256L*256L-(ULONG)Bpb_Buff[30]*256L);
  1090. }
  1091. start_sec=0;
  1092. sector_len=1;
  1093. //*** write
  1094. if (!dpdrive.Write(start_sec,sector_len,Bpb_Buff)){
  1095. //*** close
  1096. return FALSE;
  1097. }
  1098. } else {
  1099. //*** close
  1100. return FALSE;
  1101. }
  1102. return TRUE;
  1103. }
  1104. #endif