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.

1521 lines
37 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. sectorio.c
  5. Abstract:
  6. Routines to perform low-level sector I/O on either Windows NT or
  7. Windows 95.
  8. Author:
  9. Ted Miller (tedm) 1 Nov 1996
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <tlhelp32.h>
  15. //
  16. // Define structures for use with Win9x VWIN32.
  17. // Note: alignment must be on 1-byte boundaries for these structures.
  18. //
  19. #include <pshpack1.h>
  20. typedef struct _DIOC_REGISTERS {
  21. DWORD reg_EBX;
  22. DWORD reg_EDX;
  23. DWORD reg_ECX;
  24. DWORD reg_EAX;
  25. DWORD reg_EDI;
  26. DWORD reg_ESI;
  27. DWORD reg_Flags;
  28. } DIOC_REGISTERS;
  29. typedef struct _DIOC_DISKIO {
  30. DWORD StartSector;
  31. WORD SectorCount;
  32. LPBYTE Buffer;
  33. } DIOC_DISKIO;
  34. #include <poppack.h>
  35. //
  36. // Local prot type
  37. //
  38. BOOL
  39. NEC98_SpecialReadOrWriteNT(
  40. IN TCHAR Drive,
  41. IN OUT LPBYTE Buffer,
  42. IN BOOL Write
  43. );
  44. //
  45. // Define codes we care about for use with VWIN32
  46. //
  47. #define VWIN32_DIOC_DOS_IOCTL 1
  48. #define VWIN32_DIOC_DOS_INT25 2
  49. #define VWIN32_DIOC_DOS_INT26 3
  50. #define VWIN32_DIOC_DOS_DRIVEINFO 6 // new in OSR2
  51. #if defined(_X86_)
  52. BOOL
  53. pGetWin9xLockFlagState (
  54. IN HANDLE VWin32Vxd,
  55. IN TCHAR Drive,
  56. OUT PINT LockStatus
  57. )
  58. {
  59. DIOC_REGISTERS RegistersIn,RegistersOut;
  60. BOOL b;
  61. DWORD SizeOut;
  62. *LockStatus = 0;
  63. //
  64. // ax = generic ioctl code
  65. //
  66. RegistersIn.reg_EAX = 0x440D;
  67. //
  68. // bx = 1-based drive number
  69. //
  70. RegistersIn.reg_EBX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
  71. //
  72. // cx = 0x86C (get lock flag state)
  73. //
  74. RegistersIn.reg_ECX = 0x86C;
  75. //
  76. // Perform the lock and check carry.
  77. //
  78. b = DeviceIoControl(
  79. VWin32Vxd,
  80. VWIN32_DIOC_DOS_IOCTL,
  81. &RegistersIn,
  82. sizeof(DIOC_REGISTERS),
  83. &RegistersOut,
  84. sizeof(DIOC_REGISTERS),
  85. &SizeOut,
  86. NULL
  87. );
  88. if (b) {
  89. if (RegistersOut.reg_Flags & 1) {
  90. b = FALSE;
  91. } else {
  92. *LockStatus = RegistersOut.reg_EAX;
  93. }
  94. }
  95. return b;
  96. }
  97. #endif
  98. typedef HANDLE(WINAPI *OPENTHREAD)(DWORD, BOOL, DWORD);
  99. BOOL
  100. pMakeThreadExclusive (
  101. BOOL Lock
  102. )
  103. {
  104. HANDLE h;
  105. THREADENTRY32 e;
  106. DWORD thisThread;
  107. HANDLE threadHandle;
  108. OPENTHREAD openThreadFn;
  109. HMODULE lib;
  110. BOOL result = FALSE;
  111. lib = LoadLibrary (TEXT("kernel32.dll"));
  112. if (!lib) {
  113. goto c0;
  114. }
  115. openThreadFn = (OPENTHREAD) GetProcAddress (lib, "OpenThread");
  116. if (!openThreadFn) {
  117. //
  118. // Must be Win98 or Win98SE -- change thread priority as workaround
  119. //
  120. if (Lock) {
  121. result = SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  122. Sleep (0);
  123. } else {
  124. result = SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  125. }
  126. goto c1;
  127. }
  128. thisThread = GetCurrentThreadId();
  129. h = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
  130. if (h == INVALID_HANDLE_VALUE) {
  131. goto c1;
  132. }
  133. e.dwSize = sizeof (e);
  134. if (Thread32First (h, &e)) {
  135. do {
  136. if (e.th32ThreadID != thisThread) {
  137. threadHandle = openThreadFn (THREAD_SUSPEND_RESUME, FALSE, e.th32ThreadID);
  138. if (threadHandle) {
  139. if (Lock) {
  140. SuspendThread (threadHandle);
  141. } else {
  142. ResumeThread (threadHandle);
  143. }
  144. CloseHandle (threadHandle);
  145. }
  146. }
  147. } while (Thread32Next (h, &e));
  148. }
  149. CloseHandle (h);
  150. result = TRUE;
  151. c1:
  152. FreeLibrary (lib);
  153. c0:
  154. return result;
  155. }
  156. #if defined(_X86_)
  157. BOOL
  158. ReadOrWriteSectorsWin9xOriginal(
  159. IN HANDLE VWin32Vxd,
  160. IN TCHAR Drive,
  161. IN UINT StartSector,
  162. IN UINT SectorCount,
  163. IN OUT LPBYTE Buffer,
  164. IN BOOL Write
  165. )
  166. /*++
  167. Routine Description:
  168. Common routine to read or write sectors on a disk under Windows 95
  169. earlier than OSR2. Uses int25/26.
  170. This routine will fail on Windows NT.
  171. Arguments:
  172. VWin32Vxd - supplies Win32 handle to VWIN32 VxD.
  173. Drive - supplies drive letter of device to be read from or written to.
  174. StartSector - supplies logical sector number of first sector to be
  175. read/written.
  176. SectorCount - supplies number of sectors to be read/written.
  177. SectorSize - supplies the number of bytes in a sector on the drive
  178. to be read from/written to.
  179. Buffer - Supplies or receives data, depending on the value or the Write
  180. parameter.
  181. Write - if 0, then this is a read operastion. If non-0, then this is
  182. a write operation.
  183. Return Value:
  184. Boolean value indicating whether the disk was read/written successfully.
  185. --*/
  186. {
  187. DIOC_REGISTERS RegistersIn,RegistersOut;
  188. DIOC_DISKIO Params;
  189. BOOL b;
  190. DWORD SizeOut;
  191. //
  192. // Set up registers and parameter block.
  193. //
  194. RegistersIn.reg_EAX = (DWORD)(TOUPPER(Drive) - TEXT('A'));
  195. RegistersIn.reg_EBX = (DWORD)&Params;
  196. RegistersIn.reg_ECX = 0xFFFF;
  197. Params.StartSector = StartSector;
  198. Params.SectorCount = (WORD)SectorCount;
  199. Params.Buffer = Buffer;
  200. //
  201. // Do the real work.
  202. //
  203. b = DeviceIoControl(
  204. VWin32Vxd,
  205. Write ? VWIN32_DIOC_DOS_INT26 : VWIN32_DIOC_DOS_INT25,
  206. &RegistersIn,
  207. sizeof(DIOC_REGISTERS),
  208. &RegistersOut,
  209. sizeof(DIOC_REGISTERS),
  210. &SizeOut,
  211. NULL
  212. );
  213. //
  214. // Check carry flag for failure.
  215. //
  216. if(b && (RegistersOut.reg_Flags & 1)) {
  217. b = FALSE;
  218. }
  219. return(b);
  220. }
  221. BOOL
  222. ReadOrWriteSectorsWin9xOsr2(
  223. IN HANDLE VWin32Vxd,
  224. IN TCHAR Drive,
  225. IN UINT StartSector,
  226. IN UINT SectorCount,
  227. IN OUT LPBYTE Buffer,
  228. IN BOOL Write
  229. )
  230. /*++
  231. Routine Description:
  232. Common routine to read or write sectors on a disk under Windows 95
  233. OSR2 or later. Uses the new int21 function 7305 (Ext_ABSDiskReadWrite).
  234. This routine will fail on Windows NT and earlier versions of Windows 95.
  235. Arguments:
  236. VWin32Vxd - supplies Win32 handle to VWIN32 VxD.
  237. Drive - supplies drive letter of device to be read from or written to.
  238. StartSector - supplies logical sector number of first sector to be
  239. read/written.
  240. SectorCount - supplies number of sectors to be read/written.
  241. SectorSize - supplies the number of bytes in a sector on the drive
  242. to be read from/written to.
  243. Buffer - Supplies or receives data, depending on the value or the Write
  244. parameter.
  245. Write - if 0, then this is a read operastion. If non-0, then this is
  246. a write operation.
  247. Return Value:
  248. Boolean value indicating whether the disk was read/written successfully.
  249. --*/
  250. {
  251. DIOC_REGISTERS RegistersIn,RegistersOut;
  252. DIOC_DISKIO Params;
  253. BOOL b;
  254. DWORD SizeOut;
  255. //
  256. // Set up registers and parameter block.
  257. //
  258. RegistersIn.reg_EAX = 0x7305;
  259. RegistersIn.reg_EBX = (DWORD)&Params;
  260. RegistersIn.reg_ECX = 0xFFFF;
  261. RegistersIn.reg_EDX = (DWORD)(TOUPPER(Drive) - TEXT('A')) + 1;
  262. RegistersIn.reg_ESI = Write ? 1 : 0;
  263. Params.StartSector = StartSector;
  264. Params.SectorCount = (WORD)SectorCount;
  265. Params.Buffer = Buffer;
  266. //
  267. // Do the real work.
  268. //
  269. b = DeviceIoControl(
  270. VWin32Vxd,
  271. VWIN32_DIOC_DOS_DRIVEINFO,
  272. &RegistersIn,
  273. sizeof(DIOC_REGISTERS),
  274. &RegistersOut,
  275. sizeof(DIOC_REGISTERS),
  276. &SizeOut,
  277. NULL
  278. );
  279. //
  280. // Check carry flag for failure.
  281. //
  282. if(b && (RegistersOut.reg_Flags & 1)) {
  283. b = FALSE;
  284. }
  285. return(b);
  286. }
  287. BOOL
  288. LockOrUnlockVolumeWin9x(
  289. IN HANDLE VWin32Vxd,
  290. IN TCHAR Drive,
  291. IN UINT Level,
  292. IN BOOL Lock
  293. )
  294. {
  295. DIOC_REGISTERS RegistersIn,RegistersOut;
  296. BOOL b;
  297. DWORD SizeOut;
  298. BOOL Pass;
  299. Pass = 0;
  300. retry:
  301. //
  302. // ax = generic ioctl code
  303. //
  304. RegistersIn.reg_EAX = 0x440d;
  305. //
  306. // bl = 1-based drive number
  307. // bh = lock level
  308. //
  309. RegistersIn.reg_EBX = (DWORD)(TOUPPER(Drive) - TEXT('A')) + 1;
  310. RegistersIn.reg_EBX |= (Level << 8);
  311. //
  312. // cl = lock or unlock volume code
  313. // ch = categoey, 8 on original Win95, 0x48 on OSR2
  314. //
  315. RegistersIn.reg_ECX = Lock ? 0x4a : 0x6a;
  316. RegistersIn.reg_ECX |= ((ISOSR2() && !Pass) ? 0x4800 : 0x800);
  317. //
  318. // dx = permissions
  319. //
  320. // bit 0 controls write operations (0 = disallowed)
  321. // bit 1 controls read operations (0 = allowed)
  322. //
  323. RegistersIn.reg_EDX = 1;
  324. //
  325. // Perform the lock and check carry.
  326. //
  327. b = DeviceIoControl(
  328. VWin32Vxd,
  329. VWIN32_DIOC_DOS_IOCTL,
  330. &RegistersIn,
  331. sizeof(DIOC_REGISTERS),
  332. &RegistersOut,
  333. sizeof(DIOC_REGISTERS),
  334. &SizeOut,
  335. NULL
  336. );
  337. if(b && (RegistersOut.reg_Flags & 1)) {
  338. b = FALSE;
  339. }
  340. //
  341. // If OSR2, try form of call with 8 in ch instead of 48.
  342. //
  343. if(!b && ISOSR2() && !Pass) {
  344. Pass = 1;
  345. goto retry;
  346. }
  347. return(b);
  348. }
  349. BOOL
  350. ReadOrWriteSectorsWin9x(
  351. IN TCHAR Drive,
  352. IN UINT StartSector,
  353. IN UINT SectorCount,
  354. IN OUT LPBYTE Buffer,
  355. IN BOOL Write
  356. )
  357. /*++
  358. Routine Description:
  359. Common routine to read or write sectors on a disk under Windows 95.
  360. This routine will fail on Windows NT. After opening the VWIN32
  361. VxD, the routine determines whether to use the original algorithm
  362. or the OSR2 algorithm, and calls the appropriate worker routine.
  363. Arguments:
  364. Drive - supplies drive letter of device to be read from or written to.
  365. StartSector - supplies logical sector number of first sector to be
  366. read/written.
  367. SectorCount - supplies number of sectors to be read/written.
  368. SectorSize - supplies the number of bytes in a sector on the drive
  369. to be read from/written to.
  370. Buffer - Supplies or receives data, depending on the value or the Write
  371. parameter.
  372. Write - if 0, then this is a read operastion. If non-0, then this is
  373. a write operation.
  374. Return Value:
  375. Boolean value indicating whether the disk was read/written successfully.
  376. If failure, last error is set to something meaningful.
  377. --*/
  378. {
  379. HANDLE hVxd;
  380. BOOL b;
  381. DWORD d;
  382. INT level;
  383. INT retry = 100;
  384. //
  385. // This thread must be the exclusive thread in our process
  386. //
  387. pMakeThreadExclusive (TRUE);
  388. //
  389. // Open VWIN32.VXD
  390. //
  391. hVxd = CreateFileA(
  392. "\\\\.\\VWIN32",
  393. Write ? GENERIC_WRITE : GENERIC_READ,
  394. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  395. NULL,
  396. OPEN_EXISTING,
  397. FILE_ATTRIBUTE_NORMAL,
  398. NULL
  399. );
  400. if(hVxd == INVALID_HANDLE_VALUE) {
  401. d = GetLastError();
  402. b = FALSE;
  403. goto c0;
  404. }
  405. //
  406. // Take out locks. We'll be as unrestrictive as possible.
  407. // The locking stuff is really funky. You have to pass in all kinds of
  408. // different parameters in OSR2 for reasons unknown. Also the
  409. // permissions bits are strangely encoded.
  410. //
  411. if(!LockOrUnlockVolumeWin9x(hVxd,Drive,1,TRUE)) {
  412. d = ERROR_SHARING_VIOLATION;
  413. b = FALSE;
  414. goto c1;
  415. }
  416. if(!LockOrUnlockVolumeWin9x(hVxd,Drive,2,TRUE)) {
  417. d = ERROR_SHARING_VIOLATION;
  418. b = FALSE;
  419. goto c2;
  420. }
  421. //
  422. // Try to get the level 3 lock. Retry if something happened while
  423. // getting the lock. Fail after too many retries.
  424. //
  425. do {
  426. if(!LockOrUnlockVolumeWin9x(hVxd,Drive,3,TRUE)) {
  427. d = ERROR_SHARING_VIOLATION;
  428. b = FALSE;
  429. goto c3;
  430. }
  431. if (!pGetWin9xLockFlagState (hVxd, Drive, &level)) {
  432. // unexpected -- INT 21h call failed
  433. break;
  434. }
  435. if (!level) {
  436. // We successfully got a clean level 3 lock
  437. break;
  438. }
  439. LockOrUnlockVolumeWin9x(hVxd,Drive,3,FALSE);
  440. retry--;
  441. } while (retry);
  442. if (!retry) {
  443. d = ERROR_SHARING_VIOLATION;
  444. b = FALSE;
  445. goto c3;
  446. }
  447. //
  448. // Go do it.
  449. //
  450. b = ISOSR2()
  451. ? ReadOrWriteSectorsWin9xOsr2(hVxd,Drive,StartSector,SectorCount,Buffer,Write)
  452. : ReadOrWriteSectorsWin9xOriginal(hVxd,Drive,StartSector,SectorCount,Buffer,Write);
  453. //
  454. // If it failed, and OSR2 routine is being used, fall back to Win95 API. This is a workaround
  455. // for Compaq because they ship OSR2 without the new OSR2 sector API support!
  456. //
  457. if (!b && ISOSR2()) {
  458. b = ReadOrWriteSectorsWin9xOriginal(hVxd,Drive,StartSector,SectorCount,Buffer,Write);
  459. }
  460. d = GetLastError();
  461. LockOrUnlockVolumeWin9x(hVxd,Drive,3,FALSE);
  462. c3:
  463. LockOrUnlockVolumeWin9x(hVxd,Drive,2,FALSE);
  464. c2:
  465. LockOrUnlockVolumeWin9x(hVxd,Drive,1,FALSE);
  466. c1:
  467. CloseHandle(hVxd);
  468. c0:
  469. //
  470. // Resume all threads
  471. //
  472. pMakeThreadExclusive (FALSE);
  473. SetLastError(d);
  474. return(b);
  475. }
  476. #endif
  477. BOOL
  478. ReadOrWriteSectorsWinNt(
  479. IN TCHAR Drive,
  480. IN UINT StartSector,
  481. IN UINT SectorCount,
  482. IN UINT SectorSize,
  483. IN OUT LPBYTE Buffer,
  484. IN BOOL Write
  485. )
  486. /*++
  487. Routine Description:
  488. Common routine to read or write sectors on a disk under Windows NT.
  489. This routine will fail on Win9x.
  490. Arguments:
  491. Drive - supplies drive letter of device to be read from or written to.
  492. StartSector - supplies logical sector number of first sector to be
  493. read/written.
  494. SectorCount - supplies number of sectors to be read/written.
  495. SectorSize - supplies the number of bytes in a sector on the drive
  496. to be read from/written to.
  497. Buffer - Supplies or receives data, depending on the value or the Write
  498. parameter. This buffer must be aligned on a sector boundary.
  499. Write - if 0, then this is a read operastion. If non-0, then this is
  500. a write operation.
  501. Return Value:
  502. Boolean value indicating whether the disk was read/written successfully.
  503. If failure, last error is set.
  504. --*/
  505. {
  506. HANDLE h;
  507. BOOL b;
  508. DWORD BytesXferred;
  509. TCHAR DeviceName[7];
  510. LONGLONG Offset;
  511. LONG OffsetHigh;
  512. DWORD d;
  513. #if defined(_X86_)
  514. if (IsNEC98() && (StartSector == 0) && (SectorCount == 1)){
  515. return(NEC98_SpecialReadOrWriteNT(Drive, Buffer, Write));
  516. }
  517. #endif
  518. //
  519. // Open the device
  520. //
  521. wsprintf(DeviceName,TEXT("\\\\.\\%c:"),Drive);
  522. h = CreateFile(
  523. DeviceName,
  524. Write ? GENERIC_WRITE : GENERIC_READ,
  525. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  526. NULL,
  527. OPEN_EXISTING,
  528. FILE_ATTRIBUTE_NORMAL,
  529. NULL
  530. );
  531. if(h == INVALID_HANDLE_VALUE) {
  532. d = GetLastError();
  533. b = FALSE;
  534. goto c0;
  535. }
  536. Offset = (LONGLONG)StartSector * (LONGLONG)SectorSize;
  537. OffsetHigh = (LONG)(Offset >> 32);
  538. //
  539. // We're passing in a 64-bit offset so we have to check last error
  540. // to distinguish the error case.
  541. //
  542. if((SetFilePointer(h,(DWORD)Offset,&OffsetHigh,FILE_BEGIN) == 0xffffffff)
  543. && (GetLastError() != NO_ERROR)) {
  544. d = GetLastError();
  545. b = FALSE;
  546. goto c1;
  547. }
  548. b = Write
  549. ? WriteFile(h,Buffer,SectorCount*SectorSize,&BytesXferred,NULL)
  550. : ReadFile(h,Buffer,SectorCount*SectorSize,&BytesXferred,NULL);
  551. d = GetLastError();
  552. c1:
  553. CloseHandle(h);
  554. c0:
  555. SetLastError(d);
  556. return(b);
  557. }
  558. BOOL
  559. ReadOrWriteSectors(
  560. IN TCHAR Drive,
  561. IN UINT StartSector,
  562. IN UINT SectorCount,
  563. IN UINT SectorSize,
  564. IN OUT LPBYTE Buffer,
  565. IN BOOL Write
  566. )
  567. /*++
  568. Routine Description:
  569. Common routine to read or write sectors on a disk. Allocates a properly
  570. aligned buffer and decides whether to call NT- or Win9x-specific
  571. i/o routine.
  572. Arguments:
  573. Drive - supplies drive letter of device to be read from or written to.
  574. StartSector - supplies logical sector number of first sector to be
  575. read/written.
  576. SectorCount - supplies number of sectors to be read/written.
  577. SectorSize - supplies the number of bytes in a sector on the drive
  578. to be read from/written to.
  579. Buffer - Supplies or receives data, depending on the value or the Write
  580. parameter. There are no alignment requirements on ths buffer.
  581. Write - if 0, then this is a read operastion. If non-0, then this is
  582. a write operation.
  583. Return Value:
  584. Boolean value indicating whether the disk was read/written successfully.
  585. Last error is undisturbed from the operation that caused any failure.
  586. --*/
  587. {
  588. LPBYTE AlignedBuffer;
  589. LPBYTE p;
  590. BOOL b;
  591. DWORD_PTR d;
  592. //
  593. // Allocate a buffer we will align on a sector boundary.
  594. //
  595. if(AlignedBuffer = MALLOC((SectorCount * SectorSize) + (SectorSize - 1))) {
  596. if(d = (DWORD_PTR)AlignedBuffer % SectorSize) {
  597. p = (PUCHAR)((DWORD_PTR)AlignedBuffer + (SectorSize - d));
  598. } else {
  599. p = AlignedBuffer;
  600. }
  601. if(Write) {
  602. CopyMemory(p,Buffer,SectorCount*SectorSize);
  603. }
  604. #if defined(_X86_)
  605. b = ISNT()
  606. ? ReadOrWriteSectorsWinNt(Drive,StartSector,SectorCount,SectorSize,p,Write)
  607. : ReadOrWriteSectorsWin9x(Drive,StartSector,SectorCount,p,Write);
  608. #elif defined(_AMD64_)
  609. b = ReadOrWriteSectorsWinNt(Drive,StartSector,SectorCount,SectorSize,p,Write);
  610. #else
  611. #error "Invalid Architeture"
  612. #endif
  613. d = GetLastError();
  614. if(b && !Write) {
  615. CopyMemory(Buffer,p,SectorCount*SectorSize);
  616. }
  617. FREE(AlignedBuffer);
  618. } else {
  619. b = FALSE;
  620. d = ERROR_NOT_ENOUGH_MEMORY;
  621. }
  622. SetLastError((DWORD)d);
  623. return(b);
  624. }
  625. BOOL
  626. ReadDiskSectors(
  627. IN TCHAR Drive,
  628. IN UINT StartSector,
  629. IN UINT SectorCount,
  630. IN UINT SectorSize,
  631. OUT LPBYTE Buffer
  632. )
  633. /*++
  634. Routine Description:
  635. Read a set of disk sectors off a disk device.
  636. Arguments:
  637. Drive - supplies drive letter of device to be read from.
  638. StartSector - supplies logical sector number of first sector to be read.
  639. SectorCount - supplies number of sectors to be read.
  640. SectorSize - supplies the number of bytes in a sector on the drive
  641. to be read from.
  642. Buffer - if successful, receives data from the disk. There are no
  643. alignment requirements on ths buffer.
  644. Return Value:
  645. Boolean value indicating whether the disk was read successfully.
  646. --*/
  647. {
  648. return(ReadOrWriteSectors(Drive,StartSector,SectorCount,SectorSize,Buffer,FALSE));
  649. }
  650. BOOL
  651. WriteDiskSectors(
  652. IN TCHAR Drive,
  653. IN UINT StartSector,
  654. IN UINT SectorCount,
  655. IN UINT SectorSize,
  656. IN LPBYTE Buffer
  657. )
  658. /*++
  659. Routine Description:
  660. Write data to a set of disk sectors.
  661. Arguments:
  662. Drive - supplies drive letter of device to be written to.
  663. StartSector - supplies logical sector number of first sector to be written.
  664. SectorCount - supplies number of sectors to be written.
  665. SectorSize - supplies the number of bytes in a sector on the drive
  666. to be written to.
  667. Buffer - supplies data to be written. There are no alignment requirements
  668. on ths buffer.
  669. Return Value:
  670. Boolean value indicating whether the disk was successfully written.
  671. --*/
  672. {
  673. return(ReadOrWriteSectors(Drive,StartSector,SectorCount,SectorSize,Buffer,TRUE));
  674. }
  675. MEDIA_TYPE
  676. GetMediaTypeNt(
  677. IN TCHAR Drive,
  678. IN PWINNT32_DRIVE_INFORMATION DriveInfo
  679. )
  680. /*++
  681. Routine Description:
  682. Determine the type/form-factor of a given (floppy) drive.
  683. THIS ROUTINE WORKS ONLY ON WINDOWS NT.
  684. Arguments:
  685. Drive - supplies drive letter of the drive in question.
  686. Return Value:
  687. Value from the MEDIA_TYPE enum indicating the drive type, which is
  688. derived from the largest media that the device driver indicates the
  689. drive can support.
  690. LastError is not set or preserved.
  691. --*/
  692. {
  693. TCHAR DeviceName[7];
  694. HANDLE h;
  695. BOOL b;
  696. BYTE Buffer[5000];
  697. DWORD Size;
  698. DWORD d;
  699. UINT u;
  700. PDISK_GEOMETRY Geometry;
  701. MEDIA_TYPE MediaTypeOrder[] = { FixedMedia, // Fixed hard disk media
  702. RemovableMedia, // Removable media other than floppy
  703. F3_120M_512, // 3.5", 120M Floppy
  704. F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
  705. F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
  706. F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
  707. F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
  708. F3_720_512, // 3.5", 720KB, 512 bytes/sector
  709. F5_360_512, // 5.25", 360KB, 512 bytes/sector
  710. F5_320_1024, // 5.25", 320KB, 1024 bytes/sector
  711. F5_320_512, // 5.25", 320KB, 512 bytes/sector
  712. F5_180_512, // 5.25", 180KB, 512 bytes/sector
  713. F5_160_512, // 5.25", 160KB, 512 bytes/sector
  714. Unknown, // Format is unknown
  715. -1
  716. };
  717. //
  718. // We don't return drive information for NT
  719. //
  720. if (DriveInfo) {
  721. memset(DriveInfo, 0, sizeof(WINNT32_DRIVE_INFORMATION));
  722. }
  723. wsprintf(DeviceName,TEXT("\\\\.\\%c:"),Drive);
  724. h = CreateFile(
  725. DeviceName,
  726. FILE_READ_ATTRIBUTES,
  727. FILE_SHARE_READ | FILE_SHARE_WRITE,
  728. NULL,
  729. OPEN_EXISTING,
  730. 0,
  731. NULL
  732. );
  733. if(h == INVALID_HANDLE_VALUE) {
  734. return(Unknown);
  735. }
  736. b = DeviceIoControl(
  737. h,
  738. IOCTL_DISK_GET_MEDIA_TYPES,
  739. NULL,
  740. 0,
  741. Buffer,
  742. sizeof(Buffer),
  743. &Size,
  744. NULL
  745. );
  746. CloseHandle(h);
  747. if(!b) {
  748. return(Unknown);
  749. }
  750. Geometry = (PDISK_GEOMETRY)Buffer;
  751. //
  752. // Inefficient, but it works.
  753. //
  754. for(u=0; MediaTypeOrder[u] != -1; u++) {
  755. for(d=0; d<Size/sizeof(DISK_GEOMETRY); d++) {
  756. if(Geometry[d].MediaType == MediaTypeOrder[u]) {
  757. return(Geometry[d].MediaType);
  758. }
  759. }
  760. }
  761. //
  762. // We don't know what it is; assume it's some hot new type.
  763. //
  764. return(Size ? Geometry[0].MediaType : Unknown);
  765. }
  766. #if defined(_X86_)
  767. MEDIA_TYPE
  768. GetMediaTypeWin9x(
  769. IN TCHAR Drive,
  770. IN PWINNT32_DRIVE_INFORMATION DriveInfo
  771. )
  772. /*++
  773. Routine Description:
  774. Determine the type/form-factor of a given (floppy) drive.
  775. THIS ROUTINE WORKS ONLY ON WINDOWS 9x.
  776. Arguments:
  777. Drive - supplies drive letter of the drive in question.
  778. Return Value:
  779. Value from the MEDIA_TYPE enum indicating the drive type, which is
  780. derived from the device type in the recommended BPB returned by
  781. the device driver for the drive.
  782. LastError is not set or preserved.
  783. --*/
  784. {
  785. HANDLE hVxd;
  786. DIOC_REGISTERS RegistersIn,RegistersOut;
  787. BOOL b;
  788. DWORD SizeOut;
  789. MEDIA_TYPE type;
  790. #include <pshpack1.h>
  791. struct {
  792. BYTE SpecialFunctions;
  793. BYTE DeviceType;
  794. WORD DeviceAttributes;
  795. WORD CylinderCount;
  796. BYTE MediaType;
  797. WORD BytesPerSector;
  798. BYTE SectorsPerCluster;
  799. WORD ReservedSectors;
  800. BYTE FatCount;
  801. WORD RootDirEntries;
  802. WORD SectorCount;
  803. BYTE MediaDescriptor;
  804. WORD SectorsPerFat;
  805. WORD SectorsPerTrack;
  806. WORD Heads;
  807. DWORD HiddenSectors;
  808. DWORD LargeSectorCount;
  809. } DeviceParams;
  810. #include <poppack.h>
  811. //
  812. // Open VWIN32.VXD
  813. //
  814. hVxd = CreateFileA(
  815. "\\\\.\\VWIN32",
  816. GENERIC_READ,
  817. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  818. NULL,
  819. OPEN_EXISTING,
  820. FILE_ATTRIBUTE_NORMAL,
  821. NULL
  822. );
  823. if(hVxd == INVALID_HANDLE_VALUE) {
  824. return(Unknown);
  825. }
  826. memset(&DeviceParams, 0, sizeof(DeviceParams));
  827. //
  828. // Set up registers for IOCTL call.
  829. //
  830. RegistersIn.reg_EAX = 0x440d; // IOCTL
  831. RegistersIn.reg_EBX = (Drive - TEXT('A')) + 1; // 1-based drive in bl
  832. RegistersIn.reg_ECX = 0x860; // category = 8, func = get device params
  833. RegistersIn.reg_EDX = (DWORD)&DeviceParams;
  834. DeviceParams.SpecialFunctions = 0;
  835. b = DeviceIoControl(
  836. hVxd,
  837. VWIN32_DIOC_DOS_IOCTL,
  838. &RegistersIn,
  839. sizeof(DIOC_REGISTERS),
  840. &RegistersOut,
  841. sizeof(DIOC_REGISTERS),
  842. &SizeOut,
  843. NULL
  844. );
  845. CloseHandle(hVxd);
  846. if(!b && !(RegistersOut.reg_Flags & 1)) {
  847. return(Unknown);
  848. }
  849. if (DriveInfo) {
  850. memset(DriveInfo, 0, sizeof(WINNT32_DRIVE_INFORMATION));
  851. DriveInfo->CylinderCount = (DWORD)(DeviceParams.CylinderCount);
  852. DriveInfo->HeadCount = (DWORD)(DeviceParams.Heads);
  853. DriveInfo->SectorsPerTrack = (DWORD)(DeviceParams.SectorsPerTrack);
  854. DriveInfo->BytesPerSector = DeviceParams.BytesPerSector;
  855. DriveInfo->SectorCount = (ULONGLONG)((DriveInfo->CylinderCount *
  856. DriveInfo->HeadCount * DriveInfo->SectorsPerTrack));
  857. }
  858. switch(DeviceParams.DeviceType) {
  859. case 0:
  860. type = F5_360_512; // close enough
  861. break;
  862. case 1:
  863. type = F5_1Pt2_512;
  864. break;
  865. case 2:
  866. type = F3_720_512;
  867. break;
  868. case 5:
  869. type = FixedMedia;
  870. break;
  871. case 7:
  872. type = F3_1Pt44_512;
  873. break;
  874. case 8:
  875. type = RemovableMedia;
  876. break;
  877. case 9:
  878. type = F3_2Pt88_512;
  879. break;
  880. default:
  881. type = Unknown;
  882. break;
  883. }
  884. return(type);
  885. }
  886. #endif
  887. MEDIA_TYPE
  888. GetMediaType(
  889. IN TCHAR Drive,
  890. IN PWINNT32_DRIVE_INFORMATION DriveInfo
  891. )
  892. {
  893. #if defined(_X86_)
  894. return(ISNT() ? GetMediaTypeNt(Drive, DriveInfo) : GetMediaTypeWin9x(Drive, DriveInfo));
  895. #elif defined(_AMD64_)
  896. return GetMediaTypeNt(Drive, DriveInfo);
  897. #else
  898. #error "Invalid Architecture"
  899. #endif
  900. }
  901. #if defined(_X86_)
  902. BOOL
  903. NEC98_SpecialReadOrWriteNT(
  904. IN TCHAR Drive,
  905. IN OUT LPBYTE Buffer,
  906. IN BOOL Write
  907. )
  908. /*++
  909. Routine Description:
  910. NEC98 specialn routine to boot sctor read or write sectors on a disk
  911. under Windows NT.
  912. This routine will fail on Win9x.
  913. Arguments:
  914. Drive - supplies drive letter of device to be read from or written to.
  915. Buffer - Supplies or receives data, depending on the value or the Write
  916. parameter. This buffer must be aligned on a sector boundary.
  917. Write - if 0, then this is a read operastion. If non-0, then this is
  918. a write operation.
  919. Return Value:
  920. Boolean value indicating whether the disk was read/written successfully.
  921. If failure, last error is set.
  922. --*/
  923. {
  924. TCHAR DrivePath[4];
  925. DWORD DontCare;
  926. DWORD SectorSize;
  927. HANDLE h;
  928. BOOL b;
  929. DWORD BytesXferred;
  930. TCHAR DeviceName[7];
  931. LONG OffsetHigh = 0;
  932. DWORD d;
  933. LPBYTE AlignedBuffer;
  934. LPBYTE p;
  935. //
  936. // Form root path
  937. //
  938. DrivePath[0] = Drive;
  939. DrivePath[1] = TEXT(':');
  940. DrivePath[2] = TEXT('\\');
  941. DrivePath[3] = 0;
  942. GetDiskFreeSpace(DrivePath,&DontCare,&SectorSize,&DontCare,&DontCare);
  943. if(AlignedBuffer = MALLOC(SectorSize + SectorSize - 1)) {
  944. if(d = (DWORD)AlignedBuffer % SectorSize) {
  945. p = (PUCHAR)((DWORD)AlignedBuffer + (SectorSize - d));
  946. } else {
  947. p = AlignedBuffer;
  948. }
  949. } else {
  950. b = FALSE;
  951. d = ERROR_NOT_ENOUGH_MEMORY;
  952. goto c0;
  953. }
  954. //
  955. // Open the device
  956. //
  957. wsprintf(DeviceName,TEXT("\\\\.\\%c:"),Drive);
  958. h = CreateFile(
  959. DeviceName,
  960. Write ? (GENERIC_WRITE | GENERIC_READ) : GENERIC_READ,
  961. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  962. NULL,
  963. OPEN_EXISTING,
  964. FILE_ATTRIBUTE_NORMAL,
  965. NULL
  966. );
  967. if(h == INVALID_HANDLE_VALUE) {
  968. d = GetLastError();
  969. b = FALSE;
  970. goto c1;
  971. }
  972. if (b = ReadFile(h, p, SectorSize, &BytesXferred, NULL)){
  973. if (Write){
  974. CopyMemory(p, Buffer, 512);
  975. SetFilePointer(h,(DWORD)0, &OffsetHigh,FILE_BEGIN);
  976. b = WriteFile(h, p, SectorSize, &BytesXferred,NULL);
  977. } else { // read
  978. CopyMemory(Buffer, p, 512);
  979. }
  980. }
  981. d = GetLastError();
  982. CloseHandle(h);
  983. c1:
  984. FREE(AlignedBuffer);
  985. c0:
  986. SetLastError(d);
  987. return(b);
  988. }
  989. //
  990. // Maximum partition size addressable by regular INT13
  991. // Max capacity = sector size * cylinders (10 bits) * heads (8 bits) *
  992. // sectors / track (6 bits)
  993. //
  994. #define MAX_INT13_PARTITION_CAPACITY 8455716864L // (512 * 1024 * 256 * 63) = 7.8GB
  995. #define FAT32_BPB_HEADS_FIELD_OFFSET 0x1A
  996. #define FAT32_BPB_SECTORSPERTRACK_FIELD_OFFSET 0x18
  997. typedef BOOL (*PGET_DISK_FREE_SPACE_EX) (
  998. LPCTSTR,
  999. PULONGLONG,
  1000. PULONGLONG,
  1001. PULONGLONG
  1002. );
  1003. BOOL
  1004. GetDriveSize9x(
  1005. TCHAR DriveLetter,
  1006. PULONGLONG DriveSize
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. Gets the total size of the given drive.
  1011. NOTE : First tries GetDriveFreeSpaceEx(...) if available and if
  1012. unsuccessful, tries to compute drive size using INT21h.
  1013. Arguments:
  1014. DriveLetter : Drive letter.
  1015. DriveSize : Recieves the drive size in bytes.
  1016. Return Value:
  1017. TRUE, if drive size was determined otherwise FALSE.
  1018. --*/
  1019. {
  1020. BOOL Result = FALSE;
  1021. if (DriveSize && !ISNT()) {
  1022. ULONGLONG TotalDriveSize = 0;
  1023. if (ISOSR2()) {
  1024. HMODULE Kernel32Handle = GetModuleHandle(TEXT("kernel32.dll"));
  1025. if (Kernel32Handle) {
  1026. PGET_DISK_FREE_SPACE_EX GetDiskFreeSpaceExPtr;
  1027. GetDiskFreeSpaceExPtr = (PGET_DISK_FREE_SPACE_EX)
  1028. GetProcAddress(Kernel32Handle, "GetDiskFreeSpaceEx");
  1029. if (GetDiskFreeSpaceExPtr) {
  1030. TCHAR DriveName[MAX_PATH];
  1031. ULONGLONG FreeBytes = 0, TotalSize = 0, ActualFreeBytes = 0;
  1032. DriveName[0] = DriveLetter;
  1033. DriveName[1] = TEXT(':');
  1034. DriveName[2] = TEXT('\\');
  1035. DriveName[3] = 0;
  1036. Result = GetDiskFreeSpaceExPtr(DriveName,
  1037. &FreeBytes,
  1038. &TotalSize,
  1039. &ActualFreeBytes);
  1040. if (Result) {
  1041. TotalDriveSize = TotalSize;
  1042. }
  1043. }
  1044. }
  1045. }
  1046. if (!Result) {
  1047. WINNT32_DRIVE_INFORMATION DriveInfo = {0};
  1048. GetMediaType(DriveLetter, &DriveInfo);
  1049. if (DriveInfo.SectorCount) {
  1050. TotalDriveSize = DriveInfo.SectorCount * DriveInfo.BytesPerSector;
  1051. Result = TRUE;
  1052. }
  1053. }
  1054. if (Result) {
  1055. *DriveSize = TotalDriveSize;
  1056. }
  1057. }
  1058. return Result;
  1059. }
  1060. #endif
  1061. BOOL
  1062. PatchBootCode(
  1063. IN WINNT32_SYSPART_FILESYSTEM FileSystem,
  1064. IN TCHAR DriveLetter,
  1065. IN OUT PUCHAR BootCode,
  1066. IN DWORD BootCodeSize
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. Patches the boot code if there is any inconsistent data
  1071. with the correct data
  1072. NOTE : Currently we update only FAT32 BPB for invalid head
  1073. count.
  1074. Arguments:
  1075. FileSystem : File system type to look into the buffer
  1076. DriveLetter : Drive letter.
  1077. BootCode : The actual boot code
  1078. BootCodeSize: Size of the boot code in bytes
  1079. Return Value:
  1080. TRUE, if boot code was patched successfully, otherwise FALSE.
  1081. --*/
  1082. {
  1083. BOOL Result = FALSE;
  1084. #if defined(_X86_)
  1085. if (BootCode && (FileSystem != Winnt32FsUnknown)) {
  1086. switch (FileSystem) {
  1087. case Winnt32FsFat32:
  1088. if (!ISNT() && (BootCodeSize >= (FAT32_BPB_HEADS_FIELD_OFFSET + sizeof(WORD)))) {
  1089. ULONGLONG DriveSize = 0;
  1090. PWORD NumberOfHeads = (PWORD)(BootCode + FAT32_BPB_HEADS_FIELD_OFFSET);
  1091. PWORD SectorsPerTrack = (PWORD)(BootCode + FAT32_BPB_SECTORSPERTRACK_FIELD_OFFSET);
  1092. TCHAR Buffer[MAX_PATH * 2];
  1093. Result = GetDriveSize9x(DriveLetter, &DriveSize);
  1094. if (Result) {
  1095. WINNT32_DRIVE_INFORMATION DriveInfo = {0};
  1096. //
  1097. // Get the drive information
  1098. //
  1099. GetMediaType(DriveLetter, &DriveInfo);
  1100. //
  1101. // dump the drive information
  1102. //
  1103. if (DriveInfo.BytesPerSector) {
  1104. _stprintf(Buffer,
  1105. TEXT("Drive Information (INT 21H):\r\nCylinders:%d,Heads:%d,Sectors/Track:%d,Sectors:%I64d,Bytes/Sector:%d"),
  1106. DriveInfo.CylinderCount,
  1107. DriveInfo.HeadCount,
  1108. DriveInfo.SectorsPerTrack,
  1109. DriveInfo.SectorCount,
  1110. DriveInfo.BytesPerSector);
  1111. DebugLog (Winnt32LogInformation, Buffer, 0);
  1112. //
  1113. // The heads value better match what we got from GetMediaType(...)
  1114. // If not, we patch it to the correct one.
  1115. //
  1116. if (DriveInfo.HeadCount && (((DWORD)(*NumberOfHeads)) != DriveInfo.HeadCount)) {
  1117. _stprintf(Buffer,
  1118. TEXT("Drive Information (BPB): Size=%I64u, Heads=%u, Sectors/Track=%u"),
  1119. DriveSize,
  1120. (*NumberOfHeads),
  1121. (*SectorsPerTrack));
  1122. DebugLog(Winnt32LogInformation,
  1123. TEXT("PatchBootCode: Existing %1"),
  1124. 0,
  1125. Buffer);
  1126. //
  1127. // update the heads value
  1128. //
  1129. *NumberOfHeads = (WORD)(DriveInfo.HeadCount);
  1130. _stprintf(Buffer,
  1131. TEXT("Drive Information (BPB): Size=%I64u, Heads=%u, Sectors/Track=%u"),
  1132. DriveSize,
  1133. (*NumberOfHeads),
  1134. (*SectorsPerTrack));
  1135. DebugLog(Winnt32LogInformation,
  1136. TEXT("PatchBootCode: New %1"),
  1137. 0,
  1138. Buffer);
  1139. }
  1140. } else {
  1141. DebugLog(Winnt32LogError,
  1142. TEXT("PatchBootCode:Failed to get the drive information"),
  1143. 0);
  1144. }
  1145. } else {
  1146. DebugLog(Winnt32LogError,
  1147. TEXT("PatchBootCode:Failed to get the drive size"),
  1148. 0);
  1149. }
  1150. }
  1151. break;
  1152. default :
  1153. break;
  1154. }
  1155. }
  1156. #endif
  1157. return Result;
  1158. }