vfsbase.cpp revision 511425b73142e61f1e2c426800a57313a737573c
/* $Id$ */
/** @file
* IPRT - Virtual File System, Base.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/vfslowlevel.h>
#include <iprt/semaphore.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#define RTVFSOBJ_MAGIC_DEAD (~RTVFSOBJ_MAGIC)
#define RTVFS_MAGIC_DEAD (~RTVFS_MAGIC)
#define RTVFSFSSTREAM_MAGIC_DEAD (~RTVFSFSSTREAM_MAGIC)
#define RTVFSDIR_MAGIC_DEAD (~RTVFSDIR_MAGIC)
#define RTVFSFILE_MAGIC_DEAD (~RTVFSFILE_MAGIC)
#define RTVFSIOSTREAM_MAGIC_DEAD (~RTVFSIOSTREAM_MAGIC)
#define RTVFSSYMLINK_MAGIC_DEAD (~RTVFSSYMLINK_MAGIC)
/** The instance data alignment. */
#define RTVFS_INST_ALIGNMENT 16U
/** The max number of symbolic links to resolve in a path. */
#define RTVFS_MAX_LINKS 20U
/** Asserts that the VFS base object vtable is valid. */
do \
{ \
} while (0)
/** Asserts that the VFS set object vtable is valid. */
do \
{ \
} while (0)
/** Asserts that the VFS I/O stream vtable is valid. */
do { \
} while (0)
/** Asserts that the VFS symlink vtable is valid. */
do { \
} while (0)
/** Validates a VFS handle and returns @a rcRet if it's invalid. */
do { \
{ \
} \
} while (0)
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* The VFS internal lock data.
*/
typedef struct RTVFSLOCKINTERNAL
{
/** The number of references to the this lock. */
/** The lock type. */
/** Type specific data. */
union
{
/** Fast mutex semaphore handle. */
/** Regular mutex semaphore handle. */
} u;
/**
* The VFS base object handle data.
*
* All other VFS handles are derived from this one. The final handle type is
* indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
*/
typedef struct RTVFSOBJINTERNAL
{
/** The VFS magic (RTVFSOBJ_MAGIC). */
/** The number of references to this VFS object. */
/** Pointer to the instance data. */
void *pvThis;
/** The vtable. */
/** The lock protecting all access to the VFS.
* Only valid RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTVFSLOCK. */
/** Reference back to the VFS containing this object. */
/**
* The VFS filesystem stream handle data.
*
* @extends RTVFSOBJINTERNAL
*/
typedef struct RTVFSFSSTREAMINTERNAL
{
/** The VFS magic (RTVFSFSTREAM_MAGIC). */
/** File open flags, at a minimum the access mask. */
/** The vtable. */
/** The base object handle data. */
/**
* The VFS handle data.
*
* @extends RTVFSOBJINTERNAL
*/
typedef struct RTVFSINTERNAL
{
/** The VFS magic (RTVFS_MAGIC). */
/** Creation flags (RTVFS_C_XXX). */
/** The vtable. */
/** The base object handle data. */
/**
* The VFS directory handle data.
*
* @extends RTVFSOBJINTERNAL
*/
typedef struct RTVFSDIRINTERNAL
{
/** The VFS magic (RTVFSDIR_MAGIC). */
/** Reserved for flags or something. */
/** The vtable. */
/** The base object handle data. */
/**
* The VFS symbolic link handle data.
*
* @extends RTVFSOBJINTERNAL
*/
typedef struct RTVFSSYMLINKINTERNAL
{
/** The VFS magic (RTVFSSYMLINK_MAGIC). */
/** Reserved for flags or something. */
/** The vtable. */
/** The base object handle data. */
/**
* The VFS I/O stream handle data.
*
* This is often part of a type specific handle, like a file or pipe.
*
* @extends RTVFSOBJINTERNAL
*/
typedef struct RTVFSIOSTREAMINTERNAL
{
/** The VFS magic (RTVFSIOSTREAM_MAGIC). */
/** File open flags, at a minimum the access mask. */
/** The vtable. */
/** The base object handle data. */
/**
* The VFS file handle data.
*
* @extends RTVFSIOSTREAMINTERNAL
*/
typedef struct RTVFSFILEINTERNAL
{
/** The VFS magic (RTVFSFILE_MAGIC). */
/** Reserved for flags or something. */
/** The vtable. */
/** The stream handle data. */
#if 0 /* later */
/**
* The VFS pipe handle data.
*
* @extends RTVFSIOSTREAMINTERNAL
*/
typedef struct RTVFSPIPEINTERNAL
{
/** The VFS magic (RTVFSPIPE_MAGIC). */
/** Reserved for flags or something. */
/** The vtable. */
/** The stream handle data. */
/**
* The VFS socket handle data.
*
* @extends RTVFSIOSTREAMINTERNAL
*/
typedef struct RTVFSSOCKETINTERNAL
{
/** The VFS magic (RTVFSSOCKET_MAGIC). */
/** Reserved for flags or something. */
/** The vtable. */
/** The stream handle data. */
#endif /* later */
/*
*
* V F S L o c k A b s t r a c t i o n
* V F S L o c k A b s t r a c t i o n
* V F S L o c k A b s t r a c t i o n
*
*
*/
{
AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
return cRefs;
}
/**
* Destroys a VFS lock handle.
*
* @param pThis The lock to destroy.
*/
{
{
case RTVFSLOCKTYPE_RW:
break;
case RTVFSLOCKTYPE_FASTMUTEX:
break;
case RTVFSLOCKTYPE_MUTEX:
break;
default:
}
}
{
AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
if (cRefs == 0)
return cRefs;
}
/**
*
* @returns IPRT status code
* @param phLock Where to return the lock handle.
*/
{
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
/**
* Creates a fast mutex lock.
*
* @returns IPRT status code
* @param phLock Where to return the lock handle.
*/
{
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
/**
* Creates a mutex lock.
*
* @returns IPRT status code
* @param phLock Where to return the lock handle.
*/
{
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
/**
* Acquires the lock for reading.
*
* @param hLock Non-nil lock handle.
* @internal
*/
{
int rc;
{
case RTVFSLOCKTYPE_RW:
break;
case RTVFSLOCKTYPE_FASTMUTEX:
break;
case RTVFSLOCKTYPE_MUTEX:
break;
default:
AssertFailed();
}
}
/**
* Release a lock held for reading.
*
* @param hLock Non-nil lock handle.
* @internal
*/
{
int rc;
{
case RTVFSLOCKTYPE_RW:
break;
case RTVFSLOCKTYPE_FASTMUTEX:
break;
case RTVFSLOCKTYPE_MUTEX:
break;
default:
AssertFailed();
}
}
/**
* Acquires the lock for writing.
*
* @param hLock Non-nil lock handle.
* @internal
*/
{
int rc;
{
case RTVFSLOCKTYPE_RW:
break;
case RTVFSLOCKTYPE_FASTMUTEX:
break;
case RTVFSLOCKTYPE_MUTEX:
break;
default:
AssertFailed();
}
}
/**
* Release a lock held for writing.
*
* @param hLock Non-nil lock handle.
* @internal
*/
{
int rc;
{
case RTVFSLOCKTYPE_RW:
break;
case RTVFSLOCKTYPE_FASTMUTEX:
break;
case RTVFSLOCKTYPE_MUTEX:
break;
default:
AssertFailed();
}
}
/*
*
* B A S E O B J E C T
* B A S E O B J E C T
* B A S E O B J E C T
*
*/
/**
* Internal object retainer that asserts sanity in strict builds.
*
* @param pThis The base object handle data.
*/
{
("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
}
/**
* Initializes the base object part of a new object.
*
* @returns IPRT status code.
* @param pThis Pointer to the base object part.
* @param pObjOps The base object vtable.
* @param hVfs The VFS handle to associate with.
* @param hLock The lock handle, pseudo handle or nil.
* @param pvThis Pointer to the private data.
*/
static int rtVfsObjInitNewObject(RTVFSOBJINTERNAL *pThis, PCRTVFSOBJOPS pObjOps, RTVFS hVfs, RTVFSLOCK hLock, void *pvThis)
{
/*
* Deal with the lock first as that's the most complicated matter.
*/
if (hLock != NIL_RTVFSLOCK)
{
int rc;
if (hLock == RTVFSLOCK_CREATE_RW)
{
}
else if (hLock == RTVFSLOCK_CREATE_FASTMUTEX)
{
}
else if (hLock == RTVFSLOCK_CREATE_MUTEX)
{
}
else
{
/*
* The caller specified a lock, we consume the this reference.
*/
AssertReturn(hLock->enmType > RTVFSLOCKTYPE_INVALID && hLock->enmType < RTVFSLOCKTYPE_END, VERR_INVALID_HANDLE);
}
}
{
/*
* Retain a reference to the VFS lock, if there is one.
*/
if (hLock != NIL_RTVFSLOCK)
{
return VERR_INVALID_HANDLE;
}
}
/*
* Do the actual initializing.
*/
return VINF_SUCCESS;
}
{
/*
* Validate the input, be extra strict in strict builds.
*/
Assert(cbInstance > 0);
/*
* Allocate the handle + instance data.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
/**
* Internal object retainer that asserts sanity in strict builds.
*
* @returns The new reference count.
* @param pThis The base object handle data.
*/
{
("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
return cRefs;
}
{
return rtVfsObjRetain(pThis);
}
/**
* Does the actual object destruction for rtVfsObjRelease().
*
* @param pThis The object to destroy.
*/
{
/*
* Invalidate the object.
*/
switch (enmType)
{
case RTVFSOBJTYPE_BASE:
break;
case RTVFSOBJTYPE_VFS:
break;
case RTVFSOBJTYPE_FS_STREAM:
ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
break;
case RTVFSOBJTYPE_IO_STREAM:
ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
break;
case RTVFSOBJTYPE_DIR:
break;
case RTVFSOBJTYPE_FILE:
ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
break;
case RTVFSOBJTYPE_SYMLINK:
ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
break;
case RTVFSOBJTYPE_INVALID:
case RTVFSOBJTYPE_END:
case RTVFSOBJTYPE_32BIT_HACK:
break;
/* no default as we want gcc warnings. */
}
/*
* Close the object and free the handle.
*/
}
/**
* Internal object releaser that asserts sanity in strict builds.
*
* @returns The new reference count.
* @param pcRefs The reference counter.
*/
{
AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
if (cRefs == 0)
return cRefs;
}
{
return rtVfsObjRelease(pThis);
}
{
if (pThis != NIL_RTVFSOBJ)
{
{
}
}
return NIL_RTVFS;
}
{
if (pThis != NIL_RTVFSOBJ)
{
{
}
}
return NIL_RTVFSFSSTREAM;
}
{
if (pThis != NIL_RTVFSOBJ)
{
{
}
}
return NIL_RTVFSDIR;
}
{
if (pThis != NIL_RTVFSOBJ)
{
{
}
}
return NIL_RTVFSIOSTREAM;
}
{
if (pThis != NIL_RTVFSOBJ)
{
{
}
}
return NIL_RTVFSFILE;
}
{
if (pThis != NIL_RTVFSOBJ)
{
{
}
}
return NIL_RTVFSSYMLINK;
}
{
{
return pThis;
}
return NIL_RTVFSOBJ;
}
{
if (hVfsFss != NIL_RTVFSFSSTREAM)
{
return pThis;
}
return NIL_RTVFSOBJ;
}
{
if (hVfsDir != NIL_RTVFSDIR)
{
return pThis;
}
return NIL_RTVFSOBJ;
}
{
if (hVfsIos != NIL_RTVFSIOSTREAM)
{
return pThis;
}
return NIL_RTVFSOBJ;
}
{
if (hVfsFile != NIL_RTVFSFILE)
{
return pThis;
}
return NIL_RTVFSOBJ;
}
{
if (hVfsSym != NIL_RTVFSSYMLINK)
{
return pThis;
}
return NIL_RTVFSOBJ;
}
{
return rc;
}
/*
*
* U T I L U T I L U T I L
* U T I L U T I L U T I L
* U T I L U T I L U T I L
*
*/
/**
* Removes dots from the path.
*
* @returns The new @a pszDst value.
* @param pPath The path parsing buffer.
* @param pszDst The current szPath position. This will be
* updated and returned.
* @param fTheEnd Indicates whether we're at the end of the path
* or not.
* @param piRestartComp The component to restart parsing at.
*/
static char *rtVfsParsePathHandleDots(PRTVFSPARSEDPATH pPath, char *pszDst, bool fTheEnd, uint16_t *piRestartComp)
{
return pszDst;
{
pPath->cComponents--;
}
{
}
else
return pszDst;
/*
* Drop the trailing slash if we're at the end of the source path.
*/
pszDst--;
return pszDst;
}
RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
{
/* In case *piRestartComp was set higher than the number of components
before making the call to this function. */
/*
* Append a slash to the destination path if necessary.
*/
if (pPath->cComponents > 0)
{
*pszDst++ = '/';
return VERR_FILENAME_TOO_LONG;
}
/*
* Parse and append the relative path.
*/
while (pszSrc[0])
{
/* Skip unncessary slashes. */
while (pszSrc[0] == '/')
pszSrc++;
/* Copy until we encounter the next slash. */
while (pszSrc[0])
{
if (pszSrc[0] == '/')
{
pszSrc++;
if (pszSrc[0])
*pszDst++ = '/';
else
break;
}
return VERR_FILENAME_TOO_LONG;
}
}
/* Terminate the string and enter its length. */
pszDst[0] = '\0';
return VINF_SUCCESS;
}
{
if (*pszPath != '/')
{
/*
* Relative, recurse and parse pszCwd first.
*/
if (RT_FAILURE(rc))
return rc;
}
else
{
/*
* Make pszPath relative, i.e. set up pPath for the root and skip
* leading slashes in pszPath before appending it.
*/
pPath->cComponents = 0;
while (pszPath[0] == '/')
pszPath++;
if (!pszPath[0])
return VINF_SUCCESS;
}
}
{
/*
* Allocate the output buffer and hand the problem to rtVfsParsePath.
*/
int rc;
if (pPath)
{
if (RT_FAILURE(rc))
{
}
}
else
return rc;
}
{
if (pPath)
{
}
}
/**
* Handles a symbolic link, adding it to
*
* @returns IPRT status code.
* @param pPath The parsed path to update.
* @param piComponent The component iterator to update.
* @param hSymlink The symbolic link to process.
*/
static int rtVfsTraverseHandleSymlink(PRTVFSPARSEDPATH pPath, uint16_t *piComponent, RTVFSSYMLINK hSymlink)
{
/*
* Read the link.
*/
char szPath[RTPATH_MAX];
if (RT_SUCCESS(rc))
{
if (szPath[0] == '/')
{
/*
* Absolute symlink.
*/
if (RT_SUCCESS(rc))
{
*piComponent = 0;
return VINF_SUCCESS;
}
}
else
{
/*
* Relative symlink, must replace the current component with the
* link value. We do that by using the remainder of the symlink
* buffer as temporary storage.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
}
}
/**
* Internal worker for various open functions as well as RTVfsTraverseToParent.
*
* @returns IPRT status code.
* @param pThis The VFS.
* @param pPath The parsed path. This may be changed as symbolic
* links are processed during the path traversal.
* @param fFollowSymlink Whether to follow the final component if it is a
* symbolic link.
* @param ppVfsParentDir Where to return the parent directory handle
* (referenced).
*/
{
/*
* Assert sanity.
*/
*ppVfsParentDir = NULL;
/*
* Open the root directory.
*/
/** @todo Union mounts, traversal optimization methods, races, ++ */
if (RT_FAILURE(rc))
return rc;
/*
* The traversal loop.
*/
unsigned cLinks = 0;
uint16_t iComponent = 0;
for (;;)
{
/*
* Are we done yet?
*/
if (fFinal && !fFollowSymlink)
{
return VINF_SUCCESS;
}
/*
* Try open the next entry.
*/
*pszEntryEnd = '\0';
if (fFinal)
{
*pszEntryEnd = '\0';
if (rc == VERR_PATH_NOT_FOUND)
rc = VINF_SUCCESS;
if (RT_FAILURE(rc))
break;
if (hSymlink == NIL_RTVFSSYMLINK)
{
return VINF_SUCCESS;
}
}
else
{
*pszEntryEnd = '/';
if (RT_FAILURE(rc))
break;
if ( hDir == NIL_RTVFSDIR
&& hSymlink == NIL_RTVFSSYMLINK
{
break;
}
}
if (hDir != NIL_RTVFSDIR)
{
/*
* Directory - advance down the path.
*/
iComponent++;
}
else if (hSymlink != NIL_RTVFSSYMLINK)
{
/*
* Symbolic link - deal with it and retry the current component.
*/
cLinks++;
if (cLinks >= RTVFS_MAX_LINKS)
{
break;
}
if (RT_FAILURE(rc))
break;
if (iRestartComp != iComponent)
{
/* Must restart from the root (optimize this). */
if (RT_FAILURE(rc))
{
break;
}
iComponent = 0;
}
}
else
{
/*
* Mount point - deal with it and retry the current component.
*/
if (RT_FAILURE(rc))
{
break;
}
iComponent = 0;
/** @todo union mounts. */
}
}
if (pCurDir)
return rc;
}
RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
{
int rc;
if (fIntr)
else
{
do
while ( rc == VERR_INTERRUPTED
&& !fIntr
if (rc == VERR_INTERRUPTED)
rc = VERR_TIMEOUT;
}
*pfRetEvents = 0;
return rc;
}
RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
{
/*
* Allocate a temporary buffer.
*/
if (!cbBuf)
if (!pvBuf)
{
if (!pvBuf)
return VERR_NO_TMP_MEMORY;
}
/*
* Pump loop.
*/
int rc;
for (;;)
{
if (RT_FAILURE(rc))
break;
break;
if (RT_FAILURE(rc))
break;
}
return rc;
}
/*
*
* F I L E S Y S T E M S T R E A M
* F I L E S Y S T E M S T R E A M
* F I L E S Y S T E M S T R E A M
*
*/
RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
{
/*
* Validate the input, be extra strict in strict builds.
*/
Assert(cbInstance > 0);
/*
* Allocate the handle + instance data.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
{
}
{
}
RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
{
}
RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
{
if (ppszName)
if (penmType)
if (phVfsObj)
*phVfsObj = NIL_RTVFSOBJ;
}
/*
*
* D I R D I R D I R
* D I R D I R D I R
* D I R D I R D I R
*
*/
{
}
{
}
/*
*
* S Y M B O L I C L I N K
* S Y M B O L I C L I N K
* S Y M B O L I C L I N K
*
*/
RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
{
/*
* Validate the input, be extra strict in strict builds.
*/
Assert(cbInstance > 0);
/*
* Allocate the handle + instance data.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
{
}
{
}
RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
{
}
{
if (!rtFsModeIsValid(fMode))
return VERR_INVALID_PARAMETER;
return rc;
}
RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
{
int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
return rc;
}
{
return rc;
}
{
return rc;
}
/*
*
* I / O S T R E A M I / O S T R E A M I / O S T R E A M
* I / O S T R E A M I / O S T R E A M I / O S T R E A M
* I / O S T R E A M I / O S T R E A M I / O S T R E A M
*
*/
RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
{
/*
* Validate the input, be extra strict in strict builds.
*/
Assert(cbInstance > 0);
/*
* Allocate the handle + instance data.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
{
}
{
}
{
{
}
/* this is no crime, so don't assert. */
return NIL_RTVFSFILE;
}
RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
{
}
RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
{
if (pcbRead)
*pcbRead = 0;
return rc;
}
RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
{
if (pcbWritten)
*pcbWritten = 0;
return rc;
}
RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
{
if (pcbRead)
*pcbRead = 0;
int rc;
else
{
rc = VINF_SUCCESS;
{
rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
if (RT_FAILURE(rc))
break;
break;
}
if (pcbRead)
}
return rc;
}
RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
{
if (pcbWritten)
*pcbWritten = 0;
int rc;
else
{
rc = VINF_SUCCESS;
{
size_t cbWrittenSeg = 0;
rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
if (RT_FAILURE(rc))
break;
if (pcbWritten)
{
break;
}
}
if (pcbWritten)
*pcbWritten = cbWritten;
}
return rc;
}
{
return rc;
}
RTDECL(RTFOFF) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
{
return rc;
}
{
if (RT_FAILURE(rc))
return off;
}
{
int rc;
{
}
{
}
else
{
if (pvBuf)
{
rc = VINF_SUCCESS;
while (cb > 0)
{
if (RT_FAILURE(rc))
break;
}
}
else
}
return rc;
}
{
int rc;
{
}
else
{
if (pvBuf)
{
rc = VINF_SUCCESS;
while (cb > 0)
{
if (RT_FAILURE(rc))
break;
}
}
else
}
return rc;
}
{
/*
* There is where the zero read behavior comes in handy.
*/
char bDummy;
}
/*
*
* F I L E F I L E F I L E
* F I L E F I L E F I L E
* F I L E F I L E F I L E
*
*/
RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
{
/*
* Validate the input, be extra strict in strict builds.
*/
Assert(cbInstance > 0);
/*
* Allocate the handle + instance data.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
{
/*
* Validate input.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Parse the path, assume current directory is root since we've got no
* caller context here.
*/
if (RT_SUCCESS(rc))
{
{
/*
* Tranverse the path, resolving the parent node and any symlinks
* in the final element, and ask the directory to open the file.
*/
if (RT_SUCCESS(rc))
{
/** @todo there is a symlink creation race here. */
if (RT_SUCCESS(rc))
{
}
}
}
else
}
return rc;
}
{
}
{
}
{
}