VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvRawImage.cpp@ 6198

Last change on this file since 6198 was 6198, checked in by vboxsync, 17 years ago

applied Alex' patch for correct handling of read-only disk images

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/** @file
2 *
3 * VBox storage devices:
4 * Raw image driver
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#define LOG_GROUP LOG_GROUP_DRV_RAW_IMAGE
24#include <VBox/pdmdrv.h>
25#include <iprt/assert.h>
26#include <iprt/file.h>
27#include <iprt/string.h>
28
29#include "Builtins.h"
30
31
32/*******************************************************************************
33* Defined Constants And Macros *
34*******************************************************************************/
35
36/** Converts a pointer to RAWIMAGE::IMedia to a PRDVRAWIMAGE. */
37#define PDMIMEDIA_2_DRVRAWIMAGE(pInterface) ( (PDRVRAWIMAGE)((uintptr_t)pInterface - RT_OFFSETOF(DRVRAWIMAGE, IMedia)) )
38
39/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
40#define PDMIBASE_2_DRVINS(pInterface) ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
41
42/** Converts a pointer to PDMDRVINS::IBase to a PVBOXHDD. */
43#define PDMIBASE_2_DRVRAWIMAGE(pInterface) ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PDRVRAWIMAGE) )
44
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50/**
51 * Block driver instance data.
52 */
53typedef struct DRVRAWIMAGE
54{
55 /** The media interface. */
56 PDMIMEDIA IMedia;
57 /** Pointer to the driver instance. */
58 PPDMDRVINS pDrvIns;
59 /** Pointer to the filename. (Freed by MM) */
60 char *pszFilename;
61 /** File handle of the raw image file. */
62 RTFILE File;
63 /** True if the image is operating in readonly mode. */
64 bool fReadOnly;
65} DRVRAWIMAGE, *PDRVRAWIMAGE;
66
67
68
69/*******************************************************************************
70* Internal Functions *
71*******************************************************************************/
72static DECLCALLBACK(int) drvRawImageRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead);
73static DECLCALLBACK(int) drvRawImageWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite);
74static DECLCALLBACK(int) drvRawImageFlush(PPDMIMEDIA pInterface);
75static DECLCALLBACK(bool) drvRawImageIsReadOnly(PPDMIMEDIA pInterface);
76static DECLCALLBACK(uint64_t) drvRawImageGetSize(PPDMIMEDIA pInterface);
77static DECLCALLBACK(int) drvRawImageGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid);
78static DECLCALLBACK(int) drvRawImageBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors);
79static DECLCALLBACK(int) drvRawImageBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors);
80static DECLCALLBACK(int) drvRawImageBiosGetTranslation(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation);
81static DECLCALLBACK(int) drvRawImageBiosSetTranslation(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation);
82
83static DECLCALLBACK(void *) drvRawImageQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface);
84
85
86
87
88/**
89 * Construct a raw image driver instance.
90 *
91 * @returns VBox status.
92 * @param pDrvIns The driver instance data.
93 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
94 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
95 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
96 * iInstance it's expected to be used a bit in this function.
97 */
98static DECLCALLBACK(int) drvRawImageConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
99{
100 PDRVRAWIMAGE pData = PDMINS2DATA(pDrvIns, PDRVRAWIMAGE);
101
102 /*
103 * Init the static parts.
104 */
105 pData->pDrvIns = pDrvIns;
106 pData->File = NIL_RTFILE;
107 /* IBase */
108 pDrvIns->IBase.pfnQueryInterface = drvRawImageQueryInterface;
109 /* IMedia */
110 pData->IMedia.pfnRead = drvRawImageRead;
111 pData->IMedia.pfnWrite = drvRawImageWrite;
112 pData->IMedia.pfnFlush = drvRawImageFlush;
113 pData->IMedia.pfnGetSize = drvRawImageGetSize;
114 pData->IMedia.pfnGetUuid = drvRawImageGetUuid;
115 pData->IMedia.pfnIsReadOnly = drvRawImageIsReadOnly;
116 pData->IMedia.pfnBiosGetGeometry = drvRawImageBiosGetGeometry;
117 pData->IMedia.pfnBiosSetGeometry = drvRawImageBiosSetGeometry;
118 pData->IMedia.pfnBiosGetTranslation = drvRawImageBiosGetTranslation;
119 pData->IMedia.pfnBiosSetTranslation = drvRawImageBiosSetTranslation;
120
121 /*
122 * Read the configuration.
123 */
124 if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0"))
125 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
126
127 char *pszName;
128 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "Path", &pszName);
129 if (VBOX_FAILURE(rc))
130 {
131 AssertMsgFailed(("Configuration error: query for \"Path\" string return %Vrc.\n", rc));
132 return rc;
133 }
134
135 /*
136 * Open the image.
137 */
138 rc = RTFileOpen(&pData->File, pszName,
139 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
140 if (VBOX_SUCCESS(rc))
141 {
142 LogFlow(("drvRawImageConstruct: Raw image '%s' opened successfully.\n", pszName));
143 pData->pszFilename = pszName;
144 pData->fReadOnly = false;
145 }
146 else
147 {
148 rc = RTFileOpen(&pData->File, pszName,
149 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
150 if (VBOX_SUCCESS(rc))
151 {
152 LogFlow(("drvRawImageConstruct: Raw image '%s' opened successfully.\n", pszName));
153 pData->pszFilename = pszName;
154 pData->fReadOnly = true;
155 }
156 else
157 {
158 AssertMsgFailed(("Could not open Raw image file %s, rc=%Vrc\n", pszName, rc));
159 MMR3HeapFree(pszName);
160 }
161 }
162
163 return rc;
164}
165
166
167/**
168 * Destruct a driver instance.
169 *
170 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
171 * resources can be freed correctly.
172 *
173 * @param pDrvIns The driver instance data.
174 */
175static DECLCALLBACK(void) drvRawImageDestruct(PPDMDRVINS pDrvIns)
176{
177 PDRVRAWIMAGE pData = PDMINS2DATA(pDrvIns, PDRVRAWIMAGE);
178 LogFlow(("drvRawImageDestruct: '%s'\n", pData->pszFilename));
179
180 if (pData->File != NIL_RTFILE)
181 {
182 RTFileClose(pData->File);
183 pData->File = NIL_RTFILE;
184 }
185 if (pData->pszFilename)
186 MMR3HeapFree(pData->pszFilename);
187}
188
189
190/** @copydoc PDMIMEDIA::pfnGetSize */
191static DECLCALLBACK(uint64_t) drvRawImageGetSize(PPDMIMEDIA pInterface)
192{
193 PDRVRAWIMAGE pData = PDMIMEDIA_2_DRVRAWIMAGE(pInterface);
194 LogFlow(("drvRawImageGetSize: '%s'\n", pData->pszFilename));
195
196 uint64_t cbFile;
197 int rc = RTFileGetSize(pData->File, &cbFile);
198 if (VBOX_SUCCESS(rc))
199 {
200 LogFlow(("drvRawImageGetSize: returns %lld (%s)\n", cbFile, pData->pszFilename));
201 return cbFile;
202 }
203
204 AssertMsgFailed(("Error querying Raw image file size, rc=%Vrc. (%s)\n", rc, pData->pszFilename));
205 return 0;
206}
207
208
209/** @copydoc PDMIMEDIA::pfnBiosGetGeometry */
210static DECLCALLBACK(int) drvRawImageBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
211{
212 return VERR_NOT_IMPLEMENTED;
213}
214
215
216/** @copydoc PDMIMEDIA::pfnBiosSetGeometry */
217static DECLCALLBACK(int) drvRawImageBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
218{
219 return VERR_NOT_IMPLEMENTED;
220}
221
222
223/**
224 * Read bits.
225 *
226 * @see PDMIMEDIA::pfnRead for details.
227 */
228static DECLCALLBACK(int) drvRawImageRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
229{
230 PDRVRAWIMAGE pData = PDMIMEDIA_2_DRVRAWIMAGE(pInterface);
231 LogFlow(("drvRawImageRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n", off, pvBuf, cbRead, pData->pszFilename));
232
233 Assert(pData->File);
234 Assert(pvBuf);
235
236 /*
237 * Seek to the position and read.
238 */
239 int rc = RTFileSeek(pData->File, off, RTFILE_SEEK_BEGIN, NULL);
240 if (VBOX_SUCCESS(rc))
241 {
242 rc = RTFileRead(pData->File, pvBuf, cbRead, NULL);
243 if (VBOX_SUCCESS(rc))
244 {
245 Log2(("drvRawImageRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n"
246 "%16.*Vhxd\n",
247 off, pvBuf, cbRead, pData->pszFilename,
248 cbRead, pvBuf));
249 }
250 else
251 AssertMsgFailed(("RTFileRead(%d, %p, %#x) -> %Vrc (off=%#llx '%s')\n",
252 pData->File, pvBuf, cbRead, rc, off, pData->pszFilename));
253 }
254 else
255 AssertMsgFailed(("RTFileSeek(%d,%#llx,) -> %Vrc\n", pData->File, off, rc));
256 LogFlow(("drvRawImageRead: returns %Vrc\n", rc));
257 return rc;
258}
259
260
261/** @copydoc PDMIMEDIA::pfnWrite */
262static DECLCALLBACK(int) drvRawImageWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
263{
264 PDRVRAWIMAGE pData = PDMIMEDIA_2_DRVRAWIMAGE(pInterface);
265 LogFlow(("drvRawImageWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n", off, pvBuf, cbWrite, pData->pszFilename));
266
267 Assert(pData->File);
268 Assert(pvBuf);
269
270 /*
271 * Seek to the position and write.
272 */
273 int rc = RTFileSeek(pData->File, off, RTFILE_SEEK_BEGIN, NULL);
274 if (VBOX_SUCCESS(rc))
275 {
276 rc = RTFileWrite(pData->File, pvBuf, cbWrite, NULL);
277 if (VBOX_SUCCESS(rc))
278 {
279 Log2(("drvRawImageWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n"
280 "%16.*Vhxd\n",
281 off, pvBuf, cbWrite, pData->pszFilename,
282 cbWrite, pvBuf));
283 }
284 else
285 AssertMsgFailed(("RTFileWrite(%d, %p, %#x) -> %Vrc (off=%#llx '%s')\n",
286 pData->File, pvBuf, cbWrite, rc, off, pData->pszFilename));
287 }
288 else
289 AssertMsgFailed(("RTFileSeek(%d,%#llx,) -> %Vrc\n", pData->File, off, rc));
290 LogFlow(("drvRawImageWrite: returns %Vrc\n", rc));
291 return rc;
292}
293
294
295/** @copydoc PDMIMEDIA::pfnFlush */
296static DECLCALLBACK(int) drvRawImageFlush(PPDMIMEDIA pInterface)
297{
298 PDRVRAWIMAGE pData = PDMIMEDIA_2_DRVRAWIMAGE(pInterface);
299 LogFlow(("drvRawImageFlush: (%s)\n", pData->pszFilename));
300
301 Assert(pData->File != NIL_RTFILE);
302 int rc = RTFileFlush(pData->File);
303 LogFlow(("drvRawImageFlush: returns %Vrc\n", rc));
304 return rc;
305}
306
307
308/** @copydoc PDMIMEDIA::pfnGetUuid */
309static DECLCALLBACK(int) drvRawImageGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
310{
311 LogFlow(("drvRawImageGetUuid: returns VERR_NOT_IMPLEMENTED\n"));
312 return VERR_NOT_IMPLEMENTED;
313}
314
315
316/** @copydoc PDMIMEDIA::pfnIsReadOnly */
317static DECLCALLBACK(bool) drvRawImageIsReadOnly(PPDMIMEDIA pInterface)
318{
319 PDRVRAWIMAGE pData = PDMIMEDIA_2_DRVRAWIMAGE(pInterface);
320 return pData->fReadOnly;
321}
322
323
324/**
325 * Stub - operation not supported.
326 *
327 * @copydoc PDMIMEDIA::pfnBiosGetTranslation
328 */
329static DECLCALLBACK(int) drvRawImageBiosGetTranslation(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation)
330{
331 NOREF(pInterface); NOREF(penmTranslation);
332 return VERR_NOT_IMPLEMENTED;
333}
334
335
336/**
337 * Stub - operation not supported.
338 *
339 * @copydoc PDMIMEDIA::pfnBiosSetTranslation
340 */
341static DECLCALLBACK(int) drvRawImageBiosSetTranslation(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation)
342{
343 NOREF(pInterface); NOREF(enmTranslation);
344 return VERR_NOT_IMPLEMENTED;
345}
346
347
348/**
349 * Queries an interface to the driver.
350 *
351 * @returns Pointer to interface.
352 * @returns NULL if the interface was not supported by the driver.
353 * @param pInterface Pointer to this interface structure.
354 * @param enmInterface The requested interface identification.
355 * @thread Any thread.
356 */
357static DECLCALLBACK(void *) drvRawImageQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
358{
359 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
360 PDRVRAWIMAGE pData = PDMINS2DATA(pDrvIns, PDRVRAWIMAGE);
361 switch (enmInterface)
362 {
363 case PDMINTERFACE_BASE:
364 return &pDrvIns->IBase;
365 case PDMINTERFACE_MEDIA:
366 return &pData->IMedia;
367 default:
368 return NULL;
369 }
370}
371
372
373/**
374 * Raw image driver registration record.
375 */
376const PDMDRVREG g_DrvRawImage =
377{
378 /* u32Version */
379 PDM_DRVREG_VERSION,
380 /* szDriverName */
381 "RawImage",
382 /* pszDescription */
383 "Raw image access driver.",
384 /* fFlags */
385 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
386 /* fClass. */
387 PDM_DRVREG_CLASS_MEDIA,
388 /* cMaxInstances */
389 ~0,
390 /* cbInstance */
391 sizeof(DRVRAWIMAGE),
392 /* pfnConstruct */
393 drvRawImageConstruct,
394 /* pfnDestruct */
395 drvRawImageDestruct,
396 /* pfnIOCtl */
397 NULL,
398 /* pfnPowerOn */
399 NULL,
400 /* pfnReset */
401 NULL,
402 /* pfnSuspend */
403 NULL,
404 /* pfnResume */
405 NULL,
406 /* pfnDetach */
407 NULL,
408 /* pfnPowerOff */
409 NULL
410};
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