VirtualBox

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

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

whitespace

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.9 KB
Line 
1/* $Id: VCICacheCore.cpp 32688 2010-09-22 09:42:55Z 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* On disk data structures *
32*******************************************************************************/
33
34/** @note All structures which are written to the disk are written in camel case
35 * and packed. */
36
37/** Block size used internally, because we cache sectors the smallest unit we
38 * have to care about is 512 bytes. */
39#define VCI_BLOCK_SIZE 512
40
41/** Convert block number/size to byte offset/size. */
42#define VCI_BLOCK2BYTE(u) ((uint64_t)(u) << 9)
43
44/** Convert byte offset/size to block number/size. */
45#define VCI_BYTE2BLOCK(u) ((u) >> 9)
46
47/**
48 * The VCI header - at the beginning of the file.
49 *
50 * All entries a stored in little endian order.
51 */
52#pragma pack(1)
53typedef struct VciHdr
54{
55 /** The signature to identify a cache image. */
56 uint32_t u32Signature;
57 /** Version of the layout of metadata in the cache. */
58 uint32_t u32Version;
59 /** Maximum size of the cache file in blocks.
60 * This includes all metadata. */
61 uint64_t cBlocksCache;
62 /** Flag indicating whether the cache was closed cleanly. */
63 uint8_t fUncleanShutdown;
64 /** Cache type. */
65 uint32_t u32CacheType;
66 /** Offset of the B+-Tree root in the image in blocks. */
67 uint64_t offTreeRoot;
68 /** Offset of the block allocation bitmap in blocks. */
69 uint64_t offBlkMap;
70 /** Size of the block allocation bitmap in blocks. */
71 uint32_t cBlkMap;
72 /** UUID of the image. */
73 RTUUID uuidImage;
74 /** Modifcation UUID for the cache. */
75 RTUUID uuidModification;
76 /** Reserved for future use. */
77 uint8_t abReserved[951];
78} VciHdr, *PVciHdr;
79#pragma pack(0)
80AssertCompileSize(VciHdr, 2 * VCI_BLOCK_SIZE);
81
82/** VCI signature to identify a valid image. */
83#define VCI_HDR_SIGNATURE UINT32_C(0x56434900) /* VCI\0 */
84/** Current version we support. */
85#define VCI_HDR_VERSION UINT32_C(0x00000001)
86
87/** Value for an unclean cache shutdown. */
88#define VCI_HDR_UNCLEAN_SHUTDOWN UINT8_C(0x01)
89/** Value for a clean cache shutdown. */
90#define VCI_HDR_CLEAN_SHUTDOWN UINT8_C(0x00)
91
92/** Cache type: Dynamic image growing to the maximum value. */
93#define VCI_HDR_CACHE_TYPE_DYNAMIC UINT32_C(0x00000001)
94/** Cache type: Fixed image, space is preallocated. */
95#define VCI_HDR_CACHE_TYPE_FIXED UINT32_C(0x00000002)
96
97/**
98 * On disk representation of an extent describing a range of cached data.
99 *
100 * All entries a stored in little endian order.
101 */
102#pragma pack(1)
103typedef struct VciCacheExtent
104{
105 /** Block address of the previous extent in the LRU list. */
106 uint64_t u64ExtentPrev;
107 /** Block address of the next extent in the LRU list. */
108 uint64_t u64ExtentNext;
109 /** Flags (for compression, encryption etc.) - currently unused and should be always 0. */
110 uint8_t u8Flags;
111 /** Reserved */
112 uint8_t u8Reserved;
113 /** First block of cached data the extent represents. */
114 uint64_t u64BlockOffset;
115 /** Number of blocks the extent represents. */
116 uint32_t u32Blocks;
117 /** First block in the image where the data is stored. */
118 uint64_t u64BlockAddr;
119} VciCacheExtent, *PVciCacheExtent;
120#pragma pack(0)
121AssertCompileSize(VciCacheExtent, 38);
122
123/**
124 * On disk representation of an internal node.
125 *
126 * All entries a stored in little endian order.
127 */
128#pragma pack(1)
129typedef struct VciTreeNodeInternal
130{
131 /** First block of cached data the internal node represents. */
132 uint64_t u64BlockOffset;
133 /** Number of blocks the internal node represents. */
134 uint32_t u32Blocks;
135 /** Block address in the image where the next node in the tree is stored. */
136 uint64_t u64ChildAddr;
137} VciTreeNodeInternal, *PVciTreeNodeInternal;
138#pragma pack(0)
139AssertCompileSize(VciTreeNodeInternal, 20);
140
141/**
142 * On-disk representation of a node in the B+-Tree.
143 *
144 * All entries a stored in little endian order.
145 */
146#pragma pack(1)
147typedef struct VciTreeNode
148{
149 /** Type of the node (root, internal, leaf). */
150 uint8_t u8Type;
151 /** Data in the node. */
152 uint8_t au8Data[4095];
153} VciTreeNode, *PVciTreeNode;
154#pragma pack(0)
155AssertCompileSize(VciTreeNode, 8 * VCI_BLOCK_SIZE);
156
157/** Node type: Root of the tree (VciTreeNodeInternal). */
158#define VCI_TREE_NODE_TYPE_ROOT UINT32_C(0x00000001)
159/** Node type: Internal node containing links to other nodes (VciTreeNodeInternal). */
160#define VCI_TREE_NODE_TYPE_INTERNAL UINT32_C(0x00000002)
161/** Node type: Leaf of the tree (VciCacheExtent). */
162#define VCI_TREE_NODE_TYPE_LEAF UINT32_C(0x00000003)
163
164/**
165 * VCI block bitmap header.
166 *
167 * All entries a stored in little endian order.
168 */
169#pragma pack(1)
170typedef struct VciBlkMap
171{
172 /** Magic of the block bitmap. */
173 uint32_t u32Magic;
174 /** Version of the block bitmap. */
175 uint32_t u32Version;
176 /** Number of blocks this block map manages. */
177 uint64_t cBlocks;
178 /** Number of free blocks. */
179 uint64_t cBlocksFree;
180 /** Number of blocks allocated for metadata. */
181 uint64_t cBlocksAllocMeta;
182 /** Number of blocks allocated for actual cached data. */
183 uint64_t cBlocksAllocData;
184 /** Reserved for future use. */
185 uint8_t au8Reserved[472];
186} VciBlkMap, *PVciBlkMap;
187#pragma pack(0)
188AssertCompileSize(VciBlkMap, VCI_BLOCK_SIZE);
189
190/** The magic which identifies a block map. */
191#define VCI_BLKMAP_MAGIC UINT32_C(0x56424c4b) /* VBLK */
192/** Current version. */
193#define VCI_BLKMAP_VERSION UINT32_C(0x00000001)
194
195/** Block bitmap entry */
196typedef uint8_t VciBlkMapEnt;
197
198/*******************************************************************************
199* Constants And Macros, Structures and Typedefs *
200*******************************************************************************/
201
202/**
203 * Block range descriptor.
204 */
205typedef struct VCIBLKRANGEDESC
206{
207 /** Previous entry in the list. */
208 struct VCIBLKRANGEDESC *pPrev;
209 /** Next entry in the list. */
210 struct VCIBLKRANGEDESC *pNext;
211 /** Start address of the range. */
212 uint64_t offAddrStart;
213 /** Number of blocks in the range. */
214 uint64_t cBlocks;
215 /** Flag whether the range is free or allocated. */
216 bool fFree;
217} VCIBLKRANGEDESC, *PVCIBLKRANGEDESC;
218
219/**
220 * Block map for the cache image - in memory structure.
221 */
222typedef struct VCIBLKMAP
223{
224 /** Number of blocks the map manages. */
225 uint64_t cBlocks;
226 /** Number of blocks allocated for metadata. */
227 uint64_t cBlocksAllocMeta;
228 /** Number of blocks allocated for actual cached data. */
229 uint64_t cBlocksAllocData;
230 /** Number of free blocks. */
231 uint64_t cBlocksFree;
232
233 /** Pointer to the head of the block range list. */
234 PVCIBLKRANGEDESC pRangesHead;
235 /** Pointer to the tail of the block range list. */
236 PVCIBLKRANGEDESC pRangesTail;
237
238 /** Pointer to the block bitmap. */
239 VciBlkMapEnt *pBlkBitmap;
240} VCIBLKMAP;
241/** Pointer to a block map. */
242typedef VCIBLKMAP *PVCIBLKMAP;
243
244/**
245 * VCI image data structure.
246 */
247typedef struct VCICACHE
248{
249 /** Image name. */
250 const char *pszFilename;
251 /** Storage handle. */
252 PVDIOSTORAGE pStorage;
253 /** I/O interface. */
254 PVDINTERFACE pInterfaceIO;
255 /** Async I/O interface callbacks. */
256 PVDINTERFACEIOINT pInterfaceIOCallbacks;
257
258 /** Pointer to the per-disk VD interface list. */
259 PVDINTERFACE pVDIfsDisk;
260 /** Pointer to the per-image VD interface list. */
261 PVDINTERFACE pVDIfsImage;
262
263 /** Error callback. */
264 PVDINTERFACE pInterfaceError;
265 /** Opaque data for error callback. */
266 PVDINTERFACEERROR pInterfaceErrorCallbacks;
267
268 /** Open flags passed by VBoxHD layer. */
269 unsigned uOpenFlags;
270 /** Image flags defined during creation or determined during open. */
271 unsigned uImageFlags;
272 /** Total size of the image. */
273 uint64_t cbSize;
274
275 /** Offset of the B+-Tree in the image in bytes. */
276 uint64_t offTreeRoot;
277 /** @todo Pointer to the root of the tree in memory. */
278
279
280 /** Offset to the block allocation bitmap in bytes. */
281 uint64_t offBlksBitmap;
282 /** Block map. */
283 PVCIBLKMAP pBlkMap;
284} VCICACHE, *PVCICACHE;
285
286/*******************************************************************************
287* Static Variables *
288*******************************************************************************/
289
290/** NULL-terminated array of supported file extensions. */
291static const char *const s_apszVciFileExtensions[] =
292{
293 "vci",
294 NULL
295};
296
297/*******************************************************************************
298* Internal Functions *
299*******************************************************************************/
300
301/**
302 * Internal: signal an error to the frontend.
303 */
304DECLINLINE(int) vciError(PVCICACHE pImage, int rc, RT_SRC_POS_DECL,
305 const char *pszFormat, ...)
306{
307 va_list va;
308 va_start(va, pszFormat);
309 if (pImage->pInterfaceError)
310 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
311 pszFormat, va);
312 va_end(va);
313 return rc;
314}
315
316/**
317 * Internal: signal an informational message to the frontend.
318 */
319DECLINLINE(int) vciMessage(PVCICACHE pImage, const char *pszFormat, ...)
320{
321 int rc = VINF_SUCCESS;
322 va_list va;
323 va_start(va, pszFormat);
324 if (pImage->pInterfaceError)
325 rc = pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser,
326 pszFormat, va);
327 va_end(va);
328 return rc;
329}
330
331
332DECLINLINE(int) vciFileOpen(PVCICACHE pImage, const char *pszFilename,
333 uint32_t fOpen)
334{
335 return pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
336 pszFilename, fOpen,
337 &pImage->pStorage);
338}
339
340DECLINLINE(int) vciFileClose(PVCICACHE pImage)
341{
342 return pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
343 pImage->pStorage);
344}
345
346DECLINLINE(int) vciFileDelete(PVCICACHE pImage, const char *pszFilename)
347{
348 return pImage->pInterfaceIOCallbacks->pfnDelete(pImage->pInterfaceIO->pvUser,
349 pszFilename);
350}
351
352DECLINLINE(int) vciFileMove(PVCICACHE pImage, const char *pszSrc,
353 const char *pszDst, unsigned fMove)
354{
355 return pImage->pInterfaceIOCallbacks->pfnMove(pImage->pInterfaceIO->pvUser,
356 pszSrc, pszDst, fMove);
357}
358
359DECLINLINE(int) vciFileGetFreeSpace(PVCICACHE pImage, const char *pszFilename,
360 int64_t *pcbFree)
361{
362 return pImage->pInterfaceIOCallbacks->pfnGetFreeSpace(pImage->pInterfaceIO->pvUser,
363 pszFilename, pcbFree);
364}
365
366DECLINLINE(int) vciFileGetSize(PVCICACHE pImage, uint64_t *pcbSize)
367{
368 return pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
369 pImage->pStorage, pcbSize);
370}
371
372DECLINLINE(int) vciFileSetSize(PVCICACHE pImage, uint64_t cbSize)
373{
374 return pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
375 pImage->pStorage, cbSize);
376}
377
378DECLINLINE(int) vciFileWriteSync(PVCICACHE pImage, uint64_t uOffset,
379 const void *pvBuffer, size_t cbBuffer)
380{
381 return pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
382 pImage->pStorage, uOffset,
383 pvBuffer, cbBuffer, NULL);
384}
385
386DECLINLINE(int) vciFileReadSync(PVCICACHE pImage, uint64_t uOffset,
387 void *pvBuffer, size_t cbBuffer)
388{
389 return pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
390 pImage->pStorage, uOffset,
391 pvBuffer, cbBuffer, NULL);
392}
393
394DECLINLINE(int) vciFileFlushSync(PVCICACHE pImage)
395{
396 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
397 pImage->pStorage);
398}
399
400DECLINLINE(int) vciFileReadUserAsync(PVCICACHE pImage, uint64_t uOffset,
401 PVDIOCTX pIoCtx, size_t cbRead)
402{
403 return pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
404 pImage->pStorage,
405 uOffset, pIoCtx,
406 cbRead);
407}
408
409DECLINLINE(int) vciFileWriteUserAsync(PVCICACHE pImage, uint64_t uOffset,
410 PVDIOCTX pIoCtx, size_t cbWrite,
411 PFNVDXFERCOMPLETED pfnComplete,
412 void *pvCompleteUser)
413{
414 return pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
415 pImage->pStorage,
416 uOffset, pIoCtx,
417 cbWrite,
418 pfnComplete,
419 pvCompleteUser);
420}
421
422DECLINLINE(int) vciFileFlushAsync(PVCICACHE pImage, PVDIOCTX pIoCtx,
423 PFNVDXFERCOMPLETED pfnComplete,
424 void *pvCompleteUser)
425{
426 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
427 pImage->pStorage,
428 pIoCtx, pfnComplete,
429 pvCompleteUser);
430}
431
432/**
433 * Internal. Flush image data to disk.
434 */
435static int vciFlushImage(PVCICACHE pImage)
436{
437 int rc = VINF_SUCCESS;
438
439 if ( pImage->pStorage
440 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
441 rc = vciFileFlushSync(pImage);
442
443 return rc;
444}
445
446/**
447 * Internal. Free all allocated space for representing an image except pImage,
448 * and optionally delete the image from disk.
449 */
450static int vciFreeImage(PVCICACHE pImage, bool fDelete)
451{
452 int rc = VINF_SUCCESS;
453
454 /* Freeing a never allocated image (e.g. because the open failed) is
455 * not signalled as an error. After all nothing bad happens. */
456 if (pImage)
457 {
458 if (pImage->pStorage)
459 {
460 /* No point updating the file that is deleted anyway. */
461 if (!fDelete)
462 vciFlushImage(pImage);
463
464 vciFileClose(pImage);
465 pImage->pStorage = NULL;
466 }
467
468 if (fDelete && pImage->pszFilename)
469 vciFileDelete(pImage, pImage->pszFilename);
470 }
471
472 LogFlowFunc(("returns %Rrc\n", rc));
473 return rc;
474}
475
476/**
477 * Creates a new block map which can manage the given number of blocks.
478 *
479 * The size of the bitmap is aligned to the VCI block size.
480 *
481 * @returns VBox status code.
482 * @param cBlocks The number of blocks the bitmap can manage.
483 * @param ppBlkMap Where to store the pointer to the block bitmap.
484 * @param pcbBlkMap Where to store the size of the block bitmap in blocks
485 * needed on the disk.
486 */
487static int vciBlkMapCreate(uint64_t cBlocks, PVCIBLKMAP *ppBlkMap, uint32_t *pcBlkMap)
488{
489 int rc = VINF_SUCCESS;
490 uint32_t cbBlkMap = RT_ALIGN_Z(cBlocks / sizeof(VciBlkMapEnt) / 8, VCI_BLOCK_SIZE);
491 PVCIBLKMAP pBlkMap = (PVCIBLKMAP)RTMemAllocZ(sizeof(VCIBLKMAP));
492 VciBlkMapEnt *pBlkBitmap = (VciBlkMapEnt *)RTMemAllocZ(cbBlkMap);
493 PVCIBLKRANGEDESC pFree = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
494
495 LogFlowFunc(("cBlocks=%u ppBlkMap=%#p pcBlkMap=%#p\n", cBlocks, ppBlkMap, pcBlkMap));
496
497 if (pBlkMap && pBlkBitmap && pFree)
498 {
499 pBlkMap->cBlocks = cBlocks;
500 pBlkMap->cBlocksAllocMeta = 0;
501 pBlkMap->cBlocksAllocData = 0;
502 pBlkMap->cBlocksFree = cBlocks;
503 pBlkMap->pBlkBitmap = pBlkBitmap;
504
505 pFree->pPrev = NULL;
506 pFree->pNext = NULL;
507 pFree->offAddrStart = 0;
508 pFree->cBlocks = cBlocks;
509 pFree->fFree = true;
510
511 pBlkMap->pRangesHead = pFree;
512 pBlkMap->pRangesTail = pFree;
513
514 Assert(!((cbBlkMap + sizeof(VciBlkMap) % VCI_BLOCK_SIZE)));
515 *ppBlkMap = pBlkMap;
516 *pcBlkMap = (cbBlkMap + sizeof(VciBlkMap)) / VCI_BLOCK_SIZE;
517 }
518 else
519 {
520 if (pBlkMap)
521 RTMemFree(pBlkMap);
522 if (pBlkBitmap)
523 RTMemFree(pBlkBitmap);
524 if (pFree)
525 RTMemFree(pFree);
526
527 rc = VERR_NO_MEMORY;
528 }
529
530 LogFlowFunc(("returns rc=%Rrc cBlkMap=%u\n", rc, *pcBlkMap));
531 return rc;
532}
533
534/**
535 * Frees a block map.
536 *
537 * @returns nothing.
538 * @param pBlkMap The block bitmap to destroy.
539 */
540static void vciBlkMapDestroy(PVCIBLKMAP pBlkMap)
541{
542 LogFlowFunc(("pBlkMap=%#p\n", pBlkMap));
543
544 PVCIBLKRANGEDESC pRangeCur = pBlkMap->pRangesHead;
545
546 while (pRangeCur)
547 {
548 PVCIBLKRANGEDESC pTmp = pRangeCur;
549
550 RTMemFree(pTmp);
551
552 pRangeCur = pRangeCur->pNext;
553 }
554
555 RTMemFree(pBlkMap->pBlkBitmap);
556 RTMemFree(pBlkMap);
557
558 LogFlowFunc(("returns\n"));
559}
560
561/**
562 * Loads the block map from the specified medium and creates all necessary
563 * in memory structures to manage used and free blocks.
564 *
565 * @returns VBox status code.
566 * @param pStorage Storage handle to read the block bitmap from.
567 * @param offBlkMap Start of the block bitmap in blocks.
568 * @param cBlkMap Size of the block bitmap on the disk in blocks.
569 * @param ppBlkMap Where to store the block bitmap on success.
570 */
571static int vciBlkMapLoad(PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap, PVCIBLKMAP *ppBlkMap)
572{
573 int rc = VINF_SUCCESS;
574 VciBlkMap BlkMap;
575
576 LogFlowFunc(("pStorage=%#p offBlkMap=%llu cBlkMap=%u ppBlkMap=%#p\n",
577 pStorage, offBlkMap, cBlkMap, ppBlkMap));
578
579 if (cBlkMap >= VCI_BYTE2BLOCK(sizeof(VciBlkMap)))
580 {
581 cBlkMap -= VCI_BYTE2BLOCK(sizeof(VciBlkMap));
582
583 rc = vciFileReadSync(pStorage, offBlkMap, &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
584 if (RT_SUCCESS(rc))
585 {
586 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
587
588 BlkMap.u32Magic = RT_LE2H_U32(BlkMap.u32Magic);
589 BlkMap.u32Version = RT_LE2H_U32(BlkMap.u32Version);
590 BlkMap.cBlocks = RT_LE2H_U32(BlkMap.cBlocks);
591 BlkMap.cBlocksFree = RT_LE2H_U32(BlkMap.cBlocksFree);
592 BlkMap.cBlocksAllocMeta = RT_LE2H_U32(BlkMap.cBlocksAllocMeta);
593 BlkMap.cBlocksAllocData = RT_LE2H_U32(BlkMap.cBlocksAllocData);
594
595 if ( BlkMap.u32Magic == VCI_BLKMAP_MAGIC
596 && BlkMap.u32Version == VCI_BLKMAP_VERSION
597 && BlkMap.cBlocks == BlkMap.cBlocksFree + BlkMap.cBlocksAllocMeta + BlkMap.cBlocksAllocData
598 && BlkMap.cBlocks / 8 == cBlkMap)
599 {
600 PVCIBLKMAP pBlkMap = (PVCIBLKMAP)RTMemAllocZ(sizeof(VCIBLKMAP));
601 if (pBlkMap)
602 {
603 pBlkMap->cBlocks = BlkMap.cBlocks;
604 pBlkMap->cBlocksFree = BlkMap.cBlocksFree;
605 pBlkMap->cBlocksAllocMeta = BlkMap.cBlocksAllocMeta;
606 pBlkMap->cBlocksAllocData = BlkMap.cBlocksAllocData;
607
608 pBlkMap->pBlkBitmap = (VciBlkMapEnt *)RTMemAllocZ(pBlkMap->cBlocks / 8);
609 if (pBlkMap->pBlkBitmap)
610 {
611 rc = vciFileReadSync(pStorage, offBlkMap, pBlkMap->pBlkBitmap, cBlkMap);
612 if (RT_SUCCESS(rc))
613 {
614 *ppBlkMap = pBlkMap;
615 LogFlowFunc(("return success\n"));
616 return VINF_SUCCESS;
617 }
618
619 RTMemFree(pBlkMap->pBlkBitmap);
620 }
621 else
622 rc = VERR_NO_MEMORY;
623
624 RTMemFree(pBlkMap);
625 }
626 else
627 rc = VERR_NO_MEMORY;
628 }
629 else
630 rc = VERR_VD_GEN_INVALID_HEADER;
631 }
632 else if (RT_SUCCESS(rc))
633 rc = VERR_VD_GEN_INVALID_HEADER;
634 }
635 else
636 rc = VERR_VD_GEN_INVALID_HEADER;
637
638 LogFlowFunc(("returns rc=%Rrc\n", rc));
639 return rc;
640}
641
642/**
643 * Saves the block map in the cache image. All neccessary on disk structures
644 * are written.
645 *
646 * @returns VBox status code.
647 * @param pBlkMap The block bitmap to save.
648 * @param pStorage Where the block bitmap should be written to.
649 * @param offBlkMap Start of the block bitmap in blocks.
650 * @param cBlkMap Size of the block bitmap on the disk in blocks.
651 */
652static int vciBlkMapSave(PVCIBLKMAP pBlkMap, PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap)
653{
654 int rc = VINF_SUCCESS;
655 VciBlkMap BlkMap;
656
657 LogFlowFunc(("pBlkMap=%#p pStorage=%#p offBlkMap=%llu cBlkMap=%u\n",
658 pBlkMap, pStorage, offBlkMap, cBlkMap));
659
660 /* Make sure the number of blocks allocated for us match our expectations. */
661 if ((pBlkMap->cBlocks / 8) + VCI_BYTE2BLOCK(sizeof(VciBlkMap)) == cBlkMap)
662 {
663 /* Setup the header */
664 memset(&BlkMap, 0, sizeof(VciBlkMap));
665
666 BlkMap.u32Magic = RT_H2LE_U32(VCI_BLKMAP_MAGIC);
667 BlkMap.u32Version = RT_H2LE_U32(VCI_BLKMAP_VERSION);
668 BlkMap.cBlocks = RT_H2LE_U32(pBlkMap->cBlocks);
669 BlkMap.cBlocksFree = RT_H2LE_U32(pBlkMap->cBlocksFree);
670 BlkMap.cBlocksAllocMeta = RT_H2LE_U32(pBlkMap->cBlocksAllocMeta);
671 BlkMap.cBlocksAllocData = RT_H2LE_U32(pBlkMap->cBlocksAllocData);
672
673 rc = vciFileWriteSync(pStorage, offBlkMap, &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
674 if (RT_SUCCESS(rc))
675 {
676 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
677 rc = vciFileWriteSync(pStorage, offBlkMap, pBlkMap->pBlkBitmap, pBlkMap->cBlocks / 8);
678 }
679 }
680 else
681 rc = VERR_INTERNAL_ERROR; /* @todo Better error code. */
682
683 LogFlowFunc(("returns rc=%Rrc\n", rc));
684 return rc;
685}
686
687/**
688 * Allocates the given number of blocks in the bitmap and returns the start block address.
689 *
690 * @returns VBox status code.
691 * @param pBlkMap The block bitmap to allocate the blocks from.
692 * @param cBlocks How many blocks to allocate.
693 * @param poffBlockAddr Where to store the start address of the allocated region.
694 */
695static int vciBlkMapAllocate(PVCIBLKMAP pBlkMap, uint32_t cBlocks, uint64_t *poffBlockAddr)
696{
697 int rc = VINF_SUCCESS;
698
699 LogFlowFunc(("pBlkMap=%#p cBlocks=%u poffBlockAddr=%#p\n",
700 pBlkMap, cBlocks, poffBlockAddr));
701
702 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
703 return rc;
704}
705
706/**
707 * Try to extend the space of an already allocated block.
708 *
709 * @returns VBox status code.
710 * @param pBlkMap The block bitmap to allocate the blocks from.
711 * @param cBlocksNew How many blocks the extended block should have.
712 * @param offBlockAddrOld The start address of the block to reallocate.
713 * @param poffBlockAddr Where to store the start address of the allocated region.
714 */
715static int vciBlkMapRealloc(PVCIBLKMAP pBlkMap, uint32_t cBlocksNew, uint64_t offBlockAddrOld,
716 uint64_t *poffBlockAddr)
717{
718 int rc = VINF_SUCCESS;
719
720 LogFlowFunc(("pBlkMap=%#p cBlocksNew=%u offBlockAddrOld=%llu poffBlockAddr=%#p\n",
721 pBlkMap, cBlocksNew, offBlockAddrOld, poffBlockAddr));
722
723 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
724 return rc;
725}
726
727/**
728 * Frees a range of blocks.
729 *
730 * @returns nothing.
731 * @param pBlkMap The block bitmap.
732 * @param offBlockAddr Address of the first block to free.
733 * @param cBlocks How many blocks to free.
734 */
735static void vciBlkMapFree(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr, uint32_t cBlocks)
736{
737 LogFlowFunc(("pBlkMap=%#p offBlockAddr=%llu cBlocks=%u\n",
738 pBlkMap, offBlockAddr, cBlocks));
739
740 LogFlowFunc(("returns\n"));
741}
742
743/**
744 * Internal: Open an image, constructing all necessary data structures.
745 */
746static int vciOpenImage(PVCICACHE pImage, unsigned uOpenFlags)
747{
748 int rc;
749
750 pImage->uOpenFlags = uOpenFlags;
751
752 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
753 if (pImage->pInterfaceError)
754 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
755
756 /* Get I/O interface. */
757 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
758 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
759 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
760 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
761
762 /*
763 * Open the image.
764 */
765 rc = vciFileOpen(pImage, pImage->pszFilename,
766 VDOpenFlagsToFileOpenFlags(uOpenFlags,
767 false /* fCreate */));
768 if (RT_FAILURE(rc))
769 {
770 /* Do NOT signal an appropriate error here, as the VD layer has the
771 * choice of retrying the open if it failed. */
772 goto out;
773 }
774
775 rc = vciFileGetSize(pImage, &pImage->cbSize);
776 if (RT_FAILURE(rc))
777 goto out;
778 if (pImage->cbSize % 512)
779 {
780 rc = VERR_VD_RAW_INVALID_HEADER;
781 goto out;
782 }
783 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
784
785out:
786 if (RT_FAILURE(rc))
787 vciFreeImage(pImage, false);
788 return rc;
789}
790
791/**
792 * Internal: Create a vci image.
793 */
794static int vciCreateImage(PVCICACHE pImage, uint64_t cbSize,
795 unsigned uImageFlags, const char *pszComment,
796 unsigned uOpenFlags, PFNVDPROGRESS pfnProgress,
797 void *pvUser, unsigned uPercentStart,
798 unsigned uPercentSpan)
799{
800 VciHdr Hdr;
801 VciTreeNode NodeRoot;
802 int rc;
803 uint64_t cBlocks = cbSize / VCI_BLOCK_SIZE; /* Size of the cache in blocks. */
804
805 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
806 {
807 rc = vciError(pImage, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("VCI: cannot create diff image '%s'"), pImage->pszFilename);
808 return rc;
809 }
810
811 pImage->uImageFlags = uImageFlags;
812
813 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
814
815 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
816 if (pImage->pInterfaceError)
817 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
818
819 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
820 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
821 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
822 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
823
824 do
825 {
826 /* Create image file. */
827 rc = vciFileOpen(pImage, pImage->pszFilename,
828 VDOpenFlagsToFileOpenFlags(uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
829 true /* fCreate */));
830 if (RT_FAILURE(rc))
831 {
832 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot create image '%s'"), pImage->pszFilename);
833 break;
834 }
835
836 /* Allocate block bitmap. */
837 uint32_t cBlkMap = 0;
838 rc = vciBlkMapCreate(cBlocks, &pImage->pBlkMap, &cBlkMap);
839 if (RT_FAILURE(rc))
840 {
841 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot create block bitmap '%s'"), pImage->pszFilename);
842 break;
843 }
844
845 /*
846 * Allocate space for the header in the block bitmap.
847 * Because the block map is empty the header has to start at block 0
848 */
849 uint64_t offHdr = 0;
850 rc = vciBlkMapAllocate(pImage->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciHdr)), &offHdr);
851 if (RT_FAILURE(rc))
852 {
853 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot allocate space for header in block bitmap '%s'"), pImage->pszFilename);
854 break;
855 }
856
857 Assert(offHdr == 0);
858
859 /*
860 * Allocate space for the block map itself.
861 */
862 uint64_t offBlkMap = 0;
863 rc = vciBlkMapAllocate(pImage->pBlkMap, cBlkMap, &offBlkMap);
864 if (RT_FAILURE(rc))
865 {
866 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pImage->pszFilename);
867 break;
868 }
869
870 /*
871 * Allocate space for the tree root node.
872 */
873 uint64_t offTreeRoot = 0;
874 rc = vciBlkMapAllocate(pImage->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciTreeNode)), &offTreeRoot);
875 if (RT_FAILURE(rc))
876 {
877 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pImage->pszFilename);
878 break;
879 }
880
881 /*
882 * Now that we are here we have all the basic structures and know where to place them in the image.
883 * It's time to write it now.
884 */
885
886 /* Setup the header. */
887 memset(&Hdr, 0, sizeof(VciHdr));
888 Hdr.u32Signature = RT_H2LE_U32(VCI_HDR_SIGNATURE);
889 Hdr.u32Version = RT_H2LE_U32(VCI_HDR_VERSION);
890 Hdr.cBlocksCache = RT_H2LE_U64(cBlocks);
891 Hdr.fUncleanShutdown = VCI_HDR_UNCLEAN_SHUTDOWN;
892 Hdr.u32CacheType = uImageFlags & VD_IMAGE_FLAGS_FIXED
893 ? RT_H2LE_U32(VCI_HDR_CACHE_TYPE_FIXED)
894 : RT_H2LE_U32(VCI_HDR_CACHE_TYPE_DYNAMIC);
895 Hdr.offTreeRoot = RT_H2LE_U64(offTreeRoot);
896 Hdr.offBlkMap = RT_H2LE_U64(offBlkMap);
897 Hdr.cBlkMap = RT_H2LE_U64(cBlkMap);
898
899 rc = vciFileWriteSync(pImage, offHdr, &Hdr, VCI_BYTE2BLOCK(sizeof(VciHdr)));
900 if (RT_FAILURE(rc))
901 {
902 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot write header '%s'"), pImage->pszFilename);
903 break;
904 }
905
906 rc = vciBlkMapSave(pImage->pBlkMap, pImage, offBlkMap, cBlkMap);
907 if (RT_FAILURE(rc))
908 {
909 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot write block map '%s'"), pImage->pszFilename);
910 break;
911 }
912
913 /* Setup the root tree. */
914 memset(&NodeRoot, 0, sizeof(VciTreeNode));
915 NodeRoot.u8Type = RT_H2LE_U32(VCI_TREE_NODE_TYPE_ROOT);
916
917 rc = vciFileWriteSync(pImage, offTreeRoot, &NodeRoot, VCI_BYTE2BLOCK(sizeof(VciTreeNode)));
918 if (RT_FAILURE(rc))
919 {
920 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot write root node '%s'"), pImage->pszFilename);
921 break;
922 }
923
924 rc = vciFlushImage(pImage);
925 if (RT_FAILURE(rc))
926 {
927 rc = vciError(pImage, rc, RT_SRC_POS, N_("VCI: cannot flush '%s'"), pImage->pszFilename);
928 break;
929 }
930
931 pImage->cbSize = cbSize;
932
933 } while (0);
934
935 if (RT_SUCCESS(rc) && pfnProgress)
936 pfnProgress(pvUser, uPercentStart + uPercentSpan);
937
938 if (RT_FAILURE(rc))
939 vciFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
940 return rc;
941}
942
943/** @copydoc VDCACHEBACKEND::pfnProbe */
944static int vciProbe(const char *pszFilename, PVDINTERFACE pVDIfsCache,
945 PVDINTERFACE pVDIfsImage)
946{
947 LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
948 int rc = VINF_SUCCESS;
949
950 if ( !VALID_PTR(pszFilename)
951 || !*pszFilename)
952 {
953 rc = VERR_INVALID_PARAMETER;
954 goto out;
955 }
956
957out:
958 LogFlowFunc(("returns %Rrc\n", rc));
959 return rc;
960}
961
962/** @copydoc VDCACHEBACKEND::pfnOpen */
963static int vciOpen(const char *pszFilename, unsigned uOpenFlags,
964 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
965 void **ppBackendData)
966{
967 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
968 int rc;
969 PVCICACHE pImage;
970
971 /* Check open flags. All valid flags are supported. */
972 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
973 {
974 rc = VERR_INVALID_PARAMETER;
975 goto out;
976 }
977
978 /* Check remaining arguments. */
979 if ( !VALID_PTR(pszFilename)
980 || !*pszFilename)
981 {
982 rc = VERR_INVALID_PARAMETER;
983 goto out;
984 }
985
986
987 pImage = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
988 if (!pImage)
989 {
990 rc = VERR_NO_MEMORY;
991 goto out;
992 }
993 pImage->pszFilename = pszFilename;
994 pImage->pStorage = NULL;
995 pImage->pVDIfsDisk = pVDIfsDisk;
996 pImage->pVDIfsImage = pVDIfsImage;
997
998 rc = vciOpenImage(pImage, uOpenFlags);
999 if (RT_SUCCESS(rc))
1000 *ppBackendData = pImage;
1001 else
1002 RTMemFree(pImage);
1003
1004out:
1005 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1006 return rc;
1007}
1008
1009/** @copydoc VDCACHEBACKEND::pfnCreate */
1010static int vciCreate(const char *pszFilename, uint64_t cbSize,
1011 unsigned uImageFlags, const char *pszComment,
1012 PCRTUUID pUuid, unsigned uOpenFlags,
1013 unsigned uPercentStart, unsigned uPercentSpan,
1014 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1015 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
1016{
1017 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",
1018 pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
1019 int rc;
1020 PVCICACHE pImage;
1021
1022 PFNVDPROGRESS pfnProgress = NULL;
1023 void *pvUser = NULL;
1024 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
1025 VDINTERFACETYPE_PROGRESS);
1026 PVDINTERFACEPROGRESS pCbProgress = NULL;
1027 if (pIfProgress)
1028 {
1029 pCbProgress = VDGetInterfaceProgress(pIfProgress);
1030 if (pCbProgress)
1031 pfnProgress = pCbProgress->pfnProgress;
1032 pvUser = pIfProgress->pvUser;
1033 }
1034
1035 /* Check open flags. All valid flags are supported. */
1036 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1037 {
1038 rc = VERR_INVALID_PARAMETER;
1039 goto out;
1040 }
1041
1042 /* Check remaining arguments. */
1043 if ( !VALID_PTR(pszFilename)
1044 || !*pszFilename)
1045 {
1046 rc = VERR_INVALID_PARAMETER;
1047 goto out;
1048 }
1049
1050 pImage = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1051 if (!pImage)
1052 {
1053 rc = VERR_NO_MEMORY;
1054 goto out;
1055 }
1056 pImage->pszFilename = pszFilename;
1057 pImage->pStorage = NULL;
1058 pImage->pVDIfsDisk = pVDIfsDisk;
1059 pImage->pVDIfsImage = pVDIfsImage;
1060
1061 rc = vciCreateImage(pImage, cbSize, uImageFlags, pszComment, uOpenFlags,
1062 pfnProgress, pvUser, uPercentStart, uPercentSpan);
1063 if (RT_SUCCESS(rc))
1064 {
1065 /* So far the image is opened in read/write mode. Make sure the
1066 * image is opened in read-only mode if the caller requested that. */
1067 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
1068 {
1069 vciFreeImage(pImage, false);
1070 rc = vciOpenImage(pImage, uOpenFlags);
1071 if (RT_FAILURE(rc))
1072 {
1073 RTMemFree(pImage);
1074 goto out;
1075 }
1076 }
1077 *ppBackendData = pImage;
1078 }
1079 else
1080 RTMemFree(pImage);
1081
1082out:
1083 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1084 return rc;
1085}
1086
1087/** @copydoc VDCACHEBACKEND::pfnClose */
1088static int vciClose(void *pBackendData, bool fDelete)
1089{
1090 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
1091 PVCICACHE pImage = (PVCICACHE)pBackendData;
1092 int rc;
1093
1094 rc = vciFreeImage(pImage, fDelete);
1095 RTMemFree(pImage);
1096
1097 LogFlowFunc(("returns %Rrc\n", rc));
1098 return rc;
1099}
1100
1101/** @copydoc VDCACHEBACKEND::pfnRead */
1102static int vciRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
1103 size_t cbToRead, size_t *pcbActuallyRead)
1104{
1105 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
1106 PVCICACHE pImage = (PVCICACHE)pBackendData;
1107 int rc = VINF_SUCCESS;
1108
1109 AssertPtr(pImage);
1110 Assert(uOffset % 512 == 0);
1111 Assert(cbToRead % 512 == 0);
1112
1113out:
1114 LogFlowFunc(("returns %Rrc\n", rc));
1115 return rc;
1116}
1117
1118/** @copydoc VDCACHEBACKEND::pfnWrite */
1119static int vciWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
1120 size_t cbToWrite, size_t *pcbWriteProcess)
1121{
1122 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
1123 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
1124 PVCICACHE pImage = (PVCICACHE)pBackendData;
1125 int rc = VINF_SUCCESS;
1126
1127 AssertPtr(pImage);
1128 Assert(uOffset % 512 == 0);
1129 Assert(cbToWrite % 512 == 0);
1130
1131out:
1132 LogFlowFunc(("returns %Rrc\n", rc));
1133 return rc;
1134}
1135
1136/** @copydoc VDCACHEBACKEND::pfnFlush */
1137static int vciFlush(void *pBackendData)
1138{
1139 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1140 PVCICACHE pImage = (PVCICACHE)pBackendData;
1141 int rc = VINF_SUCCESS;
1142
1143 rc = vciFlushImage(pImage);
1144 LogFlowFunc(("returns %Rrc\n", rc));
1145 return rc;
1146}
1147
1148/** @copydoc VDCACHEBACKEND::pfnGetVersion */
1149static unsigned vciGetVersion(void *pBackendData)
1150{
1151 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1152 PVCICACHE pImage = (PVCICACHE)pBackendData;
1153
1154 AssertPtr(pImage);
1155
1156 if (pImage)
1157 return 1;
1158 else
1159 return 0;
1160}
1161
1162/** @copydoc VDCACHEBACKEND::pfnGetSize */
1163static uint64_t vciGetSize(void *pBackendData)
1164{
1165 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1166 PVCICACHE pImage = (PVCICACHE)pBackendData;
1167 uint64_t cb = 0;
1168
1169 AssertPtr(pImage);
1170
1171 if (pImage && pImage->pStorage)
1172 cb = pImage->cbSize;
1173
1174 LogFlowFunc(("returns %llu\n", cb));
1175 return cb;
1176}
1177
1178/** @copydoc VDCACHEBACKEND::pfnGetFileSize */
1179static uint64_t vciGetFileSize(void *pBackendData)
1180{
1181 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1182 PVCICACHE pImage = (PVCICACHE)pBackendData;
1183 uint64_t cb = 0;
1184
1185 AssertPtr(pImage);
1186
1187 if (pImage)
1188 {
1189 uint64_t cbFile;
1190 if (pImage->pStorage)
1191 {
1192 int rc = vciFileGetSize(pImage, &cbFile);
1193 if (RT_SUCCESS(rc))
1194 cb = cbFile;
1195 }
1196 }
1197
1198 LogFlowFunc(("returns %lld\n", cb));
1199 return cb;
1200}
1201
1202/** @copydoc VDCACHEBACKEND::pfnGetImageFlags */
1203static unsigned vciGetImageFlags(void *pBackendData)
1204{
1205 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1206 PVCICACHE pImage = (PVCICACHE)pBackendData;
1207 unsigned uImageFlags;
1208
1209 AssertPtr(pImage);
1210
1211 if (pImage)
1212 uImageFlags = pImage->uImageFlags;
1213 else
1214 uImageFlags = 0;
1215
1216 LogFlowFunc(("returns %#x\n", uImageFlags));
1217 return uImageFlags;
1218}
1219
1220/** @copydoc VDCACHEBACKEND::pfnGetOpenFlags */
1221static unsigned vciGetOpenFlags(void *pBackendData)
1222{
1223 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1224 PVCICACHE pImage = (PVCICACHE)pBackendData;
1225 unsigned uOpenFlags;
1226
1227 AssertPtr(pImage);
1228
1229 if (pImage)
1230 uOpenFlags = pImage->uOpenFlags;
1231 else
1232 uOpenFlags = 0;
1233
1234 LogFlowFunc(("returns %#x\n", uOpenFlags));
1235 return uOpenFlags;
1236}
1237
1238/** @copydoc VDCACHEBACKEND::pfnSetOpenFlags */
1239static int vciSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
1240{
1241 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
1242 PVCICACHE pImage = (PVCICACHE)pBackendData;
1243 int rc;
1244
1245 /* Image must be opened and the new flags must be valid. Just readonly and
1246 * info flags are supported. */
1247 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
1248 {
1249 rc = VERR_INVALID_PARAMETER;
1250 goto out;
1251 }
1252
1253 /* Implement this operation via reopening the image. */
1254 rc = vciFreeImage(pImage, false);
1255 if (RT_FAILURE(rc))
1256 goto out;
1257 rc = vciOpenImage(pImage, uOpenFlags);
1258
1259out:
1260 LogFlowFunc(("returns %Rrc\n", rc));
1261 return rc;
1262}
1263
1264/** @copydoc VDCACHEBACKEND::pfnGetComment */
1265static int vciGetComment(void *pBackendData, char *pszComment,
1266 size_t cbComment)
1267{
1268 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
1269 PVCICACHE pImage = (PVCICACHE)pBackendData;
1270 int rc;
1271
1272 AssertPtr(pImage);
1273
1274 if (pImage)
1275 rc = VERR_NOT_SUPPORTED;
1276 else
1277 rc = VERR_VD_NOT_OPENED;
1278
1279 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
1280 return rc;
1281}
1282
1283/** @copydoc VDCACHEBACKEND::pfnSetComment */
1284static int vciSetComment(void *pBackendData, const char *pszComment)
1285{
1286 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1287 PVCICACHE pImage = (PVCICACHE)pBackendData;
1288 int rc;
1289
1290 AssertPtr(pImage);
1291
1292 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1293 {
1294 rc = VERR_VD_IMAGE_READ_ONLY;
1295 goto out;
1296 }
1297
1298 if (pImage)
1299 rc = VERR_NOT_SUPPORTED;
1300 else
1301 rc = VERR_VD_NOT_OPENED;
1302
1303out:
1304 LogFlowFunc(("returns %Rrc\n", rc));
1305 return rc;
1306}
1307
1308/** @copydoc VDCACHEBACKEND::pfnGetUuid */
1309static int vciGetUuid(void *pBackendData, PRTUUID pUuid)
1310{
1311 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1312 PVCICACHE pImage = (PVCICACHE)pBackendData;
1313 int rc;
1314
1315 AssertPtr(pImage);
1316
1317 if (pImage)
1318 rc = VERR_NOT_SUPPORTED;
1319 else
1320 rc = VERR_VD_NOT_OPENED;
1321
1322 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1323 return rc;
1324}
1325
1326/** @copydoc VDCACHEBACKEND::pfnSetUuid */
1327static int vciSetUuid(void *pBackendData, PCRTUUID pUuid)
1328{
1329 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1330 PVCICACHE pImage = (PVCICACHE)pBackendData;
1331 int rc;
1332
1333 LogFlowFunc(("%RTuuid\n", pUuid));
1334 AssertPtr(pImage);
1335
1336 if (pImage)
1337 {
1338 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1339 rc = VERR_NOT_SUPPORTED;
1340 else
1341 rc = VERR_VD_IMAGE_READ_ONLY;
1342 }
1343 else
1344 rc = VERR_VD_NOT_OPENED;
1345
1346 LogFlowFunc(("returns %Rrc\n", rc));
1347 return rc;
1348}
1349
1350/** @copydoc VDCACHEBACKEND::pfnGetModificationUuid */
1351static int vciGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1352{
1353 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1354 PVCICACHE pImage = (PVCICACHE)pBackendData;
1355 int rc;
1356
1357 AssertPtr(pImage);
1358
1359 if (pImage)
1360 rc = VERR_NOT_SUPPORTED;
1361 else
1362 rc = VERR_VD_NOT_OPENED;
1363
1364 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1365 return rc;
1366}
1367
1368/** @copydoc VDCACHEBACKEND::pfnSetModificationUuid */
1369static int vciSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1370{
1371 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1372 PVCICACHE pImage = (PVCICACHE)pBackendData;
1373 int rc;
1374
1375 AssertPtr(pImage);
1376
1377 if (pImage)
1378 {
1379 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1380 rc = VERR_NOT_SUPPORTED;
1381 else
1382 rc = VERR_VD_IMAGE_READ_ONLY;
1383 }
1384 else
1385 rc = VERR_VD_NOT_OPENED;
1386
1387 LogFlowFunc(("returns %Rrc\n", rc));
1388 return rc;
1389}
1390
1391/** @copydoc VDCACHEBACKEND::pfnDump */
1392static void vciDump(void *pBackendData)
1393{
1394 NOREF(pBackendData);
1395}
1396
1397/** @copydoc VDCACHEBACKEND::pfnAsyncRead */
1398static int vciAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
1399 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
1400{
1401 int rc = VINF_SUCCESS;
1402 PVCICACHE pImage = (PVCICACHE)pBackendData;
1403
1404 rc = vciFileReadUserAsync(pImage, uOffset, pIoCtx, cbRead);
1405 if (RT_SUCCESS(rc))
1406 *pcbActuallyRead = cbRead;
1407
1408 return rc;
1409}
1410
1411/** @copydoc VDCACHEBACKEND::pfnAsyncWrite */
1412static int vciAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
1413 PVDIOCTX pIoCtx, size_t *pcbWriteProcess)
1414{
1415 int rc = VINF_SUCCESS;
1416 PVCICACHE pImage = (PVCICACHE)pBackendData;
1417
1418 rc = vciFileWriteUserAsync(pImage, uOffset, pIoCtx, cbWrite, NULL, NULL);
1419 if (RT_SUCCESS(rc))
1420 *pcbWriteProcess = cbWrite;
1421
1422 return rc;
1423}
1424
1425/** @copydoc VDCACHEBACKEND::pfnAsyncFlush */
1426static int vciAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
1427{
1428 int rc = VINF_SUCCESS;
1429 PVCICACHE pImage = (PVCICACHE)pBackendData;
1430
1431 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1432 rc = vciFileFlushAsync(pImage, pIoCtx, NULL, NULL);
1433
1434 return rc;
1435}
1436
1437
1438VDCACHEBACKEND g_VciCacheBackend =
1439{
1440 /* pszBackendName */
1441 "vci",
1442 /* cbSize */
1443 sizeof(VDCACHEBACKEND),
1444 /* uBackendCaps */
1445 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_ASYNC,
1446 /* papszFileExtensions */
1447 s_apszVciFileExtensions,
1448 /* paConfigInfo */
1449 NULL,
1450 /* hPlugin */
1451 NIL_RTLDRMOD,
1452 /* pfnProbe */
1453 vciProbe,
1454 /* pfnOpen */
1455 vciOpen,
1456 /* pfnCreate */
1457 vciCreate,
1458 /* pfnClose */
1459 vciClose,
1460 /* pfnRead */
1461 vciRead,
1462 /* pfnWrite */
1463 vciWrite,
1464 /* pfnFlush */
1465 vciFlush,
1466 /* pfnGetVersion */
1467 vciGetVersion,
1468 /* pfnGetSize */
1469 vciGetSize,
1470 /* pfnGetFileSize */
1471 vciGetFileSize,
1472 /* pfnGetImageFlags */
1473 vciGetImageFlags,
1474 /* pfnGetOpenFlags */
1475 vciGetOpenFlags,
1476 /* pfnSetOpenFlags */
1477 vciSetOpenFlags,
1478 /* pfnGetComment */
1479 vciGetComment,
1480 /* pfnSetComment */
1481 vciSetComment,
1482 /* pfnGetUuid */
1483 vciGetUuid,
1484 /* pfnSetUuid */
1485 vciSetUuid,
1486 /* pfnGetModificationUuid */
1487 vciGetModificationUuid,
1488 /* pfnSetModificationUuid */
1489 vciSetModificationUuid,
1490 /* pfnDump */
1491 vciDump,
1492 /* pfnAsyncRead */
1493 vciAsyncRead,
1494 /* pfnAsyncWrite */
1495 vciAsyncWrite,
1496 /* pfnAsyncFlush */
1497 vciAsyncFlush,
1498 /* pfnComposeLocation */
1499 NULL,
1500 /* pfnComposeName */
1501 NULL
1502};
1503
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use