VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/SharedFolders/vboxvfs_vfsops.c@ 9592

Last change on this file since 9592 was 9175, checked in by vboxsync, 17 years ago

re-export SharedFolders and vbi (installer).

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Id
File size: 15.8 KB
Line 
1/* $Id: vboxvfs_vfsops.c 9175 2008-05-27 15:19:34Z vboxsync $ */
2/** @file
3 * VirtualBox File System Driver for Solaris Guests.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * Sun Microsystems, Inc. confidential
10 * All rights reserved
11 */
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#include <sys/types.h>
18#include <sys/mntent.h>
19#include <sys/param.h>
20#include <sys/modctl.h>
21#include <sys/mount.h>
22#include <sys/policy.h>
23#include <sys/ddi.h>
24#include <sys/sunddi.h>
25#include "vboxvfs.h"
26
27#include <VBox/log.h>
28#include <iprt/string.h>
29#include <iprt/mem.h>
30
31
32/*******************************************************************************
33* Defined Constants And Macros *
34*******************************************************************************/
35/** The module name. */
36#define DEVICE_NAME "vboxvfs"
37/** The module description as seen in 'modinfo'. */
38#define DEVICE_DESC "VirtualBox Shared Filesystem"
39
40/** Mount Options */
41#define MNTOPT_VBOXVFS_UID "uid"
42#define MNTOPT_VBOXVFS_GID "gid"
43
44/** Helpers */
45#define VFS2VBOXVFS(vfs) ((vboxvfs_globinfo_t *)((vfs)->vfs_data))
46#define VBOXVFS2VFS(vboxvfs) ((vboxvfs)->pVFS)
47
48
49/*******************************************************************************
50* Internal Functions *
51*******************************************************************************/
52static int VBoxVFS_Init(int fType, char *pszName);
53static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred);
54static int VBoxVFS_Unmount(vfs_t *pVFS, int fFlags, cred_t *pCred);
55static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode);
56static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat);
57static int VBoxVFS_Sync(vfs_t *pVFS, short fFlags, cred_t *pCred);
58static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid);
59static void VBoxVFS_FreeVFS(vfs_t *pVFS);
60
61static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred);
62static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue);
63
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68/**
69 * mntopts_t: mount options table array
70 */
71static mntopt_t g_VBoxVFSMountOptions[] =
72{
73 /* Option Name Cancel Opt. Default Arg Flags Data */
74 { MNTOPT_VBOXVFS_UID, NULL, NULL, MO_HASVALUE, NULL },
75 { MNTOPT_VBOXVFS_GID, NULL, NULL, MO_HASVALUE, NULL }
76};
77
78/**
79 * mntopts_t: mount options table prototype
80 */
81static mntopts_t g_VBoxVFSMountTableProt =
82{
83 sizeof(g_VBoxVFSMountOptions) / sizeof(mntopt_t),
84 g_VBoxVFSMountOptions
85};
86
87/**
88 * vfsdef_t: driver specific mount options
89 */
90static vfsdef_t g_VBoxVFSDef =
91{
92 VFSDEF_VERSION,
93 DEVICE_NAME,
94 VBoxVFS_Init,
95 VSW_HASPROTO,
96 &g_VBoxVFSMountTableProt
97};
98
99/**
100 * modlfs: loadable file system
101 */
102static struct modlfs g_VBoxVFSLoadMod =
103{
104 &mod_fsops, /* extern from kernel */
105 DEVICE_DESC,
106 &g_VBoxVFSDef
107};
108
109/**
110 * modlinkage: export install/remove/info to the kernel
111 */
112static struct modlinkage g_VBoxVFSModLinkage =
113{
114 MODREV_1, /* loadable module system revision */
115 &g_VBoxVFSLoadMod,
116 NULL /* terminate array of linkage structures */
117};
118
119/**
120 * state info. for vboxvfs
121 */
122typedef struct
123{
124 /** Device Info handle. */
125 dev_info_t *pDip;
126 /** Driver Mutex. */
127 kmutex_t Mtx;
128} vboxvfs_state_t;
129
130
131/*******************************************************************************
132* Global Variables *
133*******************************************************************************/
134/** Opaque pointer to list of states. */
135static void *g_pVBoxVFSState;
136/** GCC C++ hack. */
137unsigned __gxx_personality_v0 = 0xdecea5ed;
138/** Global connection to the client. */
139static VBSFCLIENT g_VBoxVFSClient;
140/** Global VFS Operations pointer. */
141vfsops_t *g_pVBoxVFS_vfsops;
142/** The file system type identifier. */
143static int g_VBoxVFSType;
144
145
146/**
147 * Kernel entry points
148 */
149int _init(void)
150{
151 LogFlow((DEVICE_NAME ":_init\n"));
152 int rc = ddi_soft_state_init(&g_pVBoxVFSState, sizeof(vboxvfs_state_t), 1);
153 if (!rc)
154 {
155 rc = mod_install(&g_VBoxVFSModLinkage);
156 if (rc)
157 ddi_soft_state_fini(&g_pVBoxVFSState);
158 }
159 return rc;
160}
161
162
163int _fini(void)
164{
165 LogFlow((DEVICE_NAME ":_fini\n"));
166 int rc = mod_remove(&g_VBoxVFSModLinkage);
167 if (!rc)
168 ddi_soft_state_fini(&g_pVBoxVFSState);
169 return rc;
170}
171
172
173int _info(struct modinfo *pModInfo)
174{
175 LogFlow((DEVICE_NAME ":_info\n"));
176 return mod_info(&g_VBoxVFSModLinkage, pModInfo);
177}
178
179
180static int VBoxVFS_Init(int fType, char *pszName)
181{
182 int rc;
183
184 LogFlow((DEVICE_NAME ":VBoxVFS_Init\n"));
185
186 /* Initialize the R0 guest library. */
187 rc = vboxInit();
188 if (VBOX_SUCCESS(rc))
189 {
190 /* Connect to the host service. */
191 rc = vboxConnect(&g_VBoxVFSClient);
192 if (VBOX_SUCCESS(rc))
193 {
194 /* Use UTF-8 encoding. */
195 rc = vboxCallSetUtf8 (&g_VBoxVFSClient);
196 if (VBOX_SUCCESS(rc))
197 {
198 /* Fill up VFS user entry points. */
199 static const fs_operation_def_t s_VBoxVFS_vfsops_template[] =
200 {
201 VFSNAME_MOUNT, { .vfs_mount = VBoxVFS_Mount },
202 VFSNAME_UNMOUNT, { .vfs_unmount = VBoxVFS_Unmount },
203 VFSNAME_ROOT, { .vfs_root = VBoxVFS_Root },
204 VFSNAME_STATVFS, { .vfs_statvfs = VBoxVFS_Statfs },
205 VFSNAME_SYNC, { .vfs_sync = VBoxVFS_Sync },
206 VFSNAME_VGET, { .vfs_vget = VBoxVFS_VGet },
207 VFSNAME_FREEVFS, { .vfs_freevfs = VBoxVFS_FreeVFS },
208 NULL, NULL
209 };
210
211 rc = vfs_setfsops(fType, s_VBoxVFS_vfsops_template, &g_pVBoxVFS_vfsops);
212 if (!rc)
213 {
214 /* Set VNode operations. */
215 rc = vn_make_ops(pszName, g_VBoxVFS_vnodeops_template, &g_pVBoxVFS_vnodeops);
216 if (!rc)
217 {
218 g_VBoxVFSType = fType;
219 LogFlow((DEVICE_NAME ":Successfully loaded vboxvfs.\n"));
220 return 0;
221 }
222 }
223 else
224 LogRel((DEVICE_NAME ":vfs_setfsops failed. rc=%d\n", rc));
225 }
226 else
227 {
228 LogRel((DEVICE_NAME ":vboxCallSetUtf8 failed. rc=%d\n", rc));
229 rc = EPROTO;
230 }
231 vboxDisconnect(&g_VBoxVFSClient);
232 }
233 else
234 {
235 LogRel((DEVICE_NAME ":Failed to connect to host! rc=%d\n", rc));
236 rc = ENXIO;
237 }
238 vboxUninit();
239 }
240 else
241 {
242 LogRel((DEVICE_NAME ":Failed to initialize R0 lib. rc=%d\n", rc));
243 rc = ENXIO;
244 }
245 return rc;
246}
247
248static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred)
249{
250 int rc;
251 int Uid = 0;
252 int Gid = 0;
253 char *pszShare;
254 size_t cbShare;
255 pathname_t PathName;
256 vnode_t *pVNodeSpec;
257 vnode_t *pVNodeDev;
258 dev_t Dev;
259 SHFLSTRING *pShflShareName = NULL;
260 size_t cbShflShareName;
261 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
262 int AddrSpace = (pMount->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE;
263#if 0
264 caddr_t pData;
265 size_t cbData;
266 vboxvfs_mountinfo_t Args;
267#endif
268
269 LogFlow((DEVICE_NAME ":VBoxVFS_Mount\n"));
270
271 /* Check user credentials for mounting in the specified target. */
272 rc = secpolicy_fs_mount(pCred, pVNode, pVFS);
273 if (rc)
274 {
275 LogRel((DEVICE_NAME ":VBoxVFS_Mount: secpolicy_fs_mount failed! invalid credentials.rc=%d\n", rc));
276 return EPERM;
277 }
278
279 /* We can mount to only directories. */
280 if (pVNode->v_type != VDIR)
281 return ENOTDIR;
282
283 /* We don't support remounting. */
284 if (pMount->flags & MS_REMOUNT)
285 return ENOTSUP;
286
287 mutex_enter(&pVNode->v_lock);
288 if ( !(pMount->flags & MS_REMOUNT)
289 && !(pMount->flags & MS_OVERLAY)
290 && (pVNode->v_count != -1 || (pVNode->v_flag & VROOT)))
291 {
292 LogRel((DEVICE_NAME ":VBoxVFS_Mount: device busy.\n"));
293 mutex_exit(&pVNode->v_lock);
294 return EBUSY;
295 }
296 mutex_exit(&pVNode->v_lock);
297
298 /* I don't think we really need to support kernel mount arguments anymore. */
299#if 0
300 /* Retreive arguments. */
301 bzero(&Args, sizeof(Args));
302 cbData = pMount->datalen;
303 pData = pMount->data;
304 if ( (pMount->flags & MS_DATA)
305 && pData != NULL
306 && cbData > 0)
307 {
308 if (cbData > sizeof(Args))
309 {
310 LogRel((DEVICE_NAME: "VBoxVFS_Mount: argument length too long. expected=%d. received=%d\n", sizeof(Args), cbData));
311 return EINVAL;
312 }
313
314 /* Copy arguments; they can be in kernel or user space. */
315 rc = ddi_copyin(pData, &Args, cbData, (pMount->flags & MS_SYSSPACE) ? FKIOCTL : 0);
316 if (rc)
317 {
318 LogRel((DEVICE_NAME: "VBoxVFS_Mount: ddi_copyin failed to copy arguments.rc=%d\n", rc));
319 return EFAULT;
320 }
321 }
322 else
323 {
324 cbData = 0;
325 pData = NULL;
326 }
327#endif
328
329 /* Get UID argument (optional). */
330 rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_UID, &Uid);
331 if (rc < 0)
332 {
333 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid uid value.\n"));
334 return EINVAL;
335 }
336
337 /* Get GID argument (optional). */
338 rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_GID, &Gid);
339 if (rc < 0)
340 {
341 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid gid value.\n"));
342 return EINVAL;
343 }
344
345 /* Get special (sharename). */
346 rc = pn_get(pMount->spec, AddrSpace, &PathName);
347 if (!rc)
348 {
349 /* Get the vnode for the special file for storing the device identifier and path. */
350 rc = lookupname(PathName.pn_path, AddrSpace, FOLLOW, NULLVPP, &pVNodeSpec);
351 if (!rc)
352 {
353 /* Check if user has permission to use the special file for mounting. */
354 rc = vboxvfs_CheckMountPerm(pVFS, pMount, pVNodeSpec, pCred);
355 VN_RELE(pVNodeSpec);
356 if (!rc)
357 {
358 Dev = pVNodeSpec->v_rdev;
359 pszShare = RTStrDup(PathName.pn_path);
360 cbShare = strlen(pszShare);
361 }
362 else
363 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid permissions to mount %s.rc=%d\n", pszShare, rc));
364 rc = EPERM;
365 }
366 else
367 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to lookup sharename.rc=%d\n", rc));
368 rc = EINVAL;
369 }
370 else
371 {
372 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to get special file path.rc=%d\n", rc));
373 rc = EINVAL;
374 }
375 pn_free(&PathName);
376
377 if (!rc)
378 return rc;
379
380 /* Get VNode of the special file being mounted. */
381 pVNodeDev = makespecvp(Dev, VBLK);
382 if (!IS_SWAPVP(pVNodeDev))
383 {
384 /* Open the vnode for mounting. */
385 rc = VOP_OPEN(&pVNodeDev, (pVFS->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, pCred, NULL);
386 if (rc)
387 {
388 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to mount.\n"));
389 rc = EINVAL;
390 }
391 }
392 else
393 {
394 LogRel((DEVICE_NAME ":VBoxVFS_Mount: cannot mount from swap.\n"));
395 rc = EINVAL;
396 }
397
398 if (!rc)
399 {
400 VN_RELE(pVNodeDev);
401 return rc;
402 }
403
404 /* Allocate the global info. structure. */
405 pVBoxVFSGlobalInfo = RTMemAlloc(sizeof(*pVBoxVFSGlobalInfo));
406 if (!pVBoxVFSGlobalInfo)
407 {
408 LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAlloc failed to alloc %d bytes for global struct.\n", sizeof(*pVBoxVFSGlobalInfo)));
409 return ENOMEM;
410 }
411
412 cbShflShareName = offsetof (SHFLSTRING, String.utf8) + cbShare + 1;
413 pShflShareName = RTMemAllocZ(cbShflShareName);
414 if (!pShflShareName)
415 {
416 RTMemFree(pVBoxVFSGlobalInfo);
417 LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAlloc failed to alloc %d bytes for ShFlShareName.\n", cbShflShareName));
418 return ENOMEM;
419 }
420
421 pShflShareName->u16Length = cbShflShareName;
422 pShflShareName->u16Size = cbShflShareName + 1;
423 memcpy (pShflShareName->String.utf8, pszShare, cbShare + 1);
424
425 rc = vboxCallMapFolder(&g_VBoxVFSClient, pShflShareName, &pVBoxVFSGlobalInfo->Map);
426 RTMemFree(pShflShareName);
427 if (VBOX_FAILURE (rc))
428 {
429 RTMemFree(pVBoxVFSGlobalInfo);
430 LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxCallMapFolder failed rc=%d\n", rc));
431 return EPROTO;
432 }
433
434 /* @todo mutex for protecting the structure. */
435 pVBoxVFSGlobalInfo->Uid = Uid;
436 pVBoxVFSGlobalInfo->Gid = Gid;
437 pVBoxVFSGlobalInfo->pVFS = pVFS;
438 pVBoxVFSGlobalInfo->Dev = Dev;
439 pVBoxVFSGlobalInfo->pVNodeDev = pVNodeDev;
440 pVFS->vfs_data = pVBoxVFSGlobalInfo;
441 pVFS->vfs_fstype = g_VBoxVFSType;
442 vfs_make_fsid(&pVFS->vfs_fsid, Dev, g_VBoxVFSType);
443
444 /* @todo root vnode */
445
446 return 0;
447}
448
449static int VBoxVFS_Unmount(vfs_t *pVFS, int fUnmount, cred_t *pCred)
450{
451 int rc;
452 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
453
454 LogFlow((DEVICE_NAME ":VBoxVFS_Unmount.\n"));
455
456 /* Check if user can unmount. */
457 rc = secpolicy_fs_unmount(pCred, pVFS);
458 if (rc)
459 {
460 LogRel((DEVICE_NAME ":VBoxVFS_Unmount: insufficient privileges to unmount.rc=%d\n", rc));
461 return EPERM;
462 }
463
464 if (fUnmount & MS_FORCE)
465 pVFS->vfs_flag |= VFS_UNMOUNTED;
466
467 /* @todo implement ref-counting of active vnodes & check for busy state here. */
468 /* @todo mutex protection needed here */
469 pVBoxVFSGlobalInfo = VFS2VBOXVFS(pVFS);
470
471 rc = vboxCallUnmapFolder(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map);
472 if (VBOX_FAILURE(rc))
473 LogRel((DEVICE_NAME ":VBoxVFS_Unmount: failed to unmap shared folder. rc=%d\n", rc));
474
475 RTMemFree(pVBoxVFSGlobalInfo);
476 pVFS->vfs_data = NULL;
477
478 return 0;
479}
480
481static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode)
482{
483 return 0;
484}
485
486static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat)
487{
488 return 0;
489}
490
491static int VBoxVFS_Sync(vfs_t *pVFS, short fFlags, cred_t *pCred)
492{
493 return 0;
494}
495
496static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid)
497{
498 return 0;
499}
500
501static void VBoxVFS_FreeVFS(vfs_t *pVFS)
502{
503 vboxDisconnect(&g_VBoxVFSClient);
504 vboxUninit();
505}
506
507static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred)
508{
509 /* Check if user has the rights to mount the special file. */
510 int fOpen = FREAD | FWRITE;
511 int fAccess = VREAD | VWRITE;
512 int rc;
513
514 if (pVNodeSpec->v_type != VBLK)
515 return ENOTBLK;
516
517 if ( (pVFS->vfs_flag & VFS_RDONLY)
518 || (pMount->flags & MS_RDONLY))
519 {
520 fOpen = FREAD;
521 fAccess = VREAD;
522 }
523
524 rc = VOP_ACCESS(pVNodeSpec, fAccess, 0, pCred, NULL /* caller_context */);
525 if (!rc)
526 rc = secpolicy_spec_open(pCred, pVNodeSpec, fOpen);
527
528 return rc;
529}
530
531static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue)
532{
533 int rc;
534 long Val;
535 char *pchOpt = NULL;
536 char *pchEnd = NULL;
537
538 rc = vfs_optionisset(pVFS, pszOpt, &pchOpt);
539 if (rc)
540 {
541 rc = ddi_strtol(pchOpt, &pchEnd, 10 /* base */, &Val);
542 if ( !rc
543 && Val > INT_MIN
544 && Val < INT_MAX
545 && pchEnd == pchOpt + strlen(pchOpt))
546 {
547 *pValue = (int)Val;
548 return 0;
549 }
550 return -1;
551 }
552 return 1;
553}
554
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette