VirtualBox

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

Last change on this file since 54558 was 50988, checked in by vboxsync, 10 years ago

Storage/VD: Cleanup VD plugin handling. One shared object can now support an arbitrary number of image backends instead of just one like before

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