VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/VCICacheCore.cpp@ 32536

Last change on this file since 32536 was 32536, checked in by vboxsync, 14 years ago

Storage/VBoxHDD: replace custom open flags with regular IPRT file open flags, introduce user-providable filesystem access interface, eliminate dependency on PGM geometry structure, change pvBuffer/cbBuffer parameter ordering to the usual conventions, eliminate the remains of the old I/O code, make more plugin methods optional to reduce redundancy, lots of cleanups

Storage/DrvVD+testcases,Main/Medium+Frontends: adapt to VBoxHDD changes, logging fixes

Storage/VDI+VMDK+DMG+Raw+VHD+Parallels+VCI: made as similar to each other as possible, added inline VFS wrappers to improve readability, full VFS support, VDI files are now 4K aligned, eliminate the remains of the old I/O code, various more or less severe bugfixes, code sort

Storage/iSCSI: support disks bigger than 2T, streamline the code to be more similar to the file-based backends, memory leak fix, error code usage like file-based backends, code sort

log+err: added new error codes/log groups and eliminated unused old ones

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/* $Id: VCICacheCore.cpp 32536 2010-09-15 18:25:32Z vboxsync $ */
2/** @file
3 * VCICacheCore - VirtualBox Cache Image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_VD_RAW /** @todo logging group */
22#include <VBox/VBoxHDD-CachePlugin.h>
23#include <VBox/err.h>
24
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/alloc.h>
28#include <iprt/file.h>
29
30
31/*******************************************************************************
32* Constants And Macros, Structures and Typedefs *
33*******************************************************************************/
34
35/**
36 * VCI image data structure.
37 */
38typedef struct VCICACHE
39{
40 /** Image name. */
41 const char *pszFilename;
42 /** Storage handle. */
43 PVDIOSTORAGE pStorage;
44 /** I/O interface. */
45 PVDINTERFACE pInterfaceIO;
46 /** Async I/O interface callbacks. */
47 PVDINTERFACEIO pInterfaceIOCallbacks;
48
49 /** Pointer to the per-disk VD interface list. */
50 PVDINTERFACE pVDIfsDisk;
51 /** Pointer to the per-image VD interface list. */
52 PVDINTERFACE pVDIfsImage;
53
54 /** Error callback. */
55 PVDINTERFACE pInterfaceError;
56 /** Opaque data for error callback. */
57 PVDINTERFACEERROR pInterfaceErrorCallbacks;
58
59 /** Open flags passed by VBoxHD layer. */
60 unsigned uOpenFlags;
61 /** Image flags defined during creation or determined during open. */
62 unsigned uImageFlags;
63 /** Total size of the image. */
64 uint64_t cbSize;
65
66} VCICACHE, *PVCICACHE;
67
68/*******************************************************************************
69* Static Variables *
70*******************************************************************************/
71
72/** NULL-terminated array of supported file extensions. */
73static const char *const s_apszVciFileExtensions[] =
74{
75 "vci",
76 NULL
77};
78
79/*******************************************************************************
80* Internal Functions *
81*******************************************************************************/
82
83/**
84 * Internal: signal an error to the frontend.
85 */
86DECLINLINE(int) vciError(PVCICACHE pImage, int rc, RT_SRC_POS_DECL,
87 const char *pszFormat, ...)
88{
89 va_list va;
90 va_start(va, pszFormat);
91 if (pImage->pInterfaceError)
92 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
93 pszFormat, va);
94 va_end(va);
95 return rc;
96}
97
98/**
99 * Internal: signal an informational message to the frontend.
100 */
101DECLINLINE(int) vciMessage(PVCICACHE pImage, const char *pszFormat, ...)
102{
103 int rc = VINF_SUCCESS;
104 va_list va;
105 va_start(va, pszFormat);
106 if (pImage->pInterfaceError)
107 rc = pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser,
108 pszFormat, va);
109 va_end(va);
110 return rc;
111}
112
113
114DECLINLINE(int) vciFileOpen(PVCICACHE pImage, const char *pszFilename,
115 uint32_t fOpen)
116{
117 return pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
118 pszFilename, fOpen,
119 &pImage->pStorage);
120}
121
122DECLINLINE(int) vciFileClose(PVCICACHE pImage)
123{
124 return pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
125 pImage->pStorage);
126}
127
128DECLINLINE(int) vciFileDelete(PVCICACHE pImage, const char *pszFilename)
129{
130 return pImage->pInterfaceIOCallbacks->pfnDelete(pImage->pInterfaceIO->pvUser,
131 pszFilename);
132}
133
134DECLINLINE(int) vciFileMove(PVCICACHE pImage, const char *pszSrc,
135 const char *pszDst, unsigned fMove)
136{
137 return pImage->pInterfaceIOCallbacks->pfnMove(pImage->pInterfaceIO->pvUser,
138 pszSrc, pszDst, fMove);
139}
140
141DECLINLINE(int) vciFileGetFreeSpace(PVCICACHE pImage, const char *pszFilename,
142 int64_t *pcbFree)
143{
144 return pImage->pInterfaceIOCallbacks->pfnGetFreeSpace(pImage->pInterfaceIO->pvUser,
145 pszFilename, pcbFree);
146}
147
148DECLINLINE(int) vciFileGetSize(PVCICACHE pImage, uint64_t *pcbSize)
149{
150 return pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
151 pImage->pStorage, pcbSize);
152}
153
154DECLINLINE(int) vciFileSetSize(PVCICACHE pImage, uint64_t cbSize)
155{
156 return pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
157 pImage->pStorage, cbSize);
158}
159
160DECLINLINE(int) vciFileWriteSync(PVCICACHE pImage, uint64_t uOffset,
161 const void *pvBuffer, size_t cbBuffer,
162 size_t *pcbWritten)
163{
164 return pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
165 pImage->pStorage, uOffset,
166 pvBuffer, cbBuffer, pcbWritten);
167}
168
169DECLINLINE(int) vciFileReadSync(PVCICACHE pImage, uint64_t uOffset,
170 void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
171{
172 return pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
173 pImage->pStorage, uOffset,
174 pvBuffer, cbBuffer, pcbRead);
175}
176
177DECLINLINE(int) vciFileFlushSync(PVCICACHE pImage)
178{
179 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
180 pImage->pStorage);
181}
182
183DECLINLINE(int) vciFileReadUserAsync(PVCICACHE pImage, uint64_t uOffset,
184 PVDIOCTX pIoCtx, size_t cbRead)
185{
186 return pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
187 pImage->pStorage,
188 uOffset, pIoCtx,
189 cbRead);
190}
191
192DECLINLINE(int) vciFileWriteUserAsync(PVCICACHE pImage, uint64_t uOffset,
193 PVDIOCTX pIoCtx, size_t cbWrite,
194 PFNVDXFERCOMPLETED pfnComplete,
195 void *pvCompleteUser)
196{
197 return pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
198 pImage->pStorage,
199 uOffset, pIoCtx,
200 cbWrite,
201 pfnComplete,
202 pvCompleteUser);
203}
204
205DECLINLINE(int) vciFileFlushAsync(PVCICACHE pImage, PVDIOCTX pIoCtx,
206 PFNVDXFERCOMPLETED pfnComplete,
207 void *pvCompleteUser)
208{
209 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
210 pImage->pStorage,
211 pIoCtx, pfnComplete,
212 pvCompleteUser);
213}
214
215
216/**
217 * Internal. Flush image data to disk.
218 */
219static int vciFlushImage(PVCICACHE pImage)
220{
221 int rc = VINF_SUCCESS;
222
223 if ( pImage->pStorage
224 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
225 rc = vciFileFlushSync(pImage);
226
227 return rc;
228}
229
230/**
231 * Internal. Free all allocated space for representing an image except pImage,
232 * and optionally delete the image from disk.
233 */
234static int vciFreeImage(PVCICACHE pImage, bool fDelete)
235{
236 int rc = VINF_SUCCESS;
237
238 /* Freeing a never allocated image (e.g. because the open failed) is
239 * not signalled as an error. After all nothing bad happens. */
240 if (pImage)
241 {
242 if (pImage->pStorage)
243 {
244 /* No point updating the file that is deleted anyway. */
245 if (!fDelete)
246 vciFlushImage(pImage);
247
248 vciFileClose(pImage);
249 pImage->pStorage = NULL;
250 }
251
252 if (fDelete && pImage->pszFilename)
253 vciFileDelete(pImage, pImage->pszFilename);
254 }
255
256 LogFlowFunc(("returns %Rrc\n", rc));
257 return rc;
258}
259
260/**
261 * Internal: Open an image, constructing all necessary data structures.
262 */
263static int vciOpenImage(PVCICACHE pImage, unsigned uOpenFlags)
264{
265 int rc;
266
267 pImage->uOpenFlags = uOpenFlags;
268
269 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
270 if (pImage->pInterfaceError)
271 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
272
273 /* Get I/O interface. */
274 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
275 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
276 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
277 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
278
279 /*
280 * Open the image.
281 */
282 rc = vciFileOpen(pImage, pImage->pszFilename,
283 VDOpenFlagsToFileOpenFlags(uOpenFlags,
284 false /* fCreate */));
285 if (RT_FAILURE(rc))
286 {
287 /* Do NOT signal an appropriate error here, as the VD layer has the
288 * choice of retrying the open if it failed. */
289 goto out;
290 }
291
292 rc = vciFileGetSize(pImage, &pImage->cbSize);
293 if (RT_FAILURE(rc))
294 goto out;
295 if (pImage->cbSize % 512)
296 {
297 rc = VERR_VD_RAW_INVALID_HEADER;
298 goto out;
299 }
300 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
301
302out:
303 if (RT_FAILURE(rc))
304 vciFreeImage(pImage, false);
305 return rc;
306}
307
308/**
309 * Internal: Create a vci image.
310 */
311static int vciCreateImage(PVCICACHE pImage, uint64_t cbSize,
312 unsigned uImageFlags, const char *pszComment,
313 unsigned uOpenFlags, PFNVDPROGRESS pfnProgress,
314 void *pvUser, unsigned uPercentStart,
315 unsigned uPercentSpan)
316{
317 int rc;
318 RTFOFF cbFree = 0;
319 uint64_t uOff;
320 size_t cbBuf = 128 * _1K;
321 void *pvBuf = NULL;
322
323 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
324 {
325 rc = vciError(pImage, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("VCI: cannot create diff image '%s'"), pImage->pszFilename);
326 goto out;
327 }
328 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
329
330 pImage->uImageFlags = uImageFlags;
331
332 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
333
334 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
335 if (pImage->pInterfaceError)
336 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
337
338 /* Get I/O interface. */
339 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
340 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
341 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
342 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
343
344 /* Create image file. */
345 rc = vciFileOpen(pImage, pImage->pszFilename,
346 VDOpenFlagsToFileOpenFlags(uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
347 true /* fCreate */));
348 if (RT_FAILURE(rc))
349 {
350 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot create image '%s'"), pImage->pszFilename);
351 goto out;
352 }
353
354 /* Check the free space on the disk and leave early if there is not
355 * sufficient space available. */
356 rc = vciFileGetFreeSpace(pImage, pImage->pszFilename, &cbFree);
357 if (RT_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
358 {
359 rc = vciError(pImage, VERR_DISK_FULL, RT_SRC_POS, N_("VCI: disk would overflow creating image '%s'"), pImage->pszFilename);
360 goto out;
361 }
362
363 /* Allocate & commit whole file if fixed image, it must be more
364 * effective than expanding file by write operations. */
365 rc = vciFileSetSize(pImage, cbSize);
366 if (RT_FAILURE(rc))
367 {
368 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: setting image size failed for '%s'"), pImage->pszFilename);
369 goto out;
370 }
371
372 /* Fill image with zeroes. We do this for every fixed-size image since on
373 * some systems (for example Windows Vista), it takes ages to write a block
374 * near the end of a sparse file and the guest could complain about an ATA
375 * timeout. */
376 pvBuf = RTMemTmpAllocZ(cbBuf);
377 if (!pvBuf)
378 {
379 rc = VERR_NO_MEMORY;
380 goto out;
381 }
382
383 uOff = 0;
384 /* Write data to all image blocks. */
385 while (uOff < cbSize)
386 {
387 unsigned cbChunk = (unsigned)RT_MIN(cbSize, cbBuf);
388
389 rc = vciFileWriteSync(pImage, uOff, pvBuf, cbChunk, NULL);
390 if (RT_FAILURE(rc))
391 {
392 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: writing block failed for '%s'"), pImage->pszFilename);
393 goto out;
394 }
395
396 uOff += cbChunk;
397
398 if (pfnProgress)
399 {
400 rc = pfnProgress(pvUser,
401 uPercentStart + uOff * uPercentSpan * 98 / (cbSize * 100));
402 if (RT_FAILURE(rc))
403 goto out;
404 }
405 }
406 RTMemTmpFree(pvBuf);
407
408 if (RT_SUCCESS(rc) && pfnProgress)
409 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
410
411 pImage->cbSize = cbSize;
412
413 rc = vciFlushImage(pImage);
414
415out:
416 if (RT_SUCCESS(rc) && pfnProgress)
417 pfnProgress(pvUser, uPercentStart + uPercentSpan);
418
419 if (RT_FAILURE(rc))
420 vciFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
421 return rc;
422}
423
424
425/** @copydoc VDCACHEBACKEND::pfnProbe */
426static int vciProbe(const char *pszFilename, PVDINTERFACE pVDIfsCache,
427 PVDINTERFACE pVDIfsImage)
428{
429 LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
430 int rc = VINF_SUCCESS;
431
432 if ( !VALID_PTR(pszFilename)
433 || !*pszFilename)
434 {
435 rc = VERR_INVALID_PARAMETER;
436 goto out;
437 }
438
439 /* Always return failure, to avoid opening everything as a vci image. */
440 rc = VERR_VD_RAW_INVALID_HEADER;
441
442out:
443 LogFlowFunc(("returns %Rrc\n", rc));
444 return rc;
445}
446
447/** @copydoc VDCACHEBACKEND::pfnOpen */
448static int vciOpen(const char *pszFilename, unsigned uOpenFlags,
449 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
450 void **ppBackendData)
451{
452 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
453 int rc;
454 PVCICACHE pImage;
455
456 /* Check open flags. All valid flags are supported. */
457 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
458 {
459 rc = VERR_INVALID_PARAMETER;
460 goto out;
461 }
462
463 /* Check remaining arguments. */
464 if ( !VALID_PTR(pszFilename)
465 || !*pszFilename)
466 {
467 rc = VERR_INVALID_PARAMETER;
468 goto out;
469 }
470
471
472 pImage = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
473 if (!pImage)
474 {
475 rc = VERR_NO_MEMORY;
476 goto out;
477 }
478 pImage->pszFilename = pszFilename;
479 pImage->pStorage = NULL;
480 pImage->pVDIfsDisk = pVDIfsDisk;
481 pImage->pVDIfsImage = pVDIfsImage;
482
483 rc = vciOpenImage(pImage, uOpenFlags);
484 if (RT_SUCCESS(rc))
485 *ppBackendData = pImage;
486 else
487 RTMemFree(pImage);
488
489out:
490 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
491 return rc;
492}
493
494/** @copydoc VDCACHEBACKEND::pfnCreate */
495static int vciCreate(const char *pszFilename, uint64_t cbSize,
496 unsigned uImageFlags, const char *pszComment,
497 PCRTUUID pUuid, unsigned uOpenFlags,
498 unsigned uPercentStart, unsigned uPercentSpan,
499 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
500 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
501{
502 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p",
503 pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
504 int rc;
505 PVCICACHE pImage;
506
507 PFNVDPROGRESS pfnProgress = NULL;
508 void *pvUser = NULL;
509 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
510 VDINTERFACETYPE_PROGRESS);
511 PVDINTERFACEPROGRESS pCbProgress = NULL;
512 if (pIfProgress)
513 {
514 pCbProgress = VDGetInterfaceProgress(pIfProgress);
515 if (pCbProgress)
516 pfnProgress = pCbProgress->pfnProgress;
517 pvUser = pIfProgress->pvUser;
518 }
519
520 /* Check open flags. All valid flags are supported. */
521 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
522 {
523 rc = VERR_INVALID_PARAMETER;
524 goto out;
525 }
526
527 /* Check remaining arguments. */
528 if ( !VALID_PTR(pszFilename)
529 || !*pszFilename)
530 {
531 rc = VERR_INVALID_PARAMETER;
532 goto out;
533 }
534
535 pImage = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
536 if (!pImage)
537 {
538 rc = VERR_NO_MEMORY;
539 goto out;
540 }
541 pImage->pszFilename = pszFilename;
542 pImage->pStorage = NULL;
543 pImage->pVDIfsDisk = pVDIfsDisk;
544 pImage->pVDIfsImage = pVDIfsImage;
545
546 rc = vciCreateImage(pImage, cbSize, uImageFlags, pszComment, uOpenFlags,
547 pfnProgress, pvUser, uPercentStart, uPercentSpan);
548 if (RT_SUCCESS(rc))
549 {
550 /* So far the image is opened in read/write mode. Make sure the
551 * image is opened in read-only mode if the caller requested that. */
552 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
553 {
554 vciFreeImage(pImage, false);
555 rc = vciOpenImage(pImage, uOpenFlags);
556 if (RT_FAILURE(rc))
557 {
558 RTMemFree(pImage);
559 goto out;
560 }
561 }
562 *ppBackendData = pImage;
563 }
564 else
565 RTMemFree(pImage);
566
567out:
568 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
569 return rc;
570}
571
572/** @copydoc VDCACHEBACKEND::pfnClose */
573static int vciClose(void *pBackendData, bool fDelete)
574{
575 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
576 PVCICACHE pImage = (PVCICACHE)pBackendData;
577 int rc;
578
579 rc = vciFreeImage(pImage, fDelete);
580 RTMemFree(pImage);
581
582 LogFlowFunc(("returns %Rrc\n", rc));
583 return rc;
584}
585
586/** @copydoc VDCACHEBACKEND::pfnRead */
587static int vciRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
588 size_t cbToRead, size_t *pcbActuallyRead)
589{
590 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
591 PVCICACHE pImage = (PVCICACHE)pBackendData;
592 int rc;
593
594 AssertPtr(pImage);
595 Assert(uOffset % 512 == 0);
596 Assert(cbToRead % 512 == 0);
597
598 if ( uOffset + cbToRead > pImage->cbSize
599 || cbToRead == 0)
600 {
601 rc = VERR_INVALID_PARAMETER;
602 goto out;
603 }
604
605 rc = vciFileReadSync(pImage, uOffset, pvBuf, cbToRead, NULL);
606 *pcbActuallyRead = cbToRead;
607
608out:
609 LogFlowFunc(("returns %Rrc\n", rc));
610 return rc;
611}
612
613/** @copydoc VDCACHEBACKEND::pfnWrite */
614static int vciWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
615 size_t cbToWrite, size_t *pcbWriteProcess)
616{
617 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
618 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
619 PVCICACHE pImage = (PVCICACHE)pBackendData;
620 int rc;
621
622 AssertPtr(pImage);
623 Assert(uOffset % 512 == 0);
624 Assert(cbToWrite % 512 == 0);
625
626 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
627 {
628 rc = VERR_VD_IMAGE_READ_ONLY;
629 goto out;
630 }
631
632 if ( uOffset + cbToWrite > pImage->cbSize
633 || cbToWrite == 0)
634 {
635 rc = VERR_INVALID_PARAMETER;
636 goto out;
637 }
638
639 rc = vciFileWriteSync(pImage, uOffset, pvBuf, cbToWrite, NULL);
640 if (pcbWriteProcess)
641 *pcbWriteProcess = cbToWrite;
642
643out:
644 LogFlowFunc(("returns %Rrc\n", rc));
645 return rc;
646}
647
648/** @copydoc VDCACHEBACKEND::pfnFlush */
649static int vciFlush(void *pBackendData)
650{
651 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
652 PVCICACHE pImage = (PVCICACHE)pBackendData;
653 int rc;
654
655 rc = vciFlushImage(pImage);
656 LogFlowFunc(("returns %Rrc\n", rc));
657 return rc;
658}
659
660/** @copydoc VDCACHEBACKEND::pfnGetVersion */
661static unsigned vciGetVersion(void *pBackendData)
662{
663 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
664 PVCICACHE pImage = (PVCICACHE)pBackendData;
665
666 AssertPtr(pImage);
667
668 if (pImage)
669 return 1;
670 else
671 return 0;
672}
673
674/** @copydoc VDCACHEBACKEND::pfnGetSize */
675static uint64_t vciGetSize(void *pBackendData)
676{
677 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
678 PVCICACHE pImage = (PVCICACHE)pBackendData;
679 uint64_t cb = 0;
680
681 AssertPtr(pImage);
682
683 if (pImage && pImage->pStorage)
684 cb = pImage->cbSize;
685
686 LogFlowFunc(("returns %llu\n", cb));
687 return cb;
688}
689
690/** @copydoc VDCACHEBACKEND::pfnGetFileSize */
691static uint64_t vciGetFileSize(void *pBackendData)
692{
693 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
694 PVCICACHE pImage = (PVCICACHE)pBackendData;
695 uint64_t cb = 0;
696
697 AssertPtr(pImage);
698
699 if (pImage)
700 {
701 uint64_t cbFile;
702 if (pImage->pStorage)
703 {
704 int rc = vciFileGetSize(pImage, &cbFile);
705 if (RT_SUCCESS(rc))
706 cb = cbFile;
707 }
708 }
709
710 LogFlowFunc(("returns %lld\n", cb));
711 return cb;
712}
713
714/** @copydoc VDCACHEBACKEND::pfnGetImageFlags */
715static unsigned vciGetImageFlags(void *pBackendData)
716{
717 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
718 PVCICACHE pImage = (PVCICACHE)pBackendData;
719 unsigned uImageFlags;
720
721 AssertPtr(pImage);
722
723 if (pImage)
724 uImageFlags = pImage->uImageFlags;
725 else
726 uImageFlags = 0;
727
728 LogFlowFunc(("returns %#x\n", uImageFlags));
729 return uImageFlags;
730}
731
732/** @copydoc VDCACHEBACKEND::pfnGetOpenFlags */
733static unsigned vciGetOpenFlags(void *pBackendData)
734{
735 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
736 PVCICACHE pImage = (PVCICACHE)pBackendData;
737 unsigned uOpenFlags;
738
739 AssertPtr(pImage);
740
741 if (pImage)
742 uOpenFlags = pImage->uOpenFlags;
743 else
744 uOpenFlags = 0;
745
746 LogFlowFunc(("returns %#x\n", uOpenFlags));
747 return uOpenFlags;
748}
749
750/** @copydoc VDCACHEBACKEND::pfnSetOpenFlags */
751static int vciSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
752{
753 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
754 PVCICACHE pImage = (PVCICACHE)pBackendData;
755 int rc;
756
757 /* Image must be opened and the new flags must be valid. Just readonly and
758 * info flags are supported. */
759 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
760 {
761 rc = VERR_INVALID_PARAMETER;
762 goto out;
763 }
764
765 /* Implement this operation via reopening the image. */
766 rc = vciFreeImage(pImage, false);
767 if (RT_FAILURE(rc))
768 goto out;
769 rc = vciOpenImage(pImage, uOpenFlags);
770
771out:
772 LogFlowFunc(("returns %Rrc\n", rc));
773 return rc;
774}
775
776/** @copydoc VDCACHEBACKEND::pfnGetComment */
777static int vciGetComment(void *pBackendData, char *pszComment,
778 size_t cbComment)
779{
780 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
781 PVCICACHE pImage = (PVCICACHE)pBackendData;
782 int rc;
783
784 AssertPtr(pImage);
785
786 if (pImage)
787 rc = VERR_NOT_SUPPORTED;
788 else
789 rc = VERR_VD_NOT_OPENED;
790
791 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
792 return rc;
793}
794
795/** @copydoc VDCACHEBACKEND::pfnSetComment */
796static int vciSetComment(void *pBackendData, const char *pszComment)
797{
798 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
799 PVCICACHE pImage = (PVCICACHE)pBackendData;
800 int rc;
801
802 AssertPtr(pImage);
803
804 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
805 {
806 rc = VERR_VD_IMAGE_READ_ONLY;
807 goto out;
808 }
809
810 if (pImage)
811 rc = VERR_NOT_SUPPORTED;
812 else
813 rc = VERR_VD_NOT_OPENED;
814
815out:
816 LogFlowFunc(("returns %Rrc\n", rc));
817 return rc;
818}
819
820/** @copydoc VDCACHEBACKEND::pfnGetUuid */
821static int vciGetUuid(void *pBackendData, PRTUUID pUuid)
822{
823 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
824 PVCICACHE pImage = (PVCICACHE)pBackendData;
825 int rc;
826
827 AssertPtr(pImage);
828
829 if (pImage)
830 rc = VERR_NOT_SUPPORTED;
831 else
832 rc = VERR_VD_NOT_OPENED;
833
834 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
835 return rc;
836}
837
838/** @copydoc VDCACHEBACKEND::pfnSetUuid */
839static int vciSetUuid(void *pBackendData, PCRTUUID pUuid)
840{
841 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
842 PVCICACHE pImage = (PVCICACHE)pBackendData;
843 int rc;
844
845 LogFlowFunc(("%RTuuid\n", pUuid));
846 AssertPtr(pImage);
847
848 if (pImage)
849 {
850 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
851 rc = VERR_NOT_SUPPORTED;
852 else
853 rc = VERR_VD_IMAGE_READ_ONLY;
854 }
855 else
856 rc = VERR_VD_NOT_OPENED;
857
858 LogFlowFunc(("returns %Rrc\n", rc));
859 return rc;
860}
861
862/** @copydoc VDCACHEBACKEND::pfnGetModificationUuid */
863static int vciGetModificationUuid(void *pBackendData, PRTUUID pUuid)
864{
865 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
866 PVCICACHE pImage = (PVCICACHE)pBackendData;
867 int rc;
868
869 AssertPtr(pImage);
870
871 if (pImage)
872 rc = VERR_NOT_SUPPORTED;
873 else
874 rc = VERR_VD_NOT_OPENED;
875
876 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
877 return rc;
878}
879
880/** @copydoc VDCACHEBACKEND::pfnSetModificationUuid */
881static int vciSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
882{
883 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
884 PVCICACHE pImage = (PVCICACHE)pBackendData;
885 int rc;
886
887 AssertPtr(pImage);
888
889 if (pImage)
890 {
891 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
892 rc = VERR_NOT_SUPPORTED;
893 else
894 rc = VERR_VD_IMAGE_READ_ONLY;
895 }
896 else
897 rc = VERR_VD_NOT_OPENED;
898
899 LogFlowFunc(("returns %Rrc\n", rc));
900 return rc;
901}
902
903/** @copydoc VDCACHEBACKEND::pfnDump */
904static void vciDump(void *pBackendData)
905{
906 NOREF(pBackendData);
907}
908
909/** @copydoc VDCACHEBACKEND::pfnAsyncRead */
910static int vciAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
911 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
912{
913 int rc = VINF_SUCCESS;
914 PVCICACHE pImage = (PVCICACHE)pBackendData;
915
916 rc = vciFileReadUserAsync(pImage, uOffset, pIoCtx, cbRead);
917 if (RT_SUCCESS(rc))
918 *pcbActuallyRead = cbRead;
919
920 return rc;
921}
922
923/** @copydoc VDCACHEBACKEND::pfnAsyncWrite */
924static int vciAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
925 PVDIOCTX pIoCtx, size_t *pcbWriteProcess)
926{
927 int rc = VINF_SUCCESS;
928 PVCICACHE pImage = (PVCICACHE)pBackendData;
929
930 rc = vciFileWriteUserAsync(pImage, uOffset, pIoCtx, cbWrite, NULL, NULL);
931 if (RT_SUCCESS(rc))
932 *pcbWriteProcess = cbWrite;
933
934 return rc;
935}
936
937/** @copydoc VDCACHEBACKEND::pfnAsyncFlush */
938static int vciAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
939{
940 int rc = VINF_SUCCESS;
941 PVCICACHE pImage = (PVCICACHE)pBackendData;
942
943 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
944 rc = vciFileFlushAsync(pImage, pIoCtx, NULL, NULL);
945
946 return rc;
947}
948
949
950VDCACHEBACKEND g_VciCacheBackend =
951{
952 /* pszBackendName */
953 "vci",
954 /* cbSize */
955 sizeof(VDCACHEBACKEND),
956 /* uBackendCaps */
957 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_ASYNC,
958 /* papszFileExtensions */
959 s_apszVciFileExtensions,
960 /* paConfigInfo */
961 NULL,
962 /* hPlugin */
963 NIL_RTLDRMOD,
964 /* pfnProbe */
965 vciProbe,
966 /* pfnOpen */
967 vciOpen,
968 /* pfnCreate */
969 vciCreate,
970 /* pfnClose */
971 vciClose,
972 /* pfnRead */
973 vciRead,
974 /* pfnWrite */
975 vciWrite,
976 /* pfnFlush */
977 vciFlush,
978 /* pfnGetVersion */
979 vciGetVersion,
980 /* pfnGetSize */
981 vciGetSize,
982 /* pfnGetFileSize */
983 vciGetFileSize,
984 /* pfnGetImageFlags */
985 vciGetImageFlags,
986 /* pfnGetOpenFlags */
987 vciGetOpenFlags,
988 /* pfnSetOpenFlags */
989 vciSetOpenFlags,
990 /* pfnGetComment */
991 vciGetComment,
992 /* pfnSetComment */
993 vciSetComment,
994 /* pfnGetUuid */
995 vciGetUuid,
996 /* pfnSetUuid */
997 vciSetUuid,
998 /* pfnGetModificationUuid */
999 vciGetModificationUuid,
1000 /* pfnSetModificationUuid */
1001 vciSetModificationUuid,
1002 /* pfnDump */
1003 vciDump,
1004 /* pfnAsyncRead */
1005 vciAsyncRead,
1006 /* pfnAsyncWrite */
1007 vciAsyncWrite,
1008 /* pfnAsyncFlush */
1009 vciAsyncFlush,
1010 /* pfnComposeLocation */
1011 NULL,
1012 /* pfnComposeName */
1013 NULL
1014};
1015
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