VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp@ 76409

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

VBoxService/Automounter: Corrected conversion to UTF-16 in vbsvcAutomounterMountIt.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.6 KB
Line 
1/* $Id: VBoxServiceAutoMount.cpp 75947 2018-12-04 13:17:55Z vboxsync $ */
2/** @file
3 * VBoxService - Auto-mounting for Shared Folders, only Linux & Solaris atm.
4 */
5
6/*
7 * Copyright (C) 2010-2017 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/** @page pg_vgsvc_automount VBoxService - Shared Folder Automounter
20 *
21 * The Shared Folder Automounter subservice mounts shared folders upon request
22 * from the host.
23 *
24 * This retrieves shared folder automount requests from Main via the VMMDev.
25 * The current implemention only does this once, for some inexplicable reason,
26 * so the run-time addition of automounted shared folders are not heeded.
27 *
28 * This subservice is only used on linux and solaris. On Windows the current
29 * thinking is this is better of done from VBoxTray, some one argue that for
30 * drive letter assigned shared folders it would be better to do some magic here
31 * (obviously not involving NDAddConnection).
32 *
33 */
34
35
36/*********************************************************************************************************************************
37* Header Files *
38*********************************************************************************************************************************/
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/dir.h>
42#include <iprt/mem.h>
43#include <iprt/path.h>
44#include <iprt/semaphore.h>
45#include <iprt/sort.h>
46#include <iprt/string.h>
47#include <VBox/VBoxGuestLib.h>
48#include <VBox/shflsvc.h>
49#include "VBoxServiceInternal.h"
50#include "VBoxServiceUtils.h"
51
52#ifdef RT_OS_WINDOWS
53#elif defined(RT_OS_OS2)
54# define INCL_DOSFILEMGR
55# define INCL_ERRORS
56# define OS2EMX_PLAIN_CHAR
57# include <os2emx.h>
58#else
59# include <errno.h>
60# include <grp.h>
61# include <sys/mount.h>
62# ifdef RT_OS_SOLARIS
63# include <sys/mntent.h>
64# include <sys/mnttab.h>
65# include <sys/vfs.h>
66RT_C_DECLS_BEGIN /* Only needed for old code.*/
67# include "../../linux/sharedfolders/vbsfmount.h"
68RT_C_DECLS_END
69# elif defined(RT_OS_LINUX)
70# include <mntent.h>
71# include <paths.h>
72RT_C_DECLS_BEGIN
73# include "../../linux/sharedfolders/vbsfmount.h"
74RT_C_DECLS_END
75# else
76# error "Port me!"
77# endif
78# include <unistd.h>
79#endif
80
81
82
83/*********************************************************************************************************************************
84* Defined Constants And Macros *
85*********************************************************************************************************************************/
86/** @def VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR
87 * Default mount directory (unix only).
88 */
89#ifndef VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR
90# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/media"
91#endif
92
93/** @def VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX
94 * Default mount prefix (unix only).
95 */
96#ifndef VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX
97# define VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX "sf_"
98#endif
99
100#ifndef _PATH_MOUNTED
101# ifdef RT_OS_SOLARIS
102# define _PATH_MOUNTED "/etc/mnttab"
103# else
104# define _PATH_MOUNTED "/etc/mtab"
105# endif
106#endif
107
108/** @def VBOXSERVICE_AUTOMOUNT_MIQF
109 * The drive letter / path mount point flag. */
110#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
111# define VBOXSERVICE_AUTOMOUNT_MIQF SHFL_MIQF_DRIVE_LETTER
112#else
113# define VBOXSERVICE_AUTOMOUNT_MIQF SHFL_MIQF_PATH
114#endif
115
116
117/*********************************************************************************************************************************
118* Structures and Typedefs *
119*********************************************************************************************************************************/
120/**
121 * Automounter mount table entry.
122 *
123 * This holds the information returned by SHFL_FN_QUERY_MAP_INFO and
124 * additional mount state info. We only keep entries for mounted mappings.
125 */
126typedef struct VBSVCAUTOMOUNTERENTRY
127{
128 /** The root ID. */
129 uint32_t idRoot;
130 /** The root ID version. */
131 uint32_t uRootIdVersion;
132 /** Map info flags, SHFL_MIF_XXX. */
133 uint64_t fFlags;
134 /** The shared folder (mapping) name. */
135 char *pszName;
136 /** The configured mount point, NULL if none. */
137 char *pszMountPoint;
138 /** The actual mount point, NULL if not mount. */
139 char *pszActualMountPoint;
140} VBSVCAUTOMOUNTERENTRY;
141/** Pointer to an automounter entry. */
142typedef VBSVCAUTOMOUNTERENTRY *PVBSVCAUTOMOUNTERENTRY;
143
144/** Automounter mount table. */
145typedef struct VBSVCAUTOMOUNTERTABLE
146{
147 /** Current number of entries in the array. */
148 uint32_t cEntries;
149 /** Max number of entries the array can hold w/o growing it. */
150 uint32_t cAllocated;
151 /** Pointer to an array of entry pointers. */
152 PVBSVCAUTOMOUNTERENTRY *papEntries;
153} VBSVCAUTOMOUNTERTABLE;
154/** Pointer to an automounter mount table. */
155typedef VBSVCAUTOMOUNTERTABLE *PVBSVCAUTOMOUNTERTABLE;
156
157
158/*********************************************************************************************************************************
159* Global Variables *
160*********************************************************************************************************************************/
161/** The semaphore we're blocking on. */
162static RTSEMEVENTMULTI g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
163/** The Shared Folders service client ID. */
164static uint32_t g_idClientSharedFolders = 0;
165/** Set if we can wait on changes to the mappings. */
166static bool g_fHostSupportsWaitAndInfoQuery = false;
167
168#ifdef RT_OS_OS2
169/** The attachment tag we use to identify attchments that belongs to us. */
170static char const g_szTag[] = "VBoxAutomounter";
171#elif defined(RT_OS_LINUX)
172/** Tag option value that lets us identify mounts that belongs to us. */
173static char const g_szTag[] = "VBoxAutomounter";
174#elif defined(RT_OS_SOLARIS)
175/** Dummy mount option that lets us identify mounts that belongs to us. */
176static char const g_szTag[] = "VBoxAutomounter";
177#endif
178
179
180
181/**
182 * @interface_method_impl{VBOXSERVICE,pfnInit}
183 */
184static DECLCALLBACK(int) vbsvcAutomounterInit(void)
185{
186 VGSvcVerbose(3, "vbsvcAutomounterInit\n");
187
188 int rc = RTSemEventMultiCreate(&g_hAutoMountEvent);
189 AssertRCReturn(rc, rc);
190
191 rc = VbglR3SharedFolderConnect(&g_idClientSharedFolders);
192 if (RT_SUCCESS(rc))
193 {
194 VGSvcVerbose(3, "vbsvcAutomounterInit: Service Client ID: %#x\n", g_idClientSharedFolders);
195 g_fHostSupportsWaitAndInfoQuery = RT_SUCCESS(VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders));
196 }
197 else
198 {
199 /* If the service was not found, we disable this service without
200 causing VBoxService to fail. */
201 if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
202 {
203 VGSvcVerbose(0, "vbsvcAutomounterInit: Shared Folders service is not available\n");
204 rc = VERR_SERVICE_DISABLED;
205 }
206 else
207 VGSvcError("Control: Failed to connect to the Shared Folders service! Error: %Rrc\n", rc);
208 RTSemEventMultiDestroy(g_hAutoMountEvent);
209 g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
210 }
211
212 return rc;
213}
214
215
216#if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) /* The old code: */
217
218/**
219 * @todo Integrate into RTFsQueryMountpoint()?
220 */
221static bool vbsvcAutoMountShareIsMountedOld(const char *pszShare, char *pszMountPoint, size_t cbMountPoint)
222{
223 AssertPtrReturn(pszShare, false);
224 AssertPtrReturn(pszMountPoint, false);
225 AssertReturn(cbMountPoint, false);
226
227 bool fMounted = false;
228
229# if defined(RT_OS_SOLARIS)
230 /** @todo What to do if we have a relative path in mtab instead
231 * of an absolute one ("temp" vs. "/media/temp")?
232 * procfs contains the full path but not the actual share name ...
233 * FILE *pFh = setmntent("/proc/mounts", "r+t"); */
234 FILE *pFh = fopen(_PATH_MOUNTED, "r");
235 if (!pFh)
236 VGSvcError("vbsvcAutoMountShareIsMountedOld: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
237 else
238 {
239 mnttab mntTab;
240 while ((getmntent(pFh, &mntTab)))
241 {
242 if (!RTStrICmp(mntTab.mnt_special, pszShare))
243 {
244 fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", mntTab.mnt_mountp)
245 ? true : false;
246 break;
247 }
248 }
249 fclose(pFh);
250 }
251# elif defined(RT_OS_LINUX)
252 FILE *pFh = setmntent(_PATH_MOUNTED, "r+t"); /** @todo r=bird: why open it for writing? (the '+') */
253 if (pFh == NULL)
254 VGSvcError("vbsvcAutoMountShareIsMountedOld: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
255 else
256 {
257 mntent *pMntEnt;
258 while ((pMntEnt = getmntent(pFh)))
259 {
260 if (!RTStrICmp(pMntEnt->mnt_fsname, pszShare))
261 {
262 fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", pMntEnt->mnt_dir)
263 ? true : false;
264 break;
265 }
266 }
267 endmntent(pFh);
268 }
269# else
270# error "PORTME!"
271# endif
272
273 VGSvcVerbose(4, "vbsvcAutoMountShareIsMountedOld: Share '%s' at mount point '%s' = %s\n",
274 pszShare, fMounted ? pszMountPoint : "<None>", fMounted ? "Yes" : "No");
275 return fMounted;
276}
277
278
279/**
280 * Unmounts a shared folder.
281 *
282 * @returns VBox status code
283 * @param pszMountPoint The shared folder mount point.
284 */
285static int vbsvcAutoMountUnmountOld(const char *pszMountPoint)
286{
287 AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
288
289 int rc = VINF_SUCCESS;
290 uint8_t uTries = 0;
291 int r;
292 while (uTries++ < 3)
293 {
294 r = umount(pszMountPoint);
295 if (r == 0)
296 break;
297/** @todo r=bird: Why do sleep 5 seconds after the final retry?
298 * May also be a good idea to check for EINVAL or other signs that someone
299 * else have already unmounted the share. */
300 RTThreadSleep(5000); /* Wait a while ... */
301 }
302 if (r == -1) /** @todo r=bird: RTThreadSleep set errno. */
303 rc = RTErrConvertFromErrno(errno);
304 return rc;
305}
306
307
308/**
309 * Prepares a mount point (create it, set group and mode).
310 *
311 * @returns VBox status code
312 * @param pszMountPoint The mount point.
313 * @param pszShareName Unused.
314 * @param pOpts For getting the group ID.
315 */
316static int vbsvcAutoMountPrepareMountPointOld(const char *pszMountPoint, const char *pszShareName, vbsf_mount_opts *pOpts)
317{
318 AssertPtrReturn(pOpts, VERR_INVALID_PARAMETER);
319 AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
320 AssertPtrReturn(pszShareName, VERR_INVALID_PARAMETER);
321
322 RTFMODE fMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG; /* Owner (=root) and the group (=vboxsf) have full access. */
323 int rc = RTDirCreateFullPath(pszMountPoint, fMode);
324 if (RT_SUCCESS(rc))
325 {
326 rc = RTPathSetOwnerEx(pszMountPoint, NIL_RTUID /* Owner, unchanged */, pOpts->gid, RTPATH_F_ON_LINK);
327 if (RT_SUCCESS(rc))
328 {
329 rc = RTPathSetMode(pszMountPoint, fMode);
330 if (RT_FAILURE(rc))
331 {
332 if (rc == VERR_WRITE_PROTECT)
333 {
334 VGSvcVerbose(3, "vbsvcAutoMountPrepareMountPointOld: Mount directory '%s' already is used/mounted\n",
335 pszMountPoint);
336 rc = VINF_SUCCESS;
337 }
338 else
339 VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not set mode %RTfmode for mount directory '%s', rc = %Rrc\n",
340 fMode, pszMountPoint, rc);
341 }
342 }
343 else
344 VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not set permissions for mount directory '%s', rc = %Rrc\n",
345 pszMountPoint, rc);
346 }
347 else
348 VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not create mount directory '%s' with mode %RTfmode, rc = %Rrc\n",
349 pszMountPoint, fMode, rc);
350 return rc;
351}
352
353
354/**
355 * Mounts a shared folder.
356 *
357 * @returns VBox status code reflecting unmount and mount point preparation
358 * results, but not actual mounting
359 *
360 * @param pszShareName The shared folder name.
361 * @param pszMountPoint The mount point.
362 */
363static int vbsvcAutoMountSharedFolderOld(const char *pszShareName, const char *pszMountPoint)
364{
365 /*
366 * Linux and solaris share the same mount structure.
367 */
368 struct group *grp_vboxsf = getgrnam("vboxsf");
369 if (!grp_vboxsf)
370 {
371 VGSvcError("vbsvcAutoMountWorker: Group 'vboxsf' does not exist\n");
372 return VINF_SUCCESS;
373 }
374
375 struct vbsf_mount_opts Opts =
376 {
377 0, /* uid */
378 (int)grp_vboxsf->gr_gid, /* gid */
379 0, /* ttl */
380 0770, /* dmode, owner and group "vboxsf" have full access */
381 0770, /* fmode, owner and group "vboxsf" have full access */
382 0, /* dmask */
383 0, /* fmask */
384 0, /* ronly */
385 0, /* sloppy */
386 0, /* noexec */
387 0, /* nodev */
388 0, /* nosuid */
389 0, /* remount */
390 "\0", /* nls_name */
391 NULL, /* convertcp */
392 };
393
394 int rc = vbsvcAutoMountPrepareMountPointOld(pszMountPoint, pszShareName, &Opts);
395 if (RT_SUCCESS(rc))
396 {
397# ifdef RT_OS_SOLARIS
398 int fFlags = 0;
399 if (Opts.ronly)
400 fFlags |= MS_RDONLY;
401 char szOptBuf[MAX_MNTOPT_STR] = { '\0', };
402 RTStrPrintf(szOptBuf, sizeof(szOptBuf), "uid=%d,gid=%d,dmode=%0o,fmode=%0o,dmask=%0o,fmask=%0o",
403 Opts.uid, Opts.gid, Opts.dmode, Opts.fmode, Opts.dmask, Opts.fmask);
404 int r = mount(pszShareName,
405 pszMountPoint,
406 fFlags | MS_OPTIONSTR,
407 "vboxfs",
408 NULL, /* char *dataptr */
409 0, /* int datalen */
410 szOptBuf,
411 sizeof(szOptBuf));
412 if (r == 0)
413 VGSvcVerbose(0, "vbsvcAutoMountWorker: Shared folder '%s' was mounted to '%s'\n", pszShareName, pszMountPoint);
414 else if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
415 VGSvcError("vbsvcAutoMountWorker: Could not mount shared folder '%s' to '%s', error = %s\n",
416 pszShareName, pszMountPoint, strerror(errno));
417
418# else /* RT_OS_LINUX */
419 unsigned long fFlags = MS_NODEV;
420
421 /*const char *szOptions = { "rw" }; - ??? */
422 struct vbsf_mount_info_new mntinf;
423 RT_ZERO(mntinf);
424
425 mntinf.nullchar = '\0';
426 mntinf.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
427 mntinf.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
428 mntinf.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
429 mntinf.length = sizeof(mntinf);
430
431 mntinf.uid = Opts.uid;
432 mntinf.gid = Opts.gid;
433 mntinf.ttl = Opts.ttl;
434 mntinf.dmode = Opts.dmode;
435 mntinf.fmode = Opts.fmode;
436 mntinf.dmask = Opts.dmask;
437 mntinf.fmask = Opts.fmask;
438 mntinf.tag[0] = '\0';
439
440 strcpy(mntinf.name, pszShareName);
441 strcpy(mntinf.nls_name, "\0");
442
443 int r = mount(pszShareName,
444 pszMountPoint,
445 "vboxsf",
446 fFlags,
447 &mntinf);
448 if (r == 0)
449 {
450 VGSvcVerbose(0, "vbsvcAutoMountWorker: Shared folder '%s' was mounted to '%s'\n", pszShareName, pszMountPoint);
451
452 r = vbsfmount_complete(pszShareName, pszMountPoint, fFlags, &Opts);
453 switch (r)
454 {
455 case 0: /* Success. */
456 errno = 0; /* Clear all errors/warnings. */
457 break;
458
459 case 1:
460 VGSvcError("vbsvcAutoMountWorker: Could not update mount table (failed to create memstream): %s\n",
461 strerror(errno));
462 break;
463
464 case 2:
465 VGSvcError("vbsvcAutoMountWorker: Could not open mount table for update: %s\n", strerror(errno));
466 break;
467
468 case 3:
469 /* VGSvcError("vbsvcAutoMountWorker: Could not add an entry to the mount table: %s\n", strerror(errno)); */
470 errno = 0;
471 break;
472
473 default:
474 VGSvcError("vbsvcAutoMountWorker: Unknown error while completing mount operation: %d\n", r);
475 break;
476 }
477 }
478 else /* r == -1, we got some error in errno. */
479 {
480 if (errno == EPROTO)
481 {
482 VGSvcVerbose(3, "vbsvcAutoMountWorker: Messed up share name, re-trying ...\n");
483
484 /** @todo r=bird: What on earth is going on here????? Why can't you
485 * strcpy(mntinf.name, pszShareName) to fix it again? */
486
487 /* Sometimes the mount utility messes up the share name. Try to
488 * un-mangle it again. */
489 char szCWD[RTPATH_MAX];
490 size_t cchCWD;
491 if (!getcwd(szCWD, sizeof(szCWD)))
492 {
493 VGSvcError("vbsvcAutoMountWorker: Failed to get the current working directory\n");
494 szCWD[0] = '\0';
495 }
496 cchCWD = strlen(szCWD);
497 if (!strncmp(pszMountPoint, szCWD, cchCWD))
498 {
499 while (pszMountPoint[cchCWD] == '/')
500 ++cchCWD;
501 /* We checked before that we have enough space */
502 strcpy(mntinf.name, pszMountPoint + cchCWD);
503 }
504 r = mount(mntinf.name, pszMountPoint, "vboxsf", fFlags, &mntinf);
505 }
506 if (r == -1) /* Was there some error from one of the tries above? */
507 {
508 switch (errno)
509 {
510 /* If we get EINVAL here, the system already has mounted the Shared Folder to another
511 * mount point. */
512 case EINVAL:
513 VGSvcVerbose(0, "vbsvcAutoMountWorker: Shared folder '%s' already is mounted!\n", pszShareName);
514 /* Ignore this error! */
515 break;
516 case EBUSY:
517 /* Ignore these errors! */
518 break;
519
520 default:
521 VGSvcError("vbsvcAutoMountWorker: Could not mount shared folder '%s' to '%s': %s (%d)\n",
522 pszShareName, pszMountPoint, strerror(errno), errno);
523 rc = RTErrConvertFromErrno(errno);
524 break;
525 }
526 }
527 }
528# endif
529 }
530 VGSvcVerbose(3, "vbsvcAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
531 return rc;
532}
533
534
535/**
536 * Processes shared folder mappings retrieved from the host.
537 *
538 * @returns VBox status code.
539 * @param paMappings The mappings.
540 * @param cMappings The number of mappings.
541 * @param pszMountDir The mount directory.
542 * @param pszSharePrefix The share prefix.
543 * @param uClientID The shared folder service (HGCM) client ID.
544 */
545static int vbsvcAutoMountProcessMappingsOld(PCVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
546 const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
547{
548 if (cMappings == 0)
549 return VINF_SUCCESS;
550 AssertPtrReturn(paMappings, VERR_INVALID_PARAMETER);
551 AssertPtrReturn(pszMountDir, VERR_INVALID_PARAMETER);
552 AssertPtrReturn(pszSharePrefix, VERR_INVALID_PARAMETER);
553 AssertReturn(uClientID > 0, VERR_INVALID_PARAMETER);
554
555 /** @todo r=bird: Why is this loop schitzoid about status codes? It quits if
556 * RTPathJoin fails (i.e. if the user specifies a very long name), but happily
557 * continues if RTStrAPrintf failes (mem alloc).
558 *
559 * It also happily continues if the 'vboxsf' group is missing, which is a waste
560 * of effort... In fact, retrieving the group ID could probably be done up
561 * front, outside the loop. */
562 int rc = VINF_SUCCESS;
563 for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
564 {
565 char *pszShareName = NULL;
566 rc = VbglR3SharedFolderGetName(uClientID, paMappings[i].u32Root, &pszShareName);
567 if ( RT_SUCCESS(rc)
568 && *pszShareName)
569 {
570 VGSvcVerbose(3, "vbsvcAutoMountWorker: Connecting share %u (%s) ...\n", i+1, pszShareName);
571
572 /** @todo r=bird: why do you copy things twice here and waste heap space?
573 * szMountPoint has a fixed size.
574 * @code
575 * char szMountPoint[RTPATH_MAX];
576 * rc = RTPathJoin(szMountPoint, sizeof(szMountPoint), pszMountDir, *pszSharePrefix ? pszSharePrefix : pszShareName);
577 * if (RT_SUCCESS(rc) && *pszSharePrefix)
578 * rc = RTStrCat(szMountPoint, sizeof(szMountPoint), pszShareName);
579 * @endcode */
580 char *pszShareNameFull = NULL;
581 if (RTStrAPrintf(&pszShareNameFull, "%s%s", pszSharePrefix, pszShareName) > 0)
582 {
583 char szMountPoint[RTPATH_MAX];
584 rc = RTPathJoin(szMountPoint, sizeof(szMountPoint), pszMountDir, pszShareNameFull);
585 if (RT_SUCCESS(rc))
586 {
587 VGSvcVerbose(4, "vbsvcAutoMountWorker: Processing mount point '%s'\n", szMountPoint);
588
589 /*
590 * Already mounted?
591 */
592 /** @todo r-bird: this does not take into account that a shared folder could
593 * be mounted twice... We're really just interested in whether the
594 * folder is mounted on 'szMountPoint', no where else... */
595 bool fSkip = false;
596 char szAlreadyMountedOn[RTPATH_MAX];
597 if (vbsvcAutoMountShareIsMountedOld(pszShareName, szAlreadyMountedOn, sizeof(szAlreadyMountedOn)))
598 {
599 /* Do if it not mounted to our desired mount point */
600 if (RTStrICmp(szMountPoint, szAlreadyMountedOn))
601 {
602 VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted on '%s', unmounting ...\n",
603 pszShareName, szAlreadyMountedOn);
604 rc = vbsvcAutoMountUnmountOld(szAlreadyMountedOn);
605 if (RT_SUCCESS(rc))
606 fSkip = false;
607 else
608 VGSvcError("vbsvcAutoMountWorker: Failed to unmount '%s', %s (%d)! (rc=%Rrc)\n",
609 szAlreadyMountedOn, strerror(errno), errno, rc); /** @todo errno isn't reliable at this point */
610 }
611 if (fSkip)
612 VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted on '%s', skipping\n",
613 pszShareName, szAlreadyMountedOn);
614 }
615 if (!fSkip)
616 {
617 /*
618 * Mount it.
619 */
620 rc = vbsvcAutoMountSharedFolderOld(pszShareName, szMountPoint);
621 }
622 }
623 else
624 VGSvcError("vbsvcAutoMountWorker: Unable to join mount point/prefix/shrae, rc = %Rrc\n", rc);
625 RTStrFree(pszShareNameFull);
626 }
627 else
628 VGSvcError("vbsvcAutoMountWorker: Unable to allocate full share name\n");
629 RTStrFree(pszShareName);
630 }
631 else
632 VGSvcError("vbsvcAutoMountWorker: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
633 paMappings[i].u32Root, rc);
634 } /* for cMappings. */
635 return rc;
636}
637
638#endif /* defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) - the old code*/
639
640
641/**
642 * Service worker function for old host.
643 *
644 * This only mount stuff on startup.
645 *
646 * @returns VBox status code.
647 * @param pfShutdown Shutdown indicator.
648 */
649static int vbsvcAutoMountWorkerOld(bool volatile *pfShutdown)
650{
651#if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX)
652 /*
653 * We only do a single pass here.
654 */
655 uint32_t cMappings;
656 PVBGLR3SHAREDFOLDERMAPPING paMappings;
657 int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /* Only process auto-mounted folders */,
658 &paMappings, &cMappings);
659 if ( RT_SUCCESS(rc)
660 && cMappings)
661 {
662 char *pszMountDir;
663 rc = VbglR3SharedFolderGetMountDir(&pszMountDir);
664 if (rc == VERR_NOT_FOUND)
665 rc = RTStrDupEx(&pszMountDir, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR);
666 if (RT_SUCCESS(rc))
667 {
668 VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder mount dir set to '%s'\n", pszMountDir);
669
670 char *pszSharePrefix;
671 rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix);
672 if (RT_SUCCESS(rc))
673 {
674 VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder mount prefix set to '%s'\n", pszSharePrefix);
675# ifdef USE_VIRTUAL_SHARES
676 /* Check for a fixed/virtual auto-mount share. */
677 if (VbglR3SharedFolderExists(g_idClientSharedFolders, "vbsfAutoMount"))
678 VGSvcVerbose(3, "vbsvcAutoMountWorker: Host supports auto-mount root\n");
679 else
680 {
681# endif
682 VGSvcVerbose(3, "vbsvcAutoMountWorker: Got %u shared folder mappings\n", cMappings);
683 rc = vbsvcAutoMountProcessMappingsOld(paMappings, cMappings, pszMountDir, pszSharePrefix,
684 g_idClientSharedFolders);
685# ifdef USE_VIRTUAL_SHARES
686 }
687# endif
688 RTStrFree(pszSharePrefix);
689 } /* Mount share prefix. */
690 else
691 VGSvcError("vbsvcAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
692 RTStrFree(pszMountDir);
693 }
694 else
695 VGSvcError("vbsvcAutoMountWorker: Error while getting the shared folder directory, rc = %Rrc\n", rc);
696 VbglR3SharedFolderFreeMappings(paMappings);
697 }
698 else if (RT_FAILURE(rc))
699 VGSvcError("vbsvcAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
700 else
701 VGSvcVerbose(3, "vbsvcAutoMountWorker: No shared folder mappings found\n");
702
703#else
704 int rc = VINF_SUCCESS;
705#endif /* defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) */
706
707
708 /*
709 * Wait on shutdown (this used to be a silly RTThreadSleep(500) loop).
710 */
711 while (!*pfShutdown)
712 {
713 rc = RTSemEventMultiWait(g_hAutoMountEvent, RT_MS_1MIN);
714 if (rc != VERR_TIMEOUT)
715 break;
716 }
717
718 VGSvcVerbose(3, "vbsvcAutoMountWorkerOld: Finished with rc=%Rrc\n", rc);
719 return rc;
720}
721
722#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
723/**
724 * Assembles the mount directory and prefix into @a pszDst.
725 *
726 * Will fall back on defaults if we have trouble with the configuration from the
727 * host. This ASSUMES that @a cbDst is rather large and won't cause trouble
728 * with the default.
729 *
730 * @returns IPRT status code.
731 * @param pszDst Where to return the prefix.
732 * @param cbDst The size of the prefix buffer.
733 */
734static int vbsvcAutomounterQueryMountDirAndPrefix(char *pszDst, size_t cbDst)
735{
736 /*
737 * Query the config first.
738 */
739 /* Mount directory: */
740 const char *pszDir = VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR;
741 char *pszCfgDir;
742 int rc = VbglR3SharedFolderGetMountDir(&pszCfgDir);
743 if (RT_SUCCESS(rc))
744 {
745 if (*pszCfgDir == '/')
746 pszDir = pszCfgDir;
747 }
748 else
749 pszCfgDir = NULL;
750
751 /* Prefix: */
752 const char *pszPrefix = VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX;
753 char *pszCfgPrefix;
754 rc = VbglR3SharedFolderGetMountPrefix(&pszCfgPrefix);
755 if (RT_SUCCESS(rc))
756 {
757 if ( strchr(pszCfgPrefix, '/') == NULL
758 && strchr(pszCfgPrefix, '\\') == NULL
759 && strcmp(pszCfgPrefix, "..") != 0)
760 pszPrefix = pszCfgPrefix;
761 }
762 else
763 pszCfgPrefix = NULL;
764
765 /*
766 * Try combine the two.
767 */
768 rc = RTPathAbs(pszDir, pszDst, cbDst);
769 if (RT_SUCCESS(rc))
770 {
771 if (*pszPrefix)
772 {
773 rc = RTPathAppend(pszDst, cbDst, pszPrefix);
774 if (RT_FAILURE(rc))
775 VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathAppend(%s,,%s) -> %Rrc\n", pszDst, pszPrefix, rc);
776 }
777 else
778 {
779 rc = RTPathEnsureTrailingSeparator(pszDst, cbDst);
780 if (RT_FAILURE(rc))
781 VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathEnsureTrailingSeparator(%s) -> %Rrc\n", pszDst, rc);
782 }
783 }
784 else
785 VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathAbs(%s) -> %Rrc\n", pszDir, rc);
786
787
788 /*
789 * Return the default dir + prefix if the above failed.
790 */
791 if (RT_FAILURE(rc))
792 {
793 rc = RTStrCopy(pszDst, cbDst, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/" VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX);
794 AssertRC(rc);
795 }
796
797 RTStrFree(pszCfgDir);
798 RTStrFree(pszCfgPrefix);
799 return rc;
800}
801#endif /* !RT_OS_WINDOW && !RT_OS_OS2 */
802
803
804/**
805 * @callback_method_impl{FNRTSORTCMP, For sorting mount table by root ID. }
806 */
807static DECLCALLBACK(int) vbsvcAutomounterCompareEntry(void const *pvElement1, void const *pvElement2, void *pvUser)
808{
809 RT_NOREF_PV(pvUser);
810 PVBSVCAUTOMOUNTERENTRY pEntry1 = (PVBSVCAUTOMOUNTERENTRY)pvElement1;
811 PVBSVCAUTOMOUNTERENTRY pEntry2 = (PVBSVCAUTOMOUNTERENTRY)pvElement2;
812 return pEntry1->idRoot < pEntry2->idRoot ? -1
813 : pEntry1->idRoot > pEntry2->idRoot ? 1 : 0;
814}
815
816
817/**
818 * Worker for vbsvcAutomounterPopulateTable for adding discovered entries.
819 *
820 * This is puts dummies in for missing values, depending on
821 * vbsvcAutomounterPopulateTable to query them later.
822 *
823 * @returns VINF_SUCCESS or VERR_NO_MEMORY;
824 * @param pMountTable The mount table to add an entry to.
825 * @param pszName The shared folder name.
826 * @param pszMountPoint The mount point.
827 */
828static int vbsvcAutomounterAddEntry(PVBSVCAUTOMOUNTERTABLE pMountTable, const char *pszName, const char *pszMountPoint)
829{
830 VGSvcVerbose(2, "vbsvcAutomounterAddEntry: %s -> %s\n", pszMountPoint, pszName);
831 PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
832 pEntry->idRoot = UINT32_MAX;
833 pEntry->uRootIdVersion = UINT32_MAX;
834 pEntry->fFlags = UINT64_MAX;
835 pEntry->pszName = RTStrDup(pszName);
836 pEntry->pszMountPoint = NULL;
837 pEntry->pszActualMountPoint = RTStrDup(pszMountPoint);
838 if (pEntry->pszName && pEntry->pszActualMountPoint)
839 {
840 if (pMountTable->cEntries + 1 <= pMountTable->cAllocated)
841 {
842 pMountTable->papEntries[pMountTable->cEntries++] = pEntry;
843 return VINF_SUCCESS;
844 }
845
846 void *pvNew = RTMemRealloc(pMountTable->papEntries, (pMountTable->cAllocated + 8) * sizeof(pMountTable->papEntries[0]));
847 if (pvNew)
848 {
849 pMountTable->cAllocated += 8;
850 pMountTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvNew;
851
852 pMountTable->papEntries[pMountTable->cEntries++] = pEntry;
853 return VINF_SUCCESS;
854 }
855 }
856 RTMemFree(pEntry->pszActualMountPoint);
857 RTMemFree(pEntry->pszName);
858 RTMemFree(pEntry);
859 return VERR_NO_MEMORY;
860}
861
862
863/**
864 * Populates the mount table as best we can with existing automount entries.
865 *
866 * @returns VINF_SUCCESS or VERR_NO_MEMORY;
867 * @param pMountTable The mount table (empty).
868 */
869static int vbsvcAutomounterPopulateTable(PVBSVCAUTOMOUNTERTABLE pMountTable)
870{
871 int rc;
872
873#ifdef RT_OS_WINDOWS
874 /*
875 * Loop thru the drive letters and check out each of them using QueryDosDeviceW.
876 */
877 static const char s_szDevicePath[] = "\\Device\\VBoxMiniRdr\\;";
878 for (char chDrive = 'Z'; chDrive >= 'A'; chDrive--)
879 {
880 RTUTF16 const wszMountPoint[4] = { chDrive, ':', '\0', '\0' };
881 RTUTF16 wszTargetPath[RTPATH_MAX];
882 DWORD const cwcResult = QueryDosDeviceW(wszMountPoint, wszTargetPath, RT_ELEMENTS(wszTargetPath));
883 if ( cwcResult > sizeof(s_szDevicePath)
884 && RTUtf16NICmpAscii(wszTargetPath, RT_STR_TUPLE(s_szDevicePath)) == 0)
885 {
886 PCRTUTF16 pwsz = &wszTargetPath[RT_ELEMENTS(s_szDevicePath) - 1];
887 Assert(pwsz[-1] == ';');
888 if ( (pwsz[0] & ~(RTUTF16)0x20) == chDrive
889 && pwsz[1] == ':'
890 && pwsz[2] == '\\')
891 {
892 /* For now we'll just use the special capitalization of the
893 "server" name to identify it as our work. We could check
894 if the symlink is from \Global?? or \??, but that trick does
895 work for older OS versions (<= XP) or when running the
896 service manually for testing/wathever purposes. */
897 /** @todo Modify the windows shared folder driver to allow tagging drives.*/
898 if (RTUtf16NCmpAscii(&pwsz[3], RT_STR_TUPLE("VBoxSvr\\")) == 0)
899 {
900 pwsz += 3 + 8;
901 if (*pwsz != '\\' && *pwsz)
902 {
903 /* The shared folder name should follow immediately after the server prefix. */
904 char *pszMountedName = NULL;
905 rc = RTUtf16ToUtf8(pwsz, &pszMountedName);
906 if (RT_SUCCESS(rc))
907 {
908 char const szMountPoint[4] = { chDrive, ':', '\0', '\0' };
909 rc = vbsvcAutomounterAddEntry(pMountTable, pszMountedName, szMountPoint);
910 RTStrFree(pszMountedName);
911 }
912 if (RT_FAILURE(rc))
913 return rc;
914 }
915 else
916 VGSvcVerbose(2, "vbsvcAutomounterPopulateTable: Malformed, not ours: %ls -> %ls\n",
917 wszMountPoint, wszTargetPath);
918 }
919 else
920 VGSvcVerbose(3, "vbsvcAutomounterPopulateTable: Not ours: %ls -> %ls\n", wszMountPoint, wszTargetPath);
921 }
922 }
923 }
924
925#elif defined(RT_OS_OS2)
926 /*
927 * Just loop thru the drive letters and check the attachment of each.
928 */
929 for (char chDrive = 'Z'; chDrive >= 'A'; chDrive--)
930 {
931 char const szMountPoint[4] = { chDrive, ':', '\0', '\0' };
932 union
933 {
934 FSQBUFFER2 FsQueryBuf;
935 char achPadding[1024];
936 } uBuf;
937 RT_ZERO(uBuf);
938 ULONG cbBuf = sizeof(uBuf) - 2;
939 APIRET rcOs2 = DosQueryFSAttach(szMountPoint, 0, FSAIL_QUERYNAME, &uBuf.FsQueryBuf, &cbBuf);
940 if (rcOs2 == NO_ERROR)
941 {
942 const char *pszFsdName = (const char *)&uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
943 if ( uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
944 && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
945 {
946 const char *pszMountedName = (const char *)&pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
947 const char *pszTag = pszMountedName + strlen(pszMountedName) + 1; /* (Safe. Always two trailing zero bytes, see above.) */
948 if (strcmp(pszTag, g_szTag) == 0)
949 {
950 rc = vbsvcAutomounterAddEntry(pMountTable, pszMountedName, szMountPoint);
951 if (RT_FAILURE(rc))
952 return rc;
953 }
954 }
955 }
956 }
957
958#elif defined(RT_OS_LINUX)
959 /*
960 * Scan the mount table file for the mount point and then match file system
961 * and device/share. We identify our mounts by mount path + prefix for now,
962 * but later we may use the same approach as on solaris.
963 */
964 FILE *pFile = setmntent("/proc/mounts", "r");
965 int iErrMounts = errno;
966 if (!pFile)
967 pFile = setmntent("/etc/mtab", "r");
968 if (pFile)
969 {
970 rc = VWRN_NOT_FOUND;
971 struct mntent *pEntry;
972 while ((pEntry = getmntent(pFile)) != NULL)
973 if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
974 if (strstr(pEntry->mnt_opts, g_szTag) != NULL)
975 {
976 rc = vbsvcAutomounterAddEntry(pMountTable, pEntry->mnt_fsname, pEntry->mnt_dir);
977 if (RT_FAILURE(rc))
978 {
979 endmntent(pFile);
980 return rc;
981 }
982 }
983 endmntent(pFile);
984 }
985 else
986 VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d) or '/proc/mounts' (errno=%d)\n",
987 _PATH_MOUNTED, errno, iErrMounts);
988
989#elif defined(RT_OS_SOLARIS)
990 /*
991 * Look thru the system mount table and inspect the vboxsf mounts.
992 */
993 FILE *pFile = fopen(_PATH_MOUNTED, "r");
994 if (pFile)
995 {
996 rc = VINF_SUCCESS;
997 struct mnttab Entry;
998 while (getmntent(pFile, &Entry) == 0)
999 if (strcmp(Entry.mnt_fstype, "vboxfs") == 0)
1000 {
1001 /* Look for the dummy automounter option. */
1002 if ( Entry.mnt_mntopts != NULL
1003 && strstr(Entry.mnt_mntopts, g_szTag) != NULL)
1004 {
1005 rc = vbsvcAutomounterAddEntry(pMountTable, Entry.mnt_special, Entry.mnt_mountp);
1006 if (RT_FAILURE(rc))
1007 {
1008 fclose(pFile);
1009 return rc;
1010 }
1011 }
1012 }
1013 fclose(pFile);
1014 }
1015 else
1016 VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
1017
1018#else
1019# error "PORTME!"
1020#endif
1021
1022 /*
1023 * Try reconcile the detected folders with data from the host.
1024 */
1025 uint32_t cMappings = 0;
1026 PVBGLR3SHAREDFOLDERMAPPING paMappings = NULL;
1027 rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
1028 if (RT_SUCCESS(rc))
1029 {
1030 for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
1031 {
1032 uint32_t const idRootSrc = paMappings[i].u32Root;
1033
1034 uint32_t uRootIdVer = UINT32_MAX;
1035 uint64_t fFlags = 0;
1036 char *pszName = NULL;
1037 char *pszMntPt = NULL;
1038 int rc2 = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
1039 &pszName, &pszMntPt, &fFlags, &uRootIdVer);
1040 if (RT_SUCCESS(rc2))
1041 {
1042 uint32_t iPrevHit = UINT32_MAX;
1043 for (uint32_t iTable = 0; iTable < pMountTable->cEntries; iTable++)
1044 {
1045 PVBSVCAUTOMOUNTERENTRY pEntry = pMountTable->papEntries[iTable];
1046 if (RTStrICmp(pEntry->pszName, pszName) == 0)
1047 {
1048 VGSvcVerbose(2, "vbsvcAutomounterPopulateTable: Identified %s -> %s: idRoot=%u ver=%u fFlags=%#x AutoMntPt=%s\n",
1049 pEntry->pszActualMountPoint, pEntry->pszName, idRootSrc, uRootIdVer, fFlags, pszMntPt);
1050 pEntry->fFlags = fFlags;
1051 pEntry->idRoot = idRootSrc;
1052 pEntry->uRootIdVersion = uRootIdVer;
1053 RTStrFree(pEntry->pszMountPoint);
1054 pEntry->pszMountPoint = RTStrDup(pszMntPt);
1055 if (!pEntry->pszMountPoint)
1056 {
1057 rc = VERR_NO_MEMORY;
1058 break;
1059 }
1060
1061 /* If multiple mappings of the same folder, pick the first or the one
1062 with matching mount point. */
1063 if (iPrevHit == UINT32_MAX)
1064 iPrevHit = iTable;
1065 else if (RTPathCompare(pszMntPt, pEntry->pszActualMountPoint) == 0)
1066 {
1067 if (iPrevHit != UINT32_MAX)
1068 pMountTable->papEntries[iPrevHit]->uRootIdVersion -= 1;
1069 iPrevHit = iTable;
1070 }
1071 else
1072 pEntry->uRootIdVersion -= 1;
1073 }
1074 }
1075
1076 RTStrFree(pszName);
1077 RTStrFree(pszMntPt);
1078 }
1079 else
1080 VGSvcError("vbsvcAutomounterPopulateTable: VbglR3SharedFolderQueryFolderInfo(%u) failed: %Rrc\n", idRootSrc, rc2);
1081 }
1082
1083 VbglR3SharedFolderFreeMappings(paMappings);
1084
1085 /*
1086 * Sort the table by root ID.
1087 */
1088 if (pMountTable->cEntries > 1)
1089 RTSortApvShell((void **)pMountTable->papEntries, pMountTable->cEntries, vbsvcAutomounterCompareEntry, NULL);
1090
1091 for (uint32_t iTable = 0; iTable < pMountTable->cEntries; iTable++)
1092 {
1093 PVBSVCAUTOMOUNTERENTRY pEntry = pMountTable->papEntries[iTable];
1094 if (pMountTable->papEntries[iTable]->idRoot != UINT32_MAX)
1095 VGSvcVerbose(1, "vbsvcAutomounterPopulateTable: #%u: %s -> %s idRoot=%u ver=%u fFlags=%#x AutoMntPt=%s\n",
1096 iTable, pEntry->pszActualMountPoint, pEntry->pszName, pEntry->idRoot, pEntry->uRootIdVersion,
1097 pEntry->fFlags, pEntry->pszMountPoint);
1098 else
1099 VGSvcVerbose(1, "vbsvcAutomounterPopulateTable: #%u: %s -> %s - not identified!\n",
1100 iTable, pEntry->pszActualMountPoint, pEntry->pszName);
1101 }
1102 }
1103 else
1104 VGSvcError("vbsvcAutomounterPopulateTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
1105 return rc;
1106}
1107
1108
1109/**
1110 * Checks whether the shared folder @a pszName is mounted on @a pszMountPoint.
1111 *
1112 * @returns Exactly one of the following IPRT status codes;
1113 * @retval VINF_SUCCESS if mounted
1114 * @retval VWRN_NOT_FOUND if nothing is mounted at @a pszMountPoint.
1115 * @retval VERR_RESOURCE_BUSY if a different shared folder is mounted there.
1116 * @retval VERR_ACCESS_DENIED if a non-shared folder file system is mounted
1117 * there.
1118 *
1119 * @param pszMountPoint The mount point to check.
1120 * @param pszName The name of the shared folder (mapping).
1121 */
1122static int vbsvcAutomounterQueryMountPoint(const char *pszMountPoint, const char *pszName)
1123{
1124 VGSvcVerbose(4, "vbsvcAutomounterQueryMountPoint: pszMountPoint=%s pszName=%s\n", pszMountPoint, pszName);
1125
1126#ifdef RT_OS_WINDOWS
1127 /*
1128 * We could've used RTFsQueryType here but would then have to
1129 * calling RTFsQueryLabel for the share name hint, ending up
1130 * doing the same work twice. We could also use QueryDosDeviceW,
1131 * but output is less clear...
1132 */
1133 PRTUTF16 pwszMountPoint = NULL;
1134 int rc = RTStrToUtf16(pszMountPoint, &pwszMountPoint);
1135 if (RT_SUCCESS(rc))
1136 {
1137 DWORD uSerial = 0;
1138 DWORD cchCompMax = 0;
1139 DWORD fFlags = 0;
1140 RTUTF16 wszLabel[512];
1141 RTUTF16 wszFileSystem[256];
1142 RT_ZERO(wszLabel);
1143 RT_ZERO(wszFileSystem);
1144 if (GetVolumeInformationW(pwszMountPoint, wszLabel, RT_ELEMENTS(wszLabel) - 1, &uSerial, &cchCompMax, &fFlags,
1145 wszFileSystem, RT_ELEMENTS(wszFileSystem) - 1))
1146 {
1147 if (RTUtf16ICmpAscii(wszFileSystem, "VBoxSharedFolderFS") == 0)
1148 {
1149 char *pszLabel = NULL;
1150 rc = RTUtf16ToUtf8(wszLabel, &pszLabel);
1151 if (RT_SUCCESS(rc))
1152 {
1153 const char *pszMountedName = pszLabel;
1154 if (RTStrStartsWith(pszMountedName, "VBOX_"))
1155 pszMountedName += sizeof("VBOX_") - 1;
1156 if (RTStrICmp(pszMountedName, pszName) == 0)
1157 {
1158 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1159 pszName, pszMountPoint);
1160 rc = VINF_SUCCESS;
1161 }
1162 else
1163 {
1164 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1165 pszMountedName, pszMountPoint, pszName);
1166 rc = VERR_RESOURCE_BUSY;
1167 }
1168 RTStrFree(pszLabel);
1169 }
1170 else
1171 {
1172 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: RTUtf16ToUtf8(%ls,) failed: %Rrc\n", wszLabel, rc);
1173 rc = VERR_RESOURCE_BUSY;
1174 }
1175 }
1176 else
1177 {
1178 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%ls' with label '%ls' mount at '%s', not '%s'...\n",
1179 wszFileSystem, wszLabel, pszMountPoint, pszName);
1180 rc = VERR_ACCESS_DENIED;
1181 }
1182 }
1183 else
1184 {
1185 rc = GetLastError();
1186 if (rc != ERROR_PATH_NOT_FOUND || g_cVerbosity >= 4)
1187 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: GetVolumeInformationW('%ls',,,,) failed: %u\n", pwszMountPoint, rc);
1188 rc = VWRN_NOT_FOUND;
1189 }
1190 RTUtf16Free(pwszMountPoint);
1191 }
1192 else
1193 {
1194 VGSvcError("vbsvcAutomounterQueryMountPoint: RTStrToUtf16(%s,) -> %Rrc\n", pszMountPoint, rc);
1195 rc = VWRN_NOT_FOUND;
1196 }
1197 return rc;
1198
1199#elif defined(RT_OS_OS2)
1200 /*
1201 * Query file system attachment info for the given drive letter.
1202 */
1203 union
1204 {
1205 FSQBUFFER2 FsQueryBuf;
1206 char achPadding[512];
1207 } uBuf;
1208 RT_ZERO(uBuf);
1209
1210 ULONG cbBuf = sizeof(uBuf);
1211 APIRET rcOs2 = DosQueryFSAttach(pszMountPoint, 0, FSAIL_QUERYNAME, &uBuf.FsQueryBuf, &cbBuf);
1212 int rc;
1213 if (rcOs2 == NO_ERROR)
1214 {
1215 const char *pszFsdName = (const char *)&uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
1216 if ( uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
1217 && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
1218 {
1219 const char *pszMountedName = (const char *)&pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
1220 if (RTStrICmp(pszMountedName, pszName) == 0)
1221 {
1222 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1223 pszName, pszMountPoint);
1224 rc = VINF_SUCCESS;
1225 }
1226 else
1227 {
1228 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1229 pszMountedName, pszMountPoint, pszName);
1230 rc = VERR_RESOURCE_BUSY;
1231 }
1232 }
1233 else
1234 {
1235 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' type %u mount at '%s', not '%s'...\n",
1236 pszFsdName, uBuf.FsQueryBuf.iType, pszMountPoint, pszName);
1237 rc = VERR_ACCESS_DENIED;
1238 }
1239 }
1240 else
1241 {
1242 rc = VWRN_NOT_FOUND;
1243 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: DosQueryFSAttach(%s) -> %u\n", pszMountPoint, rcOs2);
1244 AssertMsgStmt(rcOs2 != ERROR_BUFFER_OVERFLOW && rcOs2 != ERROR_INVALID_PARAMETER,
1245 ("%s -> %u\n", pszMountPoint, rcOs2), rc = VERR_ACCESS_DENIED);
1246 }
1247 return rc;
1248
1249#elif defined(RT_OS_LINUX)
1250 /*
1251 * Scan one of the mount table file for the mount point and then
1252 * match file system and device/share.
1253 */
1254 FILE *pFile = setmntent("/proc/mounts", "r");
1255 int rc = errno;
1256 if (!pFile)
1257 pFile = setmntent(_PATH_MOUNTED, "r");
1258 if (pFile)
1259 {
1260 rc = VWRN_NOT_FOUND;
1261 struct mntent *pEntry;
1262 while ((pEntry = getmntent(pFile)) != NULL)
1263 if (RTPathCompare(pEntry->mnt_dir, pszMountPoint) == 0)
1264 {
1265 if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
1266 {
1267 if (RTStrICmp(pEntry->mnt_fsname, pszName) == 0)
1268 {
1269 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1270 pszName, pszMountPoint);
1271 rc = VINF_SUCCESS;
1272 }
1273 else
1274 {
1275 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1276 pEntry->mnt_fsname, pszMountPoint, pszName);
1277 rc = VERR_RESOURCE_BUSY;
1278 }
1279 }
1280 else
1281 {
1282 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
1283 pEntry->mnt_type, pEntry->mnt_fsname, pszMountPoint, pszName);
1284 rc = VERR_ACCESS_DENIED;
1285 }
1286 /* We continue searching in case of stacked mounts, we want the last one. */
1287 }
1288 endmntent(pFile);
1289 }
1290 else
1291 {
1292 VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '/proc/mounts' (errno=%d) or '%s' (errno=%d)\n",
1293 rc, _PATH_MOUNTED, errno);
1294 rc = VERR_ACCESS_DENIED;
1295 }
1296 return rc;
1297
1298#elif defined(RT_OS_SOLARIS)
1299 /*
1300 * Similar to linux.
1301 */
1302 int rc;
1303 FILE *pFile = fopen(_PATH_MOUNTED, "r");
1304 if (pFile)
1305 {
1306 rc = VWRN_NOT_FOUND;
1307 struct mnttab Entry;
1308 while (getmntent(pFile, &Entry) == 0)
1309 if (RTPathCompare(Entry.mnt_mountp, pszMountPoint) == 0)
1310 {
1311 if (strcmp(Entry.mnt_fstype, "vboxfs") == 0)
1312 {
1313 if (RTStrICmp(Entry.mnt_special, pszName) == 0)
1314 {
1315 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1316 pszName, pszMountPoint);
1317 rc = VINF_SUCCESS;
1318 }
1319 else
1320 {
1321 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1322 Entry.mnt_special, pszMountPoint, pszName);
1323 rc = VERR_RESOURCE_BUSY;
1324 }
1325 }
1326 else
1327 {
1328 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
1329 Entry.mnt_fstype, Entry.mnt_special, pszMountPoint, pszName);
1330 rc = VERR_ACCESS_DENIED;
1331 }
1332 /* We continue searching in case of stacked mounts, we want the last one. */
1333 }
1334 fclose(pFile);
1335 }
1336 else
1337 {
1338 VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
1339 rc = VERR_ACCESS_DENIED;
1340 }
1341 return rc;
1342#else
1343# error "PORTME"
1344#endif
1345}
1346
1347
1348/**
1349 * Worker for vbsvcAutomounterMountNewEntry that does the OS mounting.
1350 *
1351 * @returns IPRT status code.
1352 * @param pEntry The entry to try mount.
1353 */
1354static int vbsvcAutomounterMountIt(PVBSVCAUTOMOUNTERENTRY pEntry)
1355{
1356 VGSvcVerbose(3, "vbsvcAutomounterMountIt: Trying to mount '%s' (idRoot=%#x) on '%s'...\n",
1357 pEntry->pszName, pEntry->idRoot, pEntry->pszActualMountPoint);
1358#ifdef RT_OS_WINDOWS
1359 /*
1360 * Attach the shared folder using WNetAddConnection2W.
1361 *
1362 * According to google we should get a drive symlink in \\GLOBAL?? when
1363 * we are running under the system account. Otherwise it will a session
1364 * local link (\\??).
1365 */
1366 Assert(RT_C_IS_UPPER(pEntry->pszActualMountPoint[0]) && pEntry->pszActualMountPoint[1] == ':' && pEntry->pszActualMountPoint[2] == '\0');
1367 RTUTF16 wszDrive[4] = { pEntry->pszActualMountPoint[0], ':', '\0', '\0' };
1368
1369 RTUTF16 wszPrefixedName[RTPATH_MAX];
1370 int rc = RTUtf16CopyAscii(wszPrefixedName, RT_ELEMENTS(wszPrefixedName), "\\\\VBoxSvr\\");
1371 AssertRC(rc);
1372
1373 size_t const offName = RTUtf16Len(wszPrefixedName);
1374 PRTUTF16 pwszName = &wszPrefixedName[offName];
1375 rc = RTStrToUtf16Ex(pEntry->pszName, RTSTR_MAX, &pwszName, sizeof(wszPrefixedName) - offName, NULL);
1376 if (RT_FAILURE(rc))
1377 {
1378 VGSvcError("vbsvcAutomounterMountIt: RTStrToUtf16Ex failed on '%s': %Rrc\n", pEntry->pszName, rc);
1379 return rc;
1380 }
1381
1382 NETRESOURCEW NetRsrc;
1383 RT_ZERO(NetRsrc);
1384 NetRsrc.dwType = RESOURCETYPE_DISK;
1385 NetRsrc.lpLocalName = wszDrive;
1386 NetRsrc.lpRemoteName = wszPrefixedName;
1387 NetRsrc.lpProvider = L"VirtualBox Shared Folders"; /* Only try our provider. */
1388 NetRsrc.lpComment = pwszName;
1389
1390 DWORD dwErr = WNetAddConnection2W(&NetRsrc, NULL /*pwszPassword*/, NULL /*pwszUserName*/, 0 /*dwFlags*/);
1391 if (dwErr == NO_ERROR)
1392 {
1393 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1394 pEntry->pszName, pEntry->pszActualMountPoint);
1395 return VINF_SUCCESS;
1396 }
1397 VGSvcError("vbsvcAutomounterMountIt: Failed to attach '%s' to '%s': %u\n",
1398 pEntry->pszName, pEntry->pszActualMountPoint, rc);
1399 return VERR_OPEN_FAILED;
1400
1401#elif defined(RT_OS_OS2)
1402 /*
1403 * It's a rather simple affair on OS/2.
1404 *
1405 * In order to be able to detect our mounts we add a 2nd string after
1406 * the folder name that tags the attachment. The IFS will remember this
1407 * and return it when DosQueryFSAttach is called.
1408 *
1409 * Note! Kernel currently accepts limited 7-bit ASCII names. We could
1410 * change that to UTF-8 if we like as that means no extra string
1411 * encoding conversion fun here.
1412 */
1413 char szzNameAndTag[256];
1414 size_t cchName = strlen(pEntry->pszName);
1415 if (cchName + 1 + sizeof(g_szTag) <= sizeof(szzNameAndTag))
1416 {
1417 memcpy(szzNameAndTag, pEntry->pszName, cchName);
1418 szzNameAndTag[cchName] = '\0';
1419 memcpy(&szzNameAndTag[cchName + 1], g_szTag, sizeof(g_szTag));
1420
1421 APIRET rc = DosFSAttach(pEntry->pszActualMountPoint, "VBOXSF", szzNameAndTag, cchName + 1 + sizeof(g_szTag), FS_ATTACH);
1422 if (rc == NO_ERROR)
1423 {
1424 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1425 pEntry->pszName, pEntry->pszActualMountPoint);
1426 return VINF_SUCCESS;
1427 }
1428 VGSvcError("vbsvcAutomounterMountIt: DosFSAttach failed to attach '%s' to '%s': %u\n",
1429 pEntry->pszName, pEntry->pszActualMountPoint, rc);
1430 }
1431 else
1432 VGSvcError("vbsvcAutomounterMountIt: Share name for attach to '%s' is too long: %u chars - '%s'\n",
1433 pEntry->pszActualMountPoint, cchName, pEntry->pszName);
1434 return VERR_OPEN_FAILED;
1435
1436#else
1437 /*
1438 * Common work for unix-like systems: Get group, make sure mount directory exist.
1439 */
1440 int rc = RTDirCreateFullPath(pEntry->pszActualMountPoint,
1441 RTFS_UNIX_IRWXU | RTFS_UNIX_IXGRP | RTFS_UNIX_IRGRP | RTFS_UNIX_IXOTH | RTFS_UNIX_IROTH);
1442 if (RT_FAILURE(rc))
1443 {
1444 VGSvcError("vbsvcAutomounterMountIt: Failed to create mount path '%s' for share '%s': %Rrc\n",
1445 pEntry->pszActualMountPoint, pEntry->pszName, rc);
1446 return rc;
1447 }
1448
1449 gid_t gidMount;
1450 struct group *grp_vboxsf = getgrnam("vboxsf");
1451 if (grp_vboxsf)
1452 gidMount = grp_vboxsf->gr_gid;
1453 else
1454 {
1455 VGSvcError("vbsvcAutomounterMountIt: Group 'vboxsf' does not exist\n");
1456 gidMount = 0;
1457 }
1458
1459# if defined(RT_OS_LINUX)
1460 /*
1461 * Linux a bit more work...
1462 */
1463 struct vbsf_mount_info_new MntInfo;
1464 RT_ZERO(MntInfo);
1465 struct vbsf_mount_opts MntOpts;
1466 RT_ZERO(MntOpts);
1467 MntInfo.nullchar = '\0';
1468 MntInfo.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
1469 MntInfo.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
1470 MntInfo.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
1471 MntInfo.length = sizeof(MntInfo);
1472 MntInfo.uid = MntOpts.uid = 0;
1473 MntInfo.gid = MntOpts.gid = gidMount;
1474 MntInfo.dmode = MntOpts.dmode = 0770;
1475 MntInfo.fmode = MntOpts.fmode = 0770;
1476 MntInfo.dmask = MntOpts.dmask = 0000;
1477 MntInfo.fmask = MntOpts.fmask = 0000;
1478 memcpy(MntInfo.tag, g_szTag, sizeof(g_szTag)); AssertCompile(sizeof(MntInfo.tag) >= sizeof(g_szTag));
1479 rc = RTStrCopy(MntInfo.name, sizeof(MntInfo.name), pEntry->pszName);
1480 if (RT_FAILURE(rc))
1481 {
1482 VGSvcError("vbsvcAutomounterMountIt: Share name '%s' is too long for the MntInfo.name field!\n", pEntry->pszName);
1483 return rc;
1484 }
1485
1486 errno = 0;
1487 unsigned long fFlags = MS_NODEV;
1488 rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, "vboxsf", fFlags, &MntInfo);
1489 if (rc == 0)
1490 {
1491 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1492 pEntry->pszName, pEntry->pszActualMountPoint);
1493
1494 errno = 0;
1495 rc = vbsfmount_complete(pEntry->pszName, pEntry->pszActualMountPoint, fFlags, &MntOpts);
1496 if (rc != 0) /* Ignorable. /etc/mtab is probably a link to /proc/mounts. */
1497 VGSvcVerbose(1, "vbsvcAutomounterMountIt: vbsfmount_complete failed: %s (%d/%d)\n",
1498 rc == 1 ? "open_memstream" : rc == 2 ? "setmntent" : rc == 3 ? "addmntent" : "unknown", rc, errno);
1499 return VINF_SUCCESS;
1500 }
1501 else if (errno == EINVAL)
1502 VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s' because it is probably mounted elsewhere arleady! (%d,%d)\n",
1503 pEntry->pszName, pEntry->pszActualMountPoint, rc, errno);
1504 else
1505 VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s': %s (%d,%d)\n",
1506 pEntry->pszName, pEntry->pszActualMountPoint, strerror(errno), rc, errno);
1507 return VERR_WRITE_ERROR;
1508
1509# elif defined(RT_OS_SOLARIS)
1510 /*
1511 * Solaris is rather simple compared to linux.
1512 *
1513 * The ',VBoxService=auto' option (g_szTag) is ignored by the kernel but helps
1514 * us identify our own mounts on restart. See vbsvcAutomounterPopulateTable().
1515 *
1516 * Note! Must pass MAX_MNTOPT_STR rather than cchOpts to mount, as it may fail
1517 * with EOVERFLOW in vfs_buildoptionstr() during domount() otherwise.
1518 */
1519 char szOpts[MAX_MNTOPT_STR] = { '\0', };
1520 ssize_t cchOpts = RTStrPrintf2(szOpts, sizeof(szOpts),
1521 "uid=0,gid=%d,dmode=0770,fmode=0770,dmask=0000,fmask=0000,tag=%s", gidMount, g_szTag);
1522 if (cchOpts <= 0)
1523 {
1524 VGSvcError("vbsvcAutomounterMountIt: szOpts overflow! %zd\n", cchOpts);
1525 return VERR_BUFFER_OVERFLOW;
1526 }
1527
1528 rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, MS_OPTIONSTR, "vboxfs",
1529 NULL /*dataptr*/, 0 /* datalen */, szOpts, MAX_MNTOPT_STR);
1530 if (rc == 0)
1531 {
1532 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1533 pEntry->pszName, pEntry->pszActualMountPoint);
1534 return VINF_SUCCESS;
1535 }
1536
1537 rc = errno;
1538 VGSvcError("vbsvcAutomounterMountIt: mount failed for '%s' on '%s' (szOpts=%s): %s (%d)\n",
1539 pEntry->pszName, pEntry->pszActualMountPoint, szOpts, strerror(rc), rc);
1540 return VERR_OPEN_FAILED;
1541
1542# else
1543# error "PORTME!"
1544# endif
1545#endif
1546}
1547
1548
1549/**
1550 * Attempts to mount the given shared folder, adding it to the mount table on
1551 * success.
1552 *
1553 * @returns iTable + 1 on success, iTable on failure.
1554 * @param pTable The mount table.
1555 * @param iTable The mount table index at which to add the mount.
1556 * @param pszName The name of the shared folder mapping.
1557 * @param pszMntPt The mount point (hint) specified by the host.
1558 * @param fFlags The shared folder flags, SHFL_MIF_XXX.
1559 * @param idRoot The root ID.
1560 * @param uRootIdVersion The root ID version.
1561 * @param fAutoMntPt Whether to try automatically assign a mount point if
1562 * pszMntPt doesn't work out. This is set in pass \#3.
1563 */
1564static uint32_t vbsvcAutomounterMountNewEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable,
1565 const char *pszName, const char *pszMntPt, uint64_t fFlags,
1566 uint32_t idRoot, uint32_t uRootIdVersion, bool fAutoMntPt)
1567{
1568 VGSvcVerbose(3, "vbsvcAutomounterMountNewEntry: #%u: '%s' at '%s'%s\n",
1569 iTable, pszName, pszMntPt, fAutoMntPt ? " auto-assign" : "");
1570
1571 /*
1572 * First we need to figure out the actual mount point.
1573 */
1574 char szActualMountPoint[RTPATH_MAX];
1575
1576#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
1577 /*
1578 * Drive letter based. We only care about the first two characters
1579 * and ignore the rest (see further down).
1580 */
1581 char chNextLetter = 'Z';
1582 if (RT_C_IS_ALPHA(pszMntPt[0]) && pszMntPt[1] == ':')
1583 szActualMountPoint[0] = RT_C_TO_UPPER(pszMntPt[0]);
1584 else if (!fAutoMntPt)
1585 return iTable;
1586 else
1587 szActualMountPoint[0] = chNextLetter--;
1588 szActualMountPoint[1] = ':';
1589 szActualMountPoint[2] = '\0';
1590
1591 int rc;
1592 for (;;)
1593 {
1594 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1595 if (rc == VWRN_NOT_FOUND)
1596 break;
1597
1598 /* next */
1599 if (chNextLetter == 'A' || !fAutoMntPt)
1600 return iTable;
1601 szActualMountPoint[0] = chNextLetter--;
1602 }
1603
1604#else
1605 /*
1606 * Path based #1: Host specified mount point.
1607 */
1608
1609 /* Skip DOS drive letter if there is a UNIX mount point path following it: */
1610 if ( pszMntPt[0] != '/'
1611 && pszMntPt[0] != '\0'
1612 && pszMntPt[1] == ':'
1613 && pszMntPt[2] == '/')
1614 pszMntPt += 2;
1615
1616 /* Try specified mount point if it starts with a UNIX slash: */
1617 int rc = VERR_ACCESS_DENIED;
1618 if (*pszMntPt == '/')
1619 {
1620 rc = RTPathAbs(pszMntPt, szActualMountPoint, sizeof(szActualMountPoint));
1621 if (RT_SUCCESS(rc))
1622 {
1623 static const char * const s_apszBlacklist[] =
1624 { "/", "/dev", "/bin", "/sbin", "/lib", "/etc", "/var", "/tmp", "/usr", "/usr/bin", "/usr/sbin", "/usr/lib" };
1625 for (size_t i = 0; i < RT_ELEMENTS(s_apszBlacklist); i++)
1626 if (strcmp(szActualMountPoint, s_apszBlacklist[i]) == 0)
1627 {
1628 rc = VERR_ACCESS_DENIED;
1629 break;
1630 }
1631 if (RT_SUCCESS(rc))
1632 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1633 }
1634 }
1635 if (rc != VWRN_NOT_FOUND)
1636 {
1637 if (!fAutoMntPt)
1638 return iTable;
1639
1640 /*
1641 * Path based #2: Mount dir + prefix + share.
1642 */
1643 rc = vbsvcAutomounterQueryMountDirAndPrefix(szActualMountPoint, sizeof(szActualMountPoint));
1644 if (RT_SUCCESS(rc))
1645 {
1646 /* Append a sanitized share name: */
1647 size_t const offShare = strlen(szActualMountPoint);
1648 size_t offDst = offShare;
1649 size_t offSrc = 0;
1650 for (;;)
1651 {
1652 char ch = pszName[offSrc++];
1653 if (ch == ' ' || ch == '/' || ch == '\\' || ch == ':' || ch == '$')
1654 ch = '_';
1655 else if (!ch)
1656 break;
1657 else if (ch < 0x20 || ch == 0x7f)
1658 continue;
1659 if (offDst < sizeof(szActualMountPoint) - 1)
1660 szActualMountPoint[offDst++] = ch;
1661 }
1662 szActualMountPoint[offDst] = '\0';
1663 if (offDst > offShare)
1664 {
1665 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1666 if (rc != VWRN_NOT_FOUND)
1667 {
1668 /*
1669 * Path based #3: Mount dir + prefix + share + _ + number.
1670 */
1671 if (offDst + 2 >= sizeof(szActualMountPoint))
1672 return iTable;
1673
1674 szActualMountPoint[offDst++] = '_';
1675 for (uint32_t iTry = 1; iTry < 10 && rc != VWRN_NOT_FOUND; iTry++)
1676 {
1677 szActualMountPoint[offDst] = '0' + iTry;
1678 szActualMountPoint[offDst + 1] = '\0';
1679 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1680 }
1681 if (rc != VWRN_NOT_FOUND)
1682 return iTable;
1683 }
1684 }
1685 else
1686 VGSvcError("vbsvcAutomounterMountNewEntry: Bad share name: %.*Rhxs", strlen(pszName), pszName);
1687 }
1688 else
1689 VGSvcError("vbsvcAutomounterMountNewEntry: Failed to construct basic auto mount point for '%s'", pszName);
1690 }
1691#endif
1692
1693 /*
1694 * Prepare a table entry and ensure space in the table..
1695 */
1696 if (pTable->cEntries + 1 > pTable->cAllocated)
1697 {
1698 void *pvEntries = RTMemRealloc(pTable->papEntries, sizeof(pTable->papEntries[0]) * (pTable->cAllocated + 8));
1699 if (!pvEntries)
1700 {
1701 VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for growing table (size %u)\n", pTable->cAllocated);
1702 return iTable;
1703 }
1704 pTable->cAllocated += 8;
1705 pTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvEntries;
1706 }
1707
1708 PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
1709 if (pEntry)
1710 {
1711 pEntry->idRoot = idRoot;
1712 pEntry->uRootIdVersion = uRootIdVersion;
1713 pEntry->fFlags = fFlags;
1714 pEntry->pszName = RTStrDup(pszName);
1715 pEntry->pszMountPoint = RTStrDup(pszMntPt);
1716 pEntry->pszActualMountPoint = RTStrDup(szActualMountPoint);
1717 if (pEntry->pszName && pEntry->pszMountPoint && pEntry->pszActualMountPoint)
1718 {
1719 /*
1720 * Now try mount it.
1721 */
1722 rc = vbsvcAutomounterMountIt(pEntry);
1723 if (RT_SUCCESS(rc))
1724 {
1725 uint32_t cToMove = pTable->cEntries - iTable;
1726 if (cToMove > 0)
1727 memmove(&pTable->papEntries[iTable + 1], &pTable->papEntries[iTable], cToMove * sizeof(pTable->papEntries[0]));
1728 pTable->papEntries[iTable] = pEntry;
1729 pTable->cEntries++;
1730 return iTable + 1;
1731 }
1732 }
1733 else
1734 VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
1735 RTMemFree(pEntry->pszActualMountPoint);
1736 RTMemFree(pEntry->pszMountPoint);
1737 RTMemFree(pEntry->pszName);
1738 RTMemFree(pEntry);
1739 }
1740 else
1741 VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
1742 return iTable;
1743}
1744
1745
1746
1747/**
1748 * Does the actual unmounting.
1749 *
1750 * @returns Exactly one of the following IPRT status codes;
1751 * @retval VINF_SUCCESS if successfully umounted or nothing was mounted there.
1752 * @retval VERR_TRY_AGAIN if the shared folder is busy.
1753 * @retval VERR_RESOURCE_BUSY if a different shared folder is mounted there.
1754 * @retval VERR_ACCESS_DENIED if a non-shared folder file system is mounted
1755 * there.
1756 *
1757 * @param pszMountPoint The mount point.
1758 * @param pszName The shared folder (mapping) name.
1759 */
1760static int vbsvcAutomounterUnmount(const char *pszMountPoint, const char *pszName)
1761{
1762 /*
1763 * Retry for 5 seconds in a hope that busy mounts will quiet down.
1764 */
1765 for (unsigned iTry = 0; ; iTry++)
1766 {
1767 /*
1768 * Check what's mounted there before we start umounting stuff.
1769 */
1770 int rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
1771 if (rc == VINF_SUCCESS)
1772 { /* pszName is mounted there */ }
1773 else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
1774 return VINF_SUCCESS;
1775 else
1776 {
1777 Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
1778 return VERR_RESOURCE_BUSY;
1779 }
1780
1781 /*
1782 * Do host specific unmounting.
1783 */
1784#ifdef RT_OS_WINDOWS
1785 Assert(RT_C_IS_UPPER(pszMountPoint[0]) && pszMountPoint[1] == ':' && pszMountPoint[2] == '\0');
1786 RTUTF16 const wszDrive[4] = { pszMountPoint[0], ':', '\0', '\0' };
1787 DWORD dwErr = WNetCancelConnection2W(wszDrive, 0 /*dwFlags*/, FALSE /*fForce*/);
1788 if (dwErr == NO_ERROR)
1789 return VINF_SUCCESS;
1790 VGSvcVerbose(2, "vbsvcAutomounterUnmount: WNetCancelConnection2W returns %u for '%s' ('%s')\n", dwErr, pszMountPoint, pszName);
1791 if (dwErr == ERROR_NOT_CONNECTED)
1792 return VINF_SUCCESS;
1793
1794#elif defined(RT_OS_OS2)
1795 APIRET rcOs2 = DosFSAttach(pszMountPoint, "VBOXSF", NULL, 0, FS_DETACH);
1796 if (rcOs2 == NO_ERROR)
1797 return VINF_SUCCESS;
1798 VGSvcVerbose(2, "vbsvcAutomounterUnmount: DosFSAttach failed on '%s' ('%s'): %u\n", pszMountPoint, pszName, rcOs2);
1799 if (rcOs2 == ERROR_INVALID_FSD_NAME)
1800 return VERR_ACCESS_DENIED;
1801 if ( rcOs2 == ERROR_INVALID_DRIVE
1802 || rcOs2 == ERROR_INVALID_PATH)
1803 return VERR_TRY_AGAIN;
1804
1805#else
1806 int rc2 = umount(pszMountPoint);
1807 if (rc2 == 0)
1808 {
1809 /* Remove the mount directory if not directly under the root dir. */
1810 RTPATHPARSED Parsed = { 0 };
1811 RTPathParse(pszMountPoint, &Parsed, sizeof(Parsed), RTPATH_STR_F_STYLE_HOST);
1812 if (Parsed.cComps >= 3)
1813 RTDirRemove(pszMountPoint);
1814
1815 return VINF_SUCCESS;
1816 }
1817 rc2 = errno;
1818 VGSvcVerbose(2, "vbsvcAutomounterUnmount: umount failed on '%s' ('%s'): %d\n", pszMountPoint, pszName, rc2);
1819 if (rc2 != EBUSY && rc2 != EAGAIN)
1820 return VERR_ACCESS_DENIED;
1821#endif
1822
1823 /*
1824 * Check what's mounted there before we start delaying.
1825 */
1826 RTThreadSleep(8); /* fudge */
1827 rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
1828 if (rc == VINF_SUCCESS)
1829 { /* pszName is mounted there */ }
1830 else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
1831 return VINF_SUCCESS;
1832 else
1833 {
1834 Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
1835 return VERR_RESOURCE_BUSY;
1836 }
1837
1838 if (iTry >= 5)
1839 return VERR_TRY_AGAIN;
1840 RTThreadSleep(1000);
1841 }
1842}
1843
1844
1845/**
1846 * Unmounts a mount table entry and evicts it from the table if successful.
1847 *
1848 * @returns The next iTable (same value on success, +1 on failure).
1849 * @param pTable The mount table.
1850 * @param iTable The table entry.
1851 * @param pszReason Why we're here.
1852 */
1853static uint32_t vbsvcAutomounterUnmountEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable, const char *pszReason)
1854{
1855 Assert(iTable < pTable->cEntries);
1856 PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
1857 VGSvcVerbose(2, "vbsvcAutomounterUnmountEntry: #%u: '%s' at '%s' (reason: %s)\n",
1858 iTable, pEntry->pszName, pEntry->pszActualMountPoint, pszReason);
1859
1860 /*
1861 * Do we need to umount the entry? Return if unmount fails and we .
1862 */
1863 if (pEntry->pszActualMountPoint)
1864 {
1865 int rc = vbsvcAutomounterUnmount(pEntry->pszActualMountPoint, pEntry->pszName);
1866 if (rc == VERR_TRY_AGAIN)
1867 {
1868 VGSvcVerbose(1, "vbsvcAutomounterUnmountEntry: Keeping '%s' -> '%s' (VERR_TRY_AGAIN)\n",
1869 pEntry->pszActualMountPoint, pEntry->pszName);
1870 return iTable + 1;
1871 }
1872 }
1873
1874 /*
1875 * Remove the entry by shifting up the ones after it.
1876 */
1877 pTable->cEntries -= 1;
1878 uint32_t cAfter = pTable->cEntries - iTable;
1879 if (cAfter)
1880 memmove(&pTable->papEntries[iTable], &pTable->papEntries[iTable + 1], cAfter * sizeof(pTable->papEntries[0]));
1881 pTable->papEntries[pTable->cEntries] = NULL;
1882
1883 RTStrFree(pEntry->pszActualMountPoint);
1884 pEntry->pszActualMountPoint = NULL;
1885 RTStrFree(pEntry->pszMountPoint);
1886 pEntry->pszMountPoint = NULL;
1887 RTStrFree(pEntry->pszName);
1888 pEntry->pszName = NULL;
1889 RTMemFree(pEntry);
1890
1891 return iTable;
1892}
1893
1894
1895/**
1896 * @callback_method_impl{FNRTSORTCMP, For sorting the mappings by ID. }
1897 */
1898static DECLCALLBACK(int) vbsvcSharedFolderMappingCompare(void const *pvElement1, void const *pvElement2, void *pvUser)
1899{
1900 RT_NOREF_PV(pvUser);
1901 PVBGLR3SHAREDFOLDERMAPPING pMapping1 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement1;
1902 PVBGLR3SHAREDFOLDERMAPPING pMapping2 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement2;
1903 return pMapping1->u32Root < pMapping2->u32Root ? -1 : pMapping1->u32Root != pMapping2->u32Root ? 1 : 0;
1904}
1905
1906
1907/**
1908 * Refreshes the mount table.
1909 *
1910 * @returns true if we've processed the current config, false if we failed to
1911 * query the mappings.
1912 * @param pTable The mount table to refresh.
1913 */
1914static bool vbsvcAutomounterRefreshTable(PVBSVCAUTOMOUNTERTABLE pTable)
1915{
1916 /*
1917 * Query the root IDs of all auto-mountable shared folder mappings.
1918 */
1919 uint32_t cMappings = 0;
1920 PVBGLR3SHAREDFOLDERMAPPING paMappings = NULL;
1921 int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
1922 if (RT_FAILURE(rc))
1923 {
1924 VGSvcError("vbsvcAutomounterRefreshTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
1925 return false;
1926 }
1927
1928 /*
1929 * Walk the table and the mappings in parallel, so we have to make sure
1930 * they are both sorted by root ID.
1931 */
1932 if (cMappings > 1)
1933 RTSortShell(paMappings, cMappings, sizeof(paMappings[0]), vbsvcSharedFolderMappingCompare, NULL);
1934
1935 /*
1936 * Pass #1: Do all the umounting.
1937 *
1938 * By doing the umount pass separately from the mount pass, we can
1939 * better handle changing involving the same mount points (switching
1940 * mount points between two shares, new share on same mount point but
1941 * with lower root ID, ++).
1942 */
1943 uint32_t iTable = 0;
1944 for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
1945 {
1946 /*
1947 * Unmount table entries up to idRootSrc.
1948 */
1949 uint32_t const idRootSrc = paMappings[iSrc].u32Root;
1950 while ( iTable < pTable->cEntries
1951 && pTable->papEntries[iTable]->idRoot < idRootSrc)
1952 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped");
1953
1954 /*
1955 * If the paMappings entry and the mount table entry has the same
1956 * root ID, umount if anything has changed or if we cannot query
1957 * the mapping data.
1958 */
1959 if (iTable < pTable->cEntries)
1960 {
1961 PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
1962 if (pEntry->idRoot == idRootSrc)
1963 {
1964 uint32_t uRootIdVer = UINT32_MAX;
1965 uint64_t fFlags = 0;
1966 char *pszName = NULL;
1967 char *pszMntPt = NULL;
1968 rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
1969 &pszName, &pszMntPt, &fFlags, &uRootIdVer);
1970 if (RT_FAILURE(rc))
1971 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "VbglR3SharedFolderQueryFolderInfo failed");
1972 else if (pEntry->uRootIdVersion != uRootIdVer)
1973 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "root ID version changed");
1974 else if (RTPathCompare(pEntry->pszMountPoint, pszMntPt) != 0)
1975 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "mount point changed");
1976 else if (RTStrICmp(pEntry->pszName, pszName) != 0)
1977 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "name changed");
1978 else
1979 {
1980 VGSvcVerbose(3, "vbsvcAutomounterRefreshTable: Unchanged: %s -> %s\n", pEntry->pszMountPoint, pEntry->pszName);
1981 iTable++;
1982 }
1983 if (RT_SUCCESS(rc))
1984 {
1985 RTStrFree(pszName);
1986 RTStrFree(pszMntPt);
1987 }
1988 }
1989 }
1990 }
1991
1992 while (iTable < pTable->cEntries)
1993 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped (tail)");
1994
1995 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u entries in mount table after pass #1.\n", pTable->cEntries);
1996
1997 /*
1998 * Pass #2: Try mount new folders that has mount points assigned.
1999 * Pass #3: Try mount new folders not mounted in pass #2.
2000 */
2001 for (uint32_t iPass = 2; iPass <= 3; iPass++)
2002 {
2003 iTable = 0;
2004 for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
2005 {
2006 uint32_t const idRootSrc = paMappings[iSrc].u32Root;
2007
2008 /*
2009 * Skip tabel entries we couldn't umount in pass #1.
2010 */
2011 while ( iTable < pTable->cEntries
2012 && pTable->papEntries[iTable]->idRoot < idRootSrc)
2013 {
2014 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Skipping idRoot=%u %s\n",
2015 iPass, iSrc, iTable, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
2016 iTable++;
2017 }
2018
2019 /*
2020 * New share?
2021 */
2022 if ( iTable >= pTable->cEntries
2023 || pTable->papEntries[iTable]->idRoot != idRootSrc)
2024 {
2025 uint32_t uRootIdVer = UINT32_MAX;
2026 uint64_t fFlags = 0;
2027 char *pszName = NULL;
2028 char *pszMntPt = NULL;
2029 rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
2030 &pszName, &pszMntPt, &fFlags, &uRootIdVer);
2031 if (RT_SUCCESS(rc))
2032 {
2033 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Mounting idRoot=%u/%u %s\n", iPass, iSrc, iTable,
2034 idRootSrc, iTable >= pTable->cEntries ? UINT32_MAX : pTable->papEntries[iTable]->idRoot, pszName);
2035 iTable = vbsvcAutomounterMountNewEntry(pTable, iTable, pszName, pszMntPt, fFlags,
2036 idRootSrc, uRootIdVer, iPass == 3);
2037
2038 RTStrFree(pszName);
2039 RTStrFree(pszMntPt);
2040 }
2041 else
2042 VGSvcVerbose(1, "vbsvcAutomounterRefreshTable: VbglR3SharedFolderQueryFolderInfo failed: %Rrc\n", rc);
2043 }
2044 else
2045 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: idRootSrc=%u vs idRoot=%u %s\n", iPass, iSrc,
2046 iTable, idRootSrc, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
2047 }
2048 }
2049
2050 VbglR3SharedFolderFreeMappings(paMappings);
2051 return true;
2052}
2053
2054
2055/**
2056 * @interface_method_impl{VBOXSERVICE,pfnWorker}
2057 */
2058static DECLCALLBACK(int) vbsvcAutomounterWorker(bool volatile *pfShutdown)
2059{
2060 /*
2061 * Tell the control thread that it can continue spawning services.
2062 */
2063 RTThreadUserSignal(RTThreadSelf());
2064
2065 /* Divert old hosts to original auto-mount code. */
2066 if (!g_fHostSupportsWaitAndInfoQuery)
2067 return vbsvcAutoMountWorkerOld(pfShutdown);
2068
2069 /*
2070 * Initialize the state in case we're restarted...
2071 */
2072 VBSVCAUTOMOUNTERTABLE MountTable = { 0, 0, NULL };
2073 int rc = vbsvcAutomounterPopulateTable(&MountTable);
2074 if (RT_FAILURE(rc))
2075 {
2076 VGSvcError("vbsvcAutomounterWorker: vbsvcAutomounterPopulateTable failed (%Rrc), quitting!\n", rc);
2077 return rc;
2078 }
2079
2080 /*
2081 * Work loop.
2082 */
2083 uint32_t uConfigVer = UINT32_MAX;
2084 uint32_t uNewVersion = 0;
2085 bool fForceRefresh = true;
2086 while (!*pfShutdown)
2087 {
2088 /*
2089 * Update the mounts.
2090 */
2091 if ( uConfigVer != uNewVersion
2092 || fForceRefresh)
2093 {
2094 fForceRefresh = !vbsvcAutomounterRefreshTable(&MountTable);
2095 uConfigVer = uNewVersion;
2096 }
2097
2098 /*
2099 * Wait for more to do.
2100 */
2101 if (!*pfShutdown)
2102 {
2103 uNewVersion = uConfigVer - 1;
2104 VGSvcVerbose(2, "vbsvcAutomounterWorker: Waiting with uConfigVer=%u\n", uConfigVer);
2105 rc = VbglR3SharedFolderWaitForMappingsChanges(g_idClientSharedFolders, uConfigVer, &uNewVersion);
2106 VGSvcVerbose(2, "vbsvcAutomounterWorker: Woke up with uNewVersion=%u and rc=%Rrc\n", uNewVersion, rc);
2107
2108 /* Delay a little before doing a table refresh so the GUI can finish
2109 all its updates. Delay a little longer on non-shutdown failure to
2110 avoid eating too many CPU cycles if something goes wrong here... */
2111 if (!*pfShutdown)
2112 RTSemEventMultiWait(g_hAutoMountEvent, RT_SUCCESS(rc) ? 256 : 1000);
2113 }
2114 }
2115
2116 /*
2117 * Destroy the mount table.
2118 */
2119 while (MountTable.cEntries-- > 0)
2120 RTMemFree(MountTable.papEntries[MountTable.cEntries]);
2121 MountTable.papEntries = NULL;
2122
2123 VGSvcVerbose(3, "vbsvcAutomounterWorker: Finished\n");
2124 return VINF_SUCCESS;
2125}
2126
2127
2128/**
2129 * @interface_method_impl{VBOXSERVICE,pfnStop}
2130 */
2131static DECLCALLBACK(void) vbsvcAutomounterStop(void)
2132{
2133 RTSemEventMultiSignal(g_hAutoMountEvent);
2134 if (g_fHostSupportsWaitAndInfoQuery)
2135 VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
2136}
2137
2138
2139/**
2140 * @interface_method_impl{VBOXSERVICE,pfnTerm}
2141 */
2142static DECLCALLBACK(void) vbsvcAutomounterTerm(void)
2143{
2144 VGSvcVerbose(3, "vbsvcAutoMountTerm\n");
2145
2146 if (g_fHostSupportsWaitAndInfoQuery)
2147 VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
2148
2149 VbglR3SharedFolderDisconnect(g_idClientSharedFolders);
2150 g_idClientSharedFolders = 0;
2151
2152 if (g_hAutoMountEvent != NIL_RTSEMEVENTMULTI)
2153 {
2154 RTSemEventMultiDestroy(g_hAutoMountEvent);
2155 g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
2156 }
2157}
2158
2159
2160/**
2161 * The 'automount' service description.
2162 */
2163VBOXSERVICE g_AutoMount =
2164{
2165 /* pszName. */
2166 "automount",
2167 /* pszDescription. */
2168 "Automounter for Shared Folders",
2169 /* pszUsage. */
2170 NULL,
2171 /* pszOptions. */
2172 NULL,
2173 /* methods */
2174 VGSvcDefaultPreInit,
2175 VGSvcDefaultOption,
2176 vbsvcAutomounterInit,
2177 vbsvcAutomounterWorker,
2178 vbsvcAutomounterStop,
2179 vbsvcAutomounterTerm
2180};
2181
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