VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostBase-linux.cpp@ 64251

Last change on this file since 64251 was 64251, checked in by vboxsync, 8 years ago

Devices/Storage/DrvHost*: Move the read/write/flush methods to the host specific code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.5 KB
Line 
1/* $Id: DrvHostBase-linux.cpp 64251 2016-10-13 14:00:33Z vboxsync $ */
2/** @file
3 * DrvHostBase - Host base drive access driver, Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
18#include <sys/ioctl.h>
19#include <sys/fcntl.h>
20#include <errno.h>
21#include <linux/version.h>
22/* All the following crap is apparently not necessary anymore since Linux
23 * version 2.6.29. */
24#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
25/* This is a hack to work around conflicts between these linux kernel headers
26 * and the GLIBC tcpip headers. They have different declarations of the 4
27 * standard byte order functions. */
28# define _LINUX_BYTEORDER_GENERIC_H
29/* This is another hack for not bothering with C++ unfriendly byteswap macros. */
30/* Those macros that are needed are defined in the header below. */
31# include "swab.h"
32#endif
33#include <linux/fd.h>
34#include <linux/cdrom.h>
35#include <limits.h>
36
37#include <iprt/mem.h>
38#include <iprt/file.h>
39#include <VBox/scsi.h>
40
41#include "DrvHostBase.h"
42
43DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
44 void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies)
45{
46 /*
47 * Minimal input validation.
48 */
49 Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE);
50 Assert(!pvBuf || pcbBuf);
51 Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE);
52 Assert(pbSense || !cbSense); RT_NOREF(cbSense);
53 AssertPtr(pbCmd);
54 Assert(cbCmd <= 16 && cbCmd >= 1);
55
56 int rc = VERR_GENERAL_FAILURE;
57 int direction;
58 struct cdrom_generic_command cgc;
59
60 switch (enmTxDir)
61 {
62 case PDMMEDIATXDIR_NONE:
63 Assert(*pcbBuf == 0);
64 direction = CGC_DATA_NONE;
65 break;
66 case PDMMEDIATXDIR_FROM_DEVICE:
67 Assert(*pcbBuf != 0);
68 Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
69 /* Make sure that the buffer is clear for commands reading
70 * data. The actually received data may be shorter than what
71 * we expect, and due to the unreliable feedback about how much
72 * data the ioctl actually transferred, it's impossible to
73 * prevent that. Returning previous buffer contents may cause
74 * security problems inside the guest OS, if users can issue
75 * commands to the CDROM device. */
76 memset(pThis->pbDoubleBuffer, '\0', *pcbBuf);
77 direction = CGC_DATA_READ;
78 break;
79 case PDMMEDIATXDIR_TO_DEVICE:
80 Assert(*pcbBuf != 0);
81 Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
82 memcpy(pThis->pbDoubleBuffer, pvBuf, *pcbBuf);
83 direction = CGC_DATA_WRITE;
84 break;
85 default:
86 AssertMsgFailed(("enmTxDir invalid!\n"));
87 direction = CGC_DATA_NONE;
88 }
89 memset(&cgc, '\0', sizeof(cgc));
90 memcpy(cgc.cmd, pbCmd, RT_MIN(CDROM_PACKET_SIZE, cbCmd));
91 cgc.buffer = (unsigned char *)pThis->pbDoubleBuffer;
92 cgc.buflen = *pcbBuf;
93 cgc.stat = 0;
94 Assert(cbSense >= sizeof(struct request_sense));
95 cgc.sense = (struct request_sense *)pbSense;
96 cgc.data_direction = direction;
97 cgc.quiet = false;
98 cgc.timeout = cTimeoutMillies;
99 rc = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_SEND_PACKET, &cgc);
100 if (rc < 0)
101 {
102 if (errno == EBUSY)
103 rc = VERR_PDM_MEDIA_LOCKED;
104 else if (errno == ENOSYS)
105 rc = VERR_NOT_SUPPORTED;
106 else
107 {
108 rc = RTErrConvertFromErrno(errno);
109 if (rc == VERR_ACCESS_DENIED && cgc.sense->sense_key == SCSI_SENSE_NONE)
110 cgc.sense->sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
111 Log2(("%s: error status %d, rc=%Rrc\n", __FUNCTION__, cgc.stat, rc));
112 }
113 }
114 switch (enmTxDir)
115 {
116 case PDMMEDIATXDIR_FROM_DEVICE:
117 memcpy(pvBuf, pThis->pbDoubleBuffer, *pcbBuf);
118 break;
119 default:
120 ;
121 }
122 Log2(("%s: after ioctl: cgc.buflen=%d txlen=%d\n", __FUNCTION__, cgc.buflen, *pcbBuf));
123 /* The value of cgc.buflen does not reliably reflect the actual amount
124 * of data transferred (for packet commands with little data transfer
125 * it's 0). So just assume that everything worked ok. */
126
127 return rc;
128}
129
130DECLHIDDEN(int) drvHostBaseGetMediaSizeOs(PDRVHOSTBASE pThis, uint64_t *pcb)
131{
132 int rc = VERR_INVALID_STATE;
133
134 if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType))
135 {
136 rc = ioctl(RTFileToNative(pThis->hFileDevice), FDFLUSH);
137 if (rc)
138 {
139 rc = RTErrConvertFromErrno (errno);
140 Log(("DrvHostFloppy: FDFLUSH ioctl(%s) failed, errno=%d rc=%Rrc\n", pThis->pszDevice, errno, rc));
141 return rc;
142 }
143
144 floppy_drive_struct DrvStat;
145 rc = ioctl(RTFileToNative(pThis->hFileDevice), FDGETDRVSTAT, &DrvStat);
146 if (rc)
147 {
148 rc = RTErrConvertFromErrno(errno);
149 Log(("DrvHostFloppy: FDGETDRVSTAT ioctl(%s) failed, errno=%d rc=%Rrc\n", pThis->pszDevice, errno, rc));
150 return rc;
151 }
152 pThis->fReadOnly = !(DrvStat.flags & FD_DISK_WRITABLE);
153 rc = RTFileSeek(pThis->hFileDevice, 0, RTFILE_SEEK_END, pcb);
154 }
155 else if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
156 {
157 /* Clear the media-changed-since-last-call-thingy just to be on the safe side. */
158 ioctl(RTFileToNative(pThis->hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT);
159 rc = RTFileSeek(pThis->hFileDevice, 0, RTFILE_SEEK_END, pcb);
160 }
161
162 return rc;
163}
164
165
166DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
167{
168 return RTFileReadAt(pThis->hFileDevice, off, pvBuf, cbRead, NULL);
169}
170
171
172DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite)
173{
174 return RTFileWriteAt(pThis->hFileDevice, off, pvBuf, cbWrite, NULL);
175}
176
177
178DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis)
179{
180 return RTFileFlush(pThis->hFileDevice);
181}
182
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette