source: trunk/src/kernel32/hmdisk.cpp@ 9298

Last change on this file since 9298 was 9298, checked in by sandervl, 23 years ago

lots of fixes/changes for physical disk & volume access

File size: 76.7 KB
Line 
1/* $Id: hmdisk.cpp,v 1.53 2002-09-26 16:06:06 sandervl Exp $ */
2
3/*
4 * Win32 Disk API functions for OS/2
5 *
6 * Copyright 2000-2002 Sander van Leeuwen
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12#include <os2win.h>
13#include <string.h>
14#include <stdio.h>
15#include <versionos2.h>
16
17#include <misc.h>
18#include "hmdisk.h"
19#include "mmap.h"
20#include <win\winioctl.h>
21#include <win\ntddscsi.h>
22#include <win\wnaspi32.h>
23#include "oslibdos.h"
24#include "osliblvm.h"
25#include "oslibcdio.h"
26#include "asmutil.h"
27
28#define DBG_LOCALLOG DBG_hmdisk
29#include "dbglocal.h"
30
31#define BIT_0 (1)
32#define BIT_1 (2)
33#define BIT_2 (4)
34#define BIT_11 (1<<11)
35
36//Converts BCD to decimal; doesn't check for illegal BCD nrs
37#define BCDToDec(a) ((a >> 4) * 10 + (a & 0xF))
38
39
40typedef struct
41{
42 BOOL fCDIoSupported;
43 ULONG driveLetter;
44 ULONG driveType;
45 ULONG dwVolumelabel;
46 CHAR signature[8];
47 DWORD dwAccess;
48 DWORD dwShare;
49 DWORD dwCreation;
50 DWORD dwFlags;
51 LPSECURITY_ATTRIBUTES lpSecurityAttributes;
52 HFILE hTemplate;
53 BOOL fPhysicalDisk;
54 DWORD dwPhysicalDiskNr;
55 BOOL fCDPlaying;
56 BOOL fShareViolation;
57 DWORD fLocked;
58 LARGE_INTEGER StartingOffset;
59 LARGE_INTEGER PartitionSize;
60 LARGE_INTEGER CurrentFilePointer;
61 CHAR szVolumeName[256];
62} DRIVE_INFO;
63
64HMDeviceDiskClass::HMDeviceDiskClass(LPCSTR lpDeviceName) : HMDeviceKernelObjectClass(lpDeviceName)
65{
66 HMDeviceRegisterEx("\\\\.\\PHYSICALDRIVE", this, NULL);
67 HMDeviceRegisterEx(VOLUME_NAME_PREFIX, this, NULL);
68}
69
70/*****************************************************************************
71 * Name : HMDeviceDiskClass::FindDevice
72 * Purpose : Checks if lpDeviceName belongs to this device class
73 * Parameters: LPCSTR lpClassDevName
74 * LPCSTR lpDeviceName
75 * int namelength
76 * Variables :
77 * Result : checks if name is for a drive of physical disk
78 * Remark :
79 * Status :
80 *
81 * Author : SvL
82 *****************************************************************************/
83BOOL HMDeviceDiskClass::FindDevice(LPCSTR lpClassDevName, LPCSTR lpDeviceName, int namelength)
84{
85 // check for "x:"
86 if (namelength == 2)
87 {
88 if (lpDeviceName[1] != ':')
89 return FALSE;
90
91 if (!( ((lpDeviceName[0] >= 'A') &&
92 (lpDeviceName[0] <= 'Z')) ||
93 ((lpDeviceName[0] >= 'a') &&
94 (lpDeviceName[0] <= 'z')) ))
95 return FALSE;
96
97 return TRUE;
98 }
99
100 //\\.\x: -> length 6
101 //\\.\PHYSICALDRIVEn -> length 18
102 if(namelength != 6 && namelength != 18) {
103 if(VERSION_IS_WIN2000_OR_HIGHER()) {
104 if(!strncmp(lpDeviceName, VOLUME_NAME_PREFIX, sizeof(VOLUME_NAME_PREFIX)-1)) {
105 return TRUE;
106 }
107 }
108 return FALSE;
109 }
110
111 // \\.\x: -> drive x (i.e. \\.\C:)
112 // \\.\PHYSICALDRIVEn -> drive n (n>=0)
113 if((strncmp(lpDeviceName, "\\\\.\\", 4) == 0) &&
114 namelength == 6 && lpDeviceName[5] == ':')
115 {
116 return TRUE;
117 }
118 if((strncmp(lpDeviceName, "\\\\.\\PHYSICALDRIVE", 17) == 0) && namelength == 18) {
119 return TRUE;
120 }
121 return FALSE;
122}
123//******************************************************************************
124//******************************************************************************
125DWORD HMDeviceDiskClass::CreateFile (LPCSTR lpFileName,
126 PHMHANDLEDATA pHMHandleData,
127 PVOID lpSecurityAttributes,
128 PHMHANDLEDATA pHMHandleDataTemplate)
129{
130 HFILE hFile;
131 HFILE hTemplate;
132 DWORD dwDriveType;
133 CHAR szDiskName[256];
134 CHAR szVolumeName[256] = "";
135 VOLUME_DISK_EXTENTS volext = {0};
136 BOOL fPhysicalDisk = FALSE;
137 DWORD dwPhysicalDiskNr = 0;
138
139 dprintf2(("KERNEL32: HMDeviceDiskClass::CreateFile %s(%s,%08x,%08x,%08x)\n",
140 lpHMDeviceName, lpFileName, pHMHandleData, lpSecurityAttributes, pHMHandleDataTemplate));
141
142 //TODO: check in NT if CREATE_ALWAYS is allowed!!
143 if(pHMHandleData->dwCreation != OPEN_EXISTING) {
144 dprintf(("Invalid creation flags %x!!", pHMHandleData->dwCreation));
145 return ERROR_INVALID_PARAMETER;
146 }
147
148 char szDrive[4];
149 szDrive[1] = ':';
150 szDrive[2] = '\0';
151
152 //if volume name, query
153 if(!strncmp(lpFileName, VOLUME_NAME_PREFIX, sizeof(VOLUME_NAME_PREFIX)-1))
154 {
155 int length;
156
157 if(!VERSION_IS_WIN2000_OR_HIGHER()) {
158 return ERROR_FILE_NOT_FOUND; //not allowed
159 }
160 if(OSLibLVMStripVolumeName(lpFileName, szVolumeName, sizeof(szVolumeName)))
161 {
162 BOOL fLVMVolume;
163
164 dwDriveType = GetDriveTypeA(lpFileName);
165
166 szDrive[0] = OSLibLVMQueryDriveFromVolumeName(szVolumeName);
167 if(szDrive[0] == -1) {
168 return ERROR_FILE_NOT_FOUND; //not found
169 }
170 if((dwDriveType == DRIVE_FIXED) && OSLibLVMGetVolumeExtents(szDrive[0], szVolumeName, &volext, &fLVMVolume) == FALSE) {
171 return ERROR_FILE_NOT_FOUND; //not found
172 }
173 if(szDrive[0] == 0)
174 {
175 //volume isn't mounted
176
177 //Note: this only works on Warp 4.5 and up
178 sprintf(szDiskName, "\\\\.\\Physical_Disk%d", volext.Extents[0].DiskNumber+1);
179 fPhysicalDisk = TRUE;
180 dwPhysicalDiskNr = volext.Extents[0].DiskNumber + 1;
181
182 if(fLVMVolume && (pHMHandleData->dwAccess & GENERIC_WRITE)) {
183 //no write access allowed for LVM volumes
184 dprintf(("CreateFile: WARNING: Write access to LVM volume denied!!"));
185 pHMHandleData->dwAccess &= ~GENERIC_WRITE;
186 }
187 }
188 else {
189 //mounted drive, make sure access requested is readonly, else fail
190 if(pHMHandleData->dwAccess & GENERIC_WRITE) {
191 //no write access allowed for mounted partitions
192 dprintf(("CreateFile: WARNING: Write access to mounted partition denied!!"));
193 pHMHandleData->dwAccess &= ~GENERIC_WRITE;
194 }
195 strcpy(szDiskName, szDrive);
196 }
197 }
198 else return ERROR_FILE_NOT_FOUND;
199 }
200 else
201 if(strncmp(lpFileName, "\\\\.\\PHYSICALDRIVE", 17) == 0)
202 {
203 //Note: this only works on Warp 4.5 and up
204 sprintf(szDiskName, "\\\\.\\Physical_Disk%c", lpFileName[17]+1);
205 fPhysicalDisk = TRUE;
206 dwPhysicalDiskNr = (DWORD)(lpFileName[17] - '0')+1;
207
208 //TODO: could be removable in theory
209 dwDriveType = DRIVE_FIXED;
210
211 if(pHMHandleData->dwAccess & GENERIC_WRITE) {
212 //no write access allowed for whole disks
213 dprintf(("CreateFile: WARNING: Write access to whole disk denied!!"));
214 pHMHandleData->dwAccess &= ~GENERIC_WRITE;
215 }
216 }
217 else {
218 strcpy(szDiskName, lpFileName);
219 szDrive[0] = *lpFileName;
220 dwDriveType = GetDriveTypeA(szDrive);
221 if(dwDriveType == DRIVE_DOESNOTEXIST) {
222 //If the drive doesn't exist, then fail right here
223 dprintf(("Drive %s does not exist; fail", szDrive));
224 return ERROR_INVALID_DRIVE; //right error??
225 }
226 }
227
228 //Disable error popus. NT allows an app to open a cdrom/dvd drive without a disk inside
229 //OS/2 fails in that case with error ERROR_NOT_READY
230 ULONG oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
231 hFile = OSLibDosCreateFile(szDiskName,
232 pHMHandleData->dwAccess,
233 pHMHandleData->dwShare,
234 (LPSECURITY_ATTRIBUTES)lpSecurityAttributes,
235 pHMHandleData->dwCreation,
236 pHMHandleData->dwFlags,
237 hTemplate);
238
239 //It is not allowed to open a readonly device with GENERIC_WRITE in OS/2;
240 //try with readonly again if that happened
241 //NOTE: Some applications open it with GENERIC_WRITE as Windows 2000 requires
242 // this for some aspi functions
243 if(hFile == INVALID_HANDLE_ERROR && dwDriveType == DRIVE_CDROM &&
244 (pHMHandleData->dwAccess & GENERIC_WRITE))
245 {
246 pHMHandleData->dwAccess &= ~GENERIC_WRITE;
247 hFile = OSLibDosCreateFile((LPSTR)szDiskName,
248 pHMHandleData->dwAccess,
249 pHMHandleData->dwShare,
250 (LPSECURITY_ATTRIBUTES)lpSecurityAttributes,
251 pHMHandleData->dwCreation,
252 pHMHandleData->dwFlags,
253 hTemplate);
254 }
255 SetErrorMode(oldmode);
256
257 DWORD lasterror = GetLastError();
258 if(hFile != INVALID_HANDLE_ERROR || lasterror == ERROR_NOT_READY ||
259 lasterror == ERROR_SHARING_VIOLATION)
260 {
261 if(hFile == INVALID_HANDLE_ERROR) {
262 dprintf(("Drive not ready"));
263 SetLastError(NO_ERROR);
264 pHMHandleData->hHMHandle = 0; //handle lookup fails if this is set to -1
265 }
266 else pHMHandleData->hHMHandle = hFile;
267
268 DRIVE_INFO *drvInfo = (DRIVE_INFO *)malloc(sizeof(DRIVE_INFO));
269 if(drvInfo == NULL) {
270 DebugInt3();
271 if(pHMHandleData->hHMHandle) OSLibDosClose(pHMHandleData->hHMHandle);
272 return ERROR_OUTOFMEMORY;
273 }
274 pHMHandleData->dwUserData = (DWORD)drvInfo;
275
276 if(lasterror == ERROR_SHARING_VIOLATION) {
277 drvInfo->fShareViolation = TRUE;
278 }
279
280 memset(drvInfo, 0, sizeof(DRIVE_INFO));
281 drvInfo->dwAccess = pHMHandleData->dwAccess;
282 drvInfo->dwShare = pHMHandleData->dwShare;
283 drvInfo->lpSecurityAttributes = (LPSECURITY_ATTRIBUTES)lpSecurityAttributes;
284 drvInfo->dwCreation= pHMHandleData->dwCreation;
285 drvInfo->dwFlags = pHMHandleData->dwFlags;
286 drvInfo->hTemplate = hTemplate;
287 drvInfo->fLocked = FALSE;
288
289 //save volume start & length if volume must be accessed through the physical disk
290 //(no other choice for unmounted volumes)
291 drvInfo->fPhysicalDisk = fPhysicalDisk;
292 drvInfo->dwPhysicalDiskNr = dwPhysicalDiskNr;
293 drvInfo->StartingOffset = volext.Extents[0].StartingOffset;
294 drvInfo->PartitionSize = volext.Extents[0].ExtentLength;
295
296 //save volume name for later (IOCtls)
297 strncpy(drvInfo->szVolumeName, szVolumeName, sizeof(drvInfo->szVolumeName)-1);
298
299 drvInfo->driveLetter = *lpFileName; //save drive letter
300 if(drvInfo->driveLetter >= 'a') {
301 drvInfo->driveLetter = drvInfo->driveLetter - ((int)'a' - (int)'A');
302 }
303
304 drvInfo->driveType = dwDriveType;
305 if(drvInfo->driveType == DRIVE_CDROM)
306 {
307 drvInfo->fCDIoSupported = OSLibCdIoIsSupported(pHMHandleData->hHMHandle);
308
309 //get cdrom signature
310 DWORD parsize = 4;
311 DWORD datasize = 4;
312 strcpy(drvInfo->signature, "CD01");
313 OSLibDosDevIOCtl(pHMHandleData->hHMHandle, 0x80, 0x61, &drvInfo->signature[0], 4, &parsize,
314 &drvInfo->signature[0], 4, &datasize);
315 }
316
317 if(hFile && drvInfo->driveType != DRIVE_FIXED) {
318 OSLibDosQueryVolumeSerialAndName(1 + drvInfo->driveLetter - 'A', &drvInfo->dwVolumelabel, NULL, 0);
319 }
320
321 //for an unmounted partition we open the physical disk that contains it, so we
322 //must set the file pointer to the correct beginning
323 if(drvInfo->fPhysicalDisk && (drvInfo->StartingOffset.HighPart != 0 ||
324 drvInfo->StartingOffset.LowPart != 0))
325 {
326 SetFilePointer(pHMHandleData, 0, NULL, FILE_BEGIN);
327 }
328 //If the disk handle was valid, then we must lock it if the drive
329 //was opened without share flags
330 if(pHMHandleData->hHMHandle && drvInfo->dwShare == 0) {
331 dprintf(("Locking drive"));
332 if(OSLibDosDevIOCtl(pHMHandleData->hHMHandle,IOCTL_DISK,DSK_LOCKDRIVE,0,0,0,0,0,0))
333 {
334 dprintf(("Sharing violation while attempting to lock the drive"));
335 OSLibDosClose(pHMHandleData->hHMHandle);
336 free(drvInfo);
337 return ERROR_SHARING_VIOLATION;
338 }
339 drvInfo->fLocked = TRUE;
340 }
341 return (NO_ERROR);
342 }
343 else {
344 dprintf(("CreateFile failed; error %d", GetLastError()));
345 return(GetLastError());
346 }
347}
348//******************************************************************************
349//******************************************************************************
350DWORD HMDeviceDiskClass::OpenDisk(PVOID pDrvInfo)
351{
352 char filename[3];
353 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pDrvInfo;
354 HFILE hFile;
355
356 filename[0] = drvInfo->driveLetter;
357 filename[1] = ':';
358 filename[2] = 0;
359
360 //Disable error popus. NT allows an app to open a cdrom/dvd drive without a disk inside
361 //OS/2 fails in that case with error ERROR_NOT_READY
362 ULONG oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
363 hFile = OSLibDosCreateFile(filename,
364 drvInfo->dwAccess,
365 drvInfo->dwShare,
366 drvInfo->lpSecurityAttributes,
367 drvInfo->dwCreation,
368 drvInfo->dwFlags,
369 drvInfo->hTemplate);
370 SetErrorMode(oldmode);
371
372 if (hFile != INVALID_HANDLE_ERROR || GetLastError() == ERROR_NOT_READY)
373 {
374 if(hFile == INVALID_HANDLE_ERROR) {
375 dprintf(("Drive not ready"));
376 return 0;
377 }
378 if(drvInfo->driveType == DRIVE_CDROM)
379 {
380 drvInfo->fCDIoSupported = OSLibCdIoIsSupported(hFile);
381
382 //get cdrom signature
383 DWORD parsize = 4;
384 DWORD datasize = 4;
385 strcpy(drvInfo->signature, "CD01");
386 OSLibDosDevIOCtl(hFile, 0x80, 0x61, &drvInfo->signature[0], 4, &parsize,
387 &drvInfo->signature[0], 4, &datasize);
388 }
389 OSLibDosQueryVolumeSerialAndName(1 + drvInfo->driveLetter - 'A', &drvInfo->dwVolumelabel, NULL, 0);
390
391 //If the disk handle was valid, then we must lock it if the drive
392 //was opened without share flags
393 if(hFile && drvInfo->dwShare == 0) {
394 dprintf(("Locking drive"));
395 if(OSLibDosDevIOCtl(hFile,IOCTL_DISK,DSK_LOCKDRIVE,0,0,0,0,0,0))
396 {
397 dprintf(("Sharing violation while attempting to lock the drive"));
398 OSLibDosClose(hFile);
399 return 0;
400 }
401 drvInfo->fLocked = TRUE;
402 }
403 return hFile;
404 }
405 return 0;
406}
407//******************************************************************************
408//******************************************************************************
409BOOL HMDeviceDiskClass::CloseHandle(PHMHANDLEDATA pHMHandleData)
410{
411 BOOL ret = TRUE;
412
413 if(pHMHandleData->hHMHandle) {
414 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
415 if(drvInfo && drvInfo->fLocked) {
416 dprintf(("Unlocking drive"));
417 OSLibDosDevIOCtl(pHMHandleData->hHMHandle,IOCTL_DISK,DSK_UNLOCKDRIVE,0,0,0,0,0,0);
418 }
419 ret = OSLibDosClose(pHMHandleData->hHMHandle);
420 }
421 if(pHMHandleData->dwUserData) {
422 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
423 free(drvInfo);
424 }
425 return ret;
426}
427//******************************************************************************
428//******************************************************************************
429
430
431// this helper function just calls the specified
432// ioctl function for the CDROM manager with no
433// parameter packet other than the CD01 signature
434// and no data packet.
435static BOOL ioctlCDROMSimple(PHMHANDLEDATA pHMHandleData,
436 DWORD dwCategory,
437 DWORD dwFunction,
438 LPDWORD lpBytesReturned, DRIVE_INFO *pdrvInfo)
439{
440 DWORD dwParameterSize = 4;
441 DWORD dwDataSize = 0;
442 DWORD ret;
443
444 if(lpBytesReturned)
445 *lpBytesReturned = 0;
446
447 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
448 dwCategory,
449 dwFunction,
450 pdrvInfo->signature,
451 4,
452 &dwParameterSize,
453 NULL,
454 0,
455 &dwDataSize);
456 return (ret == ERROR_SUCCESS);
457}
458
459
460// this helper function just calls the specified
461// ioctl function for the DISK manager with the
462// specified function codes
463static BOOL ioctlDISKUnlockEject(PHMHANDLEDATA pHMHandleData,
464 DWORD dwCommand,
465 DWORD dwDiskHandle,
466 LPDWORD lpBytesReturned)
467{
468#pragma pack(1)
469 struct
470 {
471 BYTE ucCommand;
472 BYTE ucHandle;
473 } ParameterBlock;
474#pragma pack()
475
476 DWORD dwParameterSize = sizeof( ParameterBlock );
477 DWORD dwDataSize = 0;
478 DWORD ret;
479
480 ParameterBlock.ucCommand = dwCommand;
481 ParameterBlock.ucHandle = dwDiskHandle;
482
483 if(lpBytesReturned)
484 *lpBytesReturned = 0;
485
486 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
487 IOCTL_DISK,
488 DSK_UNLOCKEJECTMEDIA,
489 &ParameterBlock,
490 sizeof( ParameterBlock ),
491 &dwParameterSize,
492 NULL,
493 0,
494 &dwDataSize);
495 return (ret == ERROR_SUCCESS);
496}
497
498
499
500BOOL HMDeviceDiskClass::DeviceIoControl(PHMHANDLEDATA pHMHandleData, DWORD dwIoControlCode,
501 LPVOID lpInBuffer, DWORD nInBufferSize,
502 LPVOID lpOutBuffer, DWORD nOutBufferSize,
503 LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
504{
505#ifdef DEBUG
506 char *msg = NULL;
507
508 switch(dwIoControlCode)
509 {
510 case FSCTL_DELETE_REPARSE_POINT:
511 msg = "FSCTL_DELETE_REPARSE_POINT";
512 break;
513 case FSCTL_DISMOUNT_VOLUME:
514 msg = "FSCTL_DISMOUNT_VOLUME";
515 break;
516 case FSCTL_GET_COMPRESSION:
517 msg = "FSCTL_GET_COMPRESSION";
518 break;
519 case FSCTL_GET_REPARSE_POINT:
520 msg = "FSCTL_GET_REPARSE_POINT";
521 break;
522 case FSCTL_LOCK_VOLUME:
523 msg = "FSCTL_LOCK_VOLUME";
524 break;
525 case FSCTL_QUERY_ALLOCATED_RANGES:
526 msg = "FSCTL_QUERY_ALLOCATED_RANGES";
527 break;
528 case FSCTL_SET_COMPRESSION:
529 msg = "FSCTL_SET_COMPRESSION";
530 break;
531 case FSCTL_SET_REPARSE_POINT:
532 msg = "FSCTL_SET_REPARSE_POINT";
533 break;
534 case FSCTL_SET_SPARSE:
535 msg = "FSCTL_SET_SPARSE";
536 break;
537 case FSCTL_SET_ZERO_DATA:
538 msg = "FSCTL_SET_ZERO_DATA";
539 break;
540 case FSCTL_UNLOCK_VOLUME:
541 msg = "FSCTL_UNLOCK_VOLUME";
542 break;
543 case IOCTL_DISK_CHECK_VERIFY:
544 msg = "IOCTL_DISK_CHECK_VERIFY";
545 break;
546 case IOCTL_DISK_EJECT_MEDIA:
547 msg = "IOCTL_DISK_EJECT_MEDIA";
548 break;
549 case IOCTL_DISK_FORMAT_TRACKS:
550 msg = "IOCTL_DISK_FORMAT_TRACKS";
551 break;
552 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
553 msg = "IOCTL_DISK_GET_DRIVE_GEOMETRY";
554 break;
555 case IOCTL_DISK_IS_WRITABLE:
556 msg = "IOCTL_DISK_IS_WRITABLE";
557 break;
558 case IOCTL_DISK_GET_DRIVE_LAYOUT:
559 msg = "IOCTL_DISK_GET_DRIVE_LAYOUT";
560 break;
561 case IOCTL_DISK_GET_MEDIA_TYPES:
562 msg = "IOCTL_DISK_GET_MEDIA_TYPES";
563 break;
564 case IOCTL_DISK_GET_PARTITION_INFO:
565 msg = "IOCTL_DISK_GET_PARTITION_INFO";
566 break;
567 case IOCTL_DISK_LOAD_MEDIA:
568 msg = "IOCTL_DISK_LOAD_MEDIA";
569 break;
570 case IOCTL_DISK_MEDIA_REMOVAL:
571 msg = "IOCTL_DISK_MEDIA_REMOVAL";
572 break;
573 case IOCTL_DISK_PERFORMANCE:
574 msg = "IOCTL_DISK_PERFORMANCE";
575 break;
576 case IOCTL_DISK_REASSIGN_BLOCKS:
577 msg = "IOCTL_DISK_REASSIGN_BLOCKS";
578 break;
579 case IOCTL_DISK_SET_DRIVE_LAYOUT:
580 msg = "IOCTL_DISK_SET_DRIVE_LAYOUT";
581 break;
582 case IOCTL_DISK_SET_PARTITION_INFO:
583 msg = "IOCTL_DISK_SET_PARTITION_INFO";
584 break;
585 case IOCTL_DISK_VERIFY:
586 msg = "IOCTL_DISK_VERIFY";
587 break;
588 case IOCTL_SERIAL_LSRMST_INSERT:
589 msg = "IOCTL_SERIAL_LSRMST_INSERT";
590 break;
591 case IOCTL_STORAGE_CHECK_VERIFY:
592 msg = "IOCTL_STORAGE_CHECK_VERIFY";
593 break;
594 case IOCTL_STORAGE_EJECT_MEDIA:
595 msg = "IOCTL_STORAGE_EJECT_MEDIA";
596 break;
597 case IOCTL_STORAGE_GET_MEDIA_TYPES:
598 msg = "IOCTL_STORAGE_GET_MEDIA_TYPES";
599 break;
600 case IOCTL_STORAGE_LOAD_MEDIA:
601 msg = "IOCTL_STORAGE_LOAD_MEDIA";
602 break;
603 case IOCTL_STORAGE_MEDIA_REMOVAL:
604 msg = "IOCTL_STORAGE_MEDIA_REMOVAL";
605 break;
606 case IOCTL_SCSI_PASS_THROUGH:
607 msg = "IOCTL_SCSI_PASS_THROUGH";
608 break;
609 case IOCTL_SCSI_MINIPORT:
610 msg = "IOCTL_SCSI_MINIPORT";
611 break;
612 case IOCTL_SCSI_GET_INQUIRY_DATA:
613 msg = "IOCTL_SCSI_GET_INQUIRY_DATA";
614 break;
615 case IOCTL_SCSI_GET_CAPABILITIES:
616 msg = "IOCTL_SCSI_GET_CAPABILITIES";
617 break;
618 case IOCTL_SCSI_PASS_THROUGH_DIRECT:
619 msg = "IOCTL_SCSI_PASS_THROUGH_DIRECT";
620 break;
621 case IOCTL_SCSI_GET_ADDRESS:
622 msg = "IOCTL_SCSI_GET_ADDRESS";
623 break;
624 case IOCTL_SCSI_RESCAN_BUS:
625 msg = "IOCTL_SCSI_RESCAN_BUS";
626 break;
627 case IOCTL_SCSI_GET_DUMP_POINTERS:
628 msg = "IOCTL_SCSI_GET_DUMP_POINTERS";
629 break;
630 case IOCTL_SCSI_FREE_DUMP_POINTERS:
631 msg = "IOCTL_SCSI_FREE_DUMP_POINTERS";
632 break;
633 case IOCTL_IDE_PASS_THROUGH:
634 msg = "IOCTL_IDE_PASS_THROUGH";
635 break;
636 case IOCTL_CDROM_UNLOAD_DRIVER:
637 msg = "IOCTL_CDROM_UNLOAD_DRIVER";
638 break;
639 case IOCTL_CDROM_READ_TOC:
640 msg = "IOCTL_CDROM_READ_TOC";
641 break;
642 case IOCTL_CDROM_GET_CONTROL:
643 msg = "IOCTL_CDROM_GET_CONTROL";
644 break;
645 case IOCTL_CDROM_PLAY_AUDIO_MSF:
646 msg = "IOCTL_CDROM_PLAY_AUDIO_MSF";
647 break;
648 case IOCTL_CDROM_SEEK_AUDIO_MSF:
649 msg = "IOCTL_CDROM_SEEK_AUDIO_MSF";
650 break;
651 case IOCTL_CDROM_STOP_AUDIO:
652 msg = "IOCTL_CDROM_STOP_AUDIO";
653 break;
654 case IOCTL_CDROM_PAUSE_AUDIO:
655 msg = "IOCTL_CDROM_PAUSE_AUDIO";
656 break;
657 case IOCTL_CDROM_RESUME_AUDIO:
658 msg = "IOCTL_CDROM_RESUME_AUDIO";
659 break;
660 case IOCTL_CDROM_GET_VOLUME:
661 msg = "IOCTL_CDROM_GET_VOLUME";
662 break;
663 case IOCTL_CDROM_SET_VOLUME:
664 msg = "IOCTL_CDROM_SET_VOLUME";
665 break;
666 case IOCTL_CDROM_READ_Q_CHANNEL:
667 msg = "IOCTL_CDROM_READ_Q_CHANNEL";
668 break;
669 case IOCTL_CDROM_GET_LAST_SESSION:
670 msg = "IOCTL_CDROM_GET_LAST_SESSION";
671 break;
672 case IOCTL_CDROM_RAW_READ:
673 msg = "IOCTL_CDROM_RAW_READ";
674 break;
675 case IOCTL_CDROM_DISK_TYPE:
676 msg = "IOCTL_CDROM_DISK_TYPE";
677 break;
678 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
679 msg = "IOCTL_CDROM_GET_DRIVE_GEOMETRY";
680 break;
681 case IOCTL_CDROM_CHECK_VERIFY:
682 msg = "IOCTL_CDROM_CHECK_VERIFY";
683 break;
684 case IOCTL_CDROM_MEDIA_REMOVAL:
685 msg = "IOCTL_CDROM_MEDIA_REMOVAL";
686 break;
687 case IOCTL_CDROM_EJECT_MEDIA:
688 msg = "IOCTL_CDROM_EJECT_MEDIA";
689 break;
690 case IOCTL_CDROM_LOAD_MEDIA:
691 msg = "IOCTL_CDROM_LOAD_MEDIA";
692 break;
693 case IOCTL_CDROM_RESERVE:
694 msg = "IOCTL_CDROM_RESERVE";
695 break;
696 case IOCTL_CDROM_RELEASE:
697 msg = "IOCTL_CDROM_RELEASE";
698 break;
699 case IOCTL_CDROM_FIND_NEW_DEVICES:
700 msg = "IOCTL_CDROM_FIND_NEW_DEVICES";
701 break;
702 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
703 msg = "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS";
704 break;
705 }
706 if(msg) {
707 dprintf(("HMDeviceDiskClass::DeviceIoControl %s %x %d %x %d %x %x", msg, lpInBuffer, nInBufferSize,
708 lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped));
709 }
710#endif
711
712 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
713 if(drvInfo == NULL) {
714 dprintf(("ERROR: DeviceIoControl: drvInfo == NULL!!!"));
715 DebugInt3();
716 SetLastError(ERROR_INVALID_HANDLE);
717 return FALSE;
718 }
719 switch(dwIoControlCode)
720 {
721 case FSCTL_DELETE_REPARSE_POINT:
722 case FSCTL_DISMOUNT_VOLUME:
723 case FSCTL_GET_COMPRESSION:
724 case FSCTL_GET_REPARSE_POINT:
725 case FSCTL_LOCK_VOLUME:
726 case FSCTL_QUERY_ALLOCATED_RANGES:
727 case FSCTL_SET_COMPRESSION:
728 case FSCTL_SET_REPARSE_POINT:
729 case FSCTL_SET_SPARSE:
730 case FSCTL_SET_ZERO_DATA:
731 case FSCTL_UNLOCK_VOLUME:
732 break;
733
734 case IOCTL_DISK_FORMAT_TRACKS:
735 case IOCTL_DISK_GET_DRIVE_LAYOUT:
736 break;
737
738 case IOCTL_DISK_IS_WRITABLE:
739 {
740 APIRET rc;
741 DWORD ret;
742 ULONG ulBytesRead = 0; /* Number of bytes read by DosRead */
743 ULONG ulWrote = 0; /* Number of bytes written by DosWrite */
744 ULONG ulLocal = 0; /* File pointer position after DosSetFilePtr */
745 UCHAR uchFileData[1] = {'0'}; /* Data to write to file */
746
747 if(!pHMHandleData->hHMHandle)
748 {
749 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
750 if(!pHMHandleData->hHMHandle) {
751 dprintf(("No disk inserted; aborting"));
752 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
753 return FALSE;
754 }
755 }
756 if(drvInfo->driveType == DRIVE_CDROM) {
757 //TODO: check behaviour in NT
758 SetLastError(ERROR_WRITE_PROTECT);
759 return FALSE;
760 }
761 else
762 if(drvInfo->driveType == DRIVE_FIXED) {
763 SetLastError(ERROR_SUCCESS);
764 return TRUE;
765 }
766
767 ULONG oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
768
769 /* Read the first byte of the disk */
770 rc = OSLibDosRead(pHMHandleData->hHMHandle, /* File Handle */
771 uchFileData, /* String to be read */
772 1L, /* Length of string to be read */
773 &ulBytesRead); /* Bytes actually read */
774
775 if (rc == 0)
776 {
777 dprintf(("IOCTL_DISK_IS_WRITABLE:OSLibDosRead failed with rc %08xh %x", rc,GetLastError()));
778 SetLastError(ERROR_ACCESS_DENIED);
779 goto writecheckfail;
780 }
781
782 /* Move the file pointer back */
783 rc = OSLibDosSetFilePtr (pHMHandleData->hHMHandle, /* File Handle */
784 -1,OSLIB_SETPTR_FILE_CURRENT);
785 if (rc == -1)
786 {
787 dprintf(("IOCTL_DISK_IS_WRITABLE:OSLibDosSetFilePtr failed with rc %d", rc));
788 SetLastError(ERROR_ACCESS_DENIED);
789 goto writecheckfail;
790 }
791
792 rc = OSLibDosWrite(pHMHandleData->hHMHandle, /* File handle */
793 (PVOID) uchFileData, /* String to be written */
794 1, /* Size of string to be written */
795 &ulWrote); /* Bytes actually written */
796
797 dprintf2(("IOCTL_DISK_IS_WRITABLE:OSLibDosWrite returned with rc %x %x", rc,GetLastError()));
798 if (rc == 0)
799 {
800 if (GetLastError() == ERROR_WRITE_PROTECT)
801 {
802 SetLastError(ERROR_WRITE_PROTECT);
803 goto writecheckfail;
804 }
805 }
806 SetErrorMode(oldmode);
807 SetLastError(ERROR_SUCCESS);
808 return TRUE;
809
810writecheckfail:
811 SetErrorMode(oldmode);
812 return FALSE;
813 }
814 //Basically the same as IOCTL_DISK_GET_DRIVE_GEOMETRY, but these two ioctls
815 //are supposed to work even without media in the drive
816 case IOCTL_STORAGE_GET_MEDIA_TYPES:
817 case IOCTL_DISK_GET_MEDIA_TYPES:
818 {
819 PDISK_GEOMETRY pGeom = (PDISK_GEOMETRY)lpOutBuffer;
820 if(nOutBufferSize < sizeof(DISK_GEOMETRY) || !pGeom) {
821 SetLastError(ERROR_INSUFFICIENT_BUFFER);
822 return FALSE;
823 }
824 if(lpBytesReturned) {
825 *lpBytesReturned = 0;
826 }
827 if(!pHMHandleData->hHMHandle) {
828 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
829 //we don't care if there's a disk present or not
830 }
831
832 if(OSLibDosGetDiskGeometry(pHMHandleData->hHMHandle, drvInfo->driveLetter, pGeom) == FALSE) {
833 dprintf(("!ERROR!: IOCTL_DISK_GET_MEDIA_TYPES: OSLibDosGetDiskGeometry failed!!"));
834 return FALSE;
835 }
836 if(lpBytesReturned) {
837 *lpBytesReturned = sizeof(DISK_GEOMETRY);
838 }
839 SetLastError(ERROR_SUCCESS);
840 return TRUE;
841 }
842
843 //This ioctl is different from IOCTL_DISK_GET_MEDIA_TYPES; some applications
844 //use it to determine if a disk is present or whether a media change has
845 //occurred
846 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
847 {
848 PDISK_GEOMETRY pGeom = (PDISK_GEOMETRY)lpOutBuffer;
849 if(nOutBufferSize < sizeof(DISK_GEOMETRY) || !pGeom) {
850 SetLastError(ERROR_INSUFFICIENT_BUFFER);
851 return FALSE;
852 }
853 if(lpBytesReturned) {
854 *lpBytesReturned = 0;
855 }
856
857 ULONG volumelabel;
858 APIRET rc;
859
860 if(!pHMHandleData->hHMHandle) {
861 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
862 if(!pHMHandleData->hHMHandle) {
863 dprintf(("No disk inserted; aborting"));
864 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
865 return FALSE;
866 }
867 }
868
869 //Applications can use this IOCTL to check if the floppy has been changed
870 //OSLibDosGetDiskGeometry won't fail when that happens so we read the
871 //volume label from the disk and return ERROR_MEDIA_CHANGED if the volume
872 //label has changed
873 //TODO: Find better way to determine if floppy was removed or switched
874 if(drvInfo->driveType != DRIVE_FIXED)
875 {
876 rc = OSLibDosQueryVolumeSerialAndName(1 + drvInfo->driveLetter - 'A', &volumelabel, NULL, 0);
877 if(rc) {
878 dprintf(("IOCTL_DISK_GET_DRIVE_GEOMETRY: OSLibDosQueryVolumeSerialAndName failed with rc %d", GetLastError()));
879 if(pHMHandleData->hHMHandle) {
880 if(drvInfo->fLocked) {
881 dprintf(("Unlocking drive"));
882 OSLibDosDevIOCtl(pHMHandleData->hHMHandle,IOCTL_DISK,DSK_UNLOCKDRIVE,0,0,0,0,0,0);
883 drvInfo->fLocked = FALSE;
884 }
885 OSLibDosClose(pHMHandleData->hHMHandle);
886 }
887 pHMHandleData->hHMHandle = 0;
888 SetLastError(ERROR_MEDIA_CHANGED);
889 return FALSE;
890 }
891 if(volumelabel != drvInfo->dwVolumelabel) {
892 dprintf(("IOCTL_DISK_GET_DRIVE_GEOMETRY: volume changed %x -> %x", drvInfo->dwVolumelabel, volumelabel));
893 SetLastError(ERROR_MEDIA_CHANGED);
894 return FALSE;
895 }
896 }
897
898 if(drvInfo->fPhysicalDisk) {
899 if(OSLibLVMGetDiskGeometry(drvInfo->dwPhysicalDiskNr, pGeom) == FALSE) {
900 dprintf(("!ERROR!: IOCTL_DISK_GET_DRIVE_GEOMETRY: OSLibDosGetDiskGeometry failed!!"));
901 return FALSE;
902 }
903 }
904 else {
905 if(OSLibDosGetDiskGeometry(pHMHandleData->hHMHandle, drvInfo->driveLetter, pGeom) == FALSE) {
906 dprintf(("!ERROR!: IOCTL_DISK_GET_DRIVE_GEOMETRY: OSLibDosGetDiskGeometry failed!!"));
907 return FALSE;
908 }
909 }
910 dprintf(("Cylinders %d", pGeom->Cylinders));
911 dprintf(("TracksPerCylinder %d", pGeom->TracksPerCylinder));
912 dprintf(("SectorsPerTrack %d", pGeom->SectorsPerTrack));
913 dprintf(("BytesPerSector %d", pGeom->BytesPerSector));
914 dprintf(("MediaType %d", pGeom->MediaType));
915 if(lpBytesReturned) {
916 *lpBytesReturned = sizeof(DISK_GEOMETRY);
917 }
918 SetLastError(ERROR_SUCCESS);
919 return TRUE;
920 }
921
922 case IOCTL_DISK_GET_PARTITION_INFO:
923 {
924 PPARTITION_INFORMATION pPartition = (PPARTITION_INFORMATION)lpOutBuffer;
925 if(nOutBufferSize < sizeof(PARTITION_INFORMATION) || !pPartition) {
926 SetLastError(ERROR_INSUFFICIENT_BUFFER);
927 return FALSE;
928 }
929 if(lpBytesReturned) {
930 *lpBytesReturned = sizeof(PARTITION_INFORMATION);
931 }
932 if(OSLibLVMGetPartitionInfo(drvInfo->driveLetter, drvInfo->szVolumeName, pPartition) == FALSE) {
933 SetLastError(ERROR_NOT_ENOUGH_MEMORY); //wrong error, but who cares
934 return FALSE;
935 }
936
937 SetLastError(ERROR_SUCCESS);
938 return TRUE;
939 }
940
941 case IOCTL_DISK_LOAD_MEDIA:
942 case IOCTL_DISK_MEDIA_REMOVAL:
943 case IOCTL_DISK_PERFORMANCE:
944 case IOCTL_DISK_REASSIGN_BLOCKS:
945 case IOCTL_DISK_SET_DRIVE_LAYOUT:
946 case IOCTL_DISK_SET_PARTITION_INFO:
947 case IOCTL_DISK_VERIFY:
948 case IOCTL_SERIAL_LSRMST_INSERT:
949 break;
950
951
952 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
953 {
954 PVOLUME_DISK_EXTENTS pVolExtent = (PVOLUME_DISK_EXTENTS)lpOutBuffer;
955 if(nOutBufferSize < sizeof(VOLUME_DISK_EXTENTS) || !pVolExtent) {
956 SetLastError(ERROR_INSUFFICIENT_BUFFER);
957 return FALSE;
958 }
959 if(OSLibLVMGetVolumeExtents(drvInfo->driveLetter, drvInfo->szVolumeName, pVolExtent) == FALSE) {
960 SetLastError(ERROR_NOT_ENOUGH_MEMORY); //wrong error, but who cares
961 return FALSE;
962 }
963
964 if(lpBytesReturned) {
965 *lpBytesReturned = sizeof(VOLUME_DISK_EXTENTS);
966 }
967 SetLastError(ERROR_SUCCESS);
968 return TRUE;
969 }
970
971 // -----------
972 // CDROM class
973 // -----------
974 case IOCTL_CDROM_READ_TOC:
975 {
976#pragma pack(1)
977 typedef struct
978 {
979 BYTE ucFirstTrack;
980 BYTE ucLastTrack;
981 DWORD ulLeadOutAddr;
982 } AudioDiskInfo;
983 typedef struct
984 {
985 DWORD ulTrackAddr;
986 BYTE ucTrackControl;
987 } AudioTrackInfo;
988 typedef struct
989 {
990 BYTE signature[4];
991 BYTE ucTrack;
992 } ParameterBlock;
993#pragma pack()
994 PCDROM_TOC pTOC = (PCDROM_TOC)lpOutBuffer;
995 DWORD rc, numtracks;
996 DWORD parsize = 4;
997 DWORD datasize;
998 AudioDiskInfo diskinfo;
999 AudioTrackInfo trackinfo;
1000 ParameterBlock parm;
1001
1002 if(lpBytesReturned)
1003 *lpBytesReturned = 0;
1004
1005 if(!pTOC) {
1006 SetLastError(ERROR_INVALID_PARAMETER);
1007 return FALSE;
1008 }
1009 if(nOutBufferSize < sizeof(CDROM_TOC)) {
1010 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1011 return FALSE;
1012 }
1013 memset(pTOC, 0, nOutBufferSize);
1014 //IOCTL_CDROMAUDIO (0x81), CDROMAUDIO_GETAUDIODISK (0x61)
1015 datasize = sizeof(diskinfo);
1016 rc = OSLibDosDevIOCtl(pHMHandleData->hHMHandle, 0x81, 0x61, &drvInfo->signature[0], 4, &parsize,
1017 &diskinfo, sizeof(diskinfo), &datasize);
1018 if(rc != NO_ERROR) {
1019 dprintf(("OSLibDosDevIOCtl failed with rc %d", rc));
1020 return FALSE;
1021 }
1022 pTOC->FirstTrack = diskinfo.ucFirstTrack;
1023 pTOC->LastTrack = diskinfo.ucLastTrack;
1024 numtracks = pTOC->LastTrack - pTOC->FirstTrack + 1;
1025 dprintf(("first %d, last %d, num %d", pTOC->FirstTrack, pTOC->LastTrack, numtracks));
1026
1027 //numtracks+1, because we have to add a track at the end
1028 int length = 4 + (numtracks+1)*sizeof(TRACK_DATA);
1029 //big endian format
1030 pTOC->Length[0] = HIBYTE((length-2)); //minus length itself;
1031 pTOC->Length[1] = LOBYTE((length-2)); //minus length itself;
1032
1033 if(nOutBufferSize < length) {
1034 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1035 return FALSE;
1036 }
1037
1038 for(int i=0;i<numtracks;i++)
1039 {
1040 parsize = sizeof(parm);
1041 memcpy(parm.signature, drvInfo->signature, 4);
1042 parm.ucTrack = pTOC->FirstTrack+i;
1043
1044 datasize = sizeof(trackinfo);
1045
1046 //IOCTL_CDROMAUDIO (0x81), CDROMAUDIO_GETAUDIOTRACK (0x62)
1047 rc = OSLibDosDevIOCtl(pHMHandleData->hHMHandle, 0x81, 0x62, &parm, sizeof(parm), &parsize,
1048 &trackinfo, sizeof(trackinfo), &datasize);
1049 if(rc != NO_ERROR) {
1050 dprintf(("OSLibDosDevIOCtl failed with rc %d", rc));
1051 return FALSE;
1052 }
1053 pTOC->TrackData[i].TrackNumber = pTOC->FirstTrack + i;
1054 pTOC->TrackData[i].Reserved = 0;
1055 pTOC->TrackData[i].Control = trackinfo.ucTrackControl >> 4;
1056 pTOC->TrackData[i].Adr = trackinfo.ucTrackControl & 0xF;
1057 pTOC->TrackData[i].Reserved1 = 0;
1058 //big endian format
1059 pTOC->TrackData[i].Address[0] = HIBYTE(HIWORD(trackinfo.ulTrackAddr));
1060 pTOC->TrackData[i].Address[1] = LOBYTE(HIWORD(trackinfo.ulTrackAddr));
1061 pTOC->TrackData[i].Address[2] = HIBYTE(LOWORD(trackinfo.ulTrackAddr));
1062 pTOC->TrackData[i].Address[3] = LOBYTE(LOWORD(trackinfo.ulTrackAddr));
1063 dprintf(("IOCTL_CDROM_READ_TOC track %d Control %d Adr %d address %x", pTOC->FirstTrack+i, pTOC->TrackData[i].Control, pTOC->TrackData[i].Adr, trackinfo.ulTrackAddr));
1064 }
1065
1066 //Add a track at the end (presumably so the app can determine the size of the 1st track)
1067 //That is what NT4, SP6 does anyway
1068 pTOC->TrackData[numtracks].TrackNumber = 0xAA;
1069 pTOC->TrackData[numtracks].Reserved = 0;
1070 pTOC->TrackData[numtracks].Control = pTOC->TrackData[numtracks-1].Control;
1071 pTOC->TrackData[numtracks].Adr = pTOC->TrackData[numtracks-1].Adr;
1072 pTOC->TrackData[numtracks].Reserved1 = 0;
1073 //big endian format
1074 //Address of pseudo track is the address of the lead-out track
1075 pTOC->TrackData[numtracks].Address[0] = HIBYTE(HIWORD(diskinfo.ulLeadOutAddr));
1076 pTOC->TrackData[numtracks].Address[1] = LOBYTE(HIWORD(diskinfo.ulLeadOutAddr));
1077 pTOC->TrackData[numtracks].Address[2] = HIBYTE(LOWORD(diskinfo.ulLeadOutAddr));
1078 pTOC->TrackData[numtracks].Address[3] = LOBYTE(LOWORD(diskinfo.ulLeadOutAddr));
1079
1080 if(lpBytesReturned)
1081 *lpBytesReturned = length;
1082
1083 SetLastError(ERROR_SUCCESS);
1084 return TRUE;
1085 }
1086
1087 case IOCTL_CDROM_UNLOAD_DRIVER:
1088 case IOCTL_CDROM_GET_CONTROL:
1089 break;
1090
1091 case IOCTL_CDROM_PLAY_AUDIO_MSF:
1092 {
1093#pragma pack(1)
1094 struct
1095 {
1096 DWORD ucSignature;
1097 BYTE ucAddressingMode;
1098 DWORD ulStartingMSF;
1099 DWORD ulEndingMSF;
1100 } ParameterBlock;
1101#pragma pack()
1102 PCDROM_PLAY_AUDIO_MSF pPlay = (PCDROM_PLAY_AUDIO_MSF)lpInBuffer;
1103
1104 if(nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) {
1105 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1106 return FALSE;
1107 }
1108 if(lpBytesReturned)
1109 *lpBytesReturned = 0;
1110
1111 dprintf(("Play CDROM audio playback %d:%d (%d) - %d:%d (%d)", pPlay->StartingM, pPlay->StartingS, pPlay->StartingF, pPlay->EndingM, pPlay->EndingS, pPlay->EndingF));
1112
1113 // setup the parameter block
1114 memcpy(&ParameterBlock.ucSignature, drvInfo->signature, 4);
1115 ParameterBlock.ucAddressingMode = 1; // MSF format
1116
1117 ParameterBlock.ulStartingMSF = pPlay->StartingM << 16 |
1118 pPlay->StartingS << 8 |
1119 pPlay->StartingF;
1120 ParameterBlock.ulEndingMSF = pPlay->EndingM << 16 |
1121 pPlay->EndingS << 8 |
1122 pPlay->EndingF;
1123
1124 DWORD dwParameterSize = sizeof( ParameterBlock );
1125 DWORD dwDataSize = 0;
1126 DWORD ret;
1127
1128 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
1129 0x81, // IOCTL_CDROMAUDIO
1130 0x50, // CDROMAUDIO_PLAYAUDIO
1131 &ParameterBlock,
1132 sizeof( ParameterBlock ),
1133 &dwParameterSize,
1134 NULL,
1135 0,
1136 &dwDataSize);
1137 if(ret != ERROR_SUCCESS) {
1138 dprintf(("IOCTL_CDROMAUDIO, CDROMAUDIO_PLAYAUDIO failed!!"));
1139 }
1140 drvInfo->fCDPlaying = TRUE;
1141 return (ret == ERROR_SUCCESS);
1142 }
1143
1144 case IOCTL_CDROM_SEEK_AUDIO_MSF:
1145 {
1146#pragma pack(1)
1147 struct
1148 {
1149 DWORD ucSignature;
1150 BYTE ucAddressingMode;
1151 DWORD ulStartingMSF;
1152 } ParameterBlock;
1153#pragma pack()
1154 CDROM_SEEK_AUDIO_MSF *pSeek = (CDROM_SEEK_AUDIO_MSF *)lpInBuffer;
1155
1156 if(nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) {
1157 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1158 return FALSE;
1159 }
1160 if(lpBytesReturned)
1161 *lpBytesReturned = 0;
1162
1163 dprintf(("IOCTL_CDROMDISK, CDROMDISK_SEEK %d:%d (%d)", pSeek->M, pSeek->S, pSeek->F));
1164
1165 // setup the parameter block
1166 memcpy(&ParameterBlock.ucSignature, drvInfo->signature, 4);
1167 ParameterBlock.ucAddressingMode = 1; // MSF format
1168
1169 ParameterBlock.ulStartingMSF = pSeek->M << 16 |
1170 pSeek->S << 8 |
1171 pSeek->F;
1172
1173 DWORD dwParameterSize = sizeof( ParameterBlock );
1174 DWORD dwDataSize = 0;
1175 DWORD ret;
1176
1177 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
1178 0x80, // IOCTL_CDROMDISK
1179 0x50, // CDROMDISK_SEEK
1180 &ParameterBlock,
1181 sizeof( ParameterBlock ),
1182 &dwParameterSize,
1183 NULL,
1184 0,
1185 &dwDataSize);
1186 if(ret != ERROR_SUCCESS) {
1187 dprintf(("IOCTL_CDROMDISK, CDROMDISK_SEEK %x failed!!", ParameterBlock.ulStartingMSF));
1188 }
1189 return (ret == ERROR_SUCCESS);
1190 }
1191
1192 case IOCTL_CDROM_PAUSE_AUDIO:
1193 // NO BREAK CASE
1194 // Note: for OS/2, pause and stop seems to be the same!
1195
1196 case IOCTL_CDROM_STOP_AUDIO:
1197 {
1198 dprintf(("Stop / pause CDROM audio playback"));
1199 drvInfo->fCDPlaying = FALSE;
1200 return ioctlCDROMSimple(pHMHandleData,
1201 0x81, // IOCTL_CDROMAUDIO
1202 0x51, // CDROMAUDIO_STOPAUDIO
1203 lpBytesReturned, drvInfo);
1204 }
1205
1206 case IOCTL_CDROM_RESUME_AUDIO:
1207 {
1208 dprintf(("Resume CDROM audio playback"));
1209 drvInfo->fCDPlaying = TRUE;
1210 return ioctlCDROMSimple(pHMHandleData,
1211 0x81, // IOCTL_CDROMAUDIO
1212 0x52, // CDROMAUDIO_RESUMEAUDIO
1213 lpBytesReturned, drvInfo);
1214 }
1215
1216 case IOCTL_CDROM_GET_VOLUME:
1217 {
1218 PVOLUME_CONTROL pVol = (PVOLUME_CONTROL)lpOutBuffer;
1219 char volbuf[8];
1220 DWORD parsize, datasize, ret;
1221
1222 if(nOutBufferSize < sizeof(VOLUME_CONTROL) || !pVol) {
1223 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1224 return FALSE;
1225 }
1226 if(lpBytesReturned) {
1227 *lpBytesReturned = 0;
1228 }
1229 parsize = 4;
1230 datasize = 8;
1231 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle, 0x81, 0x60, drvInfo->signature, 4, &parsize,
1232 volbuf, 8, &datasize);
1233
1234 if(ret)
1235 return FALSE;
1236
1237 if(lpBytesReturned) {
1238 *lpBytesReturned = sizeof(VOLUME_CONTROL);
1239 }
1240 pVol->PortVolume[0] = volbuf[1];
1241 pVol->PortVolume[1] = volbuf[3];
1242 pVol->PortVolume[2] = volbuf[5];
1243 pVol->PortVolume[3] = volbuf[7];
1244 SetLastError(ERROR_SUCCESS);
1245 return TRUE;
1246 }
1247
1248 case IOCTL_CDROM_SET_VOLUME:
1249 {
1250 PVOLUME_CONTROL pVol = (PVOLUME_CONTROL)lpInBuffer;
1251 char volbuf[8];
1252 DWORD parsize, datasize, ret;
1253
1254 if(nInBufferSize < sizeof(VOLUME_CONTROL) || !pVol) {
1255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1256 return FALSE;
1257 }
1258 if(lpBytesReturned) {
1259 *lpBytesReturned = 0;
1260 }
1261 parsize = 4;
1262 datasize = 8;
1263 volbuf[0] = 0;
1264 volbuf[1] = pVol->PortVolume[0];
1265 volbuf[2] = 1;
1266 volbuf[3] = pVol->PortVolume[1];
1267 volbuf[4] = 2;
1268 volbuf[5] = pVol->PortVolume[2];
1269 volbuf[6] = 3;
1270 volbuf[7] = pVol->PortVolume[3];
1271 dprintf(("Set CD volume (%d,%d)(%d,%d)", pVol->PortVolume[0], pVol->PortVolume[1], pVol->PortVolume[2], pVol->PortVolume[3]));
1272 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle, 0x81, 0x40, drvInfo->signature, 4, &parsize,
1273 volbuf, 8, &datasize);
1274
1275 if(ret)
1276 return FALSE;
1277
1278 SetLastError(ERROR_SUCCESS);
1279 return TRUE;
1280 }
1281 case IOCTL_CDROM_READ_Q_CHANNEL:
1282 {
1283#pragma pack(1)
1284 struct
1285 {
1286 BYTE ucControlAddr;
1287 BYTE ucTrackNr;
1288 BYTE ucIndex;
1289 BYTE ucRuntimeTrackMin;
1290 BYTE ucRuntimeTrackSec;
1291 BYTE ucRuntimeTrackFrame;
1292 BYTE ucReserved;
1293 BYTE ucRuntimeDiscMin;
1294 BYTE ucRuntimeDiscSec;
1295 BYTE ucRuntimeDiscFrame;
1296 } DataBlock;
1297 struct {
1298 WORD usAudioStatus;
1299 DWORD ulStartLoc;
1300 DWORD ulEndLoc;
1301 } DataBlockStatus;
1302#pragma pack()
1303 CDROM_SUB_Q_DATA_FORMAT *pFormat = (CDROM_SUB_Q_DATA_FORMAT*)lpInBuffer;
1304 SUB_Q_CHANNEL_DATA *pChannelData = (SUB_Q_CHANNEL_DATA *)lpOutBuffer;
1305 char signature[8];
1306
1307 if(nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT) || !pFormat) {
1308 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1309 return FALSE;
1310 }
1311 if(nOutBufferSize < sizeof(SUB_Q_CHANNEL_DATA) || !pChannelData) {
1312 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1313 return FALSE;
1314 }
1315 if(lpBytesReturned) {
1316 *lpBytesReturned = 0;
1317 }
1318
1319 DWORD dwParameterSize = 4;
1320 DWORD dwDataSize = sizeof(DataBlock);
1321 DWORD ret;
1322
1323 memcpy(signature, drvInfo->signature, dwParameterSize);
1324
1325 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
1326 0x81, // IOCTL_CDROMAUDIO
1327 0x63, // CDROMAUDIO_GETSUBCHANNELQ
1328 signature,
1329 dwParameterSize,
1330 &dwParameterSize,
1331 &DataBlock,
1332 sizeof(DataBlock),
1333 &dwDataSize);
1334 if(ret != ERROR_SUCCESS) {
1335 dprintf(("IOCTL_CDROMAUDIO, CDROMAUDIO_GETSUBCHANNELQ failed!!"));
1336 return FALSE;
1337 }
1338
1339 dwDataSize = sizeof(DataBlockStatus);
1340 ret = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
1341 0x81, // IOCTL_CDROMAUDIO
1342 0x65, // CDROMAUDIO_GETAUDIOSTATUS
1343 signature,
1344 dwParameterSize,
1345 &dwParameterSize,
1346 &DataBlockStatus,
1347 sizeof(DataBlockStatus),
1348 &dwDataSize);
1349 if(ret != ERROR_SUCCESS) {
1350 dprintf(("IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOSTATUS failed!!"));
1351 return FALSE;
1352 }
1353 dprintf(("CDROMAUDIO_GETAUDIOSTATUS returned %d %x %x", DataBlockStatus.usAudioStatus, DataBlockStatus.ulStartLoc, DataBlockStatus.ulEndLoc));
1354
1355 pChannelData->CurrentPosition.Header.Reserved = 0;
1356 if(DataBlockStatus.usAudioStatus & 1) {
1357 pChannelData->CurrentPosition.Header.AudioStatus = AUDIO_STATUS_PAUSED;
1358 }
1359 else {
1360 if(DataBlockStatus.ulStartLoc == 0) {//no play command has been issued before
1361 pChannelData->CurrentPosition.Header.AudioStatus = AUDIO_STATUS_NO_STATUS;
1362 }
1363 else {//assume in progress, but could alse be finished playing
1364 pChannelData->CurrentPosition.Header.AudioStatus = (drvInfo->fCDPlaying) ? AUDIO_STATUS_IN_PROGRESS : AUDIO_STATUS_PLAY_COMPLETE;
1365 }
1366 }
1367
1368 switch(pFormat->Format) {
1369 case IOCTL_CDROM_SUB_Q_CHANNEL:
1370 dprintf(("IOCTL_CDROM_SUB_Q_CHANNEL not supported"));
1371 return FALSE;
1372 case IOCTL_CDROM_CURRENT_POSITION:
1373 pChannelData->CurrentPosition.Header.DataLength[0] = sizeof(pChannelData->CurrentPosition);
1374 pChannelData->CurrentPosition.Header.DataLength[1] = 0;
1375 pChannelData->CurrentPosition.Control = DataBlock.ucControlAddr >> 4;
1376 pChannelData->CurrentPosition.ADR = DataBlock.ucControlAddr & 0xF;
1377 pChannelData->CurrentPosition.IndexNumber = BCDToDec(DataBlock.ucIndex);
1378 pChannelData->CurrentPosition.TrackNumber = BCDToDec(DataBlock.ucTrackNr);
1379 pChannelData->CurrentPosition.TrackRelativeAddress[1] = DataBlock.ucRuntimeTrackMin;
1380 pChannelData->CurrentPosition.TrackRelativeAddress[2] = DataBlock.ucRuntimeTrackSec;
1381 pChannelData->CurrentPosition.TrackRelativeAddress[3] = DataBlock.ucRuntimeTrackFrame;
1382 pChannelData->CurrentPosition.AbsoluteAddress[1] = DataBlock.ucRuntimeDiscMin;
1383 pChannelData->CurrentPosition.AbsoluteAddress[2] = DataBlock.ucRuntimeDiscSec;
1384 pChannelData->CurrentPosition.AbsoluteAddress[3] = DataBlock.ucRuntimeDiscFrame;
1385 pChannelData->CurrentPosition.FormatCode = IOCTL_CDROM_CURRENT_POSITION;
1386 dprintf(("IOCTL_CDROM_CURRENT_POSITION: Control %x ADR %x Index %d Track %d Track Rel %d:%d (%d) Absolute %d:%d (%d)", pChannelData->CurrentPosition.Control, pChannelData->CurrentPosition.ADR, pChannelData->CurrentPosition.IndexNumber, pChannelData->CurrentPosition.TrackNumber, pChannelData->CurrentPosition.TrackRelativeAddress[1], pChannelData->CurrentPosition.TrackRelativeAddress[2], pChannelData->CurrentPosition.TrackRelativeAddress[3], pChannelData->CurrentPosition.AbsoluteAddress[1], pChannelData->CurrentPosition.AbsoluteAddress[2], pChannelData->CurrentPosition.AbsoluteAddress[3]));
1387 if(lpBytesReturned) {
1388 *lpBytesReturned = sizeof(*pChannelData);
1389 }
1390 break;
1391 case IOCTL_CDROM_MEDIA_CATALOG:
1392 dprintf(("IOCTL_CDROM_MEDIA_CATALOG not supported"));
1393 return FALSE;
1394 case IOCTL_CDROM_TRACK_ISRC:
1395 dprintf(("IOCTL_CDROM_TRACK_ISRC not supported"));
1396 return FALSE;
1397 }
1398 return (ret == ERROR_SUCCESS);
1399 }
1400
1401 case IOCTL_CDROM_GET_LAST_SESSION:
1402 case IOCTL_CDROM_RAW_READ:
1403 case IOCTL_CDROM_DISK_TYPE:
1404 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1405 case IOCTL_CDROM_MEDIA_REMOVAL:
1406 break;
1407
1408 case IOCTL_CDROM_EJECT_MEDIA:
1409 {
1410 dprintf(("Eject CDROM media"));
1411 return ioctlCDROMSimple(pHMHandleData,
1412 0x80, // IOCTL_CDROM
1413 0x44, // CDROMDISK_EJECTDISK
1414 lpBytesReturned, drvInfo);
1415 }
1416
1417 case IOCTL_CDROM_LOAD_MEDIA:
1418 {
1419 dprintf(("Loading CDROM media"));
1420 return ioctlCDROMSimple(pHMHandleData,
1421 0x80, // IOCTL_CDROM
1422 0x45, // CDROMDISK_CLOSETRAY
1423 lpBytesReturned, drvInfo);
1424 }
1425
1426 case IOCTL_CDROM_RESERVE:
1427 case IOCTL_CDROM_RELEASE:
1428 case IOCTL_CDROM_FIND_NEW_DEVICES:
1429 break;
1430
1431
1432 // -------------
1433 // STORAGE class
1434 // -------------
1435
1436 case IOCTL_CDROM_CHECK_VERIFY:
1437 if(drvInfo->driveType != DRIVE_CDROM) {
1438 SetLastError(ERROR_GEN_FAILURE); //TODO: right error?
1439 return FALSE;
1440 }
1441 //no break;
1442 case IOCTL_DISK_CHECK_VERIFY:
1443 case IOCTL_STORAGE_CHECK_VERIFY:
1444 {
1445#pragma pack(1)
1446 typedef struct
1447 {
1448 BYTE ucCommandInfo;
1449 WORD usDriveUnit;
1450 } ParameterBlock;
1451#pragma pack()
1452
1453 dprintf(("IOCTL_CDROM(DISK/STORAGE)CHECK_VERIFY %s", drvInfo->signature));
1454 if(lpBytesReturned) {
1455 *lpBytesReturned = 0;
1456 }
1457
1458 if(!pHMHandleData->hHMHandle) {
1459 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
1460 if(!pHMHandleData->hHMHandle) {
1461 dprintf(("No disk inserted; aborting"));
1462 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
1463 return FALSE;
1464 }
1465 }
1466
1467 DWORD parsize = sizeof(ParameterBlock);
1468 DWORD datasize = 2;
1469 WORD status = 0;
1470 DWORD rc;
1471 ParameterBlock parm;
1472
1473 parm.ucCommandInfo = 0;
1474 parm.usDriveUnit = drvInfo->driveLetter - 'A';
1475// rc = OSLibDosDevIOCtl(pHMHandleData->hHMHandle, 0x08, 0x66, &parm, sizeof(parm), &parsize,
1476 //TODO: this doesn't work for floppies for some reason...
1477 rc = OSLibDosDevIOCtl(-1, IOCTL_DISK, DSK_GETLOCKSTATUS, &parm, sizeof(parm), &parsize,
1478 &status, sizeof(status), &datasize);
1479 if(rc != NO_ERROR) {
1480 dprintf(("OSLibDosDevIOCtl failed with rc %d datasize %d", rc, datasize));
1481 return FALSE;
1482 }
1483 dprintf(("Disk status 0x%x", status));
1484 //if no disk present, return FALSE
1485 if(!(status & (BIT_2))) {
1486 SetLastError(ERROR_NOT_READY); //NT4, SP6 returns this
1487 return FALSE;
1488 }
1489 SetLastError(NO_ERROR);
1490 return TRUE;
1491 }
1492
1493 case IOCTL_DISK_EJECT_MEDIA:
1494 case IOCTL_STORAGE_EJECT_MEDIA:
1495 {
1496 dprintf(("Ejecting storage media"));
1497 return ioctlDISKUnlockEject(pHMHandleData,
1498 0x02, // EJECT media
1499 -1,
1500 lpBytesReturned);
1501 }
1502
1503 case IOCTL_STORAGE_LOAD_MEDIA:
1504 // case IOCTL_STORAGE_LOAD_MEDIA2:
1505 {
1506 dprintf(("Loading storage media"));
1507 return ioctlDISKUnlockEject(pHMHandleData,
1508 0x03, // LOAD media
1509 -1,
1510 lpBytesReturned);
1511 }
1512
1513 // case IOCTL_STORAGE_EJECTION_CONTROL:
1514 case IOCTL_STORAGE_MEDIA_REMOVAL:
1515 break;
1516
1517
1518 // -------------------
1519 // SCSI passthru class
1520 // -------------------
1521
1522 case IOCTL_SCSI_MINIPORT:
1523 case IOCTL_SCSI_GET_INQUIRY_DATA:
1524 break;
1525
1526 case IOCTL_SCSI_GET_CAPABILITIES:
1527 break;
1528
1529 case IOCTL_SCSI_PASS_THROUGH:
1530 //no break; same as IOCTL_SCSI_PASS_THROUGH_DIRECT
1531 case IOCTL_SCSI_PASS_THROUGH_DIRECT:
1532 {
1533 PSCSI_PASS_THROUGH_DIRECT pPacket = (PSCSI_PASS_THROUGH_DIRECT)lpOutBuffer;
1534 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1535 CDIO_CMD_BUFFER cdiocmd;
1536
1537 if(nOutBufferSize < sizeof(SCSI_PASS_THROUGH_DIRECT) ||
1538 !pPacket || pPacket->Length < sizeof(SCSI_PASS_THROUGH_DIRECT))
1539 {
1540 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1541 return FALSE;
1542 }
1543
1544 if(!drvInfo || drvInfo->fCDIoSupported == FALSE) {
1545 dprintf(("os2cdrom.dmd CD interface not supported!!"));
1546 SetLastError(ERROR_ACCESS_DENIED);
1547 return FALSE;
1548 }
1549 if(lpBytesReturned) {
1550 *lpBytesReturned = 0;
1551 }
1552
1553 if(pPacket->CdbLength > sizeof(cdiocmd.arCDB)) {
1554 dprintf(("CDB buffer too big (%d)!!", pPacket->CdbLength));
1555 SetLastError(ERROR_INVALID_PARAMETER);
1556 return FALSE;
1557 }
1558
1559 memset(&cdiocmd, 0, sizeof(cdiocmd));
1560
1561 switch(pPacket->DataIn) {
1562 case SCSI_IOCTL_DATA_OUT:
1563 cdiocmd.flDirection = CMDDIR_OUTPUT;
1564 break;
1565 case SCSI_IOCTL_DATA_IN:
1566 cdiocmd.flDirection = CMDDIR_INPUT;
1567 break;
1568 case SCSI_IOCTL_DATA_UNSPECIFIED:
1569 cdiocmd.flDirection = CMDDIR_OUTPUT|CMDDIR_INPUT;;
1570 break;
1571 default:
1572 dprintf(("Invalid DataIn (%d)!!", pPacket->DataIn));
1573 SetLastError(ERROR_INVALID_PARAMETER);
1574 return FALSE;
1575 }
1576
1577 cdiocmd.cbCDB = pPacket->CdbLength;
1578 memcpy(cdiocmd.arCDB, pPacket->Cdb, pPacket->CdbLength);
1579
1580 dprintf(("IOCTL_SCSI_PASS_THROUGH_DIRECT %x len %x, %x%02x%02x%02x %x%02x", pPacket->Cdb[0], pPacket->DataTransferLength, pPacket->Cdb[2], pPacket->Cdb[3], pPacket->Cdb[4], pPacket->Cdb[5], pPacket->Cdb[7], pPacket->Cdb[8]));
1581
1582 if(OSLibCdIoSendCommand(pHMHandleData->hHMHandle, &cdiocmd, pPacket->DataBuffer, pPacket->DataTransferLength) == FALSE) {
1583 dprintf(("OSLibCdIoSendCommand failed!!"));
1584 pPacket->ScsiStatus = SS_ERR;
1585 SetLastError(ERROR_ADAP_HDW_ERR); //returned by NT4, SP6
1586 return FALSE;
1587 }
1588
1589 if(pPacket->SenseInfoLength) {
1590 if(OSLibCdIoRequestSense(pHMHandleData->hHMHandle, (char *)pPacket + pPacket->SenseInfoOffset, pPacket->SenseInfoLength) == FALSE) {
1591 dprintf(("OSLibCdIoRequestSense failed!!"));
1592 pPacket->ScsiStatus = SS_ERR;
1593 SetLastError(ERROR_ADAP_HDW_ERR); //returned by NT4, SP6
1594 return FALSE;
1595 }
1596 }
1597 pPacket->ScsiStatus = SS_COMP;
1598 SetLastError(ERROR_SUCCESS);
1599 return TRUE;
1600 }
1601 case IOCTL_SCSI_GET_ADDRESS:
1602 {
1603 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1604
1605 if(!drvInfo || drvInfo->fCDIoSupported == FALSE) {
1606 dprintf(("os2cdrom.dmd CD interface not supported!!"));
1607 SetLastError(ERROR_ACCESS_DENIED);
1608 return FALSE;
1609 }
1610
1611 if(!lpOutBuffer || nOutBufferSize < 8) {
1612 SetLastError(ERROR_INSUFFICIENT_BUFFER); //todo: right error?
1613 return(FALSE);
1614 }
1615 SCSI_ADDRESS *addr = (SCSI_ADDRESS *)lpOutBuffer;
1616 addr->Length = sizeof(SCSI_ADDRESS);
1617 addr->PortNumber = 0;
1618 addr->PathId = 0;
1619 //irrelevant, since os2cdrom.dmd doesn't need them
1620 addr->TargetId = 1;
1621 addr->Lun = 0;
1622 SetLastError(ERROR_SUCCESS);
1623 return TRUE;
1624 }
1625
1626 case IOCTL_SCSI_RESCAN_BUS:
1627 case IOCTL_SCSI_GET_DUMP_POINTERS:
1628 case IOCTL_SCSI_FREE_DUMP_POINTERS:
1629 case IOCTL_IDE_PASS_THROUGH:
1630 break;
1631
1632 }
1633 dprintf(("HMDeviceDiskClass::DeviceIoControl: unimplemented dwIoControlCode=%08lx\n", dwIoControlCode));
1634 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1635 return FALSE;
1636}
1637/*****************************************************************************
1638 * Name : BOOL HMDeviceDiskClass::ReadFile
1639 * Purpose : read data from handle / device
1640 * Parameters: PHMHANDLEDATA pHMHandleData,
1641 * LPCVOID lpBuffer,
1642 * DWORD nNumberOfBytesToRead,
1643 * LPDWORD lpNumberOfBytesRead,
1644 * LPOVERLAPPED lpOverlapped
1645 * Variables :
1646 * Result : Boolean
1647 * Remark :
1648 * Status :
1649 *
1650 * Author : Patrick Haller [Wed, 1998/02/11 20:44]
1651 *****************************************************************************/
1652
1653BOOL HMDeviceDiskClass::ReadFile(PHMHANDLEDATA pHMHandleData,
1654 LPCVOID lpBuffer,
1655 DWORD nNumberOfBytesToRead,
1656 LPDWORD lpNumberOfBytesRead,
1657 LPOVERLAPPED lpOverlapped,
1658 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1659{
1660 LPVOID lpRealBuf;
1661 Win32MemMap *map;
1662 DWORD offset, bytesread;
1663 BOOL bRC;
1664 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1665
1666 dprintf2(("KERNEL32: HMDeviceDiskClass::ReadFile %s(%08x,%08x,%08x,%08x,%08x)",
1667 lpHMDeviceName, pHMHandleData, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped));
1668
1669 //It's legal for this pointer to be NULL
1670 if(lpNumberOfBytesRead)
1671 *lpNumberOfBytesRead = 0;
1672 else
1673 lpNumberOfBytesRead = &bytesread;
1674
1675 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) {
1676 dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!"));
1677 SetLastError(ERROR_INVALID_PARAMETER);
1678 return FALSE;
1679 }
1680
1681 if(lpCompletionRoutine) {
1682 dprintf(("!WARNING!: lpCompletionRoutine not supported -> fall back to sync IO"));
1683 }
1684
1685 //If we didn't get an OS/2 handle for the disk before, get one now
1686 if(!pHMHandleData->hHMHandle) {
1687 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
1688 if(!pHMHandleData->hHMHandle) {
1689 dprintf(("No disk inserted; aborting"));
1690 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
1691 return FALSE;
1692 }
1693 }
1694
1695 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) {
1696 dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation"));
1697 }
1698
1699 //SvL: DosRead doesn't like writing to memory addresses returned by
1700 // DosAliasMem -> search for original memory mapped pointer and use
1701 // that one + commit pages if not already present
1702 map = Win32MemMapView::findMapByView((ULONG)lpBuffer, &offset, MEMMAP_ACCESS_WRITE);
1703 if(map) {
1704 lpRealBuf = (LPVOID)((ULONG)map->getMappingAddr() + offset);
1705 DWORD nrpages = nNumberOfBytesToRead/4096;
1706 if(offset & 0xfff)
1707 nrpages++;
1708 if(nNumberOfBytesToRead & 0xfff)
1709 nrpages++;
1710
1711 map->commitPage(offset & ~0xfff, TRUE, nrpages);
1712 }
1713 else lpRealBuf = (LPVOID)lpBuffer;
1714
1715 //if unmounted volume, check upper boundary as we're accessing the entire physical drive
1716 //instead of just the volume
1717 if(drvInfo->fPhysicalDisk && (drvInfo->StartingOffset.HighPart != 0 ||
1718 drvInfo->StartingOffset.LowPart != 0))
1719 {
1720 LARGE_INTEGER distance, result, endpos;
1721
1722 //calculate end position in partition
1723 Add64(&drvInfo->StartingOffset, &drvInfo->PartitionSize, &endpos);
1724
1725 distance.HighPart = 0;
1726 distance.LowPart = nNumberOfBytesToRead;
1727 Add64(&distance, &drvInfo->CurrentFilePointer, &result);
1728
1729 //check upper boundary
1730 if(result.HighPart > endpos.HighPart ||
1731 (result.HighPart == endpos.HighPart && result.LowPart > endpos.LowPart) )
1732 {
1733 Sub64(&endpos, &drvInfo->CurrentFilePointer, &result);
1734 nNumberOfBytesToRead = result.LowPart;
1735 dprintf(("Read past end of volume; nNumberOfBytesToRead reduced to %d", nNumberOfBytesToRead));
1736 DebugInt3();
1737 }
1738 }
1739
1740 if(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) {
1741 dprintf(("ERROR: Overlapped IO not yet implememented!!"));
1742 }
1743 // else {
1744 bRC = OSLibDosRead(pHMHandleData->hHMHandle,
1745 (PVOID)lpRealBuf,
1746 nNumberOfBytesToRead,
1747 lpNumberOfBytesRead);
1748// }
1749
1750 if(bRC == 0) {
1751 dprintf(("KERNEL32: HMDeviceDiskClass::ReadFile returned %08xh %x", bRC, GetLastError()));
1752 dprintf(("%x -> %d", lpBuffer, IsBadWritePtr((LPVOID)lpBuffer, nNumberOfBytesToRead)));
1753 }
1754 else dprintf2(("KERNEL32: HMDeviceDiskClass::ReadFile read %x bytes pos %x", *lpNumberOfBytesRead, SetFilePointer(pHMHandleData, 0, NULL, FILE_CURRENT)));
1755
1756 //if unmounted volume, add starting offset to position as we're accessing the entire physical drive
1757 //instead of just the volume
1758 if(drvInfo->fPhysicalDisk && (drvInfo->StartingOffset.HighPart != 0 ||
1759 drvInfo->StartingOffset.LowPart != 0) && bRC == TRUE)
1760 {
1761 LARGE_INTEGER distance, result;
1762
1763 distance.HighPart = 0;
1764 distance.LowPart = *lpNumberOfBytesRead;
1765 Add64(&distance, &drvInfo->CurrentFilePointer, &result);
1766 drvInfo->CurrentFilePointer = result;
1767
1768 dprintf(("New unmounted volume current file pointer %08x%08x", drvInfo->CurrentFilePointer.HighPart, drvInfo->CurrentFilePointer.LowPart));
1769 }
1770
1771 return bRC;
1772}
1773/*****************************************************************************
1774 * Name : DWORD HMDeviceDiskClass::SetFilePointer
1775 * Purpose : set file pointer
1776 * Parameters: PHMHANDLEDATA pHMHandleData
1777 * LONG lDistanceToMove
1778 * PLONG lpDistanceToMoveHigh
1779 * DWORD dwMoveMethod
1780 * Variables :
1781 * Result : API returncode
1782 * Remark :
1783 * Status :
1784 *
1785 * Author : Patrick Haller [Wed, 1999/06/17 20:44]
1786 *****************************************************************************/
1787DWORD HMDeviceDiskClass::SetFilePointer(PHMHANDLEDATA pHMHandleData,
1788 LONG lDistanceToMove,
1789 PLONG lpDistanceToMoveHigh,
1790 DWORD dwMoveMethod)
1791{
1792 DWORD ret;
1793
1794 if(lpDistanceToMoveHigh) {
1795 dprintf(("KERNEL32: HMDeviceDiskClass::SetFilePointer %s %08x%08x %d",
1796 lpHMDeviceName, *lpDistanceToMoveHigh, lDistanceToMove, dwMoveMethod));
1797 }
1798
1799 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1800 if(drvInfo == NULL) {
1801 dprintf(("ERROR: SetFilePointer: drvInfo == NULL!!!"));
1802 DebugInt3();
1803 SetLastError(ERROR_INVALID_HANDLE);
1804 return FALSE;
1805 }
1806
1807 if(!pHMHandleData->hHMHandle) {
1808 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1809 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
1810 if(!pHMHandleData->hHMHandle) {
1811 dprintf(("No disk inserted; aborting"));
1812 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
1813 return -1;
1814 }
1815 }
1816
1817 //if unmounted volume, add starting offset to position as we're accessing the entire physical drive
1818 //instead of just the volume
1819 if(drvInfo->fPhysicalDisk && (drvInfo->StartingOffset.HighPart != 0 ||
1820 drvInfo->StartingOffset.LowPart != 0))
1821 {
1822 LARGE_INTEGER distance, result, endpos;
1823 LARGE_INTEGER position;
1824
1825 if(lpDistanceToMoveHigh) {
1826 distance.HighPart = *lpDistanceToMoveHigh;
1827 }
1828 else {
1829 if(lDistanceToMove < 0) {
1830 distance.HighPart = -1;
1831 }
1832 else distance.HighPart = 0;
1833 }
1834 distance.LowPart = lDistanceToMove;
1835
1836 //calculate end position in partition
1837 Add64(&drvInfo->StartingOffset, &drvInfo->PartitionSize, &endpos);
1838 result.HighPart = 0;
1839 result.LowPart = 1;
1840 Sub64(&endpos, &result, &endpos);
1841
1842 switch(dwMoveMethod) {
1843 case FILE_BEGIN:
1844 Add64(&distance, &drvInfo->StartingOffset, &result);
1845 break;
1846 case FILE_CURRENT:
1847 Add64(&distance, &drvInfo->CurrentFilePointer, &result);
1848 break;
1849 case FILE_END:
1850 Add64(&distance, &endpos, &result);
1851 break;
1852 }
1853 //check upper boundary
1854 if(result.HighPart > endpos.HighPart ||
1855 (result.HighPart == endpos.HighPart && result.LowPart > endpos.LowPart) )
1856 {
1857 SetLastError(ERROR_INVALID_PARAMETER);
1858 return -1;
1859 }
1860 //check lower boundary
1861 if(result.HighPart < drvInfo->StartingOffset.HighPart ||
1862 (result.HighPart == drvInfo->StartingOffset.HighPart && result.LowPart < drvInfo->StartingOffset.LowPart))
1863 {
1864 SetLastError(ERROR_NEGATIVE_SEEK);
1865 return -1;
1866 }
1867
1868 dprintf(("SetFilePointer (unmounted partition) %08x%08x -> %08x%08x", distance.HighPart, distance.LowPart, result.HighPart, result.LowPart));
1869 ret = OSLibDosSetFilePointer(pHMHandleData->hHMHandle,
1870 result.LowPart,
1871 (DWORD *)&result.HighPart,
1872 FILE_BEGIN);
1873
1874 Sub64(&result, &drvInfo->StartingOffset, &drvInfo->CurrentFilePointer);
1875 ret = drvInfo->CurrentFilePointer.LowPart;
1876 if(lpDistanceToMoveHigh) {
1877 *lpDistanceToMoveHigh = drvInfo->CurrentFilePointer.HighPart;
1878 }
1879 }
1880 else {
1881 ret = OSLibDosSetFilePointer(pHMHandleData->hHMHandle,
1882 lDistanceToMove,
1883 (DWORD *)lpDistanceToMoveHigh,
1884 dwMoveMethod);
1885 }
1886
1887 if(ret == -1) {
1888 dprintf(("SetFilePointer failed (error = %d)", GetLastError()));
1889 }
1890 return ret;
1891}
1892
1893/*****************************************************************************
1894 * Name : BOOL HMDeviceDiskClass::WriteFile
1895 * Purpose : write data to handle / device
1896 * Parameters: PHMHANDLEDATA pHMHandleData,
1897 * LPCVOID lpBuffer,
1898 * DWORD nNumberOfBytesToWrite,
1899 * LPDWORD lpNumberOfBytesWritten,
1900 * LPOVERLAPPED lpOverlapped
1901 * Variables :
1902 * Result : Boolean
1903 * Remark :
1904 * Status :
1905 *
1906 * Author : Patrick Haller [Wed, 1998/02/11 20:44]
1907 *****************************************************************************/
1908
1909BOOL HMDeviceDiskClass::WriteFile(PHMHANDLEDATA pHMHandleData,
1910 LPCVOID lpBuffer,
1911 DWORD nNumberOfBytesToWrite,
1912 LPDWORD lpNumberOfBytesWritten,
1913 LPOVERLAPPED lpOverlapped,
1914 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1915{
1916 LPVOID lpRealBuf;
1917 Win32MemMap *map;
1918 DWORD offset, byteswritten;
1919 BOOL bRC;
1920
1921 dprintf2(("KERNEL32: HMDeviceDiskClass::WriteFile %s(%08x,%08x,%08x,%08x,%08x) - stub?\n",
1922 lpHMDeviceName, pHMHandleData, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten,
1923 lpOverlapped));
1924
1925 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1926 if(drvInfo == NULL) {
1927 dprintf(("ERROR: WriteFile: drvInfo == NULL!!!"));
1928 DebugInt3();
1929 SetLastError(ERROR_INVALID_HANDLE);
1930 return FALSE;
1931 }
1932 if(!(drvInfo->dwAccess & GENERIC_WRITE)) {
1933 dprintf(("ERROR: WriteFile: write access denied!"));
1934 SetLastError(ERROR_ACCESS_DENIED);
1935 return FALSE;
1936 }
1937 //It's legal for this pointer to be NULL
1938 if(lpNumberOfBytesWritten)
1939 *lpNumberOfBytesWritten = 0;
1940 else
1941 lpNumberOfBytesWritten = &byteswritten;
1942
1943 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) {
1944 dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!"));
1945 SetLastError(ERROR_INVALID_PARAMETER);
1946 return FALSE;
1947 }
1948 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) {
1949 dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation"));
1950 }
1951 if(lpCompletionRoutine) {
1952 dprintf(("!WARNING!: lpCompletionRoutine not supported -> fall back to sync IO"));
1953 }
1954
1955 //If we didn't get an OS/2 handle for the disk before, get one now
1956 if(!pHMHandleData->hHMHandle) {
1957 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
1958 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
1959 if(!pHMHandleData->hHMHandle) {
1960 dprintf(("No disk inserted; aborting"));
1961 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
1962 return FALSE;
1963 }
1964 }
1965
1966 //SvL: DosWrite doesn't like reading from memory addresses returned by
1967 // DosAliasMem -> search for original memory mapped pointer and use
1968 // that one + commit pages if not already present
1969 map = Win32MemMapView::findMapByView((ULONG)lpBuffer, &offset, MEMMAP_ACCESS_READ);
1970 if(map) {
1971 lpRealBuf = (LPVOID)((ULONG)map->getMappingAddr() + offset);
1972 DWORD nrpages = nNumberOfBytesToWrite/4096;
1973 if(offset & 0xfff)
1974 nrpages++;
1975 if(nNumberOfBytesToWrite & 0xfff)
1976 nrpages++;
1977
1978 map->commitPage(offset & ~0xfff, TRUE, nrpages);
1979 }
1980 else lpRealBuf = (LPVOID)lpBuffer;
1981
1982 //if unmounted volume, check upper boundary as we're accessing the entire physical drive
1983 //instead of just the volume
1984 if(drvInfo->fPhysicalDisk && (drvInfo->StartingOffset.HighPart != 0 ||
1985 drvInfo->StartingOffset.LowPart != 0))
1986 {
1987 LARGE_INTEGER distance, result, endpos;
1988
1989 //calculate end position in partition
1990 Add64(&drvInfo->StartingOffset, &drvInfo->PartitionSize, &endpos);
1991
1992 distance.HighPart = 0;
1993 distance.LowPart = nNumberOfBytesToWrite;
1994 Add64(&distance, &drvInfo->CurrentFilePointer, &result);
1995
1996 //check upper boundary
1997 if(result.HighPart > endpos.HighPart ||
1998 (result.HighPart == endpos.HighPart && result.LowPart > endpos.LowPart) )
1999 {
2000 Sub64(&endpos, &drvInfo->CurrentFilePointer, &result);
2001 nNumberOfBytesToWrite = result.LowPart;
2002 dprintf(("Write past end of volume; nNumberOfBytesToWrite reduced to %d", nNumberOfBytesToWrite));
2003 DebugInt3();
2004 }
2005 }
2006
2007 if(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) {
2008 dprintf(("ERROR: Overlapped IO not yet implememented!!"));
2009 }
2010// else {
2011 bRC = OSLibDosWrite(pHMHandleData->hHMHandle,
2012 (PVOID)lpRealBuf,
2013 nNumberOfBytesToWrite,
2014 lpNumberOfBytesWritten);
2015// }
2016
2017 //if unmounted volume, add starting offset to position as we're accessing the entire physical drive
2018 //instead of just the volume
2019 if(drvInfo->fPhysicalDisk && (drvInfo->StartingOffset.HighPart != 0 ||
2020 drvInfo->StartingOffset.LowPart != 0) && bRC == TRUE)
2021 {
2022 LARGE_INTEGER distance, result;
2023
2024 distance.HighPart = 0;
2025 distance.LowPart = *lpNumberOfBytesWritten;
2026 Add64(&distance, &drvInfo->CurrentFilePointer, &result);
2027 drvInfo->CurrentFilePointer = result;
2028
2029 dprintf(("New unmounted volume current file pointer %08x%08x", drvInfo->CurrentFilePointer.HighPart, drvInfo->CurrentFilePointer.LowPart));
2030 }
2031
2032 dprintf2(("KERNEL32: HMDeviceDiskClass::WriteFile returned %08xh\n",
2033 bRC));
2034
2035 return bRC;
2036}
2037
2038/*****************************************************************************
2039 * Name : DWORD HMDeviceDiskClass::GetFileSize
2040 * Purpose : set file time
2041 * Parameters: PHMHANDLEDATA pHMHandleData
2042 * PDWORD pSize
2043 * Variables :
2044 * Result : API returncode
2045 * Remark :
2046 * Status :
2047 *
2048 * Author : Patrick Haller [Wed, 1999/06/17 20:44]
2049 *****************************************************************************/
2050
2051DWORD HMDeviceDiskClass::GetFileSize(PHMHANDLEDATA pHMHandleData,
2052 PDWORD lpdwFileSizeHigh)
2053{
2054 DRIVE_INFO *drvInfo = (DRIVE_INFO*)pHMHandleData->dwUserData;
2055 if(drvInfo == NULL) {
2056 dprintf(("ERROR: GetFileSize: drvInfo == NULL!!!"));
2057 DebugInt3();
2058 SetLastError(ERROR_INVALID_HANDLE);
2059 return -1; //INVALID_SET_FILE_POINTER
2060 }
2061
2062 dprintf2(("KERNEL32: HMDeviceDiskClass::GetFileSize %s(%08xh,%08xh)\n",
2063 lpHMDeviceName, pHMHandleData, lpdwFileSizeHigh));
2064
2065 //If we didn't get an OS/2 handle for the disk before, get one now
2066 if(!pHMHandleData->hHMHandle) {
2067 pHMHandleData->hHMHandle = OpenDisk(drvInfo);
2068 if(!pHMHandleData->hHMHandle) {
2069 dprintf(("No disk inserted; aborting"));
2070 SetLastError((drvInfo->fShareViolation) ? ERROR_SHARING_VIOLATION : ERROR_NOT_READY);
2071 return -1; //INVALID_SET_FILE_POINTER
2072 }
2073 }
2074
2075 if(drvInfo->PartitionSize.HighPart || drvInfo->PartitionSize.LowPart) {
2076 if(lpdwFileSizeHigh)
2077 *lpdwFileSizeHigh = drvInfo->PartitionSize.HighPart;
2078
2079 return drvInfo->PartitionSize.LowPart;
2080 }
2081 else {
2082 LARGE_INTEGER position, size;
2083
2084 //get current position
2085 position.HighPart = 0;
2086 position.LowPart = SetFilePointer(pHMHandleData, 0, (PLONG)&position.HighPart, FILE_CURRENT);
2087 SetFilePointer(pHMHandleData, 0, NULL, FILE_BEGIN);
2088 size.HighPart = 0;
2089 size.LowPart = SetFilePointer(pHMHandleData, 0, (PLONG)&size.HighPart, FILE_END);
2090
2091 //restore old position
2092 SetFilePointer(pHMHandleData, position.LowPart, (PLONG)&position.HighPart, FILE_BEGIN);
2093
2094 if(lpdwFileSizeHigh)
2095 *lpdwFileSizeHigh = size.HighPart;
2096
2097 return size.LowPart;
2098 }
2099}
2100
2101/*****************************************************************************
2102 * Name : DWORD HMDeviceDiskClass::GetFileType
2103 * Purpose : determine the handle type
2104 * Parameters: PHMHANDLEDATA pHMHandleData
2105 * Variables :
2106 * Result : API returncode
2107 * Remark :
2108 * Status :
2109 *
2110 * Author : Patrick Haller [Wed, 1998/02/11 20:44]
2111 *****************************************************************************/
2112
2113DWORD HMDeviceDiskClass::GetFileType(PHMHANDLEDATA pHMHandleData)
2114{
2115 dprintf2(("KERNEL32: HMDeviceDiskClass::GetFileType %s(%08x)\n",
2116 lpHMDeviceName, pHMHandleData));
2117
2118 return FILE_TYPE_DISK;
2119}
2120//******************************************************************************
2121//******************************************************************************
Note: See TracBrowser for help on using the repository browser.