VirtualBox

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

Last change on this file since 94130 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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