VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsmemory.cpp@ 36596

Last change on this file since 36596 was 36555, checked in by vboxsync, 14 years ago

Use DECLHIDDEN, especially in IPRT.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Id: vfsmemory.cpp 36555 2011-04-05 12:34:09Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Memory Backed VFS.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/vfs.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/file.h>
38#include <iprt/list.h>
39#include <iprt/poll.h>
40#include <iprt/string.h>
41#include <iprt/vfslowlevel.h>
42
43
44
45/*******************************************************************************
46* Header Files *
47*******************************************************************************/
48#include "internal/iprt.h"
49#include <iprt/vfs.h>
50
51#include <iprt/err.h>
52#include <iprt/mem.h>
53
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 */
69typedef 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 */
81typedef 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. */
93typedef RTVFSMEMEXTENT *PRTVFSMEMEXTENT;
94
95/**
96 * Memory file.
97 */
98typedef 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. */
113typedef RTVFSMEMFILE *PRTVFSMEMFILE;
114
115
116
117/**
118 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
119 */
120static 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 */
144static 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 */
165static 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 = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
186 if ( !pNext
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 */
213DECLINLINE(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 = RTListGetNext(&pThis->ExtentHead, pExtent, 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 */
240static 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 {
272 cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
273 if (pcbRead)
274 *pcbRead = cbLeftToRead;
275 }
276
277 /*
278 * Ok, we've got a valid stretch within the file. Do the reading.
279 */
280 if (cbLeftToRead > 0)
281 {
282 uint8_t *pbDst = (uint8_t *)pSgBuf->paSegs[0].pvSeg;
283 bool fHit;
284 PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
285 for (;;)
286 {
287 PRTVFSMEMEXTENT pNext;
288 size_t cbThisRead;
289 Assert(!pExtent || pExtent->off <= offUnsigned);
290
291 /*
292 * Do we hit an extent covering the the current file surface?
293 */
294 if (fHit)
295 {
296 size_t const offExtent = (size_t)(offUnsigned - pExtent->off);
297 cbThisRead = pExtent->cb - offExtent;
298 if (cbThisRead >= cbLeftToRead)
299 cbThisRead = cbLeftToRead;
300
301 memcpy(pbDst, &pExtent->abData[offUnsigned - pExtent->off], cbThisRead);
302
303 offUnsigned += cbThisRead;
304 cbLeftToRead -= cbThisRead;
305 if (!cbLeftToRead)
306 break;
307 pbDst += cbThisRead;
308
309 pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
310 if ( pNext
311 && pNext->off == pExtent->off + pExtent->cb)
312 {
313 pExtent = pNext;
314 continue;
315 }
316 fHit = false;
317 }
318
319 /*
320 * No extent of this portion (sparse file).
321 */
322 else if (pExtent)
323 pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
324 else
325 pNext = NULL;
326 Assert(!pNext || pNext->off > pExtent->off);
327
328 if ( !pNext
329 || offUnsigned + cbLeftToRead <= pNext->off)
330 cbThisRead = cbLeftToRead;
331 else
332 cbThisRead = (size_t)(pNext->off - offUnsigned);
333
334 RT_BZERO(pbDst, cbThisRead);
335
336 offUnsigned += cbThisRead;
337 cbLeftToRead -= cbThisRead;
338 if (!cbLeftToRead)
339 break;
340 pbDst += cbThisRead;
341
342 /* Go on and read content from the next extent. */
343 fHit = true;
344 pExtent = pNext;
345 }
346 }
347
348 pThis->offCurPos = offUnsigned;
349 return VINF_SUCCESS;
350}
351
352
353/**
354 * Allocates a new extent covering the ground at @a offUnsigned.
355 *
356 * @returns Pointer to the new extent on success, NULL if we're out of memory.
357 * @param pThis The memory file.
358 * @param offUnsigned The location to allocate the extent at.
359 * @param cbToWrite The number of bytes we're interested in writing
360 * starting at @a offUnsigned.
361 * @param pPrev The extention before @a offUnsigned. NULL if
362 * none.
363 */
364static PRTVFSMEMEXTENT rtVfsMemFile_AllocExtent(PRTVFSMEMFILE pThis, uint64_t offUnsigned, size_t cbToWrite,
365 PRTVFSMEMEXTENT pPrev)
366{
367 /*
368 * Adjust the extent size if we haven't reached the max size yet.
369 */
370 if (pThis->cbExtent != RTVFSMEM_MAX_EXTENT_SIZE)
371 {
372 if (cbToWrite >= RTVFSMEM_MAX_EXTENT_SIZE)
373 pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
374 else if (!RTListIsEmpty(&pThis->ExtentHead))
375 {
376 uint32_t cbNextExtent = pThis->cbExtent;
377 if (RT_IS_POWER_OF_TWO(cbNextExtent))
378 cbNextExtent *= 2;
379 else
380 {
381 /* Make it a power of two (seeRTVfsMemorizeIoStreamAsFile). */
382 cbNextExtent = _4K;
383 while (cbNextExtent < pThis->cbExtent)
384 cbNextExtent *= 2;
385 }
386 if (((pThis->Base.ObjInfo.cbAllocated + cbNextExtent) & (cbNextExtent - 1)) == 0)
387 pThis->cbExtent = cbNextExtent;
388 }
389 }
390
391 /*
392 * Figure out the size and position of the extent we're adding.
393 */
394 uint64_t offExtent = offUnsigned & ~(uint64_t)(pThis->cbExtent - 1);
395 uint32_t cbExtent = pThis->cbExtent;
396
397 uint64_t const offPrev = pPrev ? pPrev->off + pPrev->cb : 0;
398 if (offExtent < offPrev)
399 offExtent = offPrev;
400
401 PRTVFSMEMEXTENT pNext = pPrev
402 ? RTListGetNext(&pThis->ExtentHead, pPrev, RTVFSMEMEXTENT, Entry)
403 : RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
404 if (pNext)
405 {
406 uint64_t cbMaxExtent = pNext->off - offExtent;
407 if (cbMaxExtent < cbExtent)
408 cbExtent = (uint32_t)cbMaxExtent;
409 }
410
411 /*
412 * Allocate, initialize and insert the new extent.
413 */
414 PRTVFSMEMEXTENT pNew = (PRTVFSMEMEXTENT)RTMemAllocZ(RT_OFFSETOF(RTVFSMEMEXTENT, abData[cbExtent]));
415 if (pNew)
416 {
417 pNew->off = offExtent;
418 pNew->cb = cbExtent;
419 if (pPrev)
420 RTListNodeInsertAfter(&pPrev->Entry, &pNew->Entry);
421 else
422 RTListPrepend(&pThis->ExtentHead, &pNew->Entry);
423
424 pThis->Base.ObjInfo.cbAllocated += cbExtent;
425 }
426 /** @todo retry with minimum size. */
427
428 return pNew;
429}
430
431
432/**
433 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
434 */
435static DECLCALLBACK(int) rtVfsMemFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
436{
437 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
438
439 Assert(pSgBuf->cSegs == 1);
440 Assert(off < 0);
441 NOREF(fBlocking);
442
443 /*
444 * Validate the write and set up the write loop.
445 */
446 size_t cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
447 if (!cbLeftToWrite)
448 return VINF_SUCCESS; /* pcbWritten is already 0. */
449 uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
450 if (offUnsigned + cbLeftToWrite >= (uint64_t)RTFOFF_MAX)
451 return VERR_OUT_OF_RANGE;
452
453 int rc = VINF_SUCCESS;
454 uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
455 bool fHit;
456 PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
457 for (;;)
458 {
459 /*
460 * If we didn't hit an extent, allocate one (unless it's all zeros).
461 */
462 if (!fHit)
463 {
464 Assert(!pExtent || (pExtent->off < offUnsigned && pExtent->off + pExtent->cb <= offUnsigned));
465
466 /* Skip leading zeros if there is a whole bunch of them. */
467 uint8_t const *pbSrcNZ = (uint8_t const *)ASMMemIsAll8(pbSrc, cbLeftToWrite, 0);
468 if (!pbSrcNZ)
469 {
470 offUnsigned += cbLeftToWrite;
471 cbLeftToWrite = 0;
472 break;
473 }
474 size_t const cbZeros = pbSrcNZ - pbSrc;
475 if (cbZeros >= RT_MIN(pThis->cbExtent, _64K))
476 {
477 offUnsigned += cbZeros;
478 cbLeftToWrite -= cbZeros;
479 pbSrc = pbSrcNZ;
480 pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
481 break;
482 }
483
484 fHit = true;
485 pExtent = rtVfsMemFile_AllocExtent(pThis, offUnsigned, cbLeftToWrite, pExtent);
486 if (!pExtent)
487 {
488 rc = VERR_NO_MEMORY;
489 break;
490 }
491 }
492
493 /*
494 * Copy the source data into the current extent.
495 */
496 uint32_t const offDst = (uint32_t)(offUnsigned - pExtent->off);
497 uint32_t cbThisWrite = pExtent->cb - offDst;
498 if (cbThisWrite > cbLeftToWrite)
499 cbThisWrite = (uint32_t)cbLeftToWrite;
500 memcpy(&pExtent->abData[offDst], pbSrc, cbThisWrite);
501
502 offUnsigned += cbLeftToWrite;
503 cbLeftToWrite -= cbThisWrite;
504 if (!cbLeftToWrite)
505 break;
506 pbSrc += cbThisWrite;
507 Assert(offUnsigned == pExtent->off + pExtent->cb);
508
509 /*
510 * Advance to the next extent.
511 */
512 PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
513 Assert(!pNext || pNext->off >= offUnsigned);
514 if (pNext && pNext->off == offUnsigned)
515 pExtent = pNext;
516 else
517 fHit = false;
518 }
519
520 /*
521 * Update the state, set return value and return.
522 * Note! There must be no alternative exit path from the loop above.
523 */
524 pThis->offCurPos = offUnsigned;
525 if ((uint64_t)pThis->Base.ObjInfo.cbObject < offUnsigned)
526 pThis->Base.ObjInfo.cbObject = offUnsigned;
527
528 if (pcbWritten)
529 *pcbWritten = pSgBuf->paSegs[0].cbSeg - cbLeftToWrite;
530 return rc;
531}
532
533
534/**
535 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
536 */
537static DECLCALLBACK(int) rtVfsMemFile_Flush(void *pvThis)
538{
539 NOREF(pvThis);
540 return VINF_SUCCESS;
541}
542
543
544/**
545 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
546 */
547static DECLCALLBACK(int) rtVfsMemFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
548 uint32_t *pfRetEvents)
549{
550 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
551 int rc;
552
553 if (fEvents != RTPOLL_EVT_ERROR)
554 {
555 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
556 rc = VINF_SUCCESS;
557 }
558 else
559 rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
560 return rc;
561}
562
563
564/**
565 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
566 */
567static DECLCALLBACK(int) rtVfsMemFile_Tell(void *pvThis, PRTFOFF poffActual)
568{
569 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
570 *poffActual = pThis->offCurPos;
571 return VINF_SUCCESS;
572}
573
574
575/**
576 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
577 */
578static DECLCALLBACK(int) rtVfsMemFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
579{
580 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
581 pThis->Base.ObjInfo.Attr.fMode = (pThis->Base.ObjInfo.Attr.fMode & ~fMask) | fMode;
582 return VINF_SUCCESS;
583}
584
585
586/**
587 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
588 */
589static DECLCALLBACK(int) rtVfsMemFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
590 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
591{
592 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
593
594 if (pAccessTime)
595 pThis->Base.ObjInfo.AccessTime = *pAccessTime;
596 if (pModificationTime)
597 pThis->Base.ObjInfo.ModificationTime = *pModificationTime;
598 if (pChangeTime)
599 pThis->Base.ObjInfo.ChangeTime = *pChangeTime;
600 if (pBirthTime)
601 pThis->Base.ObjInfo.BirthTime = *pBirthTime;
602
603 return VINF_SUCCESS;
604}
605
606
607/**
608 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
609 */
610static DECLCALLBACK(int) rtVfsMemFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
611{
612 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
613
614 if (uid != NIL_RTUID)
615 pThis->Base.ObjInfo.Attr.u.Unix.uid = uid;
616 if (gid != NIL_RTUID)
617 pThis->Base.ObjInfo.Attr.u.Unix.gid = gid;
618
619 return VINF_SUCCESS;
620}
621
622
623/**
624 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
625 */
626static DECLCALLBACK(int) rtVfsMemFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
627{
628 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
629
630 /*
631 * Seek relative to which position.
632 */
633 uint64_t offWrt;
634 switch (uMethod)
635 {
636 case RTFILE_SEEK_BEGIN:
637 offWrt = 0;
638 break;
639
640 case RTFILE_SEEK_CURRENT:
641 offWrt = pThis->offCurPos;
642 break;
643
644 case RTFILE_SEEK_END:
645 offWrt = pThis->Base.ObjInfo.cbObject;
646 break;
647
648 default:
649 return VERR_INTERNAL_ERROR_5;
650 }
651
652 /*
653 * Calc new position, take care to stay without bounds.
654 */
655 uint64_t offNew;
656 if (offSeek == 0)
657 offNew = offWrt;
658 else if (offSeek > 0)
659 {
660 offNew = offWrt + offSeek;
661 if ( offNew < offWrt
662 || offNew > RTFOFF_MAX)
663 offNew = RTFOFF_MAX;
664 }
665 else if ((uint64_t)-offSeek < offWrt)
666 offNew = offWrt + offSeek;
667 else
668 offNew = 0;
669
670 /*
671 * Update the state and set return value.
672 */
673 if ( pThis->pCurExt
674 && pThis->pCurExt->off - offNew >= pThis->pCurExt->cb)
675 pThis->pCurExt = NULL;
676 pThis->offCurPos = offNew;
677
678 *poffActual = offNew;
679 return VINF_SUCCESS;
680}
681
682
683/**
684 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
685 */
686static DECLCALLBACK(int) rtVfsMemFile_QuerySize(void *pvThis, uint64_t *pcbFile)
687{
688 PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
689 *pcbFile = pThis->Base.ObjInfo.cbObject;
690 return VINF_SUCCESS;
691}
692
693
694/**
695 * Standard file operations.
696 */
697DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsStdFileOps =
698{
699 { /* Stream */
700 { /* Obj */
701 RTVFSOBJOPS_VERSION,
702 RTVFSOBJTYPE_FILE,
703 "MemFile",
704 rtVfsMemFile_Close,
705 rtVfsMemFile_QueryInfo,
706 RTVFSOBJOPS_VERSION
707 },
708 RTVFSIOSTREAMOPS_VERSION,
709 RTVFSIOSTREAMOPS_FEAT_NO_SG,
710 rtVfsMemFile_Read,
711 rtVfsMemFile_Write,
712 rtVfsMemFile_Flush,
713 rtVfsMemFile_PollOne,
714 rtVfsMemFile_Tell,
715 NULL /*Skip*/,
716 NULL /*ZeroFill*/,
717 RTVFSIOSTREAMOPS_VERSION,
718 },
719 RTVFSFILEOPS_VERSION,
720 /*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
721 { /* ObjSet */
722 RTVFSOBJSETOPS_VERSION,
723 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
724 rtVfsMemFile_SetMode,
725 rtVfsMemFile_SetTimes,
726 rtVfsMemFile_SetOwner,
727 RTVFSOBJSETOPS_VERSION
728 },
729 rtVfsMemFile_Seek,
730 rtVfsMemFile_QuerySize,
731 RTVFSFILEOPS_VERSION
732};
733
734
735
736
737
738RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile)
739{
740 /*
741 * Create a memory file instance and try set the extension size to match
742 * the length of the I/O stream.
743 */
744 RTFSOBJINFO ObjInfo;
745 int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
746 if (RT_SUCCESS(rc))
747 {
748 RTVFSFILE hVfsFile;
749 PRTVFSMEMFILE pThis;
750 rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(*pThis), fFlags | RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
751 &hVfsFile, (void **)&pThis);
752 if (RT_SUCCESS(rc))
753 {
754 pThis->Base.ObjInfo = ObjInfo;
755 pThis->offCurPos = 0;
756 pThis->pCurExt = NULL;
757 RTListInit(&pThis->ExtentHead);
758 if (ObjInfo.cbObject <= 0)
759 pThis->cbExtent = _4K;
760 else if (ObjInfo.cbObject < RTVFSMEM_MAX_EXTENT_SIZE)
761 pThis->cbExtent = _4K /* ObjInfo.cbObject */;
762 else
763 pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
764
765 /*
766 * Copy the stream.
767 */
768 RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile);
769 rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent);
770 RTVfsIoStrmRelease(hVfsIosDst);
771 if (RT_SUCCESS(rc))
772 {
773 pThis->pCurExt = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
774 pThis->offCurPos = 0;
775
776 if (!(fFlags & RTFILE_O_WRITE))
777 {
778 /** @todo clear RTFILE_O_WRITE from the resulting. */
779 }
780 *phVfsFile = hVfsFile;
781 return VINF_SUCCESS;
782 }
783 RTVfsFileRelease(hVfsFile);
784 }
785 }
786 return rc;
787}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette