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.

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