[33060] | 1 | /* $Id: VDIfVfs2.cpp 67182 2017-05-31 20:31:09Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[59601] | 3 | * Virtual Disk Image (VDI), I/O interface to IPRT VFS I/O stream glue.
|
---|
[33060] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[62482] | 7 | * Copyright (C) 2012-2016 Oracle Corporation
|
---|
[33060] | 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 |
|
---|
[57372] | 19 | /*********************************************************************************************************************************
|
---|
| 20 | * Header Files *
|
---|
| 21 | *********************************************************************************************************************************/
|
---|
[59601] | 22 | #include <iprt/types.h>
|
---|
| 23 | #include <iprt/assert.h>
|
---|
| 24 | #include <iprt/mem.h>
|
---|
| 25 | #include <iprt/err.h>
|
---|
[33060] | 26 | #include <iprt/asm.h>
|
---|
[59601] | 27 | #include <iprt/string.h>
|
---|
| 28 | #include <iprt/file.h>
|
---|
| 29 | #include <iprt/sg.h>
|
---|
| 30 | #include <iprt/vfslowlevel.h>
|
---|
| 31 | #include <iprt/poll.h>
|
---|
[33567] | 32 | #include <VBox/vd.h>
|
---|
[59601] | 33 | #include <VBox/vd-ifs-internal.h>
|
---|
[33060] | 34 |
|
---|
[59601] | 35 | #include <VBox/log.h>
|
---|
[50200] | 36 |
|
---|
| 37 |
|
---|
[57372] | 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Structures and Typedefs *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[59601] | 41 | /**
|
---|
| 42 | * Extended VD I/O interface structure that vdIfFromVfs_xxx uses.
|
---|
| 43 | *
|
---|
| 44 | * It's passed as pvUser to each call.
|
---|
| 45 | */
|
---|
| 46 | typedef struct VDIFFROMVFS
|
---|
[33060] | 47 | {
|
---|
[59601] | 48 | VDINTERFACEIO CoreIo;
|
---|
[33060] | 49 |
|
---|
[59601] | 50 | /** Magic. */
|
---|
| 51 | uint32_t u32Magic;
|
---|
| 52 | /** The stream access mode (RTFILE_O_ACCESS_MASK), possibly others. */
|
---|
| 53 | uint32_t fAccessMode;
|
---|
| 54 | /** The I/O stream. This is NIL after it's been closed. */
|
---|
| 55 | RTVFSIOSTREAM hVfsIos;
|
---|
[33060] | 56 | /** Completion callback. */
|
---|
[59601] | 57 | PFNVDCOMPLETED pfnCompleted;
|
---|
| 58 | /** User parameter for the completion callback. */
|
---|
| 59 | void *pvCompletedUser;
|
---|
| 60 | /** Set if hVfsIos has been opened. */
|
---|
| 61 | bool fOpened;
|
---|
| 62 | } VDIFFROMVFS;
|
---|
| 63 | /** Magic value for VDIFFROMVFS::u32Magic. */
|
---|
| 64 | #define VDIFFROMVFS_MAGIC UINT32_C(0x11223344)
|
---|
[33060] | 65 |
|
---|
[59601] | 66 | /** Pointer to the instance data for the vdIfFromVfs_ methods. */
|
---|
| 67 | typedef struct VDIFFROMVFS *PVDIFFROMVFS;
|
---|
[50200] | 68 |
|
---|
[59601] | 69 |
|
---|
| 70 | typedef struct FILESTORAGEINTERNAL
|
---|
[33060] | 71 | {
|
---|
[59601] | 72 | /** File handle. */
|
---|
| 73 | RTFILE file;
|
---|
| 74 | } FILESTORAGEINTERNAL, *PFILESTORAGEINTERNAL;
|
---|
[33060] | 75 |
|
---|
| 76 |
|
---|
[57372] | 77 | /*********************************************************************************************************************************
|
---|
| 78 | * Defined Constants And Macros *
|
---|
| 79 | *********************************************************************************************************************************/
|
---|
| 80 |
|
---|
[36015] | 81 | #define STATUS_WAIT UINT32_C(0)
|
---|
| 82 | #define STATUS_WRITE UINT32_C(1)
|
---|
| 83 | #define STATUS_WRITING UINT32_C(2)
|
---|
| 84 | #define STATUS_READ UINT32_C(3)
|
---|
| 85 | #define STATUS_READING UINT32_C(4)
|
---|
| 86 | #define STATUS_END UINT32_C(5)
|
---|
[33060] | 87 |
|
---|
| 88 | /* Enable for getting some flow history. */
|
---|
| 89 | #if 0
|
---|
| 90 | # define DEBUG_PRINT_FLOW() RTPrintf("%s\n", __FUNCTION__)
|
---|
| 91 | #else
|
---|
[45367] | 92 | # define DEBUG_PRINT_FLOW() do {} while (0)
|
---|
[33060] | 93 | #endif
|
---|
| 94 |
|
---|
| 95 |
|
---|
[57372] | 96 | /*********************************************************************************************************************************
|
---|
| 97 | * Internal Functions *
|
---|
| 98 | *********************************************************************************************************************************/
|
---|
[47516] | 99 |
|
---|
[57372] | 100 |
|
---|
[50200] | 101 | /** @name VDINTERFACEIO stubs returning not-implemented.
|
---|
| 102 | * @{
|
---|
| 103 | */
|
---|
| 104 |
|
---|
| 105 | /** @interface_method_impl{VDINTERFACEIO,pfnDelete} */
|
---|
| 106 | static DECLCALLBACK(int) notImpl_Delete(void *pvUser, const char *pcszFilename)
|
---|
| 107 | {
|
---|
| 108 | NOREF(pvUser); NOREF(pcszFilename);
|
---|
[59601] | 109 | Log(("%s\n", __FUNCTION__));
|
---|
[67182] | 110 | AssertFailed();
|
---|
[50200] | 111 | return VERR_NOT_IMPLEMENTED;
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | /** @interface_method_impl{VDINTERFACEIO,pfnMove} */
|
---|
| 115 | static DECLCALLBACK(int) notImpl_Move(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
|
---|
| 116 | {
|
---|
| 117 | NOREF(pvUser); NOREF(pcszSrc); NOREF(pcszDst); NOREF(fMove);
|
---|
[59601] | 118 | Log(("%s\n", __FUNCTION__));
|
---|
[67182] | 119 | AssertFailed();
|
---|
[50200] | 120 | return VERR_NOT_IMPLEMENTED;
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | /** @interface_method_impl{VDINTERFACEIO,pfnGetFreeSpace} */
|
---|
| 124 | static DECLCALLBACK(int) notImpl_GetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
|
---|
| 125 | {
|
---|
| 126 | NOREF(pvUser); NOREF(pcszFilename); NOREF(pcbFreeSpace);
|
---|
[59601] | 127 | Log(("%s\n", __FUNCTION__));
|
---|
[67182] | 128 | AssertFailed();
|
---|
[50200] | 129 | return VERR_NOT_IMPLEMENTED;
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | /** @interface_method_impl{VDINTERFACEIO,pfnGetModificationTime} */
|
---|
| 133 | static DECLCALLBACK(int) notImpl_GetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
|
---|
| 134 | {
|
---|
| 135 | NOREF(pvUser); NOREF(pcszFilename); NOREF(pModificationTime);
|
---|
[59601] | 136 | Log(("%s\n", __FUNCTION__));
|
---|
[67182] | 137 | AssertFailed();
|
---|
[50200] | 138 | return VERR_NOT_IMPLEMENTED;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | /** @interface_method_impl{VDINTERFACEIO,pfnSetSize} */
|
---|
| 142 | static DECLCALLBACK(int) notImpl_SetSize(void *pvUser, void *pvStorage, uint64_t cb)
|
---|
| 143 | {
|
---|
| 144 | NOREF(pvUser); NOREF(pvStorage); NOREF(cb);
|
---|
[59601] | 145 | Log(("%s\n", __FUNCTION__));
|
---|
[67182] | 146 | AssertFailed();
|
---|
[50200] | 147 | return VERR_NOT_IMPLEMENTED;
|
---|
| 148 | }
|
---|
| 149 |
|
---|
[62873] | 150 | #if 0 /* unused */
|
---|
[50200] | 151 | /** @interface_method_impl{VDINTERFACEIO,pfnWriteSync} */
|
---|
[51092] | 152 | static DECLCALLBACK(int) notImpl_WriteSync(void *pvUser, void *pvStorage, uint64_t off, const void *pvBuf,
|
---|
| 153 | size_t cbWrite, size_t *pcbWritten)
|
---|
[50200] | 154 | {
|
---|
[62873] | 155 | RT_NOREF6(pvUser, pvStorage, off, pvBuf, cbWrite, pcbWritten)
|
---|
[59601] | 156 | Log(("%s\n", __FUNCTION__));
|
---|
[50200] | 157 | return VERR_NOT_IMPLEMENTED;
|
---|
| 158 | }
|
---|
[62873] | 159 | #endif
|
---|
[50200] | 160 |
|
---|
| 161 | /** @interface_method_impl{VDINTERFACEIO,pfnFlushSync} */
|
---|
| 162 | static DECLCALLBACK(int) notImpl_FlushSync(void *pvUser, void *pvStorage)
|
---|
| 163 | {
|
---|
| 164 | NOREF(pvUser); NOREF(pvStorage);
|
---|
[59601] | 165 | Log(("%s\n", __FUNCTION__));
|
---|
[67182] | 166 | AssertFailed();
|
---|
[50200] | 167 | return VERR_NOT_IMPLEMENTED;
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | /** @} */
|
---|
| 171 |
|
---|
| 172 |
|
---|
[59601] | 173 | /** @interface_method_impl{VDINTERFACEIO,pfnOpen} */
|
---|
| 174 | static DECLCALLBACK(int) vdIfFromVfs_Open(void *pvUser, const char *pszLocation, uint32_t fOpen,
|
---|
[64272] | 175 | PFNVDCOMPLETED pfnCompleted, void **ppvStorage)
|
---|
[33060] | 176 | {
|
---|
[62729] | 177 | RT_NOREF1(pszLocation);
|
---|
[59601] | 178 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)pvUser;
|
---|
[33060] | 179 |
|
---|
[50204] | 180 | /*
|
---|
[50200] | 181 | * Validate input.
|
---|
| 182 | */
|
---|
[64272] | 183 | AssertPtrReturn(ppvStorage, VERR_INVALID_POINTER);
|
---|
[50200] | 184 | AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
|
---|
| 185 |
|
---|
| 186 | /*
|
---|
[59601] | 187 | * We ignore the name, assuming the caller is opening the stream/file we're .
|
---|
| 188 | * serving. Thus, after close, all open calls fail.
|
---|
[50200] | 189 | */
|
---|
[59601] | 190 | AssertReturn(!pThis->fOpened, VERR_FILE_NOT_FOUND);
|
---|
| 191 | AssertReturn(pThis->hVfsIos != NIL_RTVFSIOSTREAM, VERR_FILE_NOT_FOUND); /* paranoia */
|
---|
| 192 | AssertMsgReturn((pThis->fAccessMode & fOpen & RTFILE_O_ACCESS_MASK) == (fOpen & RTFILE_O_ACCESS_MASK),
|
---|
| 193 | ("fAccessMode=%#x fOpen=%#x\n", pThis->fAccessMode, fOpen), VERR_ACCESS_DENIED);
|
---|
[50200] | 194 |
|
---|
[59601] | 195 | pThis->fAccessMode = fOpen & RTFILE_O_ACCESS_MASK;
|
---|
| 196 | pThis->fOpened = true;
|
---|
| 197 | pThis->pfnCompleted = pfnCompleted;
|
---|
| 198 | pThis->pvCompletedUser = pvUser;
|
---|
[50200] | 199 |
|
---|
[64272] | 200 | *ppvStorage = pThis->hVfsIos;
|
---|
[59601] | 201 | return VINF_SUCCESS;
|
---|
[50200] | 202 | }
|
---|
| 203 |
|
---|
| 204 | /** @interface_method_impl{VDINTERFACEIO,pfnClose} */
|
---|
[59601] | 205 | static DECLCALLBACK(int) vdIfFromVfs_Close(void *pvUser, void *pvStorage)
|
---|
[50200] | 206 | {
|
---|
[59601] | 207 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)pvUser;
|
---|
| 208 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
[59610] | 209 | AssertReturn(pThis->hVfsIos == (RTVFSIOSTREAM)pvStorage, VERR_INVALID_HANDLE);
|
---|
[59601] | 210 | AssertReturn(pThis->fOpened, VERR_INVALID_HANDLE);
|
---|
[50200] | 211 |
|
---|
[62729] | 212 | RTVfsIoStrmRelease(pThis->hVfsIos);
|
---|
[59601] | 213 | pThis->hVfsIos = NIL_RTVFSIOSTREAM;
|
---|
[50200] | 214 |
|
---|
[59601] | 215 | return VINF_SUCCESS;
|
---|
[50200] | 216 | }
|
---|
| 217 |
|
---|
| 218 |
|
---|
| 219 | /** @interface_method_impl{VDINTERFACEIO,pfnGetSize} */
|
---|
[59601] | 220 | static DECLCALLBACK(int) vdIfFromVfs_GetSize(void *pvUser, void *pvStorage, uint64_t *pcb)
|
---|
[50200] | 221 | {
|
---|
[59601] | 222 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)pvUser;
|
---|
| 223 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
[59610] | 224 | AssertReturn(pThis->hVfsIos == (RTVFSIOSTREAM)pvStorage, VERR_INVALID_HANDLE);
|
---|
[59601] | 225 | AssertReturn(pThis->fOpened, VERR_INVALID_HANDLE);
|
---|
[50200] | 226 |
|
---|
| 227 | RTFSOBJINFO ObjInfo;
|
---|
[59601] | 228 | int rc = RTVfsIoStrmQueryInfo(pThis->hVfsIos, &ObjInfo, RTFSOBJATTRADD_NOTHING);
|
---|
[50200] | 229 | if (RT_SUCCESS(rc))
|
---|
| 230 | *pcb = ObjInfo.cbObject;
|
---|
| 231 | return rc;
|
---|
| 232 | }
|
---|
| 233 |
|
---|
[58132] | 234 | /** @interface_method_impl{VDINTERFACEIO,pfnReadSync} */
|
---|
[59601] | 235 | static DECLCALLBACK(int) vdIfFromVfs_ReadSync(void *pvUser, void *pvStorage, uint64_t off, void *pvBuf,
|
---|
| 236 | size_t cbToRead, size_t *pcbRead)
|
---|
[50200] | 237 | {
|
---|
[59601] | 238 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)pvUser;
|
---|
| 239 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
[59610] | 240 | AssertReturn(pThis->hVfsIos == (RTVFSIOSTREAM)pvStorage, VERR_INVALID_HANDLE);
|
---|
[59601] | 241 | AssertReturn(pThis->fOpened, VERR_INVALID_HANDLE);
|
---|
[50200] | 242 | AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
|
---|
[59601] | 243 | AssertReturn(pThis->fAccessMode & RTFILE_O_READ, VERR_ACCESS_DENIED);
|
---|
[50200] | 244 |
|
---|
[59601] | 245 | return RTVfsIoStrmReadAt(pThis->hVfsIos, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
|
---|
[50200] | 246 | }
|
---|
| 247 |
|
---|
| 248 |
|
---|
[59601] | 249 | /** @interface_method_impl{VDINTERFACEIO,pfnWriteSync} */
|
---|
| 250 | static DECLCALLBACK(int) vdIfFromVfs_WriteSync(void *pvUser, void *pvStorage, uint64_t off, void const *pvBuf,
|
---|
| 251 | size_t cbToWrite, size_t *pcbWritten)
|
---|
[50200] | 252 | {
|
---|
[59601] | 253 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)pvUser;
|
---|
| 254 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
[59610] | 255 | AssertReturn(pThis->hVfsIos == (RTVFSIOSTREAM)pvStorage, VERR_INVALID_HANDLE);
|
---|
[59601] | 256 | AssertReturn(pThis->fOpened, VERR_INVALID_HANDLE);
|
---|
| 257 | AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
|
---|
| 258 | AssertReturn(pThis->fAccessMode & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
|
---|
[56307] | 259 |
|
---|
[59601] | 260 | return RTVfsIoStrmWriteAt(pThis->hVfsIos, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
|
---|
[50200] | 261 | }
|
---|
| 262 |
|
---|
| 263 |
|
---|
[59601] | 264 | VBOXDDU_DECL(int) VDIfCreateFromVfsStream(RTVFSIOSTREAM hVfsIos, uint32_t fAccessMode, PVDINTERFACEIO *ppIoIf)
|
---|
[50200] | 265 | {
|
---|
[59601] | 266 | /*
|
---|
| 267 | * Validate input.
|
---|
| 268 | */
|
---|
| 269 | AssertPtrReturn(ppIoIf, VERR_INVALID_POINTER);
|
---|
| 270 | *ppIoIf = NULL;
|
---|
| 271 | AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
|
---|
| 272 | AssertReturn(fAccessMode & RTFILE_O_ACCESS_MASK, VERR_INVALID_FLAGS);
|
---|
[50200] | 273 |
|
---|
[59601] | 274 | uint32_t cRefs = RTVfsIoStrmRetain(hVfsIos);
|
---|
| 275 | AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
|
---|
[50200] | 276 |
|
---|
[59601] | 277 | /*
|
---|
| 278 | * Allocate and init a callback + instance data structure.
|
---|
| 279 | */
|
---|
| 280 | int rc;
|
---|
| 281 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)RTMemAllocZ(sizeof(*pThis));
|
---|
| 282 | if (pThis)
|
---|
[59555] | 283 | {
|
---|
[59601] | 284 | pThis->CoreIo.pfnOpen = vdIfFromVfs_Open;
|
---|
| 285 | pThis->CoreIo.pfnClose = vdIfFromVfs_Close;
|
---|
| 286 | pThis->CoreIo.pfnDelete = notImpl_Delete;
|
---|
| 287 | pThis->CoreIo.pfnMove = notImpl_Move;
|
---|
| 288 | pThis->CoreIo.pfnGetFreeSpace = notImpl_GetFreeSpace;
|
---|
| 289 | pThis->CoreIo.pfnGetModificationTime = notImpl_GetModificationTime;
|
---|
| 290 | pThis->CoreIo.pfnGetSize = vdIfFromVfs_GetSize;
|
---|
| 291 | pThis->CoreIo.pfnSetSize = notImpl_SetSize;
|
---|
| 292 | pThis->CoreIo.pfnReadSync = vdIfFromVfs_ReadSync;
|
---|
| 293 | pThis->CoreIo.pfnWriteSync = vdIfFromVfs_WriteSync;
|
---|
| 294 | pThis->CoreIo.pfnFlushSync = notImpl_FlushSync;
|
---|
[50200] | 295 |
|
---|
[59601] | 296 | pThis->hVfsIos = hVfsIos;
|
---|
| 297 | pThis->fAccessMode = fAccessMode;
|
---|
| 298 | pThis->fOpened = false;
|
---|
| 299 | pThis->u32Magic = VDIFFROMVFS_MAGIC;
|
---|
[59555] | 300 |
|
---|
[59601] | 301 | PVDINTERFACE pFakeList = NULL;
|
---|
| 302 | rc = VDInterfaceAdd(&pThis->CoreIo.Core, "FromVfsStream", VDINTERFACETYPE_IO, pThis, sizeof(pThis->CoreIo), &pFakeList);
|
---|
| 303 | if (RT_SUCCESS(rc))
|
---|
[59555] | 304 | {
|
---|
[59601] | 305 | *ppIoIf = &pThis->CoreIo;
|
---|
| 306 | return VINF_SUCCESS;
|
---|
[59555] | 307 | }
|
---|
| 308 |
|
---|
[59601] | 309 | RTMemFree(pThis);
|
---|
[50200] | 310 | }
|
---|
[59601] | 311 | else
|
---|
| 312 | rc = VERR_NO_MEMORY;
|
---|
| 313 | RTVfsIoStrmRelease(hVfsIos);
|
---|
[33060] | 314 | return rc;
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 |
|
---|
[59601] | 318 | VBOXDDU_DECL(int) VDIfDestroyFromVfsStream(PVDINTERFACEIO pIoIf)
|
---|
[33060] | 319 | {
|
---|
[59601] | 320 | if (pIoIf)
|
---|
[33060] | 321 | {
|
---|
[59601] | 322 | PVDIFFROMVFS pThis = (PVDIFFROMVFS)pIoIf;
|
---|
| 323 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
| 324 | AssertReturn(pThis->u32Magic == VDIFFROMVFS_MAGIC, VERR_INVALID_MAGIC);
|
---|
[33060] | 325 |
|
---|
[59601] | 326 | if (pThis->hVfsIos != NIL_RTVFSIOSTREAM)
|
---|
[33060] | 327 | {
|
---|
[59601] | 328 | RTVfsIoStrmRelease(pThis->hVfsIos);
|
---|
| 329 | pThis->hVfsIos = NIL_RTVFSIOSTREAM;
|
---|
[33060] | 330 | }
|
---|
[59601] | 331 | pThis->u32Magic = ~VDIFFROMVFS_MAGIC;
|
---|
[33060] | 332 | }
|
---|
| 333 | return VINF_SUCCESS;
|
---|
| 334 | }
|
---|
| 335 |
|
---|