VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/VBoxHDD.cpp@ 13384

Last change on this file since 13384 was 12639, checked in by vboxsync, 16 years ago

Storeage: misc file headers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/* $Id: VBoxHDD.cpp 12639 2008-09-22 13:19:14Z vboxsync $ */
2/** @file
3 * VBoxHDD - VBox HDD container implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DRV_VBOXHDD
26#include <VBox/VBoxHDD.h>
27#include <VBox/pdmdrv.h>
28#include <iprt/alloc.h>
29#include <iprt/assert.h>
30#include <iprt/uuid.h>
31#include <iprt/file.h>
32#include <iprt/string.h>
33
34#include "VDICore.h"
35#include "Builtins.h"
36
37
38/*******************************************************************************
39* Defined Constants And Macros *
40*******************************************************************************/
41/** Converts a pointer to VDIDISK::IMedia to a PVDIDISK. */
42#define PDMIMEDIA_2_VDIDISK(pInterface) ( (PVDIDISK)((uintptr_t)pInterface - RT_OFFSETOF(VDIDISK, IMedia)) )
43
44/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
45#define PDMIBASE_2_DRVINS(pInterface) ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
46
47/** Converts a pointer to PDMDRVINS::IBase to a PVDIDISK. */
48#define PDMIBASE_2_VDIDISK(pInterface) ( PDMINS_2_DATA(PDMIBASE_2_DRVINS(pInterface), PVDIDISK) )
49
50
51
52
53/** @copydoc PDMIMEDIA::pfnGetSize */
54static DECLCALLBACK(uint64_t) vdiGetSize(PPDMIMEDIA pInterface)
55{
56 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
57 uint64_t cb = VDIDiskGetSize(pThis);
58 LogFlow(("vdiGetSize: returns %#llx (%llu)\n", cb, cb));
59 return cb;
60}
61
62
63/**
64 * Get stored media PCHS geometry - BIOS property.
65 *
66 * @see PDMIMEDIA::pfnBiosGetPCHSGeometry for details.
67 */
68static DECLCALLBACK(int) vdiBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
69{
70 LogFlow(("%s: returns VERR_NOT_IMPLEMENTED\n", __FUNCTION__));
71 return VERR_NOT_IMPLEMENTED;
72}
73
74
75/**
76 * Set stored media PCHS geometry - BIOS property.
77 *
78 * @see PDMIMEDIA::pfnBiosSetPCHSGeometry for details.
79 */
80static DECLCALLBACK(int) vdiBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
81{
82 LogFlow(("%s: returns VERR_NOT_IMPLEMENTED\n", __FUNCTION__));
83 return VERR_NOT_IMPLEMENTED;
84}
85
86
87/**
88 * Get stored media LCHS geometry - BIOS property.
89 *
90 * @see PDMIMEDIA::pfnBiosGetLCHSGeometry for details.
91 */
92static DECLCALLBACK(int) vdiBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
93{
94 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
95 int rc = VDIDiskGetLCHSGeometry(pThis, pLCHSGeometry);
96 if (RT_SUCCESS(rc))
97 {
98 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
99 return VINF_SUCCESS;
100 }
101 Log(("%s: The Bios geometry data was not available.\n", __FUNCTION__));
102 return VERR_PDM_GEOMETRY_NOT_SET;
103}
104
105
106/**
107 * Set stored media LCHS geometry - BIOS property.
108 *
109 * @see PDMIMEDIA::pfnBiosSetLCHSGeometry for details.
110 */
111static DECLCALLBACK(int) vdiBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
112{
113 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
114 int rc = VDIDiskSetLCHSGeometry(pThis, pLCHSGeometry);
115 LogFlow(("%s: returns %Rrc (%d,%d,%d)\n", __FUNCTION__, rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
116 return rc;
117}
118
119
120/**
121 * Read bits.
122 *
123 * @see PDMIMEDIA::pfnRead for details.
124 */
125static DECLCALLBACK(int) vdiRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
126{
127 LogFlow(("vdiRead: off=%#llx pvBuf=%p cbRead=%d\n", off, pvBuf, cbRead));
128 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
129 int rc = VDIDiskRead(pThis, off, pvBuf, cbRead);
130 if (RT_SUCCESS(rc))
131 Log2(("vdiRead: off=%#llx pvBuf=%p cbRead=%d\n"
132 "%.*Vhxd\n",
133 off, pvBuf, cbRead, cbRead, pvBuf));
134 LogFlow(("vdiRead: returns %Rrc\n", rc));
135 return rc;
136}
137
138
139/**
140 * Write bits.
141 *
142 * @see PDMIMEDIA::pfnWrite for details.
143 */
144static DECLCALLBACK(int) vdiWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
145{
146 LogFlow(("vdiWrite: off=%#llx pvBuf=%p cbWrite=%d\n", off, pvBuf, cbWrite));
147 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
148 Log2(("vdiWrite: off=%#llx pvBuf=%p cbWrite=%d\n"
149 "%.*Vhxd\n",
150 off, pvBuf, cbWrite, cbWrite, pvBuf));
151 int rc = VDIDiskWrite(pThis, off, pvBuf, cbWrite);
152 LogFlow(("vdiWrite: returns %Rrc\n", rc));
153 return rc;
154}
155
156
157/**
158 * Flush bits to media.
159 *
160 * @see PDMIMEDIA::pfnFlush for details.
161 */
162static DECLCALLBACK(int) vdiFlush(PPDMIMEDIA pInterface)
163{
164 LogFlow(("vdiFlush:\n"));
165 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
166 VDIFlushImage(pThis->pLast);
167 int rc = VINF_SUCCESS;
168 LogFlow(("vdiFlush: returns %Rrc\n", rc));
169 return rc;
170}
171
172
173/** @copydoc PDMIMEDIA::pfnGetUuid */
174static DECLCALLBACK(int) vdiGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
175{
176 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
177 int rc = VDIDiskGetImageUuid(pThis, 0, pUuid);
178 LogFlow(("vdiGetUuid: returns %Rrc ({%RTuuid})\n", rc, pUuid));
179 return rc;
180}
181
182
183/** @copydoc PDMIMEDIA::pfnIsReadOnly */
184static DECLCALLBACK(bool) vdiIsReadOnly(PPDMIMEDIA pInterface)
185{
186 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
187 LogFlow(("vdiIsReadOnly: returns %d\n", VDIDiskIsReadOnly(pThis)));
188 return VDIDiskIsReadOnly(pThis);
189}
190
191
192/**
193 * Queries an interface to the driver.
194 *
195 * @returns Pointer to interface.
196 * @returns NULL if the interface was not supported by the driver.
197 * @param pInterface Pointer to this interface structure.
198 * @param enmInterface The requested interface identification.
199 * @thread Any thread.
200 */
201static DECLCALLBACK(void *) vdiQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
202{
203 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
204 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
205 switch (enmInterface)
206 {
207 case PDMINTERFACE_BASE:
208 return &pDrvIns->IBase;
209 case PDMINTERFACE_MEDIA:
210 return &pThis->IMedia;
211 default:
212 return NULL;
213 }
214}
215
216
217/**
218 * Before the VM resumes we'll have to undo the read-only mode change
219 * done in vdiSuspend.
220 *
221 * @param pDrvIns The driver instance data.
222 */
223static DECLCALLBACK(void) vdiResume(PPDMDRVINS pDrvIns)
224{
225 LogFlow(("vdiSuspend:\n"));
226#if 1 //#ifdef DEBUG_dmik
227 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
228 if (!(pThis->pLast->fOpen & VDI_OPEN_FLAGS_READONLY))
229 {
230 int rc = vdiChangeImageMode(pThis->pLast, false);
231 AssertRC(rc);
232 }
233#endif
234}
235
236
237/**
238 * When the VM has been suspended we'll change the image mode to read-only
239 * so that main and others can read the VDIs. This is important when
240 * saving state and so forth.
241 *
242 * @param pDrvIns The driver instance data.
243 */
244static DECLCALLBACK(void) vdiSuspend(PPDMDRVINS pDrvIns)
245{
246 LogFlow(("vdiSuspend:\n"));
247#if 1 // #ifdef DEBUG_dmik
248 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
249 if (!(pThis->pLast->fOpen & VDI_OPEN_FLAGS_READONLY))
250 {
251 int rc = vdiChangeImageMode(pThis->pLast, true);
252 AssertRC(rc);
253 }
254#endif
255}
256
257
258/**
259 * Destruct a driver instance.
260 *
261 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
262 * resources can be freed correctly.
263 *
264 * @param pDrvIns The driver instance data.
265 */
266static DECLCALLBACK(void) vdiDestruct(PPDMDRVINS pDrvIns)
267{
268 LogFlow(("vdiDestruct:\n"));
269 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
270 VDIDiskCloseAllImages(pThis);
271}
272
273
274/**
275 * Construct a VBox HDD media driver instance.
276 *
277 * @returns VBox status.
278 * @param pDrvIns The driver instance data.
279 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
280 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
281 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
282 * iInstance it's expected to be used a bit in this function.
283 */
284static DECLCALLBACK(int) vdiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
285{
286 LogFlow(("vdiConstruct:\n"));
287 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
288 char *pszName; /**< The path of the disk image file. */
289 bool fReadOnly; /**< True if the media is readonly. */
290 bool fHonorZeroWrites = false;
291
292 /*
293 * Init the static parts.
294 */
295 pDrvIns->IBase.pfnQueryInterface = vdiQueryInterface;
296 pThis->pDrvIns = pDrvIns;
297
298 vdiInitVDIDisk(pThis);
299
300 /* IMedia */
301 pThis->IMedia.pfnRead = vdiRead;
302 pThis->IMedia.pfnWrite = vdiWrite;
303 pThis->IMedia.pfnFlush = vdiFlush;
304 pThis->IMedia.pfnGetSize = vdiGetSize;
305 pThis->IMedia.pfnGetUuid = vdiGetUuid;
306 pThis->IMedia.pfnIsReadOnly = vdiIsReadOnly;
307 pThis->IMedia.pfnBiosGetPCHSGeometry = vdiBiosGetPCHSGeometry;
308 pThis->IMedia.pfnBiosSetPCHSGeometry = vdiBiosSetPCHSGeometry;
309 pThis->IMedia.pfnBiosGetLCHSGeometry = vdiBiosGetLCHSGeometry;
310 pThis->IMedia.pfnBiosSetLCHSGeometry = vdiBiosSetLCHSGeometry;
311
312 /*
313 * Validate configuration and find the great to the level of umpteen grandparent.
314 * The parents are found in the 'Parent' subtree, so it's sorta up side down
315 * from the image dependency tree.
316 */
317 unsigned iLevel = 0;
318 PCFGMNODE pCurNode = pCfgHandle;
319 for (;;)
320 {
321 if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0ReadOnly\0HonorZeroWrites\0"))
322 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
323
324 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
325 if (!pParent)
326 break;
327 pCurNode = pParent;
328 iLevel++;
329 }
330
331 /*
332 * Open the images.
333 */
334 int rc = VINF_SUCCESS;
335 while (pCurNode && RT_SUCCESS(rc))
336 {
337 /*
338 * Read the image configuration.
339 */
340 int rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
341 if (RT_FAILURE(rc))
342 return PDMDRV_SET_ERROR(pDrvIns, rc,
343 N_("VHDD: Configuration error: Querying \"Path\" as string failed"));
344
345 rc = CFGMR3QueryBool(pCurNode, "ReadOnly", &fReadOnly);
346 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
347 fReadOnly = false;
348 else if (RT_FAILURE(rc))
349 {
350 MMR3HeapFree(pszName);
351 return PDMDRV_SET_ERROR(pDrvIns, rc,
352 N_("VHDD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
353 }
354
355 if (!fHonorZeroWrites)
356 {
357 rc = CFGMR3QueryBool(pCfgHandle, "HonorZeroWrites", &fHonorZeroWrites);
358 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
359 fHonorZeroWrites = false;
360 else if (RT_FAILURE(rc))
361 {
362 MMR3HeapFree(pszName);
363 return PDMDRV_SET_ERROR(pDrvIns, rc,
364 N_("VHDD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
365 }
366 }
367
368 /*
369 * Open the image.
370 */
371 rc = VDIDiskOpenImage(pThis, pszName, fReadOnly ? VDI_OPEN_FLAGS_READONLY
372 : VDI_OPEN_FLAGS_NORMAL);
373 if (RT_SUCCESS(rc))
374 Log(("vdiConstruct: %d - Opened '%s' in %s mode\n",
375 iLevel, pszName, VDIDiskIsReadOnly(pThis) ? "read-only" : "read-write"));
376 else
377 AssertMsgFailed(("Failed to open image '%s' rc=%Rrc\n", pszName, rc));
378 MMR3HeapFree(pszName);
379
380 /* next */
381 iLevel--;
382 pCurNode = CFGMR3GetParent(pCurNode);
383 }
384
385 /* If any of the images has the flag set, handle zero writes like normal. */
386 if (RT_SUCCESS(rc))
387 pThis->fHonorZeroWrites = fHonorZeroWrites;
388
389 /* On failure, vdiDestruct will be called, so no need to clean up here. */
390
391 if (rc == VERR_ACCESS_DENIED)
392 /* This should never happen here since this case is covered by Console::PowerUp */
393 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
394 N_("Cannot open virtual disk image '%s' for %s access"),
395 pszName, fReadOnly ? "readonly" : "read/write");
396
397 return rc;
398}
399
400
401/**
402 * VBox HDD driver registration record.
403 */
404const PDMDRVREG g_DrvVBoxHDD =
405{
406 /* u32Version */
407 PDM_DRVREG_VERSION,
408 /* szDriverName */
409 "VBoxHDD",
410 /* pszDescription */
411 "VBoxHDD media driver.",
412 /* fFlags */
413 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
414 /* fClass. */
415 PDM_DRVREG_CLASS_MEDIA,
416 /* cMaxInstances */
417 ~0,
418 /* cbInstance */
419 sizeof(VDIDISK),
420 /* pfnConstruct */
421 vdiConstruct,
422 /* pfnDestruct */
423 vdiDestruct,
424 /* pfnIOCtl */
425 NULL,
426 /* pfnPowerOn */
427 NULL,
428 /* pfnReset */
429 NULL,
430 /* pfnSuspend */
431 vdiSuspend,
432 /* pfnResume */
433 vdiResume,
434 /* pfnDetach */
435 NULL
436};
437
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