VirtualBox

source: vbox/trunk/src/VBox/Additions/darwin/VBoxSF/VBoxSF-Utils.cpp@ 75666

Last change on this file since 75666 was 75666, checked in by vboxsync, 6 years ago

darwin/VBoxSF: updates

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