VirtualBox

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

Last change on this file since 56754 was 56754, checked in by vboxsync, 9 years ago

Storage: More minor memory leak fixes in testcases, unused code or rare taken error code paths found by Parfait

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