VirtualBox

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

Last change on this file since 107044 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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