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

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

IOCTL_STORAGE_GET_MEDIA_TYPES/IOCTL_DISK_GET_MEDIA_TYPES should always succeed; don't fail CreateFile in case of a sharing violation; handle is usable in windoze (although very limited)

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