VirtualBox

source: vbox/trunk/src/VBox/Additions/darwin/vboxfs/VBoxVFS-utils.cpp@ 69206

Last change on this file since 69206 was 63526, checked in by vboxsync, 8 years ago

fixed headers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 KB
Line 
1/* $Id: VBoxVFS-utils.cpp 63526 2016-08-16 08:44:20Z vboxsync $ */
2/** @file
3 * VBoxVFS - helper functions.
4 */
5
6/*
7 * Copyright (C) 2013-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <mach/kmod.h>
19#include <libkern/libkern.h>
20#include <mach/mach_types.h>
21
22#include <sys/mount.h>
23#include <sys/vnode.h>
24#include <sys/errno.h>
25#include <sys/fcntl.h>
26
27#include <iprt/assert.h>
28#include <iprt/mem.h>
29
30#include "vboxvfs.h"
31
32/**
33 * Helper function to create XNU VFS vnode object.
34 *
35 * @param mp Mount data structure
36 * @param type vnode type (directory, regular file, etc)
37 * @param pParent Parent vnode object (NULL for VBoxVFS root vnode)
38 * @param fIsRoot Flag that indicates if created vnode object is
39 * VBoxVFS root vnode (TRUE for VBoxVFS root vnode, FALSE
40 * for all aother vnodes)
41 * @param Path within Shared Folder
42 * @param ret Returned newly created vnode
43 *
44 * @return 0 on success, error code otherwise
45 */
46int
47vboxvfs_create_vnode_internal(struct mount *mp, enum vtype type, vnode_t pParent, int fIsRoot, PSHFLSTRING Path, vnode_t *ret)
48{
49 int rc;
50 vnode_t vnode;
51
52 vboxvfs_vnode_t *pVnodeData;
53 vboxvfs_mount_t *pMount;
54
55 AssertReturn(mp, EINVAL);
56
57 pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp);
58 AssertReturn(pMount, EINVAL);
59 AssertReturn(pMount->pLockGroup, EINVAL);
60
61 AssertReturn(Path, EINVAL);
62
63 pVnodeData = (vboxvfs_vnode_t *)RTMemAllocZ(sizeof(vboxvfs_vnode_t));
64 AssertReturn(pVnodeData, ENOMEM);
65
66 /* Initialize private data */
67 pVnodeData->pHandle = SHFL_HANDLE_NIL;
68 pVnodeData->pPath = Path;
69
70 pVnodeData->pLockAttr = lck_attr_alloc_init();
71 if (pVnodeData->pLockAttr)
72 {
73 pVnodeData->pLock = lck_rw_alloc_init(pMount->pLockGroup, pVnodeData->pLockAttr);
74 if (pVnodeData->pLock)
75 {
76 struct vnode_fsparam vnode_params;
77
78 vnode_params.vnfs_mp = mp;
79 vnode_params.vnfs_vtype = type;
80 vnode_params.vnfs_str = NULL;
81 vnode_params.vnfs_dvp = pParent;
82 vnode_params.vnfs_fsnode = pVnodeData; /** Private data attached per xnu's vnode object */
83 vnode_params.vnfs_vops = g_VBoxVFSVnodeDirOpsVector;
84
85 vnode_params.vnfs_markroot = fIsRoot;
86 vnode_params.vnfs_marksystem = FALSE;
87 vnode_params.vnfs_rdev = 0;
88 vnode_params.vnfs_filesize = 0;
89 vnode_params.vnfs_cnp = NULL;
90
91 vnode_params.vnfs_flags = VNFS_ADDFSREF | VNFS_NOCACHE;
92
93 rc = vnode_create(VNCREATE_FLAVOR, sizeof(vnode_params), &vnode_params, &vnode);
94 if (rc == 0)
95 *ret = vnode;
96
97 return 0;
98 }
99 else
100 {
101 PDEBUG("Unable to allocate lock");
102 rc = ENOMEM;
103 }
104
105 lck_attr_free(pVnodeData->pLockAttr);
106 }
107 else
108 {
109 PDEBUG("Unable to allocate lock attr");
110 rc = ENOMEM;
111 }
112
113 return rc;
114}
115
116/**
117 * Convert guest absolute VFS path (starting from VFS root) to a host path
118 * within mounted shared folder (returning it as a char *).
119 *
120 * @param mp Mount data structure
121 * @param pszGuestPath Guest absolute VFS path (starting from VFS root)
122 * @param cbGuestPath Size of pszGuestPath
123 * @param pszHostPath Returned char * wich contains host path
124 * @param cbHostPath Returned pszHostPath size
125 *
126 * @return 0 on success, error code otherwise
127 */
128int
129vboxvfs_guest_path_to_char_path_internal(mount_t mp, char *pszGuestPath, int cbGuestPath, char **pszHostPath, int *cbHostPath)
130{
131 vboxvfs_mount_t *pMount;
132
133 /* Guest side: mount point path buffer and its size */
134 char *pszMntPointPath;
135 int cbMntPointPath = MAXPATHLEN;
136
137 /* Host side: path within mounted shared folder and its size */
138 char *pszHostPathInternal;
139 size_t cbHostPathInternal;
140
141 int rc;
142
143 AssertReturn(mp, EINVAL);
144 AssertReturn(pszGuestPath, EINVAL); AssertReturn(cbGuestPath >= 0, EINVAL);
145 AssertReturn(pszHostPath, EINVAL); AssertReturn(cbHostPath, EINVAL);
146
147 pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); AssertReturn(pMount->pRootVnode, EINVAL);
148
149 /* Get mount point path */
150 pszMntPointPath = (char *)RTMemAllocZ(cbMntPointPath);
151 if (pszMntPointPath)
152 {
153 rc = vn_getpath(pMount->pRootVnode, pszMntPointPath, &cbMntPointPath);
154 if (rc == 0 && cbGuestPath >= cbMntPointPath)
155 {
156 cbHostPathInternal = cbGuestPath - cbMntPointPath + 1;
157 pszHostPathInternal = (char *)RTMemAllocZ(cbHostPathInternal);
158 if (pszHostPathInternal)
159 {
160 memcpy(pszHostPathInternal, pszGuestPath + cbMntPointPath, cbGuestPath - cbMntPointPath);
161 PDEBUG("guest<->host path converion result: '%s' mounted to '%s'", pszHostPathInternal, pszMntPointPath);
162
163 RTMemFree(pszMntPointPath);
164
165 *pszHostPath = pszHostPathInternal;
166 *cbHostPath = cbGuestPath - cbMntPointPath;
167
168 return 0;
169
170 }
171 else
172 {
173 PDEBUG("No memory to allocate buffer for guest<->host path conversion (cbHostPathInternal)");
174 rc = ENOMEM;
175 }
176
177 }
178 else
179 {
180 PDEBUG("Unable to get guest vnode path: %d", rc);
181 }
182
183 RTMemFree(pszMntPointPath);
184 }
185 else
186 {
187 PDEBUG("No memory to allocate buffer for guest<->host path conversion (pszMntPointPath)");
188 rc = ENOMEM;
189 }
190
191 return rc;
192}
193
194/**
195 * Convert guest absolute VFS path (starting from VFS root) to a host path
196 * within mounted shared folder.
197 *
198 * @param mp Mount data structure
199 * @param pszGuestPath Guest absolute VFS path (starting from VFS root)
200 * @param cbGuestPath Size of pszGuestPath
201 * @param ppResult Returned PSHFLSTRING object wich contains host path
202 *
203 * @return 0 on success, error code otherwise
204 */
205int
206vboxvfs_guest_path_to_shflstring_path_internal(mount_t mp, char *pszGuestPath, int cbGuestPath, PSHFLSTRING *ppResult)
207{
208 vboxvfs_mount_t *pMount;
209
210 /* Guest side: mount point path buffer and its size */
211 char *pszMntPointPath;
212 int cbMntPointPath = MAXPATHLEN;
213
214 /* Host side: path within mounted shared folder and its size */
215 PSHFLSTRING pSFPath;
216 size_t cbSFPath;
217
218 int rc;
219
220 AssertReturn(mp, EINVAL);
221 AssertReturn(pszGuestPath, EINVAL);
222 AssertReturn(cbGuestPath >= 0, EINVAL);
223
224 char *pszHostPath;
225 int cbHostPath;
226
227 rc = vboxvfs_guest_path_to_char_path_internal(mp, pszGuestPath, cbGuestPath, &pszHostPath, &cbHostPath);
228 if (rc == 0)
229 {
230 cbSFPath = offsetof(SHFLSTRING, String.utf8) + (size_t)cbHostPath + 1;
231 pSFPath = (PSHFLSTRING)RTMemAllocZ(cbSFPath);
232 if (pSFPath)
233 {
234 pSFPath->u16Length = cbHostPath;
235 pSFPath->u16Size = cbHostPath + 1;
236 memcpy(pSFPath->String.utf8, pszHostPath, cbHostPath);
237 vboxvfs_put_path_internal((void **)&pszHostPath);
238
239 *ppResult = pSFPath;
240 }
241 }
242
243 return rc;
244}
245
246/**
247 * Wrapper function for vboxvfs_guest_path_to_char_path_internal() which
248 * converts guest path to host path using vnode object information.
249 *
250 * @param vnode Guest's VFS object
251 * @param ppHostPath Allocated char * which contain a path
252 * @param pcbPath Size of ppPath
253 *
254 * @return 0 on success, error code otherwise.
255 */
256int
257vboxvfs_guest_vnode_to_char_path_internal(vnode_t vnode, char **ppHostPath, int *pcbHostPath)
258{
259 mount_t mp;
260 int rc;
261
262 char *pszPath;
263 int cbPath = MAXPATHLEN;
264
265 AssertReturn(ppHostPath, EINVAL);
266 AssertReturn(pcbHostPath, EINVAL);
267 AssertReturn(vnode, EINVAL);
268 mp = vnode_mount(vnode); AssertReturn(mp, EINVAL);
269
270 pszPath = (char *)RTMemAllocZ(cbPath);
271 if (pszPath)
272 {
273 rc = vn_getpath(vnode, pszPath, &cbPath);
274 if (rc == 0)
275 {
276 return vboxvfs_guest_path_to_char_path_internal(mp, pszPath, cbPath, ppHostPath, pcbHostPath);
277 }
278 }
279 else
280 {
281 rc = ENOMEM;
282 }
283
284 return rc;
285}
286
287/**
288 * Wrapper function for vboxvfs_guest_path_to_shflstring_path_internal() which
289 * converts guest path to host path using vnode object information.
290 *
291 * @param vnode Guest's VFS object
292 * @param ppResult Allocated PSHFLSTRING object which contain a path
293 *
294 * @return 0 on success, error code otherwise.
295 */
296int
297vboxvfs_guest_vnode_to_shflstring_path_internal(vnode_t vnode, PSHFLSTRING *ppResult)
298{
299 mount_t mp;
300 int rc;
301
302 char *pszPath;
303 int cbPath = MAXPATHLEN;
304
305 AssertReturn(ppResult, EINVAL);
306 AssertReturn(vnode, EINVAL);
307 mp = vnode_mount(vnode); AssertReturn(mp, EINVAL);
308
309 pszPath = (char *)RTMemAllocZ(cbPath);
310 if (pszPath)
311 {
312 rc = vn_getpath(vnode, pszPath, &cbPath);
313 if (rc == 0)
314 {
315 return vboxvfs_guest_path_to_shflstring_path_internal(mp, pszPath, cbPath, ppResult);
316 }
317 }
318 else
319 {
320 rc = ENOMEM;
321 }
322
323 return rc;
324}
325
326
327/**
328 * Free resources allocated by vboxvfs_path_internal() and vboxvfs_guest_vnode_to_shflstring_path_internal().
329 *
330 * @param ppHandle Reference to object to be freed.
331 */
332void
333vboxvfs_put_path_internal(void **ppHandle)
334{
335 AssertReturnVoid(ppHandle);
336 AssertReturnVoid(*ppHandle);
337 RTMemFree(*ppHandle);
338}
339
340static void
341vboxvfs_g2h_mode_dump_inernal(uint32_t fHostMode)
342{
343 PDEBUG("Host VFS object flags (0x%X) dump:", (int)fHostMode);
344
345 if (fHostMode & SHFL_CF_ACCESS_READ) PDEBUG("SHFL_CF_ACCESS_READ");
346 if (fHostMode & SHFL_CF_ACCESS_WRITE) PDEBUG("SHFL_CF_ACCESS_WRITE");
347 if (fHostMode & SHFL_CF_ACCESS_APPEND) PDEBUG("SHFL_CF_ACCESS_APPEND");
348
349 if ((fHostMode & (SHFL_CF_ACT_FAIL_IF_EXISTS |
350 SHFL_CF_ACT_REPLACE_IF_EXISTS |
351 SHFL_CF_ACT_OVERWRITE_IF_EXISTS)) == 0)
352 PDEBUG("SHFL_CF_ACT_OPEN_IF_EXISTS");
353
354 if (fHostMode & SHFL_CF_ACT_CREATE_IF_NEW) PDEBUG("SHFL_CF_ACT_CREATE_IF_NEW");
355 if (fHostMode & SHFL_CF_ACT_FAIL_IF_NEW) PDEBUG("SHFL_CF_ACT_FAIL_IF_NEW");
356 if (fHostMode & SHFL_CF_ACT_OVERWRITE_IF_EXISTS) PDEBUG("SHFL_CF_ACT_OVERWRITE_IF_EXISTS");
357 if (fHostMode & SHFL_CF_DIRECTORY) PDEBUG("SHFL_CF_DIRECTORY");
358
359 PDEBUG("Done");
360}
361
362
363/**
364 * Open existing VBoxVFS object and return its handle.
365 *
366 * @param pMount Mount session data.
367 * @param pPath VFS path to the object relative to mount point.
368 * @param fFlags For directory object it should be
369 * SHFL_CF_DIRECTORY and 0 for any other object.
370 * @param pHandle Returned handle.
371 *
372 * @return 0 on success, error code otherwise.
373 */
374int
375vboxvfs_open_internal(vboxvfs_mount_t *pMount, PSHFLSTRING pPath, uint32_t fFlags, SHFLHANDLE *pHandle)
376{
377 SHFLCREATEPARMS parms;
378
379 int rc;
380
381 AssertReturn(pMount, EINVAL);
382 AssertReturn(pPath, EINVAL);
383 AssertReturn(pHandle, EINVAL);
384
385 bzero(&parms, sizeof(parms));
386
387 vboxvfs_g2h_mode_dump_inernal(fFlags);
388
389 parms.Handle = SHFL_HANDLE_NIL;
390 parms.Info.cbObject = 0;
391 parms.CreateFlags = fFlags;
392
393 rc = VbglR0SfCreate(&g_vboxSFClient, &pMount->pMap, pPath, &parms);
394 if (RT_SUCCESS(rc))
395 {
396 *pHandle = parms.Handle;
397 }
398 else
399 {
400 PDEBUG("vboxvfs_open_internal() failed: %d", rc);
401 }
402
403 return rc;
404}
405
406/**
407 * Release VBoxVFS object handle openned by vboxvfs_open_internal().
408 *
409 * @param pMount Mount session data.
410 * @param pHandle Handle to close.
411 *
412 * @return 0 on success, IPRT error code otherwise.
413 */
414int
415vboxvfs_close_internal(vboxvfs_mount_t *pMount, SHFLHANDLE pHandle)
416{
417 AssertReturn(pMount, EINVAL);
418 return VbglR0SfClose(&g_vboxSFClient, &pMount->pMap, pHandle);
419}
420
421/**
422 * Get information about host VFS object.
423 *
424 * @param mp Mount point data
425 * @param pSHFLDPath Path to VFS object within mounted shared folder
426 * @param Info Returned info
427 *
428 * @return 0 on success, error code otherwise.
429 */
430int
431vboxvfs_get_info_internal(mount_t mp, PSHFLSTRING pSHFLDPath, PSHFLFSOBJINFO Info)
432{
433 vboxvfs_mount_t *pMount;
434 SHFLCREATEPARMS parms;
435
436 int rc;
437
438 AssertReturn(mp, EINVAL);
439 AssertReturn(pSHFLDPath, EINVAL);
440 AssertReturn(Info, EINVAL);
441
442 pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL);
443
444 parms.Handle = 0;
445 parms.Info.cbObject = 0;
446 parms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
447
448 rc = VbglR0SfCreate(&g_vboxSFClient, &pMount->pMap, pSHFLDPath, &parms);
449 if (rc == 0)
450 *Info = parms.Info;
451
452 return rc;
453}
454
455/**
456 * Check if VFS object exists on a host side.
457 *
458 * @param vnode Guest VFS vnode that corresponds to host VFS object
459 *
460 * @return 1 if exists, 0 otherwise.
461 */
462int
463vboxvfs_exist_internal(vnode_t vnode)
464{
465 int rc;
466
467 PSHFLSTRING pSFPath = NULL;
468 SHFLHANDLE handle;
469 uint32_t fFlags;
470
471 vboxvfs_mount_t *pMount;
472 mount_t mp;
473
474 /* Return FALSE if invalid parameter given */
475 AssertReturn(vnode, 0);
476
477 mp = vnode_mount(vnode); AssertReturn(mp, EINVAL);
478 pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL);
479
480 fFlags = (vnode_isdir(vnode)) ? SHFL_CF_DIRECTORY : 0;
481 fFlags |= SHFL_CF_ACCESS_READ | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
482
483 rc = vboxvfs_guest_vnode_to_shflstring_path_internal(vnode, &pSFPath); AssertReturn(rc == 0, rc);
484 if (rc == 0)
485 {
486 rc = vboxvfs_open_internal(pMount, pSFPath, fFlags, &handle);
487 if (rc == 0)
488 {
489 rc = vboxvfs_close_internal(pMount, handle);
490 if (rc != 0)
491 {
492 PDEBUG("Unable to close() VBoxVFS object handle while checking if object exist on host: %d", rc);
493 }
494 }
495 }
496
497 vboxvfs_put_path_internal((void **)&pSFPath);
498
499 return (rc == 0);
500}
501
502/**
503 * Convert host VFS object mode flags into guest ones.
504 *
505 * @param fHostMode Host flags
506 *
507 * @return Guest flags
508 */
509mode_t
510vboxvfs_h2g_mode_inernal(RTFMODE fHostMode)
511{
512 mode_t fGuestMode = 0;
513
514 fGuestMode = /* Owner */
515 ((fHostMode & RTFS_UNIX_IRUSR) ? S_IRUSR : 0 ) |
516 ((fHostMode & RTFS_UNIX_IWUSR) ? S_IWUSR : 0 ) |
517 ((fHostMode & RTFS_UNIX_IXUSR) ? S_IXUSR : 0 ) |
518 /* Group */
519 ((fHostMode & RTFS_UNIX_IRGRP) ? S_IRGRP : 0 ) |
520 ((fHostMode & RTFS_UNIX_IWGRP) ? S_IWGRP : 0 ) |
521 ((fHostMode & RTFS_UNIX_IXGRP) ? S_IXGRP : 0 ) |
522 /* Other */
523 ((fHostMode & RTFS_UNIX_IROTH) ? S_IROTH : 0 ) |
524 ((fHostMode & RTFS_UNIX_IWOTH) ? S_IWOTH : 0 ) |
525 ((fHostMode & RTFS_UNIX_IXOTH) ? S_IXOTH : 0 ) |
526 /* SUID, SGID, SVTXT */
527 ((fHostMode & RTFS_UNIX_ISUID) ? S_ISUID : 0 ) |
528 ((fHostMode & RTFS_UNIX_ISGID) ? S_ISGID : 0 ) |
529 ((fHostMode & RTFS_UNIX_ISTXT) ? S_ISVTX : 0 ) |
530 /* VFS object types */
531 ((RTFS_IS_FIFO(fHostMode)) ? S_IFIFO : 0 ) |
532 ((RTFS_IS_DEV_CHAR(fHostMode)) ? S_IFCHR : 0 ) |
533 ((RTFS_IS_DIRECTORY(fHostMode)) ? S_IFDIR : 0 ) |
534 ((RTFS_IS_DEV_BLOCK(fHostMode)) ? S_IFBLK : 0 ) |
535 ((RTFS_IS_FILE(fHostMode)) ? S_IFREG : 0 ) |
536 ((RTFS_IS_SYMLINK(fHostMode)) ? S_IFLNK : 0 ) |
537 ((RTFS_IS_SOCKET(fHostMode)) ? S_IFSOCK : 0 );
538
539 return fGuestMode;
540}
541
542/**
543 * Convert guest VFS object mode flags into host ones.
544 *
545 * @param fGuestMode Host flags
546 *
547 * @return Host flags
548 */
549uint32_t
550vboxvfs_g2h_mode_inernal(mode_t fGuestMode)
551{
552 uint32_t fHostMode = 0;
553
554 fHostMode = ((fGuestMode & FREAD) ? SHFL_CF_ACCESS_READ : 0 ) |
555 ((fGuestMode & FWRITE) ? SHFL_CF_ACCESS_WRITE : 0 ) |
556 /* skipped: O_NONBLOCK */
557 ((fGuestMode & O_APPEND) ? SHFL_CF_ACCESS_APPEND : 0 ) |
558 /* skipped: O_SYNC */
559 /* skipped: O_SHLOCK */
560 /* skipped: O_EXLOCK */
561 /* skipped: O_ASYNC */
562 /* skipped: O_FSYNC */
563 /* skipped: O_NOFOLLOW */
564 ((fGuestMode & O_CREAT) ? SHFL_CF_ACT_CREATE_IF_NEW | (!(fGuestMode & O_TRUNC) ? SHFL_CF_ACT_OPEN_IF_EXISTS : 0) : SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW ) |
565 ((fGuestMode & O_TRUNC) ? SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACCESS_WRITE : 0 );
566 /* skipped: O_EXCL */
567
568 return fHostMode;
569}
570
571/**
572 * Mount helper: Contruct SHFLSTRING which contains VBox share name or path.
573 *
574 * @param szName Char * string containing share name.
575 * @param cbName Length of pShareName.
576 *
577 * @return Allocated SHFLSTRING which contains VBox share name or path, NULL otherwise.
578 */
579SHFLSTRING *
580vboxvfs_construct_shflstring(char *szName, size_t cbName)
581{
582 size_t cbSHFLString;
583 SHFLSTRING *pSHFLString;
584
585 AssertReturn(szName, NULL);
586
587 cbSHFLString = offsetof(SHFLSTRING, String.utf8) + cbName + 1;
588 pSHFLString = (SHFLSTRING *)RTMemAllocZ(cbSHFLString);
589
590 if (pSHFLString)
591 {
592 pSHFLString->u16Length = cbSHFLString;
593 pSHFLString->u16Size = cbSHFLString + 1;
594
595 /* Do not do that for empty strings */
596 if (cbName > 0)
597 memcpy(pSHFLString->String.utf8, szName, cbName + 1);
598
599 return pSHFLString;
600 }
601
602 return NULL;
603}
604
Note: See TracBrowser for help on using the repository browser.

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