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.

1053 lines
32 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. rcpatch.cpp
  5. Abstract:
  6. Patches cmdcons\bootsect.dat to the current
  7. active system partition boot sector.
  8. NOTE : This is needed if someone wants to
  9. sysprep the recovery console also as part
  10. of the reference machine and then apply the
  11. images to different target machines.
  12. This utility needs to be executed in
  13. mini-setup using the sysprep infrastructure.
  14. Also allows you to patch the MBR boot code
  15. Author:
  16. Vijay Jayaseelan (vijayj) 02-Nov-2000
  17. Revision History:
  18. None
  19. --*/
  20. #include <nt.h>
  21. #include <ntrtl.h>
  22. #include <nturtl.h>
  23. #include <bootmbr.h>
  24. #include <iostream>
  25. #include <string>
  26. #include <exception>
  27. #include <windows.h>
  28. #include <tchar.h>
  29. #include <locale>
  30. #include "msg.h"
  31. #include <libmsg.h>
  32. //
  33. // Global variables used to get formatted message for this program.
  34. //
  35. HMODULE ThisModule = NULL;
  36. WCHAR Message[4096];
  37. //
  38. // Helper dump operators
  39. //
  40. std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
  41. FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
  42. fputws((PWSTR)str.c_str(), OutStream);
  43. return os;
  44. }
  45. //
  46. // Helper dump operators
  47. //
  48. std::ostream& operator<<(std::ostream &os, WCHAR *Str) {
  49. std::wstring WStr = Str;
  50. os << WStr;
  51. return os;
  52. }
  53. //
  54. // Exceptions
  55. //
  56. struct ProgramException : public std::exception {
  57. virtual void Dump(std::ostream &os) = 0;
  58. };
  59. //
  60. // Abstracts a Win32 error
  61. //
  62. struct W32Error : public ProgramException {
  63. DWORD ErrorCode;
  64. W32Error(DWORD ErrCode = GetLastError()) : ErrorCode(ErrCode){}
  65. void Dump(std::ostream &os) {
  66. WCHAR MsgBuffer[4096];
  67. MsgBuffer[0] = UNICODE_NULL;
  68. if (GetFormattedMessage(ThisModule,
  69. TRUE,
  70. MsgBuffer,
  71. sizeof(MsgBuffer)/sizeof(MsgBuffer[0]),
  72. ErrorCode)){
  73. std::wstring Msg(MsgBuffer);
  74. os << Msg;
  75. } else {
  76. os << std::hex << ErrorCode;
  77. }
  78. }
  79. };
  80. //
  81. // Invalid arguments
  82. //
  83. struct InvalidArguments : public ProgramException {
  84. const char *what() const throw() {
  85. return "Invalid Arguments";
  86. }
  87. void Dump(std::ostream &os) {
  88. os << what() << std::endl;
  89. }
  90. };
  91. //
  92. // Invalid arguments
  93. //
  94. struct ProgramUsage : public ProgramException {
  95. std::wstring PrgUsage;
  96. ProgramUsage(){}
  97. const char *what() const throw() {
  98. return "Program Usage exception";
  99. }
  100. void Dump(std::ostream &os) {
  101. os << GetFormattedMessage( ThisModule,
  102. FALSE,
  103. Message,
  104. sizeof(Message)/sizeof(Message[0]),
  105. MSG_PGM_USAGE) << std::endl;
  106. }
  107. };
  108. //
  109. // Program Arguments abstraction
  110. //
  111. struct ProgramArguments {
  112. bool PatchMBR;
  113. bool BootCodePatch;
  114. ULONG DiskIndex;
  115. WCHAR DriveLetter;
  116. ProgramArguments(INT Argc, WCHAR *Argv[]) {
  117. PatchMBR = false;
  118. DiskIndex = 0;
  119. BootCodePatch = false;
  120. bool ShowUsage = false;
  121. for (ULONG Index=0; !ShowUsage && (Index < Argc); Index++) {
  122. if (!_wcsicmp(Argv[Index], L"/fixmbr")) {
  123. Index++;
  124. if ((Index < Argc) && Argv[Index]) {
  125. ULONG CharIndex;
  126. for (CharIndex=0;
  127. Argv[Index] && iswdigit(Argv[Index][CharIndex]);
  128. CharIndex++){
  129. // do nothing currently
  130. }
  131. if (CharIndex && !Argv[Index][CharIndex]) {
  132. PWSTR EndPtr = NULL;
  133. PatchMBR = true;
  134. DiskIndex = wcstoul(Argv[Index], &EndPtr, 10);
  135. }
  136. }
  137. ShowUsage = !PatchMBR;
  138. } else if (!_wcsicmp(Argv[Index], L"/?") ||
  139. !_wcsicmp(Argv[Index], L"-?") ||
  140. !_wcsicmp(Argv[Index], L"?") ||
  141. !_wcsicmp(Argv[Index], L"/h") ||
  142. !_wcsicmp(Argv[Index], L"-h")) {
  143. ShowUsage = true;
  144. } else if (!_wcsicmp(Argv[Index], L"/syspart")){
  145. Index++;
  146. if ((Index < Argc) && Argv[Index]) {
  147. //
  148. // Check validity of the character that follows the
  149. // "/syspart" option.
  150. //
  151. if (iswalpha(Argv[Index][0])){
  152. BootCodePatch = true;
  153. DriveLetter = Argv[Index][0];
  154. }
  155. }
  156. }
  157. }
  158. if (ShowUsage) {
  159. throw new ProgramUsage();
  160. }
  161. }
  162. };
  163. //
  164. // Dumps the given binary data of the specified size
  165. // into the output stream with required indent size
  166. //
  167. void
  168. DumpBinary(unsigned char *Data, int Size,
  169. std::ostream& os, int Indent = 16)
  170. {
  171. if (Data && Size) {
  172. int Index = 0;
  173. int foo;
  174. char szBuff[128] = {'.'};
  175. int Ruler = 0;
  176. while (Index < Size) {
  177. if (!(Index % Indent)) {
  178. if (Index) {
  179. szBuff[Indent] = 0;
  180. os << szBuff;
  181. }
  182. os << std::endl;
  183. os.width(8);
  184. os.fill('0');
  185. os << Ruler << " ";
  186. Ruler += Indent;
  187. }
  188. foo = *(Data + Index);
  189. szBuff[Index % Indent] = ::isalnum(foo) ? (char)foo : (char)'.';
  190. os.width(2);
  191. os.fill('0');
  192. os.flags(std::ios::uppercase | std::ios::hex);
  193. os << foo << ' ';
  194. Index++;
  195. }
  196. while (Index % Indent) {
  197. os << ' ';
  198. Index++;
  199. szBuff[Index % Indent] = ' ';
  200. }
  201. szBuff[Indent] = 0;
  202. os << szBuff;
  203. } else {
  204. os << GetFormattedMessage( ThisModule,
  205. FALSE,
  206. Message,
  207. sizeof(Message)/sizeof(Message[0]),
  208. MSG_NO_DATA) << std::endl;
  209. }
  210. }
  211. //
  212. // File system types we care about
  213. //
  214. enum FsType {
  215. FileSystemFat,
  216. FileSystemFat32,
  217. FileSystemNtfs,
  218. FileSystemUnknown
  219. };
  220. //
  221. // Abstracts a disk (using Win32 APIs)
  222. //
  223. class W32Disk {
  224. public:
  225. W32Disk(ULONG Index) {
  226. swprintf(Name,
  227. L"\\\\.\\PHYSICALDRIVE%d",
  228. Index);
  229. DiskHandle = CreateFile(Name,
  230. GENERIC_READ | GENERIC_WRITE,
  231. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  232. NULL,
  233. OPEN_EXISTING,
  234. FILE_ATTRIBUTE_NORMAL,
  235. NULL);
  236. if ((DiskHandle == INVALID_HANDLE_VALUE) ||
  237. (DiskHandle == NULL)) {
  238. throw new W32Error(GetLastError());
  239. }
  240. }
  241. ~W32Disk() {
  242. CloseHandle(DiskHandle);
  243. }
  244. //
  245. // Reads the requested size of data from the given sector
  246. //
  247. DWORD ReadSectors(ULONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
  248. SetFilePointer(DiskHandle,
  249. Index * SectorSize,
  250. NULL,
  251. FILE_BEGIN);
  252. DWORD LastError = GetLastError();
  253. if (!LastError) {
  254. DWORD BytesRead = 0;
  255. if (!ReadFile(DiskHandle,
  256. DataBuffer,
  257. BufferSize,
  258. &BytesRead,
  259. NULL)) {
  260. LastError = GetLastError();
  261. }
  262. }
  263. return LastError;
  264. }
  265. //
  266. // Writes the requested size of data to the specified sector
  267. //
  268. DWORD WriteSectors(ULONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
  269. SetFilePointer(DiskHandle,
  270. Index * SectorSize,
  271. NULL,
  272. FILE_BEGIN);
  273. DWORD LastError = GetLastError();
  274. if (!LastError) {
  275. DWORD BytesWritten = 0;
  276. if (!WriteFile(DiskHandle,
  277. DataBuffer,
  278. BufferSize,
  279. &BytesWritten,
  280. NULL)) {
  281. LastError = GetLastError();
  282. }
  283. }
  284. return LastError;
  285. }
  286. protected:
  287. //
  288. // data members
  289. //
  290. WCHAR Name[MAX_PATH];
  291. HANDLE DiskHandle;
  292. const static ULONG SectorSize = 512;
  293. };
  294. //
  295. // Abstracts a Partition (using Win32 APIs)
  296. //
  297. class W32Partition {
  298. public:
  299. //
  300. // constructor(s)
  301. //
  302. W32Partition(const std::wstring &VolName) :
  303. SectorSize(512), FileSystemType(FileSystemUnknown) {
  304. if (VolName.length() == 1) {
  305. DriveName = TEXT("\\\\.\\");
  306. DriveName += VolName;
  307. DriveName += TEXT(":");
  308. } else {
  309. DriveName = TEXT("\\\\.\\") + VolName + TEXT("\\");
  310. }
  311. //
  312. // Open the partition
  313. //
  314. PartitionHandle = CreateFile(DriveName.c_str(),
  315. GENERIC_READ,
  316. FILE_SHARE_READ | FILE_SHARE_WRITE,
  317. NULL,
  318. OPEN_EXISTING,
  319. FILE_ATTRIBUTE_NORMAL,
  320. NULL);
  321. if (PartitionHandle != INVALID_HANDLE_VALUE) {
  322. DWORD NotUsed = 0;
  323. std::wstring RootPath = VolName;
  324. WCHAR FileSystemName[64] = {0};
  325. if (VolName.length() == 1) {
  326. RootPath += TEXT(":\\");
  327. } else {
  328. RootPath += TEXT("\\");
  329. }
  330. //
  331. // Get the file system information on the
  332. // partition
  333. //
  334. if (GetVolumeInformation(RootPath.c_str(),
  335. NULL,
  336. 0,
  337. &NotUsed,
  338. &NotUsed,
  339. &NotUsed,
  340. FileSystemName,
  341. sizeof(FileSystemName)/sizeof(FileSystemName[0]))) {
  342. std::wstring FsName = FileSystemName;
  343. if (FsName == TEXT("FAT")) {
  344. FileSystemType = FileSystemFat;
  345. } else if (FsName == TEXT("FAT32")) {
  346. FileSystemType = FileSystemFat32;
  347. } else if (FsName == TEXT("NTFS")) {
  348. FileSystemType = FileSystemNtfs;
  349. } else {
  350. FileSystemType = FileSystemUnknown;
  351. }
  352. switch (GetFileSystemType()) {
  353. case FileSystemFat:
  354. case FileSystemFat32:
  355. BootCodeSize = 1 * SectorSize;
  356. break;
  357. case FileSystemNtfs:
  358. BootCodeSize = 16 * SectorSize;
  359. break;
  360. default:
  361. break;
  362. }
  363. }
  364. }
  365. DWORD LastError = GetLastError();
  366. if (LastError) {
  367. CleanUp();
  368. throw new W32Error(LastError);
  369. }
  370. }
  371. //
  372. // destructor
  373. //
  374. virtual ~W32Partition() {
  375. CleanUp();
  376. }
  377. ULONG GetBootCodeSize() const {
  378. return BootCodeSize;
  379. }
  380. FsType GetFileSystemType() const {
  381. return FileSystemType;
  382. }
  383. //
  384. // Reads the requested size of data from the given sector
  385. //
  386. DWORD ReadSectors(ULONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
  387. SetFilePointer(PartitionHandle,
  388. Index * SectorSize,
  389. NULL,
  390. FILE_BEGIN);
  391. DWORD LastError = GetLastError();
  392. if (!LastError) {
  393. DWORD BytesRead = 0;
  394. if (!ReadFile(PartitionHandle,
  395. DataBuffer,
  396. BufferSize,
  397. &BytesRead,
  398. NULL)) {
  399. LastError = GetLastError();
  400. }
  401. }
  402. return LastError;
  403. }
  404. protected:
  405. void CleanUp() {
  406. if (PartitionHandle != INVALID_HANDLE_VALUE) {
  407. CloseHandle(PartitionHandle);
  408. PartitionHandle = INVALID_HANDLE_VALUE;
  409. }
  410. }
  411. //
  412. // Data members
  413. //
  414. std::wstring DriveName;
  415. HANDLE PartitionHandle;
  416. const ULONG SectorSize;
  417. FsType FileSystemType;
  418. ULONG BootCodeSize;
  419. };
  420. DWORD
  421. GetSystemPartitionName(
  422. IN OUT PWSTR NameBuffer
  423. )
  424. /*++
  425. Routine Description:
  426. Retrieves the system partition name from the registry
  427. Arguments:
  428. NameBuffer - Buffer to hold the system partition name. Should
  429. be of minimum MAX_PATH size
  430. Return value:
  431. 0 if successful otherwise appropriate Win32 error code
  432. --*/
  433. {
  434. DWORD ErrorCode = ERROR_BAD_ARGUMENTS;
  435. if (NameBuffer) {
  436. HKEY SetupKey = NULL;
  437. ErrorCode = RegOpenKey(HKEY_LOCAL_MACHINE,
  438. TEXT("System\\Setup"),
  439. &SetupKey);
  440. if (!ErrorCode && SetupKey) {
  441. DWORD Type = REG_SZ;
  442. DWORD BufferSize = MAX_PATH * sizeof(TCHAR);
  443. ErrorCode = RegQueryValueEx(SetupKey,
  444. TEXT("SystemPartition"),
  445. NULL,
  446. &Type,
  447. (PBYTE)NameBuffer,
  448. &BufferSize);
  449. RegCloseKey(SetupKey);
  450. }
  451. }
  452. return ErrorCode;
  453. }
  454. DWORD
  455. GetSystemPartitionDriveLetter(
  456. WCHAR &SysPart
  457. )
  458. /*++
  459. Routine Description:
  460. Gets the system partition drive letter (like C / D etc.)
  461. NOTE : The logic is
  462. 1. Find the system partition volume name by looking
  463. at HKLM\System\Setup\SystemPartition value.
  464. 2. Iterate through \DosDevices namespace, finding
  465. target name string for all drive letters. If
  466. there is match then we found the system drive
  467. letter
  468. Arguments:
  469. SysPart - Place holder for system partition drive letter
  470. Return value:
  471. 0 if successful otherwise appropriate Win32 error code
  472. --*/
  473. {
  474. WCHAR SystemPartitionName[MAX_PATH] = {0};
  475. DWORD Result = ERROR_BAD_ARGUMENTS;
  476. WCHAR SysPartName = 0;
  477. Result = GetSystemPartitionName(SystemPartitionName);
  478. if (!Result) {
  479. NTSTATUS Status;
  480. UNICODE_STRING UnicodeString;
  481. OBJECT_ATTRIBUTES Attributes;
  482. OSVERSIONINFO VersionInfo = {0};
  483. PWSTR W2KDir = TEXT("\\??");
  484. PWSTR WhistlerDir = TEXT("\\global??");
  485. PWSTR DosDirName = W2KDir;
  486. //
  487. // NOTE : On whistler \\?? directory does not not have all
  488. // the needed partition drive letters. They are present
  489. // under \\global?? directory
  490. //
  491. VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  492. if (GetVersionEx(&VersionInfo) && (VersionInfo.dwMajorVersion == 5)
  493. && (VersionInfo.dwMinorVersion == 1)) {
  494. DosDirName = WhistlerDir;
  495. }
  496. std::wstring DirName = DosDirName;
  497. UnicodeString.Buffer = (PWSTR)DirName.c_str();
  498. UnicodeString.Length = lstrlenW(UnicodeString.Buffer)*sizeof(WCHAR);
  499. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  500. InitializeObjectAttributes( &Attributes,
  501. &UnicodeString,
  502. OBJ_CASE_INSENSITIVE,
  503. NULL,
  504. NULL
  505. );
  506. HANDLE DirectoryHandle = NULL;
  507. ULONG BufferSize = 512 * 1024;
  508. PBYTE Buffer = new BYTE[BufferSize];
  509. PBYTE EndOfBuffer = Buffer + BufferSize;
  510. ULONG Context = 0;
  511. ULONG ReturnedLength = 0;
  512. bool Found = false;
  513. POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
  514. if ( Buffer ) {
  515. RtlZeroMemory(Buffer, BufferSize);
  516. Status = NtOpenDirectoryObject( &DirectoryHandle,
  517. DIRECTORY_QUERY,
  518. &Attributes);
  519. if (NT_SUCCESS(Status)) {
  520. Status = NtQueryDirectoryObject(DirectoryHandle,
  521. Buffer,
  522. BufferSize,
  523. FALSE,
  524. TRUE,
  525. &Context,
  526. &ReturnedLength);
  527. }
  528. while (NT_SUCCESS( Status ) && !Found) {
  529. //
  530. // Check the status of the operation.
  531. //
  532. if (!NT_SUCCESS( Status ) && (Status != STATUS_NO_MORE_ENTRIES)) {
  533. break;
  534. }
  535. while (!Found && (((PBYTE)DirInfo) < EndOfBuffer)) {
  536. WCHAR ObjName[4096] = {0};
  537. //
  538. // Check if there is another record. If there isn't, then get out
  539. // of the loop now
  540. //
  541. if (!DirInfo->Name.Buffer || !DirInfo->Name.Length) {
  542. break;
  543. }
  544. //
  545. // Make sure that the Name is pointing within the buffer
  546. // supplied by us.
  547. //
  548. if ((DirInfo->Name.Buffer > (PVOID)Buffer) &&
  549. (DirInfo->Name.Buffer < (PVOID)EndOfBuffer)) {
  550. memmove(ObjName, DirInfo->Name.Buffer, DirInfo->Name.Length);
  551. ObjName[DirInfo->Name.Length/(sizeof(WCHAR))] = 0;
  552. if ((wcslen(ObjName) == 2) && (ObjName[1] == TEXT(':'))) {
  553. OBJECT_ATTRIBUTES ObjAttrs;
  554. UNICODE_STRING UnicodeStr;
  555. HANDLE ObjectHandle = NULL;
  556. WCHAR DriveLetter = ObjName[0];
  557. WCHAR FullObjName[4096] = {0};
  558. wcscpy(FullObjName, TEXT("\\DosDevices\\"));
  559. wcscat(FullObjName, ObjName);
  560. UnicodeStr.Buffer = FullObjName;
  561. UnicodeStr.Length = wcslen(FullObjName) * sizeof(WCHAR);
  562. UnicodeStr.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  563. InitializeObjectAttributes(
  564. &ObjAttrs,
  565. &UnicodeStr,
  566. OBJ_CASE_INSENSITIVE,
  567. NULL,
  568. NULL
  569. );
  570. Status = NtOpenSymbolicLinkObject(&ObjectHandle,
  571. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  572. &ObjAttrs
  573. );
  574. if(NT_SUCCESS(Status)) {
  575. //
  576. // Query the object to get the link target.
  577. //
  578. UnicodeString.Buffer = FullObjName;
  579. UnicodeString.Length = 0;
  580. UnicodeString.MaximumLength = sizeof(FullObjName)-sizeof(WCHAR);
  581. Status = NtQuerySymbolicLinkObject(ObjectHandle,
  582. &UnicodeString,
  583. NULL);
  584. CloseHandle(ObjectHandle);
  585. if (NT_SUCCESS(Status)) {
  586. FullObjName[UnicodeString.Length/sizeof(WCHAR)] = NULL;
  587. if (!_wcsicmp(FullObjName, SystemPartitionName)) {
  588. Found = true;
  589. SysPartName = DriveLetter;
  590. }
  591. }
  592. }
  593. }
  594. }
  595. //
  596. // There is another record so advance DirInfo to the next entry
  597. //
  598. DirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) DirInfo) +
  599. sizeof( OBJECT_DIRECTORY_INFORMATION ) );
  600. }
  601. RtlZeroMemory(Buffer, BufferSize);
  602. Status = NtQueryDirectoryObject( DirectoryHandle,
  603. Buffer,
  604. BufferSize,
  605. FALSE,
  606. FALSE,
  607. &Context,
  608. &ReturnedLength);
  609. }
  610. delete []Buffer;
  611. if (!Found) {
  612. Result = ERROR_FILE_NOT_FOUND;
  613. }
  614. }
  615. else { // if we can't allocate the Buffer
  616. Result = ERROR_OUTOFMEMORY;
  617. }
  618. if (!Result && !SysPartName) {
  619. Result = ERROR_FILE_NOT_FOUND;
  620. }
  621. }
  622. if (!Result) {
  623. SysPart = SysPartName;
  624. }
  625. return Result;
  626. }
  627. DWORD
  628. PatchBootSectorForRC(
  629. IN PBYTE BootSector,
  630. IN ULONG Size,
  631. IN FsType FileSystemType
  632. )
  633. /*++
  634. Routine Description:
  635. Patches the given boot sector for recovery console
  636. Arguments:
  637. BootSector : BootSector copy in memory
  638. Size : Size of the boot sector
  639. FsType : File system type on which the boot sector
  640. resides
  641. Return value:
  642. 0 if successful otherwise appropriate Win32 error code
  643. --*/
  644. {
  645. DWORD Result = ERROR_BAD_ARGUMENTS;
  646. BYTE NtfsNtldr[] = { 'N', 0, 'T', 0, 'L', 0, 'D', 0, 'R', 0 };
  647. BYTE NtfsCmldr[] = { 'C', 0, 'M', 0, 'L', 0, 'D', 0, 'R', 0 };
  648. BYTE FatNtldr[] = { 'N', 'T', 'L', 'D', 'R' };
  649. BYTE FatCmldr[] = { 'C', 'M', 'L', 'D', 'R' };
  650. PBYTE SrcSeq = NtfsNtldr;
  651. PBYTE DestSeq = NtfsCmldr;
  652. ULONG SeqSize = sizeof(NtfsNtldr);
  653. if (BootSector && Size && (FileSystemType != FileSystemUnknown)) {
  654. Result = ERROR_FILE_NOT_FOUND;
  655. if (FileSystemType != FileSystemNtfs) {
  656. SrcSeq = FatNtldr;
  657. DestSeq = FatCmldr;
  658. SeqSize = sizeof(FatNtldr);
  659. }
  660. for (ULONG Index=0; Index < (Size - SeqSize); Index++) {
  661. if (!memcmp(BootSector + Index, SrcSeq, SeqSize)) {
  662. memcpy(BootSector + Index, DestSeq, SeqSize);
  663. Result = 0;
  664. break;
  665. }
  666. }
  667. }
  668. if (!Result) {
  669. SetLastError(Result);
  670. }
  671. return Result;
  672. }
  673. VOID
  674. PatchMasterBootCode(
  675. IN ULONG DiskIndex
  676. )
  677. /*++
  678. Routine Description:
  679. Writes the master boot code to the specified disk's
  680. MBR
  681. Arguments:
  682. DiskIndex - NT disk number to use (0, 1, etc)
  683. Return value:
  684. None. On error throws appropriate exception.
  685. --*/
  686. {
  687. W32Disk Disk(DiskIndex);
  688. BYTE MBRSector[512] = {0};
  689. DWORD Error = Disk.ReadSectors(0, MBRSector);
  690. if (!Error) {
  691. CopyMemory(MBRSector, x86BootCode, 440);
  692. Error = Disk.WriteSectors(0, MBRSector);
  693. }
  694. if (Error) {
  695. throw new W32Error(Error);
  696. }
  697. }
  698. //
  699. // main() entry point
  700. //
  701. int
  702. __cdecl
  703. wmain(
  704. int Argc,
  705. wchar_t *Argv[]
  706. )
  707. {
  708. int Result = 0;
  709. ThisModule = GetModuleHandle(NULL);
  710. try {
  711. ProgramArguments Args(Argc, Argv);
  712. bool Successful = false;
  713. WCHAR SysPartName[MAX_PATH] = {0};
  714. DWORD LastError = 0;
  715. WCHAR SysPartDrvLetter = 0;
  716. if (Args.PatchMBR) {
  717. try {
  718. PatchMasterBootCode(Args.DiskIndex);
  719. Result = 0;
  720. std::cout << GetFormattedMessage( ThisModule,
  721. FALSE,
  722. Message,
  723. sizeof(Message)/sizeof(Message[0]),
  724. MSG_MBR_PATCHED_SUCCESSFULLY) << std::endl;
  725. }
  726. catch(W32Error *Exp) {
  727. if (Exp) {
  728. Exp->Dump(std::cout);
  729. }
  730. }
  731. } else {
  732. //
  733. // Get hold of the system partition drive letter
  734. //
  735. if (Args.BootCodePatch)
  736. SysPartDrvLetter = Args.DriveLetter;
  737. else
  738. LastError = GetSystemPartitionDriveLetter(SysPartDrvLetter);
  739. if (!LastError) {
  740. SysPartName[0] = SysPartDrvLetter;
  741. SysPartName[1] = NULL;
  742. W32Partition SysPart(SysPartName);
  743. std::wstring RcBootFileName = SysPartName;
  744. std::wstring RcBackupBootFileName = SysPartName;
  745. RcBootFileName += TEXT(":\\cmdcons\\bootsect.dat");
  746. RcBackupBootFileName += TEXT(":\\cmdcons\\bootsect.bak");
  747. //
  748. // Make a backup of recovery console's existing bootsect.dat file and
  749. // delete the existing bootsect.dat file
  750. //
  751. if (CopyFile(RcBootFileName.c_str(), RcBackupBootFileName.c_str(), FALSE) &&
  752. SetFileAttributes(RcBootFileName.c_str(), FILE_ATTRIBUTE_NORMAL) &&
  753. DeleteFile(RcBootFileName.c_str())) {
  754. //
  755. // Create a new bootsect.dat file
  756. //
  757. HANDLE BootSectorFile = CreateFile(RcBootFileName.c_str(),
  758. GENERIC_READ | GENERIC_WRITE,
  759. FILE_SHARE_READ | FILE_SHARE_WRITE,
  760. NULL,
  761. CREATE_ALWAYS,
  762. FILE_ATTRIBUTE_NORMAL,
  763. NULL);
  764. if (BootSectorFile != INVALID_HANDLE_VALUE) {
  765. BYTE BootSector[0x4000] = {0}; // 16K
  766. //
  767. // Get the current boot sector from the system partition
  768. //
  769. if (!SysPart.ReadSectors(0, BootSector, SysPart.GetBootCodeSize())) {
  770. DWORD BytesWritten = 0;
  771. //
  772. // Patch the boot sector and write it out
  773. //
  774. if (!PatchBootSectorForRC(BootSector,
  775. SysPart.GetBootCodeSize(),
  776. SysPart.GetFileSystemType()) &&
  777. WriteFile(BootSectorFile,
  778. BootSector,
  779. SysPart.GetBootCodeSize(),
  780. &BytesWritten,
  781. NULL)) {
  782. Successful = true;
  783. }
  784. }
  785. LastError = GetLastError();
  786. CloseHandle(BootSectorFile);
  787. }
  788. }
  789. if (!LastError) {
  790. LastError = GetLastError();
  791. }
  792. }
  793. if (!Successful || LastError) {
  794. throw new W32Error(LastError);
  795. }
  796. Result = 0;
  797. std::cout << GetFormattedMessage( ThisModule,
  798. FALSE,
  799. Message,
  800. sizeof(Message)/sizeof(Message[0]),
  801. MSG_RC_PATCHED_SUCCESSFULLY) << std::endl;
  802. }
  803. }
  804. catch(ProgramArguments *pArgs) {
  805. Result = 1;
  806. std::cout << GetFormattedMessage( ThisModule,
  807. FALSE,
  808. Message,
  809. sizeof(Message)/sizeof(Message[0]),
  810. MSG_PGM_USAGE) << std::endl;
  811. if (pArgs) {
  812. delete pArgs;
  813. }
  814. }
  815. catch(W32Error *W32Err) {
  816. if (W32Err) { // to make prefix happy :(
  817. Result = W32Err->ErrorCode;
  818. switch (W32Err->ErrorCode) {
  819. case ERROR_FILE_NOT_FOUND:
  820. case ERROR_PATH_NOT_FOUND:
  821. std::cout << GetFormattedMessage( ThisModule,
  822. FALSE,
  823. Message,
  824. sizeof(Message)/sizeof(Message[0]),
  825. MSG_COULD_NOT_FIND_RC) << std::endl;
  826. break;
  827. default:
  828. W32Err->Dump(std::cout);
  829. break;
  830. }
  831. delete W32Err;
  832. }
  833. }
  834. catch(ProgramException *PrgExp) {
  835. Result = 1;
  836. PrgExp->Dump(std::cout);
  837. delete PrgExp;
  838. } catch (exception *Exp) {
  839. Result = 1;
  840. std::cout << Exp->what() << std::endl;
  841. }
  842. return Result;
  843. }