VirtualBox

source: vbox/trunk/src/VBox/Storage/VCICache.cpp@ 33682

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

VD: Move the generic virtual disk framework + backends to src/VBox/Storage and rename the files to get rid of the HDD part because it supports floppy and DVD images too

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.5 KB
Line 
1/* $Id: VCICache.cpp 33567 2010-10-28 15:37:21Z 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/vd-cache-plugin.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#include <iprt/asm.h>
30
31/*******************************************************************************
32* On disk data structures *
33*******************************************************************************/
34
35/** @note All structures which are written to the disk are written in camel case
36 * and packed. */
37
38/** Block size used internally, because we cache sectors the smallest unit we
39 * have to care about is 512 bytes. */
40#define VCI_BLOCK_SIZE 512
41
42/** Convert block number/size to byte offset/size. */
43#define VCI_BLOCK2BYTE(u) ((uint64_t)(u) << 9)
44
45/** Convert byte offset/size to block number/size. */
46#define VCI_BYTE2BLOCK(u) ((u) >> 9)
47
48/**
49 * The VCI header - at the beginning of the file.
50 *
51 * All entries a stored in little endian order.
52 */
53#pragma pack(1)
54typedef struct VciHdr
55{
56 /** The signature to identify a cache image. */
57 uint32_t u32Signature;
58 /** Version of the layout of metadata in the cache. */
59 uint32_t u32Version;
60 /** Maximum size of the cache file in blocks.
61 * This includes all metadata. */
62 uint64_t cBlocksCache;
63 /** Flag indicating whether the cache was closed cleanly. */
64 uint8_t fUncleanShutdown;
65 /** Cache type. */
66 uint32_t u32CacheType;
67 /** Offset of the B+-Tree root in the image in blocks. */
68 uint64_t offTreeRoot;
69 /** Offset of the block allocation bitmap in blocks. */
70 uint64_t offBlkMap;
71 /** Size of the block allocation bitmap in blocks. */
72 uint32_t cBlkMap;
73 /** UUID of the image. */
74 RTUUID uuidImage;
75 /** Modification UUID for the cache. */
76 RTUUID uuidModification;
77 /** Reserved for future use. */
78 uint8_t abReserved[951];
79} VciHdr, *PVciHdr;
80#pragma pack()
81AssertCompileSize(VciHdr, 2 * VCI_BLOCK_SIZE);
82
83/** VCI signature to identify a valid image. */
84#define VCI_HDR_SIGNATURE UINT32_C(0x56434900) /* VCI\0 */
85/** Current version we support. */
86#define VCI_HDR_VERSION UINT32_C(0x00000001)
87
88/** Value for an unclean cache shutdown. */
89#define VCI_HDR_UNCLEAN_SHUTDOWN UINT8_C(0x01)
90/** Value for a clean cache shutdown. */
91#define VCI_HDR_CLEAN_SHUTDOWN UINT8_C(0x00)
92
93/** Cache type: Dynamic image growing to the maximum value. */
94#define VCI_HDR_CACHE_TYPE_DYNAMIC UINT32_C(0x00000001)
95/** Cache type: Fixed image, space is preallocated. */
96#define VCI_HDR_CACHE_TYPE_FIXED UINT32_C(0x00000002)
97
98/**
99 * On disk representation of an extent describing a range of cached data.
100 *
101 * All entries a stored in little endian order.
102 */
103#pragma pack(1)
104typedef struct VciCacheExtent
105{
106 /** Block address of the previous extent in the LRU list. */
107 uint64_t u64ExtentPrev;
108 /** Block address of the next extent in the LRU list. */
109 uint64_t u64ExtentNext;
110 /** Flags (for compression, encryption etc.) - currently unused and should be always 0. */
111 uint8_t u8Flags;
112 /** Reserved */
113 uint8_t u8Reserved;
114 /** First block of cached data the extent represents. */
115 uint64_t u64BlockOffset;
116 /** Number of blocks the extent represents. */
117 uint32_t u32Blocks;
118 /** First block in the image where the data is stored. */
119 uint64_t u64BlockAddr;
120} VciCacheExtent, *PVciCacheExtent;
121#pragma pack()
122AssertCompileSize(VciCacheExtent, 38);
123
124/**
125 * On disk representation of an internal node.
126 *
127 * All entries a stored in little endian order.
128 */
129#pragma pack(1)
130typedef struct VciTreeNodeInternal
131{
132 /** First block of cached data the internal node represents. */
133 uint64_t u64BlockOffset;
134 /** Number of blocks the internal node represents. */
135 uint32_t u32Blocks;
136 /** Block address in the image where the next node in the tree is stored. */
137 uint64_t u64ChildAddr;
138} VciTreeNodeInternal, *PVciTreeNodeInternal;
139#pragma pack()
140AssertCompileSize(VciTreeNodeInternal, 20);
141
142/**
143 * On-disk representation of a node in the B+-Tree.
144 *
145 * All entries a stored in little endian order.
146 */
147#pragma pack(1)
148typedef struct VciTreeNode
149{
150 /** Type of the node (root, internal, leaf). */
151 uint8_t u8Type;
152 /** Data in the node. */
153 uint8_t au8Data[4095];
154} VciTreeNode, *PVciTreeNode;
155#pragma pack()
156AssertCompileSize(VciTreeNode, 8 * VCI_BLOCK_SIZE);
157
158/** Node type: Internal node containing links to other nodes (VciTreeNodeInternal). */
159#define VCI_TREE_NODE_TYPE_INTERNAL UINT8_C(0x01)
160/** Node type: Leaf of the tree (VciCacheExtent). */
161#define VCI_TREE_NODE_TYPE_LEAF UINT8_C(0x02)
162
163/** Number of cache extents described by one node. */
164#define VCI_TREE_EXTENTS_PER_NODE ((sizeof(VciTreeNode)-1) / sizeof(VciCacheExtent))
165/** Number of internal nodes managed by one tree node. */
166#define VCI_TREE_INTERNAL_NODES_PER_NODE ((sizeof(VciTreeNode)-1) / sizeof(VciTreeNodeInternal))
167
168/**
169 * VCI block bitmap header.
170 *
171 * All entries a stored in little endian order.
172 */
173#pragma pack(1)
174typedef struct VciBlkMap
175{
176 /** Magic of the block bitmap. */
177 uint32_t u32Magic;
178 /** Version of the block bitmap. */
179 uint32_t u32Version;
180 /** Number of blocks this block map manages. */
181 uint64_t cBlocks;
182 /** Number of free blocks. */
183 uint64_t cBlocksFree;
184 /** Number of blocks allocated for metadata. */
185 uint64_t cBlocksAllocMeta;
186 /** Number of blocks allocated for actual cached data. */
187 uint64_t cBlocksAllocData;
188 /** Reserved for future use. */
189 uint8_t au8Reserved[472];
190} VciBlkMap, *PVciBlkMap;
191#pragma pack()
192AssertCompileSize(VciBlkMap, VCI_BLOCK_SIZE);
193
194/** The magic which identifies a block map. */
195#define VCI_BLKMAP_MAGIC UINT32_C(0x56424c4b) /* VBLK */
196/** Current version. */
197#define VCI_BLKMAP_VERSION UINT32_C(0x00000001)
198
199/** Block bitmap entry */
200typedef uint8_t VciBlkMapEnt;
201
202/*******************************************************************************
203* Constants And Macros, Structures and Typedefs *
204*******************************************************************************/
205
206/**
207 * Block range descriptor.
208 */
209typedef struct VCIBLKRANGEDESC
210{
211 /** Previous entry in the list. */
212 struct VCIBLKRANGEDESC *pPrev;
213 /** Next entry in the list. */
214 struct VCIBLKRANGEDESC *pNext;
215 /** Start address of the range. */
216 uint64_t offAddrStart;
217 /** Number of blocks in the range. */
218 uint64_t cBlocks;
219 /** Flag whether the range is free or allocated. */
220 bool fFree;
221} VCIBLKRANGEDESC, *PVCIBLKRANGEDESC;
222
223/**
224 * Block map for the cache image - in memory structure.
225 */
226typedef struct VCIBLKMAP
227{
228 /** Number of blocks the map manages. */
229 uint64_t cBlocks;
230 /** Number of blocks allocated for metadata. */
231 uint64_t cBlocksAllocMeta;
232 /** Number of blocks allocated for actual cached data. */
233 uint64_t cBlocksAllocData;
234 /** Number of free blocks. */
235 uint64_t cBlocksFree;
236
237 /** Pointer to the head of the block range list. */
238 PVCIBLKRANGEDESC pRangesHead;
239 /** Pointer to the tail of the block range list. */
240 PVCIBLKRANGEDESC pRangesTail;
241
242} VCIBLKMAP;
243/** Pointer to a block map. */
244typedef VCIBLKMAP *PVCIBLKMAP;
245
246/**
247 * B+-Tree node header.
248 */
249typedef struct VCITREENODE
250{
251 /** Type of the node (VCI_TREE_NODE_TYPE_*). */
252 uint8_t u8Type;
253 /** Block address where the node is stored. */
254 uint64_t u64BlockAddr;
255 /** Pointer to the parent. */
256 struct VCITREENODE *pParent;
257} VCITREENODE, *PVCITREENODE;
258
259/**
260 * B+-Tree node pointer.
261 */
262typedef struct VCITREENODEPTR
263{
264 /** Flag whether the node is in memory or still on the disk. */
265 bool fInMemory;
266 /** Type dependent data. */
267 union
268 {
269 /** Pointer to a in memory node. */
270 PVCITREENODE pNode;
271 /** Start block address of the node. */
272 uint64_t offAddrBlockNode;
273 } u;
274} VCITREENODEPTR, *PVCITREENODEPTR;
275
276/**
277 * Internal node.
278 */
279typedef struct VCINODEINTERNAL
280{
281 /** First block of cached data the internal node represents. */
282 uint64_t u64BlockOffset;
283 /** Number of blocks the internal node represents. */
284 uint32_t u32Blocks;
285 /** Pointer to the child node. */
286 VCITREENODEPTR PtrChild;
287} VCINODEINTERNAL, *PVCINODEINTERNAL;
288
289/**
290 * A in memory internal B+-tree node.
291 */
292typedef struct VCITREENODEINT
293{
294 /** Node core. */
295 VCITREENODE Core;
296 /** Number of used nodes. */
297 unsigned cUsedNodes;
298 /** Array of internal nodes. */
299 VCINODEINTERNAL aIntNodes[VCI_TREE_INTERNAL_NODES_PER_NODE];
300} VCITREENODEINT, *PVCITREENODEINT;
301
302/**
303 * A in memory cache extent.
304 */
305typedef struct VCICACHEEXTENT
306{
307 /** First block of cached data the extent represents. */
308 uint64_t u64BlockOffset;
309 /** Number of blocks the extent represents. */
310 uint32_t u32Blocks;
311 /** First block in the image where the data is stored. */
312 uint64_t u64BlockAddr;
313} VCICACHEEXTENT, *PVCICACHEEXTENT;
314
315/**
316 * A in memory leaf B+-tree node.
317 */
318typedef struct VCITREENODELEAF
319{
320 /** Node core. */
321 VCITREENODE Core;
322 /** Number of used nodes. */
323 unsigned cUsedNodes;
324 /** The extents in the node. */
325 VCICACHEEXTENT aExtents[VCI_TREE_EXTENTS_PER_NODE];
326} VCITREENODELEAF, *PVCITREENODELEAF;
327
328/**
329 * VCI image data structure.
330 */
331typedef struct VCICACHE
332{
333 /** Image name. */
334 const char *pszFilename;
335 /** Storage handle. */
336 PVDIOSTORAGE pStorage;
337 /** I/O interface. */
338 PVDINTERFACE pInterfaceIO;
339 /** Async I/O interface callbacks. */
340 PVDINTERFACEIOINT pInterfaceIOCallbacks;
341
342 /** Pointer to the per-disk VD interface list. */
343 PVDINTERFACE pVDIfsDisk;
344 /** Pointer to the per-image VD interface list. */
345 PVDINTERFACE pVDIfsImage;
346
347 /** Error callback. */
348 PVDINTERFACE pInterfaceError;
349 /** Opaque data for error callback. */
350 PVDINTERFACEERROR pInterfaceErrorCallbacks;
351
352 /** Open flags passed by VBoxHD layer. */
353 unsigned uOpenFlags;
354 /** Image flags defined during creation or determined during open. */
355 unsigned uImageFlags;
356 /** Total size of the image. */
357 uint64_t cbSize;
358
359 /** Offset of the B+-Tree in the image in bytes. */
360 uint64_t offTreeRoot;
361 /** Pointer to the root node of the B+-Tree. */
362 PVCITREENODE pRoot;
363 /** Offset to the block allocation bitmap in bytes. */
364 uint64_t offBlksBitmap;
365 /** Block map. */
366 PVCIBLKMAP pBlkMap;
367} VCICACHE, *PVCICACHE;
368
369/** No block free in bitmap error code. */
370#define VERR_VCI_NO_BLOCKS_FREE (-65536)
371
372/*******************************************************************************
373* Static Variables *
374*******************************************************************************/
375
376/** NULL-terminated array of supported file extensions. */
377static const char *const s_apszVciFileExtensions[] =
378{
379 "vci",
380 NULL
381};
382
383/*******************************************************************************
384* Internal Functions *
385*******************************************************************************/
386
387/**
388 * Internal: signal an error to the frontend.
389 */
390DECLINLINE(int) vciError(PVCICACHE pCache, int rc, RT_SRC_POS_DECL,
391 const char *pszFormat, ...)
392{
393 va_list va;
394 va_start(va, pszFormat);
395 if (pCache->pInterfaceError)
396 pCache->pInterfaceErrorCallbacks->pfnError(pCache->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
397 pszFormat, va);
398 va_end(va);
399 return rc;
400}
401
402/**
403 * Internal: signal an informational message to the frontend.
404 */
405DECLINLINE(int) vciMessage(PVCICACHE pCache, const char *pszFormat, ...)
406{
407 int rc = VINF_SUCCESS;
408 va_list va;
409 va_start(va, pszFormat);
410 if (pCache->pInterfaceError)
411 rc = pCache->pInterfaceErrorCallbacks->pfnMessage(pCache->pInterfaceError->pvUser,
412 pszFormat, va);
413 va_end(va);
414 return rc;
415}
416
417
418DECLINLINE(int) vciFileOpen(PVCICACHE pCache, const char *pszFilename,
419 uint32_t fOpen)
420{
421 return pCache->pInterfaceIOCallbacks->pfnOpen(pCache->pInterfaceIO->pvUser,
422 pszFilename, fOpen,
423 &pCache->pStorage);
424}
425
426DECLINLINE(int) vciFileClose(PVCICACHE pCache)
427{
428 return pCache->pInterfaceIOCallbacks->pfnClose(pCache->pInterfaceIO->pvUser,
429 pCache->pStorage);
430}
431
432DECLINLINE(int) vciFileDelete(PVCICACHE pCache, const char *pszFilename)
433{
434 return pCache->pInterfaceIOCallbacks->pfnDelete(pCache->pInterfaceIO->pvUser,
435 pszFilename);
436}
437
438DECLINLINE(int) vciFileMove(PVCICACHE pCache, const char *pszSrc,
439 const char *pszDst, unsigned fMove)
440{
441 return pCache->pInterfaceIOCallbacks->pfnMove(pCache->pInterfaceIO->pvUser,
442 pszSrc, pszDst, fMove);
443}
444
445DECLINLINE(int) vciFileGetFreeSpace(PVCICACHE pCache, const char *pszFilename,
446 int64_t *pcbFree)
447{
448 return pCache->pInterfaceIOCallbacks->pfnGetFreeSpace(pCache->pInterfaceIO->pvUser,
449 pszFilename, pcbFree);
450}
451
452DECLINLINE(int) vciFileGetSize(PVCICACHE pCache, uint64_t *pcbSize)
453{
454 return pCache->pInterfaceIOCallbacks->pfnGetSize(pCache->pInterfaceIO->pvUser,
455 pCache->pStorage, pcbSize);
456}
457
458DECLINLINE(int) vciFileSetSize(PVCICACHE pCache, uint64_t cbSize)
459{
460 return pCache->pInterfaceIOCallbacks->pfnSetSize(pCache->pInterfaceIO->pvUser,
461 pCache->pStorage, cbSize);
462}
463
464DECLINLINE(int) vciFileWriteSync(PVCICACHE pCache, uint64_t uOffset,
465 const void *pvBuffer, size_t cbBuffer)
466{
467 return pCache->pInterfaceIOCallbacks->pfnWriteSync(pCache->pInterfaceIO->pvUser,
468 pCache->pStorage, uOffset,
469 pvBuffer, cbBuffer, NULL);
470}
471
472DECLINLINE(int) vciFileReadSync(PVCICACHE pCache, uint64_t uOffset,
473 void *pvBuffer, size_t cbBuffer)
474{
475 return pCache->pInterfaceIOCallbacks->pfnReadSync(pCache->pInterfaceIO->pvUser,
476 pCache->pStorage, uOffset,
477 pvBuffer, cbBuffer, NULL);
478}
479
480DECLINLINE(int) vciFileFlushSync(PVCICACHE pCache)
481{
482 return pCache->pInterfaceIOCallbacks->pfnFlushSync(pCache->pInterfaceIO->pvUser,
483 pCache->pStorage);
484}
485
486DECLINLINE(int) vciFileReadUserAsync(PVCICACHE pCache, uint64_t uOffset,
487 PVDIOCTX pIoCtx, size_t cbRead)
488{
489 return pCache->pInterfaceIOCallbacks->pfnReadUserAsync(pCache->pInterfaceIO->pvUser,
490 pCache->pStorage,
491 uOffset, pIoCtx,
492 cbRead);
493}
494
495DECLINLINE(int) vciFileWriteUserAsync(PVCICACHE pCache, uint64_t uOffset,
496 PVDIOCTX pIoCtx, size_t cbWrite,
497 PFNVDXFERCOMPLETED pfnComplete,
498 void *pvCompleteUser)
499{
500 return pCache->pInterfaceIOCallbacks->pfnWriteUserAsync(pCache->pInterfaceIO->pvUser,
501 pCache->pStorage,
502 uOffset, pIoCtx,
503 cbWrite,
504 pfnComplete,
505 pvCompleteUser);
506}
507
508DECLINLINE(int) vciFileFlushAsync(PVCICACHE pCache, PVDIOCTX pIoCtx,
509 PFNVDXFERCOMPLETED pfnComplete,
510 void *pvCompleteUser)
511{
512 return pCache->pInterfaceIOCallbacks->pfnFlushAsync(pCache->pInterfaceIO->pvUser,
513 pCache->pStorage,
514 pIoCtx, pfnComplete,
515 pvCompleteUser);
516}
517
518/**
519 * Internal. Flush image data to disk.
520 */
521static int vciFlushImage(PVCICACHE pCache)
522{
523 int rc = VINF_SUCCESS;
524
525 if ( pCache->pStorage
526 && !(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
527 rc = vciFileFlushSync(pCache);
528
529 return rc;
530}
531
532/**
533 * Internal. Free all allocated space for representing an image except pCache,
534 * and optionally delete the image from disk.
535 */
536static int vciFreeImage(PVCICACHE pCache, bool fDelete)
537{
538 int rc = VINF_SUCCESS;
539
540 /* Freeing a never allocated image (e.g. because the open failed) is
541 * not signalled as an error. After all nothing bad happens. */
542 if (pCache)
543 {
544 if (pCache->pStorage)
545 {
546 /* No point updating the file that is deleted anyway. */
547 if (!fDelete)
548 vciFlushImage(pCache);
549
550 vciFileClose(pCache);
551 pCache->pStorage = NULL;
552 }
553
554 if (fDelete && pCache->pszFilename)
555 vciFileDelete(pCache, pCache->pszFilename);
556 }
557
558 LogFlowFunc(("returns %Rrc\n", rc));
559 return rc;
560}
561
562/**
563 * Creates a new block map which can manage the given number of blocks.
564 *
565 * The size of the bitmap is aligned to the VCI block size.
566 *
567 * @returns VBox status code.
568 * @param cBlocks The number of blocks the bitmap can manage.
569 * @param ppBlkMap Where to store the pointer to the block bitmap.
570 * @param pcbBlkMap Where to store the size of the block bitmap in blocks
571 * needed on the disk.
572 */
573static int vciBlkMapCreate(uint64_t cBlocks, PVCIBLKMAP *ppBlkMap, uint32_t *pcBlkMap)
574{
575 int rc = VINF_SUCCESS;
576 uint32_t cbBlkMap = RT_ALIGN_Z(cBlocks / sizeof(VciBlkMapEnt) / 8, VCI_BLOCK_SIZE);
577 PVCIBLKMAP pBlkMap = (PVCIBLKMAP)RTMemAllocZ(sizeof(VCIBLKMAP));
578 PVCIBLKRANGEDESC pFree = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
579
580 LogFlowFunc(("cBlocks=%u ppBlkMap=%#p pcBlkMap=%#p\n", cBlocks, ppBlkMap, pcBlkMap));
581
582 if (pBlkMap && pFree)
583 {
584 pBlkMap->cBlocks = cBlocks;
585 pBlkMap->cBlocksAllocMeta = 0;
586 pBlkMap->cBlocksAllocData = 0;
587 pBlkMap->cBlocksFree = cBlocks;
588
589 pFree->pPrev = NULL;
590 pFree->pNext = NULL;
591 pFree->offAddrStart = 0;
592 pFree->cBlocks = cBlocks;
593 pFree->fFree = true;
594
595 pBlkMap->pRangesHead = pFree;
596 pBlkMap->pRangesTail = pFree;
597
598 Assert(!((cbBlkMap + sizeof(VciBlkMap) % VCI_BLOCK_SIZE)));
599 *ppBlkMap = pBlkMap;
600 *pcBlkMap = (cbBlkMap + sizeof(VciBlkMap)) / VCI_BLOCK_SIZE;
601 }
602 else
603 {
604 if (pBlkMap)
605 RTMemFree(pBlkMap);
606 if (pFree)
607 RTMemFree(pFree);
608
609 rc = VERR_NO_MEMORY;
610 }
611
612 LogFlowFunc(("returns rc=%Rrc cBlkMap=%u\n", rc, *pcBlkMap));
613 return rc;
614}
615
616/**
617 * Frees a block map.
618 *
619 * @returns nothing.
620 * @param pBlkMap The block bitmap to destroy.
621 */
622static void vciBlkMapDestroy(PVCIBLKMAP pBlkMap)
623{
624 LogFlowFunc(("pBlkMap=%#p\n", pBlkMap));
625
626 PVCIBLKRANGEDESC pRangeCur = pBlkMap->pRangesHead;
627
628 while (pRangeCur)
629 {
630 PVCIBLKRANGEDESC pTmp = pRangeCur;
631
632 RTMemFree(pTmp);
633
634 pRangeCur = pRangeCur->pNext;
635 }
636
637 RTMemFree(pBlkMap);
638
639 LogFlowFunc(("returns\n"));
640}
641
642/**
643 * Loads the block map from the specified medium and creates all necessary
644 * in memory structures to manage used and free blocks.
645 *
646 * @returns VBox status code.
647 * @param pStorage Storage handle to read the block bitmap from.
648 * @param offBlkMap Start of the block bitmap in blocks.
649 * @param cBlkMap Size of the block bitmap on the disk in blocks.
650 * @param ppBlkMap Where to store the block bitmap on success.
651 */
652static int vciBlkMapLoad(PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap, PVCIBLKMAP *ppBlkMap)
653{
654 int rc = VINF_SUCCESS;
655 VciBlkMap BlkMap;
656
657 LogFlowFunc(("pStorage=%#p offBlkMap=%llu cBlkMap=%u ppBlkMap=%#p\n",
658 pStorage, offBlkMap, cBlkMap, ppBlkMap));
659
660 if (cBlkMap >= VCI_BYTE2BLOCK(sizeof(VciBlkMap)))
661 {
662 cBlkMap -= VCI_BYTE2BLOCK(sizeof(VciBlkMap));
663
664 rc = vciFileReadSync(pStorage, VCI_BLOCK2BYTE(offBlkMap), &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
665 if (RT_SUCCESS(rc))
666 {
667 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
668
669 BlkMap.u32Magic = RT_LE2H_U32(BlkMap.u32Magic);
670 BlkMap.u32Version = RT_LE2H_U32(BlkMap.u32Version);
671 BlkMap.cBlocks = RT_LE2H_U32(BlkMap.cBlocks);
672 BlkMap.cBlocksFree = RT_LE2H_U32(BlkMap.cBlocksFree);
673 BlkMap.cBlocksAllocMeta = RT_LE2H_U32(BlkMap.cBlocksAllocMeta);
674 BlkMap.cBlocksAllocData = RT_LE2H_U32(BlkMap.cBlocksAllocData);
675
676 if ( BlkMap.u32Magic == VCI_BLKMAP_MAGIC
677 && BlkMap.u32Version == VCI_BLKMAP_VERSION
678 && BlkMap.cBlocks == BlkMap.cBlocksFree + BlkMap.cBlocksAllocMeta + BlkMap.cBlocksAllocData
679 && BlkMap.cBlocks / 8 == cBlkMap)
680 {
681 PVCIBLKMAP pBlkMap = (PVCIBLKMAP)RTMemAllocZ(sizeof(VCIBLKMAP));
682 if (pBlkMap)
683 {
684 pBlkMap->cBlocks = BlkMap.cBlocks;
685 pBlkMap->cBlocksFree = BlkMap.cBlocksFree;
686 pBlkMap->cBlocksAllocMeta = BlkMap.cBlocksAllocMeta;
687 pBlkMap->cBlocksAllocData = BlkMap.cBlocksAllocData;
688
689 /* Load the bitmap and construct the range list. */
690 uint32_t cBlocksFree = 0;
691 uint32_t cBlocksAllocated = 0;
692 PVCIBLKRANGEDESC pRangeCur = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
693
694 if (pRangeCur)
695 {
696 uint8_t abBitmapBuffer[16 * _1K];
697 uint32_t cBlocksRead = 0;
698 int iBit = 0;
699 uint64_t cBlocksLeft = pBlkMap->cBlocks;
700
701 cBlocksRead = RT_MIN(VCI_BYTE2BLOCK(sizeof(abBitmapBuffer)), cBlocksLeft);
702 rc = vciFileReadSync(pStorage, VCI_BLOCK2BYTE(offBlkMap), abBitmapBuffer,
703 VCI_BLOCK2BYTE(cBlocksRead));
704
705 if (RT_SUCCESS(rc))
706 {
707 pRangeCur->fFree = !(abBitmapBuffer[0] & 0x01);
708 pRangeCur->offAddrStart = 0;
709 pRangeCur->cBlocks = 0;
710 pRangeCur->pNext = NULL;
711 pRangeCur->pPrev = NULL;
712 pBlkMap->pRangesHead = pRangeCur;
713 pBlkMap->pRangesTail = pRangeCur;
714 }
715
716 while ( RT_SUCCESS(rc)
717 && cBlocksLeft)
718 {
719#if 0
720 while (cBlocksRead)
721 {
722 if (pRangeCur->fFree)
723 {
724 /* Check for the first set bit. */
725 }
726 else
727 {
728 /* Check for the first free bit. */
729 }
730
731 if (iBit == -1)
732 {
733 /* No change. */
734 pRangeCur->cBlocks += cBlocksRead;
735 cBlocksRead = 0;
736 }
737 else
738 {
739 /* Create a new range descriptor. */
740 }
741 }
742#endif
743 cBlocksLeft -= cBlocksRead;
744 offBlkMap += cBlocksRead;
745
746 if (cBlocksLeft)
747 {
748 /* Read next chunk. */
749 }
750 }
751 }
752 else
753 rc = VERR_NO_MEMORY;
754
755 if (RT_SUCCESS(rc))
756 {
757 *ppBlkMap = pBlkMap;
758 LogFlowFunc(("return success\n"));
759 return VINF_SUCCESS;
760 }
761 else
762 RTMemFree(pBlkMap);
763 }
764 else
765 rc = VERR_NO_MEMORY;
766 }
767 else
768 rc = VERR_VD_GEN_INVALID_HEADER;
769 }
770 else if (RT_SUCCESS(rc))
771 rc = VERR_VD_GEN_INVALID_HEADER;
772 }
773 else
774 rc = VERR_VD_GEN_INVALID_HEADER;
775
776 LogFlowFunc(("returns rc=%Rrc\n", rc));
777 return rc;
778}
779
780/**
781 * Saves the block map in the cache image. All necessary on disk structures
782 * are written.
783 *
784 * @returns VBox status code.
785 * @param pBlkMap The block bitmap to save.
786 * @param pStorage Where the block bitmap should be written to.
787 * @param offBlkMap Start of the block bitmap in blocks.
788 * @param cBlkMap Size of the block bitmap on the disk in blocks.
789 */
790static int vciBlkMapSave(PVCIBLKMAP pBlkMap, PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap)
791{
792 int rc = VINF_SUCCESS;
793 VciBlkMap BlkMap;
794
795 LogFlowFunc(("pBlkMap=%#p pStorage=%#p offBlkMap=%llu cBlkMap=%u\n",
796 pBlkMap, pStorage, offBlkMap, cBlkMap));
797
798 /* Make sure the number of blocks allocated for us match our expectations. */
799 if ((pBlkMap->cBlocks / 8) + VCI_BYTE2BLOCK(sizeof(VciBlkMap)) == cBlkMap)
800 {
801 /* Setup the header */
802 memset(&BlkMap, 0, sizeof(VciBlkMap));
803
804 BlkMap.u32Magic = RT_H2LE_U32(VCI_BLKMAP_MAGIC);
805 BlkMap.u32Version = RT_H2LE_U32(VCI_BLKMAP_VERSION);
806 BlkMap.cBlocks = RT_H2LE_U32(pBlkMap->cBlocks);
807 BlkMap.cBlocksFree = RT_H2LE_U32(pBlkMap->cBlocksFree);
808 BlkMap.cBlocksAllocMeta = RT_H2LE_U32(pBlkMap->cBlocksAllocMeta);
809 BlkMap.cBlocksAllocData = RT_H2LE_U32(pBlkMap->cBlocksAllocData);
810
811 rc = vciFileWriteSync(pStorage, VCI_BLOCK2BYTE(offBlkMap), &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
812 if (RT_SUCCESS(rc))
813 {
814 uint8_t abBitmapBuffer[16*_1K];
815 unsigned iBit = 0;
816 PVCIBLKRANGEDESC pCur = pBlkMap->pRangesHead;
817
818 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
819
820 /* Write the descriptor ranges. */
821 while (pCur)
822 {
823 uint64_t cBlocks = pCur->cBlocks;
824
825 while (cBlocks)
826 {
827 uint64_t cBlocksMax = RT_MIN(cBlocks, sizeof(abBitmapBuffer) * 8 - iBit);
828
829 if (pCur->fFree)
830 ASMBitClearRange(abBitmapBuffer, iBit, iBit + cBlocksMax);
831 else
832 ASMBitSetRange(abBitmapBuffer, iBit, iBit + cBlocksMax);
833
834 iBit += cBlocksMax;
835 cBlocks -= cBlocksMax;
836
837 if (iBit == sizeof(abBitmapBuffer) * 8)
838 {
839 /* Buffer is full, write to file and reset. */
840 rc = vciFileWriteSync(pStorage, offBlkMap, abBitmapBuffer, sizeof(abBitmapBuffer));
841 if (RT_FAILURE(rc))
842 break;
843
844 offBlkMap += VCI_BYTE2BLOCK(sizeof(abBitmapBuffer));
845 iBit = 0;
846 }
847 }
848
849 pCur = pCur->pNext;
850 }
851
852 Assert(iBit % 8 == 0);
853
854 if (RT_SUCCESS(rc) && iBit)
855 rc = vciFileWriteSync(pStorage, offBlkMap, abBitmapBuffer, iBit / 8);
856 }
857 }
858 else
859 rc = VERR_INTERNAL_ERROR; /* @todo Better error code. */
860
861 LogFlowFunc(("returns rc=%Rrc\n", rc));
862 return rc;
863}
864
865/**
866 * Finds the range block describing the given block address.
867 *
868 * @returns Pointer to the block range descriptor or NULL if none could be found.
869 * @param pBlkMap The block bitmap to search on.
870 * @param offBlockAddr The block address to search for.
871 */
872static PVCIBLKRANGEDESC vciBlkMapFindByBlock(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr)
873{
874 PVCIBLKRANGEDESC pBlk = pBlkMap->pRangesHead;
875
876 while ( pBlk
877 && pBlk->offAddrStart < offBlockAddr)
878 pBlk = pBlk->pNext;
879
880 return pBlk;
881}
882
883/**
884 * Allocates the given number of blocks in the bitmap and returns the start block address.
885 *
886 * @returns VBox status code.
887 * @param pBlkMap The block bitmap to allocate the blocks from.
888 * @param cBlocks How many blocks to allocate.
889 * @param poffBlockAddr Where to store the start address of the allocated region.
890 */
891static int vciBlkMapAllocate(PVCIBLKMAP pBlkMap, uint32_t cBlocks, uint64_t *poffBlockAddr)
892{
893 PVCIBLKRANGEDESC pBestFit = NULL;
894 PVCIBLKRANGEDESC pCur = NULL;
895 int rc = VINF_SUCCESS;
896
897 LogFlowFunc(("pBlkMap=%#p cBlocks=%u poffBlockAddr=%#p\n",
898 pBlkMap, cBlocks, poffBlockAddr));
899
900 pCur = pBlkMap->pRangesHead;
901
902 while (pCur)
903 {
904 if ( pCur->fFree
905 && pCur->cBlocks >= cBlocks)
906 {
907 if ( !pBestFit
908 || pCur->cBlocks < pBestFit->cBlocks)
909 {
910 pBestFit = pCur;
911 /* Stop searching if the size is matching exactly. */
912 if (pBestFit->cBlocks == cBlocks)
913 break;
914 }
915 }
916 pCur = pCur->pNext;
917 }
918
919 Assert(!pBestFit || pBestFit->fFree);
920
921 if (pBestFit)
922 {
923 pBestFit->fFree = false;
924
925 if (pBestFit->cBlocks > cBlocks)
926 {
927 /* Create a new free block. */
928 PVCIBLKRANGEDESC pFree = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
929
930 if (pFree)
931 {
932 pFree->fFree = true;
933 pFree->cBlocks = pBestFit->cBlocks - cBlocks;
934 pFree->offAddrStart = pBestFit->offAddrStart + cBlocks;
935
936 /* Link into the list. */
937 pFree->pNext = pBestFit->pNext;
938 pBestFit->pNext = pFree;
939 pFree->pPrev = pBestFit;
940 if (!pFree->pNext)
941 pBlkMap->pRangesTail = pFree;
942
943 *poffBlockAddr = pBestFit->offAddrStart;
944 }
945 else
946 {
947 rc = VERR_NO_MEMORY;
948 pBestFit->fFree = true;
949 }
950 }
951 }
952 else
953 rc = VERR_VCI_NO_BLOCKS_FREE;
954
955 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
956 return rc;
957}
958
959/**
960 * Try to extend the space of an already allocated block.
961 *
962 * @returns VBox status code.
963 * @param pBlkMap The block bitmap to allocate the blocks from.
964 * @param cBlocksNew How many blocks the extended block should have.
965 * @param offBlockAddrOld The start address of the block to reallocate.
966 * @param poffBlockAddr Where to store the start address of the allocated region.
967 */
968static int vciBlkMapRealloc(PVCIBLKMAP pBlkMap, uint32_t cBlocksNew, uint64_t offBlockAddrOld,
969 uint64_t *poffBlockAddr)
970{
971 int rc = VINF_SUCCESS;
972
973 LogFlowFunc(("pBlkMap=%#p cBlocksNew=%u offBlockAddrOld=%llu poffBlockAddr=%#p\n",
974 pBlkMap, cBlocksNew, offBlockAddrOld, poffBlockAddr));
975
976 AssertMsgFailed(("Implement\n"));
977
978 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
979 return rc;
980}
981
982/**
983 * Frees a range of blocks.
984 *
985 * @returns nothing.
986 * @param pBlkMap The block bitmap.
987 * @param offBlockAddr Address of the first block to free.
988 * @param cBlocks How many blocks to free.
989 */
990static void vciBlkMapFree(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr, uint32_t cBlocks)
991{
992 PVCIBLKRANGEDESC pBlk;
993
994 LogFlowFunc(("pBlkMap=%#p offBlockAddr=%llu cBlocks=%u\n",
995 pBlkMap, offBlockAddr, cBlocks));
996
997 while (cBlocks)
998 {
999 pBlk = vciBlkMapFindByBlock(pBlkMap, offBlockAddr);
1000 AssertPtr(pBlk);
1001
1002 /* Easy case, the whole block is freed. */
1003 if ( pBlk->offAddrStart == offBlockAddr
1004 && pBlk->cBlocks <= cBlocks)
1005 {
1006 pBlk->fFree = true;
1007 cBlocks -= pBlk->cBlocks;
1008 offBlockAddr += pBlk->cBlocks;
1009
1010 /* Check if it is possible to merge free blocks. */
1011 if ( pBlk->pPrev
1012 && pBlk->pPrev->fFree)
1013 {
1014 PVCIBLKRANGEDESC pBlkPrev = pBlk->pPrev;
1015
1016 Assert(pBlkPrev->offAddrStart + pBlkPrev->cBlocks == pBlk->offAddrStart);
1017 pBlkPrev->cBlocks += pBlk->cBlocks;
1018 pBlkPrev->pNext = pBlk->pNext;
1019 if (pBlk->pNext)
1020 pBlk->pNext->pPrev = pBlkPrev;
1021 else
1022 pBlkMap->pRangesTail = pBlkPrev;
1023
1024 RTMemFree(pBlk);
1025 pBlk = pBlkPrev;
1026 }
1027
1028 /* Now the one to the right. */
1029 if ( pBlk->pNext
1030 && pBlk->pNext->fFree)
1031 {
1032 PVCIBLKRANGEDESC pBlkNext = pBlk->pNext;
1033
1034 Assert(pBlk->offAddrStart + pBlk->cBlocks == pBlkNext->offAddrStart);
1035 pBlk->cBlocks += pBlkNext->cBlocks;
1036 pBlk->pNext = pBlkNext->pNext;
1037 if (pBlkNext->pNext)
1038 pBlkNext->pNext->pPrev = pBlk;
1039 else
1040 pBlkMap->pRangesTail = pBlk;
1041
1042 RTMemFree(pBlkNext);
1043 }
1044 }
1045 else
1046 {
1047 /* The block is intersecting. */
1048 AssertMsgFailed(("TODO\n"));
1049 }
1050 }
1051
1052 LogFlowFunc(("returns\n"));
1053}
1054
1055/**
1056 * Converts a tree node from the image to the in memory structure.
1057 *
1058 * @returns Pointer to the in memory tree node.
1059 * @param offBlockAddrNode Block address of the node.
1060 * @param pNodeImage Pointer to the image representation of the node.
1061 */
1062static PVCITREENODE vciTreeNodeImage2Host(uint64_t offBlockAddrNode, PVciTreeNode pNodeImage)
1063{
1064 PVCITREENODE pNode = NULL;
1065
1066 if (pNodeImage->u8Type == VCI_TREE_NODE_TYPE_LEAF)
1067 {
1068 PVCITREENODELEAF pLeaf = (PVCITREENODELEAF)RTMemAllocZ(sizeof(VCITREENODELEAF));
1069
1070 if (pLeaf)
1071 {
1072 PVciCacheExtent pExtent = (PVciCacheExtent)&pNodeImage->au8Data[0];
1073
1074 pLeaf->Core.u8Type = VCI_TREE_NODE_TYPE_LEAF;
1075
1076 for (unsigned idx = 0; idx < RT_ELEMENTS(pLeaf->aExtents); idx++)
1077 {
1078 pLeaf->aExtents[idx].u64BlockOffset = RT_LE2H_U64(pExtent->u64BlockOffset);
1079 pLeaf->aExtents[idx].u32Blocks = RT_LE2H_U32(pExtent->u32Blocks);
1080 pLeaf->aExtents[idx].u64BlockAddr = RT_LE2H_U64(pExtent->u64BlockAddr);
1081 pExtent++;
1082
1083 if ( pLeaf->aExtents[idx].u32Blocks
1084 && pLeaf->aExtents[idx].u64BlockAddr)
1085 pLeaf->cUsedNodes++;
1086 }
1087
1088 pNode = &pLeaf->Core;
1089 }
1090 }
1091 else if (pNodeImage->u8Type == VCI_TREE_NODE_TYPE_INTERNAL)
1092 {
1093 PVCITREENODEINT pInt = (PVCITREENODEINT)RTMemAllocZ(sizeof(VCITREENODEINT));
1094
1095 if (pInt)
1096 {
1097 PVciTreeNodeInternal pIntImage = (PVciTreeNodeInternal)&pNodeImage->au8Data[0];
1098
1099 pInt->Core.u8Type = VCI_TREE_NODE_TYPE_INTERNAL;
1100
1101 for (unsigned idx = 0; idx < RT_ELEMENTS(pInt->aIntNodes); idx++)
1102 {
1103 pInt->aIntNodes[idx].u64BlockOffset = RT_LE2H_U64(pIntImage->u64BlockOffset);
1104 pInt->aIntNodes[idx].u32Blocks = RT_LE2H_U32(pIntImage->u32Blocks);
1105 pInt->aIntNodes[idx].PtrChild.fInMemory = false;
1106 pInt->aIntNodes[idx].PtrChild.u.offAddrBlockNode = RT_LE2H_U64(pIntImage->u64ChildAddr);
1107 pIntImage++;
1108
1109 if ( pInt->aIntNodes[idx].u32Blocks
1110 && pInt->aIntNodes[idx].PtrChild.u.offAddrBlockNode)
1111 pInt->cUsedNodes++;
1112 }
1113
1114 pNode = &pInt->Core;
1115 }
1116 }
1117 else
1118 AssertMsgFailed(("Invalid node type %d\n", pNodeImage->u8Type));
1119
1120 if (pNode)
1121 pNode->u64BlockAddr = offBlockAddrNode;
1122
1123 return pNode;
1124}
1125
1126/**
1127 * Looks up the cache extent for the given virtual block address.
1128 *
1129 * @returns Pointer to the cache extent or NULL if none could be found.
1130 * @param pCache The cache image instance.
1131 * @param offBlockOffset The block offset to search for.
1132 */
1133static PVCICACHEEXTENT vciCacheExtentLookup(PVCICACHE pCache, uint64_t offBlockOffset)
1134{
1135 int rc = VINF_SUCCESS;
1136 PVCICACHEEXTENT pExtent = NULL;
1137 PVCITREENODE pNodeCur = pCache->pRoot;
1138
1139 while ( RT_SUCCESS(rc)
1140 && pNodeCur
1141 && pNodeCur->u8Type != VCI_TREE_NODE_TYPE_LEAF)
1142 {
1143 PVCITREENODEINT pNodeInt = (PVCITREENODEINT)pNodeCur;
1144
1145 Assert(pNodeCur->u8Type == VCI_TREE_NODE_TYPE_INTERNAL);
1146
1147 /* Search for the correct internal node. */
1148 unsigned idxMin = 0;
1149 unsigned idxMax = pNodeInt->cUsedNodes;
1150 unsigned idxCur = pNodeInt->cUsedNodes / 2;
1151
1152 while (idxMin < idxMax)
1153 {
1154 PVCINODEINTERNAL pInt = &pNodeInt->aIntNodes[idxCur];
1155
1156 /* Determine the search direction. */
1157 if (offBlockOffset < pInt->u64BlockOffset)
1158 {
1159 /* Search left from the current extent. */
1160 idxMax = idxCur;
1161 }
1162 else if (offBlockOffset >= pInt->u64BlockOffset + pInt->u32Blocks)
1163 {
1164 /* Search right from the current extent. */
1165 idxMin = idxCur;
1166 }
1167 else
1168 {
1169 /* The block lies in the node, stop searching. */
1170 if (pInt->PtrChild.fInMemory)
1171 pNodeCur = pInt->PtrChild.u.pNode;
1172 else
1173 {
1174 PVCITREENODE pNodeNew;
1175 VciTreeNode NodeTree;
1176
1177 /* Read from disk and add to the tree. */
1178 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pInt->PtrChild.u.offAddrBlockNode),
1179 &NodeTree, sizeof(NodeTree));
1180 AssertRC(rc);
1181
1182 pNodeNew = vciTreeNodeImage2Host(pInt->PtrChild.u.offAddrBlockNode, &NodeTree);
1183 if (pNodeNew)
1184 {
1185 /* Link to the parent. */
1186 pInt->PtrChild.fInMemory = true;
1187 pInt->PtrChild.u.pNode = pNodeNew;
1188 pNodeNew->pParent = pNodeCur;
1189 pNodeCur = pNodeNew;
1190 }
1191 else
1192 rc = VERR_NO_MEMORY;
1193 }
1194 break;
1195 }
1196
1197 idxCur = idxMin + (idxMax - idxMin) / 2;
1198 }
1199 }
1200
1201 if ( RT_SUCCESS(rc)
1202 && pNodeCur)
1203 {
1204 PVCITREENODELEAF pLeaf = (PVCITREENODELEAF)pNodeCur;
1205 Assert(pNodeCur->u8Type == VCI_TREE_NODE_TYPE_LEAF);
1206
1207 /* Search the range. */
1208 unsigned idxMin = 0;
1209 unsigned idxMax = pLeaf->cUsedNodes;
1210 unsigned idxCur = pLeaf->cUsedNodes / 2;
1211
1212 while (idxMin < idxMax)
1213 {
1214 PVCICACHEEXTENT pExtentCur = &pLeaf->aExtents[idxCur];
1215
1216 /* Determine the search direction. */
1217 if (offBlockOffset < pExtentCur->u64BlockOffset)
1218 {
1219 /* Search left from the current extent. */
1220 idxMax = idxCur;
1221 }
1222 else if (offBlockOffset >= pExtentCur->u64BlockOffset + pExtentCur->u32Blocks)
1223 {
1224 /* Search right from the current extent. */
1225 idxMin = idxCur;
1226 }
1227 else
1228 {
1229 /* We found the extent, stop searching. */
1230 pExtent = pExtentCur;
1231 break;
1232 }
1233
1234 idxCur = idxMin + (idxMax - idxMin) / 2;
1235 }
1236 }
1237
1238 return pExtent;
1239}
1240
1241/**
1242 * Internal: Open an image, constructing all necessary data structures.
1243 */
1244static int vciOpenImage(PVCICACHE pCache, unsigned uOpenFlags)
1245{
1246 VciHdr Hdr;
1247 uint64_t cbFile;
1248 int rc;
1249
1250 pCache->uOpenFlags = uOpenFlags;
1251
1252 pCache->pInterfaceError = VDInterfaceGet(pCache->pVDIfsDisk, VDINTERFACETYPE_ERROR);
1253 if (pCache->pInterfaceError)
1254 pCache->pInterfaceErrorCallbacks = VDGetInterfaceError(pCache->pInterfaceError);
1255
1256 /* Get I/O interface. */
1257 pCache->pInterfaceIO = VDInterfaceGet(pCache->pVDIfsImage, VDINTERFACETYPE_IOINT);
1258 AssertPtrReturn(pCache->pInterfaceIO, VERR_INVALID_PARAMETER);
1259 pCache->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pCache->pInterfaceIO);
1260 AssertPtrReturn(pCache->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1261
1262 /*
1263 * Open the image.
1264 */
1265 rc = vciFileOpen(pCache, pCache->pszFilename,
1266 VDOpenFlagsToFileOpenFlags(uOpenFlags,
1267 false /* fCreate */));
1268 if (RT_FAILURE(rc))
1269 {
1270 /* Do NOT signal an appropriate error here, as the VD layer has the
1271 * choice of retrying the open if it failed. */
1272 goto out;
1273 }
1274
1275 rc = vciFileGetSize(pCache, &cbFile);
1276 if (RT_FAILURE(rc) || cbFile < sizeof(VciHdr))
1277 {
1278 rc = VERR_VD_GEN_INVALID_HEADER;
1279 goto out;
1280 }
1281
1282 rc = vciFileReadSync(pCache, 0, &Hdr, sizeof(Hdr));
1283 if (RT_FAILURE(rc))
1284 {
1285 rc = VERR_VD_GEN_INVALID_HEADER;
1286 goto out;
1287 }
1288
1289 Hdr.u32Signature = RT_LE2H_U32(Hdr.u32Signature);
1290 Hdr.u32Version = RT_LE2H_U32(Hdr.u32Version);
1291 Hdr.cBlocksCache = RT_LE2H_U64(Hdr.cBlocksCache);
1292 Hdr.u32CacheType = RT_LE2H_U32(Hdr.u32CacheType);
1293 Hdr.offTreeRoot = RT_LE2H_U64(Hdr.offTreeRoot);
1294 Hdr.offBlkMap = RT_LE2H_U64(Hdr.offBlkMap);
1295 Hdr.cBlkMap = RT_LE2H_U64(Hdr.cBlkMap);
1296
1297 if ( Hdr.u32Signature == VCI_HDR_SIGNATURE
1298 && Hdr.u32Version == VCI_HDR_VERSION)
1299 {
1300 pCache->offTreeRoot = Hdr.offTreeRoot;
1301 pCache->offBlksBitmap = Hdr.offBlkMap;
1302
1303 /* Load the block map. */
1304 rc = vciBlkMapLoad(pCache, VCI_BLOCK2BYTE(pCache->offBlksBitmap), Hdr.cBlkMap, &pCache->pBlkMap);
1305 if (RT_SUCCESS(rc))
1306 {
1307 /* Load the first tree node. */
1308 VciTreeNode RootNode;
1309
1310 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pCache->offTreeRoot), &RootNode, sizeof(VciTreeNode));
1311 if (RT_SUCCESS(rc))
1312 {
1313 pCache->pRoot = vciTreeNodeImage2Host(pCache->offTreeRoot, &RootNode);
1314 if (!pCache->pRoot)
1315 rc = VERR_NO_MEMORY;
1316 }
1317 }
1318 }
1319 else
1320 rc = VERR_VD_GEN_INVALID_HEADER;
1321
1322out:
1323 if (RT_FAILURE(rc))
1324 vciFreeImage(pCache, false);
1325 return rc;
1326}
1327
1328/**
1329 * Internal: Create a vci image.
1330 */
1331static int vciCreateImage(PVCICACHE pCache, uint64_t cbSize,
1332 unsigned uImageFlags, const char *pszComment,
1333 unsigned uOpenFlags, PFNVDPROGRESS pfnProgress,
1334 void *pvUser, unsigned uPercentStart,
1335 unsigned uPercentSpan)
1336{
1337 VciHdr Hdr;
1338 VciTreeNode NodeRoot;
1339 int rc;
1340 uint64_t cBlocks = cbSize / VCI_BLOCK_SIZE; /* Size of the cache in blocks. */
1341
1342 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
1343 {
1344 rc = vciError(pCache, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("VCI: cannot create diff image '%s'"), pCache->pszFilename);
1345 return rc;
1346 }
1347
1348 pCache->uImageFlags = uImageFlags;
1349
1350 pCache->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
1351
1352 pCache->pInterfaceError = VDInterfaceGet(pCache->pVDIfsDisk, VDINTERFACETYPE_ERROR);
1353 if (pCache->pInterfaceError)
1354 pCache->pInterfaceErrorCallbacks = VDGetInterfaceError(pCache->pInterfaceError);
1355
1356 pCache->pInterfaceIO = VDInterfaceGet(pCache->pVDIfsImage, VDINTERFACETYPE_IOINT);
1357 AssertPtrReturn(pCache->pInterfaceIO, VERR_INVALID_PARAMETER);
1358 pCache->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pCache->pInterfaceIO);
1359 AssertPtrReturn(pCache->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1360
1361 do
1362 {
1363 /* Create image file. */
1364 rc = vciFileOpen(pCache, pCache->pszFilename,
1365 VDOpenFlagsToFileOpenFlags(uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
1366 true /* fCreate */));
1367 if (RT_FAILURE(rc))
1368 {
1369 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot create image '%s'"), pCache->pszFilename);
1370 break;
1371 }
1372
1373 /* Allocate block bitmap. */
1374 uint32_t cBlkMap = 0;
1375 rc = vciBlkMapCreate(cBlocks, &pCache->pBlkMap, &cBlkMap);
1376 if (RT_FAILURE(rc))
1377 {
1378 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot create block bitmap '%s'"), pCache->pszFilename);
1379 break;
1380 }
1381
1382 /*
1383 * Allocate space for the header in the block bitmap.
1384 * Because the block map is empty the header has to start at block 0
1385 */
1386 uint64_t offHdr = 0;
1387 rc = vciBlkMapAllocate(pCache->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciHdr)), &offHdr);
1388 if (RT_FAILURE(rc))
1389 {
1390 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for header in block bitmap '%s'"), pCache->pszFilename);
1391 break;
1392 }
1393
1394 Assert(offHdr == 0);
1395
1396 /*
1397 * Allocate space for the block map itself.
1398 */
1399 uint64_t offBlkMap = 0;
1400 rc = vciBlkMapAllocate(pCache->pBlkMap, cBlkMap, &offBlkMap);
1401 if (RT_FAILURE(rc))
1402 {
1403 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pCache->pszFilename);
1404 break;
1405 }
1406
1407 /*
1408 * Allocate space for the tree root node.
1409 */
1410 uint64_t offTreeRoot = 0;
1411 rc = vciBlkMapAllocate(pCache->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciTreeNode)), &offTreeRoot);
1412 if (RT_FAILURE(rc))
1413 {
1414 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pCache->pszFilename);
1415 break;
1416 }
1417
1418 /*
1419 * Allocate the in memory root node.
1420 */
1421 pCache->pRoot = (PVCITREENODE)RTMemAllocZ(sizeof(VCITREENODELEAF));
1422 if (!pCache->pRoot)
1423 {
1424 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate B+-Tree root pointer '%s'"), pCache->pszFilename);
1425 break;
1426 }
1427
1428 pCache->pRoot->u8Type = VCI_TREE_NODE_TYPE_LEAF;
1429 /* Rest remains 0 as the tree is still empty. */
1430
1431 /*
1432 * Now that we are here we have all the basic structures and know where to place them in the image.
1433 * It's time to write it now.
1434 */
1435
1436 /* Setup the header. */
1437 memset(&Hdr, 0, sizeof(VciHdr));
1438 Hdr.u32Signature = RT_H2LE_U32(VCI_HDR_SIGNATURE);
1439 Hdr.u32Version = RT_H2LE_U32(VCI_HDR_VERSION);
1440 Hdr.cBlocksCache = RT_H2LE_U64(cBlocks);
1441 Hdr.fUncleanShutdown = VCI_HDR_UNCLEAN_SHUTDOWN;
1442 Hdr.u32CacheType = uImageFlags & VD_IMAGE_FLAGS_FIXED
1443 ? RT_H2LE_U32(VCI_HDR_CACHE_TYPE_FIXED)
1444 : RT_H2LE_U32(VCI_HDR_CACHE_TYPE_DYNAMIC);
1445 Hdr.offTreeRoot = RT_H2LE_U64(offTreeRoot);
1446 Hdr.offBlkMap = RT_H2LE_U64(offBlkMap);
1447 Hdr.cBlkMap = RT_H2LE_U64(cBlkMap);
1448
1449 rc = vciFileWriteSync(pCache, offHdr, &Hdr, VCI_BYTE2BLOCK(sizeof(VciHdr)));
1450 if (RT_FAILURE(rc))
1451 {
1452 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write header '%s'"), pCache->pszFilename);
1453 break;
1454 }
1455
1456 rc = vciBlkMapSave(pCache->pBlkMap, pCache, offBlkMap, cBlkMap);
1457 if (RT_FAILURE(rc))
1458 {
1459 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write block map '%s'"), pCache->pszFilename);
1460 break;
1461 }
1462
1463 /* Setup the root tree. */
1464 memset(&NodeRoot, 0, sizeof(VciTreeNode));
1465 NodeRoot.u8Type = RT_H2LE_U32(VCI_TREE_NODE_TYPE_LEAF);
1466
1467 rc = vciFileWriteSync(pCache, offTreeRoot, &NodeRoot, VCI_BYTE2BLOCK(sizeof(VciTreeNode)));
1468 if (RT_FAILURE(rc))
1469 {
1470 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write root node '%s'"), pCache->pszFilename);
1471 break;
1472 }
1473
1474 rc = vciFlushImage(pCache);
1475 if (RT_FAILURE(rc))
1476 {
1477 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot flush '%s'"), pCache->pszFilename);
1478 break;
1479 }
1480
1481 pCache->cbSize = cbSize;
1482
1483 } while (0);
1484
1485 if (RT_SUCCESS(rc) && pfnProgress)
1486 pfnProgress(pvUser, uPercentStart + uPercentSpan);
1487
1488 if (RT_FAILURE(rc))
1489 vciFreeImage(pCache, rc != VERR_ALREADY_EXISTS);
1490 return rc;
1491}
1492
1493/** @copydoc VDCACHEBACKEND::pfnProbe */
1494static int vciProbe(const char *pszFilename, PVDINTERFACE pVDIfsCache,
1495 PVDINTERFACE pVDIfsImage)
1496{
1497 VciHdr Hdr;
1498 PVDIOSTORAGE pStorage;
1499 uint64_t cbFile;
1500 int rc = VINF_SUCCESS;
1501
1502 LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
1503
1504 /* Get I/O interface. */
1505 PVDINTERFACE pInterfaceIO = VDInterfaceGet(pVDIfsImage, VDINTERFACETYPE_IOINT);
1506 AssertPtrReturn(pInterfaceIO, VERR_INVALID_PARAMETER);
1507 PVDINTERFACEIOINT pInterfaceIOCallbacks = VDGetInterfaceIOInt(pInterfaceIO);
1508 AssertPtrReturn(pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1509
1510 rc = pInterfaceIOCallbacks->pfnOpen(pInterfaceIO->pvUser, pszFilename,
1511 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
1512 false /* fCreate */),
1513 &pStorage);
1514 if (RT_FAILURE(rc))
1515 goto out;
1516
1517 rc = pInterfaceIOCallbacks->pfnGetSize(pInterfaceIO->pvUser, pStorage, &cbFile);
1518 if (RT_FAILURE(rc) || cbFile < sizeof(VciHdr))
1519 {
1520 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1521 rc = VERR_VD_GEN_INVALID_HEADER;
1522 goto out;
1523 }
1524
1525 rc = pInterfaceIOCallbacks->pfnReadSync(pInterfaceIO->pvUser, pStorage, 0, &Hdr, sizeof(Hdr), NULL);
1526 if (RT_FAILURE(rc))
1527 {
1528 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1529 rc = VERR_VD_GEN_INVALID_HEADER;
1530 goto out;
1531 }
1532
1533 Hdr.u32Signature = RT_LE2H_U32(Hdr.u32Signature);
1534 Hdr.u32Version = RT_LE2H_U32(Hdr.u32Version);
1535 Hdr.cBlocksCache = RT_LE2H_U64(Hdr.cBlocksCache);
1536 Hdr.u32CacheType = RT_LE2H_U32(Hdr.u32CacheType);
1537 Hdr.offTreeRoot = RT_LE2H_U64(Hdr.offTreeRoot);
1538 Hdr.offBlkMap = RT_LE2H_U64(Hdr.offBlkMap);
1539 Hdr.cBlkMap = RT_LE2H_U64(Hdr.cBlkMap);
1540
1541 if ( Hdr.u32Signature == VCI_HDR_SIGNATURE
1542 && Hdr.u32Version == VCI_HDR_VERSION)
1543 rc = VINF_SUCCESS;
1544 else
1545 rc = VERR_VD_GEN_INVALID_HEADER;
1546
1547 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1548
1549out:
1550 LogFlowFunc(("returns %Rrc\n", rc));
1551 return rc;
1552}
1553
1554/** @copydoc VDCACHEBACKEND::pfnOpen */
1555static int vciOpen(const char *pszFilename, unsigned uOpenFlags,
1556 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1557 void **ppBackendData)
1558{
1559 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
1560 int rc;
1561 PVCICACHE pCache;
1562
1563 /* Check open flags. All valid flags are supported. */
1564 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1565 {
1566 rc = VERR_INVALID_PARAMETER;
1567 goto out;
1568 }
1569
1570 /* Check remaining arguments. */
1571 if ( !VALID_PTR(pszFilename)
1572 || !*pszFilename)
1573 {
1574 rc = VERR_INVALID_PARAMETER;
1575 goto out;
1576 }
1577
1578
1579 pCache = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1580 if (!pCache)
1581 {
1582 rc = VERR_NO_MEMORY;
1583 goto out;
1584 }
1585 pCache->pszFilename = pszFilename;
1586 pCache->pStorage = NULL;
1587 pCache->pVDIfsDisk = pVDIfsDisk;
1588 pCache->pVDIfsImage = pVDIfsImage;
1589
1590 rc = vciOpenImage(pCache, uOpenFlags);
1591 if (RT_SUCCESS(rc))
1592 *ppBackendData = pCache;
1593 else
1594 RTMemFree(pCache);
1595
1596out:
1597 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1598 return rc;
1599}
1600
1601/** @copydoc VDCACHEBACKEND::pfnCreate */
1602static int vciCreate(const char *pszFilename, uint64_t cbSize,
1603 unsigned uImageFlags, const char *pszComment,
1604 PCRTUUID pUuid, unsigned uOpenFlags,
1605 unsigned uPercentStart, unsigned uPercentSpan,
1606 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1607 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
1608{
1609 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",
1610 pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
1611 int rc;
1612 PVCICACHE pCache;
1613
1614 PFNVDPROGRESS pfnProgress = NULL;
1615 void *pvUser = NULL;
1616 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
1617 VDINTERFACETYPE_PROGRESS);
1618 PVDINTERFACEPROGRESS pCbProgress = NULL;
1619 if (pIfProgress)
1620 {
1621 pCbProgress = VDGetInterfaceProgress(pIfProgress);
1622 if (pCbProgress)
1623 pfnProgress = pCbProgress->pfnProgress;
1624 pvUser = pIfProgress->pvUser;
1625 }
1626
1627 /* Check open flags. All valid flags are supported. */
1628 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1629 {
1630 rc = VERR_INVALID_PARAMETER;
1631 goto out;
1632 }
1633
1634 /* Check remaining arguments. */
1635 if ( !VALID_PTR(pszFilename)
1636 || !*pszFilename)
1637 {
1638 rc = VERR_INVALID_PARAMETER;
1639 goto out;
1640 }
1641
1642 pCache = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1643 if (!pCache)
1644 {
1645 rc = VERR_NO_MEMORY;
1646 goto out;
1647 }
1648 pCache->pszFilename = pszFilename;
1649 pCache->pStorage = NULL;
1650 pCache->pVDIfsDisk = pVDIfsDisk;
1651 pCache->pVDIfsImage = pVDIfsImage;
1652
1653 rc = vciCreateImage(pCache, cbSize, uImageFlags, pszComment, uOpenFlags,
1654 pfnProgress, pvUser, uPercentStart, uPercentSpan);
1655 if (RT_SUCCESS(rc))
1656 {
1657 /* So far the image is opened in read/write mode. Make sure the
1658 * image is opened in read-only mode if the caller requested that. */
1659 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
1660 {
1661 vciFreeImage(pCache, false);
1662 rc = vciOpenImage(pCache, uOpenFlags);
1663 if (RT_FAILURE(rc))
1664 {
1665 RTMemFree(pCache);
1666 goto out;
1667 }
1668 }
1669 *ppBackendData = pCache;
1670 }
1671 else
1672 RTMemFree(pCache);
1673
1674out:
1675 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1676 return rc;
1677}
1678
1679/** @copydoc VDCACHEBACKEND::pfnClose */
1680static int vciClose(void *pBackendData, bool fDelete)
1681{
1682 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
1683 PVCICACHE pCache = (PVCICACHE)pBackendData;
1684 int rc;
1685
1686 rc = vciFreeImage(pCache, fDelete);
1687 RTMemFree(pCache);
1688
1689 LogFlowFunc(("returns %Rrc\n", rc));
1690 return rc;
1691}
1692
1693/** @copydoc VDCACHEBACKEND::pfnRead */
1694static int vciRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
1695 size_t cbToRead, size_t *pcbActuallyRead)
1696{
1697 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
1698 PVCICACHE pCache = (PVCICACHE)pBackendData;
1699 int rc = VINF_SUCCESS;
1700 PVCICACHEEXTENT pExtent;
1701
1702 AssertPtr(pCache);
1703 Assert(uOffset % 512 == 0);
1704 Assert(cbToRead % 512 == 0);
1705
1706
1707 pExtent = vciCacheExtentLookup(pCache, VCI_BYTE2BLOCK(uOffset));
1708 if (pExtent)
1709 {
1710 uint64_t offRead = uOffset - VCI_BLOCK2BYTE(pExtent->u64BlockOffset);
1711 cbToRead = RT_MIN(cbToRead, VCI_BLOCK2BYTE(pExtent->u32Blocks) - offRead);
1712
1713 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pExtent->u64BlockAddr) + offRead,
1714 pvBuf, cbToRead);
1715 }
1716 else
1717 {
1718 /** @todo Best fit to check whether we have cached data later and set
1719 * pcbActuallyRead accordingly. */
1720 rc = VERR_VD_BLOCK_FREE;
1721 }
1722
1723 if (pcbActuallyRead)
1724 *pcbActuallyRead = cbToRead;
1725
1726out:
1727 LogFlowFunc(("returns %Rrc\n", rc));
1728 return rc;
1729}
1730
1731/** @copydoc VDCACHEBACKEND::pfnWrite */
1732static int vciWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
1733 size_t cbToWrite, size_t *pcbWriteProcess)
1734{
1735 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
1736 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
1737 PVCICACHE pCache = (PVCICACHE)pBackendData;
1738 int rc = VINF_SUCCESS;
1739
1740 AssertPtr(pCache);
1741 Assert(uOffset % 512 == 0);
1742 Assert(cbToWrite % 512 == 0);
1743
1744out:
1745 LogFlowFunc(("returns %Rrc\n", rc));
1746 return rc;
1747}
1748
1749/** @copydoc VDCACHEBACKEND::pfnFlush */
1750static int vciFlush(void *pBackendData)
1751{
1752 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1753 PVCICACHE pCache = (PVCICACHE)pBackendData;
1754 int rc = VINF_SUCCESS;
1755
1756 rc = vciFlushImage(pCache);
1757 LogFlowFunc(("returns %Rrc\n", rc));
1758 return rc;
1759}
1760
1761/** @copydoc VDCACHEBACKEND::pfnGetVersion */
1762static unsigned vciGetVersion(void *pBackendData)
1763{
1764 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1765 PVCICACHE pCache = (PVCICACHE)pBackendData;
1766
1767 AssertPtr(pCache);
1768
1769 if (pCache)
1770 return 1;
1771 else
1772 return 0;
1773}
1774
1775/** @copydoc VDCACHEBACKEND::pfnGetSize */
1776static uint64_t vciGetSize(void *pBackendData)
1777{
1778 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1779 PVCICACHE pCache = (PVCICACHE)pBackendData;
1780 uint64_t cb = 0;
1781
1782 AssertPtr(pCache);
1783
1784 if (pCache && pCache->pStorage)
1785 cb = pCache->cbSize;
1786
1787 LogFlowFunc(("returns %llu\n", cb));
1788 return cb;
1789}
1790
1791/** @copydoc VDCACHEBACKEND::pfnGetFileSize */
1792static uint64_t vciGetFileSize(void *pBackendData)
1793{
1794 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1795 PVCICACHE pCache = (PVCICACHE)pBackendData;
1796 uint64_t cb = 0;
1797
1798 AssertPtr(pCache);
1799
1800 if (pCache)
1801 {
1802 uint64_t cbFile;
1803 if (pCache->pStorage)
1804 {
1805 int rc = vciFileGetSize(pCache, &cbFile);
1806 if (RT_SUCCESS(rc))
1807 cb = cbFile;
1808 }
1809 }
1810
1811 LogFlowFunc(("returns %lld\n", cb));
1812 return cb;
1813}
1814
1815/** @copydoc VDCACHEBACKEND::pfnGetImageFlags */
1816static unsigned vciGetImageFlags(void *pBackendData)
1817{
1818 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1819 PVCICACHE pCache = (PVCICACHE)pBackendData;
1820 unsigned uImageFlags;
1821
1822 AssertPtr(pCache);
1823
1824 if (pCache)
1825 uImageFlags = pCache->uImageFlags;
1826 else
1827 uImageFlags = 0;
1828
1829 LogFlowFunc(("returns %#x\n", uImageFlags));
1830 return uImageFlags;
1831}
1832
1833/** @copydoc VDCACHEBACKEND::pfnGetOpenFlags */
1834static unsigned vciGetOpenFlags(void *pBackendData)
1835{
1836 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1837 PVCICACHE pCache = (PVCICACHE)pBackendData;
1838 unsigned uOpenFlags;
1839
1840 AssertPtr(pCache);
1841
1842 if (pCache)
1843 uOpenFlags = pCache->uOpenFlags;
1844 else
1845 uOpenFlags = 0;
1846
1847 LogFlowFunc(("returns %#x\n", uOpenFlags));
1848 return uOpenFlags;
1849}
1850
1851/** @copydoc VDCACHEBACKEND::pfnSetOpenFlags */
1852static int vciSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
1853{
1854 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
1855 PVCICACHE pCache = (PVCICACHE)pBackendData;
1856 int rc;
1857
1858 /* Image must be opened and the new flags must be valid. Just readonly and
1859 * info flags are supported. */
1860 if (!pCache || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
1861 {
1862 rc = VERR_INVALID_PARAMETER;
1863 goto out;
1864 }
1865
1866 /* Implement this operation via reopening the image. */
1867 rc = vciFreeImage(pCache, false);
1868 if (RT_FAILURE(rc))
1869 goto out;
1870 rc = vciOpenImage(pCache, uOpenFlags);
1871
1872out:
1873 LogFlowFunc(("returns %Rrc\n", rc));
1874 return rc;
1875}
1876
1877/** @copydoc VDCACHEBACKEND::pfnGetComment */
1878static int vciGetComment(void *pBackendData, char *pszComment,
1879 size_t cbComment)
1880{
1881 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
1882 PVCICACHE pCache = (PVCICACHE)pBackendData;
1883 int rc;
1884
1885 AssertPtr(pCache);
1886
1887 if (pCache)
1888 rc = VERR_NOT_SUPPORTED;
1889 else
1890 rc = VERR_VD_NOT_OPENED;
1891
1892 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
1893 return rc;
1894}
1895
1896/** @copydoc VDCACHEBACKEND::pfnSetComment */
1897static int vciSetComment(void *pBackendData, const char *pszComment)
1898{
1899 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1900 PVCICACHE pCache = (PVCICACHE)pBackendData;
1901 int rc;
1902
1903 AssertPtr(pCache);
1904
1905 if (pCache)
1906 {
1907 if (pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1908 rc = VERR_VD_IMAGE_READ_ONLY;
1909 else
1910 rc = VERR_NOT_SUPPORTED;
1911 }
1912 else
1913 rc = VERR_VD_NOT_OPENED;
1914
1915out:
1916 LogFlowFunc(("returns %Rrc\n", rc));
1917 return rc;
1918}
1919
1920/** @copydoc VDCACHEBACKEND::pfnGetUuid */
1921static int vciGetUuid(void *pBackendData, PRTUUID pUuid)
1922{
1923 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1924 PVCICACHE pCache = (PVCICACHE)pBackendData;
1925 int rc;
1926
1927 AssertPtr(pCache);
1928
1929 if (pCache)
1930 rc = VERR_NOT_SUPPORTED;
1931 else
1932 rc = VERR_VD_NOT_OPENED;
1933
1934 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1935 return rc;
1936}
1937
1938/** @copydoc VDCACHEBACKEND::pfnSetUuid */
1939static int vciSetUuid(void *pBackendData, PCRTUUID pUuid)
1940{
1941 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1942 PVCICACHE pCache = (PVCICACHE)pBackendData;
1943 int rc;
1944
1945 LogFlowFunc(("%RTuuid\n", pUuid));
1946 AssertPtr(pCache);
1947
1948 if (pCache)
1949 {
1950 if (!(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1951 rc = VERR_NOT_SUPPORTED;
1952 else
1953 rc = VERR_VD_IMAGE_READ_ONLY;
1954 }
1955 else
1956 rc = VERR_VD_NOT_OPENED;
1957
1958 LogFlowFunc(("returns %Rrc\n", rc));
1959 return rc;
1960}
1961
1962/** @copydoc VDCACHEBACKEND::pfnGetModificationUuid */
1963static int vciGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1964{
1965 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1966 PVCICACHE pCache = (PVCICACHE)pBackendData;
1967 int rc;
1968
1969 AssertPtr(pCache);
1970
1971 if (pCache)
1972 rc = VERR_NOT_SUPPORTED;
1973 else
1974 rc = VERR_VD_NOT_OPENED;
1975
1976 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1977 return rc;
1978}
1979
1980/** @copydoc VDCACHEBACKEND::pfnSetModificationUuid */
1981static int vciSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1982{
1983 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1984 PVCICACHE pCache = (PVCICACHE)pBackendData;
1985 int rc;
1986
1987 AssertPtr(pCache);
1988
1989 if (pCache)
1990 {
1991 if (!(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1992 rc = VERR_NOT_SUPPORTED;
1993 else
1994 rc = VERR_VD_IMAGE_READ_ONLY;
1995 }
1996 else
1997 rc = VERR_VD_NOT_OPENED;
1998
1999 LogFlowFunc(("returns %Rrc\n", rc));
2000 return rc;
2001}
2002
2003/** @copydoc VDCACHEBACKEND::pfnDump */
2004static void vciDump(void *pBackendData)
2005{
2006 NOREF(pBackendData);
2007}
2008
2009/** @copydoc VDCACHEBACKEND::pfnAsyncRead */
2010static int vciAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
2011 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
2012{
2013 int rc = VERR_NOT_SUPPORTED;
2014 PVCICACHE pCache = (PVCICACHE)pBackendData;
2015
2016 return rc;
2017}
2018
2019/** @copydoc VDCACHEBACKEND::pfnAsyncWrite */
2020static int vciAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
2021 PVDIOCTX pIoCtx, size_t *pcbWriteProcess)
2022{
2023 int rc = VERR_NOT_SUPPORTED;
2024 PVCICACHE pCache = (PVCICACHE)pBackendData;
2025
2026 return rc;
2027}
2028
2029/** @copydoc VDCACHEBACKEND::pfnAsyncFlush */
2030static int vciAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
2031{
2032 int rc = VERR_NOT_SUPPORTED;
2033 PVCICACHE pCache = (PVCICACHE)pBackendData;
2034
2035 return rc;
2036}
2037
2038
2039VDCACHEBACKEND g_VciCacheBackend =
2040{
2041 /* pszBackendName */
2042 "vci",
2043 /* cbSize */
2044 sizeof(VDCACHEBACKEND),
2045 /* uBackendCaps */
2046 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_VFS,
2047 /* papszFileExtensions */
2048 s_apszVciFileExtensions,
2049 /* paConfigInfo */
2050 NULL,
2051 /* hPlugin */
2052 NIL_RTLDRMOD,
2053 /* pfnProbe */
2054 vciProbe,
2055 /* pfnOpen */
2056 vciOpen,
2057 /* pfnCreate */
2058 vciCreate,
2059 /* pfnClose */
2060 vciClose,
2061 /* pfnRead */
2062 vciRead,
2063 /* pfnWrite */
2064 vciWrite,
2065 /* pfnFlush */
2066 vciFlush,
2067 /* pfnGetVersion */
2068 vciGetVersion,
2069 /* pfnGetSize */
2070 vciGetSize,
2071 /* pfnGetFileSize */
2072 vciGetFileSize,
2073 /* pfnGetImageFlags */
2074 vciGetImageFlags,
2075 /* pfnGetOpenFlags */
2076 vciGetOpenFlags,
2077 /* pfnSetOpenFlags */
2078 vciSetOpenFlags,
2079 /* pfnGetComment */
2080 vciGetComment,
2081 /* pfnSetComment */
2082 vciSetComment,
2083 /* pfnGetUuid */
2084 vciGetUuid,
2085 /* pfnSetUuid */
2086 vciSetUuid,
2087 /* pfnGetModificationUuid */
2088 vciGetModificationUuid,
2089 /* pfnSetModificationUuid */
2090 vciSetModificationUuid,
2091 /* pfnDump */
2092 vciDump,
2093 /* pfnAsyncRead */
2094 vciAsyncRead,
2095 /* pfnAsyncWrite */
2096 vciAsyncWrite,
2097 /* pfnAsyncFlush */
2098 vciAsyncFlush,
2099 /* pfnComposeLocation */
2100 NULL,
2101 /* pfnComposeName */
2102 NULL
2103};
2104
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