VirtualBox

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

Last change on this file since 40107 was 38469, checked in by vboxsync, 13 years ago

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

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