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.

816 lines
17 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 "pch.h"
  13. #include <tlhelp32.h>
  14. #define ISOSR2() ISATLEASTOSR2()
  15. #define MALLOC(u) (LocalAlloc (GMEM_FIXED, u))
  16. #define FREE(u) (LocalFree (u))
  17. //
  18. // Define structures for use with Win9x VWIN32.
  19. // Note: alignment must be on 1-byte boundaries for these structures.
  20. //
  21. #include <pshpack1.h>
  22. typedef struct _DIOC_REGISTERS {
  23. DWORD reg_EBX;
  24. DWORD reg_EDX;
  25. DWORD reg_ECX;
  26. DWORD reg_EAX;
  27. DWORD reg_EDI;
  28. DWORD reg_ESI;
  29. DWORD reg_Flags;
  30. } DIOC_REGISTERS;
  31. typedef struct _DIOC_DISKIO {
  32. DWORD StartSector;
  33. WORD SectorCount;
  34. LPBYTE Buffer;
  35. } DIOC_DISKIO;
  36. #include <poppack.h>
  37. //
  38. // Define codes we care about for use with VWIN32
  39. //
  40. #define VWIN32_DIOC_DOS_IOCTL 1
  41. #define VWIN32_DIOC_DOS_INT25 2
  42. #define VWIN32_DIOC_DOS_INT26 3
  43. #define VWIN32_DIOC_DOS_DRIVEINFO 6 // new in OSR2
  44. BOOL
  45. ReadOrWriteSectorsWin9xOriginal(
  46. IN HANDLE VWin32Vxd,
  47. IN TCHAR Drive,
  48. IN UINT StartSector,
  49. IN UINT SectorCount,
  50. IN OUT LPBYTE Buffer,
  51. IN BOOL Write
  52. )
  53. /*++
  54. Routine Description:
  55. Common routine to read or write sectors on a disk under Windows 95
  56. earlier than OSR2. Uses int25/26.
  57. This routine will fail on Windows NT.
  58. Arguments:
  59. VWin32Vxd - supplies Win32 handle to VWIN32 VxD.
  60. Drive - supplies drive letter of device to be read from or written to.
  61. StartSector - supplies logical sector number of first sector to be
  62. read/written.
  63. SectorCount - supplies number of sectors to be read/written.
  64. SectorSize - supplies the number of bytes in a sector on the drive
  65. to be read from/written to.
  66. Buffer - Supplies or receives data, depending on the value or the Write
  67. parameter.
  68. Write - if 0, then this is a read operastion. If non-0, then this is
  69. a write operation.
  70. Return Value:
  71. Boolean value indicating whether the disk was read/written successfully.
  72. --*/
  73. {
  74. DIOC_REGISTERS RegistersIn,RegistersOut;
  75. DIOC_DISKIO Params;
  76. BOOL b;
  77. DWORD SizeOut;
  78. //
  79. // Set up registers and parameter block.
  80. //
  81. RegistersIn.reg_EAX = (DWORD)(_totupper(Drive) - TEXT('A'));
  82. RegistersIn.reg_EBX = (DWORD)&Params;
  83. RegistersIn.reg_ECX = 0xFFFF;
  84. Params.StartSector = StartSector;
  85. Params.SectorCount = (WORD)SectorCount;
  86. Params.Buffer = Buffer;
  87. //
  88. // Do the real work.
  89. //
  90. b = DeviceIoControl(
  91. VWin32Vxd,
  92. Write ? VWIN32_DIOC_DOS_INT26 : VWIN32_DIOC_DOS_INT25,
  93. &RegistersIn,
  94. sizeof(DIOC_REGISTERS),
  95. &RegistersOut,
  96. sizeof(DIOC_REGISTERS),
  97. &SizeOut,
  98. NULL
  99. );
  100. //
  101. // Check carry flag for failure.
  102. //
  103. if(b && (RegistersOut.reg_Flags & 1)) {
  104. b = FALSE;
  105. }
  106. return(b);
  107. }
  108. BOOL
  109. ReadOrWriteSectorsWin9xOsr2(
  110. IN HANDLE VWin32Vxd,
  111. IN TCHAR Drive,
  112. IN UINT StartSector,
  113. IN UINT SectorCount,
  114. IN OUT LPBYTE Buffer,
  115. IN BOOL Write
  116. )
  117. /*++
  118. Routine Description:
  119. Common routine to read or write sectors on a disk under Windows 95
  120. OSR2 or later. Uses the new int21 function 7305 (Ext_ABSDiskReadWrite).
  121. This routine will fail on Windows NT and earlier versions of Windows 95.
  122. Arguments:
  123. VWin32Vxd - supplies Win32 handle to VWIN32 VxD.
  124. Drive - supplies drive letter of device to be read from or written to.
  125. StartSector - supplies logical sector number of first sector to be
  126. read/written.
  127. SectorCount - supplies number of sectors to be read/written.
  128. SectorSize - supplies the number of bytes in a sector on the drive
  129. to be read from/written to.
  130. Buffer - Supplies or receives data, depending on the value or the Write
  131. parameter.
  132. Write - if 0, then this is a read operastion. If non-0, then this is
  133. a write operation.
  134. Return Value:
  135. Boolean value indicating whether the disk was read/written successfully.
  136. --*/
  137. {
  138. DIOC_REGISTERS RegistersIn,RegistersOut;
  139. DIOC_DISKIO Params;
  140. BOOL b;
  141. DWORD SizeOut;
  142. //
  143. // Set up registers and parameter block.
  144. //
  145. RegistersIn.reg_EAX = 0x7305;
  146. RegistersIn.reg_EBX = (DWORD)&Params;
  147. RegistersIn.reg_ECX = 0xFFFF;
  148. RegistersIn.reg_EDX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
  149. RegistersIn.reg_ESI = Write ? 1 : 0;
  150. Params.StartSector = StartSector;
  151. Params.SectorCount = (WORD)SectorCount;
  152. Params.Buffer = Buffer;
  153. //
  154. // Do the real work.
  155. //
  156. b = DeviceIoControl(
  157. VWin32Vxd,
  158. VWIN32_DIOC_DOS_DRIVEINFO,
  159. &RegistersIn,
  160. sizeof(DIOC_REGISTERS),
  161. &RegistersOut,
  162. sizeof(DIOC_REGISTERS),
  163. &SizeOut,
  164. NULL
  165. );
  166. //
  167. // Check carry flag for failure.
  168. //
  169. if(b && (RegistersOut.reg_Flags & 1)) {
  170. b = FALSE;
  171. SetLastError (ERROR_IO_DEVICE);
  172. }
  173. return(b);
  174. }
  175. BOOL
  176. LockOrUnlockVolumeWin9x(
  177. IN HANDLE VWin32Vxd,
  178. IN TCHAR Drive,
  179. IN UINT Level,
  180. IN BOOL Lock
  181. )
  182. {
  183. DIOC_REGISTERS RegistersIn,RegistersOut;
  184. BOOL b;
  185. DWORD SizeOut;
  186. BOOL Pass;
  187. Pass = 0;
  188. retry:
  189. //
  190. // ax = generic ioctl code
  191. //
  192. RegistersIn.reg_EAX = 0x440d;
  193. //
  194. // bl = 1-based drive number
  195. // bh = lock level
  196. //
  197. RegistersIn.reg_EBX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
  198. RegistersIn.reg_EBX |= (Level << 8);
  199. //
  200. // cl = lock or unlock volume code
  201. // ch = categoey, 8 on original Win95, 0x48 on OSR2
  202. //
  203. RegistersIn.reg_ECX = Lock ? 0x4a : 0x6a;
  204. RegistersIn.reg_ECX |= ((ISOSR2() && !Pass) ? 0x4800 : 0x800);
  205. //
  206. // dx = permissions
  207. //
  208. // bit 0 controls write operations (0 = disallowed)
  209. // bit 1 controls read operations (0 = allowed)
  210. //
  211. RegistersIn.reg_EDX = 1;
  212. //
  213. // Perform the lock and check carry.
  214. //
  215. b = DeviceIoControl(
  216. VWin32Vxd,
  217. VWIN32_DIOC_DOS_IOCTL,
  218. &RegistersIn,
  219. sizeof(DIOC_REGISTERS),
  220. &RegistersOut,
  221. sizeof(DIOC_REGISTERS),
  222. &SizeOut,
  223. NULL
  224. );
  225. if(b && (RegistersOut.reg_Flags & 1)) {
  226. b = FALSE;
  227. }
  228. //
  229. // If OSR2, try form of call with 8 in ch instead of 48.
  230. //
  231. if(!b && ISOSR2() && !Pass) {
  232. Pass = 1;
  233. goto retry;
  234. }
  235. return(b);
  236. }
  237. BOOL
  238. pGetWin9xLockFlagState (
  239. IN HANDLE VWin32Vxd,
  240. IN TCHAR Drive,
  241. OUT PINT LockStatus
  242. )
  243. {
  244. DIOC_REGISTERS RegistersIn,RegistersOut;
  245. BOOL b;
  246. DWORD SizeOut;
  247. *LockStatus = 0;
  248. //
  249. // ax = generic ioctl code
  250. //
  251. RegistersIn.reg_EAX = 0x440D;
  252. //
  253. // bx = 1-based drive number
  254. //
  255. RegistersIn.reg_EBX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
  256. //
  257. // cx = 0x86C (get lock flag state)
  258. //
  259. RegistersIn.reg_ECX = 0x86C;
  260. //
  261. // Perform the lock and check carry.
  262. //
  263. b = DeviceIoControl(
  264. VWin32Vxd,
  265. VWIN32_DIOC_DOS_IOCTL,
  266. &RegistersIn,
  267. sizeof(DIOC_REGISTERS),
  268. &RegistersOut,
  269. sizeof(DIOC_REGISTERS),
  270. &SizeOut,
  271. NULL
  272. );
  273. if (b) {
  274. if (RegistersOut.reg_Flags & 1) {
  275. b = FALSE;
  276. } else {
  277. *LockStatus = RegistersOut.reg_EAX;
  278. }
  279. }
  280. return b;
  281. }
  282. BOOL
  283. ResetWin9xDisk (
  284. IN HANDLE VWin32Vxd,
  285. IN TCHAR Drive
  286. )
  287. {
  288. DIOC_REGISTERS RegistersIn,RegistersOut;
  289. BOOL b;
  290. DWORD SizeOut;
  291. //
  292. // ax = generic ioctl code
  293. //
  294. RegistersIn.reg_EAX = 0x710d;
  295. //
  296. // cx = 0 (reset & flush disk)
  297. //
  298. RegistersIn.reg_ECX = 0;
  299. //
  300. // dx = 1-based drive number
  301. //
  302. RegistersIn.reg_EDX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
  303. //
  304. // Perform the lock and check carry.
  305. //
  306. b = DeviceIoControl(
  307. VWin32Vxd,
  308. VWIN32_DIOC_DOS_IOCTL,
  309. &RegistersIn,
  310. sizeof(DIOC_REGISTERS),
  311. &RegistersOut,
  312. sizeof(DIOC_REGISTERS),
  313. &SizeOut,
  314. NULL
  315. );
  316. if(b && (RegistersOut.reg_Flags & 1)) {
  317. b = FALSE;
  318. }
  319. return b;
  320. }
  321. typedef HANDLE(WINAPI *OPENTHREAD)(DWORD, BOOL, DWORD);
  322. BOOL
  323. pMakeThreadExclusive (
  324. BOOL Lock
  325. )
  326. {
  327. HANDLE h;
  328. THREADENTRY32 e;
  329. DWORD thisThread;
  330. HANDLE threadHandle;
  331. OPENTHREAD openThreadFn;
  332. HMODULE lib;
  333. BOOL result = FALSE;
  334. lib = LoadLibrary (TEXT("kernel32.dll"));
  335. if (!lib) {
  336. goto c0;
  337. }
  338. openThreadFn = (OPENTHREAD) GetProcAddress (lib, "OpenThread");
  339. if (!openThreadFn) {
  340. //
  341. // Must be Win98 or Win98SE -- change thread priority as workaround
  342. //
  343. if (Lock) {
  344. result = SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  345. Sleep (0);
  346. } else {
  347. result = SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  348. }
  349. goto c1;
  350. }
  351. thisThread = GetCurrentThreadId();
  352. h = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
  353. if (h == INVALID_HANDLE_VALUE) {
  354. goto c1;
  355. }
  356. e.dwSize = sizeof (e);
  357. if (Thread32First (h, &e)) {
  358. do {
  359. if (e.th32ThreadID != thisThread) {
  360. threadHandle = openThreadFn (THREAD_SUSPEND_RESUME, FALSE, e.th32ThreadID);
  361. if (threadHandle) {
  362. if (Lock) {
  363. SuspendThread (threadHandle);
  364. } else {
  365. ResumeThread (threadHandle);
  366. }
  367. CloseHandle (threadHandle);
  368. }
  369. }
  370. } while (Thread32Next (h, &e));
  371. }
  372. CloseHandle (h);
  373. result = TRUE;
  374. c1:
  375. FreeLibrary (lib);
  376. c0:
  377. return result;
  378. }
  379. BOOL
  380. ReadOrWriteSectorsWin9x(
  381. IN TCHAR Drive,
  382. IN UINT StartSector,
  383. IN UINT SectorCount,
  384. IN OUT LPBYTE Buffer,
  385. IN BOOL Write
  386. )
  387. /*++
  388. Routine Description:
  389. Common routine to read or write sectors on a disk under Windows 95.
  390. This routine will fail on Windows NT. After opening the VWIN32
  391. VxD, the routine determines whether to use the original algorithm
  392. or the OSR2 algorithm, and calls the appropriate worker routine.
  393. Arguments:
  394. Drive - supplies drive letter of device to be read from or written to.
  395. StartSector - supplies logical sector number of first sector to be
  396. read/written.
  397. SectorCount - supplies number of sectors to be read/written.
  398. SectorSize - supplies the number of bytes in a sector on the drive
  399. to be read from/written to.
  400. Buffer - Supplies or receives data, depending on the value or the Write
  401. parameter.
  402. Write - if 0, then this is a read operastion. If non-0, then this is
  403. a write operation.
  404. Return Value:
  405. Boolean value indicating whether the disk was read/written successfully.
  406. If failure, last error is set to something meaningful.
  407. --*/
  408. {
  409. HANDLE hVxd;
  410. BOOL b;
  411. DWORD d;
  412. INT level;
  413. INT retry = 100;
  414. //
  415. // This thread must be the exclusive thread in our process
  416. //
  417. pMakeThreadExclusive (TRUE);
  418. //
  419. // Open VWIN32.VXD
  420. //
  421. hVxd = CreateFileA(
  422. "\\\\.\\VWIN32",
  423. Write ? GENERIC_WRITE : GENERIC_READ,
  424. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  425. NULL,
  426. OPEN_EXISTING,
  427. FILE_ATTRIBUTE_NORMAL,
  428. NULL
  429. );
  430. if(hVxd == INVALID_HANDLE_VALUE) {
  431. d = GetLastError();
  432. b = FALSE;
  433. goto c0;
  434. }
  435. //
  436. // Take out locks. We'll be as unrestrictive as possible.
  437. // The locking stuff is really funky. You have to pass in all kinds of
  438. // different parameters in OSR2 for reasons unknown. Also the
  439. // permissions bits are strangely encoded.
  440. //
  441. if(!LockOrUnlockVolumeWin9x(hVxd,Drive,1,TRUE)) {
  442. d = ERROR_SHARING_VIOLATION;
  443. b = FALSE;
  444. goto c1;
  445. }
  446. if(!LockOrUnlockVolumeWin9x(hVxd,Drive,2,TRUE)) {
  447. d = ERROR_SHARING_VIOLATION;
  448. b = FALSE;
  449. goto c2;
  450. }
  451. //
  452. // Try to get the level 3 lock. Retry if something happened while
  453. // getting the lock. Fail after too many retries.
  454. //
  455. do {
  456. if(!LockOrUnlockVolumeWin9x(hVxd,Drive,3,TRUE)) {
  457. d = ERROR_SHARING_VIOLATION;
  458. b = FALSE;
  459. goto c3;
  460. }
  461. if (!pGetWin9xLockFlagState (hVxd, Drive, &level)) {
  462. // unexpected -- INT 21h call failed
  463. break;
  464. }
  465. if (!level) {
  466. // We successfully got a clean level 3 lock
  467. break;
  468. }
  469. LockOrUnlockVolumeWin9x(hVxd,Drive,3,FALSE);
  470. retry--;
  471. } while (retry);
  472. if (!retry) {
  473. d = ERROR_SHARING_VIOLATION;
  474. b = FALSE;
  475. goto c3;
  476. }
  477. //
  478. // Go do it.
  479. //
  480. b = ISOSR2()
  481. ? ReadOrWriteSectorsWin9xOsr2(hVxd,Drive,StartSector,SectorCount,Buffer,Write)
  482. : ReadOrWriteSectorsWin9xOriginal(hVxd,Drive,StartSector,SectorCount,Buffer,Write);
  483. //
  484. // If it failed, and OSR2 routine is being used, fall back to Win95 API. This is a workaround
  485. // for Compaq because they ship OSR2 without the new OSR2 sector API support!
  486. //
  487. if (!b && ISOSR2()) {
  488. b = ReadOrWriteSectorsWin9xOriginal(hVxd,Drive,StartSector,SectorCount,Buffer,Write);
  489. }
  490. d = GetLastError();
  491. LockOrUnlockVolumeWin9x(hVxd,Drive,3,FALSE);
  492. c3:
  493. LockOrUnlockVolumeWin9x(hVxd,Drive,2,FALSE);
  494. c2:
  495. LockOrUnlockVolumeWin9x(hVxd,Drive,1,FALSE);
  496. c1:
  497. CloseHandle(hVxd);
  498. c0:
  499. //
  500. // Resume all threads
  501. //
  502. pMakeThreadExclusive (FALSE);
  503. SetLastError(d);
  504. return(b);
  505. }
  506. BOOL
  507. ReadOrWriteSectors(
  508. IN TCHAR Drive,
  509. IN UINT StartSector,
  510. IN UINT SectorCount,
  511. IN UINT SectorSize,
  512. IN OUT LPBYTE Buffer,
  513. IN BOOL Write
  514. )
  515. /*++
  516. Routine Description:
  517. Common routine to read or write sectors on a disk. Allocates a properly
  518. aligned buffer and decides whether to call NT- or Win9x-specific
  519. i/o routine.
  520. Arguments:
  521. Drive - supplies drive letter of device to be read from or written to.
  522. StartSector - supplies logical sector number of first sector to be
  523. read/written.
  524. SectorCount - supplies number of sectors to be read/written.
  525. SectorSize - supplies the number of bytes in a sector on the drive
  526. to be read from/written to.
  527. Buffer - Supplies or receives data, depending on the value or the Write
  528. parameter. There are no alignment requirements on ths buffer.
  529. Write - if 0, then this is a read operastion. If non-0, then this is
  530. a write operation.
  531. Return Value:
  532. Boolean value indicating whether the disk was read/written successfully.
  533. Last error is undisturbed from the operation that caused any failure.
  534. --*/
  535. {
  536. LPBYTE AlignedBuffer;
  537. LPBYTE p;
  538. BOOL b;
  539. DWORD d;
  540. //
  541. // Allocate a buffer we will align on a sector boundary.
  542. //
  543. if(AlignedBuffer = MALLOC((SectorCount * SectorSize) + (SectorSize - 1))) {
  544. if(d = (DWORD)AlignedBuffer % SectorSize) {
  545. p = (PUCHAR)((DWORD)AlignedBuffer + (SectorSize - d));
  546. } else {
  547. p = AlignedBuffer;
  548. }
  549. if(Write) {
  550. CopyMemory(p,Buffer,SectorCount*SectorSize);
  551. }
  552. b = ReadOrWriteSectorsWin9x(Drive,StartSector,SectorCount,p,Write);
  553. d = GetLastError();
  554. if(b && !Write) {
  555. CopyMemory(Buffer,p,SectorCount*SectorSize);
  556. }
  557. FREE(AlignedBuffer);
  558. } else {
  559. b = FALSE;
  560. d = ERROR_NOT_ENOUGH_MEMORY;
  561. }
  562. SetLastError(d);
  563. return(b);
  564. }
  565. BOOL
  566. ReadDiskSectors(
  567. IN TCHAR Drive,
  568. IN UINT StartSector,
  569. IN UINT SectorCount,
  570. IN UINT SectorSize,
  571. OUT LPBYTE Buffer
  572. )
  573. /*++
  574. Routine Description:
  575. Read a set of disk sectors off a disk device.
  576. Arguments:
  577. Drive - supplies drive letter of device to be read from.
  578. StartSector - supplies logical sector number of first sector to be read.
  579. SectorCount - supplies number of sectors to be read.
  580. SectorSize - supplies the number of bytes in a sector on the drive
  581. to be read from.
  582. Buffer - if successful, receives data from the disk. There are no
  583. alignment requirements on ths buffer.
  584. Return Value:
  585. Boolean value indicating whether the disk was read successfully.
  586. --*/
  587. {
  588. return(ReadOrWriteSectors(Drive,StartSector,SectorCount,SectorSize,Buffer,FALSE));
  589. }
  590. BOOL
  591. WriteDiskSectors(
  592. IN TCHAR Drive,
  593. IN UINT StartSector,
  594. IN UINT SectorCount,
  595. IN UINT SectorSize,
  596. IN LPBYTE Buffer
  597. )
  598. /*++
  599. Routine Description:
  600. Write data to a set of disk sectors.
  601. Arguments:
  602. Drive - supplies drive letter of device to be written to.
  603. StartSector - supplies logical sector number of first sector to be written.
  604. SectorCount - supplies number of sectors to be written.
  605. SectorSize - supplies the number of bytes in a sector on the drive
  606. to be written to.
  607. Buffer - supplies data to be written. There are no alignment requirements
  608. on ths buffer.
  609. Return Value:
  610. Boolean value indicating whether the disk was successfully written.
  611. --*/
  612. {
  613. return(ReadOrWriteSectors(Drive,StartSector,SectorCount,SectorSize,Buffer,TRUE));
  614. }