diff --git a/emulators/virtualbox-ose-additions-nox11/Makefile b/emulators/virtualbox-ose-additions-nox11/Makefile index a3744275a9a3..be1a45194f0a 100644 --- a/emulators/virtualbox-ose-additions-nox11/Makefile +++ b/emulators/virtualbox-ose-additions-nox11/Makefile @@ -1,8 +1,8 @@ -PORTREVISION= 0 +PORTREVISION= 1 PKGNAMESUFFIX= -additions-nox11 MASTERDIR= ${.CURDIR}/../virtualbox-ose-additions OPTIONS_EXCLUDE= DBUS DEBUG OPENGL X11 .include "${MASTERDIR}/Makefile" diff --git a/emulators/virtualbox-ose-additions/Makefile b/emulators/virtualbox-ose-additions/Makefile index 0bcd8a8fe54a..744878d43317 100644 --- a/emulators/virtualbox-ose-additions/Makefile +++ b/emulators/virtualbox-ose-additions/Makefile @@ -1,164 +1,164 @@ PORTNAME= virtualbox-ose DISTVERSION= 6.1.50 -PORTREVISION?= 0 +PORTREVISION?= 1 CATEGORIES= emulators MASTER_SITES= https://download.virtualbox.org/virtualbox/${DISTVERSION}/ PKGNAMESUFFIX?= -additions DISTNAME= VirtualBox-${DISTVERSION} MAINTAINER= vbox@FreeBSD.org COMMENT= VirtualBox additions for FreeBSD guests WWW= https://www.virtualbox.org/ LICENSE= GPLv2 LICENSE_FILE= ${WRKSRC}/COPYING ONLY_FOR_ARCHS= amd64 BUILD_DEPENDS= yasm:devel/yasm \ kmk:devel/kBuild \ xsltproc:textproc/libxslt USES= compiler:c++11-lang cpe iconv kmod tar:bzip2 CPE_VENDOR= oracle CPE_PRODUCT= vm_virtualbox USE_RC_SUBR= vboxguest vboxservice HAS_CONFIGURE= yes CONFIGURE_ARGS+= --disable-alsa \ --disable-docs \ --disable-libvpx \ --disable-opengl \ --disable-pulse \ --disable-python \ --disable-sdl-ttf \ --disable-xpcom CONFIGURE_ARGS+= --nofatal --with-gcc="${CC}" --with-g++="${CXX}" MAKE_JOBS_UNSAFE= yes CONFLICTS_INSTALL= virtualbox-ose-additions-legacy \ virtualbox-ose-additions-nox11-legacy PATCHDIR= ${.CURDIR}/../${PORTNAME}/files EXTRACT_AFTER_ARGS= --exclude tools/*.x86 --exclude tools/*.amd64 --exclude Firmware WRKSRC= ${WRKDIR}/VirtualBox-${DISTVERSION} OPTIONS_DEFINE= DBUS DEBUG X11 OPTIONS_DEFAULT= DBUS X11 OPTIONS_SUB= yes DBUS_LIB_DEPENDS= libdbus-1.so:devel/dbus DBUS_CONFIGURE_OFF= --disable-dbus DEBUG_CONFIGURE_ON= --build-debug DEBUG_VARS= KMK_BUILDTYPE=debug DEBUG_VARS_OFF= KMK_BUILDTYPE=release X11_BUILD_DEPENDS= ${LOCALBASE}/include/xorg/compiler.h:x11-servers/xorg-server X11_RUN_DEPENDS= xrandr:x11/xrandr X11_USES= pkgconfig xorg X11_USE= XORG=x11,xcursor,xext,xorgproto,xmu,xrandr,xt X11_VARS= VBOX_WITH_X11=1 .include .if ${SLAVE_PORT} == no CONFLICTS_INSTALL+= virtualbox-ose-additions-nox11 .else CONFLICTS_INSTALL+= virtualbox-ose-additions .endif VIDEODIR= ${PREFIX}/lib/xorg/modules/drivers INPUTDIR= ${PREFIX}/lib/xorg/modules/input VBOX_BIN= ${WRKSRC}/out/${KMK_ARCH}/${KMK_BUILDTYPE}/bin/additions VBOX_SBINS= VBoxControl \ VBoxService \ mount_vboxvfs BUILD_WRKSRC= ${VBOX_BIN}/src KMK_ARCH= freebsd.${ARCH:S/i386/x86/} KMK_CONFIG+= VBOX_LIBPATH_X11=${LOCALBASE} VBOX_FREEBSD_SRC=${SRC_BASE}/sys .if ${PORT_OPTIONS:MX11} .else VBOX_WITH_X11= .endif .include post-patch: @${ECHO_CMD} 'VBOX_ONLY_ADDITIONS = 1' > ${WRKSRC}/LocalConfig.kmk @${ECHO_CMD} 'VBOX_WITH_DRAG_AND_DROP = ${VBOX_WITH_X11}' >> \ ${WRKSRC}/LocalConfig.kmk @${ECHO_CMD} 'VBOX_WITH_DRAG_AND_DROP_GH = ${VBOX_WITH_X11}' >> \ ${WRKSRC}/LocalConfig.kmk @${ECHO_CMD} 'VBOX_WITH_X11_ADDITIONS = ${VBOX_WITH_X11}' >> \ ${WRKSRC}/LocalConfig.kmk @${ECHO_CMD} 'VBOX_GCC_std = -std=c++11' >> ${WRKSRC}/LocalConfig.kmk @${ECHO_CMD} 'CXXDEFS += _LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR' >> \ ${WRKSRC}/LocalConfig.kmk .if ${COMPILER_TYPE} == clang @${REINPLACE_CMD} -e 's| -finline-limit=8000||' \ -e 's| -fno-merge-constants||' \ -e 's| -mpreferred-stack-boundary=2||' ${WRKSRC}/Config.kmk .endif @${REINPLACE_CMD} -e 's|/usr/local|${LOCALBASE}|g' \ ${WRKSRC}/Config.kmk ${WRKSRC}/configure \ ${WRKSRC}/kBuild/header.kmk ${WRKSRC}/kBuild/units/qt4.kmk \ ${WRKSRC}/kBuild/units/qt5.kmk ${WRKSRC}/kBuild/sdks/LIBSDL.kmk \ ${WRKSRC}/src/VBox/Additions/x11/Installer/98vboxadd-xclient \ ${WRKSRC}/src/VBox/Additions/x11/Installer/vboxclient.desktop \ ${WRKSRC}/src/VBox/Additions/x11/vboxmouse/Makefile.kmk \ ${WRKSRC}/src/VBox/Additions/x11/vboxvideo/Makefile.kmk @${REINPLACE_CMD} \ -e 's|\$$KBUILDDIR_BIN/kmk_sed|${LOCALBASE}/bin/kmk_sed|g' \ ${WRKSRC}/configure .if empty(ICONV_LIB) @${REINPLACE_CMD} -e 's|iconv||' ${WRKSRC}/Config.kmk \ ${WRKSRC}/src/VBox/Runtime/Makefile.kmk \ ${WRKSRC}/src/VBox/Additions/x11/VBoxClient/Makefile.kmk @${ECHO_CMD} 'VBOX_ICONV_DEFS = LIBICONV_PLUG' >> ${WRKSRC}/LocalConfig.kmk .endif post-patch-X11-on: @${ECHO_CMD} 'VBOX_USE_SYSTEM_XORG_HEADERS = 1' >> \ ${WRKSRC}/LocalConfig.kmk pre-build: cd ${WRKSRC} && ${SH} -c \ ". env.sh && ${KMK_CONFIG} ${LOCALBASE}/bin/kmk" do-install: ${MKDIR} ${STAGEDIR}${KMODDIR} ${INSTALL_KLD} ${VBOX_BIN}/src/vboxguest/vboxguest.ko \ ${STAGEDIR}${KMODDIR} ${INSTALL_KLD} ${VBOX_BIN}/vboxvfs.ko ${STAGEDIR}${KMODDIR} ${INSTALL_LIB} ${VBOX_BIN}/pam_vbox.so ${STAGEDIR}${PREFIX}/lib ${INSTALL_PROGRAM} ${VBOX_SBINS:S|^|${VBOX_BIN}/|} \ ${STAGEDIR}${PREFIX}/sbin/ do-install-X11-on: ${INSTALL_PROGRAM} ${VBOX_BIN}/VBoxClient ${STAGEDIR}${PREFIX}/bin/ ${INSTALL_SCRIPT} \ ${WRKSRC}/src/VBox/Additions/x11/Installer/98vboxadd-xclient \ ${STAGEDIR}${PREFIX}/bin/VBoxClient-all # X11 autostart ${MKDIR} ${STAGEDIR}${PREFIX}/etc/xdg/autostart/ ${INSTALL_DATA} \ ${WRKSRC}/src/VBox/Additions/x11/Installer/vboxclient.desktop \ ${STAGEDIR}${PREFIX}/etc/xdg/autostart/ # KDE autostart ${MKDIR} ${STAGEDIR}${PREFIX}/share/autostart/ ${INSTALL_DATA} \ ${WRKSRC}/src/VBox/Additions/x11/Installer/vboxclient.desktop \ ${STAGEDIR}${PREFIX}/share/autostart/ ${MKDIR} ${STAGEDIR}${VIDEODIR} ${INSTALL_LIB} ${VBOX_BIN}/vboxvideo_drv_system.so \ ${STAGEDIR}${VIDEODIR}/vboxvideo_drv.so ${MKDIR} ${STAGEDIR}${INPUTDIR} ${INSTALL_LIB} ${VBOX_BIN}/vboxmouse_drv_system.so \ ${STAGEDIR}${INPUTDIR}/vboxmouse_drv.so .include diff --git a/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs.h b/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs.h index 3551533f2bcd..858e894c7b6b 100644 --- a/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs.h +++ b/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs.h @@ -1,427 +1,428 @@ --- src/VBox/Additions/freebsd/vboxvfs/vboxvfs.h.orig 2021-01-07 15:34:22 UTC +++ src/VBox/Additions/freebsd/vboxvfs/vboxvfs.h @@ -1,8 +1,3 @@ -/* $Id: vboxvfs.h $ */ -/** @file - * Description. - */ - /* * Copyright (C) 2010-2020 Oracle Corporation * -@@ -24,72 +19,377 @@ +@@ -24,72 +19,378 @@ #define VBOXVFS_VFSNAME "vboxvfs" #define VBOXVFS_VERSION 1 -#define MAX_HOST_NAME 256 -#define MAX_NLS_NAME 32 +#define MAX_HOST_NAME 256 +#define MAX_NLS_NAME 32 +//#define MODEMASK 07777 /* mode bits plus permission bits */ +/** Helper macros */ +#define VFSTOVBOXFS(mp) ((struct vboxfs_mnt *)((mp)->mnt_data)) +#define VP_TO_VBOXFS_NODE(vp) ((struct vboxfs_node *)(vp)->v_data) +#define VBOXTOV(np) ((struct vnode *)(np)->n_vnode) -struct vboxvfs_mount_info { - char name[MAX_HOST_NAME]; - char nls_name[MAX_NLS_NAME]; - int uid; - int gid; - int ttl; -}; +#define ROOTDIR_INO 1 +#define THEFILE_INO 2 +#define THEFILE_NAME "thefile" +#define VBOXFS_NODE_LOCK(node) mtx_lock(&(node)->sf_interlock) +#define VBOXFS_NODE_UNLOCK(node) mtx_unlock(&(node)->sf_interlock) +#define VBOXFS_NODE_MTX(node) (&(node)->sf_interlock) +#define VBOXFS_NODE_ASSERT_LOCKED(node) mtx_assert(VBOXFS_NODE_MTX(node), \ + MA_OWNED) + +#ifdef INVARIANTS +#define VBOXFS_ASSERT_LOCKED(node) do { \ + MPASS(node != NULL); \ + MPASS(node->sf_vnode != NULL); \ + if (!VOP_ISLOCKED(node->sf_vnode) && \ + !mtx_owned(VBOXFS_NODE_MTX(node))) \ + panic("vboxfs: node is not locked: %p", node); \ + } while (0) +#define VBOXFS_ASSERT_ELOCKED(node) do { \ + MPASS((node) != NULL); \ + MPASS((node)->sf_vnode != NULL); \ + mtx_assert(VBOXFS_NODE_MTX(node), MA_OWNED); \ + ASSERT_VOP_LOCKED((node)->sf_vnode, "vboxfs"); \ + } while (0) +#else +#define VBOXFS_ASSERT_LOCKED(node) (void)0 +#define VBOXFS_ASSERT_ELOCKED(node) (void)0 +#endif + +#define VBOXFS_VNODE_ALLOCATING 1 +#define VBOXFS_VNODE_WANT 2 +#define VBOXFS_VNODE_DOOMED 4 +#define VBOXFS_VNODE_WRECLAIM 8 + +MALLOC_DECLARE(M_VBOXVFS); + #ifdef _KERNEL +#ifndef FREEBSD_STYLE +#include "../../../../../include/iprt/nocrt/limits.h" +#include "../../../../../include/iprt/alloc.h" +#include "../../../../../include/iprt/asm.h" +#include "../../../../../include/iprt/asm-amd64-x86.h" +#include "../../../../../include/iprt/asm-math.h" +#include "../../../../../include/iprt/assert.h" +#include "../../../../../include/iprt/cdefs.h" +#include "../../../../../include/iprt/err.h" +#include "../../../../../include/iprt/fs.h" +#include "../../../../../include/iprt/log.h" +#include "../../../../../include/iprt/mem.h" +#include "../../../../../include/iprt/param.h" +#include "../../../../../include/iprt/path.h" +#include "../../../../../include/iprt/semaphore.h" +#include "../../../../../include/iprt/stdarg.h" +#include "../../../../../include/iprt/stdint.h" +#include "../../../../../include/iprt/string.h" +#include "../../../../../include/iprt/time.h" +#include "../../../../../include/iprt/types.h" +#include "../../../../../include/iprt/uni.h" -#include +#else + +#include "iprt/nocrt/limits.h" +#include "iprt/alloc.h" +#include "iprt/asm.h" +#include "iprt/asm-amd64-x86.h" +#include "iprt/asm-math.h" +#include "iprt/assert.h" +#include "iprt/cdefs.h" +#include "iprt/err.h" +#include "iprt/fs.h" +#include "iprt/log.h" +#include "iprt/mem.h" +#include "iprt/param.h" +#include "iprt/path.h" +#include "iprt/semaphore.h" +#include "iprt/stdarg.h" +#include "iprt/stdint.h" +#include "iprt/string.h" +#include "iprt/time.h" +#include "iprt/types.h" +#include "iprt/uni.h" + +#include "common/VBoxGuestLib/SysHlp.h" + +#endif /* !FREEBSD_STYLE */ + #include #include +#include -struct vboxvfsmount { - uid_t uid; - gid_t gid; - mode_t file_mode; - mode_t dir_mode; - struct mount *mp; - struct ucred *owner; - u_int flags; - long nextino; - int caseopt; - int didrele; +#include + +#if __FreeBSD_version >= 1400093 +typedef __enum_uint8(vtype) enum_vtype_t; +#else +typedef enum vtype enum_vtype_t; +#endif + +#define VBOXVFS_DEBUG(lvl, ...) do { \ + if (vboxvfs_debug >= (lvl)) { \ + printf("VBOXVFS[%u]: ", lvl); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } \ +} while (0) + +/* + * representation of an active mount point + */ +struct sfp_mount { + VBGLSFMAP map; }; -/* structs - stolen from the linux shared module code */ +/* + * Mount / Unmount a shared folder. + * + * sfprov_mount() takes as input the connection pointer and the name of + * the shared folder. On success, it returns zero and supplies an + * sfp_mount_t handle. On failure it returns any relevant errno value. + * + * sfprov_unmount() unmounts the mounted file system. It returns 0 on + * success and any relevant errno on failure. + */ +typedef struct sfp_mount sfp_mount_t; + +struct sfp_file { + SHFLHANDLE handle; + VBGLSFMAP map; /* need this again for the close operation */ +}; + +typedef struct sfp_file sfp_file_t; + +/* + * File operations: open/close/read/write/etc. + * + * open/create can return any relevant errno, however ENOENT + * generally means that the host file didn't exist. + */ +typedef struct sffs_stat { + mode_t sf_mode; + off_t sf_size; + off_t sf_alloc; + struct timespec sf_atime; + struct timespec sf_mtime; + struct timespec sf_ctime; +} sffs_stat_t; + +/* + * Read directory entries. + */ +/* + * a singly linked list of buffers, each containing an array of stat's+dirent's. + * sf_len is length of the sf_entries array, in bytes. + */ +typedef struct sffs_dirents { + struct sffs_dirents *sf_next; + long long sf_len; + struct sffs_dirent { + sffs_stat_t sf_stat; + struct dirent sf_entry; /* this is variable length */ + off_t sf_off; + } sf_entries[1]; +} sffs_dirents_t; + +/* + * Shared Folders filesystem per-mount data structure. + */ +struct vboxfs_mnt { + struct mount *sf_vfsp; /* filesystem's vfs struct */ + sfp_mount_t *sf_handle; /* guest-host communication handle */ + uid_t sf_uid; /* owner of all shared folders */ + gid_t sf_gid; /* group of all shared folders */ + mode_t sf_dmode; /* mode of all directories */ + mode_t sf_fmode; /* mode of all files */ + mode_t sf_dmask; /* mask of all directories */ + mode_t sf_fmask; /* mask of all files */ + int sf_stat_ttl; /* ttl for stat caches (in ms) */ + int sf_fsync; /* whether to honor fsync or not */ + uint64_t sf_ino; /* per FS ino generator */ + uma_zone_t sf_node_pool; + struct vboxfs_node *sf_root; +}; + +/* + * vboxfs_node is the file system dependent vnode data for vboxfs. + * vboxfs_node's also track all files ever accessed, both open and closed. + * It duplicates some of the information in vnode, since it holds + * information for files that may have been completely closed. + * + */ +struct vboxfs_node { + struct vboxfs_mnt *vboxfsmp; /* containing mounted file system */ + char *sf_path; /* full pathname to file or dir */ + uint64_t sf_ino; /* assigned unique ID number */ + struct vnode *sf_vnode; /* vnode if active */ + sfp_file_t *sf_file; /* non NULL if open */ + struct vboxfs_node *sf_parent; /* parent sfnode of this one */ ++ uint32_t sf_opencnt; /* sf_file reference counter */ + uint16_t sf_children; /* number of children sfnodes */ + uint8_t sf_type; /* VDIR or VREG */ + uint8_t sf_vpstate; /* XXX: ADD COMMENT */ + uint8_t sf_is_stale; /* this is stale and should be purged */ + sffs_stat_t sf_stat; /* cached file attrs for this node */ + uint64_t sf_stat_time; /* last-modified time of sf_stat */ + sffs_dirents_t *sf_dir_list; /* list of entries for this directory */ + -+ /* interlock to protect sf_vpstate */ ++ /* interlock to protect sf_vpstate, sf_file and sf_opencnt */ + struct mtx sf_interlock; +}; + +struct vboxfs_mount_info { + char name[MAX_HOST_NAME]; /* share name */ + char nls_name[MAX_NLS_NAME];/* name of an I/O charset */ + int uid; /* user ID for all entries, default 0=root */ + int gid; /* group ID for all entries, default 0=root */ + int ttl; /* time to live */ + int dmode; /* mode for directories if != 0xffffffff */ + int fmode; /* mode for regular files if != 0xffffffff */ + int dmask; /* umask applied to directories */ + int fmask; /* umask applied to regular files */ +}; + struct sf_glob_info { - VBGLSFMAP map; -/* struct nls_table *nls;*/ - int ttl; - int uid; - int gid; - struct vnode *vnode_root; + VBGLSFMAP map; +/* struct nls_table *nls;*/ + int ttl; + int uid; + int gid; + struct vnode *vnode_root; }; +/** Per-file system mount instance data. */ +typedef struct vboxfs_globinfo +{ + VBGLSFMAP Map; + int Ttl; + int Uid; + int Gid; + struct mount *pVFS; + struct vboxfs_node *pVNodeRoot; +} vboxfs_globinfo_t; + struct sf_inode_info { - SHFLSTRING *path; - int force_restat; + SHFLSTRING *path; + int force_restat; }; #if 0 struct sf_dir_info { - struct list_head info_list; + struct list_head info_list; }; #endif struct sf_dir_buf { - size_t nb_entries; - size_t free_bytes; - size_t used_bytes; - void *buf; + size_t nb_entries; + size_t free_bytes; + size_t used_bytes; + void *buf; #if 0 - struct list_head head; + struct list_head head; #endif }; struct sf_reg_info { - SHFLHANDLE handle; + SHFLHANDLE handle; }; +int vboxfs_alloc_vp(struct mount *, struct vboxfs_node *, int, + struct vnode **); +void vboxfs_free_vp(struct vnode *); + +int vboxfs_alloc_node(struct mount *, struct vboxfs_mnt *, const char*, + enum_vtype_t, uid_t, gid_t, mode_t, struct vboxfs_node *, + struct vboxfs_node **); +void vboxfs_free_node(struct vboxfs_mnt *, struct vboxfs_node *); + +/* + * These are the provider interfaces used by sffs to access the underlying + * shared file system. + */ +#define SFPROV_VERSION 1 + +/* + * Initialization and termination. + * sfprov_connect() is called once before any other interfaces and returns + * a handle used in further calls. The argument should be SFPROV_VERSION + * from above. On failure it returns a NULL pointer. + * + * sfprov_disconnect() must only be called after all sf file systems have been + * unmounted. + */ +typedef struct sfp_connection sfp_connection_t; + +extern sfp_connection_t *sfprov_connect(int); +extern void sfprov_disconnect(void); + +extern int sfprov_mount(char *, sfp_mount_t **); +extern int sfprov_unmount(sfp_mount_t *); + +/* + * query information about a mounted file system + */ +typedef struct sffs_fsinfo { + uint64_t blksize; + uint64_t blksused; + uint64_t blksavail; + uint32_t maxnamesize; + uint32_t readonly; + uint32_t serial; +} sffs_fsinfo_t; + +extern int sfprov_get_fsinfo(sfp_mount_t *, sffs_fsinfo_t *); + +extern int sfprov_create(sfp_mount_t *, char *path, mode_t mode, -+ sfp_file_t **fp, sffs_stat_t *stat); ++ sffs_stat_t *stat); +extern int sfprov_open(sfp_mount_t *, char *path, sfp_file_t **fp); +extern int sfprov_close(sfp_file_t *fp); +extern int sfprov_read(sfp_file_t *, char * buffer, uint64_t offset, + uint32_t *numbytes, int buflocked); +extern int sfprov_write(sfp_file_t *, char * buffer, uint64_t offset, + uint32_t *numbytes, int buflocked); +extern int sfprov_fsync(sfp_file_t *fp); + + +/* + * get/set information about a file (or directory) using pathname + */ +extern int sfprov_get_mode(sfp_mount_t *, char *, mode_t *); +extern int sfprov_get_size(sfp_mount_t *, char *, uint64_t *); +extern int sfprov_get_atime(sfp_mount_t *, char *, struct timespec *); +extern int sfprov_get_mtime(sfp_mount_t *, char *, struct timespec *); +extern int sfprov_get_ctime(sfp_mount_t *, char *, struct timespec *); +extern int sfprov_get_attr(sfp_mount_t *, char *, sffs_stat_t *); +extern int sfprov_set_attr(sfp_mount_t *, char *, mode_t, + struct timespec, struct timespec, struct timespec); +extern int sfprov_set_size(sfp_mount_t *, char *, uint64_t); + + +/* + * File/Directory operations + */ +extern int sfprov_trunc(sfp_mount_t *, char *); +extern int sfprov_remove(sfp_mount_t *, char *path, u_int is_link); +extern int sfprov_mkdir(sfp_mount_t *, char *path, mode_t mode, -+ sfp_file_t **fp, sffs_stat_t *stat); ++ sffs_stat_t *stat); +extern int sfprov_rmdir(sfp_mount_t *, char *path); +extern int sfprov_rename(sfp_mount_t *, char *from, char *to, u_int is_dir); + + +/* + * Symbolic link operations + */ +extern int sfprov_set_show_symlinks(void); +extern int sfprov_readlink(sfp_mount_t *, char *path, char *target, + size_t tgt_size); +extern int sfprov_symlink(sfp_mount_t *, char *linkname, char *target, + sffs_stat_t *stat); + +#define SFFS_DIRENTS_SIZE 8192 +#define SFFS_DIRENTS_OFF (offsetof(sffs_dirents_t, sf_entries[0])) + +extern int sfprov_readdir(sfp_mount_t *mnt, char *path, + sffs_dirents_t **dirents); + #endif /* KERNEL */ #endif /* !GA_INCLUDED_SRC_freebsd_vboxvfs_vboxvfs_h */ - diff --git a/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__prov.c b/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__prov.c index 340e72a1578d..e606c4f1de6f 100644 --- a/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__prov.c +++ b/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__prov.c @@ -1,1024 +1,1015 @@ ---- src/VBox/Additions/freebsd/vboxvfs/vboxvfs_prov.c.orig 2020-06-26 09:59:35 UTC -+++ src/VBox/Additions/freebsd/vboxvfs/vboxvfs_prov.c -@@ -0,0 +1,1021 @@ +--- src/VBox/Additions/freebsd/vboxvfs/vboxvfs_prov.c.orig 2024-08-15 13:18:37.777504000 +0900 ++++ src/VBox/Additions/freebsd/vboxvfs/vboxvfs_prov.c 2024-08-15 13:18:37.777446000 +0900 +@@ -0,0 +1,1012 @@ +/* + * Copyright (C) 2008-2016 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * 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. + */ + +/* + * Provider interfaces for shared folder file system. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vboxvfs.h" + +#define DIRENT_RECLEN(namelen) \ + ((offsetof(struct dirent, d_name[0]) + 1 + (namelen) + 7) & ~ 7) +#define DIRENT_NAMELEN(reclen) \ + ((reclen) - (offsetof(struct dirent, d_name[0]))) + +static VBGLSFCLIENT vbox_client; + +extern u_int vboxvfs_debug; + +static int +sfprov_vbox2errno(int rc) +{ + if (rc == VERR_ACCESS_DENIED) + return (EACCES); + if (rc == VERR_INVALID_NAME) + return (ENOENT); + return (RTErrConvertToErrno(rc)); +} + +/* + * utility to create strings + */ +static SHFLSTRING * +sfprov_string(char *path, int *sz) +{ + SHFLSTRING *str; + int len = strlen(path); + + *sz = len + 1 + sizeof (*str) - sizeof (str->String); + str = malloc(*sz, M_VBOXVFS, M_WAITOK | M_ZERO); + str->u16Size = len + 1; + str->u16Length = len; + strcpy(str->String.utf8, path); + return (str); +} + +sfp_connection_t * +sfprov_connect(int version) +{ + /* only one version for now, so must match */ + int error = -1; + + if (version != SFPROV_VERSION) { + printf("%s: version mismatch (%d, expected %d)\n", __func__, + version, SFPROV_VERSION); + return (NULL); + } + + if (RT_FAILURE(VbglR0SfInit())) + return (NULL); + + if (RT_FAILURE(VbglR0SfConnect(&vbox_client))) { + VbglR0SfTerm(); + return (NULL); + } + + if (RT_FAILURE(VbglR0SfSetUtf8(&vbox_client))) { + VbglR0SfDisconnect(&vbox_client); + VbglR0SfTerm(); + return (NULL); + } + return ((sfp_connection_t *)&vbox_client); +} + +void +sfprov_disconnect() +{ + VbglR0SfDisconnect(&vbox_client); + VbglR0SfTerm(); +} + +int +sfprov_mount(char *path, sfp_mount_t **mnt) +{ + sfp_mount_t *m; + SHFLSTRING *str; + int size; + int rc; + + VBOXVFS_DEBUG(1, "%s: Enter", __FUNCTION__); + VBOXVFS_DEBUG(1, "%s: path: [%s]", __FUNCTION__, path); + + m = malloc(sizeof (*m), M_VBOXVFS, M_WAITOK | M_ZERO); + str = sfprov_string(path, &size); + + int error; + rc = VbglR0SfMapFolder(&vbox_client, str, &m->map); + if (RT_FAILURE(rc)) { + free(m, M_VBOXVFS); + *mnt = NULL; + error = sfprov_vbox2errno(rc); + } else { + *mnt = m; + error = 0; + } + free(str, M_VBOXVFS); + printf("%s(%s): error=%d rc=%d\n", __func__, path, error, rc); + return (error); +} + +int +sfprov_unmount(sfp_mount_t *mnt) +{ + int rc; + + rc = VbglR0SfUnmapFolder(&vbox_client, &mnt->map); + if (RT_FAILURE(rc)) { + printf("sfprov_unmount: VbglR0SfUnmapFolder() failed rc=%d\n", rc); + rc = sfprov_vbox2errno(rc); + } else { + rc = 0; + } + + free(mnt, M_VBOXVFS); + return (rc); +} + +/* + * query information about a mounted file system + */ +int +sfprov_get_fsinfo(sfp_mount_t *mnt, sffs_fsinfo_t *fsinfo) +{ + int rc; + SHFLVOLINFO info; + uint32_t bytes = sizeof(SHFLVOLINFO); + size_t bytesused; + + rc = VbglR0SfFsInfo(&vbox_client, &mnt->map, 0, + (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + + fsinfo->blksize = info.ulBytesPerAllocationUnit; + bytesused = + info.ullTotalAllocationBytes - info.ullAvailableAllocationBytes; + fsinfo->blksused = bytesused / info.ulBytesPerAllocationUnit; + fsinfo->blksavail = info.ullAvailableAllocationBytes / + info.ulBytesPerAllocationUnit; + fsinfo->maxnamesize = info.fsProperties.cbMaxComponent; + fsinfo->readonly = info.fsProperties.fReadOnly; + fsinfo->serial = info.ulSerial; + return (0); +} + +/* + * file/directory information conversions. + */ +static void +sfprov_fmode_from_mode(RTFMODE *fMode, mode_t mode) +{ + RTFMODE m = 0; + +#define mode_set(r) ((mode & (S_##r)) ? RTFS_UNIX_##r : 0) + m = mode_set (ISUID); + m |= mode_set (ISGID); + m |= (mode & S_ISVTX) ? RTFS_UNIX_ISTXT : 0; + m |= mode_set (IRUSR); + m |= mode_set (IWUSR); + m |= mode_set (IXUSR); + m |= mode_set (IRGRP); + m |= mode_set (IWGRP); + m |= mode_set (IXGRP); + m |= mode_set (IROTH); + m |= mode_set (IWOTH); + m |= mode_set (IXOTH); + + if (S_ISDIR(mode)) + m |= RTFS_TYPE_DIRECTORY; + else if (S_ISREG(mode)) + m |= RTFS_TYPE_FILE; + else if (S_ISFIFO(mode)) + m |= RTFS_TYPE_FIFO; + else if (S_ISCHR(mode)) + m |= RTFS_TYPE_DEV_CHAR; + else if (S_ISBLK(mode)) + m |= RTFS_TYPE_DEV_BLOCK; + else if (S_ISLNK(mode)) + m |= RTFS_TYPE_SYMLINK; + else if (S_ISSOCK(mode)) + m |= RTFS_TYPE_SOCKET; + else + m |= RTFS_TYPE_FILE; + + *fMode = m; +} + +static void +sfprov_mode_from_fmode(mode_t *mode, RTFMODE fMode) +{ + mode_t m = 0; + + if (RTFS_IS_DIRECTORY(fMode)) + m |= S_IFDIR; + else if (RTFS_IS_FILE(fMode)) + m |= S_IFREG; + else if (RTFS_IS_FIFO(fMode)) + m |= S_IFIFO; + else if (RTFS_IS_DEV_CHAR(fMode)) + m |= S_IFCHR; + else if (RTFS_IS_DEV_BLOCK(fMode)) + m |= S_IFBLK; + else if (RTFS_IS_SYMLINK(fMode)) + m |= S_IFLNK; + else if (RTFS_IS_SOCKET(fMode)) + m |= S_IFSOCK; + + if (fMode & RTFS_UNIX_IRUSR) + m |= S_IRUSR; + if (fMode & RTFS_UNIX_IWUSR) + m |= S_IWUSR; + if (fMode & RTFS_UNIX_IXUSR) + m |= S_IXUSR; + if (fMode & RTFS_UNIX_IRGRP) + m |= S_IRGRP; + if (fMode & RTFS_UNIX_IWGRP) + m |= S_IWGRP; + if (fMode & RTFS_UNIX_IXGRP) + m |= S_IXGRP; + if (fMode & RTFS_UNIX_IROTH) + m |= S_IROTH; + if (fMode & RTFS_UNIX_IWOTH) + m |= S_IWOTH; + if (fMode & RTFS_UNIX_IXOTH) + m |= S_IXOTH; + if (fMode & RTFS_UNIX_ISUID) + m |= S_ISUID; + if (fMode & RTFS_UNIX_ISGID) + m |= S_ISGID; + if (fMode & RTFS_UNIX_ISTXT) + m |= S_ISVTX; + *mode = m; +} + +static void +sfprov_ftime_from_timespec(struct timespec *time, RTTIMESPEC *ts) +{ + uint64_t nanosec = RTTimeSpecGetNano(ts); + time->tv_sec = nanosec / UINT64_C(1000000000); + time->tv_nsec = nanosec % UINT64_C(1000000000); +} + +static void +sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info) +{ + sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode); + stat->sf_size = info->cbObject; + stat->sf_alloc = info->cbAllocated; + sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime); + sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime); + sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime); +} + +/* + * File operations: open/close/read/write/etc. + * + * open/create can return any relevant errno, however ENOENT + * generally means that the host file didn't exist. + */ +int +sfprov_create( + sfp_mount_t *mnt, + char *path, + mode_t mode, -+ sfp_file_t **fp, + sffs_stat_t *stat) +{ + int rc; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + int size; + sfp_file_t *newfp; + + str = sfprov_string(path, &size); + parms.Handle = SHFL_HANDLE_NIL; + parms.Info.cbObject = 0; + sfprov_fmode_from_mode(&parms.Info.Attr.fMode, mode); + parms.CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW | + SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACCESS_READWRITE; + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + free(str, M_VBOXVFS); + + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + if (parms.Handle == SHFL_HANDLE_NIL) { + if (parms.Result == SHFL_FILE_EXISTS) + return (EEXIST); + return (ENOENT); + } -+ newfp = malloc(sizeof(sfp_file_t), M_VBOXVFS, M_WAITOK | M_ZERO); -+ newfp->handle = parms.Handle; -+ newfp->map = mnt->map; -+ *fp = newfp; ++ (void)VbglR0SfClose(&vbox_client, &mnt->map, parms.Handle); + sfprov_stat_from_info(stat, &parms.Info); + return (0); +} + +int +sfprov_open(sfp_mount_t *mnt, char *path, sfp_file_t **fp) +{ + int rc; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + int size; + sfp_file_t *newfp; + + /* + * First we attempt to open it read/write. If that fails we + * try read only. + */ + bzero(&parms, sizeof(parms)); + str = sfprov_string(path, &size); + parms.Handle = SHFL_HANDLE_NIL; + parms.Info.cbObject = 0; + parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE; + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + if (RT_FAILURE(rc) && rc != VERR_ACCESS_DENIED) { + free(str, M_VBOXVFS); + return (sfprov_vbox2errno(rc)); + } + if (parms.Handle == SHFL_HANDLE_NIL) { + if (parms.Result == SHFL_PATH_NOT_FOUND || + parms.Result == SHFL_FILE_NOT_FOUND) { + free(str, M_VBOXVFS); + return (ENOENT); + } + parms.CreateFlags = + SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + if (RT_FAILURE(rc)) { + free(str, M_VBOXVFS); + return (sfprov_vbox2errno(rc)); + } + if (parms.Handle == SHFL_HANDLE_NIL) { + free(str, M_VBOXVFS); + return (ENOENT); + } + } + else + free(str, M_VBOXVFS); + newfp = malloc(sizeof(sfp_file_t), M_VBOXVFS, M_WAITOK | M_ZERO); + newfp->handle = parms.Handle; + newfp->map = mnt->map; + *fp = newfp; + return (0); +} + +int +sfprov_trunc(sfp_mount_t *mnt, char *path) +{ + int rc; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + int size; + + /* + * open it read/write. + */ + str = sfprov_string(path, &size); + parms.Handle = 0; + parms.Info.cbObject = 0; + parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE | + SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + free(str, M_VBOXVFS); + + if (RT_FAILURE(rc)) { + return (sfprov_vbox2errno(rc)); + } + (void)VbglR0SfClose(&vbox_client, &mnt->map, parms.Handle); + return (0); +} + +int +sfprov_close(sfp_file_t *fp) +{ + int rc; + + rc = VbglR0SfClose(&vbox_client, &fp->map, fp->handle); + free(fp, M_VBOXVFS); + return (0); +} + +int +sfprov_read(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes, + int buflocked) +{ + int rc; + + rc = VbglR0SfRead(&vbox_client, &fp->map, fp->handle, offset, + numbytes, (uint8_t *)buffer, buflocked); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + return (0); +} + +int +sfprov_write(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes, + int buflocked) +{ + int rc; + + rc = VbglR0SfWrite(&vbox_client, &fp->map, fp->handle, offset, + numbytes, (uint8_t *)buffer, buflocked); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + return (0); +} + +int +sfprov_fsync(sfp_file_t *fp) +{ + int rc; + + rc = VbglR0SfFlush(&vbox_client, &fp->map, fp->handle); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + return (0); +} + + +static int +sfprov_getinfo(sfp_mount_t *mnt, char *path, PSHFLFSOBJINFO info) +{ + int rc; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + int size; + + str = sfprov_string(path, &size); + parms.Handle = 0; + parms.Info.cbObject = 0; + parms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + free(str, M_VBOXVFS); + + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + if (parms.Result != SHFL_FILE_EXISTS) + return (ENOENT); + *info = parms.Info; + return (0); +} + +/* + * get information about a file (or directory) + */ +int +sfprov_get_mode(sfp_mount_t *mnt, char *path, mode_t *mode) +{ + int rc; + SHFLFSOBJINFO info; + + rc = sfprov_getinfo(mnt, path, &info); + if (rc) + return (rc); + sfprov_mode_from_fmode(mode, info.Attr.fMode); + return (0); +} + +int +sfprov_get_size(sfp_mount_t *mnt, char *path, uint64_t *size) +{ + int rc; + SHFLFSOBJINFO info; + + rc = sfprov_getinfo(mnt, path, &info); + if (rc) + return (rc); + *size = info.cbObject; + return (0); +} + + +int +sfprov_get_atime(sfp_mount_t *mnt, char *path, struct timespec *time) +{ + int rc; + SHFLFSOBJINFO info; + + rc = sfprov_getinfo(mnt, path, &info); + if (rc) + return (rc); + sfprov_ftime_from_timespec(time, &info.AccessTime); + return (0); +} + +int +sfprov_get_mtime(sfp_mount_t *mnt, char *path, struct timespec *time) +{ + int rc; + SHFLFSOBJINFO info; + + rc = sfprov_getinfo(mnt, path, &info); + if (rc) + return (rc); + sfprov_ftime_from_timespec(time, &info.ModificationTime); + return (0); +} + +int +sfprov_get_ctime(sfp_mount_t *mnt, char *path, struct timespec *time) +{ + int rc; + SHFLFSOBJINFO info; + + rc = sfprov_getinfo(mnt, path, &info); + if (rc) + return (rc); + sfprov_ftime_from_timespec(time, &info.ChangeTime); + return (0); +} + +int +sfprov_get_attr(sfp_mount_t *mnt, char *path, sffs_stat_t *attr) +{ + int rc; + SHFLFSOBJINFO info; + + rc = sfprov_getinfo(mnt, path, &info); + if (rc) + return (rc); + sfprov_stat_from_info(attr, &info); + return (0); +} + +static void +sfprov_timespec_from_ftime(RTTIMESPEC *ts, struct timespec time) +{ + uint64_t nanosec = UINT64_C(1000000000) * time.tv_sec + time.tv_nsec; + RTTimeSpecSetNano(ts, nanosec); +} + +int +sfprov_set_attr( + sfp_mount_t *mnt, + char *path, + mode_t mode, + struct timespec atime, + struct timespec mtime, + struct timespec ctime) +{ + int rc, err; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + SHFLFSOBJINFO info; + uint32_t bytes; + int str_size; + + str = sfprov_string(path, &str_size); + parms.Handle = 0; + parms.Info.cbObject = 0; + parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS + | SHFL_CF_ACT_FAIL_IF_NEW + | SHFL_CF_ACCESS_ATTR_WRITE; + + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + + if (RT_FAILURE(rc)) { + printf("sfprov_set_attr: VbglR0SfCreate(%s) failed rc=%d\n", + path, rc); + err = sfprov_vbox2errno(rc); + goto fail2; + } + if (parms.Result != SHFL_FILE_EXISTS) { + err = ENOENT; + goto fail1; + } + + RT_ZERO(info); +#if 0 + if (mask & AT_MODE) + sfprov_fmode_from_mode(&info.Attr.fMode, mode); + if (mask & AT_ATIME) + sfprov_timespec_from_ftime(&info.AccessTime, atime); + if (mask & AT_MTIME) + sfprov_timespec_from_ftime(&info.ModificationTime, mtime); + if (mask & AT_CTIME) + sfprov_timespec_from_ftime(&info.ChangeTime, ctime); +#endif + bytes = sizeof(info); + rc = VbglR0SfFsInfo(&vbox_client, &mnt->map, parms.Handle, + (SHFL_INFO_SET | SHFL_INFO_FILE), &bytes, (SHFLDIRINFO *)&info); + if (RT_FAILURE(rc)) { + if (rc != VERR_ACCESS_DENIED && rc != VERR_WRITE_PROTECT) + { + printf("sfprov_set_attr: VbglR0SfFsInfo(%s, FILE) failed rc=%d\n", + path, rc); + } + err = sfprov_vbox2errno(rc); + goto fail1; + } + + err = 0; + +fail1: + rc = VbglR0SfClose(&vbox_client, &mnt->map, parms.Handle); + if (RT_FAILURE(rc)) { + printf("sfprov_set_attr: VbglR0SfClose(%s) failed rc=%d\n", + path, rc); + } +fail2: + free(str, M_VBOXVFS); + return err; +} + +int +sfprov_set_size(sfp_mount_t *mnt, char *path, uint64_t size) +{ + int rc, err; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + SHFLFSOBJINFO info; + uint32_t bytes; + int str_size; + + str = sfprov_string(path, &str_size); + parms.Handle = 0; + parms.Info.cbObject = 0; + parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS + | SHFL_CF_ACT_FAIL_IF_NEW + | SHFL_CF_ACCESS_WRITE; + + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + + if (RT_FAILURE(rc)) { + printf("sfprov_set_size: VbglR0SfCreate(%s) failed rc=%d\n", + path, rc); + err = sfprov_vbox2errno(rc); + goto fail2; + } + if (parms.Result != SHFL_FILE_EXISTS) { + err = ENOENT; + goto fail1; + } + + RT_ZERO(info); + info.cbObject = size; + bytes = sizeof(info); + rc = VbglR0SfFsInfo(&vbox_client, &mnt->map, parms.Handle, + (SHFL_INFO_SET | SHFL_INFO_SIZE), &bytes, (SHFLDIRINFO *)&info); + if (RT_FAILURE(rc)) { + printf("sfprov_set_size: VbglR0SfFsInfo(%s, SIZE) failed rc=%d\n", + path, rc); + err = sfprov_vbox2errno(rc); + goto fail1; + } + + err = 0; + +fail1: + rc = VbglR0SfClose(&vbox_client, &mnt->map, parms.Handle); + if (RT_FAILURE(rc)) { + printf("sfprov_set_size: VbglR0SfClose(%s) failed rc=%d\n", + path, rc); + } +fail2: + free(str, M_VBOXVFS); + return err; +} + +/* + * Directory operations + */ +int +sfprov_mkdir( + sfp_mount_t *mnt, + char *path, + mode_t mode, -+ sfp_file_t **fp, + sffs_stat_t *stat) +{ + int rc; + SHFLCREATEPARMS parms; + SHFLSTRING *str; + int size; -+ sfp_file_t *newfp; + + str = sfprov_string(path, &size); + parms.Handle = SHFL_HANDLE_NIL; + parms.Info.cbObject = 0; + sfprov_fmode_from_mode(&parms.Info.Attr.fMode, mode); + parms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW | + SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ; + rc = VbglR0SfCreate(&vbox_client, &mnt->map, str, &parms); + free(str, M_VBOXVFS); + + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + if (parms.Handle == SHFL_HANDLE_NIL) { + if (parms.Result == SHFL_FILE_EXISTS) + return (EEXIST); + return (ENOENT); + } -+ newfp = malloc(sizeof(sfp_file_t), M_VBOXVFS, M_WAITOK | M_ZERO); -+ newfp->handle = parms.Handle; -+ newfp->map = mnt->map; -+ *fp = newfp; ++ (void)VbglR0SfClose(&vbox_client, &mnt->map, parms.Handle); + sfprov_stat_from_info(stat, &parms.Info); + return (0); +} + +int +sfprov_set_show_symlinks(void) +{ + int rc; + + rc = VbglR0SfSetSymlinks(&vbox_client); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + + return (0); +} + +int +sfprov_remove(sfp_mount_t *mnt, char *path, u_int is_link) +{ + int rc; + SHFLSTRING *str; + int size; + + str = sfprov_string(path, &size); + rc = VbglR0SfRemove(&vbox_client, &mnt->map, str, + SHFL_REMOVE_FILE | (is_link ? SHFL_REMOVE_SYMLINK : 0)); + free(str, M_VBOXVFS); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + return (0); +} + +int +sfprov_readlink( + sfp_mount_t *mnt, + char *path, + char *target, + size_t tgt_size) +{ + int rc; + SHFLSTRING *str; + int size; + + str = sfprov_string(path, &size); + + rc = VbglR0SfReadLink(&vbox_client, &mnt->map, str, (uint32_t) tgt_size, + target); + if (RT_FAILURE(rc)) + rc = sfprov_vbox2errno(rc); + + free(str, M_VBOXVFS); + return (rc); +} + +int +sfprov_symlink( + sfp_mount_t *mnt, + char *linkname, + char *target, + sffs_stat_t *stat) +{ + int rc; + SHFLSTRING *lnk, *tgt; + int lnk_size, tgt_size; + SHFLFSOBJINFO info; + + lnk = sfprov_string(linkname, &lnk_size); + tgt = sfprov_string(target, &tgt_size); + + rc = VbglR0SfSymlink(&vbox_client, &mnt->map, lnk, tgt, &info); + if (RT_FAILURE(rc)) { + rc = sfprov_vbox2errno(rc); + goto done; + } + + if (stat != NULL) + sfprov_stat_from_info(stat, &info); + +done: + free(lnk, M_VBOXVFS); + free(tgt, M_VBOXVFS); + + return (rc); +} + +int +sfprov_rmdir(sfp_mount_t *mnt, char *path) +{ + int rc; + SHFLSTRING *str; + int size; + + str = sfprov_string(path, &size); + rc = VbglR0SfRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_DIR); + free(str, M_VBOXVFS); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + return (0); +} + +int +sfprov_rename(sfp_mount_t *mnt, char *from, char *to, u_int is_dir) +{ + int rc; + SHFLSTRING *old, *new; + int old_size, new_size; + + old = sfprov_string(from, &old_size); + new = sfprov_string(to, &new_size); + rc = VbglR0SfRename(&vbox_client, &mnt->map, old, new, + (is_dir ? SHFL_RENAME_DIR : SHFL_RENAME_FILE) | + SHFL_RENAME_REPLACE_IF_EXISTS); + free(old, M_VBOXVFS); + free(new, M_VBOXVFS); + if (RT_FAILURE(rc)) + return (sfprov_vbox2errno(rc)); + return (0); +} + +/* + * Read all filenames in a directory. + * + * - success - all entries read and returned + * - ENOENT - Couldn't open the directory for reading + * - EINVAL - Internal error of some kind + * + * On successful return, *dirents points to a list of sffs_dirents_t; + * for each dirent, all fields except the d_ino will be set appropriately. + * The caller is responsible for freeing the dirents buffer. + */ +int +sfprov_readdir( + sfp_mount_t *mnt, + char *path, + sffs_dirents_t **dirents) +{ + int error; + char *cp; + int len; + SHFLSTRING *mask_str = NULL; /* must be path with "/" appended */ + int mask_size; + sfp_file_t *fp; + uint32_t infobuff_alloc = 16384; + SHFLDIRINFO *infobuff = NULL, *info; + uint32_t numbytes; + uint32_t nents; + uint32_t size; + off_t offset; + sffs_dirents_t *cur_buf; + struct sffs_dirent *dirent; + unsigned short reclen; + unsigned short entlen; + + *dirents = NULL; + + error = sfprov_open(mnt, path, &fp); + if (error != 0) + return (ENOENT); + + /* + * Allocate the first dirents buffers. + */ + *dirents = malloc(SFFS_DIRENTS_SIZE, M_VBOXVFS, M_WAITOK | M_ZERO); + if (*dirents == NULL) { + error = (ENOSPC); + goto done; + } + cur_buf = *dirents; + cur_buf->sf_next = NULL; + cur_buf->sf_len = 0; + + /* + * Create mask that VBox expects. This needs to be the directory path, + * plus a "*" wildcard to get all files. + */ + len = strlen(path) + 3; + cp = malloc(len, M_VBOXVFS, M_WAITOK | M_ZERO); + if (cp == NULL) { + error = (ENOSPC); + goto done; + } + strcpy(cp, path); + strcat(cp, "/*"); + mask_str = sfprov_string(cp, &mask_size); + free(cp, M_VBOXVFS); + + /* + * Now loop using VbglR0SfDirInfo + */ + infobuff = malloc(infobuff_alloc, M_VBOXVFS, M_WAITOK | M_ZERO); + if (infobuff == NULL) { + error = (ENOSPC); + goto done; + } + + offset = 0; + for (;;) { + numbytes = infobuff_alloc; + error = VbglR0SfDirInfo(&vbox_client, &fp->map, fp->handle, + mask_str, 0, 0, &numbytes, infobuff, &nents); + + switch (error) { + case VINF_SUCCESS: + /* fallthrough */ + case VERR_NO_MORE_FILES: + break; + case VERR_NO_TRANSLATION: + /* XXX ??? */ + break; + default: + error = sfprov_vbox2errno(error); + goto done; + } + + /* + * Create the dirent_t's and save the stats for each name + */ + for (info = infobuff; (char *) info < (char *) infobuff + numbytes; nents--) { + size_t buflen; + + /* expand buffers if we need more space */ + reclen = DIRENT_RECLEN(strlen(info->name.String.utf8)); + entlen = sizeof(struct sffs_dirent) + reclen; + buflen = SFFS_DIRENTS_OFF + cur_buf->sf_len + entlen; + if (buflen > SFFS_DIRENTS_SIZE) { + cur_buf->sf_next = malloc(SFFS_DIRENTS_SIZE, + M_VBOXVFS, M_WAITOK | M_ZERO); + if (cur_buf->sf_next == NULL) { + error = ENOSPC; + goto done; + } + cur_buf = cur_buf->sf_next; + cur_buf->sf_next = NULL; + cur_buf->sf_len = 0; + } + + /* create the dirent with the name, offset, and len */ + dirent = (struct sffs_dirent *) + (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len); + strncpy(&dirent->sf_entry.d_name[0], + info->name.String.utf8, DIRENT_NAMELEN(reclen)); + dirent->sf_entry.d_reclen = reclen; + dirent->sf_entry.d_namlen = strlen(info->name.String.utf8); + dirent->sf_entry.d_name[dirent->sf_entry.d_namlen] = 0; + offset += entlen; + dirent->sf_off = offset; + + /* save the stats */ + sfprov_stat_from_info(&dirent->sf_stat, &info->Info); + + /* next info */ + cur_buf->sf_len += entlen; + size = offsetof (SHFLDIRINFO, name.String) + info->name.u16Size; + info = (SHFLDIRINFO *) ((uintptr_t) info + size); + } + KASSERT(nents == 0, ("nents != 0")); + KASSERT((char *) info == (char *) infobuff + numbytes, "(char *) info != (char *) infobuff + numbytes"); + + if (error == VERR_NO_MORE_FILES) + break; + } + error = 0; + +done: + if (error != 0) { + while (*dirents) { + cur_buf = (*dirents)->sf_next; + free(*dirents, M_VBOXVFS); + *dirents = cur_buf; + } + } + if (infobuff != NULL) + free(infobuff, M_VBOXVFS); + if (mask_str != NULL) + free(mask_str, M_VBOXVFS); + sfprov_close(fp); + + return (error); +} diff --git a/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__vnops.c b/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__vnops.c index d0da1fbf3f45..edd43c7c03c7 100644 --- a/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__vnops.c +++ b/emulators/virtualbox-ose/files/patch-src_VBox_Additions_freebsd_vboxvfs_vboxvfs__vnops.c @@ -1,1491 +1,1543 @@ ---- src/VBox/Additions/freebsd/vboxvfs/vboxvfs_vnops.c.orig 2022-07-19 20:51:58 UTC +--- src/VBox/Additions/freebsd/vboxvfs/vboxvfs_vnops.c.orig 2023-07-12 15:59:35 UTC +++ src/VBox/Additions/freebsd/vboxvfs/vboxvfs_vnops.c -@@ -14,228 +14,1364 @@ +@@ -14,228 +14,1416 @@ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ - -#include "vboxvfs.h" #include #include #include #include -#include +#include +#include +#include #include +#include #include -#include +#include #include -#include #include -#include -#include -#include +#include +#include +#include +#include -#include -#include +#include +#include "vboxvfs.h" + +#if __FreeBSD_version < 1300063 +#define VN_IS_DOOMED(vp) (((vp)->v_iflag & VI_DOOMED) != 0) +#endif + /* * Prototypes for VBOXVFS vnode operations */ -static vop_create_t vboxvfs_create; -static vop_mknod_t vboxvfs_mknod; -static vop_open_t vboxvfs_open; -static vop_close_t vboxvfs_close; -static vop_access_t vboxvfs_access; -static vop_getattr_t vboxvfs_getattr; -static vop_setattr_t vboxvfs_setattr; -static vop_read_t vboxvfs_read; -static vop_write_t vboxvfs_write; -static vop_fsync_t vboxvfs_fsync; -static vop_remove_t vboxvfs_remove; -static vop_link_t vboxvfs_link; -static vop_lookup_t vboxvfs_lookup; -static vop_rename_t vboxvfs_rename; -static vop_mkdir_t vboxvfs_mkdir; -static vop_rmdir_t vboxvfs_rmdir; -static vop_symlink_t vboxvfs_symlink; -static vop_readdir_t vboxvfs_readdir; -static vop_strategy_t vboxvfs_strategy; -static vop_print_t vboxvfs_print; -static vop_pathconf_t vboxvfs_pathconf; -static vop_advlock_t vboxvfs_advlock; -static vop_getextattr_t vboxvfs_getextattr; -static vop_ioctl_t vboxvfs_ioctl; -static vop_getpages_t vboxvfs_getpages; -static vop_inactive_t vboxvfs_inactive; -static vop_putpages_t vboxvfs_putpages; -static vop_reclaim_t vboxvfs_reclaim; +static vop_create_t vboxfs_create; +static vop_open_t vboxfs_open; +static vop_close_t vboxfs_close; +static vop_access_t vboxfs_access; +static vop_getattr_t vboxfs_getattr; +static vop_setattr_t vboxfs_setattr; +static vop_read_t vboxfs_read; +static vop_readlink_t vboxfs_readlink; +static vop_write_t vboxfs_write; +static vop_fsync_t vboxfs_fsync; +static vop_remove_t vboxfs_remove; +static vop_link_t vboxfs_link; -+static vop_cachedlookup_t vboxfs_lookup; ++static vop_lookup_t vboxfs_lookup; ++static vop_cachedlookup_t vboxfs_cachedlookup; +static vop_rename_t vboxfs_rename; +static vop_mkdir_t vboxfs_mkdir; +static vop_rmdir_t vboxfs_rmdir; +static vop_symlink_t vboxfs_symlink; +static vop_readdir_t vboxfs_readdir; +static vop_print_t vboxfs_print; +static vop_pathconf_t vboxfs_pathconf; +static vop_advlock_t vboxfs_advlock; +static vop_ioctl_t vboxfs_ioctl; +static vop_inactive_t vboxfs_inactive; +static vop_reclaim_t vboxfs_reclaim; +static vop_vptofh_t vboxfs_vptofh; -struct vop_vector vboxvfs_vnodeops = { - .vop_default = &default_vnodeops, +struct vop_vector vboxfs_vnodeops = { + .vop_default = &default_vnodeops, - .vop_access = vboxvfs_access, - .vop_advlock = vboxvfs_advlock, - .vop_close = vboxvfs_close, - .vop_create = vboxvfs_create, - .vop_fsync = vboxvfs_fsync, - .vop_getattr = vboxvfs_getattr, - .vop_getextattr = vboxvfs_getextattr, - .vop_getpages = vboxvfs_getpages, - .vop_inactive = vboxvfs_inactive, - .vop_ioctl = vboxvfs_ioctl, - .vop_link = vboxvfs_link, - .vop_lookup = vboxvfs_lookup, - .vop_mkdir = vboxvfs_mkdir, - .vop_mknod = vboxvfs_mknod, - .vop_open = vboxvfs_open, - .vop_pathconf = vboxvfs_pathconf, - .vop_print = vboxvfs_print, - .vop_putpages = vboxvfs_putpages, - .vop_read = vboxvfs_read, - .vop_readdir = vboxvfs_readdir, - .vop_reclaim = vboxvfs_reclaim, - .vop_remove = vboxvfs_remove, - .vop_rename = vboxvfs_rename, - .vop_rmdir = vboxvfs_rmdir, - .vop_setattr = vboxvfs_setattr, - .vop_strategy = vboxvfs_strategy, - .vop_symlink = vboxvfs_symlink, - .vop_write = vboxvfs_write, + .vop_access = vboxfs_access, + .vop_advlock = VOP_EOPNOTSUPP, + .vop_close = vboxfs_close, + .vop_create = vboxfs_create, + .vop_fsync = vboxfs_fsync, + .vop_getattr = vboxfs_getattr, + .vop_getextattr = VOP_EOPNOTSUPP, + .vop_inactive = vboxfs_inactive, + .vop_ioctl = vboxfs_ioctl, + .vop_link = vboxfs_link, -+ .vop_lookup = vfs_cache_lookup, -+ .vop_cachedlookup = vboxfs_lookup, ++ .vop_lookup = vboxfs_lookup, ++ .vop_cachedlookup = vboxfs_cachedlookup, + .vop_mkdir = vboxfs_mkdir, + .vop_mknod = VOP_EOPNOTSUPP, + .vop_open = vboxfs_open, + .vop_pathconf = vboxfs_pathconf, + .vop_print = vboxfs_print, + .vop_read = vboxfs_read, + .vop_readdir = vboxfs_readdir, + .vop_readlink = vboxfs_readlink, + .vop_reclaim = vboxfs_reclaim, + .vop_remove = vboxfs_remove, + .vop_rename = vboxfs_rename, + .vop_rmdir = vboxfs_rmdir, + .vop_setattr = vboxfs_setattr, + .vop_vptofh = vboxfs_vptofh, + .vop_symlink = vboxfs_symlink, + .vop_write = vboxfs_write, + .vop_bmap = VOP_EOPNOTSUPP }; +#if __FreeBSD_version > 1300068 +VFS_VOP_VECTOR_REGISTER(vboxfs_vnodeops); +#endif -static int vboxvfs_access(struct vop_access_args *ap) +static uint64_t +vsfnode_cur_time_usec(void) { - return 0; + struct timeval now; + + getmicrotime(&now); + + return (now.tv_sec*1000 + now.tv_usec); } -static int vboxvfs_open(struct vop_open_args *ap) +static int +vsfnode_stat_cached(struct vboxfs_node *np) { - return 0; + return (vsfnode_cur_time_usec() - np->sf_stat_time) < + np->vboxfsmp->sf_stat_ttl * 1000UL; } -static int vboxvfs_close(struct vop_close_args *ap) +static int +vsfnode_update_stat_cache(struct vboxfs_node *np) { - return 0; + int error; + + error = sfprov_get_attr(np->vboxfsmp->sf_handle, np->sf_path, + &np->sf_stat); +#if 0 + if (error == ENOENT) + sfnode_make_stale(node); +#endif + if (error == 0) + np->sf_stat_time = vsfnode_cur_time_usec(); + + return (error); } -static int vboxvfs_getattr(struct vop_getattr_args *ap) +/* + * Need to clear v_object for insmntque failure. + */ +static void +vboxfs_insmntque_dtr(struct vnode *vp, void *dtr_arg) { - return 0; + + // XXX: vboxfs_destroy_vobject(vp, vp->v_object); + vp->v_object = NULL; + vp->v_data = NULL; + vp->v_op = &dead_vnodeops; + vgone(vp); + vput(vp); } -static int vboxvfs_setattr(struct vop_setattr_args *ap) +/* + * Allocates a new vnode for the node node or returns a new reference to + * an existing one if the node had already a vnode referencing it. The + * resulting locked vnode is returned in *vpp. + * + * Returns zero on success or an appropriate error code on failure. + */ +int +vboxfs_alloc_vp(struct mount *mp, struct vboxfs_node *node, int lkflag, + struct vnode **vpp) { - return 0; + struct vnode *vp; + int error; + + error = 0; +loop: + VBOXFS_NODE_LOCK(node); +loop1: + if ((vp = node->sf_vnode) != NULL) { + MPASS((node->sf_vpstate & VBOXFS_VNODE_DOOMED) == 0); + VI_LOCK(vp); + if ((node->sf_type == VDIR && node->sf_parent == NULL) || + (VN_IS_DOOMED(vp) && + (lkflag & LK_NOWAIT) != 0)) { + VI_UNLOCK(vp); + VBOXFS_NODE_UNLOCK(node); + error = ENOENT; + vp = NULL; + goto out; + } + if (VN_IS_DOOMED(vp)) { + VI_UNLOCK(vp); + node->sf_vpstate |= VBOXFS_VNODE_WRECLAIM; + while ((node->sf_vpstate & VBOXFS_VNODE_WRECLAIM) != 0) { + msleep(&node->sf_vnode, VBOXFS_NODE_MTX(node), + 0, "vsfE", 0); + } + goto loop1; + } + VBOXFS_NODE_UNLOCK(node); +#if __FreeBSD_version < 1300109 + error = vget(vp, lkflag | LK_INTERLOCK, curthread); +#else + error = vget(vp, lkflag | LK_INTERLOCK); +#endif + if (error == ENOENT) + goto loop; + if (error != 0) { + vp = NULL; + goto out; + } + + /* + * Make sure the vnode is still there after + * getting the interlock to avoid racing a free. + */ + if (node->sf_vnode == NULL || node->sf_vnode != vp) { + vput(vp); + goto loop; + } + + goto out; + } + + if ((node->sf_vpstate & VBOXFS_VNODE_DOOMED) || + (node->sf_type == VDIR && node->sf_parent == NULL)) { + VBOXFS_NODE_UNLOCK(node); + error = ENOENT; + vp = NULL; + goto out; + } + + /* + * otherwise lock the vp list while we call getnewvnode + * since that can block. + */ + if (node->sf_vpstate & VBOXFS_VNODE_ALLOCATING) { + node->sf_vpstate |= VBOXFS_VNODE_WANT; + error = msleep((caddr_t) &node->sf_vpstate, + VBOXFS_NODE_MTX(node), PDROP | PCATCH, + "vboxfs_alloc_vp", 0); + if (error) + return error; + + goto loop; + } else + node->sf_vpstate |= VBOXFS_VNODE_ALLOCATING; + + VBOXFS_NODE_UNLOCK(node); + + /* Get a new vnode and associate it with our node. */ + error = getnewvnode("vboxfs", mp, &vboxfs_vnodeops, &vp); + if (error != 0) + goto unlock; + MPASS(vp != NULL); + + /* lkflag is ignored, the lock is exclusive */ + (void) vn_lock(vp, lkflag | LK_RETRY); + + vp->v_data = node; + vp->v_type = node->sf_type; + + /* Type-specific initialization. */ + switch (node->sf_type) { + case VBLK: + /* FALLTHROUGH */ + case VCHR: + /* FALLTHROUGH */ + case VLNK: + /* FALLTHROUGH */ + case VSOCK: + /* FALLTHROUGH */ + case VFIFO: + /* FALLTHROUGH */ + case VREG: + break; + case VDIR: + MPASS(node->sf_parent != NULL); + if (node->sf_parent == node) + vp->v_vflag |= VV_ROOT; + break; + + default: + panic("vboxfs_alloc_vp: type %p %d", node, (int)node->sf_type); + } + + if (vp->v_type != VFIFO) + VN_LOCK_ASHARE(vp); + +#if __FreeBSD_version < 1400051 + error = insmntque1(vp, mp, vboxfs_insmntque_dtr, NULL); +#else + error = insmntque(vp, mp); +#endif + if (error) { +#if __FreeBSD_version >= 1400051 + vboxfs_insmntque_dtr(vp, NULL); +#endif + vp = NULL; + } + +unlock: + VBOXFS_NODE_LOCK(node); + + MPASS(node->sf_vpstate & VBOXFS_VNODE_ALLOCATING); + node->sf_vpstate &= ~VBOXFS_VNODE_ALLOCATING; + node->sf_vnode = vp; + + if (node->sf_vpstate & VBOXFS_VNODE_WANT) { + node->sf_vpstate &= ~VBOXFS_VNODE_WANT; + VBOXFS_NODE_UNLOCK(node); + wakeup((caddr_t) &node->sf_vpstate); + } else + VBOXFS_NODE_UNLOCK(node); + +out: + *vpp = vp; + +#ifdef INVARIANTS + if (error == 0) { + MPASS(*vpp != NULL && VOP_ISLOCKED(*vpp)); + VBOXFS_NODE_LOCK(node); + MPASS(*vpp == node->sf_vnode); + VBOXFS_NODE_UNLOCK(node); + } +#endif + + return error; } -static int vboxvfs_read(struct vop_read_args *ap) +/* + * Destroys the association between the vnode vp and the node it + * references. + */ +void +vboxfs_free_vp(struct vnode *vp) { - return 0; + struct vboxfs_node *node; + + node = VP_TO_VBOXFS_NODE(vp); + + VBOXFS_NODE_ASSERT_LOCKED(node); + node->sf_vnode = NULL; + if ((node->sf_vpstate & VBOXFS_VNODE_WRECLAIM) != 0) + wakeup(&node->sf_vnode); + node->sf_vpstate &= ~VBOXFS_VNODE_WRECLAIM; + vp->v_data = NULL; } -static int vboxvfs_write(struct vop_write_args *ap) +/* + * Allocate new vboxfs_node and vnode for given file + */ +static int +vboxfs_alloc_file(struct vboxfs_mnt *vboxfsmp, const char *fullpath, + enum_vtype_t type, mode_t mode, struct vboxfs_node *parent, + int lkflag, struct vnode **vpp) { - return 0; + int error; + struct vboxfs_node *unode; + + error = vboxfs_alloc_node(vboxfsmp->sf_vfsp, vboxfsmp, fullpath, type, + vboxfsmp->sf_uid, vboxfsmp->sf_gid, mode, parent, &unode); + + if (error) + goto out; + + error = vboxfs_alloc_vp(vboxfsmp->sf_vfsp, unode, lkflag, vpp); + if (error) + vboxfs_free_node(vboxfsmp, unode); + +out: + return (error); } -static int vboxvfs_create(struct vop_create_args *ap) +static int +vboxfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags, + struct vnode **rvp) { - return 0; + + return (vboxfs_alloc_vp(mp, arg, lkflags, rvp)); } -static int vboxvfs_remove(struct vop_remove_args *ap) +/* + * Construct a new pathname given an sfnode plus an optional tail + * component of length len + * This handles ".." and "." + */ +static char * +sfnode_construct_path(struct vboxfs_node *node, char *tail, int len) { - return 0; + char *p; ++ size_t dstsz; + + if (len <= 2 && tail[0] == '.' && (len == 1 || tail[1] == '.')) + panic("construct path for %s", tail); -+ p = malloc(strlen(node->sf_path) + 1 + len + 1, M_VBOXVFS, M_WAITOK); ++ dstsz = strlen(node->sf_path) + 1 + len + 1; ++ p = malloc(dstsz, M_VBOXVFS, M_WAITOK); + strcpy(p, node->sf_path); + strcat(p, "/"); -+ strcat(p, tail); ++ strlcat(p, tail, dstsz); + return (p); } -static int vboxvfs_rename(struct vop_rename_args *ap) +static int +vboxfs_access(struct vop_access_args *ap) { - return 0; + struct vnode *vp = ap->a_vp; + accmode_t accmode = ap->a_accmode; + struct vboxfs_node *node; + int error; + mode_t m; + + MPASS(VOP_ISLOCKED(vp)); + + node = VP_TO_VBOXFS_NODE(vp); + + if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + return (EROFS); + /* NOT REACHED */ + default: + break; + } + } + + if (vsfnode_stat_cached(node)) + error = 0; + else + error = vsfnode_update_stat_cache(node); + m = (error == 0) ? node->sf_stat.sf_mode : 0; + +#if __FreeBSD_version < 1300105 + return (vaccess(vp->v_type, m, node->vboxfsmp->sf_uid, + node->vboxfsmp->sf_gid, accmode, ap->a_cred, NULL)); +#else + return (vaccess(vp->v_type, m, node->vboxfsmp->sf_uid, + node->vboxfsmp->sf_gid, accmode, ap->a_cred)); +#endif } -static int vboxvfs_link(struct vop_link_args *ap) +/* + * Clears the (cached) directory listing for the node. + */ +static void +vfsnode_clear_dir_list(struct vboxfs_node *np) { - return EOPNOTSUPP; + while (np->sf_dir_list != NULL) { + sffs_dirents_t *next = np->sf_dir_list->sf_next; + free(np->sf_dir_list, M_VBOXVFS); + np->sf_dir_list = next; + } } -static int vboxvfs_symlink(struct vop_symlink_args *ap) +static int -+vboxfs_open(struct vop_open_args *ap) ++vboxfs_get_sfp_file(struct vboxfs_node *np) { - return EOPNOTSUPP; -+ struct vboxfs_node *np; + sfp_file_t *fp; + int error; + ++ fp = NULL; ++ VBOXFS_NODE_LOCK(np); ++ for (;;) { ++ if (np->sf_file != NULL) { ++ if (fp != NULL) ++ (void) sfprov_close(fp); ++ np->sf_opencnt++; ++ fp = np->sf_file; ++ break; ++ } else if (fp != NULL) { ++ np->sf_file = fp; ++ KASSERT(np->sf_opencnt == 0, ++ ("np %p opencnt (%d) must be zero.", ++ np, np->sf_opencnt)); ++ np->sf_opencnt = 1; ++ break; ++ } ++ VBOXFS_NODE_UNLOCK(np); ++ error = sfprov_open(np->vboxfsmp->sf_handle, np->sf_path, &fp); ++ if (error != 0) ++ return (error); ++ VBOXFS_NODE_LOCK(np); ++ } ++ VBOXFS_NODE_UNLOCK(np); ++ ++ return (0); + } + +-static int vboxvfs_mknod(struct vop_mknod_args *ap) ++static void ++vboxfs_put_sfp_file(struct vboxfs_node *np) + { +- return EOPNOTSUPP; ++ VBOXFS_NODE_LOCK(np); ++ np->sf_opencnt--; ++ if (np->sf_opencnt == 0) { ++ (void) sfprov_close(np->sf_file); ++ np->sf_file = NULL; ++ } ++ VBOXFS_NODE_UNLOCK(np); + } + +-static int vboxvfs_mkdir(struct vop_mkdir_args *ap) ++static int ++vboxfs_open(struct vop_open_args *ap) + { +- return 0; ++ struct vboxfs_node *np; ++ int error; ++ + MPASS(VOP_ISLOCKED(vp)); + + np = VP_TO_VBOXFS_NODE(ap->a_vp); -+ error = sfprov_open(np->vboxfsmp->sf_handle, np->sf_path, &fp); ++ error = vboxfs_get_sfp_file(np); + if (error != 0) + goto out; + -+ np->sf_file = fp; + vnode_create_vobject(ap->a_vp, 0, ap->a_td); -+ +out: + MPASS(VOP_ISLOCKED(vp)); + + return (error); } --static int vboxvfs_mknod(struct vop_mknod_args *ap) +-static int vboxvfs_rmdir(struct vop_rmdir_args *ap) +static void +vfsnode_invalidate_stat_cache(struct vboxfs_node *np) { -- return EOPNOTSUPP; +- return 0; + np->sf_stat_time = 0; } --static int vboxvfs_mkdir(struct vop_mkdir_args *ap) +-static int vboxvfs_readdir(struct vop_readdir_args *ap) +static int +vboxfs_close(struct vop_close_args *ap) { - return 0; + struct vnode *vp = ap->a_vp; + struct vboxfs_node *np; + + np = VP_TO_VBOXFS_NODE(vp); + + /* + * Free the directory entries for the node. We do this on this call + * here because the directory node may not become inactive for a long + * time after the readdir is over. Case in point, if somebody cd's into + * the directory then it won't become inactive until they cd away again. + * In such a case we would end up with the directory listing not getting + * updated (i.e. the result of 'ls' always being the same) until they + * change the working directory. + */ + vfsnode_clear_dir_list(np); + + vfsnode_invalidate_stat_cache(np); + -+ if (np->sf_file != NULL && vp->v_usecount <= 1) { -+ (void) sfprov_close(np->sf_file); -+ np->sf_file = NULL; -+ } ++ vboxfs_put_sfp_file(np); + + return (0); } --static int vboxvfs_rmdir(struct vop_rmdir_args *ap) +-static int vboxvfs_fsync(struct vop_fsync_args *ap) +static int +vboxfs_getattr(struct vop_getattr_args *ap) { - return 0; + struct vnode *vp = ap->a_vp; + struct vattr *vap = ap->a_vap; + struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); + struct vboxfs_mnt *mp = np->vboxfsmp; + mode_t mode; + int error = 0; + + mode = 0; + vap->va_type = vp->v_type; + + vap->va_nlink = 1; /* number of references to file */ + vap->va_uid = mp->sf_uid; /* owner user id */ + vap->va_gid = mp->sf_gid; /* owner group id */ + vap->va_rdev = NODEV; /* device the special file represents */ + vap->va_gen = VNOVAL; /* generation number of file */ + vap->va_flags = 0; /* flags defined for file */ + vap->va_filerev = 0; /* file modification number */ + vap->va_vaflags = 0; /* operations flags */ + vap->va_fileid = np->sf_ino; /* file id */ + vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; + if (vap->va_fileid == 0) + vap->va_fileid = 2; + + vap->va_atime.tv_sec = VNOVAL; + vap->va_atime.tv_nsec = VNOVAL; + vap->va_mtime.tv_sec = VNOVAL; + vap->va_mtime.tv_nsec = VNOVAL; + vap->va_ctime.tv_sec = VNOVAL; + vap->va_ctime.tv_nsec = VNOVAL; + + if (!vsfnode_stat_cached(np)) { + error = vsfnode_update_stat_cache(np); + if (error != 0) + goto done; + } + + vap->va_atime = np->sf_stat.sf_atime; + vap->va_mtime = np->sf_stat.sf_mtime; + vap->va_ctime = np->sf_stat.sf_ctime; + + mode = np->sf_stat.sf_mode; + + vap->va_mode = mode; + if (S_ISDIR(mode)) { + vap->va_type = VDIR; /* vnode type (for create) */ + vap->va_mode = mp->sf_dmode != 0 ? (mp->sf_dmode & 0777) : vap->va_mode; + vap->va_mode &= ~mp->sf_dmask; + vap->va_mode |= S_IFDIR; + } else if (S_ISREG(mode)) { + vap->va_type = VREG; + vap->va_mode = mp->sf_fmode != 0 ? (mp->sf_fmode & 0777) : vap->va_mode; + vap->va_mode &= ~mp->sf_fmask; + vap->va_mode |= S_IFREG; + } else if (S_ISFIFO(mode)) + vap->va_type = VFIFO; + else if (S_ISCHR(mode)) + vap->va_type = VCHR; + else if (S_ISBLK(mode)) + vap->va_type = VBLK; + else if (S_ISLNK(mode)) { + vap->va_type = VLNK; + vap->va_mode = mp->sf_fmode != 0 ? (mp->sf_fmode & 0777) : vap->va_mode; + vap->va_mode &= ~mp->sf_fmask; + vap->va_mode |= S_IFLNK; + } else if (S_ISSOCK(mode)) + vap->va_type = VSOCK; + + vap->va_size = np->sf_stat.sf_size; + vap->va_blocksize = 512; + /* bytes of disk space held by file */ + vap->va_bytes = (np->sf_stat.sf_alloc + 511) / 512; + +done: + return (error); } --static int vboxvfs_readdir(struct vop_readdir_args *ap) +-static int vboxvfs_print (struct vop_print_args *ap) +static int +vboxfs_setattr(struct vop_setattr_args *ap) { - return 0; + struct vnode *vp = ap->a_vp; + struct vattr *vap = ap->a_vap; + struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); + int error; + mode_t mode; + + mode = vap->va_mode; + if (vp->v_type == VREG) + mode |= S_IFREG; + else if (vp->v_type == VDIR) + mode |= S_IFDIR; + else if (vp->v_type == VBLK) + mode |= S_IFBLK; + else if (vp->v_type == VCHR) + mode |= S_IFCHR; + else if (vp->v_type == VLNK) + mode |= S_IFLNK; + else if (vp->v_type == VFIFO) + mode |= S_IFIFO; + else if (vp->v_type == VSOCK) + mode |= S_IFSOCK; + + vfsnode_invalidate_stat_cache(np); + + error = sfprov_set_attr(np->vboxfsmp->sf_handle, np->sf_path, + mode, vap->va_atime, vap->va_mtime, vap->va_ctime); +#if 0 + if (error == ENOENT) + sfnode_make_stale(np); +#endif + if (vap->va_size != (u_quad_t)VNOVAL) { + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VLNK: + /* FALLTHROUGH */ + case VREG: + error = sfprov_set_size(np->vboxfsmp->sf_handle, np->sf_path, vap->va_size); + break; + case VCHR: + /* FALLTHROUGH */ + case VBLK: + /* FALLTHROUGH */ + case VSOCK: + /* FALLTHROUGH */ + case VFIFO: + /* FALLTHROUGH */ + case VNON: + /* FALLTHROUGH */ + case VBAD: + /* FALLTHROUGH */ + case VMARKER: + return (0); + } + } + + return (error); } --static int vboxvfs_fsync(struct vop_fsync_args *ap) +-static int vboxvfs_pathconf (struct vop_pathconf_args *ap) +#define blkoff(vboxfsmp, loc) ((loc) & (vboxfsmp)->bmask) + +static int +vboxfs_read(struct vop_read_args *ap) { - return 0; + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); + int error = 0; + uint32_t bytes; + uint32_t done; + unsigned long offset; + ssize_t total; + void *tmpbuf; + + if (vp->v_type == VDIR) + return (EISDIR); + + if (vp->v_type != VREG) + return (EINVAL); + + if (uio->uio_offset < 0) + return (EINVAL); + + total = uio->uio_resid; + if (total == 0) + return (0); + + /* + * XXXGONZO: this is just to get things working + * should be optimized + */ + tmpbuf = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK, 0, ~0, PAGE_SIZE, 0); + if (tmpbuf == 0) + return (ENOMEM); + ++ /* ++ * XXX VOP_READ() is called without VOP_OPEN() on exec case. ++ * We need to ensure the file is opened here. ++ */ ++ error = vboxfs_get_sfp_file(np); ++ if (error != 0) /* Maybe removed on the host. */ ++ return (EIO); + do { + offset = uio->uio_offset; + done = bytes = min(PAGE_SIZE, uio->uio_resid); + error = sfprov_read(np->sf_file, tmpbuf, + offset, &done, 0); + if (error == 0 && done > 0) + error = uiomove(tmpbuf, done, uio); + } while (error == 0 && uio->uio_resid > 0 && done > 0); ++ vboxfs_put_sfp_file(np); + + contigfree(tmpbuf, PAGE_SIZE, M_DEVBUF); + + /* a partial read is never an error */ + if (total != uio->uio_resid) + error = 0; + + return (error); } --static int vboxvfs_print (struct vop_print_args *ap) +-static int vboxvfs_strategy (struct vop_strategy_args *ap) +static int +vboxfs_write(struct vop_write_args *ap) { - return 0; + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); + int error = 0; + uint32_t bytes; + uint32_t done; + unsigned long offset; + ssize_t total; + void *tmpbuf; + + if (vp->v_type == VDIR) + return (EISDIR); + + if (vp->v_type != VREG) + return (EINVAL); + + if (uio->uio_offset < 0) + return (EINVAL); + + total = uio->uio_resid; + if (total == 0) + return (0); + + /* + * XXXGONZO: this is just to get things working + * should be optimized + */ + tmpbuf = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK, 0, ~0, PAGE_SIZE, 0); + if (tmpbuf == 0) + return (ENOMEM); + + do { + offset = uio->uio_offset; + bytes = min(PAGE_SIZE, uio->uio_resid); + error = uiomove(tmpbuf, bytes, uio); + if (error != 0) + break; + done = bytes; + error = sfprov_write(np->sf_file, tmpbuf, + offset, &done, 0); + if (error != 0) + break; + total -= done; + if (done != bytes) + uio->uio_resid += bytes - done; + } while (error == 0 && uio->uio_resid > 0 && done > 0); + + contigfree(tmpbuf, PAGE_SIZE, M_DEVBUF); + + /* a partial write is never an error */ + if (total != uio->uio_resid) + error = 0; + + return (error); } --static int vboxvfs_pathconf (struct vop_pathconf_args *ap) +-static int vboxvfs_ioctl(struct vop_ioctl_args *ap) +static int +vboxfs_create(struct vop_create_args *ap) { -- return 0; +- return ENOTTY; + struct vnode *dvp = ap->a_dvp; + struct vnode **vpp = ap->a_vpp; + struct componentname *cnp = ap->a_cnp; + struct vattr *vap = ap->a_vap; + sffs_stat_t stat; + char *fullpath = NULL; + struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(dvp); -+ sfp_file_t *fp; + int error; + struct vboxfs_mnt *vboxfsmp = dir->vboxfsmp; + + MPASS(vap->va_type == VREG); + + fullpath = sfnode_construct_path(dir, cnp->cn_nameptr, cnp->cn_namelen); + error = sfprov_create(dir->vboxfsmp->sf_handle, fullpath, vap->va_mode, -+ &fp, &stat); ++ &stat); + + if (error) + goto out; + + error = vboxfs_alloc_file(vboxfsmp, fullpath, VREG, vap->va_mode, dir, cnp->cn_lkflags, vpp); + +out: + if (fullpath) + free(fullpath, M_VBOXVFS); + + if (error == 0) { + vfsnode_clear_dir_list(dir); + if ((cnp->cn_flags & MAKEENTRY) != 0) + cache_enter(dvp, *vpp, cnp); + } + + return (error); } --static int vboxvfs_strategy (struct vop_strategy_args *ap) +-static int vboxvfs_getextattr(struct vop_getextattr_args *ap) +static int +vboxfs_remove(struct vop_remove_args *ap) { - return 0; + struct vnode *dvp = ap->a_dvp; + struct vnode *vp = ap->a_vp; + struct vboxfs_node *np, *dir; + + int error; + + MPASS(VOP_ISLOCKED(dvp)); + MPASS(VOP_ISLOCKED(vp)); + + error = 0; + + np = VP_TO_VBOXFS_NODE(vp); + dir = VP_TO_VBOXFS_NODE(vp); + -+ /* -+ * If anything else is using this vnode, then fail the remove. -+ * Why? Windows hosts can't sfprov_remove() a file that is open, -+ * so we have to sfprov_close() it first. -+ * There is no errno for this - since it's not a problem on UNIX, -+ * but ETXTBSY is the closest. -+ */ -+ if (np->sf_file != NULL) { -+ if (vp->v_usecount > 1) { -+ error = ETXTBSY; -+ goto out; -+ } -+ sfprov_close(np->sf_file); -+ np->sf_file = NULL; -+ } -+ + error = sfprov_remove(np->vboxfsmp->sf_handle, np->sf_path, + np->sf_type == VLNK); + +#if 0 + if (error == ENOENT || error == 0) + sfnode_make_stale(np); +#endif + + if (error == 0) + vfsnode_clear_dir_list(dir); + +out: + return (error); } --static int vboxvfs_ioctl(struct vop_ioctl_args *ap) +-static int vboxvfs_advlock(struct vop_advlock_args *ap) +static int +vboxfs_rename(struct vop_rename_args *ap) { -- return ENOTTY; +- return 0; + struct vnode *fvp; + struct vnode *fdvp; + struct vnode *tvp; + struct vnode *tdvp; + struct componentname *fcnp; + struct componentname *tcnp; + struct vboxfs_node *np; + int ret; + + fvp = ap->a_fvp; + fdvp = ap->a_fdvp; + tvp = ap->a_tvp; + tdvp = ap->a_tdvp; + fcnp = ap->a_fcnp; + tcnp = ap->a_tcnp; + + /* Check for cross-device rename */ + if ((fvp->v_mount != tdvp->v_mount) || + (tvp && (fvp->v_mount != tvp->v_mount))) { + ret = EXDEV; + goto out; + } + np = VP_TO_VBOXFS_NODE(fvp); + if (np == NULL) + return (0); + ret = sfprov_rename(np->vboxfsmp->sf_handle, + fcnp->cn_nameptr, tcnp->cn_nameptr, fvp->v_type == VDIR); +out: + if (tdvp == tvp) + vrele(tdvp); + else + vput(tdvp); + if (tvp) + vput(tvp); + vrele(fdvp); + vrele(fvp); + return (ret); } --static int vboxvfs_getextattr(struct vop_getextattr_args *ap) +-static int vboxvfs_lookup(struct vop_lookup_args *ap) +static int +vboxfs_link(struct vop_link_args *ap) { - return 0; + return (EOPNOTSUPP); } --static int vboxvfs_advlock(struct vop_advlock_args *ap) +-static int vboxvfs_inactive(struct vop_inactive_args *ap) +static int +vboxfs_symlink(struct vop_symlink_args *ap) { - return 0; + struct vnode *dvp = ap->a_dvp; + struct vnode **vpp = ap->a_vpp; + struct componentname *cnp = ap->a_cnp; + struct vattr *vap = ap->a_vap; + sffs_stat_t stat; + char *fullpath = NULL; + struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(dvp); + int error; + struct vboxfs_mnt *vboxfsmp = dir->vboxfsmp; + + MPASS(vap->va_type == VLNK); + + fullpath = sfnode_construct_path(dir, cnp->cn_nameptr, cnp->cn_namelen); + error = sfprov_symlink(dir->vboxfsmp->sf_handle, fullpath, ap->a_target, &stat); + + if (error) + goto out; + + error = vboxfs_alloc_file(vboxfsmp, fullpath, VLNK, vap->va_mode, dir, cnp->cn_lkflags, vpp); + +out: + if (fullpath) + free(fullpath, M_VBOXVFS); + + if (error == 0) + vfsnode_clear_dir_list(dir); + + return (error); } --static int vboxvfs_lookup(struct vop_lookup_args *ap) +-static int vboxvfs_reclaim(struct vop_reclaim_args *ap) +static int +vboxfs_mkdir(struct vop_mkdir_args *ap) { - return 0; + struct vnode *dvp = ap->a_dvp; + struct vnode **vpp = ap->a_vpp; + struct componentname *cnp = ap->a_cnp; + struct vattr *vap = ap->a_vap; + sffs_stat_t stat; + char *fullpath = NULL; + struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(dvp); -+ sfp_file_t *fp; + int error; + struct vboxfs_mnt *vboxfsmp = dir->vboxfsmp; + + MPASS(vap->va_type == VDIR); + + fullpath = sfnode_construct_path(dir, cnp->cn_nameptr, cnp->cn_namelen); + error = sfprov_mkdir(dir->vboxfsmp->sf_handle, fullpath, vap->va_mode, -+ &fp, &stat); ++ &stat); + + if (error) + goto out; + + error = vboxfs_alloc_file(vboxfsmp, fullpath, VDIR, vap->va_mode, dir, cnp->cn_lkflags, vpp); + +out: + if (fullpath) + free(fullpath, M_VBOXVFS); + + if (error == 0) + vfsnode_clear_dir_list(dir); + + return (error); } --static int vboxvfs_inactive(struct vop_inactive_args *ap) +-static int vboxvfs_getpages(struct vop_getpages_args *ap) +static int +vboxfs_rmdir(struct vop_rmdir_args *ap) { - return 0; + struct vnode *dvp = ap->a_dvp; + struct vnode *vp = ap->a_vp; + struct vboxfs_node *np, *dir; + + int error; + + MPASS(VOP_ISLOCKED(dvp)); + MPASS(VOP_ISLOCKED(vp)); + + error = 0; + + np = VP_TO_VBOXFS_NODE(vp); + dir = VP_TO_VBOXFS_NODE(vp); + -+ /* -+ * If anything else is using this vnode, then fail the remove. -+ * Why? Windows hosts can't sfprov_remove() a file that is open, -+ * so we have to sfprov_close() it first. -+ * There is no errno for this - since it's not a problem on UNIX, -+ * but ETXTBSY is the closest. -+ */ -+ if (np->sf_file != NULL) { -+ if (vp->v_usecount > 1) { -+ error = ETXTBSY; -+ goto out; -+ } -+ sfprov_close(np->sf_file); -+ np->sf_file = NULL; -+ } -+ + error = sfprov_rmdir(np->vboxfsmp->sf_handle, np->sf_path); + +#if 0 + if (error == ENOENT || error == 0) + sfnode_make_stale(np); +#endif + + if (error == 0) + vfsnode_clear_dir_list(dir); + +out: + return (error); } --static int vboxvfs_reclaim(struct vop_reclaim_args *ap) +-static int vboxvfs_putpages(struct vop_putpages_args *ap) +static int +vboxfs_readdir(struct vop_readdir_args *ap) { - return 0; + int *eofp = ap->a_eofflag; + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(vp); + struct vboxfs_node *node = NULL; + struct sffs_dirent *dirent = NULL; + sffs_dirents_t *cur_buf; + off_t offset = 0; + off_t orig_off = uio->uio_offset; + int error = 0; + int dummy_eof; + + if (vp->v_type != VDIR) + return (ENOTDIR); + + if (eofp == NULL) + eofp = &dummy_eof; + *eofp = 0; + + /* + * Get the directory entry names from the host. This gets all + * entries. These are stored in a linked list of sffs_dirents_t + * buffers, each of which contains a list of dirent64_t's. + */ + if (dir->sf_dir_list == NULL) { + error = sfprov_readdir(dir->vboxfsmp->sf_handle, dir->sf_path, + &dir->sf_dir_list); + if (error != 0) + goto done; + } + + /* + * Validate and skip to the desired offset. + */ + cur_buf = dir->sf_dir_list; + offset = 0; + + while (cur_buf != NULL && offset + cur_buf->sf_len <= uio->uio_offset) { + offset += cur_buf->sf_len; + cur_buf = cur_buf->sf_next; + } + + if (cur_buf == NULL && offset != uio->uio_offset) { + error = EINVAL; + goto done; + } + + if (cur_buf != NULL && offset != uio->uio_offset) { + off_t off = offset; + int step; + dirent = &cur_buf->sf_entries[0]; + + while (off < uio->uio_offset) { + if (dirent->sf_off == uio->uio_offset) + break; + step = sizeof(struct sffs_dirent) + dirent->sf_entry.d_reclen; + dirent = (struct sffs_dirent *) (((char *) dirent) + step); + off += step; + } + + if (off >= uio->uio_offset) { + error = EINVAL; + goto done; + } + } + + offset = uio->uio_offset - offset; + + /* + * Lookup each of the names, so that we have ino's, and copy to + * result buffer. + */ + while (cur_buf != NULL) { + if (offset >= cur_buf->sf_len) { + cur_buf = cur_buf->sf_next; + offset = 0; + continue; + } + + dirent = (struct sffs_dirent *) + (((char *) &cur_buf->sf_entries[0]) + offset); + if (dirent->sf_entry.d_reclen > uio->uio_resid) + break; + + if (strcmp(dirent->sf_entry.d_name, ".") == 0) { + node = dir; + } else if (strcmp(dirent->sf_entry.d_name, "..") == 0) { + node = dir->sf_parent; + if (node == NULL) + node = dir; + } else { +#if 0 + node = vsfnode_lookup(dir, dirent->sf_entry.d_name, VNON, + 0, &dirent->sf_stat, vsfnode_cur_time_usec(), NULL); + if (node == NULL) + panic("sffs_readdir() lookup failed"); +#endif + } + + if (node) + dirent->sf_entry.d_fileno = node->sf_ino; + else + dirent->sf_entry.d_fileno = 0xdeadbeef; + + error = uiomove(&dirent->sf_entry, dirent->sf_entry.d_reclen, uio); + if (error != 0) + break; + + uio->uio_offset = dirent->sf_off; + offset += sizeof(struct sffs_dirent) + dirent->sf_entry.d_reclen; + } + + if (error == 0 && cur_buf == NULL) + *eofp = 1; +done: + if (error != 0) + uio->uio_offset = orig_off; + return (error); } --static int vboxvfs_getpages(struct vop_getpages_args *ap) +static int +vboxfs_readlink(struct vop_readlink_args *v) - { -- return 0; ++{ + struct vnode *vp = v->a_vp; + struct uio *uio = v->a_uio; + + int error; + struct vboxfs_node *np; + void *tmpbuf; + + MPASS(uio->uio_offset == 0); + MPASS(vp->v_type == VLNK); + + np = VP_TO_VBOXFS_NODE(vp); + + tmpbuf = contigmalloc(MAXPATHLEN, M_DEVBUF, M_WAITOK, 0, ~0, 1, 0); + if (tmpbuf == NULL) + return (ENOMEM); + + error = sfprov_readlink(np->vboxfsmp->sf_handle, np->sf_path, tmpbuf, + MAXPATHLEN); + if (error) + goto done; + + error = uiomove(tmpbuf, strlen(tmpbuf), uio); + +done: + if (tmpbuf) + contigfree(tmpbuf, MAXPATHLEN, M_DEVBUF); + return (error); - } - --static int vboxvfs_putpages(struct vop_putpages_args *ap) ++} ++ +static int +vboxfs_fsync(struct vop_fsync_args *ap) - { -- return 0; ++{ + struct vnode *vp; + struct vboxfs_node *np; + int ret; + + vp = ap->a_vp; + np = VP_TO_VBOXFS_NODE(vp); + if (np == NULL) + return (0); + ret = sfprov_fsync(np->sf_file); + return (ret); - } - ++} ++ +static int +vboxfs_print(struct vop_print_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct vboxfs_node *np; + + np = VP_TO_VBOXFS_NODE(vp); + + if (np == NULL) { + printf("No vboxfs_node data\n"); + return (0); + } + + printf("\tpath = %s, parent = %p", np->sf_path, + np->sf_parent ? np->sf_parent : NULL); + printf("\n"); + return (0); +} + +static int +vboxfs_pathconf(struct vop_pathconf_args *ap) +{ + register_t *retval = ap->a_retval; + int error = 0; + + switch (ap->a_name) { + case _PC_LINK_MAX: + *retval = 65535; + break; + case _PC_NAME_MAX: + *retval = NAME_MAX; + break; + case _PC_PATH_MAX: + *retval = PATH_MAX; + break; + default: + error = EINVAL; + break; + } + return (error); +} + +/* + * File specific ioctls. + */ +static int +vboxfs_ioctl(struct vop_ioctl_args *ap) +{ + return (ENOTTY); +} + +/* + * Lookup an entry in a directory and create a new vnode if found. + */ +static int -+vboxfs_lookup(struct vop_cachedlookup_args /* { -+ struct vnodeop_desc *a_desc; -+ struct vnode *a_dvp; -+ struct vnode **a_vpp; -+ struct componentname *a_cnp; -+ } */ *ap) ++vboxfs_lookup1(struct vnode *dvp, struct vnode **vpp, ++ struct componentname *cnp) +{ -+ struct componentname *cnp = ap->a_cnp; -+ struct vnode *dvp = ap->a_dvp; /* the directory vnode */ + char *nameptr = cnp->cn_nameptr; /* the name of the file or directory */ -+ struct vnode **vpp = ap->a_vpp; /* the vnode we found or NULL */ + struct vnode *tdp = NULL; + struct vboxfs_node *node = VP_TO_VBOXFS_NODE(dvp); + struct vboxfs_mnt *vboxfsmp = node->vboxfsmp; + u_long nameiop = cnp->cn_nameiop; + u_long flags = cnp->cn_flags; + sffs_stat_t stat; + //long namelen; + ino_t id = 0; + int ltype, type, error = 0; + int lkflags = cnp->cn_lkflags; + char *fullpath = NULL; + ++ *vpp = NULLVP; + error = ENOENT; + if (cnp->cn_flags & ISDOTDOT) { + error = vn_vget_ino_gen(dvp, vboxfs_vn_get_ino_alloc, + node->sf_parent, cnp->cn_lkflags, vpp); + error = ENOENT; + if (error != 0) + goto out; + + } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { + VREF(dvp); + *vpp = dvp; + error = 0; + } else { + mode_t m; + type = VNON; + fullpath = sfnode_construct_path(node, cnp->cn_nameptr, cnp->cn_namelen); + error = sfprov_get_attr(node->vboxfsmp->sf_handle, + fullpath, &stat); + // stat_time = vsfnode_cur_time_usec(); + + m = stat.sf_mode; + if (error != 0) { + /* The entry was not found in the directory. + * This is OK if we are creating or renaming an + * entry and are working on the last component of + * the path name. */ + if ((cnp->cn_flags & ISLASTCN) && + (cnp->cn_nameiop == CREATE || \ + cnp->cn_nameiop == RENAME || + (cnp->cn_nameiop == DELETE && + cnp->cn_flags & DOWHITEOUT && + cnp->cn_flags & ISWHITEOUT))) { + error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, +#if __FreeBSD_version < 1400037 + cnp->cn_thread); +#else + curthread); +#endif + if (error != 0) + goto out; + +#if __FreeBSD_version < 1400068 + /* Keep the component name in the buffer for + * future uses. */ + cnp->cn_flags |= SAVENAME; +#endif + + error = EJUSTRETURN; + } else + error = ENOENT; + } + else { + if (S_ISDIR(m)) + type = VDIR; + else if (S_ISREG(m)) + type = VREG; + else if (S_ISLNK(m)) + type = VLNK; + error = vboxfs_alloc_file(vboxfsmp, fullpath, type, 0755, node, cnp->cn_lkflags, vpp); + } + } + + if ((cnp->cn_flags & MAKEENTRY) != 0) + cache_enter(dvp, *vpp, cnp); +out: + if (fullpath) + free(fullpath, M_VBOXVFS); + + return (error); +} + +static int ++vboxfs_cachedlookup(struct vop_cachedlookup_args *ap) ++{ ++ return (vboxfs_lookup1(ap->a_dvp, ap->a_vpp, ap->a_cnp)); ++} ++ ++static int ++vboxfs_lookup(struct vop_lookup_args *ap) ++{ ++ struct vnode *dvp = ap->a_dvp; ++ struct componentname *cnp = ap->a_cnp; ++ struct vboxfs_node *np = VP_TO_VBOXFS_NODE(dvp); ++ struct timespec mtime; ++ int flags = cnp->cn_flags; ++ int error; ++ ++ if (dvp->v_type != VDIR) ++ return (ENOTDIR); ++ ++ if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && ++ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) ++ return (EROFS); ++ ++ error = vn_dir_check_exec(dvp, cnp); ++ if (error != 0) ++ return (error); ++ ++ /* Check if the directory is unmodified on the host. */ ++ mtime = np->sf_stat.sf_mtime; ++ error = vsfnode_update_stat_cache(np); ++ if (error == 0) { ++ if (mtime.tv_sec == np->sf_stat.sf_mtime.tv_sec && ++ mtime.tv_nsec == np->sf_stat.sf_mtime.tv_nsec) ++ return (vfs_cache_lookup(ap)); ++ } ++ ++ cache_purge(dvp); ++ ++ return (vboxfs_lookup1(ap->a_dvp, ap->a_vpp, ap->a_cnp)); ++} ++ ++static int +vboxfs_inactive(struct vop_inactive_args *ap) +{ + return (0); +} + +static int +vboxfs_reclaim(struct vop_reclaim_args *ap) +{ + struct vnode *vp; + struct vboxfs_node *node; + struct vboxfs_mnt *vboxfsmp; + + vp = ap->a_vp; + node = VP_TO_VBOXFS_NODE(vp); + vboxfsmp = node->vboxfsmp; + + vnode_destroy_vobject(vp); + vp->v_object = NULL; + cache_purge(vp); + + VBOXFS_NODE_LOCK(node); + VBOXFS_ASSERT_ELOCKED(node); + vboxfs_free_vp(vp); + + /* If the node referenced by this vnode was deleted by the user, + * we must free its associated data structures (now that the vnode + * is being reclaimed). */ + if ((node->sf_vpstate & VBOXFS_VNODE_ALLOCATING) == 0) { + node->sf_vpstate = VBOXFS_VNODE_DOOMED; + VBOXFS_NODE_UNLOCK(node); + vboxfs_free_node(vboxfsmp, node); + } else + VBOXFS_NODE_UNLOCK(node); + + MPASS(vp->v_data == NULL); + + return (0); +} + +static int +vboxfs_vptofh(struct vop_vptofh_args *ap) +{ + + return (EOPNOTSUPP); +}