Changeset 34407 in vbox
- Timestamp:
- Nov 26, 2010 4:45:50 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/vfslowlevel.h
r34029 r34407 620 620 /** The structure version (RTVFSIOSTREAMOPS_VERSION). */ 621 621 uint32_t uVersion; 622 /** Reserved field, MBZ. */623 uint32_t f Reserved;622 /** Feature field. */ 623 uint32_t fFeatures; 624 624 625 625 /** … … 722 722 /** The RTVFSIOSTREAMOPS structure version. */ 723 723 #define RTVFSIOSTREAMOPS_VERSION RT_MAKE_U32_FROM_U8(0xff,0x6f,1,0) 724 725 /** @name RTVFSIOSTREAMOPS::fFeatures 726 * @{ */ 727 /** No scatter gather lists, thank you. */ 728 #define RTVFSIOSTREAMOPS_FEAT_NO_SG RT_BIT_32(0) 729 /** Mask of the valid I/O stream feature flags. */ 730 #define RTVFSIOSTREAMOPS_FEAT_VALID_MASK UINT32_C(0x00000001) 731 /** @} */ 724 732 725 733 … … 900 908 RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath); 901 909 910 /** 911 * Dummy implementation of RTVFSIOSTREAMOPS::pfnPollOne. 912 * 913 * This handles the case where there is no chance any events my be raised and 914 * all that is required is to wait according to the parameters. 915 * 916 * @returns IPRT status code. 917 * @param pvThis The implementation specific file data. 918 * @param fEvents The events to poll for (RTPOLL_EVT_XXX). 919 * @param cMillies How long to wait for event to eventuate. 920 * @param fIntr Whether the wait is interruptible and can return 921 * VERR_INTERRUPTED (@c true) or if this condition 922 * should be hidden from the caller (@c false). 923 * @param pfRetEvents Where to return the event mask. 924 * @sa RTVFSIOSTREAMOPS::pfnPollOne, RTPollSetAdd, RTPoll, RTPollNoResume. 925 */ 926 RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents); 927 928 /** 929 * Pumps data from one I/O stream to another. 930 * 931 * The data is read in chunks from @a hVfsIosSrc and written to @a hVfsIosDst 932 * until @hVfsIosSrc indicates end of stream. 933 * 934 * @returns IPRT status code 935 * 936 * @param hVfsIosSrc The input stream. 937 * @param hVfsIosDst The output stream. 938 * @param cbBufHint Hints at a good temporary buffer size, pass 0 if 939 * clueless. 940 */ 941 RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint); 942 902 943 /** @} */ 903 944 -
trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
r34055 r34407 101 101 RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \ 102 102 Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \ 103 Assert(!( pIoStreamOps)->fReserved); \103 Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \ 104 104 AssertPtr((pIoStreamOps)->pfnRead); \ 105 105 AssertPtr((pIoStreamOps)->pfnWrite); \ … … 1509 1509 1510 1510 1511 RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents) 1512 { 1513 int rc; 1514 if (fIntr) 1515 rc = RTThreadSleep(cMillies); 1516 else 1517 { 1518 uint64_t uMsStart = RTTimeMilliTS(); 1519 do 1520 rc = RTThreadSleep(cMillies); 1521 while ( rc == VERR_INTERRUPTED 1522 && !fIntr 1523 && RTTimeMilliTS() - uMsStart < cMillies); 1524 if (rc == VERR_INTERRUPTED) 1525 rc = VERR_TIMEOUT; 1526 } 1527 1528 *pfRetEvents = 0; 1529 return rc; 1530 } 1531 1532 1533 RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint) 1534 { 1535 /* 1536 * Allocate a temporary buffer. 1537 */ 1538 size_t cbBuf = cbBufHint; 1539 if (!cbBuf) 1540 cbBuf = _64K; 1541 else if (cbBuf < _4K) 1542 cbBuf = _4K; 1543 else if (cbBuf > _1M) 1544 cbBuf = _1M; 1545 1546 void *pvBuf = RTMemTmpAlloc(cbBuf); 1547 if (!pvBuf) 1548 { 1549 cbBuf = _4K; 1550 pvBuf = RTMemTmpAlloc(cbBuf); 1551 if (!pvBuf) 1552 return VERR_NO_TMP_MEMORY; 1553 } 1554 1555 /* 1556 * Pump loop. 1557 */ 1558 int rc; 1559 for (;;) 1560 { 1561 size_t cbRead; 1562 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead); 1563 if (RT_FAILURE(rc)) 1564 break; 1565 if (rc == VINF_EOF && cbRead == 0) 1566 break; 1567 1568 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/); 1569 if (RT_FAILURE(rc)) 1570 break; 1571 } 1572 1573 RTMemTmpFree(pvBuf); 1574 return rc; 1575 } 1576 1577 1511 1578 1512 1579 … … 1799 1866 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH); 1800 1867 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH); 1801 Assert(! pIoStreamOps->fReserved);1868 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); 1802 1869 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM); 1803 1870 Assert(cbInstance > 0); … … 1887 1954 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE); 1888 1955 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER); 1956 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED); 1889 1957 1890 1958 RTSGSEG Seg = { pvBuf, cbToRead }; … … 1908 1976 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE); 1909 1977 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER); 1978 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED); 1910 1979 1911 1980 RTSGSEG Seg = { (void *)pvBuf, cbToWrite }; … … 1930 1999 AssertPtr(pSgBuf); 1931 2000 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER); 2001 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED); 1932 2002 1933 2003 RTVfsLockAcquireWrite(pThis->Base.hLock); 1934 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead); 2004 int rc; 2005 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG)) 2006 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead); 2007 else 2008 { 2009 size_t cbRead = 0; 2010 rc = VINF_SUCCESS; 2011 2012 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++) 2013 { 2014 RTSGBUF SgBuf; 2015 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1); 2016 2017 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg; 2018 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL); 2019 if (RT_FAILURE(rc)) 2020 break; 2021 cbRead += cbReadSeg; 2022 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS) 2023 break; 2024 } 2025 2026 if (pcbRead) 2027 *pcbRead = cbRead; 2028 } 1935 2029 RTVfsLockReleaseWrite(pThis->Base.hLock); 1936 2030 return rc; … … 1948 2042 AssertPtr(pSgBuf); 1949 2043 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER); 2044 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED); 1950 2045 1951 2046 RTVfsLockAcquireWrite(pThis->Base.hLock); 1952 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten); 2047 int rc; 2048 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG)) 2049 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten); 2050 else 2051 { 2052 size_t cbWritten = 0; 2053 rc = VINF_SUCCESS; 2054 2055 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++) 2056 { 2057 RTSGBUF SgBuf; 2058 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1); 2059 2060 size_t cbWrittenSeg = 0; 2061 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL); 2062 if (RT_FAILURE(rc)) 2063 break; 2064 if (pcbWritten) 2065 { 2066 cbWritten += cbWrittenSeg; 2067 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg) 2068 break; 2069 } 2070 } 2071 2072 if (pcbWritten) 2073 *pcbWritten = cbWritten; 2074 } 1953 2075 RTVfsLockReleaseWrite(pThis->Base.hLock); 1954 2076 return rc; … … 2011 2133 RTVfsLockAcquireWrite(pThis->Base.hLock); 2012 2134 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb); 2135 RTVfsLockReleaseWrite(pThis->Base.hLock); 2136 } 2137 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE) 2138 { 2139 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream); 2140 RTFOFF offIgnored; 2141 2142 RTVfsLockAcquireWrite(pThis->Base.hLock); 2143 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored); 2013 2144 RTVfsLockReleaseWrite(pThis->Base.hLock); 2014 2145 } -
trunk/src/VBox/Runtime/common/vfs/vfsmemory.cpp
r34391 r34407 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Virtual File System, Memory Files.3 * IPRT - Virtual File System, Memory Backed VFS. 4 4 */ 5 5 … … 32 32 #include <iprt/vfs.h> 33 33 34 #include <iprt/asm.h> 34 35 #include <iprt/assert.h> 35 36 #include <iprt/err.h> 36 37 #include <iprt/file.h> 37 #include <iprt/handle.h> 38 #include <iprt/list.h> 39 #include <iprt/poll.h> 40 #include <iprt/string.h> 41 #include <iprt/vfslowlevel.h> 38 42 39 43 … … 49 53 50 54 55 /******************************************************************************* 56 * Defined Constants And Macros * 57 *******************************************************************************/ 58 /** The max extent size. */ 59 #define RTVFSMEM_MAX_EXTENT_SIZE _2M 60 61 62 /******************************************************************************* 63 * Structures and Typedefs * 64 *******************************************************************************/ 65 66 /** 67 * Memory base object info. 68 */ 69 typedef struct RTVFSMEMBASE 70 { 71 /** The basic object info. */ 72 RTFSOBJINFO ObjInfo; 73 } RTVFSMEMBASE; 74 75 76 /** 77 * Memory file extent. 78 * 79 * This stores part of the file content. 80 */ 81 typedef struct RTVFSMEMEXTENT 82 { 83 /** Extent list entry. */ 84 RTLISTNODE Entry; 85 /** The offset of this extent within the file. */ 86 uint64_t off; 87 /** The size of the this extent. */ 88 uint32_t cb; 89 /** The data. */ 90 uint8_t abData[1]; 91 } RTVFSMEMEXTENT; 92 /** Pointer to a memory file extent. */ 93 typedef RTVFSMEMEXTENT *PRTVFSMEMEXTENT; 94 95 /** 96 * Memory file. 97 */ 98 typedef struct RTVFSMEMFILE 99 { 100 /** The base info. */ 101 RTVFSMEMBASE Base; 102 /** The current file position. */ 103 uint64_t offCurPos; 104 /** Pointer to the current file extent. */ 105 PRTVFSMEMEXTENT pCurExt; 106 /** Linked list of file extents - RTVFSMEMEXTENT. */ 107 RTLISTNODE ExtentHead; 108 /** The current extent size. 109 * This is slowly grown to RTVFSMEM_MAX_EXTENT_SIZE as the file grows. */ 110 uint32_t cbExtent; 111 } RTVFSMEMFILE; 112 /** Pointer to a memory file. */ 113 typedef RTVFSMEMFILE *PRTVFSMEMFILE; 114 115 116 117 /** 118 * @interface_method_impl{RTVFSOBJOPS,pfnClose} 119 */ 120 static DECLCALLBACK(int) rtVfsMemFile_Close(void *pvThis) 121 { 122 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 123 124 /* 125 * Free the extent list. 126 */ 127 PRTVFSMEMEXTENT pCur, pNext; 128 RTListForEachSafe(&pThis->ExtentHead, pCur, pNext, RTVFSMEMEXTENT, Entry) 129 { 130 pCur->off = RTFOFF_MAX; 131 pCur->cb = UINT32_MAX; 132 RTListNodeRemove(&pCur->Entry); 133 RTMemFree(pCur); 134 } 135 pThis->pCurExt = NULL; 136 137 return VINF_SUCCESS; 138 } 139 140 141 /** 142 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo} 143 */ 144 static DECLCALLBACK(int) rtVfsMemFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr) 145 { 146 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 147 switch (enmAddAttr) 148 { 149 case RTFSOBJATTRADD_NOTHING: 150 case RTFSOBJATTRADD_UNIX: 151 *pObjInfo = pThis->Base.ObjInfo; 152 return VINF_SUCCESS; 153 154 default: 155 return VERR_NOT_SUPPORTED; 156 } 157 } 158 159 160 /** 161 * The slow paths of rtVfsMemFile_LocateExtent. 162 * 163 * @copydoc rtVfsMemFile_LocateExtent 164 */ 165 static PRTVFSMEMEXTENT rtVfsMemFile_LocateExtentSlow(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit) 166 { 167 /* 168 * Search from the start or the previously used extent. The heuristics 169 * are very very simple, but whatever. 170 */ 171 PRTVFSMEMEXTENT pExtent = pThis->pCurExt; 172 if (!pExtent || pExtent->off < off) 173 { 174 pExtent = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry); 175 if (!pExtent) 176 { 177 *pfHit = false; 178 return NULL; 179 } 180 } 181 182 while (off - pExtent->off >= pExtent->cb) 183 { 184 Assert(pExtent->off <= off); 185 PRTVFSMEMEXTENT pNext = RTListNodeGetNext(&pExtent->Entry, RTVFSMEMEXTENT, Entry); 186 if ( RTListNodeIsLast(&pThis->ExtentHead, &pNext->Entry) 187 || pNext->off > off) 188 { 189 *pfHit = false; 190 return pExtent; 191 } 192 193 pExtent = pNext; 194 } 195 196 *pfHit = true; 197 pThis->pCurExt = pExtent; 198 return pExtent; 199 } 200 201 202 /** 203 * Locates the extent covering the specified offset, or then one before it. 204 * 205 * @returns The closest extent. NULL if off is 0 and there are no extent 206 * covering byte 0 yet. 207 * @param pThis The memory file. 208 * @param off The offset (0-positive). 209 * @param pfHit Where to indicate whether the extent is a 210 * direct hit (@c true) or just a closest match 211 * (@c false). 212 */ 213 DECLINLINE(PRTVFSMEMEXTENT) rtVfsMemFile_LocateExtent(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit) 214 { 215 /* 216 * The most likely case is that we're hitting the extent we used in the 217 * previous access or the one immediately following it. 218 */ 219 PRTVFSMEMEXTENT pExtent = pThis->pCurExt; 220 if (!pExtent) 221 return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit); 222 223 if (off - pExtent->off >= pExtent->cb) 224 { 225 pExtent = RTListNodeGetNext(&pExtent->Entry, RTVFSMEMEXTENT, Entry); 226 if ( !pExtent 227 || off - pExtent->off >= pExtent->cb) 228 return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit); 229 pThis->pCurExt = pExtent; 230 } 231 232 *pfHit = true; 233 return pExtent; 234 } 235 236 237 /** 238 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead} 239 */ 240 static DECLCALLBACK(int) rtVfsMemFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead) 241 { 242 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 243 244 Assert(pSgBuf->cSegs == 1); 245 Assert(off < 0); 246 NOREF(fBlocking); 247 248 /* 249 * Find the current position and check if it's within the file. 250 */ 251 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off; 252 if (offUnsigned >= (uint64_t)pThis->Base.ObjInfo.cbObject) 253 { 254 if (pcbRead) 255 { 256 *pcbRead = 0; 257 pThis->offCurPos = offUnsigned; 258 return VINF_EOF; 259 } 260 return VERR_EOF; 261 } 262 263 size_t cbLeftToRead; 264 if (offUnsigned + pSgBuf->paSegs[0].cbSeg > (uint64_t)pThis->Base.ObjInfo.cbObject) 265 { 266 if (!pcbRead) 267 return VERR_EOF; 268 *pcbRead = cbLeftToRead = (size_t)((uint64_t)pThis->Base.ObjInfo.cbObject - offUnsigned); 269 } 270 else 271 *pcbRead = cbLeftToRead = pSgBuf->paSegs[0].cbSeg; 272 273 /* 274 * Ok, we've got a valid stretch within the file. Do the reading. 275 */ 276 if (cbLeftToRead > 0) 277 { 278 uint8_t *pbDst = (uint8_t *)pSgBuf->paSegs[0].pvSeg; 279 bool fHit; 280 PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit); 281 for (;;) 282 { 283 PRTVFSMEMEXTENT pNext; 284 size_t cbThisRead; 285 Assert(!pExtent || pExtent->off <= offUnsigned); 286 287 /* 288 * Do we hit an extent covering the the current file surface? 289 */ 290 if (fHit) 291 { 292 size_t const offExtent = (size_t)(offUnsigned - pExtent->off); 293 cbThisRead = pExtent->cb - offExtent; 294 if (cbThisRead >= cbLeftToRead) 295 cbThisRead = cbLeftToRead; 296 297 memcpy(pbDst, &pExtent->abData[offUnsigned - pExtent->off], cbThisRead); 298 299 offUnsigned += cbThisRead; 300 cbLeftToRead -= cbThisRead; 301 if (!cbLeftToRead) 302 break; 303 pbDst += cbThisRead; 304 305 pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry); 306 if ( pNext 307 && pNext->off == pExtent->off + pExtent->cb) 308 { 309 pExtent = pNext; 310 continue; 311 } 312 fHit = false; 313 } 314 315 /* 316 * No extent of this portion (sparse file). 317 */ 318 else if (pExtent) 319 pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry); 320 else 321 pNext = NULL; 322 Assert(!pNext || pNext->off > pExtent->off); 323 324 if ( !pNext 325 || offUnsigned + cbLeftToRead <= pNext->off) 326 cbThisRead = cbLeftToRead; 327 else 328 cbThisRead = pNext->off - offUnsigned; 329 330 RT_BZERO(pbDst, cbThisRead); 331 332 offUnsigned += cbThisRead; 333 cbLeftToRead -= cbThisRead; 334 if (!cbLeftToRead) 335 break; 336 pbDst += cbThisRead; 337 338 /* Go on and read content from the next extent. */ 339 fHit = true; 340 pExtent = pNext; 341 } 342 } 343 344 pThis->offCurPos = offUnsigned; 345 return VINF_SUCCESS; 346 } 347 348 349 /** 350 * Allocates a new extent covering the ground at @a offUnsigned. 351 * 352 * @returns Pointer to the new extent on success, NULL if we're out of memory. 353 * @param pThis The memory file. 354 * @param offUnsigned The location to allocate the extent at. 355 * @param cbToWrite The number of bytes we're interested in writing 356 * starting at @a offUnsigned. 357 * @param pPrev The extention before @a offUnsigned. NULL if 358 * none. 359 */ 360 static PRTVFSMEMEXTENT rtVfsMemFile_AllocExtent(PRTVFSMEMFILE pThis, uint64_t offUnsigned, size_t cbToWrite, 361 PRTVFSMEMEXTENT pPrev) 362 { 363 /* 364 * Adjust the extent size if we haven't reached the max size yet. 365 */ 366 if (pThis->cbExtent != RTVFSMEM_MAX_EXTENT_SIZE) 367 { 368 if (cbToWrite >= RTVFSMEM_MAX_EXTENT_SIZE) 369 pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE; 370 else if (!RTListIsEmpty(&pThis->ExtentHead)) 371 { 372 size_t cbNextExtent = pThis->cbExtent; 373 if (RT_IS_POWER_OF_TWO(cbNextExtent)) 374 cbNextExtent *= 2; 375 else 376 { 377 /* Make it a power of two (seeRTVfsMemorizeIoStreamAsFile). */ 378 cbNextExtent = _4K; 379 while (cbNextExtent < pThis->cbExtent) 380 cbNextExtent *= 2; 381 } 382 if (((pThis->Base.ObjInfo.cbAllocated + cbNextExtent) & (cbNextExtent - 1)) == 0) 383 pThis->cbExtent = cbNextExtent; 384 } 385 } 386 387 /* 388 * Figure out the size and position of the extent we're adding. 389 */ 390 uint64_t offExtent = offUnsigned & ~(uint64_t)(pThis->cbExtent - 1); 391 uint32_t cbExtent = pThis->cbExtent; 392 393 uint64_t const offPrev = pPrev ? pPrev->off + pPrev->cb : 0; 394 if (offExtent < offPrev) 395 offExtent = offPrev; 396 397 PRTVFSMEMEXTENT pNext = pPrev 398 ? RTListGetNext(&pThis->ExtentHead, pPrev, RTVFSMEMEXTENT, Entry) 399 : RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry); 400 if (pNext) 401 { 402 uint64_t cbMaxExtent = pNext->off - offExtent; 403 if (cbMaxExtent < cbExtent) 404 cbExtent = cbMaxExtent; 405 } 406 407 /* 408 * Allocate, initialize and insert the new extent. 409 */ 410 PRTVFSMEMEXTENT pNew = (PRTVFSMEMEXTENT)RTMemAllocZ(RT_OFFSETOF(RTVFSMEMEXTENT, abData[cbExtent])); 411 if (pNew) 412 { 413 pNew->off = offExtent; 414 pNew->cb = cbExtent; 415 if (pPrev) 416 RTListNodeInsertAfter(&pPrev->Entry, &pNew->Entry); 417 else 418 RTListPrepend(&pThis->ExtentHead, &pNew->Entry); 419 420 pThis->Base.ObjInfo.cbAllocated += cbExtent; 421 } 422 /** @todo retry with minimum size. */ 423 424 return pNew; 425 } 426 427 428 /** 429 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite} 430 */ 431 static DECLCALLBACK(int) rtVfsMemFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten) 432 { 433 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 434 435 Assert(pSgBuf->cSegs == 1); 436 Assert(off < 0); 437 NOREF(fBlocking); 438 439 /* 440 * Validate the write and set up the write loop. 441 */ 442 size_t cbLeftToWrite = pSgBuf->paSegs[0].cbSeg; 443 if (!cbLeftToWrite) 444 return VINF_SUCCESS; /* pcbWritten is already 0. */ 445 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off; 446 if (offUnsigned + cbLeftToWrite >= (uint64_t)RTFOFF_MAX) 447 return VERR_OUT_OF_RANGE; 448 449 int rc = VINF_SUCCESS; 450 uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg; 451 bool fHit; 452 PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit); 453 for (;;) 454 { 455 /* 456 * If we didn't hit an extent, allocate one (unless it's all zeros). 457 */ 458 if (!fHit) 459 { 460 Assert(!pExtent || (pExtent->off < offUnsigned && pExtent->off + pExtent->cb <= offUnsigned)); 461 462 /* Skip leading zeros if there is a whole bunch of them. */ 463 uint8_t const *pbSrcNZ = (uint8_t const *)ASMMemIsAll8(pbSrc, cbLeftToWrite, 0); 464 if (!pbSrcNZ) 465 { 466 offUnsigned += cbLeftToWrite; 467 cbLeftToWrite = 0; 468 break; 469 } 470 size_t const cbZeros = pbSrcNZ - pbSrc; 471 if (cbZeros >= RT_MIN(pThis->cbExtent, _64K)) 472 { 473 offUnsigned += cbZeros; 474 cbLeftToWrite -= cbZeros; 475 pbSrc = pbSrcNZ; 476 pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit); 477 break; 478 } 479 480 fHit = true; 481 pExtent = rtVfsMemFile_AllocExtent(pThis, offUnsigned, cbLeftToWrite, pExtent); 482 if (!pExtent) 483 { 484 rc = VERR_NO_MEMORY; 485 break; 486 } 487 } 488 489 /* 490 * Copy the source data into the current extent. 491 */ 492 uint32_t const offDst = offUnsigned - pExtent->off; 493 uint32_t cbThisWrite = pExtent->cb - offDst; 494 if (cbThisWrite > cbLeftToWrite) 495 cbThisWrite = (uint32_t)cbLeftToWrite; 496 memcpy(&pExtent->abData[offDst], pbSrc, cbThisWrite); 497 498 offUnsigned += cbLeftToWrite; 499 cbLeftToWrite -= cbThisWrite; 500 if (!cbLeftToWrite) 501 break; 502 pbSrc += cbThisWrite; 503 Assert(offUnsigned == pExtent->off + pExtent->cb); 504 505 /* 506 * Advance to the next extent. 507 */ 508 PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry); 509 Assert(!pNext || pNext->off >= offUnsigned); 510 if (pNext && pNext->off == offUnsigned) 511 pExtent = pNext; 512 else 513 fHit = false; 514 } 515 516 /* 517 * Update the state, set return value and return. 518 * Note! There must be no alternative exit path from the loop above. 519 */ 520 pThis->offCurPos = offUnsigned; 521 if ((uint64_t)pThis->Base.ObjInfo.cbObject < offUnsigned) 522 pThis->Base.ObjInfo.cbObject = offUnsigned; 523 524 if (pcbWritten) 525 *pcbWritten = pSgBuf->paSegs[0].cbSeg - cbLeftToWrite; 526 return rc; 527 } 528 529 530 /** 531 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush} 532 */ 533 static DECLCALLBACK(int) rtVfsMemFile_Flush(void *pvThis) 534 { 535 NOREF(pvThis); 536 return VINF_SUCCESS; 537 } 538 539 540 /** 541 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne} 542 */ 543 static DECLCALLBACK(int) rtVfsMemFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, 544 uint32_t *pfRetEvents) 545 { 546 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 547 int rc; 548 549 if (fEvents != RTPOLL_EVT_ERROR) 550 { 551 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR; 552 rc = VINF_SUCCESS; 553 } 554 else 555 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents); 556 return rc; 557 } 558 559 560 /** 561 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell} 562 */ 563 static DECLCALLBACK(int) rtVfsMemFile_Tell(void *pvThis, PRTFOFF poffActual) 564 { 565 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 566 *poffActual = pThis->offCurPos; 567 return VINF_SUCCESS; 568 } 569 570 571 /** 572 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode} 573 */ 574 static DECLCALLBACK(int) rtVfsMemFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask) 575 { 576 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 577 pThis->Base.ObjInfo.Attr.fMode = (pThis->Base.ObjInfo.Attr.fMode & ~fMask) | fMode; 578 return VINF_SUCCESS; 579 } 580 581 582 /** 583 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes} 584 */ 585 static DECLCALLBACK(int) rtVfsMemFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, 586 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime) 587 { 588 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 589 590 if (pAccessTime) 591 pThis->Base.ObjInfo.AccessTime = *pAccessTime; 592 if (pModificationTime) 593 pThis->Base.ObjInfo.ModificationTime = *pModificationTime; 594 if (pChangeTime) 595 pThis->Base.ObjInfo.ChangeTime = *pChangeTime; 596 if (pBirthTime) 597 pThis->Base.ObjInfo.BirthTime = *pBirthTime; 598 599 return VINF_SUCCESS; 600 } 601 602 603 /** 604 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner} 605 */ 606 static DECLCALLBACK(int) rtVfsMemFile_SetOwner(void *pvThis, RTUID uid, RTGID gid) 607 { 608 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 609 610 if (uid != NIL_RTUID) 611 pThis->Base.ObjInfo.Attr.u.Unix.uid = uid; 612 if (gid != NIL_RTUID) 613 pThis->Base.ObjInfo.Attr.u.Unix.gid = gid; 614 615 return VINF_SUCCESS; 616 } 617 618 619 /** 620 * @interface_method_impl{RTVFSFILEOPS,pfnSeek} 621 */ 622 static DECLCALLBACK(int) rtVfsMemFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual) 623 { 624 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 625 626 /* 627 * Seek relative to which position. 628 */ 629 uint64_t offWrt; 630 switch (uMethod) 631 { 632 case RTFILE_SEEK_BEGIN: 633 offWrt = 0; 634 break; 635 636 case RTFILE_SEEK_CURRENT: 637 offWrt = pThis->offCurPos; 638 break; 639 640 case RTFILE_SEEK_END: 641 offWrt = pThis->Base.ObjInfo.cbObject; 642 break; 643 644 default: 645 return VERR_INTERNAL_ERROR_5; 646 } 647 648 /* 649 * Calc new position, take care to stay without bounds. 650 */ 651 uint64_t offNew; 652 if (offSeek == 0) 653 offNew = offWrt; 654 else if (offSeek > 0) 655 { 656 offNew = offWrt + offSeek; 657 if ( offNew < offWrt 658 || offNew > RTFOFF_MAX) 659 offNew = RTFOFF_MAX; 660 } 661 else if ((uint64_t)-offSeek < offNew) 662 offNew = offWrt + offSeek; 663 else 664 offNew = 0; 665 666 /* 667 * Update the state and set return value. 668 */ 669 if ( pThis->pCurExt 670 && pThis->pCurExt->off - offNew >= pThis->pCurExt->cb) 671 pThis->pCurExt = NULL; 672 pThis->offCurPos = offNew; 673 674 *poffActual = offNew; 675 return VINF_SUCCESS; 676 } 677 678 679 /** 680 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize} 681 */ 682 static DECLCALLBACK(int) rtVfsMemFile_QuerySize(void *pvThis, uint64_t *pcbFile) 683 { 684 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis; 685 return pThis->Base.ObjInfo.cbObject; 686 } 687 688 689 /** 690 * Standard file operations. 691 */ 692 DECLHIDDEN(const RTVFSFILEOPS) g_rtVfsStdFileOps = 693 { 694 { /* Stream */ 695 { /* Obj */ 696 RTVFSOBJOPS_VERSION, 697 RTVFSOBJTYPE_FILE, 698 "MemFile", 699 rtVfsMemFile_Close, 700 rtVfsMemFile_QueryInfo, 701 RTVFSOBJOPS_VERSION 702 }, 703 RTVFSIOSTREAMOPS_VERSION, 704 RTVFSIOSTREAMOPS_FEAT_NO_SG, 705 rtVfsMemFile_Read, 706 rtVfsMemFile_Write, 707 rtVfsMemFile_Flush, 708 rtVfsMemFile_PollOne, 709 rtVfsMemFile_Tell, 710 NULL /*Skip*/, 711 NULL /*ZeroFill*/, 712 RTVFSIOSTREAMOPS_VERSION, 713 }, 714 RTVFSFILEOPS_VERSION, 715 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0, 716 { /* ObjSet */ 717 RTVFSOBJSETOPS_VERSION, 718 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet), 719 rtVfsMemFile_SetMode, 720 rtVfsMemFile_SetTimes, 721 rtVfsMemFile_SetOwner, 722 RTVFSOBJSETOPS_VERSION 723 }, 724 rtVfsMemFile_Seek, 725 rtVfsMemFile_QuerySize, 726 RTVFSFILEOPS_VERSION 727 }; 728 729 730 51 731 52 732 53 733 RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile) 54 734 { 55 return VERR_NOT_IMPLEMENTED; 56 } 735 /* 736 * Create a memory file instance and try set the extension size to match 737 * the length of the I/O stream. 738 */ 739 RTFSOBJINFO ObjInfo; 740 int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX); 741 if (RT_SUCCESS(rc)) 742 { 743 RTVFSFILE hVfsFile; 744 PRTVFSMEMFILE pThis; 745 rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(*pThis), fFlags, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis); 746 if (RT_SUCCESS(rc)) 747 { 748 pThis->Base.ObjInfo = ObjInfo; 749 pThis->offCurPos = 0; 750 pThis->pCurExt = NULL; 751 RTListInit(&pThis->ExtentHead); 752 if (ObjInfo.cbObject <= 0) 753 pThis->cbExtent = _4K; 754 else if (ObjInfo.cbObject < RTVFSMEM_MAX_EXTENT_SIZE) 755 pThis->cbExtent = _4K; 756 else 757 pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE; 758 759 /* 760 * Copy the stream. 761 */ 762 RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile); 763 rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent); 764 RTVfsIoStrmRelease(hVfsIosDst); 765 if (RT_SUCCESS(rc)) 766 { 767 *phVfsFile = hVfsFile; 768 return VINF_SUCCESS; 769 } 770 RTVfsFileRelease(hVfsFile); 771 } 772 } 773 return rc; 774 }
Note:
See TracChangeset
for help on using the changeset viewer.