vfsmemory.cpp revision 985524f3b29e0f50c596635c16fae80bc78dcc45
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/* $Id$ */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** @file
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * IPRT - Virtual File System, Memory Backed VFS.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/*
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * Copyright (C) 2010 Oracle Corporation
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * available from http://www.virtualbox.org. This file is free software;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * you can redistribute it and/or modify it under the terms of the GNU
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * General Public License (GPL) as published by the Free Software
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * The contents of this file may alternatively be used under the terms
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * of the Common Development and Distribution License Version 1.0
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox OSE distribution, in which case the provisions of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * CDDL are applicable instead of those of the GPL.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * You may elect to license modified versions of this file under the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * terms and conditions of either the GPL or the CDDL or both.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/*******************************************************************************
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync* Header Files *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync*******************************************************************************/
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include "internal/iprt.h"
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/vfs.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#include <iprt/asm.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/assert.h>
230bd8589bba39933ac5ec21482d6186d675e604vboxsync#include <iprt/err.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/file.h>
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#include <iprt/list.h>
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#include <iprt/poll.h>
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync#include <iprt/string.h>
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync#include <iprt/vfslowlevel.h>
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
b72d3233df38e3122eda39b39a27b35c27209615vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync* Header Files *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#include "internal/iprt.h"
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#include <iprt/vfs.h>
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync#include <iprt/err.h>
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#include <iprt/mem.h>
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync* Defined Constants And Macros *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** The max extent size. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync#define RTVFSMEM_MAX_EXTENT_SIZE _2M
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync* Structures and Typedefs *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/**
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * Memory base object info.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsynctypedef struct RTVFSMEMBASE
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The basic object info. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync RTFSOBJINFO ObjInfo;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync} RTVFSMEMBASE;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/**
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Memory file extent.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This stores part of the file content.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsynctypedef struct RTVFSMEMEXTENT
230bd8589bba39933ac5ec21482d6186d675e604vboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Extent list entry. */
230bd8589bba39933ac5ec21482d6186d675e604vboxsync RTLISTNODE Entry;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** The offset of this extent within the file. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync uint64_t off;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync /** The size of the this extent. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync uint32_t cb;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync /** The data. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync uint8_t abData[1];
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync} RTVFSMEMEXTENT;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Pointer to a memory file extent. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsynctypedef RTVFSMEMEXTENT *PRTVFSMEMEXTENT;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/**
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Memory file.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsynctypedef struct RTVFSMEMFILE
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** The base info. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync RTVFSMEMBASE Base;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The current file position. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync uint64_t offCurPos;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Pointer to the current file extent. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync PRTVFSMEMEXTENT pCurExt;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Linked list of file extents - RTVFSMEMEXTENT. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync RTLISTNODE ExtentHead;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** The current extent size.
0368e9c310393e82ef37c480b6acbd0f107cf0edvboxsync * This is slowly grown to RTVFSMEM_MAX_EXTENT_SIZE as the file grows. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync uint32_t cbExtent;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync} RTVFSMEMFILE;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Pointer to a memory file. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsynctypedef RTVFSMEMFILE *PRTVFSMEMFILE;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/**
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * @interface_method_impl{RTVFSOBJOPS,pfnClose}
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_Close(void *pvThis)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /*
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * Free the extent list.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync PRTVFSMEMEXTENT pCur, pNext;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync RTListForEachSafe(&pThis->ExtentHead, pCur, pNext, RTVFSMEMEXTENT, Entry)
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync pCur->off = RTFOFF_MAX;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync pCur->cb = UINT32_MAX;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync RTListNodeRemove(&pCur->Entry);
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync RTMemFree(pCur);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync pThis->pCurExt = NULL;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return VINF_SUCCESS;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync}
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/**
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync switch (enmAddAttr)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case RTFSOBJATTRADD_NOTHING:
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync case RTFSOBJATTRADD_UNIX:
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync *pObjInfo = pThis->Base.ObjInfo;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync return VINF_SUCCESS;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync default:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return VERR_NOT_SUPPORTED;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync}
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync/**
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * The slow paths of rtVfsMemFile_LocateExtent.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * @copydoc rtVfsMemFile_LocateExtent
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic PRTVFSMEMEXTENT rtVfsMemFile_LocateExtentSlow(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /*
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * Search from the start or the previously used extent. The heuristics
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * are very very simple, but whatever.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync PRTVFSMEMEXTENT pExtent = pThis->pCurExt;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync if (!pExtent || pExtent->off < off)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync pExtent = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync if (!pExtent)
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync *pfHit = false;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync return NULL;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync while (off - pExtent->off >= pExtent->cb)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync Assert(pExtent->off <= off);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync if ( !pNext
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync || pNext->off > off)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync *pfHit = false;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync return pExtent;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync }
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pExtent = pNext;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync }
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync *pfHit = true;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync pThis->pCurExt = pExtent;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync return pExtent;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync}
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/**
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * Locates the extent covering the specified offset, or then one before it.
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync *
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * @returns The closest extent. NULL if off is 0 and there are no extent
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * covering byte 0 yet.
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * @param pThis The memory file.
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * @param off The offset (0-positive).
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * @param pfHit Where to indicate whether the extent is a
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * direct hit (@c true) or just a closest match
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * (@c false).
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncDECLINLINE(PRTVFSMEMEXTENT) rtVfsMemFile_LocateExtent(PRTVFSMEMFILE pThis, uint64_t off, bool *pfHit)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /*
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * The most likely case is that we're hitting the extent we used in the
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * previous access or the one immediately following it.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync PRTVFSMEMEXTENT pExtent = pThis->pCurExt;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync if (!pExtent)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync if (off - pExtent->off >= pExtent->cb)
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync {
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync pExtent = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync if ( !pExtent
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync || off - pExtent->off >= pExtent->cb)
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync return rtVfsMemFile_LocateExtentSlow(pThis, off, pfHit);
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync pThis->pCurExt = pExtent;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync }
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync *pfHit = true;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync return pExtent;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync}
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
b72d3233df38e3122eda39b39a27b35c27209615vboxsync/**
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
5981e6935987b08737b730b63a41acc1dd696377vboxsync */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync{
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync Assert(pSgBuf->cSegs == 1);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync Assert(off < 0);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync NOREF(fBlocking);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync /*
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync * Find the current position and check if it's within the file.
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync if (offUnsigned >= (uint64_t)pThis->Base.ObjInfo.cbObject)
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync {
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync if (pcbRead)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync {
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync *pcbRead = 0;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync pThis->offCurPos = offUnsigned;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync return VINF_EOF;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync }
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync return VERR_EOF;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync }
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync size_t cbLeftToRead;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync if (offUnsigned + pSgBuf->paSegs[0].cbSeg > (uint64_t)pThis->Base.ObjInfo.cbObject)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync {
b35e3948f1287430503b6b432945b8cf4bfd3a23vboxsync if (!pcbRead)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync return VERR_EOF;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync *pcbRead = cbLeftToRead = (size_t)((uint64_t)pThis->Base.ObjInfo.cbObject - offUnsigned);
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync }
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync else
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync {
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync cbLeftToRead = pSgBuf->paSegs[0].cbSeg;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync if (pcbRead)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync *pcbRead = cbLeftToRead;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync }
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync /*
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync * Ok, we've got a valid stretch within the file. Do the reading.
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync if (cbLeftToRead > 0)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync {
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync uint8_t *pbDst = (uint8_t *)pSgBuf->paSegs[0].pvSeg;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync bool fHit;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync for (;;)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync {
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync PRTVFSMEMEXTENT pNext;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync size_t cbThisRead;
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync Assert(!pExtent || pExtent->off <= offUnsigned);
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync * Do we hit an extent covering the the current file surface?
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (fHit)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync size_t const offExtent = (size_t)(offUnsigned - pExtent->off);
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync cbThisRead = pExtent->cb - offExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (cbThisRead >= cbLeftToRead)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbThisRead = cbLeftToRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync memcpy(pbDst, &pExtent->abData[offUnsigned - pExtent->off], cbThisRead);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync offUnsigned += cbThisRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbLeftToRead -= cbThisRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!cbLeftToRead)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync break;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pbDst += cbThisRead;
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if ( pNext
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync && pNext->off == pExtent->off + pExtent->cb)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pExtent = pNext;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync continue;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync fHit = false;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * No extent of this portion (sparse file).
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else if (pExtent)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pNext = NULL;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Assert(!pNext || pNext->off > pExtent->off);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if ( !pNext
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync || offUnsigned + cbLeftToRead <= pNext->off)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbThisRead = cbLeftToRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync cbThisRead = (size_t)(pNext->off - offUnsigned);
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync RT_BZERO(pbDst, cbThisRead);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync offUnsigned += cbThisRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbLeftToRead -= cbThisRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!cbLeftToRead)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync break;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pbDst += cbThisRead;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* Go on and read content from the next extent. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync fHit = true;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pExtent = pNext;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pThis->offCurPos = offUnsigned;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return VINF_SUCCESS;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync}
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/**
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Allocates a new extent covering the ground at @a offUnsigned.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync *
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @returns Pointer to the new extent on success, NULL if we're out of memory.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pThis The memory file.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param offUnsigned The location to allocate the extent at.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param cbToWrite The number of bytes we're interested in writing
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * starting at @a offUnsigned.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pPrev The extention before @a offUnsigned. NULL if
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * none.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic PRTVFSMEMEXTENT rtVfsMemFile_AllocExtent(PRTVFSMEMFILE pThis, uint64_t offUnsigned, size_t cbToWrite,
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMEXTENT pPrev)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync{
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Adjust the extent size if we haven't reached the max size yet.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pThis->cbExtent != RTVFSMEM_MAX_EXTENT_SIZE)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (cbToWrite >= RTVFSMEM_MAX_EXTENT_SIZE)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else if (!RTListIsEmpty(&pThis->ExtentHead))
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync uint32_t cbNextExtent = pThis->cbExtent;
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync if (RT_IS_POWER_OF_TWO(cbNextExtent))
b72d3233df38e3122eda39b39a27b35c27209615vboxsync cbNextExtent *= 2;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* Make it a power of two (seeRTVfsMemorizeIoStreamAsFile). */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbNextExtent = _4K;
b72d3233df38e3122eda39b39a27b35c27209615vboxsync while (cbNextExtent < pThis->cbExtent)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbNextExtent *= 2;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (((pThis->Base.ObjInfo.cbAllocated + cbNextExtent) & (cbNextExtent - 1)) == 0)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pThis->cbExtent = cbNextExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Figure out the size and position of the extent we're adding.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint64_t offExtent = offUnsigned & ~(uint64_t)(pThis->cbExtent - 1);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint32_t cbExtent = pThis->cbExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint64_t const offPrev = pPrev ? pPrev->off + pPrev->cb : 0;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (offExtent < offPrev)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync offExtent = offPrev;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMEXTENT pNext = pPrev
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync ? RTListGetNext(&pThis->ExtentHead, pPrev, RTVFSMEMEXTENT, Entry)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync : RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pNext)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint64_t cbMaxExtent = pNext->off - offExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (cbMaxExtent < cbExtent)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbExtent = (uint32_t)cbMaxExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Allocate, initialize and insert the new extent.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMEXTENT pNew = (PRTVFSMEMEXTENT)RTMemAllocZ(RT_OFFSETOF(RTVFSMEMEXTENT, abData[cbExtent]));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pNew)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pNew->off = offExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pNew->cb = cbExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pPrev)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync RTListNodeInsertAfter(&pPrev->Entry, &pNew->Entry);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync RTListPrepend(&pThis->ExtentHead, &pNew->Entry);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pThis->Base.ObjInfo.cbAllocated += cbExtent;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /** @todo retry with minimum size. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return pNew;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync}
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/**
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync{
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Assert(pSgBuf->cSegs == 1);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Assert(off < 0);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync NOREF(fBlocking);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Validate the write and set up the write loop.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync size_t cbLeftToWrite = pSgBuf->paSegs[0].cbSeg;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!cbLeftToWrite)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return VINF_SUCCESS; /* pcbWritten is already 0. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint64_t offUnsigned = off < 0 ? pThis->offCurPos : (uint64_t)off;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (offUnsigned + cbLeftToWrite >= (uint64_t)RTFOFF_MAX)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return VERR_OUT_OF_RANGE;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync int rc = VINF_SUCCESS;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync bool fHit;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMEXTENT pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync for (;;)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * If we didn't hit an extent, allocate one (unless it's all zeros).
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!fHit)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Assert(!pExtent || (pExtent->off < offUnsigned && pExtent->off + pExtent->cb <= offUnsigned));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* Skip leading zeros if there is a whole bunch of them. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint8_t const *pbSrcNZ = (uint8_t const *)ASMMemIsAll8(pbSrc, cbLeftToWrite, 0);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!pbSrcNZ)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync offUnsigned += cbLeftToWrite;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbLeftToWrite = 0;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync break;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync size_t const cbZeros = pbSrcNZ - pbSrc;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (cbZeros >= RT_MIN(pThis->cbExtent, _64K))
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync offUnsigned += cbZeros;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbLeftToWrite -= cbZeros;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pbSrc = pbSrcNZ;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pExtent = rtVfsMemFile_LocateExtent(pThis, offUnsigned, &fHit);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync break;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync fHit = true;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pExtent = rtVfsMemFile_AllocExtent(pThis, offUnsigned, cbLeftToWrite, pExtent);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!pExtent)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync rc = VERR_NO_MEMORY;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync break;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync }
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Copy the source data into the current extent.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint32_t const offDst = (uint32_t)(offUnsigned - pExtent->off);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint32_t cbThisWrite = pExtent->cb - offDst;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (cbThisWrite > cbLeftToWrite)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbThisWrite = (uint32_t)cbLeftToWrite;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync memcpy(&pExtent->abData[offDst], pbSrc, cbThisWrite);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync offUnsigned += cbLeftToWrite;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync cbLeftToWrite -= cbThisWrite;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (!cbLeftToWrite)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync break;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pbSrc += cbThisWrite;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Assert(offUnsigned == pExtent->off + pExtent->cb);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Advance to the next extent.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMEXTENT pNext = RTListGetNext(&pThis->ExtentHead, pExtent, RTVFSMEMEXTENT, Entry);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Assert(!pNext || pNext->off >= offUnsigned);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pNext && pNext->off == offUnsigned)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pExtent = pNext;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync fHit = false;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
b72d3233df38e3122eda39b39a27b35c27209615vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /*
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Update the state, set return value and return.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Note! There must be no alternative exit path from the loop above.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pThis->offCurPos = offUnsigned;
b72d3233df38e3122eda39b39a27b35c27209615vboxsync if ((uint64_t)pThis->Base.ObjInfo.cbObject < offUnsigned)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pThis->Base.ObjInfo.cbObject = offUnsigned;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pcbWritten)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync *pcbWritten = pSgBuf->paSegs[0].cbSeg - cbLeftToWrite;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return rc;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync}
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/**
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
aace59ca7fd1b66174593c5a564878cfac89e11evboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_Flush(void *pvThis)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync{
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync NOREF(pvThis);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return VINF_SUCCESS;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync}
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/**
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync uint32_t *pfRetEvents)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync{
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync int rc;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (fEvents != RTPOLL_EVT_ERROR)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync rc = VINF_SUCCESS;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync }
b72d3233df38e3122eda39b39a27b35c27209615vboxsync else
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync rc = RTVfsUtilDummyPollOne(fEvents, cMillies, fIntr, pfRetEvents);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return rc;
b72d3233df38e3122eda39b39a27b35c27209615vboxsync}
b72d3233df38e3122eda39b39a27b35c27209615vboxsync
b72d3233df38e3122eda39b39a27b35c27209615vboxsync
b72d3233df38e3122eda39b39a27b35c27209615vboxsync/**
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic DECLCALLBACK(int) rtVfsMemFile_Tell(void *pvThis, PRTFOFF poffActual)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *poffActual = pThis->offCurPos;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return VINF_SUCCESS;
}
/**
* @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
*/
static DECLCALLBACK(int) rtVfsMemFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
{
PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
pThis->Base.ObjInfo.Attr.fMode = (pThis->Base.ObjInfo.Attr.fMode & ~fMask) | fMode;
return VINF_SUCCESS;
}
/**
* @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
*/
static DECLCALLBACK(int) rtVfsMemFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
{
PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
if (pAccessTime)
pThis->Base.ObjInfo.AccessTime = *pAccessTime;
if (pModificationTime)
pThis->Base.ObjInfo.ModificationTime = *pModificationTime;
if (pChangeTime)
pThis->Base.ObjInfo.ChangeTime = *pChangeTime;
if (pBirthTime)
pThis->Base.ObjInfo.BirthTime = *pBirthTime;
return VINF_SUCCESS;
}
/**
* @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
*/
static DECLCALLBACK(int) rtVfsMemFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
{
PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
if (uid != NIL_RTUID)
pThis->Base.ObjInfo.Attr.u.Unix.uid = uid;
if (gid != NIL_RTUID)
pThis->Base.ObjInfo.Attr.u.Unix.gid = gid;
return VINF_SUCCESS;
}
/**
* @interface_method_impl{RTVFSFILEOPS,pfnSeek}
*/
static DECLCALLBACK(int) rtVfsMemFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
{
PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
/*
* Seek relative to which position.
*/
uint64_t offWrt;
switch (uMethod)
{
case RTFILE_SEEK_BEGIN:
offWrt = 0;
break;
case RTFILE_SEEK_CURRENT:
offWrt = pThis->offCurPos;
break;
case RTFILE_SEEK_END:
offWrt = pThis->Base.ObjInfo.cbObject;
break;
default:
return VERR_INTERNAL_ERROR_5;
}
/*
* Calc new position, take care to stay without bounds.
*/
uint64_t offNew;
if (offSeek == 0)
offNew = offWrt;
else if (offSeek > 0)
{
offNew = offWrt + offSeek;
if ( offNew < offWrt
|| offNew > RTFOFF_MAX)
offNew = RTFOFF_MAX;
}
else if ((uint64_t)-offSeek < offWrt)
offNew = offWrt + offSeek;
else
offNew = 0;
/*
* Update the state and set return value.
*/
if ( pThis->pCurExt
&& pThis->pCurExt->off - offNew >= pThis->pCurExt->cb)
pThis->pCurExt = NULL;
pThis->offCurPos = offNew;
*poffActual = offNew;
return VINF_SUCCESS;
}
/**
* @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
*/
static DECLCALLBACK(int) rtVfsMemFile_QuerySize(void *pvThis, uint64_t *pcbFile)
{
PRTVFSMEMFILE pThis = (PRTVFSMEMFILE)pvThis;
*pcbFile = pThis->Base.ObjInfo.cbObject;
return VINF_SUCCESS;
}
/**
* Standard file operations.
*/
DECLHIDDEN(const RTVFSFILEOPS) g_rtVfsStdFileOps =
{
{ /* Stream */
{ /* Obj */
RTVFSOBJOPS_VERSION,
RTVFSOBJTYPE_FILE,
"MemFile",
rtVfsMemFile_Close,
rtVfsMemFile_QueryInfo,
RTVFSOBJOPS_VERSION
},
RTVFSIOSTREAMOPS_VERSION,
RTVFSIOSTREAMOPS_FEAT_NO_SG,
rtVfsMemFile_Read,
rtVfsMemFile_Write,
rtVfsMemFile_Flush,
rtVfsMemFile_PollOne,
rtVfsMemFile_Tell,
NULL /*Skip*/,
NULL /*ZeroFill*/,
RTVFSIOSTREAMOPS_VERSION,
},
RTVFSFILEOPS_VERSION,
/*RTVFSIOFILEOPS_FEAT_NO_AT_OFFSET*/ 0,
{ /* ObjSet */
RTVFSOBJSETOPS_VERSION,
RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
rtVfsMemFile_SetMode,
rtVfsMemFile_SetTimes,
rtVfsMemFile_SetOwner,
RTVFSOBJSETOPS_VERSION
},
rtVfsMemFile_Seek,
rtVfsMemFile_QuerySize,
RTVFSFILEOPS_VERSION
};
RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile)
{
/*
* Create a memory file instance and try set the extension size to match
* the length of the I/O stream.
*/
RTFSOBJINFO ObjInfo;
int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
if (RT_SUCCESS(rc))
{
RTVFSFILE hVfsFile;
PRTVFSMEMFILE pThis;
rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(*pThis), fFlags | RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
&hVfsFile, (void **)&pThis);
if (RT_SUCCESS(rc))
{
pThis->Base.ObjInfo = ObjInfo;
pThis->offCurPos = 0;
pThis->pCurExt = NULL;
RTListInit(&pThis->ExtentHead);
if (ObjInfo.cbObject <= 0)
pThis->cbExtent = _4K;
else if (ObjInfo.cbObject < RTVFSMEM_MAX_EXTENT_SIZE)
pThis->cbExtent = _4K /* ObjInfo.cbObject */;
else
pThis->cbExtent = RTVFSMEM_MAX_EXTENT_SIZE;
/*
* Copy the stream.
*/
RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFile);
rc = RTVfsUtilPumpIoStreams(hVfsIos, hVfsIosDst, pThis->cbExtent);
RTVfsIoStrmRelease(hVfsIosDst);
if (RT_SUCCESS(rc))
{
pThis->pCurExt = RTListGetFirst(&pThis->ExtentHead, RTVFSMEMEXTENT, Entry);
pThis->offCurPos = 0;
if (!(fFlags & RTFILE_O_WRITE))
{
/** @todo clear RTFILE_O_WRITE from the resulting. */
}
*phVfsFile = hVfsFile;
return VINF_SUCCESS;
}
RTVfsFileRelease(hVfsFile);
}
}
return rc;
}