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.

620 lines
15 KiB

  1. /* demioctl.c - SVC handlers for DOS IOCTL calls
  2. *
  3. * demIOCTL
  4. *
  5. * Modification History:
  6. *
  7. * Sudeepb 23-Apr-1991 Created
  8. *
  9. */
  10. #include "dem.h"
  11. #include "demmsg.h"
  12. #include <softpc.h>
  13. #include <winbase.h>
  14. #include "demdasd.h"
  15. PFNSVC apfnSVCIoctl [] = {
  16. demIoctlInvalid, // IOCTL_GET_DEVICE_INFO 0
  17. demIoctlInvalid, // IOCTL_SET_DEVICE_INFO 1
  18. demIoctlInvalid, // IOCTL_READ_HANDLE 2
  19. demIoctlInvalid, // IOCTL_WRITE_HANDLE 3
  20. demIoctlInvalid, // IOCTL_READ_DRIVE 4
  21. demIoctlInvalid, // IOCTL_WRITE_DRIVE 5
  22. demIoctlInvalid, // IOCTL_GET_INPUT_STATUS 6
  23. demIoctlInvalid, // IOCTL_GET_OUTPUT_STATUS 7
  24. demIoctlChangeable, // IOCTL_CHANGEABLE 8
  25. demIoctlChangeable, // IOCTL_DeviceLocOrRem 9
  26. demIoctlInvalid, // IOCTL_HandleLocOrRem a
  27. demIoctlInvalid, // IOCTL_SHARING_RETRY b
  28. demIoctlInvalid, // GENERIC_IOCTL_HANDLE c
  29. demIoctlDiskGeneric, // GENERIC_IOCTL d
  30. demIoctlInvalid, // IOCTL_GET_DRIVE_MAP e
  31. demIoctlInvalid, // IOCTL_SET_DRIVE_MAP f
  32. demIoctlInvalid, // IOCTL_QUERY_HANDLE 10
  33. demIoctlDiskQuery, // IOCTL_QUERY_BLOCK 11
  34. demIoctlInvalid
  35. };
  36. MEDIA_TYPE MediaForFormat;
  37. #define MAX_IOCTL_INDEX (sizeof (apfnSVCIoctl) / sizeof (PFNSVC))
  38. /* demIOCTL - DOS IOCTLS
  39. *
  40. *
  41. * Entry - depends on the subfunction. See dos\ioctl.asm
  42. *
  43. * Exit
  44. * SUCCESS
  45. * Client (CY) = 0
  46. * for other registers see the corresponding function header
  47. *
  48. * FAILURE
  49. * Client (CY) = 1
  50. * for other registers see the corresponding function header
  51. */
  52. VOID demIOCTL (VOID)
  53. {
  54. ULONG iIoctl;
  55. iIoctl = (ULONG) getAL();
  56. #if DBG
  57. if (iIoctl >= MAX_IOCTL_INDEX){
  58. setAX((USHORT) ERROR_INVALID_FUNCTION);
  59. setCF(1);
  60. return;
  61. }
  62. #endif
  63. (apfnSVCIoctl [iIoctl])();
  64. return;
  65. }
  66. /* demIoctlChangeable - Is drive removeable (subfunc 8) or remote (subfunc 9)
  67. *
  68. *
  69. * Entry - Client (AL) - subfunc
  70. * Client (BL) - drive number (a=0,b=1 etc)
  71. *
  72. * Exit
  73. * SUCCESS
  74. * Client (CY) = 0
  75. * if subfunc 8
  76. * AX = 0 if removeable media
  77. * AX = 1 otherwise
  78. * if subfunc 9
  79. * DX = 0 if not remote
  80. * DX = 1000 if remote
  81. *
  82. * FAILURE
  83. * Client (CY) = 1
  84. * Client (AX) = error code
  85. *
  86. * CDROM drives are considered remote drives with write protection
  87. * by dos. (full support requires a VDD)
  88. */
  89. VOID demIoctlChangeable (VOID)
  90. {
  91. ULONG ulSubFunc;
  92. CHAR RootPathName[] = "?:\\";
  93. DWORD DriveType;
  94. UCHAR DriveNum;
  95. ulSubFunc = getAL();
  96. // Form Root path
  97. DriveNum = getBL();
  98. DriveType = demGetPhysicalDriveType(DriveNum);
  99. if (DriveType == DRIVE_UNKNOWN) {
  100. RootPathName[0] = (CHAR)('A' + DriveNum);
  101. DriveType = GetDriveTypeOem(RootPathName);
  102. }
  103. if (DriveType == DRIVE_UNKNOWN || DriveType == DRIVE_NO_ROOT_DIR){
  104. setAX (ERROR_INVALID_DRIVE);
  105. setCF(1);
  106. return;
  107. }
  108. if (ulSubFunc == IOCTL_CHANGEABLE){
  109. #ifdef JAPAN
  110. /* For MS-WORKS 2.5 */
  111. if (DriveType == DRIVE_REMOTE || DriveType == DRIVE_CDROM){
  112. setCF(1);
  113. setAX(0x000f);
  114. return;
  115. }
  116. #endif // JAPAN
  117. if(DriveType == DRIVE_REMOVABLE)
  118. setAX(0);
  119. else
  120. setAX(1); // includes CDROM drives
  121. }
  122. else {
  123. setAL(0);
  124. if (DriveType == DRIVE_REMOTE || DriveType == DRIVE_CDROM)
  125. #ifdef JAPAN
  126. /* For ICHITARO Ver.4 */
  127. setDH(0x10);
  128. else
  129. setDH(0);
  130. #else // !JAPAN
  131. setDX(0x1000);
  132. else
  133. // We have to return 800 rather then 0 as Dos Based Quatrro pro
  134. // behaves very badly if this bit is not set. sudeepb 15-Jun-1994
  135. setDX(0x800);
  136. #endif // !JAPAN
  137. }
  138. setCF(0);
  139. return;
  140. }
  141. /* demIoctlDiskGeneric - Block device generic ioctl
  142. *
  143. *
  144. * Entry - Client (BL) = drive number (a=0;b=1 etc)
  145. * (CL) = subfucntion code
  146. * (SI:DX) pointer to parameter block.
  147. * Exit
  148. * SUCCESS
  149. * Client (CY) = 0
  150. * (AX) = 0
  151. * parameter block updated
  152. * FAILURE
  153. * Client (CY) = 1
  154. * (AX) = error code
  155. */
  156. VOID demIoctlDiskGeneric (VOID)
  157. {
  158. BYTE Code, Drive;
  159. PDEVICE_PARAMETERS pdms;
  160. PMID pmid;
  161. PRW_BLOCK pRW;
  162. PFMT_BLOCK pfmt;
  163. PBDS pbds;
  164. DWORD Head, Cylinder;
  165. DWORD TrackSize;
  166. DWORD Sectors, StartSector;
  167. BYTE BootSector[BYTES_PER_SECTOR];
  168. PBOOTSECTOR pbs;
  169. PBPB pBPB;
  170. PACCESSCTRL pAccessCtrl;
  171. WORD SectorSize, ClusterSize, TotalClusters, FreeClusters;
  172. Code = getCL();
  173. Drive = getBL();
  174. if (Code == IOCTL_GETMEDIA) {
  175. pmid = (PMID) GetVDMAddr(getSI(), getDX());
  176. if (!GetMediaId(Drive, (PVOLINFO)pmid)) {
  177. setAX(demWinErrorToDosError(GetLastError()));
  178. setCF(1);
  179. }
  180. else {
  181. setAX(0);
  182. setCF(0);
  183. }
  184. return;
  185. }
  186. #ifdef JAPAN
  187. /* For Ichitaro Ver.4 */
  188. if (!demIsDriveFloppy(Drive) && Code==IOCTL_GETDPM){
  189. CHAR RootPathName[] = "?:\\";
  190. DWORD dwDriveType;
  191. RootPathName[0] = (CHAR)('A' + getBL());
  192. dwDriveType = GetDriveTypeOem(RootPathName);
  193. if (dwDriveType == DRIVE_FIXED){
  194. pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX());
  195. pdms->DeviceType = 5;
  196. pdms->DeviceAttrs = NON_REMOVABLE;
  197. }
  198. }
  199. #endif // JAPAN
  200. // if we don't know the drive, bail out
  201. if((pbds = demGetBDS(Drive)) == NULL && Code != IOCTL_GETDPM) {
  202. #if defined(NEC_98)
  203. setAX(DOS_FILE_NOT_FOUND);
  204. #else // !NEC_98
  205. if (!demIsDriveFloppy(Drive))
  206. host_direct_access_error(NOSUPPORT_HARDDISK);
  207. setAX(DOS_FILE_NOT_FOUND);
  208. #endif // !NEC_98
  209. setCF(1);
  210. return;
  211. }
  212. switch (Code) {
  213. case IOCTL_SETDPM:
  214. pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX());
  215. if (!(pdms->Functions & ONLY_SET_TRACKLAYOUT)) {
  216. pbds->FormFactor = pdms->DeviceType;
  217. pbds->Cylinders = pdms->Cylinders;
  218. pbds->Flags = pdms->DeviceAttrs;
  219. pbds->MediaType = pdms->MediaType;
  220. if (pdms->Functions & INSTALL_FAKE_BPB) {
  221. pbds->Flags |= RETURN_FAKE_BPB;
  222. pbds->bpb = pdms->bpb;
  223. // update the total sectors, we need it
  224. // for verification
  225. pbds->TotalSectors = (pbds->bpb.Sectors) ?
  226. pbds->bpb.Sectors :
  227. pbds->bpb.BigSectors;
  228. }
  229. else {
  230. pbds->Flags &= ~RETURN_FAKE_BPB;
  231. pbds->rbpb = pdms->bpb;
  232. }
  233. }
  234. MediaForFormat = Unknown;
  235. if (!(pbds->Flags & NON_REMOVABLE)){
  236. nt_floppy_close(pbds->DrivePhys);
  237. }
  238. else {
  239. nt_fdisk_close(pbds->DrivePhys);
  240. }
  241. break;
  242. case IOCTL_WRITETRACK:
  243. pRW = (PRW_BLOCK) GetVDMAddr(getSI(), getDX());
  244. Sectors = pRW->Sectors;
  245. StartSector = pRW->StartSector;
  246. StartSector += pbds->bpb.TrackSize *
  247. (pRW->Cylinder * pbds->bpb.Heads + pRW->Head);
  248. Sectors = demDasdWrite(pbds,
  249. StartSector,
  250. Sectors,
  251. pRW->BufferOff,
  252. pRW->BufferSeg
  253. );
  254. if (Sectors != pRW->Sectors) {
  255. setAX(demWinErrorToDosError(GetLastError()));
  256. setCF(1);
  257. return;
  258. }
  259. break;
  260. case IOCTL_FORMATTRACK:
  261. pfmt = (PFMT_BLOCK)GetVDMAddr(getSI(), getDX());
  262. Head = pfmt->Head;
  263. Cylinder = pfmt->Cylinder;
  264. if ((pbds->Flags & NON_REMOVABLE) &&
  265. pfmt->Head < pbds->bpb.Heads &&
  266. pfmt->Cylinder < pbds->Cylinders)
  267. {
  268. if (pfmt->Functions == STATUS_FOR_FORMAT){
  269. pfmt->Functions = 0;
  270. setCF(0);
  271. return;
  272. }
  273. if (!demDasdFormat(pbds, Head, Cylinder, NULL)) {
  274. setAX(demWinErrorToDosError(GetLastError()));
  275. setCF(1);
  276. return;
  277. }
  278. }
  279. else {
  280. if (MediaForFormat == Unknown) {
  281. demDasdFormat(pbds,
  282. Head,
  283. Cylinder,
  284. &MediaForFormat
  285. );
  286. }
  287. if (pfmt->Functions & STATUS_FOR_FORMAT){
  288. if (MediaForFormat == Unknown)
  289. pfmt->Functions = 2; // illegal combination
  290. else
  291. pfmt->Functions = 0;
  292. break;
  293. }
  294. if (MediaForFormat == Unknown ||
  295. !demDasdFormat(pbds, Head, Cylinder, &MediaForFormat)) {
  296. setAX(demWinErrorToDosError(GetLastError()));
  297. setCF(1);
  298. return;
  299. }
  300. }
  301. break;
  302. case IOCTL_SETMEDIA:
  303. pmid = (PMID) GetVDMAddr(getSI(), getDX());
  304. if (pbds->Flags & NON_REMOVABLE) {
  305. Sectors = nt_fdisk_read(pbds->DrivePhys,
  306. 0,
  307. BYTES_PER_SECTOR,
  308. BootSector
  309. );
  310. }
  311. else {
  312. if (demGetBPB(pbds))
  313. Sectors = nt_floppy_read(pbds->DrivePhys,
  314. 0,
  315. BYTES_PER_SECTOR,
  316. BootSector
  317. );
  318. else
  319. Sectors = 0;
  320. }
  321. pbs = (PBOOTSECTOR) BootSector;
  322. if (Sectors != BYTES_PER_SECTOR ||
  323. pbs->ExtBootSig != EXT_BOOTSECT_SIG)
  324. {
  325. setAX(demWinErrorToDosError(GetLastError()));
  326. setCF(1);
  327. return;
  328. }
  329. pbs->SerialNum = pmid->SerialNum;
  330. pbs->Label = pmid->Label;
  331. pbs->FileSysType = pmid->FileSysType;
  332. if (pbds->Flags & NON_REMOVABLE) {
  333. Sectors = nt_fdisk_write(pbds->DrivePhys,
  334. 0,
  335. BYTES_PER_SECTOR,
  336. (PBYTE)pbs
  337. );
  338. nt_fdisk_close(pbds->DrivePhys);
  339. }
  340. else {
  341. Sectors = nt_floppy_write(pbds->DrivePhys,
  342. 0,
  343. BYTES_PER_SECTOR,
  344. (PBYTE) pbs
  345. );
  346. nt_floppy_close(pbds->DrivePhys);
  347. }
  348. if (Sectors != BYTES_PER_SECTOR) {
  349. setAX(demWinErrorToDosError(GetLastError()));
  350. setCF(1);
  351. return;
  352. }
  353. break;
  354. // ioctl get device parameters
  355. case IOCTL_GETDPM:
  356. pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX());
  357. // if we couldn't find the bds, fake one
  358. if (pbds == NULL) {
  359. HANDLE hVolume;
  360. CHAR achRoot[]="\\\\.\\?:";
  361. DISK_GEOMETRY DiskGM;
  362. DWORD SizeReturned;
  363. if (!demGetDiskFreeSpace(Drive,
  364. &SectorSize,
  365. &ClusterSize,
  366. &TotalClusters,
  367. &FreeClusters
  368. )){
  369. setAX(demWinErrorToDosError(GetLastError()));
  370. setCF(1);
  371. return;
  372. }
  373. achRoot[4] = Drive + 'A';
  374. hVolume = CreateFileA(achRoot,
  375. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  376. FILE_SHARE_READ | FILE_SHARE_WRITE,
  377. NULL,
  378. OPEN_EXISTING,
  379. 0,
  380. NULL);
  381. if (hVolume == INVALID_HANDLE_VALUE) {
  382. setAX(demWinErrorToDosError(GetLastError()));
  383. setCF(1);
  384. return;
  385. }
  386. if (!DeviceIoControl(hVolume,
  387. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  388. NULL,
  389. 0,
  390. &DiskGM,
  391. sizeof(DISK_GEOMETRY),
  392. &SizeReturned,
  393. NULL
  394. )) {
  395. CloseHandle(hVolume);
  396. setAX(demWinErrorToDosError(GetLastError()));
  397. setCF(1);
  398. return;
  399. }
  400. CloseHandle(hVolume);
  401. Sectors = DiskGM.Cylinders.LowPart *
  402. DiskGM.TracksPerCylinder *
  403. DiskGM.SectorsPerTrack;
  404. pdms->DeviceType = FF_FDISK;
  405. pdms->DeviceAttrs = NON_REMOVABLE;
  406. pdms->MediaType = 0;
  407. pdms->bpb.SectorSize = SectorSize;
  408. pdms->bpb.ClusterSize = (BYTE) ClusterSize;
  409. pdms->bpb.ReservedSectors = 1;
  410. pdms->bpb.FATs = 2;
  411. pdms->bpb.RootDirs = (Sectors > 32680) ? 512 : 64;
  412. pdms->bpb.MediaID = 0xF8;
  413. pdms->bpb.TrackSize = (WORD) DiskGM.SectorsPerTrack;
  414. pdms->bpb.Heads = (WORD) DiskGM.TracksPerCylinder;
  415. pdms->Cylinders = (WORD) DiskGM.Cylinders.LowPart;
  416. if (Sectors >= 40000) {
  417. TrackSize = 256 * ClusterSize + 2;
  418. pdms->bpb.FATSize = (WORD) ((Sectors - pdms->bpb.ReservedSectors
  419. - pdms->bpb.RootDirs * 32 / 512 +
  420. TrackSize - 1 ) / TrackSize);
  421. }
  422. else {
  423. pdms->bpb.FATSize = (WORD) (((Sectors / ClusterSize) * 3 / 2) /
  424. 512 + 1);
  425. }
  426. pdms->bpb.HiddenSectors = Sectors;
  427. Sectors = TotalClusters * ClusterSize;
  428. if (Sectors >= 0x10000) {
  429. pdms->bpb.Sectors = 0;
  430. pdms->bpb.BigSectors = Sectors;
  431. }
  432. else {
  433. pdms->bpb.Sectors = (WORD) Sectors;
  434. pdms->bpb.BigSectors = 0;
  435. }
  436. pdms->bpb.HiddenSectors -= Sectors;
  437. break;
  438. }
  439. pdms->DeviceType = pbds->FormFactor;
  440. pdms->DeviceAttrs = pbds->Flags & ~(HAS_CHANGELINE);
  441. pdms->Cylinders = pbds->Cylinders;
  442. pdms->MediaType = 0;
  443. if (pdms->Functions & BUILD_DEVICE_BPB){
  444. if (!(pbds->Flags & NON_REMOVABLE) &&
  445. !demGetBPB(pbds)) {
  446. setAX(demWinErrorToDosError(GetLastError()));
  447. setCF(1);
  448. return;
  449. }
  450. pBPB = &pbds->bpb;
  451. }
  452. else
  453. // copy recommended bpb
  454. pBPB = &pbds->rbpb;
  455. pdms->bpb = *pBPB;
  456. break;
  457. case IOCTL_READTRACK:
  458. pRW = (PRW_BLOCK) GetVDMAddr(getSI(), getDX());
  459. Sectors = pRW->Sectors;
  460. StartSector = pRW->StartSector;
  461. StartSector += pbds->bpb.TrackSize *
  462. (pRW->Cylinder * pbds->bpb.Heads + pRW->Head);
  463. Sectors = demDasdRead(pbds,
  464. StartSector,
  465. Sectors,
  466. pRW->BufferOff,
  467. pRW->BufferSeg
  468. );
  469. if (Sectors != pRW->Sectors) {
  470. setAX(demWinErrorToDosError(GetLastError()));
  471. setCF(1);
  472. return;
  473. }
  474. break;
  475. case IOCTL_VERIFYTRACK:
  476. pfmt = (PFMT_BLOCK) GetVDMAddr(getSI(), getDX());
  477. if(!demDasdVerify(pbds, pfmt->Head, pfmt->Cylinder)) {
  478. setAX(demWinErrorToDosError(GetLastError()));
  479. setCF(1);
  480. return;
  481. }
  482. break;
  483. case IOCTL_GETACCESS:
  484. pAccessCtrl = (PACCESSCTRL) GetVDMAddr(getSI(), getDX());
  485. pAccessCtrl->AccessFlag = (pbds->Flags & UNFORMATTED_MEDIA) ?
  486. 0 : 1;
  487. break;
  488. case IOCTL_SETACCESS:
  489. pAccessCtrl = (PACCESSCTRL) GetVDMAddr(getSI(), getDX());
  490. pbds->Flags &= ~(UNFORMATTED_MEDIA);
  491. if (pAccessCtrl->AccessFlag == 0)
  492. #if defined(NEC_98)
  493. pbds->Flags |= UNFORMATTED_MEDIA;
  494. #else // !NEC_98
  495. pAccessCtrl->AccessFlag |= UNFORMATTED_MEDIA;
  496. #endif // !NEC_98
  497. break;
  498. default:
  499. setAX(DOS_INVALID_FUNCTION);
  500. setCF(1);
  501. return;
  502. }
  503. setAX(0);
  504. setCF(0);
  505. }
  506. /* demIoctlDiskQuery - Query block device generic ioctl capability
  507. *
  508. *
  509. * Entry - Client (BL) = drive number (a=0;b=1 etc)
  510. * (CL) = generic ioctl subfuntion to be queried
  511. * Exit
  512. * SUCCESS
  513. * Client (CY) = 0
  514. * The specific ioctl is supported
  515. * FAILURE
  516. * Client (CY) = 1
  517. * The given ioctl is not supported
  518. */
  519. VOID demIoctlDiskQuery (VOID)
  520. {
  521. BYTE Code, Drive;
  522. Code = getCL();
  523. Drive = getBL();
  524. if (demGetBDS(Drive) == NULL) {
  525. setAX(DOS_FILE_NOT_FOUND);
  526. setCF(1);
  527. return;
  528. }
  529. switch (Code) {
  530. case IOCTL_SETDPM:
  531. case IOCTL_WRITETRACK:
  532. case IOCTL_FORMATTRACK:
  533. case IOCTL_SETMEDIA:
  534. case IOCTL_GETDPM:
  535. case IOCTL_READTRACK:
  536. case IOCTL_VERIFYTRACK:
  537. case IOCTL_GETMEDIA:
  538. // case IOCTL_GETACCESS:
  539. // case IOCTL_SETACCESS:
  540. setAX(0);
  541. setCF(0);
  542. break;
  543. default:
  544. setAX(DOS_ACCESS_DENIED);
  545. setCF(1);
  546. break;
  547. }
  548. }
  549. /* demIoctlInvalid - For those subfunctions which may be implemented later
  550. *
  551. *
  552. * Entry -
  553. *
  554. * Exit
  555. * Client (CY) = 1
  556. * Client (AX) = error_invalid_function
  557. */
  558. VOID demIoctlInvalid (VOID)
  559. {
  560. setCF(1);
  561. setAX(ERROR_INVALID_FUNCTION);
  562. return;
  563. }