VirtualBox

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

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

Storage: Implement offical support for other disk types like DVD and floppy images. DMG images can be used now without hacks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.5 KB
Line 
1/* $Id: VCICacheCore.cpp 33524 2010-10-27 16:44:37Z 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#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 /** Modifcation UUID for the cache. */
76 RTUUID uuidModification;
77 /** Reserved for future use. */
78 uint8_t abReserved[951];
79} VciHdr, *PVciHdr;
80#pragma pack(0)
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(0)
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(0)
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(0)
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(0)
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 while (cBlocksRead)
720 {
721 if (pRangeCur->fFree)
722 {
723 /* Check for the first set bit. */
724 }
725 else
726 {
727 /* Check for the first free bit. */
728 }
729
730 if (iBit == -1)
731 {
732 /* No change. */
733 pRangeCur->cBlocks += cBlocksRead;
734 cBlocksRead = 0;
735 }
736 else
737 {
738 /* Create a new range descriptor. */
739 }
740 }
741 cBlocksLeft -= cBlocksRead;
742 offBlkMap += cBlocksRead;
743
744 if (cBlocksLeft)
745 {
746 /* Read next chunk. */
747 }
748 }
749 }
750 else
751 rc = VERR_NO_MEMORY;
752
753 if (RT_SUCCESS(rc))
754 {
755 *ppBlkMap = pBlkMap;
756 LogFlowFunc(("return success\n"));
757 return VINF_SUCCESS;
758 }
759 else
760 RTMemFree(pBlkMap);
761 }
762 else
763 rc = VERR_NO_MEMORY;
764 }
765 else
766 rc = VERR_VD_GEN_INVALID_HEADER;
767 }
768 else if (RT_SUCCESS(rc))
769 rc = VERR_VD_GEN_INVALID_HEADER;
770 }
771 else
772 rc = VERR_VD_GEN_INVALID_HEADER;
773
774 LogFlowFunc(("returns rc=%Rrc\n", rc));
775 return rc;
776}
777
778/**
779 * Saves the block map in the cache image. All neccessary on disk structures
780 * are written.
781 *
782 * @returns VBox status code.
783 * @param pBlkMap The block bitmap to save.
784 * @param pStorage Where the block bitmap should be written to.
785 * @param offBlkMap Start of the block bitmap in blocks.
786 * @param cBlkMap Size of the block bitmap on the disk in blocks.
787 */
788static int vciBlkMapSave(PVCIBLKMAP pBlkMap, PVCICACHE pStorage, uint64_t offBlkMap, uint32_t cBlkMap)
789{
790 int rc = VINF_SUCCESS;
791 VciBlkMap BlkMap;
792
793 LogFlowFunc(("pBlkMap=%#p pStorage=%#p offBlkMap=%llu cBlkMap=%u\n",
794 pBlkMap, pStorage, offBlkMap, cBlkMap));
795
796 /* Make sure the number of blocks allocated for us match our expectations. */
797 if ((pBlkMap->cBlocks / 8) + VCI_BYTE2BLOCK(sizeof(VciBlkMap)) == cBlkMap)
798 {
799 /* Setup the header */
800 memset(&BlkMap, 0, sizeof(VciBlkMap));
801
802 BlkMap.u32Magic = RT_H2LE_U32(VCI_BLKMAP_MAGIC);
803 BlkMap.u32Version = RT_H2LE_U32(VCI_BLKMAP_VERSION);
804 BlkMap.cBlocks = RT_H2LE_U32(pBlkMap->cBlocks);
805 BlkMap.cBlocksFree = RT_H2LE_U32(pBlkMap->cBlocksFree);
806 BlkMap.cBlocksAllocMeta = RT_H2LE_U32(pBlkMap->cBlocksAllocMeta);
807 BlkMap.cBlocksAllocData = RT_H2LE_U32(pBlkMap->cBlocksAllocData);
808
809 rc = vciFileWriteSync(pStorage, VCI_BLOCK2BYTE(offBlkMap), &BlkMap, VCI_BYTE2BLOCK(sizeof(VciBlkMap)));
810 if (RT_SUCCESS(rc))
811 {
812 uint8_t abBitmapBuffer[16*_1K];
813 unsigned iBit = 0;
814 PVCIBLKRANGEDESC pCur = pBlkMap->pRangesHead;
815
816 offBlkMap += VCI_BYTE2BLOCK(sizeof(VciBlkMap));
817
818 /* Write the descriptor ranges. */
819 while (pCur)
820 {
821 uint64_t cBlocks = pCur->cBlocks;
822
823 while (cBlocks)
824 {
825 uint64_t cBlocksMax = RT_MIN(cBlocks, sizeof(abBitmapBuffer) * 8 - iBit);
826
827 if (pCur->fFree)
828 ASMBitClearRange(abBitmapBuffer, iBit, iBit + cBlocksMax);
829 else
830 ASMBitSetRange(abBitmapBuffer, iBit, iBit + cBlocksMax);
831
832 iBit += cBlocksMax;
833 cBlocks -= cBlocksMax;
834
835 if (iBit == sizeof(abBitmapBuffer) * 8)
836 {
837 /* Buffer is full, write to file and reset. */
838 rc = vciFileWriteSync(pStorage, offBlkMap, abBitmapBuffer, sizeof(abBitmapBuffer));
839 if (RT_FAILURE(rc))
840 break;
841
842 offBlkMap += VCI_BYTE2BLOCK(sizeof(abBitmapBuffer));
843 iBit = 0;
844 }
845 }
846
847 pCur = pCur->pNext;
848 }
849
850 Assert(iBit % 8 == 0);
851
852 if (RT_SUCCESS(rc) && iBit)
853 rc = vciFileWriteSync(pStorage, offBlkMap, abBitmapBuffer, iBit / 8);
854 }
855 }
856 else
857 rc = VERR_INTERNAL_ERROR; /* @todo Better error code. */
858
859 LogFlowFunc(("returns rc=%Rrc\n", rc));
860 return rc;
861}
862
863/**
864 * Finds the range block describing the given block address.
865 *
866 * @returns Pointer to the block range descriptor or NULL if none could be found.
867 * @param pBlkMap The block bitmap to search on.
868 * @param offBlockAddr The block address to search for.
869 */
870static PVCIBLKRANGEDESC vciBlkMapFindByBlock(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr)
871{
872 PVCIBLKRANGEDESC pBlk = pBlkMap->pRangesHead;
873
874 while ( pBlk
875 && pBlk->offAddrStart < offBlockAddr)
876 pBlk = pBlk->pNext;
877
878 return pBlk;
879}
880
881/**
882 * Allocates the given number of blocks in the bitmap and returns the start block address.
883 *
884 * @returns VBox status code.
885 * @param pBlkMap The block bitmap to allocate the blocks from.
886 * @param cBlocks How many blocks to allocate.
887 * @param poffBlockAddr Where to store the start address of the allocated region.
888 */
889static int vciBlkMapAllocate(PVCIBLKMAP pBlkMap, uint32_t cBlocks, uint64_t *poffBlockAddr)
890{
891 PVCIBLKRANGEDESC pBestFit = NULL;
892 PVCIBLKRANGEDESC pCur = NULL;
893 int rc = VINF_SUCCESS;
894
895 LogFlowFunc(("pBlkMap=%#p cBlocks=%u poffBlockAddr=%#p\n",
896 pBlkMap, cBlocks, poffBlockAddr));
897
898 pCur = pBlkMap->pRangesHead;
899
900 while (pCur)
901 {
902 if ( pCur->fFree
903 && pCur->cBlocks >= cBlocks)
904 {
905 if ( !pBestFit
906 || pCur->cBlocks < pBestFit->cBlocks)
907 {
908 pBestFit = pCur;
909 /* Stop searching if the size is matching exactly. */
910 if (pBestFit->cBlocks == cBlocks)
911 break;
912 }
913 }
914 pCur = pCur->pNext;
915 }
916
917 Assert(!pBestFit || pBestFit->fFree);
918
919 if (pBestFit)
920 {
921 pBestFit->fFree = false;
922
923 if (pBestFit->cBlocks > cBlocks)
924 {
925 /* Create a new free block. */
926 PVCIBLKRANGEDESC pFree = (PVCIBLKRANGEDESC)RTMemAllocZ(sizeof(VCIBLKRANGEDESC));
927
928 if (pFree)
929 {
930 pFree->fFree = true;
931 pFree->cBlocks = pBestFit->cBlocks - cBlocks;
932 pFree->offAddrStart = pBestFit->offAddrStart + cBlocks;
933
934 /* Link into the list. */
935 pFree->pNext = pBestFit->pNext;
936 pBestFit->pNext = pFree;
937 pFree->pPrev = pBestFit;
938 if (!pFree->pNext)
939 pBlkMap->pRangesTail = pFree;
940
941 *poffBlockAddr = pBestFit->offAddrStart;
942 }
943 else
944 {
945 rc = VERR_NO_MEMORY;
946 pBestFit->fFree = true;
947 }
948 }
949 }
950 else
951 rc = VERR_VCI_NO_BLOCKS_FREE;
952
953 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
954 return rc;
955}
956
957/**
958 * Try to extend the space of an already allocated block.
959 *
960 * @returns VBox status code.
961 * @param pBlkMap The block bitmap to allocate the blocks from.
962 * @param cBlocksNew How many blocks the extended block should have.
963 * @param offBlockAddrOld The start address of the block to reallocate.
964 * @param poffBlockAddr Where to store the start address of the allocated region.
965 */
966static int vciBlkMapRealloc(PVCIBLKMAP pBlkMap, uint32_t cBlocksNew, uint64_t offBlockAddrOld,
967 uint64_t *poffBlockAddr)
968{
969 int rc = VINF_SUCCESS;
970
971 LogFlowFunc(("pBlkMap=%#p cBlocksNew=%u offBlockAddrOld=%llu poffBlockAddr=%#p\n",
972 pBlkMap, cBlocksNew, offBlockAddrOld, poffBlockAddr));
973
974 AssertMsgFailed(("Implement\n"));
975
976 LogFlowFunc(("returns rc=%Rrc offBlockAddr=%llu\n", rc, *poffBlockAddr));
977 return rc;
978}
979
980/**
981 * Frees a range of blocks.
982 *
983 * @returns nothing.
984 * @param pBlkMap The block bitmap.
985 * @param offBlockAddr Address of the first block to free.
986 * @param cBlocks How many blocks to free.
987 */
988static void vciBlkMapFree(PVCIBLKMAP pBlkMap, uint64_t offBlockAddr, uint32_t cBlocks)
989{
990 PVCIBLKRANGEDESC pBlk;
991
992 LogFlowFunc(("pBlkMap=%#p offBlockAddr=%llu cBlocks=%u\n",
993 pBlkMap, offBlockAddr, cBlocks));
994
995 while (cBlocks)
996 {
997 pBlk = vciBlkMapFindByBlock(pBlkMap, offBlockAddr);
998 AssertPtr(pBlk);
999
1000 /* Easy case, the whole block is freed. */
1001 if ( pBlk->offAddrStart == offBlockAddr
1002 && pBlk->cBlocks <= cBlocks)
1003 {
1004 pBlk->fFree = true;
1005 cBlocks -= pBlk->cBlocks;
1006 offBlockAddr += pBlk->cBlocks;
1007
1008 /* Check if it is possible to merge free blocks. */
1009 if ( pBlk->pPrev
1010 && pBlk->pPrev->fFree)
1011 {
1012 PVCIBLKRANGEDESC pBlkPrev = pBlk->pPrev;
1013
1014 Assert(pBlkPrev->offAddrStart + pBlkPrev->cBlocks == pBlk->offAddrStart);
1015 pBlkPrev->cBlocks += pBlk->cBlocks;
1016 pBlkPrev->pNext = pBlk->pNext;
1017 if (pBlk->pNext)
1018 pBlk->pNext->pPrev = pBlkPrev;
1019 else
1020 pBlkMap->pRangesTail = pBlkPrev;
1021
1022 RTMemFree(pBlk);
1023 pBlk = pBlkPrev;
1024 }
1025
1026 /* Now the one to the right. */
1027 if ( pBlk->pNext
1028 && pBlk->pNext->fFree)
1029 {
1030 PVCIBLKRANGEDESC pBlkNext = pBlk->pNext;
1031
1032 Assert(pBlk->offAddrStart + pBlk->cBlocks == pBlkNext->offAddrStart);
1033 pBlk->cBlocks += pBlkNext->cBlocks;
1034 pBlk->pNext = pBlkNext->pNext;
1035 if (pBlkNext->pNext)
1036 pBlkNext->pNext->pPrev = pBlk;
1037 else
1038 pBlkMap->pRangesTail = pBlk;
1039
1040 RTMemFree(pBlkNext);
1041 }
1042 }
1043 else
1044 {
1045 /* The block is intersecting. */
1046 AssertMsgFailed(("TODO\n"));
1047 }
1048 }
1049
1050 LogFlowFunc(("returns\n"));
1051}
1052
1053/**
1054 * Converts a tree node from the image to the in memory structure.
1055 *
1056 * @returns Pointer to the in memory tree node.
1057 * @param offBlockAddrNode Block address of the node.
1058 * @param pNodeImage Pointer to the image representation of the node.
1059 */
1060static PVCITREENODE vciTreeNodeImage2Host(uint64_t offBlockAddrNode, PVciTreeNode pNodeImage)
1061{
1062 PVCITREENODE pNode = NULL;
1063
1064 if (pNodeImage->u8Type == VCI_TREE_NODE_TYPE_LEAF)
1065 {
1066 PVCITREENODELEAF pLeaf = (PVCITREENODELEAF)RTMemAllocZ(sizeof(VCITREENODELEAF));
1067
1068 if (pLeaf)
1069 {
1070 PVciCacheExtent pExtent = (PVciCacheExtent)&pNodeImage->au8Data[0];
1071
1072 pLeaf->Core.u8Type = VCI_TREE_NODE_TYPE_LEAF;
1073
1074 for (unsigned idx = 0; idx < RT_ELEMENTS(pLeaf->aExtents); idx++)
1075 {
1076 pLeaf->aExtents[idx].u64BlockOffset = RT_LE2H_U64(pExtent->u64BlockOffset);
1077 pLeaf->aExtents[idx].u32Blocks = RT_LE2H_U32(pExtent->u32Blocks);
1078 pLeaf->aExtents[idx].u64BlockAddr = RT_LE2H_U64(pExtent->u64BlockAddr);
1079 pExtent++;
1080
1081 if ( pLeaf->aExtents[idx].u32Blocks
1082 && pLeaf->aExtents[idx].u64BlockAddr)
1083 pLeaf->cUsedNodes++;
1084 }
1085
1086 pNode = &pLeaf->Core;
1087 }
1088 }
1089 else if (pNodeImage->u8Type == VCI_TREE_NODE_TYPE_INTERNAL)
1090 {
1091 PVCITREENODEINT pInt = (PVCITREENODEINT)RTMemAllocZ(sizeof(VCITREENODEINT));
1092
1093 if (pInt)
1094 {
1095 PVciTreeNodeInternal pIntImage = (PVciTreeNodeInternal)&pNodeImage->au8Data[0];
1096
1097 pInt->Core.u8Type = VCI_TREE_NODE_TYPE_INTERNAL;
1098
1099 for (unsigned idx = 0; idx < RT_ELEMENTS(pInt->aIntNodes); idx++)
1100 {
1101 pInt->aIntNodes[idx].u64BlockOffset = RT_LE2H_U64(pIntImage->u64BlockOffset);
1102 pInt->aIntNodes[idx].u32Blocks = RT_LE2H_U32(pIntImage->u32Blocks);
1103 pInt->aIntNodes[idx].PtrChild.fInMemory = false;
1104 pInt->aIntNodes[idx].PtrChild.u.offAddrBlockNode = RT_LE2H_U64(pIntImage->u64ChildAddr);
1105 pIntImage++;
1106
1107 if ( pInt->aIntNodes[idx].u32Blocks
1108 && pInt->aIntNodes[idx].PtrChild.u.offAddrBlockNode)
1109 pInt->cUsedNodes++;
1110 }
1111
1112 pNode = &pInt->Core;
1113 }
1114 }
1115 else
1116 AssertMsgFailed(("Invalid node type %d\n", pNodeImage->u8Type));
1117
1118 if (pNode)
1119 pNode->u64BlockAddr = offBlockAddrNode;
1120
1121 return pNode;
1122}
1123
1124/**
1125 * Looks up the cache extent for the given virtual block address.
1126 *
1127 * @returns Pointer to the cache extent or NULL if none could be found.
1128 * @param pCache The cache image instance.
1129 * @param offBlockOffset The block offset to search for.
1130 */
1131static PVCICACHEEXTENT vciCacheExtentLookup(PVCICACHE pCache, uint64_t offBlockOffset)
1132{
1133 int rc = VINF_SUCCESS;
1134 PVCICACHEEXTENT pExtent = NULL;
1135 PVCITREENODE pNodeCur = pCache->pRoot;
1136
1137 while ( RT_SUCCESS(rc)
1138 && pNodeCur
1139 && pNodeCur->u8Type != VCI_TREE_NODE_TYPE_LEAF)
1140 {
1141 PVCITREENODEINT pNodeInt = (PVCITREENODEINT)pNodeCur;
1142
1143 Assert(pNodeCur->u8Type == VCI_TREE_NODE_TYPE_INTERNAL);
1144
1145 /* Search for the correct internal node. */
1146 unsigned idxMin = 0;
1147 unsigned idxMax = pNodeInt->cUsedNodes;
1148 unsigned idxCur = pNodeInt->cUsedNodes / 2;
1149
1150 while (idxMin < idxMax)
1151 {
1152 PVCINODEINTERNAL pInt = &pNodeInt->aIntNodes[idxCur];
1153
1154 /* Determine the search direction. */
1155 if (offBlockOffset < pInt->u64BlockOffset)
1156 {
1157 /* Search left from the current extent. */
1158 idxMax = idxCur;
1159 }
1160 else if (offBlockOffset >= pInt->u64BlockOffset + pInt->u32Blocks)
1161 {
1162 /* Search right from the current extent. */
1163 idxMin = idxCur;
1164 }
1165 else
1166 {
1167 /* The block lies in the node, stop searching. */
1168 if (pInt->PtrChild.fInMemory)
1169 pNodeCur = pInt->PtrChild.u.pNode;
1170 else
1171 {
1172 PVCITREENODE pNodeNew;
1173 VciTreeNode NodeTree;
1174
1175 /* Read from disk and add to the tree. */
1176 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pInt->PtrChild.u.offAddrBlockNode),
1177 &NodeTree, sizeof(NodeTree));
1178 AssertRC(rc);
1179
1180 pNodeNew = vciTreeNodeImage2Host(pInt->PtrChild.u.offAddrBlockNode, &NodeTree);
1181 if (pNodeNew)
1182 {
1183 /* Link to the parent. */
1184 pInt->PtrChild.fInMemory = true;
1185 pInt->PtrChild.u.pNode = pNodeNew;
1186 pNodeNew->pParent = pNodeCur;
1187 pNodeCur = pNodeNew;
1188 }
1189 else
1190 rc = VERR_NO_MEMORY;
1191 }
1192 break;
1193 }
1194
1195 idxCur = idxMin + (idxMax - idxMin) / 2;
1196 }
1197 }
1198
1199 if ( RT_SUCCESS(rc)
1200 && pNodeCur)
1201 {
1202 PVCITREENODELEAF pLeaf = (PVCITREENODELEAF)pNodeCur;
1203 Assert(pNodeCur->u8Type == VCI_TREE_NODE_TYPE_LEAF);
1204
1205 /* Search the range. */
1206 unsigned idxMin = 0;
1207 unsigned idxMax = pLeaf->cUsedNodes;
1208 unsigned idxCur = pLeaf->cUsedNodes / 2;
1209
1210 while (idxMin < idxMax)
1211 {
1212 PVCICACHEEXTENT pExtentCur = &pLeaf->aExtents[idxCur];
1213
1214 /* Determine the search direction. */
1215 if (offBlockOffset < pExtentCur->u64BlockOffset)
1216 {
1217 /* Search left from the current extent. */
1218 idxMax = idxCur;
1219 }
1220 else if (offBlockOffset >= pExtentCur->u64BlockOffset + pExtentCur->u32Blocks)
1221 {
1222 /* Search right from the current extent. */
1223 idxMin = idxCur;
1224 }
1225 else
1226 {
1227 /* We found the extent, stop searching. */
1228 pExtent = pExtentCur;
1229 break;
1230 }
1231
1232 idxCur = idxMin + (idxMax - idxMin) / 2;
1233 }
1234 }
1235
1236 return pExtent;
1237}
1238
1239/**
1240 * Internal: Open an image, constructing all necessary data structures.
1241 */
1242static int vciOpenImage(PVCICACHE pCache, unsigned uOpenFlags)
1243{
1244 VciHdr Hdr;
1245 uint64_t cbFile;
1246 int rc;
1247
1248 pCache->uOpenFlags = uOpenFlags;
1249
1250 pCache->pInterfaceError = VDInterfaceGet(pCache->pVDIfsDisk, VDINTERFACETYPE_ERROR);
1251 if (pCache->pInterfaceError)
1252 pCache->pInterfaceErrorCallbacks = VDGetInterfaceError(pCache->pInterfaceError);
1253
1254 /* Get I/O interface. */
1255 pCache->pInterfaceIO = VDInterfaceGet(pCache->pVDIfsImage, VDINTERFACETYPE_IOINT);
1256 AssertPtrReturn(pCache->pInterfaceIO, VERR_INVALID_PARAMETER);
1257 pCache->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pCache->pInterfaceIO);
1258 AssertPtrReturn(pCache->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1259
1260 /*
1261 * Open the image.
1262 */
1263 rc = vciFileOpen(pCache, pCache->pszFilename,
1264 VDOpenFlagsToFileOpenFlags(uOpenFlags,
1265 false /* fCreate */));
1266 if (RT_FAILURE(rc))
1267 {
1268 /* Do NOT signal an appropriate error here, as the VD layer has the
1269 * choice of retrying the open if it failed. */
1270 goto out;
1271 }
1272
1273 rc = vciFileGetSize(pCache, &cbFile);
1274 if (RT_FAILURE(rc) || cbFile < sizeof(VciHdr))
1275 {
1276 rc = VERR_VD_GEN_INVALID_HEADER;
1277 goto out;
1278 }
1279
1280 rc = vciFileReadSync(pCache, 0, &Hdr, sizeof(Hdr));
1281 if (RT_FAILURE(rc))
1282 {
1283 rc = VERR_VD_GEN_INVALID_HEADER;
1284 goto out;
1285 }
1286
1287 Hdr.u32Signature = RT_LE2H_U32(Hdr.u32Signature);
1288 Hdr.u32Version = RT_LE2H_U32(Hdr.u32Version);
1289 Hdr.cBlocksCache = RT_LE2H_U64(Hdr.cBlocksCache);
1290 Hdr.u32CacheType = RT_LE2H_U32(Hdr.u32CacheType);
1291 Hdr.offTreeRoot = RT_LE2H_U64(Hdr.offTreeRoot);
1292 Hdr.offBlkMap = RT_LE2H_U64(Hdr.offBlkMap);
1293 Hdr.cBlkMap = RT_LE2H_U64(Hdr.cBlkMap);
1294
1295 if ( Hdr.u32Signature == VCI_HDR_SIGNATURE
1296 && Hdr.u32Version == VCI_HDR_VERSION)
1297 {
1298 pCache->offTreeRoot = Hdr.offTreeRoot;
1299 pCache->offBlksBitmap = Hdr.offBlkMap;
1300
1301 /* Load the block map. */
1302 rc = vciBlkMapLoad(pCache, VCI_BLOCK2BYTE(pCache->offBlksBitmap), Hdr.cBlkMap, &pCache->pBlkMap);
1303 if (RT_SUCCESS(rc))
1304 {
1305 /* Load the first tree node. */
1306 VciTreeNode RootNode;
1307
1308 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pCache->offTreeRoot), &RootNode, sizeof(VciTreeNode));
1309 if (RT_SUCCESS(rc))
1310 {
1311 pCache->pRoot = vciTreeNodeImage2Host(pCache->offTreeRoot, &RootNode);
1312 if (!pCache->pRoot)
1313 rc = VERR_NO_MEMORY;
1314 }
1315 }
1316 }
1317 else
1318 rc = VERR_VD_GEN_INVALID_HEADER;
1319
1320out:
1321 if (RT_FAILURE(rc))
1322 vciFreeImage(pCache, false);
1323 return rc;
1324}
1325
1326/**
1327 * Internal: Create a vci image.
1328 */
1329static int vciCreateImage(PVCICACHE pCache, uint64_t cbSize,
1330 unsigned uImageFlags, const char *pszComment,
1331 unsigned uOpenFlags, PFNVDPROGRESS pfnProgress,
1332 void *pvUser, unsigned uPercentStart,
1333 unsigned uPercentSpan)
1334{
1335 VciHdr Hdr;
1336 VciTreeNode NodeRoot;
1337 int rc;
1338 uint64_t cBlocks = cbSize / VCI_BLOCK_SIZE; /* Size of the cache in blocks. */
1339
1340 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
1341 {
1342 rc = vciError(pCache, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("VCI: cannot create diff image '%s'"), pCache->pszFilename);
1343 return rc;
1344 }
1345
1346 pCache->uImageFlags = uImageFlags;
1347
1348 pCache->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
1349
1350 pCache->pInterfaceError = VDInterfaceGet(pCache->pVDIfsDisk, VDINTERFACETYPE_ERROR);
1351 if (pCache->pInterfaceError)
1352 pCache->pInterfaceErrorCallbacks = VDGetInterfaceError(pCache->pInterfaceError);
1353
1354 pCache->pInterfaceIO = VDInterfaceGet(pCache->pVDIfsImage, VDINTERFACETYPE_IOINT);
1355 AssertPtrReturn(pCache->pInterfaceIO, VERR_INVALID_PARAMETER);
1356 pCache->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pCache->pInterfaceIO);
1357 AssertPtrReturn(pCache->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1358
1359 do
1360 {
1361 /* Create image file. */
1362 rc = vciFileOpen(pCache, pCache->pszFilename,
1363 VDOpenFlagsToFileOpenFlags(uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
1364 true /* fCreate */));
1365 if (RT_FAILURE(rc))
1366 {
1367 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot create image '%s'"), pCache->pszFilename);
1368 break;
1369 }
1370
1371 /* Allocate block bitmap. */
1372 uint32_t cBlkMap = 0;
1373 rc = vciBlkMapCreate(cBlocks, &pCache->pBlkMap, &cBlkMap);
1374 if (RT_FAILURE(rc))
1375 {
1376 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot create block bitmap '%s'"), pCache->pszFilename);
1377 break;
1378 }
1379
1380 /*
1381 * Allocate space for the header in the block bitmap.
1382 * Because the block map is empty the header has to start at block 0
1383 */
1384 uint64_t offHdr = 0;
1385 rc = vciBlkMapAllocate(pCache->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciHdr)), &offHdr);
1386 if (RT_FAILURE(rc))
1387 {
1388 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for header in block bitmap '%s'"), pCache->pszFilename);
1389 break;
1390 }
1391
1392 Assert(offHdr == 0);
1393
1394 /*
1395 * Allocate space for the block map itself.
1396 */
1397 uint64_t offBlkMap = 0;
1398 rc = vciBlkMapAllocate(pCache->pBlkMap, cBlkMap, &offBlkMap);
1399 if (RT_FAILURE(rc))
1400 {
1401 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pCache->pszFilename);
1402 break;
1403 }
1404
1405 /*
1406 * Allocate space for the tree root node.
1407 */
1408 uint64_t offTreeRoot = 0;
1409 rc = vciBlkMapAllocate(pCache->pBlkMap, VCI_BYTE2BLOCK(sizeof(VciTreeNode)), &offTreeRoot);
1410 if (RT_FAILURE(rc))
1411 {
1412 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate space for block map in block map '%s'"), pCache->pszFilename);
1413 break;
1414 }
1415
1416 /*
1417 * Allocate the in memory root node.
1418 */
1419 pCache->pRoot = (PVCITREENODE)RTMemAllocZ(sizeof(VCITREENODELEAF));
1420 if (!pCache->pRoot)
1421 {
1422 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot allocate B+-Tree root pointer '%s'"), pCache->pszFilename);
1423 break;
1424 }
1425
1426 pCache->pRoot->u8Type = VCI_TREE_NODE_TYPE_LEAF;
1427 /* Rest remains 0 as the tree is still empty. */
1428
1429 /*
1430 * Now that we are here we have all the basic structures and know where to place them in the image.
1431 * It's time to write it now.
1432 */
1433
1434 /* Setup the header. */
1435 memset(&Hdr, 0, sizeof(VciHdr));
1436 Hdr.u32Signature = RT_H2LE_U32(VCI_HDR_SIGNATURE);
1437 Hdr.u32Version = RT_H2LE_U32(VCI_HDR_VERSION);
1438 Hdr.cBlocksCache = RT_H2LE_U64(cBlocks);
1439 Hdr.fUncleanShutdown = VCI_HDR_UNCLEAN_SHUTDOWN;
1440 Hdr.u32CacheType = uImageFlags & VD_IMAGE_FLAGS_FIXED
1441 ? RT_H2LE_U32(VCI_HDR_CACHE_TYPE_FIXED)
1442 : RT_H2LE_U32(VCI_HDR_CACHE_TYPE_DYNAMIC);
1443 Hdr.offTreeRoot = RT_H2LE_U64(offTreeRoot);
1444 Hdr.offBlkMap = RT_H2LE_U64(offBlkMap);
1445 Hdr.cBlkMap = RT_H2LE_U64(cBlkMap);
1446
1447 rc = vciFileWriteSync(pCache, offHdr, &Hdr, VCI_BYTE2BLOCK(sizeof(VciHdr)));
1448 if (RT_FAILURE(rc))
1449 {
1450 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write header '%s'"), pCache->pszFilename);
1451 break;
1452 }
1453
1454 rc = vciBlkMapSave(pCache->pBlkMap, pCache, offBlkMap, cBlkMap);
1455 if (RT_FAILURE(rc))
1456 {
1457 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write block map '%s'"), pCache->pszFilename);
1458 break;
1459 }
1460
1461 /* Setup the root tree. */
1462 memset(&NodeRoot, 0, sizeof(VciTreeNode));
1463 NodeRoot.u8Type = RT_H2LE_U32(VCI_TREE_NODE_TYPE_LEAF);
1464
1465 rc = vciFileWriteSync(pCache, offTreeRoot, &NodeRoot, VCI_BYTE2BLOCK(sizeof(VciTreeNode)));
1466 if (RT_FAILURE(rc))
1467 {
1468 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot write root node '%s'"), pCache->pszFilename);
1469 break;
1470 }
1471
1472 rc = vciFlushImage(pCache);
1473 if (RT_FAILURE(rc))
1474 {
1475 rc = vciError(pCache, rc, RT_SRC_POS, N_("VCI: cannot flush '%s'"), pCache->pszFilename);
1476 break;
1477 }
1478
1479 pCache->cbSize = cbSize;
1480
1481 } while (0);
1482
1483 if (RT_SUCCESS(rc) && pfnProgress)
1484 pfnProgress(pvUser, uPercentStart + uPercentSpan);
1485
1486 if (RT_FAILURE(rc))
1487 vciFreeImage(pCache, rc != VERR_ALREADY_EXISTS);
1488 return rc;
1489}
1490
1491/** @copydoc VDCACHEBACKEND::pfnProbe */
1492static int vciProbe(const char *pszFilename, PVDINTERFACE pVDIfsCache,
1493 PVDINTERFACE pVDIfsImage)
1494{
1495 VciHdr Hdr;
1496 PVDIOSTORAGE pStorage;
1497 uint64_t cbFile;
1498 int rc = VINF_SUCCESS;
1499
1500 LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
1501
1502 /* Get I/O interface. */
1503 PVDINTERFACE pInterfaceIO = VDInterfaceGet(pVDIfsImage, VDINTERFACETYPE_IOINT);
1504 AssertPtrReturn(pInterfaceIO, VERR_INVALID_PARAMETER);
1505 PVDINTERFACEIOINT pInterfaceIOCallbacks = VDGetInterfaceIOInt(pInterfaceIO);
1506 AssertPtrReturn(pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
1507
1508 rc = pInterfaceIOCallbacks->pfnOpen(pInterfaceIO->pvUser, pszFilename,
1509 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
1510 false /* fCreate */),
1511 &pStorage);
1512 if (RT_FAILURE(rc))
1513 goto out;
1514
1515 rc = pInterfaceIOCallbacks->pfnGetSize(pInterfaceIO->pvUser, pStorage, &cbFile);
1516 if (RT_FAILURE(rc) || cbFile < sizeof(VciHdr))
1517 {
1518 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1519 rc = VERR_VD_GEN_INVALID_HEADER;
1520 goto out;
1521 }
1522
1523 rc = pInterfaceIOCallbacks->pfnReadSync(pInterfaceIO->pvUser, pStorage, 0, &Hdr, sizeof(Hdr), NULL);
1524 if (RT_FAILURE(rc))
1525 {
1526 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1527 rc = VERR_VD_GEN_INVALID_HEADER;
1528 goto out;
1529 }
1530
1531 Hdr.u32Signature = RT_LE2H_U32(Hdr.u32Signature);
1532 Hdr.u32Version = RT_LE2H_U32(Hdr.u32Version);
1533 Hdr.cBlocksCache = RT_LE2H_U64(Hdr.cBlocksCache);
1534 Hdr.u32CacheType = RT_LE2H_U32(Hdr.u32CacheType);
1535 Hdr.offTreeRoot = RT_LE2H_U64(Hdr.offTreeRoot);
1536 Hdr.offBlkMap = RT_LE2H_U64(Hdr.offBlkMap);
1537 Hdr.cBlkMap = RT_LE2H_U64(Hdr.cBlkMap);
1538
1539 if ( Hdr.u32Signature == VCI_HDR_SIGNATURE
1540 && Hdr.u32Version == VCI_HDR_VERSION)
1541 rc = VINF_SUCCESS;
1542 else
1543 rc = VERR_VD_GEN_INVALID_HEADER;
1544
1545 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
1546
1547out:
1548 LogFlowFunc(("returns %Rrc\n", rc));
1549 return rc;
1550}
1551
1552/** @copydoc VDCACHEBACKEND::pfnOpen */
1553static int vciOpen(const char *pszFilename, unsigned uOpenFlags,
1554 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1555 void **ppBackendData)
1556{
1557 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
1558 int rc;
1559 PVCICACHE pCache;
1560
1561 /* Check open flags. All valid flags are supported. */
1562 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1563 {
1564 rc = VERR_INVALID_PARAMETER;
1565 goto out;
1566 }
1567
1568 /* Check remaining arguments. */
1569 if ( !VALID_PTR(pszFilename)
1570 || !*pszFilename)
1571 {
1572 rc = VERR_INVALID_PARAMETER;
1573 goto out;
1574 }
1575
1576
1577 pCache = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1578 if (!pCache)
1579 {
1580 rc = VERR_NO_MEMORY;
1581 goto out;
1582 }
1583 pCache->pszFilename = pszFilename;
1584 pCache->pStorage = NULL;
1585 pCache->pVDIfsDisk = pVDIfsDisk;
1586 pCache->pVDIfsImage = pVDIfsImage;
1587
1588 rc = vciOpenImage(pCache, uOpenFlags);
1589 if (RT_SUCCESS(rc))
1590 *ppBackendData = pCache;
1591 else
1592 RTMemFree(pCache);
1593
1594out:
1595 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1596 return rc;
1597}
1598
1599/** @copydoc VDCACHEBACKEND::pfnCreate */
1600static int vciCreate(const char *pszFilename, uint64_t cbSize,
1601 unsigned uImageFlags, const char *pszComment,
1602 PCRTUUID pUuid, unsigned uOpenFlags,
1603 unsigned uPercentStart, unsigned uPercentSpan,
1604 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1605 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
1606{
1607 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",
1608 pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
1609 int rc;
1610 PVCICACHE pCache;
1611
1612 PFNVDPROGRESS pfnProgress = NULL;
1613 void *pvUser = NULL;
1614 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
1615 VDINTERFACETYPE_PROGRESS);
1616 PVDINTERFACEPROGRESS pCbProgress = NULL;
1617 if (pIfProgress)
1618 {
1619 pCbProgress = VDGetInterfaceProgress(pIfProgress);
1620 if (pCbProgress)
1621 pfnProgress = pCbProgress->pfnProgress;
1622 pvUser = pIfProgress->pvUser;
1623 }
1624
1625 /* Check open flags. All valid flags are supported. */
1626 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
1627 {
1628 rc = VERR_INVALID_PARAMETER;
1629 goto out;
1630 }
1631
1632 /* Check remaining arguments. */
1633 if ( !VALID_PTR(pszFilename)
1634 || !*pszFilename)
1635 {
1636 rc = VERR_INVALID_PARAMETER;
1637 goto out;
1638 }
1639
1640 pCache = (PVCICACHE)RTMemAllocZ(sizeof(VCICACHE));
1641 if (!pCache)
1642 {
1643 rc = VERR_NO_MEMORY;
1644 goto out;
1645 }
1646 pCache->pszFilename = pszFilename;
1647 pCache->pStorage = NULL;
1648 pCache->pVDIfsDisk = pVDIfsDisk;
1649 pCache->pVDIfsImage = pVDIfsImage;
1650
1651 rc = vciCreateImage(pCache, cbSize, uImageFlags, pszComment, uOpenFlags,
1652 pfnProgress, pvUser, uPercentStart, uPercentSpan);
1653 if (RT_SUCCESS(rc))
1654 {
1655 /* So far the image is opened in read/write mode. Make sure the
1656 * image is opened in read-only mode if the caller requested that. */
1657 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
1658 {
1659 vciFreeImage(pCache, false);
1660 rc = vciOpenImage(pCache, uOpenFlags);
1661 if (RT_FAILURE(rc))
1662 {
1663 RTMemFree(pCache);
1664 goto out;
1665 }
1666 }
1667 *ppBackendData = pCache;
1668 }
1669 else
1670 RTMemFree(pCache);
1671
1672out:
1673 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1674 return rc;
1675}
1676
1677/** @copydoc VDCACHEBACKEND::pfnClose */
1678static int vciClose(void *pBackendData, bool fDelete)
1679{
1680 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
1681 PVCICACHE pCache = (PVCICACHE)pBackendData;
1682 int rc;
1683
1684 rc = vciFreeImage(pCache, fDelete);
1685 RTMemFree(pCache);
1686
1687 LogFlowFunc(("returns %Rrc\n", rc));
1688 return rc;
1689}
1690
1691/** @copydoc VDCACHEBACKEND::pfnRead */
1692static int vciRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
1693 size_t cbToRead, size_t *pcbActuallyRead)
1694{
1695 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
1696 PVCICACHE pCache = (PVCICACHE)pBackendData;
1697 int rc = VINF_SUCCESS;
1698 PVCICACHEEXTENT pExtent;
1699
1700 AssertPtr(pCache);
1701 Assert(uOffset % 512 == 0);
1702 Assert(cbToRead % 512 == 0);
1703
1704
1705 pExtent = vciCacheExtentLookup(pCache, VCI_BYTE2BLOCK(uOffset));
1706 if (pExtent)
1707 {
1708 uint64_t offRead = uOffset - VCI_BLOCK2BYTE(pExtent->u64BlockOffset);
1709 cbToRead = RT_MIN(cbToRead, VCI_BLOCK2BYTE(pExtent->u32Blocks) - offRead);
1710
1711 rc = vciFileReadSync(pCache, VCI_BLOCK2BYTE(pExtent->u64BlockAddr) + offRead,
1712 pvBuf, cbToRead);
1713 }
1714 else
1715 {
1716 /** @todo Best fit to check whether we have cached data later and set
1717 * pcbActuallyRead accordingly. */
1718 rc = VERR_VD_BLOCK_FREE;
1719 }
1720
1721 if (pcbActuallyRead)
1722 *pcbActuallyRead = cbToRead;
1723
1724out:
1725 LogFlowFunc(("returns %Rrc\n", rc));
1726 return rc;
1727}
1728
1729/** @copydoc VDCACHEBACKEND::pfnWrite */
1730static int vciWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
1731 size_t cbToWrite, size_t *pcbWriteProcess)
1732{
1733 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
1734 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
1735 PVCICACHE pCache = (PVCICACHE)pBackendData;
1736 int rc = VINF_SUCCESS;
1737
1738 AssertPtr(pCache);
1739 Assert(uOffset % 512 == 0);
1740 Assert(cbToWrite % 512 == 0);
1741
1742out:
1743 LogFlowFunc(("returns %Rrc\n", rc));
1744 return rc;
1745}
1746
1747/** @copydoc VDCACHEBACKEND::pfnFlush */
1748static int vciFlush(void *pBackendData)
1749{
1750 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1751 PVCICACHE pCache = (PVCICACHE)pBackendData;
1752 int rc = VINF_SUCCESS;
1753
1754 rc = vciFlushImage(pCache);
1755 LogFlowFunc(("returns %Rrc\n", rc));
1756 return rc;
1757}
1758
1759/** @copydoc VDCACHEBACKEND::pfnGetVersion */
1760static unsigned vciGetVersion(void *pBackendData)
1761{
1762 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1763 PVCICACHE pCache = (PVCICACHE)pBackendData;
1764
1765 AssertPtr(pCache);
1766
1767 if (pCache)
1768 return 1;
1769 else
1770 return 0;
1771}
1772
1773/** @copydoc VDCACHEBACKEND::pfnGetSize */
1774static uint64_t vciGetSize(void *pBackendData)
1775{
1776 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1777 PVCICACHE pCache = (PVCICACHE)pBackendData;
1778 uint64_t cb = 0;
1779
1780 AssertPtr(pCache);
1781
1782 if (pCache && pCache->pStorage)
1783 cb = pCache->cbSize;
1784
1785 LogFlowFunc(("returns %llu\n", cb));
1786 return cb;
1787}
1788
1789/** @copydoc VDCACHEBACKEND::pfnGetFileSize */
1790static uint64_t vciGetFileSize(void *pBackendData)
1791{
1792 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1793 PVCICACHE pCache = (PVCICACHE)pBackendData;
1794 uint64_t cb = 0;
1795
1796 AssertPtr(pCache);
1797
1798 if (pCache)
1799 {
1800 uint64_t cbFile;
1801 if (pCache->pStorage)
1802 {
1803 int rc = vciFileGetSize(pCache, &cbFile);
1804 if (RT_SUCCESS(rc))
1805 cb = cbFile;
1806 }
1807 }
1808
1809 LogFlowFunc(("returns %lld\n", cb));
1810 return cb;
1811}
1812
1813/** @copydoc VDCACHEBACKEND::pfnGetImageFlags */
1814static unsigned vciGetImageFlags(void *pBackendData)
1815{
1816 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1817 PVCICACHE pCache = (PVCICACHE)pBackendData;
1818 unsigned uImageFlags;
1819
1820 AssertPtr(pCache);
1821
1822 if (pCache)
1823 uImageFlags = pCache->uImageFlags;
1824 else
1825 uImageFlags = 0;
1826
1827 LogFlowFunc(("returns %#x\n", uImageFlags));
1828 return uImageFlags;
1829}
1830
1831/** @copydoc VDCACHEBACKEND::pfnGetOpenFlags */
1832static unsigned vciGetOpenFlags(void *pBackendData)
1833{
1834 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1835 PVCICACHE pCache = (PVCICACHE)pBackendData;
1836 unsigned uOpenFlags;
1837
1838 AssertPtr(pCache);
1839
1840 if (pCache)
1841 uOpenFlags = pCache->uOpenFlags;
1842 else
1843 uOpenFlags = 0;
1844
1845 LogFlowFunc(("returns %#x\n", uOpenFlags));
1846 return uOpenFlags;
1847}
1848
1849/** @copydoc VDCACHEBACKEND::pfnSetOpenFlags */
1850static int vciSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
1851{
1852 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
1853 PVCICACHE pCache = (PVCICACHE)pBackendData;
1854 int rc;
1855
1856 /* Image must be opened and the new flags must be valid. Just readonly and
1857 * info flags are supported. */
1858 if (!pCache || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
1859 {
1860 rc = VERR_INVALID_PARAMETER;
1861 goto out;
1862 }
1863
1864 /* Implement this operation via reopening the image. */
1865 rc = vciFreeImage(pCache, false);
1866 if (RT_FAILURE(rc))
1867 goto out;
1868 rc = vciOpenImage(pCache, uOpenFlags);
1869
1870out:
1871 LogFlowFunc(("returns %Rrc\n", rc));
1872 return rc;
1873}
1874
1875/** @copydoc VDCACHEBACKEND::pfnGetComment */
1876static int vciGetComment(void *pBackendData, char *pszComment,
1877 size_t cbComment)
1878{
1879 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
1880 PVCICACHE pCache = (PVCICACHE)pBackendData;
1881 int rc;
1882
1883 AssertPtr(pCache);
1884
1885 if (pCache)
1886 rc = VERR_NOT_SUPPORTED;
1887 else
1888 rc = VERR_VD_NOT_OPENED;
1889
1890 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
1891 return rc;
1892}
1893
1894/** @copydoc VDCACHEBACKEND::pfnSetComment */
1895static int vciSetComment(void *pBackendData, const char *pszComment)
1896{
1897 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1898 PVCICACHE pCache = (PVCICACHE)pBackendData;
1899 int rc;
1900
1901 AssertPtr(pCache);
1902
1903 if (pCache)
1904 {
1905 if (pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1906 rc = VERR_VD_IMAGE_READ_ONLY;
1907 else
1908 rc = VERR_NOT_SUPPORTED;
1909 }
1910 else
1911 rc = VERR_VD_NOT_OPENED;
1912
1913out:
1914 LogFlowFunc(("returns %Rrc\n", rc));
1915 return rc;
1916}
1917
1918/** @copydoc VDCACHEBACKEND::pfnGetUuid */
1919static int vciGetUuid(void *pBackendData, PRTUUID pUuid)
1920{
1921 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1922 PVCICACHE pCache = (PVCICACHE)pBackendData;
1923 int rc;
1924
1925 AssertPtr(pCache);
1926
1927 if (pCache)
1928 rc = VERR_NOT_SUPPORTED;
1929 else
1930 rc = VERR_VD_NOT_OPENED;
1931
1932 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1933 return rc;
1934}
1935
1936/** @copydoc VDCACHEBACKEND::pfnSetUuid */
1937static int vciSetUuid(void *pBackendData, PCRTUUID pUuid)
1938{
1939 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1940 PVCICACHE pCache = (PVCICACHE)pBackendData;
1941 int rc;
1942
1943 LogFlowFunc(("%RTuuid\n", pUuid));
1944 AssertPtr(pCache);
1945
1946 if (pCache)
1947 {
1948 if (!(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1949 rc = VERR_NOT_SUPPORTED;
1950 else
1951 rc = VERR_VD_IMAGE_READ_ONLY;
1952 }
1953 else
1954 rc = VERR_VD_NOT_OPENED;
1955
1956 LogFlowFunc(("returns %Rrc\n", rc));
1957 return rc;
1958}
1959
1960/** @copydoc VDCACHEBACKEND::pfnGetModificationUuid */
1961static int vciGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1962{
1963 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1964 PVCICACHE pCache = (PVCICACHE)pBackendData;
1965 int rc;
1966
1967 AssertPtr(pCache);
1968
1969 if (pCache)
1970 rc = VERR_NOT_SUPPORTED;
1971 else
1972 rc = VERR_VD_NOT_OPENED;
1973
1974 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1975 return rc;
1976}
1977
1978/** @copydoc VDCACHEBACKEND::pfnSetModificationUuid */
1979static int vciSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1980{
1981 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1982 PVCICACHE pCache = (PVCICACHE)pBackendData;
1983 int rc;
1984
1985 AssertPtr(pCache);
1986
1987 if (pCache)
1988 {
1989 if (!(pCache->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1990 rc = VERR_NOT_SUPPORTED;
1991 else
1992 rc = VERR_VD_IMAGE_READ_ONLY;
1993 }
1994 else
1995 rc = VERR_VD_NOT_OPENED;
1996
1997 LogFlowFunc(("returns %Rrc\n", rc));
1998 return rc;
1999}
2000
2001/** @copydoc VDCACHEBACKEND::pfnDump */
2002static void vciDump(void *pBackendData)
2003{
2004 NOREF(pBackendData);
2005}
2006
2007/** @copydoc VDCACHEBACKEND::pfnAsyncRead */
2008static int vciAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
2009 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
2010{
2011 int rc = VERR_NOT_SUPPORTED;
2012 PVCICACHE pCache = (PVCICACHE)pBackendData;
2013
2014 return rc;
2015}
2016
2017/** @copydoc VDCACHEBACKEND::pfnAsyncWrite */
2018static int vciAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
2019 PVDIOCTX pIoCtx, size_t *pcbWriteProcess)
2020{
2021 int rc = VERR_NOT_SUPPORTED;
2022 PVCICACHE pCache = (PVCICACHE)pBackendData;
2023
2024 return rc;
2025}
2026
2027/** @copydoc VDCACHEBACKEND::pfnAsyncFlush */
2028static int vciAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
2029{
2030 int rc = VERR_NOT_SUPPORTED;
2031 PVCICACHE pCache = (PVCICACHE)pBackendData;
2032
2033 return rc;
2034}
2035
2036
2037VDCACHEBACKEND g_VciCacheBackend =
2038{
2039 /* pszBackendName */
2040 "vci",
2041 /* cbSize */
2042 sizeof(VDCACHEBACKEND),
2043 /* uBackendCaps */
2044 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_VFS,
2045 /* papszFileExtensions */
2046 s_apszVciFileExtensions,
2047 /* paConfigInfo */
2048 NULL,
2049 /* hPlugin */
2050 NIL_RTLDRMOD,
2051 /* pfnProbe */
2052 vciProbe,
2053 /* pfnOpen */
2054 vciOpen,
2055 /* pfnCreate */
2056 vciCreate,
2057 /* pfnClose */
2058 vciClose,
2059 /* pfnRead */
2060 vciRead,
2061 /* pfnWrite */
2062 vciWrite,
2063 /* pfnFlush */
2064 vciFlush,
2065 /* pfnGetVersion */
2066 vciGetVersion,
2067 /* pfnGetSize */
2068 vciGetSize,
2069 /* pfnGetFileSize */
2070 vciGetFileSize,
2071 /* pfnGetImageFlags */
2072 vciGetImageFlags,
2073 /* pfnGetOpenFlags */
2074 vciGetOpenFlags,
2075 /* pfnSetOpenFlags */
2076 vciSetOpenFlags,
2077 /* pfnGetComment */
2078 vciGetComment,
2079 /* pfnSetComment */
2080 vciSetComment,
2081 /* pfnGetUuid */
2082 vciGetUuid,
2083 /* pfnSetUuid */
2084 vciSetUuid,
2085 /* pfnGetModificationUuid */
2086 vciGetModificationUuid,
2087 /* pfnSetModificationUuid */
2088 vciSetModificationUuid,
2089 /* pfnDump */
2090 vciDump,
2091 /* pfnAsyncRead */
2092 vciAsyncRead,
2093 /* pfnAsyncWrite */
2094 vciAsyncWrite,
2095 /* pfnAsyncFlush */
2096 vciAsyncFlush,
2097 /* pfnComposeLocation */
2098 NULL,
2099 /* pfnComposeName */
2100 NULL
2101};
2102
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use