VirtualBox

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

最後變更 在這個檔案從10023是 10023,由 vboxsync 提交於 16 年 前

Solaris vboxvfs: resolved symbols and updated the VBOXGUESTR0 template. Added ConvertToErrno to GuestR0 IPRT.

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

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