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.

586 lines
12 KiB

  1. //
  2. // DISK.CPP - Classes for partition table manipulation
  3. //
  4. // Revision History:
  5. //
  6. #include "disk.h"
  7. #include <stdio.h>
  8. #include <rpc.h>
  9. #include <rpcdce.h>
  10. #include <bootmbr.h>
  11. HRESULT
  12. CDrive::Initialize(
  13. LPCTSTR lpszLogicalDrive
  14. )
  15. {
  16. HANDLE handle;
  17. HRESULT hr;
  18. DISK_GEOMETRY geom;
  19. ULONG bps;
  20. PVOID unalignedBuffer;
  21. PVOID buffer;
  22. /*
  23. * Open the disk device
  24. */
  25. handle = LowOpenPartition(lpszLogicalDrive);
  26. if (handle == INVALID_HANDLE_VALUE) {
  27. return E_INVALIDARG;
  28. }
  29. /*
  30. * Get the geometry
  31. */
  32. hr = LowGetGeometry(handle, &geom);
  33. if (FAILED(hr)) {
  34. CloseHandle(handle);
  35. return hr;
  36. }
  37. m_geometry.cylinders = geom.Cylinders.QuadPart;
  38. m_geometry.mediaType = geom.MediaType;
  39. m_geometry.tracksPerCylinder = geom.TracksPerCylinder;
  40. m_geometry.sectorsPerTrack = geom.SectorsPerTrack;
  41. m_geometry.bytesPerSector = geom.BytesPerSector;
  42. m_geometry.bytesPerTrack = m_geometry.sectorsPerTrack *
  43. m_geometry.bytesPerSector;
  44. m_geometry.bytesPerCylinder = m_geometry.tracksPerCylinder *
  45. m_geometry.bytesPerTrack;
  46. m_geometry.totalSectorCount = (ULONGLONG)(m_geometry.cylinders *
  47. m_geometry.bytesPerCylinder);
  48. m_length = m_geometry.cylinders * m_geometry.bytesPerCylinder;
  49. if (m_length == 0) {
  50. // Probably no media is present in the drive
  51. return E_INVALIDARG;
  52. }
  53. /*
  54. * Get the true length of the drive
  55. */
  56. hr = LowGetLength(handle, &m_trueLength);
  57. if (FAILED(hr)) {
  58. CloseHandle(handle);
  59. return hr;
  60. }
  61. /*
  62. * Check whether this is a NEC98 disk
  63. */
  64. m_isNEC98 = FALSE;
  65. bps = m_geometry.bytesPerSector;
  66. unalignedBuffer = (PVOID) new char[2 * bps];
  67. if (!unalignedBuffer) {
  68. CloseHandle(handle);
  69. return E_OUTOFMEMORY;
  70. }
  71. buffer = (PVOID) (((ULONG_PTR)unalignedBuffer + bps) & ~((ULONG_PTR)(bps - 1)));
  72. hr = LowReadSectors(handle, bps, 0, 1, buffer);
  73. if (FAILED(hr)) {
  74. delete [] (char*) unalignedBuffer;
  75. CloseHandle(handle);
  76. return hr;
  77. }
  78. if (IsNEC_98) {
  79. if (((unsigned char *)buffer)[0x1fe] == 0x55 && ((unsigned char *)buffer)[0x1ff] == 0xaa) {
  80. if (((unsigned char *)buffer)[4] == 'I' && ((unsigned char *)buffer)[5] == 'P' &&
  81. ((unsigned char *)buffer)[6] == 'L' && ((unsigned char *)buffer)[7] == '1') {
  82. m_isNEC98 = TRUE;
  83. }
  84. } else {
  85. m_isNEC98 = TRUE;
  86. }
  87. }
  88. delete [] (char*) unalignedBuffer;
  89. /*
  90. * We have all the information we need. Return.
  91. */
  92. CloseHandle(handle);
  93. return S_OK;
  94. }
  95. CDrive::~CDrive(
  96. )
  97. {
  98. }
  99. HRESULT
  100. CDrive::ReadBootRecord(
  101. LPCTSTR lpszLogicalDrive,
  102. UINT nSectors,
  103. PBYTE *buffer
  104. )
  105. {
  106. HANDLE hPartition;
  107. HRESULT hr;
  108. *buffer = new BYTE[m_geometry.bytesPerSector * nSectors];
  109. // Do disk ops, read bootcode
  110. //
  111. hPartition = LowOpenPartition(lpszLogicalDrive);
  112. if ( hPartition == INVALID_HANDLE_VALUE )
  113. {
  114. delete[] *buffer;
  115. *buffer = NULL;
  116. throw new W32Error();
  117. }
  118. hr = LowReadSectors(hPartition, m_geometry.bytesPerSector, 0, nSectors, *buffer);
  119. if ( S_OK != hr )
  120. {
  121. delete[] *buffer;
  122. *buffer = NULL;
  123. CloseHandle( hPartition );
  124. throw new W32Error();
  125. }
  126. CloseHandle( hPartition );
  127. // The calling function is responsible for cleaning up the buffer.
  128. //
  129. return hr;
  130. }
  131. HRESULT
  132. CDrive::WriteBootRecord(
  133. LPCTSTR lpszLogicalDrive,
  134. UINT nSectors,
  135. PBYTE *buffer
  136. )
  137. {
  138. HANDLE hPartition;
  139. HRESULT hr;
  140. UINT *uiBackupSector = NULL;
  141. // Do disk ops, write bootcode
  142. //
  143. hPartition = LowOpenPartition(lpszLogicalDrive);
  144. if ( INVALID_HANDLE_VALUE == hPartition )
  145. {
  146. throw new W32Error();
  147. }
  148. // Figure out where the backup boot sector is. It is at offset 0x32 in the boot record.
  149. //
  150. uiBackupSector = (UINT *) &((*buffer)[0x32]);
  151. hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, 0, nSectors, *buffer);
  152. if ( S_OK != hr )
  153. {
  154. CloseHandle(hPartition);
  155. throw new W32Error();
  156. }
  157. if ( uiBackupSector )
  158. {
  159. hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, *uiBackupSector, nSectors, *buffer);
  160. }
  161. if ( S_OK != hr )
  162. {
  163. CloseHandle(hPartition);
  164. throw new W32Error();
  165. }
  166. CloseHandle(hPartition);
  167. return hr;
  168. }
  169. HRESULT
  170. CDrive::WriteBootRecordXP(
  171. LPCTSTR lpszLogicalDrive,
  172. UINT nSectors,
  173. PBYTE *buffer
  174. )
  175. {
  176. HANDLE hPartition;
  177. HRESULT hr;
  178. UINT *uiBackupSector = NULL;
  179. // Do disk ops, write bootcode
  180. //
  181. hPartition = LowOpenPartition(lpszLogicalDrive);
  182. if ( INVALID_HANDLE_VALUE == hPartition )
  183. {
  184. throw new W32Error();
  185. }
  186. // Figure out where the backup boot sector is. It is at offset 0x32 in the boot record.
  187. //
  188. uiBackupSector = (UINT *) &((*buffer)[0x32]);
  189. // Write out the first 2 sectors to sectors 0 and 1 on the disk. We will write the
  190. // third sector to sector 12.
  191. //
  192. hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, 0, nSectors - 1, *buffer);
  193. if ( S_OK != hr )
  194. {
  195. CloseHandle(hPartition);
  196. throw new W32Error();
  197. }
  198. // For NT we need to write out the third sector of the bootcode to sector 12.
  199. //
  200. hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, 12, 1, *buffer + (2 * m_geometry.bytesPerSector));
  201. if ( S_OK != hr )
  202. {
  203. CloseHandle(hPartition);
  204. throw new W32Error();
  205. }
  206. if ( uiBackupSector )
  207. {
  208. hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, *uiBackupSector, nSectors, *buffer);
  209. }
  210. if ( S_OK != hr )
  211. {
  212. CloseHandle(hPartition);
  213. throw new W32Error();
  214. }
  215. CloseHandle(hPartition);
  216. return hr;
  217. }
  218. HANDLE
  219. LowOpenDisk(
  220. ULONG diskNumber
  221. )
  222. {
  223. HANDLE handle = NULL;
  224. int err = 0;
  225. int i = 0;
  226. WCHAR buffer[64];
  227. swprintf(buffer, L"\\\\.\\PHYSICALDRIVE%lu", diskNumber);
  228. for ( i = 0; i < 5; i++ )
  229. {
  230. handle = CreateFile(
  231. buffer,
  232. GENERIC_READ |
  233. GENERIC_WRITE,
  234. FILE_SHARE_DELETE |
  235. FILE_SHARE_READ |
  236. FILE_SHARE_WRITE,
  237. NULL,
  238. OPEN_EXISTING,
  239. FILE_ATTRIBUTE_NORMAL,
  240. NULL);
  241. if (handle == INVALID_HANDLE_VALUE)
  242. {
  243. err = GetLastError();
  244. if (err == ERROR_SHARING_VIOLATION) Sleep(2000);
  245. else break;
  246. }
  247. else break;
  248. }
  249. return handle;
  250. }
  251. HANDLE
  252. LowOpenPartition(
  253. ULONG diskNumber,
  254. ULONG partitionNumber
  255. )
  256. {
  257. WCHAR buffer[64];
  258. swprintf(buffer, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%lu\\Partition%lu",
  259. diskNumber, partitionNumber);
  260. return CreateFile(
  261. buffer,
  262. GENERIC_READ | GENERIC_WRITE,
  263. FILE_SHARE_DELETE,
  264. NULL,
  265. OPEN_EXISTING,
  266. FILE_ATTRIBUTE_NORMAL,
  267. NULL);
  268. }
  269. HANDLE
  270. LowOpenPartition(
  271. LPCTSTR lpszLogicalDrive
  272. )
  273. {
  274. return CreateFile(
  275. lpszLogicalDrive,
  276. GENERIC_READ | GENERIC_WRITE,
  277. FILE_SHARE_DELETE,
  278. NULL,
  279. OPEN_EXISTING,
  280. FILE_ATTRIBUTE_NORMAL,
  281. NULL);
  282. }
  283. HRESULT
  284. LowGetGeometry(
  285. HANDLE handle,
  286. PDISK_GEOMETRY geometry
  287. )
  288. {
  289. ULONG size;
  290. if (!DeviceIoControl(
  291. handle,
  292. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  293. NULL,
  294. 0,
  295. geometry,
  296. sizeof(DISK_GEOMETRY),
  297. &size,
  298. NULL)) {
  299. return E_FAIL;
  300. }
  301. return S_OK;
  302. }
  303. HRESULT
  304. LowGetLength(
  305. HANDLE handle,
  306. PLONGLONG length
  307. )
  308. {
  309. PARTITION_INFORMATION_EX partInfoEx;
  310. PARTITION_INFORMATION partInfo;
  311. ULONG size;
  312. /*
  313. * Try first the new ioctl
  314. */
  315. if (DeviceIoControl(
  316. handle,
  317. IOCTL_DISK_GET_PARTITION_INFO_EX,
  318. NULL,
  319. 0,
  320. &partInfoEx,
  321. sizeof(PARTITION_INFORMATION_EX),
  322. &size,
  323. NULL)) {
  324. *length = partInfoEx.PartitionLength.QuadPart;
  325. return S_OK;
  326. }
  327. /*
  328. * For Win2K systems we should use the old ioctl
  329. */
  330. if (DeviceIoControl(
  331. handle,
  332. IOCTL_DISK_GET_PARTITION_INFO,
  333. NULL,
  334. 0,
  335. &partInfo,
  336. sizeof(PARTITION_INFORMATION),
  337. &size,
  338. NULL)) {
  339. *length = partInfo.PartitionLength.QuadPart;
  340. return S_OK;
  341. }
  342. return E_FAIL;
  343. }
  344. HRESULT
  345. LowReadSectors(
  346. HANDLE handle,
  347. ULONG sectorSize,
  348. ULONG startingSector,
  349. ULONG numberOfSectors,
  350. PVOID buffer
  351. )
  352. {
  353. IO_STATUS_BLOCK statusBlock;
  354. LARGE_INTEGER byteOffset;
  355. byteOffset.QuadPart = UInt32x32To64(startingSector, sectorSize);
  356. statusBlock.Status = 0;
  357. statusBlock.Information = 0;
  358. if (!NT_SUCCESS(NtReadFile(
  359. handle,
  360. 0,
  361. NULL,
  362. NULL,
  363. &statusBlock,
  364. buffer,
  365. numberOfSectors * sectorSize,
  366. &byteOffset,
  367. NULL))) {
  368. return E_FAIL;
  369. }
  370. return S_OK;
  371. }
  372. HRESULT
  373. LowWriteSectors(
  374. HANDLE handle,
  375. ULONG sectorSize,
  376. ULONG startingSector,
  377. ULONG numberOfSectors,
  378. PVOID buffer
  379. )
  380. {
  381. IO_STATUS_BLOCK statusBlock;
  382. LARGE_INTEGER byteOffset;
  383. byteOffset.QuadPart = UInt32x32To64(startingSector, sectorSize);
  384. statusBlock.Status = 0;
  385. statusBlock.Information = 0;
  386. if (!NT_SUCCESS(NtWriteFile(
  387. handle,
  388. 0,
  389. NULL,
  390. NULL,
  391. &statusBlock,
  392. buffer,
  393. numberOfSectors * sectorSize,
  394. &byteOffset,
  395. NULL))) {
  396. return E_FAIL;
  397. }
  398. return S_OK;
  399. }
  400. HRESULT
  401. LowFsLock(
  402. HANDLE handle
  403. )
  404. {
  405. ULONG size;
  406. if (!DeviceIoControl(
  407. handle,
  408. FSCTL_LOCK_VOLUME,
  409. NULL,
  410. 0,
  411. NULL,
  412. 0,
  413. &size,
  414. NULL)) {
  415. return E_FAIL;
  416. }
  417. return S_OK;
  418. }
  419. HRESULT
  420. LowFsUnlock(
  421. HANDLE handle
  422. )
  423. {
  424. ULONG size;
  425. if (!DeviceIoControl(
  426. handle,
  427. FSCTL_UNLOCK_VOLUME,
  428. NULL,
  429. 0,
  430. NULL,
  431. 0,
  432. &size,
  433. NULL)) {
  434. return E_FAIL;
  435. }
  436. return S_OK;
  437. }
  438. HRESULT
  439. LowFsDismount(
  440. HANDLE handle
  441. )
  442. {
  443. ULONG size;
  444. if (!DeviceIoControl(
  445. handle,
  446. FSCTL_DISMOUNT_VOLUME,
  447. NULL,
  448. 0,
  449. NULL,
  450. 0,
  451. &size,
  452. NULL)) {
  453. return E_FAIL;
  454. }
  455. return S_OK;
  456. }
  457. LONGLONG
  458. RoundUp(
  459. LONGLONG value,
  460. LONGLONG factor
  461. )
  462. /*
  463. * Rounds a value up to a multiple of a given number
  464. */
  465. {
  466. // This is the most common case so treat it separately
  467. if (value % factor == 0) {
  468. return value;
  469. }
  470. // And this is the generic formula
  471. return ((LONGLONG)((value + factor - 1) / factor)) * factor;
  472. }
  473. LONGLONG
  474. RoundDown(
  475. LONGLONG value,
  476. LONGLONG factor
  477. )
  478. /*
  479. * Rounds a value down to a multiple of a given number
  480. */
  481. {
  482. // This is the most common case so treat it separately
  483. if (value % factor == 0) {
  484. return value;
  485. }
  486. //And this the generic formula
  487. return ((LONGLONG)(value / factor)) * factor;
  488. }