[34391] | 1 | /* $Id: vfsmemory.cpp 103005 2024-01-23 23:55:58Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[34407] | 3 | * IPRT - Virtual File System, Memory Backed VFS.
|
---|
[34391] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2010-2023 Oracle and/or its affiliates.
|
---|
[34391] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[34391] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[34391] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[34391] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[34391] | 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
[57358] | 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Header Files *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[34391] | 41 | #include "internal/iprt.h"
|
---|
| 42 | #include <iprt/vfs.h>
|
---|
| 43 |
|
---|
[103005] | 44 | #include <iprt/asm-mem.h>
|
---|
[34391] | 45 | #include <iprt/assert.h>
|
---|
| 46 | #include <iprt/err.h>
|
---|
| 47 | #include <iprt/file.h>
|
---|
[34407] | 48 | #include <iprt/list.h>
|
---|
| 49 | #include <iprt/poll.h>
|
---|
| 50 | #include <iprt/string.h>
|
---|
| 51 | #include <iprt/vfslowlevel.h>
|
---|
[34391] | 52 |
|
---|
| 53 |
|
---|
| 54 |
|
---|
[57358] | 55 | /*********************************************************************************************************************************
|
---|
| 56 | * Header Files *
|
---|
| 57 | *********************************************************************************************************************************/
|
---|
[34391] | 58 | #include "internal/iprt.h"
|
---|
| 59 | #include <iprt/vfs.h>
|
---|
| 60 |
|
---|
| 61 | #include <iprt/err.h>
|
---|
| 62 | #include <iprt/mem.h>
|
---|
| 63 |
|
---|
| 64 |
|
---|
[57358] | 65 | /*********************************************************************************************************************************
|
---|
| 66 | * Defined Constants And Macros *
|
---|
| 67 | *********************************************************************************************************************************/
|
---|
[34407] | 68 | /** The max extent size. */
|
---|
| 69 | #define RTVFSMEM_MAX_EXTENT_SIZE _2M
|
---|
[34391] | 70 |
|
---|
| 71 |
|
---|
[57358] | 72 | /*********************************************************************************************************************************
|
---|
| 73 | * Structures and Typedefs *
|
---|
| 74 | *********************************************************************************************************************************/
|
---|
[34407] | 75 |
|
---|
| 76 | /**
|
---|
| 77 | * Memory base object info.
|
---|
| 78 | */
|
---|
| 79 | typedef struct RTVFSMEMBASE
|
---|
| 80 | {
|
---|
| 81 | /** The basic object info. */
|
---|
| 82 | RTFSOBJINFO ObjInfo;
|
---|
| 83 | } RTVFSMEMBASE;
|
---|
| 84 |
|
---|
| 85 |
|
---|
| 86 | /**
|
---|
| 87 | * Memory file extent.
|
---|
| 88 | *
|
---|
| 89 | * This stores part of the file content.
|
---|
| 90 | */
|
---|
| 91 | typedef struct RTVFSMEMEXTENT
|
---|
| 92 | {
|
---|
| 93 | /** Extent list entry. */
|
---|
| 94 | RTLISTNODE Entry;
|
---|
| 95 | /** The offset of this extent within the file. */
|
---|
| 96 | uint64_t off;
|
---|
| 97 | /** The size of the this extent. */
|
---|
| 98 | uint32_t cb;
|
---|
| 99 | /** The data. */
|
---|
| 100 | uint8_t abData[1];
|
---|
| 101 | } RTVFSMEMEXTENT;
|
---|
| 102 | /** Pointer to a memory file extent. */
|
---|
| 103 | typedef RTVFSMEMEXTENT *PRTVFSMEMEXTENT;
|
---|
| 104 |
|
---|
| 105 | /**
|
---|
| 106 | * Memory file.
|
---|
| 107 | */
|
---|
| 108 | typedef struct RTVFSMEMFILE
|
---|
| 109 | {
|
---|
| 110 | /** The base info. */
|
---|
| 111 | RTVFSMEMBASE Base;
|
---|
| 112 | /** The current file position. */
|
---|
| 113 | uint64_t offCurPos;
|
---|
| 114 | /** Pointer to the current file extent. */
|
---|
| 115 | PRTVFSMEMEXTENT pCurExt;
|
---|
| 116 | /** Linked list of file extents - RTVFSMEMEXTENT. */
|
---|
[39515] | 117 | RTLISTANCHOR ExtentHead;
|
---|
[34407] | 118 | /** The current extent size.
|
---|
| 119 | * This is slowly grown to RTVFSMEM_MAX_EXTENT_SIZE as the file grows. */
|
---|
| 120 | uint32_t cbExtent;
|
---|
| 121 | } RTVFSMEMFILE;
|
---|
| 122 | /** Pointer to a memory file. */
|
---|
| 123 | typedef RTVFSMEMFILE *PRTVFSMEMFILE;
|
---|
| 124 |
|
---|
| 125 |
|
---|
| 126 |
|
---|
| 127 | /**
|
---|
| 128 | * @interface_method_impl{RTVFSOBJOPS,pfnClose}
|
---|
| 129 | */
|
---|
| 130 | static DECLCALLBACK(int) rtVfsMemFile_Close(void *pvThis)
|
---|
| 131 | {
|
---|
| 132 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 133 |
|
---|
| 134 | /*
|
---|
| 135 | * Free the extent list.
|
---|
| 136 | */
|
---|
| 137 | PRTVFSMEMEXTENT pCur, pNext;
|
---|
| 138 | RTListForEachSafe(&pThis->ExtentHead, pCur, pNext, RTVFSMEMEXTENT, Entry)
|
---|
| 139 | {
|
---|
| 140 | pCur->off = RTFOFF_MAX;
|
---|
| 141 | pCur->cb = UINT32_MAX;
|
---|
| 142 | RTListNodeRemove(&pCur->Entry);
|
---|
| 143 | RTMemFree(pCur);
|
---|
| 144 | }
|
---|
| 145 | pThis->pCurExt = NULL;
|
---|
| 146 |
|
---|
| 147 | return VINF_SUCCESS;
|
---|
| 148 | }
|
---|
| 149 |
|
---|
| 150 |
|
---|
| 151 | /**
|
---|
| 152 | * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
|
---|
| 153 | */
|
---|
| 154 | static DECLCALLBACK(int) rtVfsMemFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
|
---|
| 155 | {
|
---|
| 156 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 157 | switch (enmAddAttr)
|
---|
| 158 | {
|
---|
| 159 | case RTFSOBJATTRADD_NOTHING:
|
---|
| 160 | case RTFSOBJATTRADD_UNIX:
|
---|
| 161 | *pObjInfo = pThis->Base.ObjInfo;
|
---|
| 162 | return VINF_SUCCESS;
|
---|
| 163 |
|
---|
| 164 | default:
|
---|
| 165 | return VERR_NOT_SUPPORTED;
|
---|
| 166 | }
|
---|
| 167 | }
|
---|
| 168 |
|
---|
| 169 |
|
---|
| 170 | /**
|
---|
| 171 | * The slow paths of rtVfsMemFile_LocateExtent.
|
---|
| 172 | *
|
---|
| 173 | * @copydoc rtVfsMemFile_LocateExtent
|
---|
| 174 | */
|
---|
| 175 | static PRTVFSMEMEXTENT rtVfsMemFile_LocateExtentSlow(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit)
|
---|
| 176 | {
|
---|
| 177 | /*
|
---|
| 178 | * Search from the start or the previously used extent. The heuristics
|
---|
| 179 | * are very very simple, but whatever.
|
---|
| 180 | */
|
---|
| 181 | PRTVFSMEMEXTENT pExtent = pThis->pCurExt;
|
---|
[67859] | 182 | if (!pExtent || off < pExtent->off)
|
---|
[34407] | 183 | {
|
---|
[40292] | 184 | /* Consider the last entry first (for writes). */
|
---|
| 185 | pExtent = RTListGetLast(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
|
---|
[34407] | 186 | if (!pExtent)
|
---|
| 187 | {
|
---|
| 188 | *pfHit = false;
|
---|
| 189 | return NULL;
|
---|
| 190 | }
|
---|
[40292] | 191 | if (off - pExtent->off < pExtent->cb)
|
---|
| 192 | {
|
---|
| 193 | *pfHit = true;
|
---|
| 194 | pThis->pCurExt = pExtent;
|
---|
| 195 | return pExtent;
|
---|
| 196 | }
|
---|
| 197 |
|
---|
[91095] | 198 | /* Otherwise, start from the head after making sure it is not an
|
---|
| 199 | offset before the first extent. */
|
---|
[40292] | 200 | pExtent = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
|
---|
[91095] | 201 | if (off < pExtent->off)
|
---|
| 202 | {
|
---|
| 203 | *pfHit = false;
|
---|
| 204 | return pExtent;
|
---|
| 205 | }
|
---|
[34407] | 206 | }
|
---|
| 207 |
|
---|
| 208 | while (off - pExtent->off >= pExtent->cb)
|
---|
| 209 | {
|
---|
| 210 | Assert(pExtent->off <= off);
|
---|
[34560] | 211 | PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
|
---|
| 212 | if ( !pNext
|
---|
[34407] | 213 | || pNext->off > off)
|
---|
| 214 | {
|
---|
| 215 | *pfHit = false;
|
---|
[40292] | 216 | return pNext;
|
---|
[34407] | 217 | }
|
---|
| 218 |
|
---|
| 219 | pExtent = pNext;
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | *pfHit = true;
|
---|
| 223 | pThis->pCurExt = pExtent;
|
---|
| 224 | return pExtent;
|
---|
| 225 | }
|
---|
| 226 |
|
---|
| 227 |
|
---|
| 228 | /**
|
---|
[40292] | 229 | * Locates the extent covering the specified offset, or the one after it.
|
---|
[34407] | 230 | *
|
---|
| 231 | * @returns The closest extent. NULL if off is 0 and there are no extent
|
---|
| 232 | * covering byte 0 yet.
|
---|
| 233 | * @param pThis The memory file.
|
---|
| 234 | * @param off The offset (0-positive).
|
---|
| 235 | * @param pfHit Where to indicate whether the extent is a
|
---|
| 236 | * direct hit (@c true) or just a closest match
|
---|
| 237 | * (@c false).
|
---|
| 238 | */
|
---|
| 239 | DECLINLINE(PRTVFSMEMEXTENT) rtVfsMemFile_LocateExtent(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit)
|
---|
| 240 | {
|
---|
| 241 | /*
|
---|
| 242 | * The most likely case is that we're hitting the extent we used in the
|
---|
| 243 | * previous access or the one immediately following it.
|
---|
| 244 | */
|
---|
| 245 | PRTVFSMEMEXTENT pExtent = pThis->pCurExt;
|
---|
| 246 | if (!pExtent)
|
---|
| 247 | return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit);
|
---|
| 248 |
|
---|
| 249 | if (off - pExtent->off >= pExtent->cb)
|
---|
| 250 | {
|
---|
[34560] | 251 | pExtent = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
|
---|
[34407] | 252 | if ( !pExtent
|
---|
| 253 | || off - pExtent->off >= pExtent->cb)
|
---|
| 254 | return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit);
|
---|
| 255 | pThis->pCurExt = pExtent;
|
---|
| 256 | }
|
---|
| 257 |
|
---|
| 258 | *pfHit = true;
|
---|
| 259 | return pExtent;
|
---|
| 260 | }
|
---|
| 261 |
|
---|
| 262 |
|
---|
| 263 | /**
|
---|
| 264 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
|
---|
| 265 | */
|
---|
[100908] | 266 | static DECLCALLBACK(int) rtVfsMemFile_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
|
---|
[34407] | 267 | {
|
---|
| 268 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 269 |
|
---|
| 270 | Assert(pSgBuf->cSegs == 1);
|
---|
| 271 | NOREF(fBlocking);
|
---|
| 272 |
|
---|
| 273 | /*
|
---|
| 274 | * Find the current position and check if it's within the file.
|
---|
| 275 | */
|
---|
| 276 | uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
|
---|
| 277 | if (offUnsigned >= (uint64_t)pThis->Base.ObjInfo.cbObject)
|
---|
| 278 | {
|
---|
| 279 | if (pcbRead)
|
---|
| 280 | {
|
---|
| 281 | *pcbRead = 0;
|
---|
| 282 | pThis->offCurPos = offUnsigned;
|
---|
| 283 | return VINF_EOF;
|
---|
| 284 | }
|
---|
| 285 | return VERR_EOF;
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 | size_t cbLeftToRead;
|
---|
| 289 | if (offUnsigned + pSgBuf->paSegs[0].cbSeg > (uint64_t)pThis->Base.ObjInfo.cbObject)
|
---|
| 290 | {
|
---|
| 291 | if (!pcbRead)
|
---|
| 292 | return VERR_EOF;
|
---|
| 293 | *pcbRead = cbLeftToRead = (size_t)((uint64_t)pThis->Base.ObjInfo.cbObject - offUnsigned);
|
---|
| 294 | }
|
---|
| 295 | else
|
---|
[34535] | 296 | {
|
---|
| 297 | cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
|
---|
| 298 | if (pcbRead)
|
---|
| 299 | *pcbRead = cbLeftToRead;
|
---|
| 300 | }
|
---|
[34407] | 301 |
|
---|
| 302 | /*
|
---|
| 303 | * Ok, we've got a valid stretch within the file. Do the reading.
|
---|
| 304 | */
|
---|
| 305 | if (cbLeftToRead > 0)
|
---|
| 306 | {
|
---|
[100908] | 307 | RTSgBufAdvance(pSgBuf, cbLeftToRead);
|
---|
| 308 |
|
---|
[34407] | 309 | uint8_t *pbDst = (uint8_t *)pSgBuf->paSegs[0].pvSeg;
|
---|
| 310 | bool fHit;
|
---|
| 311 | PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
|
---|
| 312 | for (;;)
|
---|
| 313 | {
|
---|
[40292] | 314 | size_t cbThisRead;
|
---|
[34407] | 315 |
|
---|
| 316 | /*
|
---|
[40292] | 317 | * Do we hit an extent covering the current file surface?
|
---|
[34407] | 318 | */
|
---|
| 319 | if (fHit)
|
---|
| 320 | {
|
---|
[40292] | 321 | /* Yes, copy the data. */
|
---|
| 322 | Assert(offUnsigned - pExtent->off < pExtent->cb);
|
---|
[34407] | 323 | size_t const offExtent = (size_t)(offUnsigned - pExtent->off);
|
---|
| 324 | cbThisRead = pExtent->cb - offExtent;
|
---|
| 325 | if (cbThisRead >= cbLeftToRead)
|
---|
| 326 | cbThisRead = cbLeftToRead;
|
---|
| 327 |
|
---|
| 328 | memcpy(pbDst, &pExtent->abData[offUnsigned - pExtent->off], cbThisRead);
|
---|
| 329 |
|
---|
| 330 | offUnsigned += cbThisRead;
|
---|
| 331 | cbLeftToRead -= cbThisRead;
|
---|
| 332 | if (!cbLeftToRead)
|
---|
| 333 | break;
|
---|
| 334 | pbDst += cbThisRead;
|
---|
| 335 |
|
---|
[40292] | 336 | /* Advance, looping immediately if not sparse. */
|
---|
| 337 | PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
|
---|
[34407] | 338 | if ( pNext
|
---|
| 339 | && pNext->off == pExtent->off + pExtent->cb)
|
---|
| 340 | {
|
---|
| 341 | pExtent = pNext;
|
---|
| 342 | continue;
|
---|
| 343 | }
|
---|
[40292] | 344 |
|
---|
| 345 | Assert(!pNext || pNext->off > pExtent->off);
|
---|
| 346 | pExtent = pNext;
|
---|
[34407] | 347 | fHit = false;
|
---|
| 348 | }
|
---|
[40292] | 349 | else
|
---|
| 350 | Assert(!pExtent || pExtent->off > offUnsigned);
|
---|
[34407] | 351 |
|
---|
| 352 | /*
|
---|
[40292] | 353 | * No extent of this portion (sparse file) - Read zeros.
|
---|
[34407] | 354 | */
|
---|
[40292] | 355 | if ( !pExtent
|
---|
| 356 | || offUnsigned + cbLeftToRead <= pExtent->off)
|
---|
[34407] | 357 | cbThisRead = cbLeftToRead;
|
---|
| 358 | else
|
---|
[40292] | 359 | cbThisRead = (size_t)(pExtent->off - offUnsigned);
|
---|
[34407] | 360 |
|
---|
| 361 | RT_BZERO(pbDst, cbThisRead);
|
---|
| 362 |
|
---|
| 363 | offUnsigned += cbThisRead;
|
---|
| 364 | cbLeftToRead -= cbThisRead;
|
---|
| 365 | if (!cbLeftToRead)
|
---|
| 366 | break;
|
---|
| 367 | pbDst += cbThisRead;
|
---|
| 368 |
|
---|
| 369 | /* Go on and read content from the next extent. */
|
---|
[40292] | 370 | fHit = true;
|
---|
[34407] | 371 | }
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | pThis->offCurPos = offUnsigned;
|
---|
| 375 | return VINF_SUCCESS;
|
---|
| 376 | }
|
---|
| 377 |
|
---|
| 378 |
|
---|
| 379 | /**
|
---|
| 380 | * Allocates a new extent covering the ground at @a offUnsigned.
|
---|
| 381 | *
|
---|
| 382 | * @returns Pointer to the new extent on success, NULL if we're out of memory.
|
---|
| 383 | * @param pThis The memory file.
|
---|
| 384 | * @param offUnsigned The location to allocate the extent at.
|
---|
| 385 | * @param cbToWrite The number of bytes we're interested in writing
|
---|
| 386 | * starting at @a offUnsigned.
|
---|
[40292] | 387 | * @param pNext The extention after @a offUnsigned. NULL if
|
---|
| 388 | * none, i.e. we're allocating space at the end of
|
---|
| 389 | * the file.
|
---|
[34407] | 390 | */
|
---|
| 391 | static PRTVFSMEMEXTENT rtVfsMemFile_AllocExtent(PRTVFSMEMFILE pThis, uint64_t offUnsigned, size_t cbToWrite,
|
---|
[40292] | 392 | PRTVFSMEMEXTENT pNext)
|
---|
[34407] | 393 | {
|
---|
| 394 | /*
|
---|
| 395 | * Adjust the extent size if we haven't reached the max size yet.
|
---|
| 396 | */
|
---|
| 397 | if (pThis->cbExtent != RTVFSMEM_MAX_EXTENT_SIZE)
|
---|
| 398 | {
|
---|
| 399 | if (cbToWrite >= RTVFSMEM_MAX_EXTENT_SIZE)
|
---|
| 400 | pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
|
---|
| 401 | else if (!RTListIsEmpty(&pThis->ExtentHead))
|
---|
| 402 | {
|
---|
[34414] | 403 | uint32_t cbNextExtent = pThis->cbExtent;
|
---|
[34407] | 404 | if (RT_IS_POWER_OF_TWO(cbNextExtent))
|
---|
| 405 | cbNextExtent *= 2;
|
---|
| 406 | else
|
---|
| 407 | {
|
---|
| 408 | /* Make it a power of two (seeRTVfsMemorizeIoStreamAsFile). */
|
---|
| 409 | cbNextExtent = _4K;
|
---|
| 410 | while (cbNextExtent < pThis->cbExtent)
|
---|
| 411 | cbNextExtent *= 2;
|
---|
| 412 | }
|
---|
| 413 | if (((pThis->Base.ObjInfo.cbAllocated + cbNextExtent) & (cbNextExtent - 1)) == 0)
|
---|
| 414 | pThis->cbExtent = cbNextExtent;
|
---|
| 415 | }
|
---|
| 416 | }
|
---|
| 417 |
|
---|
| 418 | /*
|
---|
| 419 | * Figure out the size and position of the extent we're adding.
|
---|
| 420 | */
|
---|
| 421 | uint64_t offExtent = offUnsigned & ~(uint64_t)(pThis->cbExtent - 1);
|
---|
| 422 | uint32_t cbExtent = pThis->cbExtent;
|
---|
| 423 |
|
---|
[40292] | 424 | PRTVFSMEMEXTENT pPrev = pNext
|
---|
| 425 | ? RTListGetPrev(&pThis->ExtentHead, pNext, RTVFSMEMEXTENT, Entry)
|
---|
| 426 | : RTListGetLast(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
|
---|
[34407] | 427 | uint64_t const offPrev = pPrev ? pPrev->off + pPrev->cb : 0;
|
---|
| 428 | if (offExtent < offPrev)
|
---|
| 429 | offExtent = offPrev;
|
---|
| 430 |
|
---|
| 431 | if (pNext)
|
---|
| 432 | {
|
---|
| 433 | uint64_t cbMaxExtent = pNext->off - offExtent;
|
---|
| 434 | if (cbMaxExtent < cbExtent)
|
---|
[34507] | 435 | cbExtent = (uint32_t)cbMaxExtent;
|
---|
[34407] | 436 | }
|
---|
| 437 |
|
---|
| 438 | /*
|
---|
| 439 | * Allocate, initialize and insert the new extent.
|
---|
| 440 | */
|
---|
[73097] | 441 | PRTVFSMEMEXTENT pNew = (PRTVFSMEMEXTENT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTVFSMEMEXTENT, abData[cbExtent]));
|
---|
[34407] | 442 | if (pNew)
|
---|
| 443 | {
|
---|
| 444 | pNew->off = offExtent;
|
---|
| 445 | pNew->cb = cbExtent;
|
---|
| 446 | if (pPrev)
|
---|
| 447 | RTListNodeInsertAfter(&pPrev->Entry, &pNew->Entry);
|
---|
| 448 | else
|
---|
| 449 | RTListPrepend(&pThis->ExtentHead, &pNew->Entry);
|
---|
| 450 |
|
---|
| 451 | pThis->Base.ObjInfo.cbAllocated += cbExtent;
|
---|
| 452 | }
|
---|
| 453 | /** @todo retry with minimum size. */
|
---|
| 454 |
|
---|
| 455 | return pNew;
|
---|
| 456 | }
|
---|
| 457 |
|
---|
| 458 |
|
---|
| 459 | /**
|
---|
| 460 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
|
---|
| 461 | */
|
---|
[100908] | 462 | static DECLCALLBACK(int) rtVfsMemFile_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
|
---|
[34407] | 463 | {
|
---|
| 464 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 465 |
|
---|
| 466 | Assert(pSgBuf->cSegs == 1);
|
---|
| 467 | NOREF(fBlocking);
|
---|
| 468 |
|
---|
| 469 | /*
|
---|
| 470 | * Validate the write and set up the write loop.
|
---|
| 471 | */
|
---|
| 472 | size_t cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
|
---|
| 473 | if (!cbLeftToWrite)
|
---|
| 474 | return VINF_SUCCESS; /* pcbWritten is already 0. */
|
---|
| 475 | uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
|
---|
| 476 | if (offUnsigned + cbLeftToWrite >= (uint64_t)RTFOFF_MAX)
|
---|
| 477 | return VERR_OUT_OF_RANGE;
|
---|
| 478 |
|
---|
| 479 | int rc = VINF_SUCCESS;
|
---|
| 480 | uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
|
---|
| 481 | bool fHit;
|
---|
| 482 | PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
|
---|
| 483 | for (;;)
|
---|
| 484 | {
|
---|
| 485 | /*
|
---|
| 486 | * If we didn't hit an extent, allocate one (unless it's all zeros).
|
---|
| 487 | */
|
---|
| 488 | if (!fHit)
|
---|
| 489 | {
|
---|
[40292] | 490 | Assert(!pExtent || pExtent->off > offUnsigned);
|
---|
[34407] | 491 |
|
---|
| 492 | /* Skip leading zeros if there is a whole bunch of them. */
|
---|
[59747] | 493 | uint8_t const *pbSrcNZ = (uint8_t const *)ASMMemFirstNonZero(pbSrc, cbLeftToWrite);
|
---|
[40127] | 494 | size_t cbZeros = pbSrcNZ ? pbSrcNZ - pbSrc : cbLeftToWrite;
|
---|
| 495 | if (cbZeros)
|
---|
[34407] | 496 | {
|
---|
[40127] | 497 | uint64_t const cbToNext = pExtent ? pExtent->off - offUnsigned : UINT64_MAX;
|
---|
| 498 | if (cbZeros > cbToNext)
|
---|
| 499 | cbZeros = (size_t)cbToNext;
|
---|
[34407] | 500 | offUnsigned += cbZeros;
|
---|
| 501 | cbLeftToWrite -= cbZeros;
|
---|
[40127] | 502 | if (!cbLeftToWrite)
|
---|
| 503 | break;
|
---|
[91091] | 504 | pbSrc += cbZeros;
|
---|
[40127] | 505 |
|
---|
| 506 | Assert(!pExtent || offUnsigned <= pExtent->off);
|
---|
| 507 | if (pExtent && pExtent->off == offUnsigned)
|
---|
| 508 | {
|
---|
| 509 | fHit = true;
|
---|
| 510 | continue;
|
---|
| 511 | }
|
---|
[34407] | 512 | }
|
---|
| 513 |
|
---|
| 514 | fHit = true;
|
---|
| 515 | pExtent = rtVfsMemFile_AllocExtent(pThis, offUnsigned, cbLeftToWrite, pExtent);
|
---|
| 516 | if (!pExtent)
|
---|
| 517 | {
|
---|
| 518 | rc = VERR_NO_MEMORY;
|
---|
| 519 | break;
|
---|
| 520 | }
|
---|
| 521 | }
|
---|
[40292] | 522 | Assert(offUnsigned - pExtent->off < pExtent->cb);
|
---|
[34407] | 523 |
|
---|
| 524 | /*
|
---|
| 525 | * Copy the source data into the current extent.
|
---|
| 526 | */
|
---|
[34507] | 527 | uint32_t const offDst = (uint32_t)(offUnsigned - pExtent->off);
|
---|
[34407] | 528 | uint32_t cbThisWrite = pExtent->cb - offDst;
|
---|
| 529 | if (cbThisWrite > cbLeftToWrite)
|
---|
| 530 | cbThisWrite = (uint32_t)cbLeftToWrite;
|
---|
| 531 | memcpy(&pExtent->abData[offDst], pbSrc, cbThisWrite);
|
---|
| 532 |
|
---|
[67510] | 533 | offUnsigned += cbThisWrite;
|
---|
[34407] | 534 | cbLeftToWrite -= cbThisWrite;
|
---|
| 535 | if (!cbLeftToWrite)
|
---|
| 536 | break;
|
---|
| 537 | pbSrc += cbThisWrite;
|
---|
| 538 | Assert(offUnsigned == pExtent->off + pExtent->cb);
|
---|
| 539 |
|
---|
| 540 | /*
|
---|
[40127] | 541 | * Advance to the next extent (emulate the lookup).
|
---|
[34407] | 542 | */
|
---|
[40127] | 543 | pExtent = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
|
---|
| 544 | fHit = pExtent && (offUnsigned - pExtent->off < pExtent->cb);
|
---|
[34407] | 545 | }
|
---|
| 546 |
|
---|
| 547 | /*
|
---|
| 548 | * Update the state, set return value and return.
|
---|
| 549 | * Note! There must be no alternative exit path from the loop above.
|
---|
| 550 | */
|
---|
| 551 | pThis->offCurPos = offUnsigned;
|
---|
| 552 | if ((uint64_t)pThis->Base.ObjInfo.cbObject < offUnsigned)
|
---|
| 553 | pThis->Base.ObjInfo.cbObject = offUnsigned;
|
---|
| 554 |
|
---|
[100908] | 555 | size_t const cbWritten = pSgBuf->paSegs[0].cbSeg - cbLeftToWrite;
|
---|
[34407] | 556 | if (pcbWritten)
|
---|
[100908] | 557 | *pcbWritten = cbWritten;
|
---|
| 558 | RTSgBufAdvance(pSgBuf, cbWritten);
|
---|
[34407] | 559 | return rc;
|
---|
| 560 | }
|
---|
| 561 |
|
---|
| 562 |
|
---|
| 563 | /**
|
---|
| 564 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
|
---|
| 565 | */
|
---|
| 566 | static DECLCALLBACK(int) rtVfsMemFile_Flush(void *pvThis)
|
---|
| 567 | {
|
---|
| 568 | NOREF(pvThis);
|
---|
| 569 | return VINF_SUCCESS;
|
---|
| 570 | }
|
---|
| 571 |
|
---|
| 572 |
|
---|
| 573 | /**
|
---|
| 574 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
|
---|
| 575 | */
|
---|
| 576 | static DECLCALLBACK(int) rtVfsMemFile_Tell(void *pvThis, PRTFOFF poffActual)
|
---|
| 577 | {
|
---|
| 578 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 579 | *poffActual = pThis->offCurPos;
|
---|
| 580 | return VINF_SUCCESS;
|
---|
| 581 | }
|
---|
| 582 |
|
---|
| 583 |
|
---|
| 584 | /**
|
---|
| 585 | * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
|
---|
| 586 | */
|
---|
| 587 | static DECLCALLBACK(int) rtVfsMemFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
|
---|
| 588 | {
|
---|
| 589 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 590 | pThis->Base.ObjInfo.Attr.fMode = (pThis->Base.ObjInfo.Attr.fMode & ~fMask) | fMode;
|
---|
| 591 | return VINF_SUCCESS;
|
---|
| 592 | }
|
---|
| 593 |
|
---|
| 594 |
|
---|
| 595 | /**
|
---|
| 596 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
|
---|
| 597 | */
|
---|
| 598 | static DECLCALLBACK(int) rtVfsMemFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
|
---|
| 599 | PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
|
---|
| 600 | {
|
---|
| 601 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 602 |
|
---|
| 603 | if (pAccessTime)
|
---|
| 604 | pThis->Base.ObjInfo.AccessTime = *pAccessTime;
|
---|
| 605 | if (pModificationTime)
|
---|
| 606 | pThis->Base.ObjInfo.ModificationTime = *pModificationTime;
|
---|
| 607 | if (pChangeTime)
|
---|
| 608 | pThis->Base.ObjInfo.ChangeTime = *pChangeTime;
|
---|
| 609 | if (pBirthTime)
|
---|
| 610 | pThis->Base.ObjInfo.BirthTime = *pBirthTime;
|
---|
| 611 |
|
---|
| 612 | return VINF_SUCCESS;
|
---|
| 613 | }
|
---|
| 614 |
|
---|
| 615 |
|
---|
| 616 | /**
|
---|
| 617 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
|
---|
| 618 | */
|
---|
| 619 | static DECLCALLBACK(int) rtVfsMemFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
|
---|
| 620 | {
|
---|
| 621 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 622 |
|
---|
| 623 | if (uid != NIL_RTUID)
|
---|
| 624 | pThis->Base.ObjInfo.Attr.u.Unix.uid = uid;
|
---|
| 625 | if (gid != NIL_RTUID)
|
---|
| 626 | pThis->Base.ObjInfo.Attr.u.Unix.gid = gid;
|
---|
| 627 |
|
---|
| 628 | return VINF_SUCCESS;
|
---|
| 629 | }
|
---|
| 630 |
|
---|
| 631 |
|
---|
| 632 | /**
|
---|
| 633 | * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
|
---|
| 634 | */
|
---|
| 635 | static DECLCALLBACK(int) rtVfsMemFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
|
---|
| 636 | {
|
---|
| 637 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 638 |
|
---|
| 639 | /*
|
---|
| 640 | * Seek relative to which position.
|
---|
| 641 | */
|
---|
| 642 | uint64_t offWrt;
|
---|
| 643 | switch (uMethod)
|
---|
| 644 | {
|
---|
| 645 | case RTFILE_SEEK_BEGIN:
|
---|
| 646 | offWrt = 0;
|
---|
| 647 | break;
|
---|
| 648 |
|
---|
| 649 | case RTFILE_SEEK_CURRENT:
|
---|
| 650 | offWrt = pThis->offCurPos;
|
---|
| 651 | break;
|
---|
| 652 |
|
---|
| 653 | case RTFILE_SEEK_END:
|
---|
| 654 | offWrt = pThis->Base.ObjInfo.cbObject;
|
---|
| 655 | break;
|
---|
| 656 |
|
---|
| 657 | default:
|
---|
| 658 | return VERR_INTERNAL_ERROR_5;
|
---|
| 659 | }
|
---|
| 660 |
|
---|
| 661 | /*
|
---|
[67329] | 662 | * Calc new position, take care to stay within RTFOFF type bounds.
|
---|
[34407] | 663 | */
|
---|
| 664 | uint64_t offNew;
|
---|
| 665 | if (offSeek == 0)
|
---|
| 666 | offNew = offWrt;
|
---|
| 667 | else if (offSeek > 0)
|
---|
| 668 | {
|
---|
| 669 | offNew = offWrt + offSeek;
|
---|
| 670 | if ( offNew < offWrt
|
---|
| 671 | || offNew > RTFOFF_MAX)
|
---|
| 672 | offNew = RTFOFF_MAX;
|
---|
| 673 | }
|
---|
[34410] | 674 | else if ((uint64_t)-offSeek < offWrt)
|
---|
[34407] | 675 | offNew = offWrt + offSeek;
|
---|
| 676 | else
|
---|
| 677 | offNew = 0;
|
---|
| 678 |
|
---|
| 679 | /*
|
---|
| 680 | * Update the state and set return value.
|
---|
| 681 | */
|
---|
| 682 | if ( pThis->pCurExt
|
---|
| 683 | && pThis->pCurExt->off - offNew >= pThis->pCurExt->cb)
|
---|
| 684 | pThis->pCurExt = NULL;
|
---|
| 685 | pThis->offCurPos = offNew;
|
---|
| 686 |
|
---|
| 687 | *poffActual = offNew;
|
---|
| 688 | return VINF_SUCCESS;
|
---|
| 689 | }
|
---|
| 690 |
|
---|
| 691 |
|
---|
| 692 | /**
|
---|
| 693 | * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
|
---|
| 694 | */
|
---|
| 695 | static DECLCALLBACK(int) rtVfsMemFile_QuerySize(void *pvThis, uint64_t *pcbFile)
|
---|
| 696 | {
|
---|
| 697 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
[34507] | 698 | *pcbFile = pThis->Base.ObjInfo.cbObject;
|
---|
| 699 | return VINF_SUCCESS;
|
---|
[34407] | 700 | }
|
---|
| 701 |
|
---|
| 702 |
|
---|
| 703 | /**
|
---|
[69977] | 704 | * @interface_method_impl{RTVFSFILEOPS,pfnSetSize}
|
---|
| 705 | */
|
---|
| 706 | static DECLCALLBACK(int) rtVfsMemFile_SetSize(void *pvThis, uint64_t cbFile, uint32_t fFlags)
|
---|
| 707 | {
|
---|
[91330] | 708 | AssertReturn(RTVFSFILE_SIZE_F_IS_VALID(fFlags), VERR_INVALID_PARAMETER);
|
---|
| 709 |
|
---|
| 710 | PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
|
---|
| 711 | if ( (fFlags & RTVFSFILE_SIZE_F_ACTION_MASK) == RTVFSFILE_SIZE_F_NORMAL
|
---|
| 712 | && (RTFOFF)cbFile >= pThis->Base.ObjInfo.cbObject)
|
---|
| 713 | {
|
---|
| 714 | /* Growing is just a matter of increasing the size of the object. */
|
---|
| 715 | pThis->Base.ObjInfo.cbObject = cbFile;
|
---|
| 716 | return VINF_SUCCESS;
|
---|
| 717 | }
|
---|
| 718 |
|
---|
[69977] | 719 | AssertMsgFailed(("Lucky you! You get to implement this (or bug bird about it).\n"));
|
---|
| 720 | return VERR_NOT_IMPLEMENTED;
|
---|
| 721 | }
|
---|
| 722 |
|
---|
| 723 |
|
---|
| 724 | /**
|
---|
| 725 | * @interface_method_impl{RTVFSFILEOPS,pfnQueryMaxSize}
|
---|
| 726 | */
|
---|
| 727 | static DECLCALLBACK(int) rtVfsMemFile_QueryMaxSize(void *pvThis, uint64_t *pcbMax)
|
---|
| 728 | {
|
---|
| 729 | RT_NOREF(pvThis);
|
---|
| 730 | *pcbMax = ~(size_t)0 >> 1;
|
---|
| 731 | return VINF_SUCCESS;
|
---|
| 732 | }
|
---|
| 733 |
|
---|
| 734 |
|
---|
| 735 | /**
|
---|
[59524] | 736 | * Memory file operations.
|
---|
[34407] | 737 | */
|
---|
[59524] | 738 | DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsMemFileOps =
|
---|
[34407] | 739 | {
|
---|
| 740 | { /* Stream */
|
---|
| 741 | { /* Obj */
|
---|
| 742 | RTVFSOBJOPS_VERSION,
|
---|
| 743 | RTVFSOBJTYPE_FILE,
|
---|
| 744 | "MemFile",
|
---|
| 745 | rtVfsMemFile_Close,
|
---|
| 746 | rtVfsMemFile_QueryInfo,
|
---|
[94291] | 747 | NULL,
|
---|
[34407] | 748 | RTVFSOBJOPS_VERSION
|
---|
| 749 | },
|
---|
| 750 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 751 | RTVFSIOSTREAMOPS_FEAT_NO_SG,
|
---|
| 752 | rtVfsMemFile_Read,
|
---|
| 753 | rtVfsMemFile_Write,
|
---|
| 754 | rtVfsMemFile_Flush,
|
---|
[69942] | 755 | NULL /*PollOne*/,
|
---|
[34407] | 756 | rtVfsMemFile_Tell,
|
---|
| 757 | NULL /*Skip*/,
|
---|
| 758 | NULL /*ZeroFill*/,
|
---|
| 759 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 760 | },
|
---|
| 761 | RTVFSFILEOPS_VERSION,
|
---|
| 762 | /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
|
---|
| 763 | { /* ObjSet */
|
---|
| 764 | RTVFSOBJSETOPS_VERSION,
|
---|
[73097] | 765 | RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
|
---|
[34407] | 766 | rtVfsMemFile_SetMode,
|
---|
| 767 | rtVfsMemFile_SetTimes,
|
---|
| 768 | rtVfsMemFile_SetOwner,
|
---|
| 769 | RTVFSOBJSETOPS_VERSION
|
---|
| 770 | },
|
---|
| 771 | rtVfsMemFile_Seek,
|
---|
| 772 | rtVfsMemFile_QuerySize,
|
---|
[69977] | 773 | rtVfsMemFile_SetSize,
|
---|
| 774 | rtVfsMemFile_QueryMaxSize,
|
---|
[34407] | 775 | RTVFSFILEOPS_VERSION
|
---|
| 776 | };
|
---|
| 777 |
|
---|
| 778 |
|
---|
[59524] | 779 | /**
|
---|
[67181] | 780 | * Initialize the RTVFSMEMFILE::Base.ObjInfo specific members.
|
---|
| 781 | *
|
---|
| 782 | * @param pObjInfo The object info to init.
|
---|
| 783 | * @param cbObject The object size set.
|
---|
| 784 | */
|
---|
| 785 | static void rtVfsMemInitObjInfo(PRTFSOBJINFO pObjInfo, uint64_t cbObject)
|
---|
| 786 | {
|
---|
| 787 | pObjInfo->cbObject = cbObject;
|
---|
| 788 | pObjInfo->cbAllocated = cbObject;
|
---|
| 789 | pObjInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | RTFS_UNIX_IRWXU;
|
---|
| 790 | pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
|
---|
| 791 | pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
|
---|
| 792 | pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
|
---|
| 793 | pObjInfo->Attr.u.Unix.cHardlinks = 1;
|
---|
| 794 | pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
|
---|
| 795 | pObjInfo->Attr.u.Unix.INodeId = 0;
|
---|
| 796 | pObjInfo->Attr.u.Unix.fFlags = 0;
|
---|
| 797 | pObjInfo->Attr.u.Unix.GenerationId = 0;
|
---|
| 798 | pObjInfo->Attr.u.Unix.Device = 0;
|
---|
| 799 | RTTimeNow(&pObjInfo->AccessTime);
|
---|
| 800 | pObjInfo->ModificationTime = pObjInfo->AccessTime;
|
---|
| 801 | pObjInfo->ChangeTime = pObjInfo->AccessTime;
|
---|
| 802 | pObjInfo->BirthTime = pObjInfo->AccessTime;
|
---|
| 803 | }
|
---|
| 804 |
|
---|
| 805 |
|
---|
| 806 | /**
|
---|
[59524] | 807 | * Initialize the RTVFSMEMFILE specific members.
|
---|
| 808 | *
|
---|
| 809 | * @param pThis The memory file to initialize.
|
---|
| 810 | * @param cbObject The object size for estimating extent size.
|
---|
| 811 | * @param fFlags The user specified flags.
|
---|
| 812 | */
|
---|
| 813 | static void rtVfsMemFileInit(PRTVFSMEMFILE pThis, RTFOFF cbObject, uint32_t fFlags)
|
---|
| 814 | {
|
---|
| 815 | pThis->offCurPos = 0;
|
---|
| 816 | pThis->pCurExt = NULL;
|
---|
| 817 | RTListInit(&pThis->ExtentHead);
|
---|
| 818 | if (cbObject <= 0)
|
---|
| 819 | pThis->cbExtent = _4K;
|
---|
| 820 | else if (cbObject < RTVFSMEM_MAX_EXTENT_SIZE)
|
---|
| 821 | pThis->cbExtent = fFlags & RTFILE_O_WRITE ? _4K : cbObject;
|
---|
| 822 | else
|
---|
| 823 | pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
|
---|
| 824 | }
|
---|
[34407] | 825 |
|
---|
| 826 |
|
---|
[59524] | 827 | /**
|
---|
| 828 | * Rewinds the file to position 0 and clears the WRITE flag if necessary.
|
---|
| 829 | *
|
---|
| 830 | * @param pThis The memory file instance.
|
---|
| 831 | * @param fFlags The user specified flags.
|
---|
| 832 | */
|
---|
| 833 | static void rtVfsMemFileResetAndFixWriteFlag(PRTVFSMEMFILE pThis, uint32_t fFlags)
|
---|
| 834 | {
|
---|
| 835 | pThis->pCurExt = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
|
---|
| 836 | pThis->offCurPos = 0;
|
---|
[34407] | 837 |
|
---|
[59524] | 838 | if (!(fFlags & RTFILE_O_WRITE))
|
---|
| 839 | {
|
---|
| 840 | /** @todo clear RTFILE_O_WRITE from the resulting. */
|
---|
| 841 | }
|
---|
| 842 | }
|
---|
| 843 |
|
---|
| 844 |
|
---|
| 845 | RTDECL(int) RTVfsMemFileCreate(RTVFSIOSTREAM hVfsIos, size_t cbEstimate, PRTVFSFILE phVfsFile)
|
---|
| 846 | {
|
---|
| 847 | /*
|
---|
| 848 | * Create a memory file instance and set the extension size according to the
|
---|
| 849 | * buffer size. Add the WRITE flag so we can use normal write APIs for
|
---|
| 850 | * copying the buffer.
|
---|
| 851 | */
|
---|
| 852 | RTVFSFILE hVfsFile;
|
---|
| 853 | PRTVFSMEMFILE pThis;
|
---|
| 854 | int rc = RTVfsNewFile(&g_rtVfsMemFileOps, sizeof(*pThis), RTFILE_O_READ | RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
|
---|
| 855 | &hVfsFile, (void **)&pThis);
|
---|
| 856 | if (RT_SUCCESS(rc))
|
---|
| 857 | {
|
---|
[67181] | 858 | rtVfsMemInitObjInfo(&pThis->Base.ObjInfo, 0);
|
---|
[59524] | 859 | rtVfsMemFileInit(pThis, cbEstimate, RTFILE_O_READ | RTFILE_O_WRITE);
|
---|
| 860 |
|
---|
[62561] | 861 | if (hVfsIos != NIL_RTVFSIOSTREAM)
|
---|
| 862 | {
|
---|
| 863 | RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile);
|
---|
| 864 | rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent);
|
---|
| 865 | RTVfsIoStrmRelease(hVfsIosDst);
|
---|
| 866 | }
|
---|
| 867 |
|
---|
| 868 | if (RT_SUCCESS(rc))
|
---|
| 869 | {
|
---|
| 870 | *phVfsFile = hVfsFile;
|
---|
| 871 | return VINF_SUCCESS;
|
---|
| 872 | }
|
---|
| 873 |
|
---|
| 874 | RTVfsFileRelease(hVfsFile);
|
---|
[59524] | 875 | }
|
---|
| 876 | return rc;
|
---|
| 877 | }
|
---|
| 878 |
|
---|
| 879 |
|
---|
[67180] | 880 | RTDECL(int) RTVfsMemIoStrmCreate(RTVFSIOSTREAM hVfsIos, size_t cbEstimate, PRTVFSIOSTREAM phVfsIos)
|
---|
| 881 | {
|
---|
| 882 | RTVFSFILE hVfsFile;
|
---|
| 883 | int rc = RTVfsMemFileCreate(hVfsIos, cbEstimate, &hVfsFile);
|
---|
| 884 | if (RT_SUCCESS(rc))
|
---|
| 885 | {
|
---|
| 886 | *phVfsIos = RTVfsFileToIoStream(hVfsFile);
|
---|
| 887 | AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
|
---|
| 888 | RTVfsFileRelease(hVfsFile);
|
---|
| 889 | }
|
---|
| 890 | return rc;
|
---|
| 891 | }
|
---|
| 892 |
|
---|
| 893 |
|
---|
[59620] | 894 | RTDECL(int) RTVfsFileFromBuffer(uint32_t fFlags, void const *pvBuf, size_t cbBuf, PRTVFSFILE phVfsFile)
|
---|
[59524] | 895 | {
|
---|
| 896 | /*
|
---|
| 897 | * Create a memory file instance and set the extension size according to the
|
---|
| 898 | * buffer size. Add the WRITE flag so we can use normal write APIs for
|
---|
| 899 | * copying the buffer.
|
---|
| 900 | */
|
---|
| 901 | RTVFSFILE hVfsFile;
|
---|
| 902 | PRTVFSMEMFILE pThis;
|
---|
| 903 | int rc = RTVfsNewFile(&g_rtVfsMemFileOps, sizeof(*pThis), fFlags | RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
|
---|
| 904 | &hVfsFile, (void **)&pThis);
|
---|
| 905 | if (RT_SUCCESS(rc))
|
---|
| 906 | {
|
---|
[67181] | 907 | rtVfsMemInitObjInfo(&pThis->Base.ObjInfo, cbBuf);
|
---|
[59524] | 908 | rtVfsMemFileInit(pThis, cbBuf, fFlags);
|
---|
| 909 |
|
---|
| 910 | /*
|
---|
| 911 | * Copy the buffer and reposition the file pointer to the start.
|
---|
| 912 | */
|
---|
| 913 | rc = RTVfsFileWrite(hVfsFile, pvBuf, cbBuf, NULL);
|
---|
| 914 | if (RT_SUCCESS(rc))
|
---|
| 915 | {
|
---|
| 916 | rtVfsMemFileResetAndFixWriteFlag(pThis, fFlags);
|
---|
| 917 | *phVfsFile = hVfsFile;
|
---|
| 918 | return VINF_SUCCESS;
|
---|
| 919 | }
|
---|
| 920 | RTVfsFileRelease(hVfsFile);
|
---|
| 921 | }
|
---|
| 922 | return rc;
|
---|
| 923 | }
|
---|
| 924 |
|
---|
| 925 |
|
---|
[59620] | 926 | RTDECL(int) RTVfsIoStrmFromBuffer(uint32_t fFlags, void const *pvBuf, size_t cbBuf, PRTVFSIOSTREAM phVfsIos)
|
---|
| 927 | {
|
---|
| 928 | RTVFSFILE hVfsFile;
|
---|
| 929 | int rc = RTVfsFileFromBuffer(fFlags, pvBuf, cbBuf, &hVfsFile);
|
---|
| 930 | if (RT_SUCCESS(rc))
|
---|
| 931 | {
|
---|
| 932 | *phVfsIos = RTVfsFileToIoStream(hVfsFile);
|
---|
| 933 | RTVfsFileRelease(hVfsFile);
|
---|
| 934 | }
|
---|
| 935 | return rc;
|
---|
| 936 | }
|
---|
| 937 |
|
---|
| 938 |
|
---|
[34391] | 939 | RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile)
|
---|
| 940 | {
|
---|
[34407] | 941 | /*
|
---|
| 942 | * Create a memory file instance and try set the extension size to match
|
---|
| 943 | * the length of the I/O stream.
|
---|
| 944 | */
|
---|
| 945 | RTFSOBJINFO ObjInfo;
|
---|
| 946 | int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
|
---|
| 947 | if (RT_SUCCESS(rc))
|
---|
| 948 | {
|
---|
| 949 | RTVFSFILE hVfsFile;
|
---|
| 950 | PRTVFSMEMFILE pThis;
|
---|
[59524] | 951 | rc = RTVfsNewFile(&g_rtVfsMemFileOps, sizeof(*pThis), fFlags | RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
|
---|
[34441] | 952 | &hVfsFile, (void **)&pThis);
|
---|
[34407] | 953 | if (RT_SUCCESS(rc))
|
---|
| 954 | {
|
---|
| 955 | pThis->Base.ObjInfo = ObjInfo;
|
---|
[59524] | 956 | rtVfsMemFileInit(pThis, ObjInfo.cbObject, fFlags);
|
---|
[34407] | 957 |
|
---|
| 958 | /*
|
---|
| 959 | * Copy the stream.
|
---|
| 960 | */
|
---|
| 961 | RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile);
|
---|
| 962 | rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent);
|
---|
| 963 | RTVfsIoStrmRelease(hVfsIosDst);
|
---|
| 964 | if (RT_SUCCESS(rc))
|
---|
| 965 | {
|
---|
[59524] | 966 | rtVfsMemFileResetAndFixWriteFlag(pThis, fFlags);
|
---|
[34407] | 967 | *phVfsFile = hVfsFile;
|
---|
| 968 | return VINF_SUCCESS;
|
---|
| 969 | }
|
---|
| 970 | RTVfsFileRelease(hVfsFile);
|
---|
| 971 | }
|
---|
| 972 | }
|
---|
| 973 | return rc;
|
---|
[34391] | 974 | }
|
---|
[59524] | 975 |
|
---|