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.

714 lines
17 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dt.cpp
  5. Abstract:
  6. Utility to do some disk related operations
  7. Author:
  8. Vijay Jayaseelan (vijayj) 26 April 2001
  9. Revision History:
  10. None
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <bootmbr.h>
  16. #include <iostream>
  17. #include <string>
  18. #include <exception>
  19. #include <windows.h>
  20. #include <tchar.h>
  21. #include <locale>
  22. #include <winioctl.h>
  23. //
  24. // Usage format
  25. //
  26. PCWSTR Usage = L"Usage: dt.exe /?\r\n"
  27. L"dt.exe /dump {[drive-letter] | [disk-number]} start-sector sector-count\r\n"
  28. L"dt.exe /diskinfo disk-number\r\n";
  29. //
  30. // Helper dump operators
  31. //
  32. std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
  33. FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
  34. fwprintf(OutStream, (PWSTR)str.c_str());
  35. return os;
  36. }
  37. //
  38. // Helper dump operators
  39. //
  40. std::ostream& operator<<(std::ostream &os, WCHAR *Str) {
  41. std::wstring WStr = Str;
  42. os << WStr;
  43. return os;
  44. }
  45. //
  46. // Exceptions
  47. //
  48. struct ProgramException : public std::exception {
  49. virtual void Dump(std::ostream &os) = 0;
  50. };
  51. //
  52. // Abstracts a Win32 error
  53. //
  54. struct W32Error : public ProgramException {
  55. DWORD ErrorCode;
  56. W32Error(DWORD ErrCode = GetLastError()) : ErrorCode(ErrCode){}
  57. void Dump(std::ostream &os) {
  58. WCHAR MsgBuffer[4096];
  59. MsgBuffer[0] = UNICODE_NULL;
  60. DWORD CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  61. NULL,
  62. ErrorCode,
  63. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  64. MsgBuffer,
  65. sizeof(MsgBuffer)/sizeof(WCHAR),
  66. NULL);
  67. if (CharCount) {
  68. std::wstring Msg(MsgBuffer);
  69. os << Msg;
  70. } else {
  71. os << std::hex << ErrorCode;
  72. }
  73. }
  74. };
  75. //
  76. // Invalid arguments
  77. //
  78. struct InvalidArguments : public ProgramException {
  79. const char *what() const throw() {
  80. return "Invalid Arguments";
  81. }
  82. void Dump(std::ostream &os) {
  83. os << what() << std::endl;
  84. }
  85. };
  86. //
  87. // Invalid arguments
  88. //
  89. struct ProgramUsage : public ProgramException {
  90. std::wstring PrgUsage;
  91. ProgramUsage(const std::wstring &Usg) : PrgUsage(Usg) {}
  92. const char *what() const throw() {
  93. return "Program Usage exception";
  94. }
  95. void Dump(std::ostream &os) {
  96. os << PrgUsage << std::endl;
  97. }
  98. };
  99. //
  100. // Program Arguments abstraction
  101. //
  102. struct ProgramArguments {
  103. bool DumpSectors;
  104. ULONG DiskIndex;
  105. std::wstring DriveLetter;
  106. LONGLONG StartingSector;
  107. ULONG NumSectors;
  108. std::wstring DeviceName;
  109. bool DumpDiskInfo;
  110. ProgramArguments(INT Argc, WCHAR *Argv[]) {
  111. bool ShowUsage = false;
  112. DumpSectors = false;
  113. DumpDiskInfo = false;
  114. DiskIndex = -1;
  115. StartingSector = -1;
  116. NumSectors = -1;
  117. for (ULONG Index=1; !ShowUsage && (Index < Argc); Index++) {
  118. if (!_wcsicmp(Argv[Index], TEXT("/dump"))) {
  119. ShowUsage = TRUE;
  120. if (((Index + 4) == Argc)) {
  121. Index++;
  122. DriveLetter = Argv[Index++];
  123. if ((DriveLetter.length() == 1)) {
  124. if (iswdigit(DriveLetter[0])) {
  125. WCHAR StrBuffer[64];
  126. DiskIndex = _wtol(DriveLetter.c_str());
  127. DriveLetter[0] = UNICODE_NULL;
  128. swprintf(StrBuffer,
  129. TEXT("\\\\.\\PHYSICALDRIVE%d"),
  130. DiskIndex);
  131. DeviceName = StrBuffer;
  132. } else {
  133. DeviceName = TEXT("\\\\.\\") + DriveLetter + TEXT(":");
  134. }
  135. StartingSector = (LONGLONG)(_wtoi64(Argv[Index++]));;
  136. NumSectors = (ULONG)_wtol(Argv[Index++]);
  137. ShowUsage = !(((DiskIndex != -1) || (DriveLetter[0])) &&
  138. (NumSectors != 0));
  139. DumpSectors = !ShowUsage;
  140. }
  141. }
  142. } else if (!_wcsicmp(Argv[Index], TEXT("/diskinfo"))) {
  143. DumpDiskInfo = TRUE;
  144. ShowUsage = TRUE;
  145. DriveLetter = Argv[++Index];
  146. if ((DriveLetter.length() == 1)) {
  147. if (iswdigit(DriveLetter[0])) {
  148. WCHAR StrBuffer[64];
  149. DiskIndex = _wtol(DriveLetter.c_str());
  150. DriveLetter[0] = UNICODE_NULL;
  151. swprintf(StrBuffer,
  152. TEXT("\\\\.\\PHYSICALDRIVE%d"),
  153. DiskIndex);
  154. DeviceName = StrBuffer;
  155. ShowUsage = FALSE;
  156. }
  157. }
  158. } else {
  159. ShowUsage = TRUE;
  160. }
  161. }
  162. if (ShowUsage) {
  163. throw new ProgramUsage(Usage);
  164. }
  165. }
  166. };
  167. //
  168. // Dumps the given binary data of the specified size
  169. // into the output stream with required indent size
  170. //
  171. void
  172. DumpBinary(unsigned char *Data, int Size,
  173. std::ostream& os, int Indent = 16)
  174. {
  175. if (Data && Size) {
  176. int Index = 0;
  177. int foo;
  178. char szBuff[128] = {'.'};
  179. int Ruler = 0;
  180. while (Index < Size) {
  181. if (!(Index % Indent)) {
  182. if (Index) {
  183. szBuff[Indent] = 0;
  184. os << szBuff;
  185. }
  186. os << std::endl;
  187. os.width(8);
  188. os.fill('0');
  189. os << Ruler << " ";
  190. Ruler += Indent;
  191. }
  192. foo = *(Data + Index);
  193. szBuff[Index % Indent] = ::isalnum(foo) ? (char)foo : (char)'.';
  194. os.width(2);
  195. os.fill('0');
  196. os.flags(std::ios::uppercase | std::ios::hex);
  197. os << foo << ' ';
  198. Index++;
  199. }
  200. while (Index % Indent) {
  201. os << ' ';
  202. Index++;
  203. szBuff[Index % Indent] = ' ';
  204. }
  205. szBuff[Indent] = 0;
  206. os << szBuff;
  207. } else {
  208. os << std::endl << "no data" << std::endl;
  209. }
  210. }
  211. //
  212. // Abstracts block device (interface)
  213. //
  214. class W32BlockDevice {
  215. public:
  216. W32BlockDevice(const std::wstring &name, ULONG SecSize) :
  217. SectorSize(SecSize), DeviceHandle(INVALID_HANDLE_VALUE), Name(name){
  218. //
  219. // Open the device
  220. //
  221. DeviceHandle = CreateFile(Name.c_str(),
  222. GENERIC_READ | GENERIC_WRITE,
  223. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  224. NULL,
  225. OPEN_EXISTING,
  226. FILE_ATTRIBUTE_NORMAL,
  227. NULL);
  228. DWORD LastError = GetLastError();
  229. if (LastError) {
  230. throw new W32Error(LastError);
  231. }
  232. }
  233. virtual ~W32BlockDevice() {
  234. if (DeviceHandle != INVALID_HANDLE_VALUE) {
  235. CloseHandle(DeviceHandle);
  236. }
  237. };
  238. ULONG GetSectorSize() const { return SectorSize; }
  239. //
  240. // Reads the requested size of data from the given sector
  241. //
  242. virtual DWORD ReadSectors(LONGLONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
  243. LARGE_INTEGER MoveLength;
  244. MoveLength.QuadPart = Index * SectorSize;
  245. SetFilePointerEx(DeviceHandle,
  246. MoveLength,
  247. NULL,
  248. FILE_BEGIN);
  249. DWORD LastError = GetLastError();
  250. if (!LastError) {
  251. DWORD BytesRead = 0;
  252. if (!ReadFile(DeviceHandle,
  253. DataBuffer,
  254. BufferSize,
  255. &BytesRead,
  256. NULL)) {
  257. LastError = GetLastError();
  258. }
  259. }
  260. return LastError;
  261. }
  262. //
  263. // Writes the requested size of data to the specified sector
  264. //
  265. virtual DWORD WriteSectors(ULONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
  266. LARGE_INTEGER MoveLength;
  267. MoveLength.QuadPart = Index * SectorSize;
  268. SetFilePointerEx(DeviceHandle,
  269. MoveLength,
  270. NULL,
  271. FILE_BEGIN);
  272. DWORD LastError = GetLastError();
  273. if (!LastError) {
  274. DWORD BytesWritten = 0;
  275. if (!WriteFile(DeviceHandle,
  276. DataBuffer,
  277. BufferSize,
  278. &BytesWritten,
  279. NULL)) {
  280. LastError = GetLastError();
  281. }
  282. }
  283. return LastError;
  284. }
  285. virtual std::ostream& Dump(std::ostream &os) {
  286. os << TEXT("Device Name = ") << TEXT("(") << Name << TEXT(")") << std::endl;
  287. return os;
  288. }
  289. const HANDLE GetHandle() const { return DeviceHandle; }
  290. protected:
  291. //
  292. // Data members
  293. //
  294. HANDLE DeviceHandle;
  295. ULONG SectorSize;
  296. std::wstring Name;
  297. };
  298. VOID
  299. DumpSectors(
  300. IN ProgramArguments &Args
  301. )
  302. {
  303. if (Args.DumpSectors) {
  304. W32BlockDevice Device(Args.DeviceName, 512);
  305. WCHAR LongString[64];
  306. BYTE Sector[4096];
  307. ULONG SectorCount = Args.NumSectors;
  308. LONGLONG StartingSector = Args.StartingSector;
  309. Device.Dump(std::cout);
  310. while (SectorCount && (Device.ReadSectors(StartingSector, Sector) == NO_ERROR)) {
  311. std::cout << std::endl << "Sector : " << std::dec;
  312. LongString[0] = 0;
  313. std::cout << _i64tow(StartingSector, LongString, 10);
  314. DumpBinary(Sector, Device.GetSectorSize(), std::cout);
  315. std::cout << std::endl;
  316. SectorCount--;
  317. StartingSector++;
  318. }
  319. } else {
  320. SetLastError(ERROR_INVALID_PARAMETER);
  321. }
  322. DWORD LastError = GetLastError();
  323. if (LastError != NO_ERROR) {
  324. throw new W32Error(LastError);
  325. }
  326. }
  327. #ifndef _WIN64
  328. std::ostream&
  329. operator<<(std::ostream &os, const ULONGLONG &LargeInteger) {
  330. WCHAR Buffer[64];
  331. swprintf(Buffer, L"%I64u", LargeInteger);
  332. os << Buffer;
  333. return os;
  334. }
  335. std::ostream&
  336. operator<<(std::ostream &os, const LONGLONG &LargeInteger) {
  337. WCHAR Buffer[64];
  338. swprintf(Buffer, L"%I64d", LargeInteger);
  339. os << Buffer;
  340. return os;
  341. }
  342. #endif // ! _WIN64
  343. inline
  344. std::ostream&
  345. operator<<(std::ostream &os, const LARGE_INTEGER &LargeInteger) {
  346. return (os << LargeInteger.QuadPart);
  347. }
  348. inline
  349. std::ostream&
  350. operator<<(std::ostream &os, const GUID &Guid) {
  351. WCHAR Buffer[MAX_PATH];
  352. swprintf(Buffer,
  353. TEXT("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
  354. Guid.Data1,
  355. Guid.Data2,
  356. Guid.Data3,
  357. Guid.Data4[0],
  358. Guid.Data4[1],
  359. Guid.Data4[2],
  360. Guid.Data4[3],
  361. Guid.Data4[4],
  362. Guid.Data4[5],
  363. Guid.Data4[6],
  364. Guid.Data4[7]);
  365. os << Buffer;
  366. return os;
  367. }
  368. inline
  369. std::ostream&
  370. operator<<(std::ostream &os, const PARTITION_INFORMATION_MBR &MbrPartInfo) {
  371. WCHAR Buffer[MAX_PATH];
  372. swprintf(Buffer,
  373. TEXT("Type : 0x%02lX, Active : %ws, Recognized : %ws, Hidden Sectors : %d"),
  374. MbrPartInfo.PartitionType,
  375. (MbrPartInfo.BootIndicator ? TEXT("TRUE") : TEXT("FALSE")),
  376. (MbrPartInfo.HiddenSectors ? TEXT("TRUE") : TEXT("FALSE")),
  377. MbrPartInfo.HiddenSectors);
  378. os << Buffer << std::endl;
  379. return os;
  380. }
  381. inline
  382. std::ostream&
  383. operator<<(std::ostream &os, const PARTITION_INFORMATION_GPT &GptPartInfo) {
  384. os << "Type : " << GptPartInfo.PartitionType << ", ";
  385. os << "Id : " << GptPartInfo.PartitionId << ", ";
  386. os << "Attrs : " << GptPartInfo.Attributes << ", ";
  387. os << "Name : " << std::wstring(GptPartInfo.Name);
  388. return os;
  389. }
  390. std::ostream&
  391. operator<<(std::ostream &os, const PARTITION_INFORMATION_EX &PartInfo) {
  392. os << "Partition# : " << std::dec << PartInfo.PartitionNumber;
  393. os << ", Start : " << PartInfo.StartingOffset.QuadPart;
  394. os << ", Length : " << PartInfo.PartitionLength.QuadPart << std::endl;
  395. switch(PartInfo.PartitionStyle) {
  396. case PARTITION_STYLE_MBR:
  397. os << PartInfo.Mbr;
  398. break;
  399. case PARTITION_STYLE_GPT:
  400. os << PartInfo.Gpt;
  401. break;
  402. default:
  403. break;
  404. }
  405. os << std::endl;
  406. return os;
  407. }
  408. std::ostream&
  409. operator<<(std::ostream &os, const DRIVE_LAYOUT_INFORMATION_MBR &MbrInfo) {
  410. os << "Signature : " << std::hex << MbrInfo.Signature;
  411. return os;
  412. }
  413. std::ostream&
  414. operator<<(std::ostream &os, const DRIVE_LAYOUT_INFORMATION_GPT &GptInfo) {
  415. os << "Disk ID : " << GptInfo.DiskId << ", ";
  416. os << "Starting Offset : " << std::dec << GptInfo.StartingUsableOffset << ", ";
  417. os << "Usable Length : " << std::dec << GptInfo.UsableLength << ", ";
  418. os << "Max Partition Count : " << std::dec << GptInfo.MaxPartitionCount;
  419. return os;
  420. }
  421. std::ostream&
  422. operator<<(std::ostream &os, const DRIVE_LAYOUT_INFORMATION_EX &DriveInfo) {
  423. os << "Disk Type : ";
  424. switch (DriveInfo.PartitionStyle) {
  425. case PARTITION_STYLE_MBR:
  426. os << "MBR";
  427. break;
  428. case PARTITION_STYLE_GPT:
  429. os << "GPT";
  430. break;
  431. default:
  432. os << "Unknown";
  433. break;
  434. }
  435. os << ", Partition Count : " << std::dec << DriveInfo.PartitionCount << " ";
  436. switch(DriveInfo.PartitionStyle) {
  437. case PARTITION_STYLE_MBR:
  438. os << DriveInfo.Mbr;
  439. break;
  440. case PARTITION_STYLE_GPT:
  441. os << DriveInfo.Gpt;
  442. break;
  443. default:
  444. break;
  445. }
  446. os << std::endl << std::endl;
  447. for (ULONG Index = 0; Index < DriveInfo.PartitionCount; Index++) {
  448. if (DriveInfo.PartitionEntry[Index].PartitionNumber) {
  449. os << DriveInfo.PartitionEntry[Index];
  450. os << std::endl;
  451. }
  452. }
  453. os << std::endl;
  454. return os;
  455. }
  456. std::ostream&
  457. operator<<(std::ostream &os, const DISK_GEOMETRY &DiskInfo) {
  458. os << "Heads : " << std::dec << DiskInfo.TracksPerCylinder;
  459. os << ", Cylinders : " << DiskInfo.Cylinders;
  460. os << ", Sectors/Track : " << std::dec << DiskInfo.SectorsPerTrack;
  461. os << ", Bytes/Sector : " << std::dec << DiskInfo.BytesPerSector;
  462. return os;
  463. }
  464. void
  465. DumpDiskCharacteristics(
  466. IN ProgramArguments &Args
  467. )
  468. {
  469. DWORD LastError = NO_ERROR;
  470. if (Args.DumpDiskInfo){
  471. W32BlockDevice Device(Args.DeviceName, 512);
  472. HANDLE DeviceHandle = (HANDLE)Device.GetHandle();
  473. ULONG BufferLength = 16 * 1024;
  474. PBYTE Buffer = new BYTE[BufferLength];
  475. if (Buffer) {
  476. DWORD BytesReturned = 0;
  477. PDISK_GEOMETRY DiskInfo = (PDISK_GEOMETRY)Buffer;
  478. Device.Dump(std::cout);
  479. if (DeviceIoControl(DeviceHandle,
  480. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  481. NULL,
  482. 0,
  483. Buffer,
  484. BufferLength,
  485. &BytesReturned,
  486. NULL)) {
  487. std::cout << (*DiskInfo) << std::endl;
  488. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)Buffer;
  489. if (DeviceIoControl(DeviceHandle,
  490. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  491. NULL,
  492. 0,
  493. Buffer,
  494. BufferLength,
  495. &BytesReturned,
  496. NULL)) {
  497. //
  498. // dump the disk information
  499. //
  500. std::cout << (*DriveLayout);
  501. }
  502. }
  503. LastError = GetLastError();
  504. delete []Buffer;
  505. }
  506. } else {
  507. SetLastError(ERROR_INVALID_PARAMETER);
  508. }
  509. if (LastError == NO_ERROR) {
  510. LastError = GetLastError();
  511. }
  512. if (LastError != NO_ERROR) {
  513. throw new W32Error(LastError);
  514. }
  515. }
  516. //
  517. // main() entry point
  518. //
  519. int
  520. __cdecl
  521. wmain(
  522. int Argc,
  523. wchar_t *Argv[]
  524. )
  525. {
  526. int Result = 0;
  527. try {
  528. ProgramArguments Args(Argc, Argv);
  529. if (Args.DumpSectors) {
  530. DumpSectors(Args);
  531. } else if (Args.DumpDiskInfo) {
  532. DumpDiskCharacteristics(Args);
  533. } else {
  534. throw new ProgramUsage(Usage);
  535. }
  536. }
  537. catch(W32Error *W32Err) {
  538. Result = 1;
  539. if (W32Err) {
  540. W32Err->Dump(std::cout);
  541. delete W32Err;
  542. }
  543. }
  544. catch(ProgramException *PrgExp) {
  545. Result = 1;
  546. if (PrgExp) {
  547. PrgExp->Dump(std::cout);
  548. delete PrgExp;
  549. }
  550. } catch (exception *Exp) {
  551. Result = 1;
  552. if (Exp) {
  553. std::cout << Exp->what() << std::endl;
  554. }
  555. }
  556. return Result;
  557. }