VirtualBox

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

Last change on this file since 64226 was 63905, checked in by vboxsync, 8 years ago

Storage/VD: Add proper versioning of the backend structures instead of just relying on the structure size to make changing callback signatures possible in the future and still being able to reject incompatible plugins

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

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