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.

417 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. setact.cpp
  5. Abstract:
  6. Gets/Sets the active partition on an MBR disk
  7. Author:
  8. Vijay Jayaseelan (vijayj) 30-Oct-2000
  9. Revision History:
  10. None
  11. --*/
  12. #include <iostream>
  13. #include <string>
  14. #include <exception>
  15. #include <windows.h>
  16. #include <winioctl.h>
  17. #include <io.h>
  18. #include <tchar.h>
  19. //
  20. // Usage format
  21. //
  22. std::wstring Usage(L"Usage: setactive.exe hardisk-number [partition-number]");
  23. //
  24. // Helper dump operators
  25. //
  26. std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
  27. FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
  28. fwprintf(OutStream, str.c_str());
  29. return os;
  30. }
  31. //
  32. // Exceptions
  33. //
  34. struct ProgramException : public std::exception {
  35. virtual void Dump(std::ostream &os) = 0;
  36. };
  37. //
  38. // Abstracts a Win32 error
  39. //
  40. struct W32Error : public ProgramException {
  41. DWORD ErrorCode;
  42. W32Error(DWORD ErrCode) : ErrorCode(ErrCode){}
  43. void Dump(std::ostream &os) {
  44. WCHAR MsgBuffer[4096];
  45. MsgBuffer[0] = UNICODE_NULL;
  46. DWORD CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  47. NULL,
  48. ErrorCode,
  49. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  50. MsgBuffer,
  51. sizeof(MsgBuffer)/sizeof(WCHAR),
  52. NULL);
  53. if (CharCount) {
  54. std::wstring Msg(MsgBuffer);
  55. os << Msg;
  56. } else {
  57. os << std::hex << ErrorCode;
  58. }
  59. }
  60. };
  61. //
  62. // Invalid arguments
  63. //
  64. struct InvalidArguments : public ProgramException {
  65. const char *what() const throw() {
  66. return "Invalid Arguments";
  67. }
  68. void Dump(std::ostream &os) {
  69. os << what() << std::endl;
  70. }
  71. };
  72. //
  73. // Invalid arguments
  74. //
  75. struct ProgramUsage : public ProgramException {
  76. std::wstring PrgUsage;
  77. ProgramUsage(const std::wstring &Usg) : PrgUsage(Usg) {}
  78. const char *what() const throw() {
  79. return "Program Usage exception";
  80. }
  81. void Dump(std::ostream &os) {
  82. os << Usage << std::endl;
  83. }
  84. };
  85. //
  86. // Argument cracker
  87. //
  88. struct ProgramArguments {
  89. ULONG DiskNumber;
  90. ULONG PartitionNumber;
  91. BOOLEAN Set;
  92. ProgramArguments(int Argc, wchar_t *Argv[]) {
  93. Set = FALSE;
  94. if (Argc > 1) {
  95. DiskNumber = (ULONG)_ttol(Argv[1]);
  96. if (Argc > 2) {
  97. PartitionNumber = (ULONG)_ttol(Argv[2]);
  98. Set = TRUE;
  99. if (!PartitionNumber) {
  100. throw new ProgramUsage(Usage);
  101. }
  102. }
  103. } else {
  104. throw new ProgramUsage(Usage);
  105. }
  106. }
  107. friend std::ostream operator<<(std::ostream &os, const ProgramArguments &Args) {
  108. os << "Arguments : DiskNumber = "
  109. << std::dec << Args.DiskNumber << ", "
  110. << std::dec << Args.PartitionNumber << std::endl;
  111. return os;
  112. }
  113. };
  114. //
  115. // HardDisk abstraction
  116. //
  117. class W32HardDisk {
  118. public:
  119. W32HardDisk(ULONG DiskNum) : DiskNumber(DiskNum), Dirty(FALSE) {
  120. WCHAR DiskName[MAX_PATH];
  121. _stprintf(DiskName, TEXT("\\\\.\\PHYSICALDRIVE%d"), DiskNumber);
  122. DiskHandle = CreateFileW(DiskName,
  123. GENERIC_READ | GENERIC_WRITE,
  124. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  125. NULL,
  126. OPEN_EXISTING,
  127. FILE_ATTRIBUTE_NORMAL,
  128. NULL);
  129. if (DiskHandle == INVALID_HANDLE_VALUE) {
  130. throw new W32Error(GetLastError());
  131. }
  132. DriveLayout = NULL;
  133. DriveLayoutSize = 0;
  134. GetPartitionInformation();
  135. }
  136. virtual ~W32HardDisk() {
  137. if (IsDirty() && !CommitChanges()) {
  138. throw new W32Error(GetLastError());
  139. }
  140. delete []((PBYTE)(DriveLayout));
  141. CloseHandle(DiskHandle);
  142. }
  143. BOOLEAN IsDirty() const { return Dirty; }
  144. ULONG GetPartitionCount() const { return DriveLayout->PartitionCount; }
  145. PARTITION_STYLE GetDiskStyle() const {
  146. return (PARTITION_STYLE)(DriveLayout->PartitionStyle);
  147. }
  148. const PARTITION_INFORMATION_EX* GetPartition(ULONG PartitionNumber) const {
  149. PPARTITION_INFORMATION_EX PartInfo = NULL;
  150. for (ULONG Index = 0; Index < DriveLayout->PartitionCount; Index++) {
  151. PPARTITION_INFORMATION_EX CurrPartInfo =
  152. DriveLayout->PartitionEntry + Index;
  153. if (CurrPartInfo->PartitionNumber == PartitionNumber) {
  154. PartInfo = CurrPartInfo;
  155. break;
  156. }
  157. }
  158. return PartInfo;
  159. }
  160. BOOLEAN SetPartitionInfo(ULONG PartitionNumber,
  161. const PARTITION_INFORMATION_EX &PartInformation) {
  162. BOOLEAN Result = FALSE;
  163. PPARTITION_INFORMATION_EX PartInfo = (PPARTITION_INFORMATION_EX)GetPartition(PartitionNumber);
  164. if (PartInfo) {
  165. *PartInfo = PartInformation;
  166. PartInfo->PartitionNumber = PartitionNumber;
  167. Dirty = Result = TRUE;
  168. }
  169. return Result;
  170. }
  171. const PARTITION_INFORMATION_EX* GetActivePartition(BOOLEAN Rescan = FALSE){
  172. if (Rescan) {
  173. GetPartitionInformation();
  174. }
  175. PPARTITION_INFORMATION_EX ActivePartition = NULL;
  176. if (GetDiskStyle() == PARTITION_STYLE_MBR) {
  177. for (ULONG Index = 0; Index < GetPartitionCount(); Index++) {
  178. PPARTITION_INFORMATION_EX PartInfo = DriveLayout->PartitionEntry + Index;
  179. if (PartInfo->Mbr.BootIndicator) {
  180. ActivePartition = PartInfo;
  181. break;
  182. }
  183. }
  184. }
  185. return ActivePartition;
  186. }
  187. BOOLEAN SetActivePartition(ULONG PartitionNumber) {
  188. BOOLEAN Result = FALSE;
  189. if (GetDiskStyle() == PARTITION_STYLE_MBR) {
  190. //
  191. // Set the give partition as active and turn off all the other
  192. // active bits on other partitions
  193. //
  194. const PARTITION_INFORMATION_EX *PartInfo = GetPartition(PartitionNumber);
  195. if (PartInfo) {
  196. //
  197. // NOTE : Does not check for primary partition
  198. //
  199. for (ULONG Index = 0; Index < GetPartitionCount(); Index++) {
  200. PPARTITION_INFORMATION_EX PartInfo = (DriveLayout->PartitionEntry + Index);
  201. if (PartInfo->PartitionNumber == PartitionNumber) {
  202. Dirty = TRUE;
  203. PartInfo->Mbr.BootIndicator = TRUE;
  204. PartInfo->RewritePartition = TRUE;
  205. Result = TRUE;
  206. } else if (CanActivatePartition(*PartInfo)) {
  207. PartInfo->Mbr.BootIndicator = FALSE;
  208. PartInfo->RewritePartition = TRUE;
  209. Dirty = TRUE;
  210. }
  211. }
  212. }
  213. }
  214. if (Result) {
  215. Result = CommitChanges();
  216. if (!Result) {
  217. throw new W32Error(GetLastError());
  218. }
  219. }
  220. return Result;
  221. }
  222. protected:
  223. VOID GetPartitionInformation() {
  224. //
  225. // Allocate space for 128 partitions
  226. //
  227. DWORD ErrorStatus = ERROR_MORE_DATA;
  228. ULONG Iteration = 0;
  229. if (DriveLayout && DriveLayoutSize) {
  230. delete [](PBYTE)(DriveLayout);
  231. }
  232. do {
  233. Iteration++;
  234. DriveLayoutSize = sizeof(PARTITION_INFORMATION_EX) * (128 * Iteration) ;
  235. DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX) new BYTE[DriveLayoutSize];
  236. ZeroMemory(DriveLayout, DriveLayoutSize);
  237. if (DriveLayout) {
  238. DWORD BytesReturned = 0;
  239. if (DeviceIoControl(DiskHandle,
  240. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  241. NULL,
  242. 0,
  243. DriveLayout,
  244. DriveLayoutSize,
  245. &BytesReturned,
  246. NULL)) {
  247. ErrorStatus = 0;
  248. } else {
  249. ErrorStatus = GetLastError();
  250. }
  251. } else {
  252. throw new W32Error(GetLastError());
  253. }
  254. }
  255. while (ErrorStatus == ERROR_MORE_DATA);
  256. if (ErrorStatus) {
  257. throw new W32Error(GetLastError());
  258. }
  259. }
  260. //
  261. // Helper methods
  262. //
  263. BOOLEAN CanActivatePartition(const PARTITION_INFORMATION_EX &PartInfo) const {
  264. return (PartInfo.PartitionNumber && PartInfo.StartingOffset.QuadPart &&
  265. PartInfo.PartitionLength.QuadPart &&
  266. (GetDiskStyle() == PARTITION_STYLE_MBR) &&
  267. !IsContainerPartition(PartInfo.Mbr.PartitionType) &&
  268. IsRecognizedPartition(PartInfo.Mbr.PartitionType));
  269. }
  270. BOOLEAN CommitChanges() {
  271. DWORD BytesReturned = 0;
  272. return DeviceIoControl(DiskHandle,
  273. IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
  274. DriveLayout,
  275. DriveLayoutSize,
  276. NULL,
  277. 0,
  278. &BytesReturned,
  279. NULL) ? TRUE : FALSE;
  280. }
  281. //
  282. // data members
  283. //
  284. ULONG DiskNumber;
  285. HANDLE DiskHandle;
  286. BOOLEAN Dirty;
  287. ULONG DriveLayoutSize;
  288. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  289. };
  290. //
  291. // main() entry point
  292. //
  293. int
  294. __cdecl
  295. wmain(
  296. int Argc,
  297. wchar_t *Argv[]
  298. )
  299. {
  300. int Result = 0;
  301. try {
  302. ProgramArguments Args(Argc, Argv);
  303. W32HardDisk Disk(Args.DiskNumber);
  304. if (Args.Set) {
  305. Disk.SetActivePartition(Args.PartitionNumber);
  306. }
  307. const PARTITION_INFORMATION_EX * ActivePart = Disk.GetActivePartition();
  308. if (ActivePart) {
  309. std::cout << std::dec << ActivePart->PartitionNumber
  310. << " is the Active Partition on Disk "
  311. << std::dec << Args.DiskNumber << std::endl;
  312. } else {
  313. std::cout << "No active partition on Disk "
  314. << std::dec << Args.DiskNumber << std::endl;
  315. }
  316. }
  317. catch(ProgramException *PrgExp) {
  318. Result = 1;
  319. PrgExp->Dump(std::cout);
  320. delete PrgExp;
  321. } catch (exception *Exp) {
  322. Result = 1;
  323. std::cout << Exp->what() << std::endl;
  324. }
  325. return Result;
  326. }