VirtualBox

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

Last change on this file since 93231 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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