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.

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