예제 #1
0
/**
 * Helper function for vboxvfs_vnode_lookup(): create new vnode.
 */
static int
vboxvfs_vnode_lookup_instantinate_vnode(vnode_t parent_vnode, char *entry_name, vnode_t *result_vnode)
{
    /* We need to construct full path to vnode in order to get
     * vboxvfs_get_info_internal() to understand us! */

    char *pszCurDirPath;
    int   cbCurDirPath = MAXPATHLEN;

    mount_t mp = vnode_mount(parent_vnode); AssertReturn(mp,  EINVAL);
    vnode_t vnode;

    int rc;

    pszCurDirPath = (char *)RTMemAllocZ(cbCurDirPath);
    if (pszCurDirPath)
    {
        rc = vn_getpath(parent_vnode, pszCurDirPath, &cbCurDirPath);
        if (rc == 0 && cbCurDirPath < MAXPATHLEN)
        {
            SHFLFSOBJINFO Info;
            PSHFLSTRING   pSHFLPath;

            /* Add '/' between path parts and truncate name if it is too long */
            strncat(pszCurDirPath, "/", 1); strncat(pszCurDirPath, entry_name, MAXPATHLEN - cbCurDirPath - 1);

            rc = vboxvfs_guest_path_to_shflstring_path_internal(mp, pszCurDirPath, strlen(pszCurDirPath) + 1, &pSHFLPath);
            if (rc == 0)
            {
                rc = vboxvfs_get_info_internal(mp, pSHFLPath, (PSHFLFSOBJINFO)&Info);
                if (rc == 0)
                {
                    enum vtype type;

                    if      (RTFS_IS_DIRECTORY(Info.Attr.fMode)) type = VDIR;
                    else if (RTFS_IS_FILE     (Info.Attr.fMode)) type = VREG;
                    else
                    {
                        PDEBUG("Not supported VFS object (%s) type: mode 0x%X",
                               entry_name,
                               Info.Attr.fMode);

                        RTMemFree(pszCurDirPath);
                        vboxvfs_put_path_internal((void **)&pSHFLPath);
                        return ENOENT;
                    }
                    /* Create new vnode */
                    rc = vboxvfs_create_vnode_internal(mp, type, parent_vnode, FALSE, pSHFLPath, &vnode);
                    if (rc == 0)
                    {
                        PDEBUG("new vnode object '%s' has been created", entry_name);

                        *result_vnode = vnode;
                        RTMemFree(pszCurDirPath);

                        return 0;
                    }
                    else
                        PDEBUG("Unable to create vnode: %d", rc);
                }
                else
                    PDEBUG("Unable to get host object info: %d", rc);

                vboxvfs_put_path_internal((void **)&pSHFLPath);
            }
            else
                PDEBUG("Unable to convert guest<->host path");
        }
        else
            PDEBUG("Unable to construct vnode path: %d", rc);

        RTMemFree(pszCurDirPath);
    }
    else
    {
        PDEBUG("Unable to allocate memory for path buffer");
        rc = ENOMEM;
    }

    return rc;
}
예제 #2
0
/**
 * Get VBoxVFS root vnode.
 *
 * Handle three cases here:
 *  - vnode does not exist yet: create a new one
 *  - currently creating vnode: wait till the end, increment usage count and return existing one
 *  - vnode already created: increment usage count and return existing one
 *  - vnode was failed to create: give a chance to try to re-create it later
 *
 * @param mp        Mount data provided by VFS layer.
 * @param ppVnode   vnode to return.
 * @param pContext  kAuth context needed in order to authentificate mount operation.
 *
 * @return 0 on success or BSD error code otherwise.
 */
static int
vboxvfs_root(struct mount *mp, struct vnode **ppVnode, vfs_context_t pContext)
{
    NOREF(pContext);

    vboxvfs_mount_t *pMount;
    int rc = 0;
    uint32_t vid;

    PDEBUG("Getting root vnode...");

    AssertReturn(mp,      EINVAL);
    AssertReturn(ppVnode, EINVAL);

    pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp);
    AssertReturn(pMount, EINVAL);

    /* Check case when vnode does not exist yet */
    if (ASMAtomicCmpXchgU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INITIALIZING, VBOXVFS_OBJECT_UNINITIALIZED))
    {
        PDEBUG("Create new root vnode");

        /* Allocate empty SHFLSTRING to indicate path to root vnode within Shared Folder */
        char        szEmpty[1];
        SHFLSTRING *pSFVnodePath;

        pSFVnodePath = vboxvfs_construct_shflstring((char *)szEmpty, 0);
        if (pSFVnodePath)
        {
            int rc2;
            rc2 = vboxvfs_create_vnode_internal(mp, VDIR, NULL, TRUE, pSFVnodePath, &pMount->pRootVnode);
            if (rc2 != 0)
            {
                RTMemFree(pSFVnodePath);
                rc = ENOTSUP;
            }
        }
        else
            rc = ENOMEM;

        /* Notify other threads about result */
        if (rc == 0)
            ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INITIALIZED);
        else
            ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INVALID);
    }
    else
    {
        /* Check case if we are currently creating vnode. Wait while other thread to finish allocation. */
        uint8_t fRootVnodeState = VBOXVFS_OBJECT_UNINITIALIZED;
        while (fRootVnodeState != VBOXVFS_OBJECT_INITIALIZED
            && fRootVnodeState != VBOXVFS_OBJECT_INVALID)
        {
            /* @todo: Currently, we are burning CPU cycles while waiting. This is for a short
             * time but we should relax here! */
            fRootVnodeState = ASMAtomicReadU8(&pMount->fRootVnodeState);

        }

        /* Check if the other thread initialized root vnode and it is ready to be returned */
        if (fRootVnodeState == VBOXVFS_OBJECT_INITIALIZED)
        {
            /* Take care about iocount */
            vid = vnode_vid(pMount->pRootVnode);
            rc = vnode_getwithvid(pMount->pRootVnode, vid);
        }
        else
        {
            /* Other thread reported initialization failure.
             * Set vnode state VBOXVFS_OBJECT_UNINITIALIZED in order to try recreate root
             * vnode in other attempt */
            ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_UNINITIALIZED);
        }

    }

    /* Only return vnode if we got success */
    if (rc == 0)
    {
        PDEBUG("Root vnode can be returned");
        *ppVnode = pMount->pRootVnode;
    }
    else
        PDEBUG("Root vnode cannot be returned: 0x%X", rc);

    return rc;
}