VirtualBox

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

最後變更 在這個檔案從57358是 57358,由 vboxsync 提交於 10 年 前

*: scm cleanup run.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette