diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Additions/darwin/VBoxSF/VBoxSF-VNodeOps.cpp | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/src/VBox/Additions/darwin/VBoxSF/VBoxSF-VNodeOps.cpp b/src/VBox/Additions/darwin/VBoxSF/VBoxSF-VNodeOps.cpp new file mode 100644 index 00000000..d90e6dbc --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxSF/VBoxSF-VNodeOps.cpp @@ -0,0 +1,843 @@ +/* $Id: VBoxSF-VNodeOps.cpp $ */ +/** @file + * VBoxSF - Darwin Shared Folders, VNode Operations. + */ + + +/* + * Copyright (C) 2013-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_SHARED_FOLDERS +#include "VBoxSFInternal.h" + +#include <iprt/mem.h> +#include <iprt/assert.h> +#include <VBox/log.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +struct default_error_args_hack +{ + struct default_error_vdesc_hack + { + int vdesc_offset; + const char *vdesc_name; + } const *a_desc; +}; + + + +/** + * Default implementation that returns ENOTSUP. + */ +static int vboxSfDwnVnDefaultError(struct default_error_args_hack *pArgs) +{ + Log(("vboxSfDwnVnDefaultError: %s\n", RT_VALID_PTR(pArgs) && RT_VALID_PTR(pArgs->a_desc) ? pArgs->a_desc->vdesc_name : "??")); + RT_NOREF(pArgs); + return ENOTSUP; +} + + +static int vboxFsDwnVnGetAttr(struct vnop_getattr_args *pArgs) +{ +#if 1 + RT_NOREF(pArgs); + return ENOTSUP; +#else + + vboxvfs_mount_t *pMount; + struct vnode_attr *vnode_args; + vboxvfs_vnode_t *pVnodeData; + + struct timespec timespec; + + SHFLFSOBJINFO Info; + mount_t mp; + vnode_t vnode; + int rc; + + PDEBUG("Getting vnode attribute..."); + + AssertReturn(pArgs, EINVAL); + + vnode = pArgs->a_vp; AssertReturn(vnode, EINVAL); + vnode_args = pArgs->a_vap; AssertReturn(vnode_args, EINVAL); + mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); + pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); + pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); + + lck_rw_lock_shared(pVnodeData->pLock); + + rc = vboxvfs_get_info_internal(mp, pVnodeData->pPath, &Info); + if (rc == 0) + { + /* Set timestamps */ + RTTimeSpecGetTimespec(&Info.BirthTime, ×pec); VATTR_RETURN(vnode_args, va_create_time, timespec); + RTTimeSpecGetTimespec(&Info.AccessTime, ×pec); VATTR_RETURN(vnode_args, va_access_time, timespec); + RTTimeSpecGetTimespec(&Info.ModificationTime, ×pec); VATTR_RETURN(vnode_args, va_modify_time, timespec); + RTTimeSpecGetTimespec(&Info.ChangeTime, ×pec); VATTR_RETURN(vnode_args, va_change_time, timespec); + VATTR_CLEAR_ACTIVE(vnode_args, va_backup_time); + + /* Set owner info. */ + VATTR_RETURN(vnode_args, va_uid, pMount->owner); + VATTR_CLEAR_ACTIVE(vnode_args, va_gid); + + /* Access mode and flags */ + VATTR_RETURN(vnode_args, va_mode, vboxvfs_h2g_mode_inernal(Info.Attr.fMode)); + VATTR_RETURN(vnode_args, va_flags, Info.Attr.u.Unix.fFlags); + + /* The current generation number (0 if this information is not available) */ + VATTR_RETURN(vnode_args, va_gen, Info.Attr.u.Unix.GenerationId); + + VATTR_RETURN(vnode_args, va_rdev, 0); + VATTR_RETURN(vnode_args, va_nlink, 2); + + VATTR_RETURN(vnode_args, va_data_size, sizeof(struct dirent)); /* Size of data returned per each readdir() request */ + + /* Hope, when it overflows nothing catastrophical will heppen! If we will not assign + * a uniq va_fileid to each vnode, `ls`, 'find' (and simmilar tools that uses fts_read() calls) will think that + * each sub-directory is self-cycled. */ + VATTR_RETURN(vnode_args, va_fileid, (pMount->cFileIdCounter++)); + + /* Not supported */ + VATTR_CLEAR_ACTIVE(vnode_args, va_linkid); + VATTR_CLEAR_ACTIVE(vnode_args, va_parentid); + VATTR_CLEAR_ACTIVE(vnode_args, va_fsid); + VATTR_CLEAR_ACTIVE(vnode_args, va_filerev); + + /* Not present on 10.6 */ + //VATTR_CLEAR_ACTIVE(vnode_args, va_addedtime); + + /** @todo take care about va_encoding (file name encoding) */ + VATTR_CLEAR_ACTIVE(vnode_args, va_encoding); + /** @todo take care about: va_acl */ + VATTR_CLEAR_ACTIVE(vnode_args, va_acl); + + VATTR_CLEAR_ACTIVE(vnode_args, va_name); + VATTR_CLEAR_ACTIVE(vnode_args, va_uuuid); + VATTR_CLEAR_ACTIVE(vnode_args, va_guuid); + + VATTR_CLEAR_ACTIVE(vnode_args, va_total_size); + VATTR_CLEAR_ACTIVE(vnode_args, va_total_alloc); + VATTR_CLEAR_ACTIVE(vnode_args, va_data_alloc); + VATTR_CLEAR_ACTIVE(vnode_args, va_iosize); + + VATTR_CLEAR_ACTIVE(vnode_args, va_nchildren); + VATTR_CLEAR_ACTIVE(vnode_args, va_dirlinkcount); + } + else + { + PDEBUG("getattr: unable to get VBoxVFS object info"); + } + + lck_rw_unlock_shared(pVnodeData->pLock); + + return rc; +#endif +} + +#if 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; +} + +/** + * Helper function for vboxvfs_vnode_lookup(): take care + * about '.' and '..' directory entries. + */ +static int +vboxvfs_vnode_lookup_dot_handler(struct vnop_lookup_args *pArgs, vnode_t *result_vnode) +{ + vnode_t vnode = NULL; + + if (pArgs->a_cnp->cn_flags & ISDOTDOT) + { + vnode = vnode_getparent(pArgs->a_dvp); + if (vnode) + { + PDEBUG("return parent directory"); + *result_vnode = vnode; + return 0; + } + else + { + PDEBUG("return parent directory not found, return current directory"); + *result_vnode = pArgs->a_dvp; + return 0; + } + } + else if ((strncmp(pArgs->a_cnp->cn_nameptr, ".", 1) == 0) && + pArgs->a_cnp->cn_namelen == 1) + { + PDEBUG("return current directory"); + *result_vnode = pArgs->a_dvp; + return 0; + } + + return ENOENT; +} +#endif + +static int vboxSfDwnVnLookup(struct vnop_lookup_args *pArgs) +{ +#if 1 + RT_NOREF(pArgs); + return ENOTSUP; +#else + int rc; + + vnode_t vnode; + vboxvfs_vnode_t *pVnodeData; + + PDEBUG("Looking up for vnode..."); + + AssertReturn(pArgs, EINVAL); + AssertReturn(pArgs->a_dvp, EINVAL); + AssertReturn(vnode_isdir(pArgs->a_dvp), EINVAL); + AssertReturn(pArgs->a_cnp, EINVAL); + AssertReturn(pArgs->a_cnp->cn_nameptr, EINVAL); + AssertReturn(pArgs->a_vpp, EINVAL); + + pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(pArgs->a_dvp); + AssertReturn(pVnodeData, EINVAL); + AssertReturn(pVnodeData->pLock, EINVAL); + + /* + todo: take care about pArgs->a_cnp->cn_nameiop + */ + + if (pArgs->a_cnp->cn_nameiop == LOOKUP) PDEBUG("LOOKUP"); + else if (pArgs->a_cnp->cn_nameiop == CREATE) PDEBUG("CREATE"); + else if (pArgs->a_cnp->cn_nameiop == RENAME) PDEBUG("RENAME"); + else if (pArgs->a_cnp->cn_nameiop == DELETE) PDEBUG("DELETE"); + else PDEBUG("Unknown cn_nameiop: 0x%X", (int)pArgs->a_cnp->cn_nameiop); + + lck_rw_lock_exclusive(pVnodeData->pLock); + + /* Take care about '.' and '..' entries */ + if (vboxvfs_vnode_lookup_dot_handler(pArgs, &vnode) == 0) + { + vnode_get(vnode); + *pArgs->a_vpp = vnode; + + lck_rw_unlock_exclusive(pVnodeData->pLock); + + return 0; + } + + /* Look into VFS cache and attempt to find previously allocated vnode there. */ + rc = cache_lookup(pArgs->a_dvp, &vnode, pArgs->a_cnp); + if (rc == -1) /* Record found */ + { + PDEBUG("Found record in VFS cache"); + + /* Check if VFS object still exist on a host side */ + if (vboxvfs_exist_internal(vnode)) + { + /* Prepare & return cached vnode */ + vnode_get(vnode); + *pArgs->a_vpp = vnode; + + rc = 0; + } + else + { + /* If vnode exist in guets VFS cache, but not exist on a host -- just forget it. */ + cache_purge(vnode); + /** @todo free vnode data here */ + rc = ENOENT; + } + } + else + { + PDEBUG("cache_lookup() returned %d, create new VFS vnode", rc); + + rc = vboxvfs_vnode_lookup_instantinate_vnode(pArgs->a_dvp, pArgs->a_cnp->cn_nameptr, &vnode); + if (rc == 0) + { + cache_enter(pArgs->a_dvp, vnode, pArgs->a_cnp); + *pArgs->a_vpp = vnode; + } + else + { + rc = ENOENT; + } + } + + lck_rw_unlock_exclusive(pVnodeData->pLock); + + return rc; +#endif +} + +static int vboxSfDwnVnOpen(struct vnop_open_args *pArgs) +{ +#if 1 + RT_NOREF(pArgs); + return ENOTSUP; +#else + vnode_t vnode; + vboxvfs_vnode_t *pVnodeData; + uint32_t fHostFlags; + mount_t mp; + vboxvfs_mount_t *pMount; + + int rc; + + PDEBUG("Opening vnode..."); + + AssertReturn(pArgs, EINVAL); + + vnode = pArgs->a_vp; AssertReturn(vnode, EINVAL); + pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); + mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); + pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); + + lck_rw_lock_exclusive(pVnodeData->pLock); + + if (vnode_isinuse(vnode, 0)) + { + PDEBUG("vnode '%s' (handle 0x%X) already has VBoxVFS object handle assigned, just return ok", + (char *)pVnodeData->pPath->String.utf8, + (int)pVnodeData->pHandle); + + lck_rw_unlock_exclusive(pVnodeData->pLock); + return 0; + } + + /* At this point we must make sure that nobody is using VBoxVFS object handle */ + //if (pVnodeData->Handle != SHFL_HANDLE_NIL) + //{ + // PDEBUG("vnode has active VBoxVFS object handle set, aborting"); + // lck_rw_unlock_exclusive(pVnodeData->pLock); + // return EINVAL; + //} + + fHostFlags = vboxvfs_g2h_mode_inernal(pArgs->a_mode); + fHostFlags |= (vnode_isdir(vnode) ? SHFL_CF_DIRECTORY : 0); + + SHFLHANDLE Handle; + rc = vboxvfs_open_internal(pMount, pVnodeData->pPath, fHostFlags, &Handle); + if (rc == 0) + { + PDEBUG("Open success: '%s' (handle 0x%X)", + (char *)pVnodeData->pPath->String.utf8, + (int)Handle); + + pVnodeData->pHandle = Handle; + } + else + { + PDEBUG("Unable to open: '%s': %d", + (char *)pVnodeData->pPath->String.utf8, + rc); + } + + lck_rw_unlock_exclusive(pVnodeData->pLock); + + return rc; +#endif +} + +static int vboxSfDwnVnClose(struct vnop_close_args *pArgs) +{ +#if 1 + RT_NOREF(pArgs); + return ENOTSUP; +#else + + vnode_t vnode; + mount_t mp; + vboxvfs_vnode_t *pVnodeData; + vboxvfs_mount_t *pMount; + + int rc; + + PDEBUG("Closing vnode..."); + + AssertReturn(pArgs, EINVAL); + + vnode = pArgs->a_vp; AssertReturn(vnode, EINVAL); + pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); + mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); + pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); + + lck_rw_lock_exclusive(pVnodeData->pLock); + + if (vnode_isinuse(vnode, 0)) + { + PDEBUG("vnode '%s' (handle 0x%X) is still in use, just return ok", + (char *)pVnodeData->pPath->String.utf8, + (int)pVnodeData->pHandle); + + lck_rw_unlock_exclusive(pVnodeData->pLock); + return 0; + } + + /* At this point we must make sure that vnode has VBoxVFS object handle assigned */ + if (pVnodeData->pHandle == SHFL_HANDLE_NIL) + { + PDEBUG("vnode has no active VBoxVFS object handle set, aborting"); + lck_rw_unlock_exclusive(pVnodeData->pLock); + return EINVAL; + } + + rc = vboxvfs_close_internal(pMount, pVnodeData->pHandle); + if (rc == 0) + { + PDEBUG("Close success: '%s' (handle 0x%X)", + (char *)pVnodeData->pPath->String.utf8, + (int)pVnodeData->pHandle); + + /* Forget about previously assigned VBoxVFS object handle */ + pVnodeData->pHandle = SHFL_HANDLE_NIL; + } + else + { + PDEBUG("Unable to close: '%s' (handle 0x%X): %d", + (char *)pVnodeData->pPath->String.utf8, + (int)pVnodeData->pHandle, rc); + } + + lck_rw_unlock_exclusive(pVnodeData->pLock); + + return rc; +#endif +} + +#if 0 +/** + * Convert SHFLDIRINFO to struct dirent and copy it back to user. + */ +static int +vboxvfs_vnode_readdir_copy_data(ino_t index, SHFLDIRINFO *Info, struct uio *uio, int *numdirent) +{ + struct dirent entry; + + int rc; + + entry.d_ino = index; + entry.d_reclen = (__uint16_t)sizeof(entry); + + /* Detect dir entry type */ + if (RTFS_IS_DIRECTORY(Info->Info.Attr.fMode)) + entry.d_type = DT_DIR; + else if (RTFS_IS_FILE(Info->Info.Attr.fMode)) + entry.d_type = DT_REG; + else + { + PDEBUG("Unknown type of host file: mode 0x%X", (int)Info->Info.Attr.fMode); + return ENOTSUP; + } + + entry.d_namlen = (__uint8_t)min(sizeof(entry.d_name), Info->name.u16Size); + memcpy(entry.d_name, Info->name.String.utf8, entry.d_namlen); + + rc = uiomove((char *)&entry, sizeof(entry), uio); + if (rc == 0) + { + uio_setoffset(uio, index * sizeof(struct dirent)); + *numdirent = (int)index; + + PDEBUG("discovered entry: '%s' (%d bytes), item #%d", entry.d_name, (int)entry.d_namlen, (int)index); + } + else + { + PDEBUG("Failed to return dirent data item #%d (%d)", (int)index, rc); + } + + return rc; +} +#endif + +static int vboxSfDwnVnReadDir(struct vnop_readdir_args *pArgs) +{ +#if 1 + RT_NOREF(pArgs); + return ENOTSUP; +#else + vboxvfs_mount_t *pMount; + vboxvfs_vnode_t *pVnodeData; + SHFLDIRINFO *Info; + uint32_t cbInfo; + mount_t mp; + vnode_t vnode; + struct uio *uio; + + int rc = 0, rc2; + + PDEBUG("Reading directory..."); + + AssertReturn(pArgs, EINVAL); + AssertReturn(pArgs->a_eofflag, EINVAL); + AssertReturn(pArgs->a_numdirent, EINVAL); + + uio = pArgs->a_uio; AssertReturn(uio, EINVAL); + vnode = pArgs->a_vp; AssertReturn(vnode, EINVAL); AssertReturn(vnode_isdir(vnode), EINVAL); + pVnodeData = (vboxvfs_vnode_t *)vnode_fsnode(vnode); AssertReturn(pVnodeData, EINVAL); + mp = vnode_mount(vnode); AssertReturn(mp, EINVAL); + pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); + + lck_rw_lock_shared(pVnodeData->pLock); + + cbInfo = sizeof(Info) + MAXPATHLEN; + Info = (SHFLDIRINFO *)RTMemAllocZ(cbInfo); + if (!Info) + { + PDEBUG("No memory to allocate internal data"); + lck_rw_unlock_shared(pVnodeData->pLock); + return ENOMEM; + } + + uint32_t index = (uint32_t)uio_offset(uio) / (uint32_t)sizeof(struct dirent); + uint32_t cFiles = 0; + + PDEBUG("Exploring VBoxVFS directory (%s), handle (0x%.8X), offset (0x%X), count (%d)", (char *)pVnodeData->pPath->String.utf8, (int)pVnodeData->pHandle, index, uio_iovcnt(uio)); + + /* Currently, there is a problem when VbglR0SfDirInfo() is not able to + * continue retrieve directory content if the same VBoxVFS handle is used. + * This macro forces to use a new handle in readdir() callback. If enabled, + * the original handle (obtained in open() callback is ignored). */ + + SHFLHANDLE Handle; + rc = vboxvfs_open_internal(pMount, + pVnodeData->pPath, + SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW, + &Handle); + if (rc != 0) + { + PDEBUG("Unable to open dir: %d", rc); + RTMemFree(Info); + lck_rw_unlock_shared(pVnodeData->pLock); + return rc; + } + +#if 0 + rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0, 0, index, &cbInfo, (PSHFLDIRINFO)Info, &cFiles); +#else + SHFLSTRING *pMask = vboxvfs_construct_shflstring("*", strlen("*")); + if (pMask) + { + for (uint32_t cSkip = 0; (cSkip < index + 1) && (rc == VINF_SUCCESS); cSkip++) + { + //rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, 0 /* pMask */, 0 /* SHFL_LIST_RETURN_ONE */, 0, &cbInfo, (PSHFLDIRINFO)Info, &cFiles); + + uint32_t cbReturned = cbInfo; + //rc = VbglR0SfDirInfo(&g_vboxSFClient, &pMount->pMap, Handle, pMask, SHFL_LIST_RETURN_ONE, 0, &cbReturned, (PSHFLDIRINFO)Info, &cFiles); + rc = VbglR0SfDirInfo(&g_SfClientDarwin, &pMount->pMap, Handle, 0, SHFL_LIST_RETURN_ONE, 0, + &cbReturned, (PSHFLDIRINFO)Info, &cFiles); + + } + + PDEBUG("read %d files", cFiles); + RTMemFree(pMask); + } + else + { + PDEBUG("Can't alloc mask"); + rc = ENOMEM; + } +#endif + rc2 = vboxvfs_close_internal(pMount, Handle); + if (rc2 != 0) + { + PDEBUG("Unable to close directory: %s: %d", + pVnodeData->pPath->String.utf8, + rc2); + } + + switch (rc) + { + case VINF_SUCCESS: + { + rc = vboxvfs_vnode_readdir_copy_data((ino_t)(index + 1), Info, uio, pArgs->a_numdirent); + break; + } + + case VERR_NO_MORE_FILES: + { + PDEBUG("No more entries in directory"); + *(pArgs->a_eofflag) = 1; + break; + } + + default: + { + PDEBUG("VbglR0SfDirInfo() for item #%d has failed: %d", (int)index, (int)rc); + rc = EINVAL; + break; + } + } + + RTMemFree(Info); + lck_rw_unlock_shared(pVnodeData->pLock); + + return rc; +#endif +} + + +static int vboxSfDwnVnPathConf(struct vnop_pathconf_args *pArgs) +{ + Log(("vboxSfDwnVnPathConf:\n")); + RT_NOREF(pArgs); + return 0; +} + + +/** + * vnop_reclaim implementation. + * + * VBoxVFS reclaim callback. + * Called when vnode is going to be deallocated. Should release + * all the VBoxVFS resources that correspond to current vnode object. + * + * @param pArgs Operation arguments passed from VFS layer. + * + * @return 0 on success, BSD error code otherwise. + */ +static int vboxSfDwnVnReclaim(struct vnop_reclaim_args *pArgs) +{ + AssertReturn(pArgs && pArgs->a_vp, EINVAL); + + /* Check that it's not a root node that's in use. */ + PVBOXSFMNTDATA pMntData = (PVBOXSFMNTDATA)vfs_fsprivate(vnode_mount(pArgs->a_vp)); + AssertReturn(!pMntData || pMntData->pVnRoot != pArgs->a_vp, EBUSY); + + /* Get the private data and free it. */ + PVBOXSFDWNVNDATA pVnData = (PVBOXSFDWNVNDATA)vnode_fsnode(pArgs->a_vp); + AssertPtrReturn(pVnData, 0); + + if (pVnData->hHandle != SHFL_HANDLE_NIL) + { + /** @todo can this happen? */ + pVnData->hHandle = SHFL_HANDLE_NIL; + } + + RTMemFree(pVnData); + return 0; +} + + +/** + * Allocates a vnode. + * + * @returns Pointer to the new VNode, NULL if out of memory. + * @param pMount The file system mount structure. + * @param enmType The vnode type. + * @param pParent The parent vnode, NULL if root. + * @param cbFile The file size + */ +vnode_t vboxSfDwnVnAlloc(mount_t pMount, enum vtype enmType, vnode_t pParent, uint64_t cbFile) +{ + /* + * Create our private data. + */ + PVBOXSFDWNVNDATA pVnData = (PVBOXSFDWNVNDATA)RTMemAllocZ(sizeof(*pVnData)); + if (pVnData) + { + pVnData->hHandle = SHFL_HANDLE_NIL; + + struct vnode_fsparam VnParms; + RT_ZERO(VnParms); + VnParms.vnfs_mp = pMount; + VnParms.vnfs_vtype = enmType; + VnParms.vnfs_str = "vboxsf"; + VnParms.vnfs_dvp = pParent; + VnParms.vnfs_fsnode = pVnData; + VnParms.vnfs_vops = g_papfnVBoxSfDwnVnDirOpsVector; + VnParms.vnfs_markroot = pParent == NULL; + VnParms.vnfs_marksystem = 0; + VnParms.vnfs_rdev = 0; + VnParms.vnfs_filesize = cbFile; + VnParms.vnfs_cnp = 0; + VnParms.vnfs_flags = VNFS_NOCACHE; + + vnode_t pVnRet; + int rc = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &VnParms, &pVnRet); + if (rc == 0) + return pVnRet; + RTMemFree(pVnData); + } + printf("vboxSfDwnVnAlloc: out of memory!\n"); + return NULL; +} + + +/** + * Vnode operations. + */ +static struct vnodeopv_entry_desc g_VBoxSfDirOpsDescList[] = +{ +#define VNODEOPFUNC int(*)(void *) + { &vnop_default_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_access_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - probably not needed. + //{ &vnop_advlock_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - later. + //{ &vnop_allocate_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - maybe, need shfl function + { &vnop_blktooff_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_blockmap_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_bwrite_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_close_desc, (VNODEOPFUNC)vboxSfDwnVnClose }, + //{ &vnop_copyfile_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_create_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_exchange_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_fsync_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_getattr_desc, (VNODEOPFUNC)vboxFsDwnVnGetAttr }, + //{ &vnop_getnamedstream_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_getxattr_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_inactive_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_ioctl_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_link_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_listxattr_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_lookup_desc, (VNODEOPFUNC)vboxSfDwnVnLookup }, + { &vnop_mkdir_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_mknod_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_mmap_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_mnomap_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_offtoblk_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_open_desc, (VNODEOPFUNC)vboxSfDwnVnOpen }, + { &vnop_pagein_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_pageout_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_pathconf_desc, (VNODEOPFUNC)vboxSfDwnVnPathConf }, + /* { &vnop_print_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, undefined in ML */ + { &vnop_read_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_readdir_desc, (VNODEOPFUNC)vboxSfDwnVnReadDir }, + //{ &vnop_readdirattr_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - hfs specific. + { &vnop_readlink_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_reclaim_desc, (VNODEOPFUNC)vboxSfDwnVnReclaim }, + { &vnop_remove_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_removexattr_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_rename_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_revoke_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - not needed + { &vnop_rmdir_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_searchfs_desc, (VNODEOPFUNC)err_searchfs }, + //{ &vnop_select_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - not needed + { &vnop_setattr_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { &vnop_setxattr_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + //{ &vnop_strategy_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - not needed + { &vnop_symlink_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + /* { &vnop_truncate_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, undefined in ML */ + //{ &vnop_whiteout_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, - not needed/supported + { &vnop_write_desc, (VNODEOPFUNC)vboxSfDwnVnDefaultError }, + { NULL, (VNODEOPFUNC)NULL }, +#undef VNODEOPFUNC +}; + +/** ??? */ +int (**g_papfnVBoxSfDwnVnDirOpsVector)(void *); + +/** + * VNode operation descriptors. + */ +struct vnodeopv_desc g_VBoxSfVnodeOpvDesc = +{ + &g_papfnVBoxSfDwnVnDirOpsVector, + g_VBoxSfDirOpsDescList +}; + |