VirtualBox

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

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

linux/vboxsf: Added more mount options: dcachettl=MILLISECONDS, inodettl=MILLISECONDS, dirbuf=BYTES and cache={default/strict|none|read|readwrite}. The readwrite cache mode isn't fully implemented yet (works same as 'read'). bugref:9172

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