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.

1524 lines
41 KiB

  1. /*++
  2. Copyright (c) 1993-1994 Microsoft Corporation
  3. Module Name:
  4. commit.c
  5. Abstract:
  6. This module contains the set of routines that support the commitment
  7. of changes to disk without rebooting.
  8. Author:
  9. Bob Rinne (bobri) 11/15/93
  10. Environment:
  11. User process.
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "fdisk.h"
  16. #include "shellapi.h"
  17. #include <winbase.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <malloc.h>
  21. #include "scsi.h"
  22. #include <ntddcdrm.h>
  23. #include <ntddscsi.h>
  24. // Lock list chain head for deleted partitions.
  25. PDRIVE_LOCKLIST DriveLockListHead = NULL;
  26. // Commit flag for case where a partition is deleted that has not drive letter
  27. extern BOOLEAN CommitDueToDelete;
  28. extern BOOLEAN CommitDueToMirror;
  29. extern BOOLEAN CommitDueToExtended;
  30. extern ULONG UpdateMbrOnDisk;
  31. extern HWND InitDlg;
  32. // List head for new drive letter assignment on commit.
  33. typedef struct _ASSIGN_LIST {
  34. struct _ASSIGN_LIST *Next;
  35. ULONG DiskNumber;
  36. BOOLEAN MoveLetter;
  37. UCHAR OriginalLetter;
  38. UCHAR DriveLetter;
  39. } ASSIGN_LIST, *PASSIGN_LIST;
  40. PASSIGN_LIST AssignDriveLetterListHead = NULL;
  41. VOID
  42. CommitToAssignLetterList(
  43. IN PREGION_DESCRIPTOR RegionDescriptor,
  44. IN BOOL MoveLetter
  45. )
  46. /*++
  47. Routine Description:
  48. Remember this region for assigning a drive letter to it upon
  49. commit.
  50. Arguments:
  51. RegionDescriptor - the region to watch
  52. MoveLetter - indicate that the region letter is already
  53. assigned to a different partition, therefore
  54. it must be "moved".
  55. Return Value:
  56. None
  57. --*/
  58. {
  59. PASSIGN_LIST newListEntry;
  60. PPERSISTENT_REGION_DATA regionData;
  61. newListEntry = (PASSIGN_LIST) Malloc(sizeof(ASSIGN_LIST));
  62. if (newListEntry) {
  63. // Save this region
  64. regionData = PERSISTENT_DATA(RegionDescriptor);
  65. newListEntry->OriginalLetter =
  66. newListEntry->DriveLetter = regionData->DriveLetter;
  67. newListEntry->DiskNumber = RegionDescriptor->Disk;
  68. newListEntry->MoveLetter = MoveLetter;
  69. // place it at the front of the chain.
  70. newListEntry->Next = AssignDriveLetterListHead;
  71. AssignDriveLetterListHead = newListEntry;
  72. }
  73. }
  74. VOID
  75. CommitAssignLetterList(
  76. VOID
  77. )
  78. /*++
  79. Routine Description:
  80. Walk the assign drive letter list and make all drive letter assignments
  81. expected. The regions data structures are moved around, so no pointer
  82. can be maintained to look at them. To determine the partition number
  83. for a new partition in this list, the Disks[] structure must be searched
  84. to find a match on the partition for the drive letter. Then the partition
  85. number will be known.
  86. Arguments:
  87. None
  88. Return Value:
  89. None
  90. --*/
  91. {
  92. PREGION_DESCRIPTOR regionDescriptor;
  93. PPERSISTENT_REGION_DATA regionData;
  94. PDISKSTATE diskp;
  95. PASSIGN_LIST assignList,
  96. prevEntry;
  97. TCHAR newName[4];
  98. WCHAR targetPath[100];
  99. LONG partitionNumber;
  100. ULONG index;
  101. assignList = AssignDriveLetterListHead;
  102. while (assignList) {
  103. if ((assignList->DriveLetter != NO_DRIVE_LETTER_YET) && (assignList->DriveLetter != NO_DRIVE_LETTER_EVER)) {
  104. diskp = Disks[assignList->DiskNumber];
  105. partitionNumber = 0;
  106. for (index = 0; index < diskp->RegionCount; index++) {
  107. regionDescriptor = &diskp->RegionArray[index];
  108. if (DmSignificantRegion(regionDescriptor)) {
  109. // If the region has a drive letter, use the drive letter
  110. // to get the info via the Windows API. Otherwise we'll
  111. // have to use the NT API.
  112. regionData = PERSISTENT_DATA(regionDescriptor);
  113. if (regionData) {
  114. if (regionData->DriveLetter == assignList->DriveLetter) {
  115. partitionNumber = regionDescriptor->Reserved->Partition->PartitionNumber;
  116. regionDescriptor->PartitionNumber = partitionNumber;
  117. break;
  118. }
  119. }
  120. }
  121. }
  122. if (partitionNumber) {
  123. HANDLE handle;
  124. ULONG status;
  125. // set up the new NT path.
  126. wsprintf((LPTSTR) targetPath,
  127. "%s\\Partition%d",
  128. GetDiskName(assignList->DiskNumber),
  129. partitionNumber);
  130. // Set up the DOS name.
  131. newName[1] = (TCHAR)':';
  132. newName[2] = 0;
  133. if (assignList->MoveLetter) {
  134. // The letter must be removed before it
  135. // can be assigned.
  136. newName[0] = (TCHAR)assignList->OriginalLetter;
  137. NetworkRemoveShare((LPCTSTR) newName);
  138. DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) newName, (LPCTSTR) NULL);
  139. newName[0] = (TCHAR)assignList->DriveLetter;
  140. } else {
  141. newName[0] = (TCHAR)assignList->DriveLetter;
  142. }
  143. // Assign the name - don't worry about errors for now.
  144. DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) newName, (LPCTSTR) targetPath);
  145. NetworkShare((LPCTSTR) newName);
  146. // Some of the file systems do not actually dismount
  147. // when requested. Instead, they set a verification
  148. // bit in the device object. Due to dynamic partitioning
  149. // this bit may get cleared by the process of the
  150. // repartitioning and the file system will then
  151. // assume it is still mounted on a new access.
  152. // To get around this problem, new drive letters
  153. // are always locked and dismounted on creation.
  154. status = LowOpenDriveLetter(assignList->DriveLetter,
  155. &handle);
  156. if (NT_SUCCESS(status)) {
  157. // Lock the drive to insure that no other access is occurring
  158. // to the volume.
  159. status = LowLockDrive(handle);
  160. if (NT_SUCCESS(status)) {
  161. LowUnlockDrive(handle);
  162. }
  163. LowCloseDisk(handle);
  164. }
  165. } else {
  166. ErrorDialog(MSG_INTERNAL_LETTER_ASSIGN_ERROR);
  167. }
  168. }
  169. prevEntry = assignList;
  170. assignList = assignList->Next;
  171. Free(prevEntry);
  172. }
  173. AssignDriveLetterListHead = NULL;
  174. }
  175. LONG
  176. CommitInternalLockDriveLetter(
  177. IN PDRIVE_LOCKLIST LockListEntry
  178. )
  179. /*++
  180. Routine Description:
  181. Support routine to perform the locking of a drive letter based on
  182. the locklist entry given.
  183. Arguments:
  184. LockListEntry - The information about what to lock.
  185. Return Values:
  186. zero - success
  187. non-zero failure
  188. --*/
  189. {
  190. ULONG status;
  191. // Lock the disk and save the handle.
  192. status = LowOpenDriveLetter(LockListEntry->DriveLetter,
  193. &LockListEntry->LockHandle);
  194. if (!NT_SUCCESS(status)) {
  195. return 1;
  196. }
  197. // Lock the drive to insure that no other access is occurring
  198. // to the volume.
  199. status = LowLockDrive(LockListEntry->LockHandle);
  200. if (!NT_SUCCESS(status)) {
  201. LowCloseDisk(LockListEntry->LockHandle);
  202. return 1;
  203. }
  204. LockListEntry->CurrentlyLocked = TRUE;
  205. return 0;
  206. }
  207. LONG
  208. CommitToLockList(
  209. IN PREGION_DESCRIPTOR RegionDescriptor,
  210. IN BOOL RemoveDriveLetter,
  211. IN BOOL LockNow,
  212. IN BOOL FailOk
  213. )
  214. /*++
  215. Routine Description:
  216. This routine adds the given drive into the lock list for processing
  217. when a commit occurs. If the LockNow flag is set it indicates that
  218. the drive letter is to be immediately locked if it is to go in the
  219. lock letter list. If this locking fails an error is returned.
  220. Arguments:
  221. RegionDescriptor - the region for the drive to lock.
  222. RemoveDriveLetter - remove the letter when performing the unlock.
  223. LockNow - If the letter is inserted in the list - lock it now.
  224. FailOk - It is ok to fail the lock - used for disabled FT sets.
  225. Return Values:
  226. non-zero - failure to add to list.
  227. --*/
  228. {
  229. PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
  230. PDRIVE_LOCKLIST lockListEntry;
  231. UCHAR driveLetter;
  232. ULONG diskNumber;
  233. if (!regionData) {
  234. // without region data there is no need to be on the lock list.
  235. return 0;
  236. }
  237. // See if this drive letter is already in the lock list.
  238. driveLetter = regionData->DriveLetter;
  239. if ((driveLetter == NO_DRIVE_LETTER_YET) || (driveLetter == NO_DRIVE_LETTER_EVER)) {
  240. // There is no drive letter to lock.
  241. CommitDueToDelete = RemoveDriveLetter;
  242. return 0;
  243. }
  244. if (!regionData->VolumeExists) {
  245. PASSIGN_LIST assignList,
  246. prevEntry;
  247. // This item has never been created so no need to put it in the
  248. // lock list. But it does need to be removed from the assign
  249. // letter list.
  250. prevEntry = NULL;
  251. assignList = AssignDriveLetterListHead;
  252. while (assignList) {
  253. // If a match is found remove it from the list.
  254. if (assignList->DriveLetter == driveLetter) {
  255. if (prevEntry) {
  256. prevEntry->Next = assignList->Next;
  257. } else {
  258. AssignDriveLetterListHead = assignList->Next;
  259. }
  260. Free(assignList);
  261. assignList = NULL;
  262. } else {
  263. prevEntry = assignList;
  264. assignList = assignList->Next;
  265. }
  266. }
  267. return 0;
  268. }
  269. diskNumber = RegionDescriptor->Disk;
  270. lockListEntry = DriveLockListHead;
  271. while (lockListEntry) {
  272. if (lockListEntry->DriveLetter == driveLetter) {
  273. // Already in the list -- update when to lock and unlock
  274. if (diskNumber < lockListEntry->LockOnDiskNumber) {
  275. lockListEntry->LockOnDiskNumber = diskNumber;
  276. }
  277. if (diskNumber > lockListEntry->UnlockOnDiskNumber) {
  278. lockListEntry->UnlockOnDiskNumber = diskNumber;
  279. }
  280. // Already in the lock list and information for locking set up.
  281. // Check to see if this should be a LockNow request.
  282. if (LockNow) {
  283. if (!lockListEntry->CurrentlyLocked) {
  284. // Need to perform the lock.
  285. if (CommitInternalLockDriveLetter(lockListEntry)) {
  286. // Leave the element in the list
  287. return 1;
  288. }
  289. }
  290. }
  291. return 0;
  292. }
  293. lockListEntry = lockListEntry->Next;
  294. }
  295. lockListEntry = (PDRIVE_LOCKLIST) Malloc(sizeof(DRIVE_LOCKLIST));
  296. if (!lockListEntry) {
  297. return 1;
  298. }
  299. // set up the lock list entry.
  300. lockListEntry->LockHandle = NULL;
  301. lockListEntry->PartitionNumber = RegionDescriptor->PartitionNumber;
  302. lockListEntry->DriveLetter = driveLetter;
  303. lockListEntry->RemoveOnUnlock = RemoveDriveLetter;
  304. lockListEntry->CurrentlyLocked = FALSE;
  305. lockListEntry->FailOk = FailOk;
  306. lockListEntry->DiskNumber = lockListEntry->UnlockOnDiskNumber =
  307. lockListEntry->LockOnDiskNumber = diskNumber;
  308. if (LockNow) {
  309. if (CommitInternalLockDriveLetter(lockListEntry)) {
  310. // Do not add this to the list.
  311. Free(lockListEntry);
  312. return 1;
  313. }
  314. }
  315. // place it at the front of the chain.
  316. lockListEntry->Next = DriveLockListHead;
  317. DriveLockListHead = lockListEntry;
  318. return 0;
  319. }
  320. LONG
  321. CommitLockVolumes(
  322. IN ULONG Disk
  323. )
  324. /*++
  325. Routine Description:
  326. This routine will go through any drive letters inserted in the lock list
  327. for the given disk number and attempt to lock the volumes. Currently,
  328. this routine locks all of the drives letters in the lock list when
  329. called the first time (i.e. when Disk == 0).
  330. Arguments:
  331. Disk - the index into the disk table.
  332. Return Values:
  333. non-zero - failure to lock the items in the list.
  334. --*/
  335. {
  336. PDRIVE_LOCKLIST lockListEntry;
  337. if (Disk) {
  338. return 0;
  339. }
  340. for (lockListEntry = DriveLockListHead; lockListEntry; lockListEntry = lockListEntry->Next) {
  341. // Lock the disk. Return on any failure if that is the
  342. // requested action for the entry. It is the responsibility
  343. // of the caller to release any successful locks.
  344. if (!lockListEntry->CurrentlyLocked) {
  345. if (CommitInternalLockDriveLetter(lockListEntry)) {
  346. if (!lockListEntry->FailOk) {
  347. return 1;
  348. }
  349. }
  350. }
  351. }
  352. return 0;
  353. }
  354. LONG
  355. CommitUnlockVolumes(
  356. IN ULONG Disk,
  357. IN BOOLEAN FreeList
  358. )
  359. /*++
  360. Routine Description:
  361. Go through and unlock any locked volumes in the locked list for the
  362. given disk. Currently this routine waits until the last disk has
  363. been processed, then unlocks all disks.
  364. Arguments:
  365. Disk - the index into the disk table.
  366. FreeList - Clean up the list as unlocks are performed or don't
  367. Return Values:
  368. non-zero - failure to lock the items in the list.
  369. --*/
  370. {
  371. PDRIVE_LOCKLIST lockListEntry,
  372. previousLockListEntry;
  373. TCHAR name[4];
  374. if (Disk != GetDiskCount()) {
  375. return 0;
  376. }
  377. lockListEntry = DriveLockListHead;
  378. if (FreeList) {
  379. DriveLockListHead = NULL;
  380. }
  381. while (lockListEntry) {
  382. // Unlock the disk.
  383. if (lockListEntry->CurrentlyLocked) {
  384. if (FreeList && lockListEntry->RemoveOnUnlock) {
  385. // set up the new dos name and NT path.
  386. name[0] = (TCHAR)lockListEntry->DriveLetter;
  387. name[1] = (TCHAR)':';
  388. name[2] = 0;
  389. NetworkRemoveShare((LPCTSTR) name);
  390. if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) name, (LPCTSTR) NULL)) {
  391. // could not remove name!!?
  392. }
  393. }
  394. LowUnlockDrive(lockListEntry->LockHandle);
  395. LowCloseDisk(lockListEntry->LockHandle);
  396. }
  397. // Move to the next entry. If requested free this entry.
  398. previousLockListEntry = lockListEntry;
  399. lockListEntry = lockListEntry->Next;
  400. if (FreeList) {
  401. Free(previousLockListEntry);
  402. }
  403. }
  404. return 0;
  405. }
  406. LETTER_ASSIGNMENT_RESULT
  407. CommitDriveLetter(
  408. IN PREGION_DESCRIPTOR RegionDescriptor,
  409. IN CHAR OldDrive,
  410. IN CHAR NewDrive
  411. )
  412. /*++
  413. Routine Description:
  414. This routine will update the drive letter information in the registry and
  415. (if the update works) it will attempt to move the current drive letter
  416. to the new one via DefineDosDevice()
  417. Arguments:
  418. RegionDescriptor - the region that should get the letter.
  419. NewDrive - the new drive letter for the volume.
  420. Return Value:
  421. 0 - the assignment failed.
  422. 1 - if the assigning of the letter occurred interactively.
  423. 2 - must reboot to do the letter.
  424. --*/
  425. {
  426. PPERSISTENT_REGION_DATA regionData;
  427. PDRIVE_LOCKLIST lockListEntry;
  428. PASSIGN_LIST assignList;
  429. HANDLE handle;
  430. TCHAR newName[4];
  431. WCHAR targetPath[100];
  432. int doIt;
  433. STATUS_CODE status = ERROR_SEVERITY_ERROR;
  434. LETTER_ASSIGNMENT_RESULT result = Failure;
  435. regionData = PERSISTENT_DATA(RegionDescriptor);
  436. // check the assign letter list for a match.
  437. // If the letter is there, then just update the list
  438. // otherwise continue on with the action.
  439. assignList = AssignDriveLetterListHead;
  440. while (assignList) {
  441. if (assignList->DriveLetter == (UCHAR)OldDrive) {
  442. assignList->DriveLetter = (UCHAR)NewDrive;
  443. return Complete;
  444. }
  445. assignList = assignList->Next;
  446. }
  447. // Search to see if the drive is currently locked.
  448. for (lockListEntry = DriveLockListHead;
  449. lockListEntry;
  450. lockListEntry = lockListEntry->Next) {
  451. if ((lockListEntry->DiskNumber == RegionDescriptor->Disk) &&
  452. (lockListEntry->PartitionNumber == RegionDescriptor->PartitionNumber)) {
  453. if (lockListEntry->CurrentlyLocked) {
  454. status = 0;
  455. }
  456. // found the match no need to continue searching.
  457. break;
  458. }
  459. }
  460. if (!NT_SUCCESS(status)) {
  461. // See if the drive can be locked.
  462. status = LowOpenPartition(GetDiskName(RegionDescriptor->Disk),
  463. RegionDescriptor->PartitionNumber,
  464. &handle);
  465. if (!NT_SUCCESS(status)) {
  466. return Failure;
  467. }
  468. // Lock the drive to insure that no other access is occurring
  469. // to the volume.
  470. status = LowLockDrive(handle);
  471. if (!NT_SUCCESS(status)) {
  472. if (IsPagefileOnDrive(OldDrive)) {
  473. ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE);
  474. } else {
  475. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
  476. }
  477. doIt = ConfirmationDialog(MSG_SCHEDULE_REBOOT, MB_ICONQUESTION | MB_YESNO);
  478. LowCloseDisk(handle);
  479. if (doIt == IDYES) {
  480. RegistryChanged = TRUE;
  481. RestartRequired = TRUE;
  482. return MustReboot;
  483. }
  484. return Failure;
  485. }
  486. } else {
  487. // This drive was found in the lock list and is already
  488. // in the locked state. It is safe to continue with
  489. // the drive letter assignment.
  490. }
  491. doIt = ConfirmationDialog(MSG_DRIVE_RENAME_WARNING, MB_ICONQUESTION | MB_YESNOCANCEL);
  492. if (doIt != IDYES) {
  493. LowUnlockDrive(handle);
  494. LowCloseDisk(handle);
  495. return Failure;
  496. }
  497. // Update the registry first. This way if something goes wrong
  498. // the new letter will arrive on reboot.
  499. if (!DiskRegistryAssignDriveLetter(Disks[RegionDescriptor->Disk]->Signature,
  500. FdGetExactOffset(RegionDescriptor),
  501. FdGetExactSize(RegionDescriptor, FALSE),
  502. (UCHAR)((NewDrive == NO_DRIVE_LETTER_EVER) ? (UCHAR)' ' : (UCHAR)NewDrive))) {
  503. // Registry update failed.
  504. return Failure;
  505. }
  506. // It is safe to change the drive letter. First, remove the
  507. // existing letter.
  508. newName[0] = (TCHAR)OldDrive;
  509. newName[1] = (TCHAR)':';
  510. newName[2] = 0;
  511. NetworkRemoveShare((LPCTSTR) newName);
  512. if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) newName, (LPCTSTR) NULL)) {
  513. LowUnlockDrive(handle);
  514. LowCloseDisk(handle);
  515. RegistryChanged = TRUE;
  516. return Failure;
  517. }
  518. if (NewDrive != NO_DRIVE_LETTER_EVER) {
  519. // set up the new dos name and NT path.
  520. newName[0] = (TCHAR)NewDrive;
  521. newName[1] = (TCHAR)':';
  522. newName[2] = 0;
  523. wsprintf((LPTSTR) targetPath,
  524. "%s\\Partition%d",
  525. GetDiskName(RegionDescriptor->Disk),
  526. RegionDescriptor->PartitionNumber);
  527. if (DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) newName, (LPCTSTR) targetPath)) {
  528. result = Complete;
  529. } else {
  530. RegistryChanged = TRUE;
  531. }
  532. NetworkShare((LPCTSTR) newName);
  533. } else {
  534. result = Complete;
  535. }
  536. // Force the file system to dismount
  537. LowUnlockDrive(handle);
  538. LowCloseDisk(handle);
  539. return result;
  540. }
  541. VOID
  542. CommitUpdateRegionStructures(
  543. VOID
  544. )
  545. /*++
  546. Routine Description:
  547. This routine is called ONLY after a successful commit of a new partitioning
  548. scheme for the system. Its is responsible for walking through the
  549. region arrays for each of the disks and updating the regions to indicate
  550. their transition from being "desired" to being actually committed
  551. to disk
  552. Arguments:
  553. None
  554. Return Values:
  555. None
  556. --*/
  557. {
  558. PDISKSTATE diskState;
  559. PREGION_DESCRIPTOR regionDescriptor;
  560. PPERSISTENT_REGION_DATA regionData;
  561. ULONG regionNumber,
  562. diskNumber;
  563. // search through all disks in the system.
  564. for (diskNumber = 0, diskState = Disks[0]; diskNumber < DiskCount; diskState = Disks[++diskNumber]) {
  565. // Look at every region array entry and update the values
  566. // to indicate that this region now exists.
  567. for (regionNumber = 0; regionNumber < diskState->RegionCount; regionNumber++) {
  568. regionDescriptor = &diskState->RegionArray[regionNumber];
  569. if (regionDescriptor->Reserved) {
  570. if (regionDescriptor->Reserved->Partition) {
  571. regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded = FALSE;
  572. }
  573. }
  574. regionData = PERSISTENT_DATA(regionDescriptor);
  575. if ((regionData) && (!regionData->VolumeExists)) {
  576. // By definition and assumption of this routine,
  577. // this region has just been committed to disk.
  578. regionData->VolumeExists = TRUE;
  579. if (regionData->TypeName) {
  580. Free(regionData->TypeName);
  581. }
  582. regionData->TypeName = Malloc((lstrlenW(wszUnformatted)+1)*sizeof(WCHAR));
  583. lstrcpyW(regionData->TypeName, wszUnformatted);
  584. }
  585. }
  586. }
  587. }
  588. VOID
  589. CommitAllChanges(
  590. IN PVOID Param
  591. )
  592. /*++
  593. Routine Description:
  594. This routine will go through all of the region descriptors and commit
  595. any changes that have occurred to disk. Then it "re-initializes"
  596. Disk Administrator and start the display/work process over again.
  597. Arguments:
  598. Param - undefined for now
  599. Return Value:
  600. None
  601. --*/
  602. {
  603. DWORD action,
  604. errorCode;
  605. ULONG diskCount,
  606. temp;
  607. BOOL profileWritten,
  608. changesMade,
  609. mustReboot,
  610. configureFt;
  611. SetCursor(hcurWait);
  612. diskCount = GetDiskCount();
  613. // Determine whether any disks have been changed, and whether
  614. // the system must be rebooted. The system must be rebooted
  615. // if the registry has changed, if any non-removable disk has
  616. // changed, or if any removable disk that was not originally
  617. // unpartitioned has changed.
  618. changesMade = configureFt = FALSE;
  619. mustReboot = RestartRequired;
  620. for (temp=0; temp<diskCount; temp++) {
  621. if (HavePartitionsBeenChanged(temp)) {
  622. changesMade = TRUE;
  623. break;
  624. }
  625. }
  626. profileWritten = FALSE;
  627. // Determine if the commit can be done without a reboot.
  628. // If FT is in the system then it must be notified to
  629. // reconfigure if a reboot is not performed. If it is
  630. // not in the system, but the new disk information requires
  631. // it, then a reboot must be forced.
  632. if (FtInstalled()) {
  633. configureFt = TRUE;
  634. }
  635. if (NewConfigurationRequiresFt()) {
  636. if (!configureFt) {
  637. // The FT driver is not loaded currently.
  638. mustReboot = TRUE;
  639. } else {
  640. // If the system is going to be rebooted, don't
  641. // have FT reconfigure prior to shutdown.
  642. if (mustReboot) {
  643. configureFt = FALSE;
  644. }
  645. }
  646. }
  647. if (RegistryChanged | changesMade | RestartRequired) {
  648. if (RestartRequired) {
  649. action = IDYES;
  650. } else {
  651. action = ConfirmationDialog(MSG_CONFIRM_EXIT, MB_ICONQUESTION | MB_YESNOCANCEL);
  652. }
  653. if (action == IDYES) {
  654. errorCode = CommitLockVolumes(0);
  655. if (errorCode) {
  656. // could not lock all volumes
  657. SetCursor(hcurNormal);
  658. ErrorDialog(MSG_CANNOT_LOCK_FOR_COMMIT);
  659. CommitUnlockVolumes(diskCount, FALSE);
  660. return;
  661. }
  662. if (mustReboot) {
  663. SetCursor(hcurNormal);
  664. if (RestartRequired) {
  665. action = IDYES;
  666. } else {
  667. action = ConfirmationDialog(MSG_REQUIRE_REBOOT, MB_ICONQUESTION | MB_YESNO);
  668. }
  669. if (action != IDYES) {
  670. CommitUnlockVolumes(diskCount, FALSE);
  671. return;
  672. }
  673. }
  674. SetCursor(hcurWait);
  675. errorCode = CommitChanges();
  676. CommitUnlockVolumes(diskCount, TRUE);
  677. SetCursor(hcurNormal);
  678. if (errorCode != NO_ERROR) {
  679. ErrorDialog(MSG_BAD_CONFIG_SET);
  680. PostQuitMessage(0);
  681. } else {
  682. ULONG OldBootPartitionNumber,
  683. NewBootPartitionNumber;
  684. CHAR OldNumberString[8],
  685. NewNumberString[8];
  686. DWORD MsgCode;
  687. // Update the configuration registry
  688. errorCode = SaveFt();
  689. // Check if FTDISK drive should reconfigure.
  690. if (configureFt) {
  691. // Issue device control to ftdisk driver to reconfigure.
  692. FtConfigure();
  693. }
  694. // Register autochk to fix up file systems
  695. // in newly extended volume sets, if necessary
  696. if (RegisterFileSystemExtend()) {
  697. mustReboot = TRUE;
  698. }
  699. // Determine if the FT driver must be enabled.
  700. if (DiskRegistryRequiresFt() == TRUE) {
  701. if (!FtInstalled()) {
  702. mustReboot = TRUE;
  703. }
  704. DiskRegistryEnableFt();
  705. } else {
  706. DiskRegistryDisableFt();
  707. }
  708. if (errorCode == NO_ERROR) {
  709. InfoDialog(MSG_OK_COMMIT);
  710. } else {
  711. ErrorDialog(MSG_BAD_CONFIG_SET);
  712. }
  713. // Has the partition number of the boot
  714. // partition changed?
  715. if (BootPartitionNumberChanged( &OldBootPartitionNumber,&NewBootPartitionNumber)) {
  716. #if i386
  717. MsgCode = MSG_BOOT_PARTITION_CHANGED_X86;
  718. #else
  719. MsgCode = MSG_BOOT_PARTITION_CHANGED_ARC;
  720. #endif
  721. sprintf(OldNumberString, "%d", OldBootPartitionNumber);
  722. sprintf(NewNumberString, "%d", NewBootPartitionNumber);
  723. InfoDialog(MsgCode, OldNumberString, NewNumberString);
  724. }
  725. ClearCommittedDiskInformation();
  726. if (UpdateMbrOnDisk) {
  727. UpdateMasterBootCode(UpdateMbrOnDisk);
  728. UpdateMbrOnDisk = 0;
  729. }
  730. // Reboot if necessary.
  731. if (mustReboot) {
  732. SetCursor(hcurWait);
  733. Sleep(5000);
  734. SetCursor(hcurNormal);
  735. FdShutdownTheSystem();
  736. profileWritten = TRUE;
  737. }
  738. CommitAssignLetterList();
  739. CommitUpdateRegionStructures();
  740. RegistryChanged = FALSE;
  741. CommitDueToDelete = CommitDueToMirror = FALSE;
  742. TotalRedrawAndRepaint();
  743. AdjustMenuAndStatus();
  744. }
  745. } else if (action == IDCANCEL) {
  746. return; // don't exit
  747. } else {
  748. FDASSERT(action == IDNO);
  749. }
  750. }
  751. }
  752. VOID
  753. FtConfigure(
  754. VOID
  755. )
  756. /*++
  757. Routine Description:
  758. This routine calls the FTDISK driver to ask it to reconfigure as changes
  759. have been made in the registry.
  760. Arguments:
  761. None
  762. Return Value:
  763. None
  764. --*/
  765. {
  766. OBJECT_ATTRIBUTES objectAttributes;
  767. STRING ntFtName;
  768. IO_STATUS_BLOCK statusBlock;
  769. UNICODE_STRING unicodeDeviceName;
  770. NTSTATUS status;
  771. HANDLE handle;
  772. // Open ft control object.
  773. RtlInitString(&ntFtName,
  774. "\\Device\\FtControl");
  775. RtlAnsiStringToUnicodeString(&unicodeDeviceName,
  776. &ntFtName,
  777. TRUE);
  778. InitializeObjectAttributes(&objectAttributes,
  779. &unicodeDeviceName,
  780. OBJ_CASE_INSENSITIVE,
  781. NULL,
  782. NULL);
  783. status = DmOpenFile(&handle,
  784. SYNCHRONIZE | FILE_ANY_ACCESS,
  785. &objectAttributes,
  786. &statusBlock,
  787. FILE_SHARE_READ | FILE_SHARE_WRITE,
  788. FILE_SYNCHRONOUS_IO_ALERT );
  789. RtlFreeUnicodeString(&unicodeDeviceName);
  790. if (!NT_SUCCESS(status)) {
  791. return;
  792. }
  793. // Issue device control to reconfigure FT.
  794. NtDeviceIoControlFile(handle,
  795. NULL,
  796. NULL,
  797. NULL,
  798. &statusBlock,
  799. FT_CONFIGURE,
  800. NULL,
  801. 0L,
  802. NULL,
  803. 0L);
  804. DmClose(handle);
  805. return;
  806. }
  807. BOOL
  808. CommitAllowed(
  809. VOID
  810. )
  811. /*++
  812. Routine Description:
  813. Determine if it is ok to perform a commit.
  814. Arguments:
  815. None
  816. Return Value:
  817. TRUE if it is ok to commit and there is something to commit
  818. FALSE otherwise
  819. --*/
  820. {
  821. if (DriveLockListHead ||
  822. AssignDriveLetterListHead ||
  823. CommitDueToDelete ||
  824. CommitDueToMirror ||
  825. CommitDueToExtended) {
  826. return TRUE;
  827. }
  828. return FALSE;
  829. }
  830. VOID
  831. RescanDevices(
  832. VOID
  833. )
  834. /*++
  835. Routine Description:
  836. This routine performs all actions necessary to dynamically rescan
  837. device buses (i.e. SCSI) and get the appropriate driver support loaded.
  838. Arguments:
  839. None
  840. Return Value:
  841. None
  842. --*/
  843. {
  844. PSCSI_ADAPTER_BUS_INFO adapterInfo;
  845. PSCSI_BUS_DATA busData;
  846. PSCSI_INQUIRY_DATA inquiryData;
  847. TCHAR physicalName[32];
  848. TCHAR driveName[32];
  849. BYTE driveBuffer[32];
  850. BYTE physicalBuffer[32];
  851. HANDLE volumeHandle;
  852. STRING string;
  853. UNICODE_STRING unicodeString;
  854. UNICODE_STRING physicalString;
  855. OBJECT_ATTRIBUTES objectAttributes;
  856. NTSTATUS ntStatus;
  857. IO_STATUS_BLOCK statusBlock;
  858. BOOLEAN diskFound,
  859. cdromFound;
  860. ULONG bytesTransferred,
  861. i,
  862. j,
  863. deviceNumber,
  864. currentPort,
  865. numberOfPorts,
  866. percentComplete,
  867. portNumber;
  868. diskFound = FALSE;
  869. cdromFound = FALSE;
  870. // Determine how many buses there are
  871. portNumber = numberOfPorts = percentComplete = 0;
  872. while (TRUE) {
  873. memset(driveBuffer, 0, sizeof(driveBuffer));
  874. sprintf(driveBuffer, "\\\\.\\Scsi%d:", portNumber);
  875. // Open the SCSI port with the DOS name.
  876. volumeHandle = CreateFile(driveBuffer,
  877. GENERIC_READ,
  878. FILE_SHARE_READ | FILE_SHARE_WRITE,
  879. NULL,
  880. OPEN_EXISTING,
  881. 0,
  882. 0);
  883. if (volumeHandle == INVALID_HANDLE_VALUE) {
  884. break;
  885. }
  886. CloseHandle(volumeHandle);
  887. numberOfPorts++;
  888. portNumber++;
  889. }
  890. currentPort = 1;
  891. portNumber = 0;
  892. // Perform the scsi bus rescan.
  893. while (TRUE) {
  894. memset(driveBuffer, 0, sizeof(driveBuffer));
  895. sprintf(driveBuffer, "\\\\.\\Scsi%d:", portNumber);
  896. // Open the SCSI port with the DOS name.
  897. volumeHandle = CreateFile(driveBuffer,
  898. GENERIC_READ,
  899. FILE_SHARE_READ | FILE_SHARE_WRITE,
  900. NULL,
  901. OPEN_EXISTING,
  902. 0,
  903. 0);
  904. if (volumeHandle == INVALID_HANDLE_VALUE) {
  905. break;
  906. }
  907. // Issue rescan device control.
  908. if (!DeviceIoControl(volumeHandle,
  909. IOCTL_SCSI_RESCAN_BUS,
  910. NULL,
  911. 0,
  912. NULL,
  913. 0,
  914. &bytesTransferred,
  915. NULL)) {
  916. CloseHandle(volumeHandle);
  917. break;
  918. }
  919. percentComplete = (currentPort * 100) / numberOfPorts;
  920. if (percentComplete < 100) {
  921. PostMessage(InitDlg,
  922. WM_USER,
  923. percentComplete,
  924. 0);
  925. }
  926. currentPort++;
  927. // Get a big chuck of memory to store the SCSI bus data.
  928. adapterInfo = malloc(0x4000);
  929. if (adapterInfo == NULL) {
  930. CloseHandle(volumeHandle);
  931. goto finish;
  932. }
  933. // Issue device control to get configuration information.
  934. if (!DeviceIoControl(volumeHandle,
  935. IOCTL_SCSI_GET_INQUIRY_DATA,
  936. NULL,
  937. 0,
  938. adapterInfo,
  939. 0x4000,
  940. &bytesTransferred,
  941. NULL)) {
  942. CloseHandle(volumeHandle);
  943. goto finish;
  944. }
  945. for (i = 0; i < adapterInfo->NumberOfBuses; i++) {
  946. busData = &adapterInfo->BusData[i];
  947. inquiryData =
  948. (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + busData->InquiryDataOffset);
  949. for (j = 0; j < busData->NumberOfLogicalUnits; j++) {
  950. // Check if device is claimed.
  951. if (!inquiryData->DeviceClaimed) {
  952. // Determine the perpherial type.
  953. switch (inquiryData->InquiryData[0] & 0x1f) {
  954. case DIRECT_ACCESS_DEVICE:
  955. diskFound = TRUE;
  956. break;
  957. case READ_ONLY_DIRECT_ACCESS_DEVICE:
  958. cdromFound = TRUE;
  959. break;
  960. case OPTICAL_DEVICE:
  961. diskFound = TRUE;
  962. break;
  963. }
  964. }
  965. // Get next device data.
  966. inquiryData =
  967. (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + inquiryData->NextInquiryDataOffset);
  968. }
  969. }
  970. free(adapterInfo);
  971. CloseHandle(volumeHandle);
  972. portNumber++;
  973. }
  974. if (diskFound) {
  975. // Send IOCTL_DISK_FIND_NEW_DEVICES commands to each existing disk.
  976. deviceNumber = 0;
  977. while (TRUE) {
  978. memset(driveBuffer, 0, sizeof(driveBuffer));
  979. sprintf(driveBuffer, "\\Device\\Harddisk%d\\Partition0", deviceNumber);
  980. RtlInitString(&string, driveBuffer);
  981. ntStatus = RtlAnsiStringToUnicodeString(&unicodeString,
  982. &string,
  983. TRUE);
  984. if (!NT_SUCCESS(ntStatus)) {
  985. break;
  986. }
  987. InitializeObjectAttributes(&objectAttributes,
  988. &unicodeString,
  989. 0,
  990. NULL,
  991. NULL);
  992. ntStatus = DmOpenFile(&volumeHandle,
  993. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
  994. &objectAttributes,
  995. &statusBlock,
  996. FILE_SHARE_READ | FILE_SHARE_WRITE,
  997. FILE_SYNCHRONOUS_IO_ALERT);
  998. if (!NT_SUCCESS(ntStatus)) {
  999. RtlFreeUnicodeString(&unicodeString);
  1000. break;
  1001. }
  1002. // Issue find device device control.
  1003. if (!DeviceIoControl(volumeHandle,
  1004. IOCTL_DISK_FIND_NEW_DEVICES,
  1005. NULL,
  1006. 0,
  1007. NULL,
  1008. 0,
  1009. &bytesTransferred,
  1010. NULL)) {
  1011. }
  1012. DmClose(volumeHandle);
  1013. // see if the physicaldrive# symbolic link is present
  1014. sprintf(physicalBuffer, "\\DosDevices\\PhysicalDrive%d", deviceNumber);
  1015. deviceNumber++;
  1016. RtlInitString(&string, physicalBuffer);
  1017. ntStatus = RtlAnsiStringToUnicodeString(&physicalString,
  1018. &string,
  1019. TRUE);
  1020. if (!NT_SUCCESS(ntStatus)) {
  1021. continue;
  1022. }
  1023. InitializeObjectAttributes(&objectAttributes,
  1024. &physicalString,
  1025. 0,
  1026. NULL,
  1027. NULL);
  1028. ntStatus = DmOpenFile(&volumeHandle,
  1029. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
  1030. &objectAttributes,
  1031. &statusBlock,
  1032. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1033. FILE_SYNCHRONOUS_IO_ALERT);
  1034. if (!NT_SUCCESS(ntStatus)) {
  1035. ULONG index;
  1036. ULONG dest;
  1037. // Name is not there - create it. This copying
  1038. // is done in case this code should ever become
  1039. // unicode and the types for the two strings would
  1040. // actually be different.
  1041. //
  1042. // Copy only the portion of the physical name
  1043. // that is in the \dosdevices\ directory
  1044. for (dest = 0, index = 12; TRUE; index++, dest++) {
  1045. physicalName[dest] = (TCHAR)physicalBuffer[index];
  1046. if (!physicalName[dest]) {
  1047. break;
  1048. }
  1049. }
  1050. // Copy all of the NT namespace name.
  1051. for (index = 0; TRUE; index++) {
  1052. driveName[index] = (TCHAR) driveBuffer[index];
  1053. if (!driveName[index]) {
  1054. break;
  1055. }
  1056. }
  1057. DefineDosDevice(DDD_RAW_TARGET_PATH,
  1058. (LPCTSTR) physicalName,
  1059. (LPCTSTR) driveName);
  1060. } else {
  1061. DmClose(volumeHandle);
  1062. }
  1063. // free allocated memory for unicode string.
  1064. RtlFreeUnicodeString(&unicodeString);
  1065. RtlFreeUnicodeString(&physicalString);
  1066. }
  1067. }
  1068. if (cdromFound) {
  1069. // Send IOCTL_CDROM_FIND_NEW_DEVICES commands to each existing cdrom.
  1070. deviceNumber = 0;
  1071. while (TRUE) {
  1072. memset(driveBuffer, 0, sizeof(driveBuffer));
  1073. sprintf(driveBuffer, "\\Device\\Cdrom%d", deviceNumber);
  1074. RtlInitString(&string, driveBuffer);
  1075. ntStatus = RtlAnsiStringToUnicodeString(&unicodeString,
  1076. &string,
  1077. TRUE);
  1078. if (!NT_SUCCESS(ntStatus)) {
  1079. break;
  1080. }
  1081. InitializeObjectAttributes(&objectAttributes,
  1082. &unicodeString,
  1083. 0,
  1084. NULL,
  1085. NULL);
  1086. ntStatus = DmOpenFile(&volumeHandle,
  1087. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
  1088. &objectAttributes,
  1089. &statusBlock,
  1090. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1091. FILE_SYNCHRONOUS_IO_ALERT);
  1092. if (!NT_SUCCESS(ntStatus)) {
  1093. break;
  1094. }
  1095. // Issue find device device control.
  1096. if (!DeviceIoControl(volumeHandle,
  1097. IOCTL_CDROM_FIND_NEW_DEVICES,
  1098. NULL,
  1099. 0,
  1100. NULL,
  1101. 0,
  1102. &bytesTransferred,
  1103. NULL)) {
  1104. }
  1105. CloseHandle(volumeHandle);
  1106. deviceNumber++;
  1107. }
  1108. }
  1109. finish:
  1110. PostMessage(InitDlg,
  1111. WM_USER,
  1112. 100,
  1113. 0);
  1114. return;
  1115. }