vboxvfs_vfsops.c revision 2f179a5059fedec182eb061e984f821a8887a1f0
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync/* $Id$ */
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync/** @file
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync * VirtualBox File System Driver for Solaris Guests. VFS operations.
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync */
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync/*
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Sun Microsystems, Inc. confidential
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * All rights reserved
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/types.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/mntent.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/param.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/modctl.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/mount.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/policy.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/ddi.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <sys/sunddi.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include "vboxvfs.h"
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync# define LOG_ENABLED
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync# define LOG_TO_BACKDOOR
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#endif
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#include <VBox/log.h>
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#include <iprt/string.h>
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#include <iprt/mem.h>
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#include <iprt/err.h>
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync/*******************************************************************************
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync* Defined Constants And Macros *
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync*******************************************************************************/
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync/** Mount Options */
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#define MNTOPT_VBOXVFS_UID "uid"
4d939f327b6fe2b8201ab00e2d7e7d12b6d47d23vboxsync#define MNTOPT_VBOXVFS_GID "gid"
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int VBoxVFS_Init(int fType, char *pszName);
static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred);
static int VBoxVFS_Unmount(vfs_t *pVFS, int fFlags, cred_t *pCred);
static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode);
static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat);
static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid);
static void VBoxVFS_FreeVFS(vfs_t *pVFS);
static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred);
static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue);
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* mntopts_t: mount options table array
*/
static mntopt_t g_VBoxVFSMountOptions[] =
{
/* Option Name Cancel Opt. Default Arg Flags Data */
{ MNTOPT_VBOXVFS_UID, NULL, NULL, MO_HASVALUE, NULL },
{ MNTOPT_VBOXVFS_GID, NULL, NULL, MO_HASVALUE, NULL }
};
/**
* mntopts_t: mount options table prototype
*/
static mntopts_t g_VBoxVFSMountTableProt =
{
sizeof(g_VBoxVFSMountOptions) / sizeof(mntopt_t),
g_VBoxVFSMountOptions
};
/**
* vfsdef_t: driver specific mount options
*/
static vfsdef_t g_VBoxVFSDef =
{
VFSDEF_VERSION,
DEVICE_NAME,
VBoxVFS_Init,
VSW_HASPROTO,
&g_VBoxVFSMountTableProt
};
/**
* modlfs: loadable file system
*/
static struct modlfs g_VBoxVFSLoadMod =
{
&mod_fsops, /* extern from kernel */
DEVICE_DESC,
&g_VBoxVFSDef
};
/**
* modlinkage: export install/remove/info to the kernel
*/
static struct modlinkage g_VBoxVFSModLinkage =
{
MODREV_1, /* loadable module system revision */
&g_VBoxVFSLoadMod,
NULL /* terminate array of linkage structures */
};
/**
* state info. for vboxvfs
*/
typedef struct
{
/** Device Info handle. */
dev_info_t *pDip;
/** Driver Mutex. */
kmutex_t Mtx;
} vboxvfs_state_t;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Opaque pointer to list of states. */
static void *g_pVBoxVFSState;
/** GCC C++ hack. */
unsigned __gxx_personality_v0 = 0xdecea5ed;
/** Global connection to the client. */
VBSFCLIENT g_VBoxVFSClient;
/** Global VFS Operations pointer. */
vfsops_t *g_pVBoxVFS_vfsops;
/** The file system type identifier. */
static int g_VBoxVFSType;
/**
* Kernel entry points
*/
int _init(void)
{
LogFlow((DEVICE_NAME ":_init\n"));
int rc = ddi_soft_state_init(&g_pVBoxVFSState, sizeof(vboxvfs_state_t), 1);
if (!rc)
{
rc = mod_install(&g_VBoxVFSModLinkage);
if (rc)
ddi_soft_state_fini(&g_pVBoxVFSState);
}
return rc;
}
int _fini(void)
{
LogFlow((DEVICE_NAME ":_fini\n"));
int rc = mod_remove(&g_VBoxVFSModLinkage);
if (!rc)
ddi_soft_state_fini(&g_pVBoxVFSState);
return rc;
}
int _info(struct modinfo *pModInfo)
{
LogFlow((DEVICE_NAME ":_info\n"));
return mod_info(&g_VBoxVFSModLinkage, pModInfo);
}
static int VBoxVFS_Init(int fType, char *pszName)
{
int rc;
LogFlow((DEVICE_NAME ":VBoxVFS_Init\n"));
/* Initialize the R0 guest library. */
rc = vboxInit();
if (VBOX_SUCCESS(rc))
{
/* Connect to the host service. */
rc = vboxConnect(&g_VBoxVFSClient);
if (VBOX_SUCCESS(rc))
{
/* Use UTF-8 encoding. */
rc = vboxCallSetUtf8 (&g_VBoxVFSClient);
if (VBOX_SUCCESS(rc))
{
/* Fill up VFS user entry points. */
static const fs_operation_def_t s_VBoxVFS_vfsops_template[] =
{
VFSNAME_MOUNT, { .vfs_mount = VBoxVFS_Mount },
VFSNAME_UNMOUNT, { .vfs_unmount = VBoxVFS_Unmount },
VFSNAME_ROOT, { .vfs_root = VBoxVFS_Root },
VFSNAME_STATVFS, { .vfs_statvfs = VBoxVFS_Statfs },
VFSNAME_VGET, { .vfs_vget = VBoxVFS_VGet },
VFSNAME_FREEVFS, { .vfs_freevfs = VBoxVFS_FreeVFS },
NULL, NULL
};
rc = vfs_setfsops(fType, s_VBoxVFS_vfsops_template, &g_pVBoxVFS_vfsops);
if (!rc)
{
/* Set VNode operations. */
rc = vn_make_ops(pszName, g_VBoxVFS_vnodeops_template, &g_pVBoxVFS_vnodeops);
if (!rc)
{
g_VBoxVFSType = fType;
LogFlow((DEVICE_NAME ":Successfully loaded vboxvfs.\n"));
return 0;
}
else
LogRel((DEVICE_NAME ":vn_make_ops failed. rc=%d\n", rc));
}
else
LogRel((DEVICE_NAME ":vfs_setfsops failed. rc=%d\n", rc));
}
else
{
LogRel((DEVICE_NAME ":vboxCallSetUtf8 failed. rc=%d\n", rc));
rc = EPROTO;
}
vboxDisconnect(&g_VBoxVFSClient);
}
else
{
LogRel((DEVICE_NAME ":Failed to connect to host! rc=%d\n", rc));
rc = ENXIO;
}
vboxUninit();
}
else
{
LogRel((DEVICE_NAME ":Failed to initialize R0 lib. rc=%d\n", rc));
rc = ENXIO;
}
return rc;
}
static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred)
{
int rc = 0;
int Uid = 0;
int Gid = 0;
char *pszShare = NULL;
size_t cbShare = NULL;
pathname_t PathName;
vboxvfs_vnode_t *pVNodeRoot = NULL;
vnode_t *pVNodeSpec = NULL;
vnode_t *pVNodeDev = NULL;
dev_t Dev = 0;
SHFLSTRING *pShflShareName = NULL;
RTFSOBJINFO FSInfo;
size_t cbShflShareName = 0;
vboxvfs_globinfo_t *pVBoxVFSGlobalInfo = NULL;
int AddrSpace = (pMount->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE;
#if 0
caddr_t pData;
size_t cbData;
vboxvfs_mountinfo_t Args;
#endif
LogFlow((DEVICE_NAME ":VBoxVFS_Mount\n"));
/* Check user credentials for mounting in the specified target. */
rc = secpolicy_fs_mount(pCred, pVNode, pVFS);
if (rc)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: secpolicy_fs_mount failed! invalid credentials.rc=%d\n", rc));
return EPERM;
}
/* We can mount to only directories. */
if (pVNode->v_type != VDIR)
return ENOTDIR;
/* We don't support remounting. */
if (pMount->flags & MS_REMOUNT)
return ENOTSUP;
mutex_enter(&pVNode->v_lock);
if ( !(pMount->flags & MS_REMOUNT)
&& !(pMount->flags & MS_OVERLAY)
&& (pVNode->v_count != -1 || (pVNode->v_flag & VROOT)))
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: device busy.\n"));
mutex_exit(&pVNode->v_lock);
return EBUSY;
}
mutex_exit(&pVNode->v_lock);
/* From what I understood the options are already parsed at a higher level */
if ( (pMount->flags & MS_DATA)
&& pMount->datalen > 0)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: unparsed options not supported.\n"));
return EINVAL;
}
/* Will be removed eventually... */
#if 0
/* Retreive arguments. */
bzero(&Args, sizeof(Args));
cbData = pMount->datalen;
pData = pMount->data;
if ( (pMount->flags & MS_DATA)
&& pData != NULL
&& cbData > 0)
{
if (cbData > sizeof(Args))
{
LogRel((DEVICE_NAME: "VBoxVFS_Mount: argument length too long. expected=%d. received=%d\n", sizeof(Args), cbData));
return EINVAL;
}
/* Copy arguments; they can be in kernel or user space. */
rc = ddi_copyin(pData, &Args, cbData, (pMount->flags & MS_SYSSPACE) ? FKIOCTL : 0);
if (rc)
{
LogRel((DEVICE_NAME: "VBoxVFS_Mount: ddi_copyin failed to copy arguments.rc=%d\n", rc));
return EFAULT;
}
}
else
{
cbData = 0;
pData = NULL;
}
#endif
/* Get UID argument (optional). */
rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_UID, &Uid);
if (rc < 0)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid uid value.\n"));
return EINVAL;
}
/* Get GID argument (optional). */
rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_GID, &Gid);
if (rc < 0)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid gid value.\n"));
return EINVAL;
}
/* Get special (sharename). */
rc = pn_get(pMount->spec, AddrSpace, &PathName);
if (!rc)
{
/* Get the vnode for the special file for storing the device identifier and path. */
rc = lookupname(PathName.pn_path, AddrSpace, FOLLOW, NULLVPP, &pVNodeSpec);
if (!rc)
{
/* Check if user has permission to use the special file for mounting. */
rc = vboxvfs_CheckMountPerm(pVFS, pMount, pVNodeSpec, pCred);
VN_RELE(pVNodeSpec);
if (!rc)
{
Dev = pVNodeSpec->v_rdev;
memcpy(pszShare, PathName.pn_path, strlen(PathName.pn_path));
cbShare = strlen(pszShare);
}
else
LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid permissions to mount %s.rc=%d\n", pszShare, rc));
rc = EPERM;
}
else
LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to lookup sharename.rc=%d\n", rc));
rc = EINVAL;
}
else
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to get special file path.rc=%d\n", rc));
rc = EINVAL;
}
pn_free(&PathName);
if (!rc)
return rc;
/* Get VNode of the special file being mounted. */
pVNodeDev = makespecvp(Dev, VBLK);
if (!IS_SWAPVP(pVNodeDev))
{
/* Open the vnode for mounting. */
rc = VOP_OPEN(&pVNodeDev, (pVFS->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, pCred, NULL);
if (rc)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to mount.\n"));
rc = EINVAL;
}
}
else
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: cannot mount from swap.\n"));
rc = EINVAL;
}
if (!rc)
{
VN_RELE(pVNodeDev);
return rc;
}
/* Allocate the global info. structure. */
pVBoxVFSGlobalInfo = RTMemAlloc(sizeof(*pVBoxVFSGlobalInfo));
if (!pVBoxVFSGlobalInfo)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAlloc failed to alloc %d bytes for global struct.\n", sizeof(*pVBoxVFSGlobalInfo)));
return ENOMEM;
}
cbShflShareName = offsetof(SHFLSTRING, String.utf8) + cbShare + 1;
pShflShareName = RTMemAllocZ(cbShflShareName);
if (!pShflShareName)
{
RTMemFree(pVBoxVFSGlobalInfo);
LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAllocZ failed to alloc %d bytes for ShFlShareName.\n", cbShflShareName));
return ENOMEM;
}
pShflShareName->u16Length = cbShflShareName;
pShflShareName->u16Size = cbShflShareName + 1;
memcpy (pShflShareName->String.utf8, pszShare, cbShare + 1);
rc = vboxCallMapFolder(&g_VBoxVFSClient, pShflShareName, &pVBoxVFSGlobalInfo->Map);
RTMemFree(pShflShareName);
if (VBOX_FAILURE (rc))
{
RTMemFree(pVBoxVFSGlobalInfo);
LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxCallMapFolder failed rc=%d\n", rc));
return EPROTO;
}
/* @todo mutex for protecting the structure. */
pVBoxVFSGlobalInfo->Uid = Uid;
pVBoxVFSGlobalInfo->Gid = Gid;
pVBoxVFSGlobalInfo->pVFS = pVFS;
pVBoxVFSGlobalInfo->pVNodeDev = pVNodeDev;
pVFS->vfs_data = pVBoxVFSGlobalInfo;
pVFS->vfs_fstype = g_VBoxVFSType;
pVFS->vfs_dev = Dev;
vfs_make_fsid(&pVFS->vfs_fsid, Dev, g_VBoxVFSType);
/* Allocate root vboxvfs_vnode_t object */
pVNodeRoot = RTMemAlloc(sizeof(*pVNodeRoot));
if (!pVNodeRoot)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAlloc failed to alloc %d bytes for root node.\n", sizeof(*pVNodeRoot)));
return ENOMEM;
}
/* Initialize the mutex */
mutex_init(&pVNodeRoot->MtxContents, "VNodeMtx", MUTEX_DEFAULT, NULL);
/* Allocate root path */
pVNodeRoot->pPath = RTMemAllocZ(sizeof(SHFLSTRING) + 1);
if (!pVNodeRoot->pPath)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAllocZ failed to alloc %d bytes for root path.\n", sizeof(SHFLSTRING) + 1));
return ENOMEM;
}
/* Initialize root path */
pVNodeRoot->pPath->u16Length = 1;
pVNodeRoot->pPath->u16Size = 2;
pVNodeRoot->pPath->String.utf8[0] = '/';
pVNodeRoot->pPath->String.utf8[1] = '\0';
/* Stat root node info from host */
rc = vboxvfs_Stat(__func__, pVBoxVFSGlobalInfo, pVNodeRoot->pPath, &FSInfo, B_FALSE);
if (rc)
{
LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxvfs_Stat failed rc(errno)=%d\n", rc));
return rc;
}
/* Initialize the root vboxvfs_node_t object */
vboxvfs_InitVNode(pVBoxVFSGlobalInfo, pVNodeRoot, &FSInfo);
return 0;
}
static int VBoxVFS_Unmount(vfs_t *pVFS, int fUnmount, cred_t *pCred)
{
int rc;
vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
LogFlow((DEVICE_NAME ":VBoxVFS_Unmount.\n"));
/* Check if user can unmount. */
rc = secpolicy_fs_unmount(pCred, pVFS);
if (rc)
{
LogRel((DEVICE_NAME ":VBoxVFS_Unmount: insufficient privileges to unmount.rc=%d\n", rc));
return EPERM;
}
if (fUnmount & MS_FORCE)
pVFS->vfs_flag |= VFS_UNMOUNTED;
/* @todo implement ref-counting of active vnodes & check for busy state here. */
/* @todo mutex protection needed here */
pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
rc = vboxCallUnmapFolder(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map);
if (VBOX_FAILURE(rc))
LogRel((DEVICE_NAME ":VBoxVFS_Unmount: failed to unmap shared folder. rc=%d\n", rc));
VN_RELE(VBOXVN_TO_VN(pVBoxVFSGlobalInfo->pVNodeRoot));
RTMemFree(pVBoxVFSGlobalInfo);
pVFS->vfs_data = NULL;
return 0;
}
static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode)
{
vboxvfs_globinfo_t *pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
*ppVNode = VBOXVN_TO_VN(pVBoxVFSGlobalInfo->pVNodeRoot);
VN_HOLD(*ppVNode);
return 0;
}
static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat)
{
SHFLVOLINFO VolumeInfo;
uint32_t cbBuffer;
vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
dev32_t Dev32;
int rc;
pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
cbBuffer = sizeof(VolumeInfo);
rc = vboxCallFSInfo(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbBuffer,
(PSHFLDIRINFO)&VolumeInfo);
if (VBOX_FAILURE(rc))
return RTErrConvertToErrno(rc);
bzero(pStat, sizeof(*pStat));
cmpldev(&Dev32, pVFS->vfs_dev);
pStat->f_fsid = Dev32;
pStat->f_flag = vf_to_stf(pVFS->vfs_flag);
pStat->f_bsize = VolumeInfo.ulBytesPerAllocationUnit;
pStat->f_frsize = VolumeInfo.ulBytesPerAllocationUnit;
pStat->f_bfree = VolumeInfo.ullAvailableAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
pStat->f_bavail = VolumeInfo.ullAvailableAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
pStat->f_blocks = VolumeInfo.ullTotalAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
pStat->f_files = 1000;
pStat->f_ffree = 1000; /* don't return 0 here since the guest may think that it is not possible to create any more files */
pStat->f_namemax = 255; /* @todo is this correct?? */
strlcpy(pStat->f_basetype, vfssw[pVFS->vfs_fstype].vsw_name, sizeof(pStat->f_basetype));
strlcpy(pStat->f_fstr, DEVICE_NAME, sizeof(pStat->f_fstr));
return 0;
}
static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid)
{
/* -- TODO -- */
return 0;
}
static void VBoxVFS_FreeVFS(vfs_t *pVFS)
{
vboxDisconnect(&g_VBoxVFSClient);
vboxUninit();
}
static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred)
{
/* Check if user has the rights to mount the special file. */
int fOpen = FREAD | FWRITE;
int fAccess = VREAD | VWRITE;
int rc;
if (pVNodeSpec->v_type != VBLK)
return ENOTBLK;
if ( (pVFS->vfs_flag & VFS_RDONLY)
|| (pMount->flags & MS_RDONLY))
{
fOpen = FREAD;
fAccess = VREAD;
}
rc = VOP_ACCESS(pVNodeSpec, fAccess, 0, pCred, NULL /* caller_context */);
if (!rc)
rc = secpolicy_spec_open(pCred, pVNodeSpec, fOpen);
return rc;
}
static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue)
{
int rc;
long Val;
char *pchOpt = NULL;
char *pchEnd = NULL;
rc = vfs_optionisset(pVFS, pszOpt, &pchOpt);
if (rc)
{
rc = ddi_strtol(pchOpt, &pchEnd, 10 /* base */, &Val);
if ( !rc
&& Val > INT_MIN
&& Val < INT_MAX
&& pchEnd == pchOpt + strlen(pchOpt))
{
*pValue = (int)Val;
return 0;
}
return -1;
}
return 1;
}