[41576] | 1 | /* $Id: VDVfs.cpp 67207 2017-06-01 13:16:02Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * Virtual Disk Container implementation. - VFS glue.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[62482] | 7 | * Copyright (C) 2012-2016 Oracle Corporation
|
---|
[41576] | 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 |
|
---|
[57358] | 19 | /*********************************************************************************************************************************
|
---|
| 20 | * Header Files *
|
---|
| 21 | *********************************************************************************************************************************/
|
---|
[41576] | 22 | #include <iprt/types.h>
|
---|
| 23 | #include <iprt/assert.h>
|
---|
| 24 | #include <iprt/mem.h>
|
---|
| 25 | #include <iprt/err.h>
|
---|
| 26 | #include <iprt/asm.h>
|
---|
| 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>
|
---|
| 32 | #include <VBox/vd.h>
|
---|
| 33 |
|
---|
| 34 |
|
---|
[57358] | 35 | /*********************************************************************************************************************************
|
---|
| 36 | * Structures and Typedefs *
|
---|
| 37 | *********************************************************************************************************************************/
|
---|
| 38 |
|
---|
[41576] | 39 | /**
|
---|
| 40 | * The internal data of a DVM volume I/O stream.
|
---|
| 41 | */
|
---|
| 42 | typedef struct VDVFSFILE
|
---|
| 43 | {
|
---|
| 44 | /** The volume the VFS file belongs to. */
|
---|
[66250] | 45 | PVDISK pDisk;
|
---|
[41576] | 46 | /** Current position. */
|
---|
| 47 | uint64_t offCurPos;
|
---|
| 48 | /** Flags given during creation. */
|
---|
| 49 | uint32_t fFlags;
|
---|
| 50 | } VDVFSFILE;
|
---|
| 51 | /** Pointer to a the internal data of a DVM volume file. */
|
---|
| 52 | typedef VDVFSFILE *PVDVFSFILE;
|
---|
| 53 |
|
---|
| 54 | /**
|
---|
| 55 | * VD read helper taking care of unaligned accesses.
|
---|
| 56 | *
|
---|
| 57 | * @return VBox status code.
|
---|
| 58 | * @param pDisk VD disk container.
|
---|
| 59 | * @param off Offset to start reading from.
|
---|
| 60 | * @param pvBuf Pointer to the buffer to read into.
|
---|
| 61 | * @param cbRead Amount of bytes to read.
|
---|
| 62 | */
|
---|
[66250] | 63 | static int vdReadHelper(PVDISK pDisk, uint64_t off, void *pvBuf, size_t cbRead)
|
---|
[41576] | 64 | {
|
---|
| 65 | int rc = VINF_SUCCESS;
|
---|
| 66 |
|
---|
| 67 | /* Take shortcut if possible. */
|
---|
| 68 | if ( off % 512 == 0
|
---|
| 69 | && cbRead % 512 == 0)
|
---|
| 70 | rc = VDRead(pDisk, off, pvBuf, cbRead);
|
---|
| 71 | else
|
---|
| 72 | {
|
---|
| 73 | uint8_t *pbBuf = (uint8_t *)pvBuf;
|
---|
| 74 | uint8_t abBuf[512];
|
---|
| 75 |
|
---|
| 76 | /* Unaligned access, make it aligned. */
|
---|
| 77 | if (off % 512 != 0)
|
---|
| 78 | {
|
---|
| 79 | uint64_t offAligned = off & ~(uint64_t)(512 - 1);
|
---|
| 80 | size_t cbToCopy = 512 - (off - offAligned);
|
---|
| 81 | rc = VDRead(pDisk, offAligned, abBuf, 512);
|
---|
| 82 | if (RT_SUCCESS(rc))
|
---|
| 83 | {
|
---|
| 84 | memcpy(pbBuf, &abBuf[off - offAligned], cbToCopy);
|
---|
| 85 | pbBuf += cbToCopy;
|
---|
| 86 | off += cbToCopy;
|
---|
| 87 | cbRead -= cbToCopy;
|
---|
| 88 | }
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 | if ( RT_SUCCESS(rc)
|
---|
| 92 | && (cbRead & ~(uint64_t)(512 - 1)))
|
---|
| 93 | {
|
---|
| 94 | size_t cbReadAligned = cbRead & ~(uint64_t)(512 - 1);
|
---|
| 95 |
|
---|
| 96 | Assert(!(off % 512));
|
---|
| 97 | rc = VDRead(pDisk, off, pbBuf, cbReadAligned);
|
---|
| 98 | if (RT_SUCCESS(rc))
|
---|
| 99 | {
|
---|
| 100 | pbBuf += cbReadAligned;
|
---|
| 101 | off += cbReadAligned;
|
---|
| 102 | cbRead -= cbReadAligned;
|
---|
| 103 | }
|
---|
| 104 | }
|
---|
| 105 |
|
---|
| 106 | if ( RT_SUCCESS(rc)
|
---|
| 107 | && cbRead)
|
---|
| 108 | {
|
---|
| 109 | Assert(cbRead < 512);
|
---|
| 110 | Assert(!(off % 512));
|
---|
| 111 |
|
---|
| 112 | rc = VDRead(pDisk, off, abBuf, 512);
|
---|
| 113 | if (RT_SUCCESS(rc))
|
---|
| 114 | memcpy(pbBuf, abBuf, cbRead);
|
---|
| 115 | }
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | return rc;
|
---|
| 119 | }
|
---|
| 120 |
|
---|
| 121 |
|
---|
| 122 | /**
|
---|
| 123 | * VD write helper taking care of unaligned accesses.
|
---|
| 124 | *
|
---|
| 125 | * @return VBox status code.
|
---|
| 126 | * @param pDisk VD disk container.
|
---|
| 127 | * @param off Offset to start writing to.
|
---|
| 128 | * @param pvBuf Pointer to the buffer to read from.
|
---|
| 129 | * @param cbWrite Amount of bytes to write.
|
---|
| 130 | */
|
---|
[66250] | 131 | static int vdWriteHelper(PVDISK pDisk, uint64_t off, const void *pvBuf, size_t cbWrite)
|
---|
[41576] | 132 | {
|
---|
| 133 | int rc = VINF_SUCCESS;
|
---|
| 134 |
|
---|
| 135 | /* Take shortcut if possible. */
|
---|
| 136 | if ( off % 512 == 0
|
---|
| 137 | && cbWrite % 512 == 0)
|
---|
| 138 | rc = VDWrite(pDisk, off, pvBuf, cbWrite);
|
---|
| 139 | else
|
---|
| 140 | {
|
---|
| 141 | uint8_t *pbBuf = (uint8_t *)pvBuf;
|
---|
| 142 | uint8_t abBuf[512];
|
---|
| 143 |
|
---|
| 144 | /* Unaligned access, make it aligned. */
|
---|
| 145 | if (off % 512 != 0)
|
---|
| 146 | {
|
---|
| 147 | uint64_t offAligned = off & ~(uint64_t)(512 - 1);
|
---|
| 148 | size_t cbToCopy = 512 - (off - offAligned);
|
---|
| 149 | rc = VDRead(pDisk, offAligned, abBuf, 512);
|
---|
| 150 | if (RT_SUCCESS(rc))
|
---|
| 151 | {
|
---|
| 152 | memcpy(&abBuf[off - offAligned], pbBuf, cbToCopy);
|
---|
| 153 | rc = VDWrite(pDisk, offAligned, abBuf, 512);
|
---|
| 154 |
|
---|
| 155 | pbBuf += cbToCopy;
|
---|
| 156 | off += cbToCopy;
|
---|
| 157 | cbWrite -= cbToCopy;
|
---|
| 158 | }
|
---|
| 159 | }
|
---|
| 160 |
|
---|
| 161 | if ( RT_SUCCESS(rc)
|
---|
| 162 | && (cbWrite & ~(uint64_t)(512 - 1)))
|
---|
| 163 | {
|
---|
| 164 | size_t cbWriteAligned = cbWrite & ~(uint64_t)(512 - 1);
|
---|
| 165 |
|
---|
| 166 | Assert(!(off % 512));
|
---|
| 167 | rc = VDWrite(pDisk, off, pbBuf, cbWriteAligned);
|
---|
| 168 | if (RT_SUCCESS(rc))
|
---|
| 169 | {
|
---|
| 170 | pbBuf += cbWriteAligned;
|
---|
| 171 | off += cbWriteAligned;
|
---|
| 172 | cbWrite -= cbWriteAligned;
|
---|
| 173 | }
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | if ( RT_SUCCESS(rc)
|
---|
| 177 | && cbWrite)
|
---|
| 178 | {
|
---|
| 179 | Assert(cbWrite < 512);
|
---|
| 180 | Assert(!(off % 512));
|
---|
| 181 |
|
---|
| 182 | rc = VDRead(pDisk, off, abBuf, 512);
|
---|
| 183 | if (RT_SUCCESS(rc))
|
---|
| 184 | {
|
---|
| 185 | memcpy(abBuf, pbBuf, cbWrite);
|
---|
| 186 | rc = VDWrite(pDisk, off, abBuf, 512);
|
---|
| 187 | }
|
---|
| 188 | }
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | return rc;
|
---|
| 192 | }
|
---|
| 193 |
|
---|
| 194 |
|
---|
| 195 | /**
|
---|
| 196 | * @interface_method_impl{RTVFSOBJOPS,pfnClose}
|
---|
| 197 | */
|
---|
| 198 | static DECLCALLBACK(int) vdVfsFile_Close(void *pvThis)
|
---|
| 199 | {
|
---|
| 200 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 201 |
|
---|
| 202 | if (pThis->fFlags & VD_VFSFILE_DESTROY_ON_RELEASE)
|
---|
| 203 | VDDestroy(pThis->pDisk);
|
---|
| 204 |
|
---|
| 205 | return VINF_SUCCESS;
|
---|
| 206 | }
|
---|
| 207 |
|
---|
| 208 |
|
---|
| 209 | /**
|
---|
| 210 | * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
|
---|
| 211 | */
|
---|
[67207] | 212 | static DECLCALLBACK(int) vdVfsFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
|
---|
[41576] | 213 | {
|
---|
[67207] | 214 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 215 | unsigned const cOpenImages = VDGetCount(pThis->pDisk);
|
---|
| 216 |
|
---|
| 217 | pObjInfo->cbObject = VDGetSize(pThis->pDisk, cOpenImages - 1);
|
---|
| 218 | pObjInfo->cbAllocated = 0;
|
---|
| 219 | for (unsigned iImage = 0; iImage < cOpenImages; iImage++)
|
---|
| 220 | pObjInfo->cbAllocated += VDGetFileSize(pThis->pDisk, iImage);
|
---|
| 221 |
|
---|
| 222 | /** @todo enumerate the disk images directly... */
|
---|
| 223 | RTTimeNow(&pObjInfo->AccessTime);
|
---|
| 224 | pObjInfo->BirthTime = pObjInfo->AccessTime;
|
---|
| 225 | pObjInfo->ChangeTime = pObjInfo->AccessTime;
|
---|
| 226 | pObjInfo->ModificationTime = pObjInfo->AccessTime;
|
---|
| 227 |
|
---|
| 228 | pObjInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0644;
|
---|
| 229 | pObjInfo->Attr.enmAdditional = enmAddAttr;
|
---|
| 230 | switch (enmAddAttr)
|
---|
| 231 | {
|
---|
| 232 | case RTFSOBJATTRADD_UNIX:
|
---|
| 233 | pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
|
---|
| 234 | pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
|
---|
| 235 | pObjInfo->Attr.u.Unix.cHardlinks = 1;
|
---|
| 236 | pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
|
---|
| 237 | pObjInfo->Attr.u.Unix.INodeId = 0;
|
---|
| 238 | pObjInfo->Attr.u.Unix.fFlags = 0;
|
---|
| 239 | pObjInfo->Attr.u.Unix.GenerationId = 0;
|
---|
| 240 | pObjInfo->Attr.u.Unix.Device = 0;
|
---|
| 241 | break;
|
---|
| 242 |
|
---|
| 243 | case RTFSOBJATTRADD_UNIX_OWNER:
|
---|
| 244 | pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID;
|
---|
| 245 | pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
|
---|
| 246 | break;
|
---|
| 247 | case RTFSOBJATTRADD_UNIX_GROUP:
|
---|
| 248 | pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID;
|
---|
| 249 | pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
|
---|
| 250 | break;
|
---|
| 251 | case RTFSOBJATTRADD_EASIZE:
|
---|
| 252 | pObjInfo->Attr.u.EASize.cb = 0;
|
---|
| 253 | break;
|
---|
| 254 |
|
---|
| 255 | default:
|
---|
| 256 | AssertFailedReturn(VERR_INVALID_PARAMETER);
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | return VINF_SUCCESS;
|
---|
[41576] | 260 | }
|
---|
| 261 |
|
---|
| 262 |
|
---|
| 263 | /**
|
---|
| 264 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
|
---|
| 265 | */
|
---|
| 266 | static DECLCALLBACK(int) vdVfsFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
|
---|
| 267 | {
|
---|
| 268 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 269 |
|
---|
| 270 | Assert(pSgBuf->cSegs == 1);
|
---|
| 271 | NOREF(fBlocking);
|
---|
| 272 |
|
---|
| 273 | /*
|
---|
| 274 | * Find the current position and check if it's within the volume.
|
---|
| 275 | */
|
---|
| 276 | uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
|
---|
[67207] | 277 | uint64_t const cbImage = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
|
---|
| 278 | if (offUnsigned >= cbImage)
|
---|
[41576] | 279 | {
|
---|
| 280 | if (pcbRead)
|
---|
| 281 | {
|
---|
| 282 | *pcbRead = 0;
|
---|
[67207] | 283 | pThis->offCurPos = cbImage;
|
---|
[41576] | 284 | return VINF_EOF;
|
---|
| 285 | }
|
---|
| 286 | return VERR_EOF;
|
---|
| 287 | }
|
---|
| 288 |
|
---|
[67207] | 289 | int rc = VINF_SUCCESS;
|
---|
| 290 | size_t cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
|
---|
| 291 | if (offUnsigned + cbLeftToRead <= cbImage)
|
---|
[41576] | 292 | {
|
---|
[67207] | 293 | if (pcbRead)
|
---|
| 294 | *pcbRead = cbLeftToRead;
|
---|
[41576] | 295 | }
|
---|
| 296 | else
|
---|
| 297 | {
|
---|
[67207] | 298 | if (!pcbRead)
|
---|
| 299 | return VERR_EOF;
|
---|
| 300 | *pcbRead = cbLeftToRead = (size_t)(cbImage - offUnsigned);
|
---|
| 301 | rc = VINF_EOF;
|
---|
[41576] | 302 | }
|
---|
| 303 |
|
---|
| 304 | /*
|
---|
| 305 | * Ok, we've got a valid stretch within the file. Do the reading.
|
---|
| 306 | */
|
---|
| 307 | if (cbLeftToRead > 0)
|
---|
| 308 | {
|
---|
[67207] | 309 | int rc2 = vdReadHelper(pThis->pDisk, offUnsigned, pSgBuf->paSegs[0].pvSeg, cbLeftToRead);
|
---|
| 310 | if (RT_SUCCESS(rc2))
|
---|
[41576] | 311 | offUnsigned += cbLeftToRead;
|
---|
[67207] | 312 | else
|
---|
| 313 | rc = rc2;
|
---|
[41576] | 314 | }
|
---|
| 315 |
|
---|
| 316 | pThis->offCurPos = offUnsigned;
|
---|
| 317 | return rc;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 |
|
---|
| 321 | /**
|
---|
| 322 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
|
---|
| 323 | */
|
---|
| 324 | static DECLCALLBACK(int) vdVfsFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
|
---|
| 325 | {
|
---|
| 326 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 327 |
|
---|
| 328 | Assert(pSgBuf->cSegs == 1);
|
---|
| 329 | NOREF(fBlocking);
|
---|
| 330 |
|
---|
| 331 | /*
|
---|
| 332 | * Find the current position and check if it's within the volume.
|
---|
| 333 | * Writing beyond the end of a volume is not supported.
|
---|
| 334 | */
|
---|
| 335 | uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
|
---|
[67207] | 336 | uint64_t const cbImage = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
|
---|
| 337 | if (offUnsigned >= cbImage)
|
---|
[41576] | 338 | {
|
---|
| 339 | if (pcbWritten)
|
---|
| 340 | {
|
---|
| 341 | *pcbWritten = 0;
|
---|
[67207] | 342 | pThis->offCurPos = cbImage;
|
---|
[41576] | 343 | }
|
---|
[67207] | 344 | return VERR_EOF;
|
---|
[41576] | 345 | }
|
---|
| 346 |
|
---|
| 347 | size_t cbLeftToWrite;
|
---|
[67207] | 348 | if (offUnsigned + pSgBuf->paSegs[0].cbSeg < cbImage)
|
---|
[41576] | 349 | {
|
---|
| 350 | cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
|
---|
| 351 | if (pcbWritten)
|
---|
| 352 | *pcbWritten = cbLeftToWrite;
|
---|
| 353 | }
|
---|
[67207] | 354 | else
|
---|
| 355 | {
|
---|
| 356 | if (!pcbWritten)
|
---|
| 357 | return VERR_EOF;
|
---|
| 358 | *pcbWritten = cbLeftToWrite = (size_t)(cbImage - offUnsigned);
|
---|
| 359 | }
|
---|
[41576] | 360 |
|
---|
| 361 | /*
|
---|
| 362 | * Ok, we've got a valid stretch within the file. Do the reading.
|
---|
| 363 | */
|
---|
[67207] | 364 | int rc = VINF_SUCCESS;
|
---|
[41576] | 365 | if (cbLeftToWrite > 0)
|
---|
| 366 | {
|
---|
[67207] | 367 | rc = vdWriteHelper(pThis->pDisk, offUnsigned, pSgBuf->paSegs[0].pvSeg, cbLeftToWrite);
|
---|
[41576] | 368 | if (RT_SUCCESS(rc))
|
---|
| 369 | offUnsigned += cbLeftToWrite;
|
---|
| 370 | }
|
---|
| 371 |
|
---|
| 372 | pThis->offCurPos = offUnsigned;
|
---|
| 373 | return rc;
|
---|
| 374 | }
|
---|
| 375 |
|
---|
| 376 |
|
---|
| 377 | /**
|
---|
| 378 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
|
---|
| 379 | */
|
---|
| 380 | static DECLCALLBACK(int) vdVfsFile_Flush(void *pvThis)
|
---|
| 381 | {
|
---|
| 382 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 383 | return VDFlush(pThis->pDisk);
|
---|
| 384 | }
|
---|
| 385 |
|
---|
| 386 |
|
---|
| 387 | /**
|
---|
| 388 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
|
---|
| 389 | */
|
---|
| 390 | static DECLCALLBACK(int) vdVfsFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
|
---|
[67207] | 391 | uint32_t *pfRetEvents)
|
---|
[41576] | 392 | {
|
---|
| 393 | NOREF(pvThis);
|
---|
| 394 | int rc;
|
---|
| 395 | if (fEvents != RTPOLL_EVT_ERROR)
|
---|
| 396 | {
|
---|
| 397 | *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
|
---|
| 398 | rc = VINF_SUCCESS;
|
---|
| 399 | }
|
---|
| 400 | else
|
---|
| 401 | rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
|
---|
| 402 | return rc;
|
---|
| 403 | }
|
---|
| 404 |
|
---|
| 405 |
|
---|
| 406 | /**
|
---|
| 407 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
|
---|
| 408 | */
|
---|
| 409 | static DECLCALLBACK(int) vdVfsFile_Tell(void *pvThis, PRTFOFF poffActual)
|
---|
| 410 | {
|
---|
| 411 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 412 | *poffActual = pThis->offCurPos;
|
---|
| 413 | return VINF_SUCCESS;
|
---|
| 414 | }
|
---|
| 415 |
|
---|
| 416 |
|
---|
| 417 | /**
|
---|
[58132] | 418 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetMode}
|
---|
[41576] | 419 | */
|
---|
| 420 | static DECLCALLBACK(int) vdVfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
|
---|
| 421 | {
|
---|
| 422 | NOREF(pvThis);
|
---|
| 423 | NOREF(fMode);
|
---|
| 424 | NOREF(fMask);
|
---|
| 425 | return VERR_NOT_SUPPORTED;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 |
|
---|
| 429 | /**
|
---|
| 430 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
|
---|
| 431 | */
|
---|
| 432 | static DECLCALLBACK(int) vdVfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
|
---|
| 433 | PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
|
---|
| 434 | {
|
---|
| 435 | NOREF(pvThis);
|
---|
| 436 | NOREF(pAccessTime);
|
---|
| 437 | NOREF(pModificationTime);
|
---|
| 438 | NOREF(pChangeTime);
|
---|
| 439 | NOREF(pBirthTime);
|
---|
| 440 | return VERR_NOT_SUPPORTED;
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 |
|
---|
| 444 | /**
|
---|
| 445 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
|
---|
| 446 | */
|
---|
| 447 | static DECLCALLBACK(int) vdVfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
|
---|
| 448 | {
|
---|
| 449 | NOREF(pvThis);
|
---|
| 450 | NOREF(uid);
|
---|
| 451 | NOREF(gid);
|
---|
| 452 | return VERR_NOT_SUPPORTED;
|
---|
| 453 | }
|
---|
| 454 |
|
---|
| 455 |
|
---|
| 456 | /**
|
---|
| 457 | * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
|
---|
| 458 | */
|
---|
| 459 | static DECLCALLBACK(int) vdVfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
|
---|
| 460 | {
|
---|
| 461 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 462 |
|
---|
| 463 | /*
|
---|
| 464 | * Seek relative to which position.
|
---|
| 465 | */
|
---|
| 466 | uint64_t offWrt;
|
---|
| 467 | switch (uMethod)
|
---|
| 468 | {
|
---|
| 469 | case RTFILE_SEEK_BEGIN:
|
---|
| 470 | offWrt = 0;
|
---|
| 471 | break;
|
---|
| 472 |
|
---|
| 473 | case RTFILE_SEEK_CURRENT:
|
---|
| 474 | offWrt = pThis->offCurPos;
|
---|
| 475 | break;
|
---|
| 476 |
|
---|
| 477 | case RTFILE_SEEK_END:
|
---|
| 478 | offWrt = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
|
---|
| 479 | break;
|
---|
| 480 |
|
---|
| 481 | default:
|
---|
| 482 | return VERR_INTERNAL_ERROR_5;
|
---|
| 483 | }
|
---|
| 484 |
|
---|
| 485 | /*
|
---|
[67207] | 486 | * Calc new position, take care to stay without bounds.
|
---|
[41576] | 487 | */
|
---|
| 488 | uint64_t offNew;
|
---|
| 489 | if (offSeek == 0)
|
---|
| 490 | offNew = offWrt;
|
---|
| 491 | else if (offSeek > 0)
|
---|
| 492 | {
|
---|
| 493 | offNew = offWrt + offSeek;
|
---|
| 494 | if ( offNew < offWrt
|
---|
| 495 | || offNew > RTFOFF_MAX)
|
---|
| 496 | offNew = RTFOFF_MAX;
|
---|
| 497 | }
|
---|
| 498 | else if ((uint64_t)-offSeek < offWrt)
|
---|
| 499 | offNew = offWrt + offSeek;
|
---|
| 500 | else
|
---|
| 501 | offNew = 0;
|
---|
| 502 |
|
---|
| 503 | /*
|
---|
| 504 | * Update the state and set return value.
|
---|
| 505 | */
|
---|
| 506 | pThis->offCurPos = offNew;
|
---|
| 507 |
|
---|
| 508 | *poffActual = offNew;
|
---|
| 509 | return VINF_SUCCESS;
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 |
|
---|
| 513 | /**
|
---|
| 514 | * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
|
---|
| 515 | */
|
---|
| 516 | static DECLCALLBACK(int) vdVfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
|
---|
| 517 | {
|
---|
| 518 | PVDVFSFILE pThis = (PVDVFSFILE)pvThis;
|
---|
| 519 | *pcbFile = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
|
---|
| 520 | return VINF_SUCCESS;
|
---|
| 521 | }
|
---|
| 522 |
|
---|
| 523 |
|
---|
| 524 | /**
|
---|
| 525 | * Standard file operations.
|
---|
| 526 | */
|
---|
| 527 | DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_vdVfsStdFileOps =
|
---|
| 528 | {
|
---|
| 529 | { /* Stream */
|
---|
| 530 | { /* Obj */
|
---|
| 531 | RTVFSOBJOPS_VERSION,
|
---|
| 532 | RTVFSOBJTYPE_FILE,
|
---|
| 533 | "VDFile",
|
---|
| 534 | vdVfsFile_Close,
|
---|
| 535 | vdVfsFile_QueryInfo,
|
---|
| 536 | RTVFSOBJOPS_VERSION
|
---|
| 537 | },
|
---|
| 538 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 539 | RTVFSIOSTREAMOPS_FEAT_NO_SG,
|
---|
| 540 | vdVfsFile_Read,
|
---|
| 541 | vdVfsFile_Write,
|
---|
| 542 | vdVfsFile_Flush,
|
---|
| 543 | vdVfsFile_PollOne,
|
---|
| 544 | vdVfsFile_Tell,
|
---|
| 545 | NULL /*Skip*/,
|
---|
| 546 | NULL /*ZeroFill*/,
|
---|
| 547 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 548 | },
|
---|
| 549 | RTVFSFILEOPS_VERSION,
|
---|
| 550 | /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
|
---|
| 551 | { /* ObjSet */
|
---|
| 552 | RTVFSOBJSETOPS_VERSION,
|
---|
| 553 | RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
|
---|
| 554 | vdVfsFile_SetMode,
|
---|
| 555 | vdVfsFile_SetTimes,
|
---|
| 556 | vdVfsFile_SetOwner,
|
---|
| 557 | RTVFSOBJSETOPS_VERSION
|
---|
| 558 | },
|
---|
| 559 | vdVfsFile_Seek,
|
---|
| 560 | vdVfsFile_QuerySize,
|
---|
| 561 | RTVFSFILEOPS_VERSION
|
---|
| 562 | };
|
---|
| 563 |
|
---|
| 564 |
|
---|
[66250] | 565 | VBOXDDU_DECL(int) VDCreateVfsFileFromDisk(PVDISK pDisk, uint32_t fFlags,
|
---|
[41576] | 566 | PRTVFSFILE phVfsFile)
|
---|
| 567 | {
|
---|
| 568 | AssertPtrReturn(pDisk, VERR_INVALID_HANDLE);
|
---|
| 569 | AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
|
---|
| 570 | AssertReturn((fFlags & ~VD_VFSFILE_FLAGS_MASK) == 0, VERR_INVALID_PARAMETER);
|
---|
| 571 |
|
---|
| 572 | /*
|
---|
| 573 | * Create the volume file.
|
---|
| 574 | */
|
---|
| 575 | RTVFSFILE hVfsFile;
|
---|
| 576 | PVDVFSFILE pThis;
|
---|
| 577 | int rc = RTVfsNewFile(&g_vdVfsStdFileOps, sizeof(*pThis), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_WRITE,
|
---|
| 578 | NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
|
---|
| 579 | if (RT_SUCCESS(rc))
|
---|
| 580 | {
|
---|
| 581 | pThis->offCurPos = 0;
|
---|
| 582 | pThis->pDisk = pDisk;
|
---|
| 583 | pThis->fFlags = fFlags;
|
---|
| 584 |
|
---|
| 585 | *phVfsFile = hVfsFile;
|
---|
| 586 | return VINF_SUCCESS;
|
---|
| 587 | }
|
---|
| 588 |
|
---|
| 589 | return rc;
|
---|
| 590 | }
|
---|
| 591 |
|
---|