VirtualBox

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

Last change on this file since 83826 was 83822, checked in by vboxsync, 5 years ago

VBoxService: VC++ 14.1 adjustments and warnings. bugref:8489

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.7 KB
Line 
1/* $Id: VBoxServiceAutoMount.cpp 83822 2020-04-19 01:13:00Z vboxsync $ */
2/** @file
3 * VBoxService - Auto-mounting for Shared Folders, only Linux & Solaris atm.
4 */
5
6/*
7 * Copyright (C) 2010-2020 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] = { (RTUTF16)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 if (rc == ERROR_PATH_NOT_FOUND)
1196 rc = VWRN_NOT_FOUND;
1197 else if ( RT_C_IS_ALPHA(pszMountPoint[0])
1198 && pszMountPoint[1] == ':'
1199 && ( pszMountPoint[2] == '\0'
1200 || (RTPATH_IS_SLASH(pszMountPoint[2]) && pszMountPoint[3] == '\0')))
1201 {
1202 /* See whether QueryDosDeviceW thinks its a malfunctioning shared folder or
1203 something else (it doesn't access the file system). We've seen
1204 VERR_NET_HOST_NOT_FOUND here for shared folders that was removed on the
1205 host side.
1206
1207 Note! This duplicates code from vbsvcAutomounterPopulateTable. */
1208 rc = VERR_ACCESS_DENIED;
1209 static const char s_szDevicePath[] = "\\Device\\VBoxMiniRdr\\;";
1210 wszFileSystem[0] = pwszMountPoint[0];
1211 wszFileSystem[1] = pwszMountPoint[1];
1212 wszFileSystem[2] = '\0';
1213 DWORD const cwcResult = QueryDosDeviceW(wszFileSystem, wszLabel, RT_ELEMENTS(wszLabel));
1214 if ( cwcResult > sizeof(s_szDevicePath)
1215 && RTUtf16NICmpAscii(wszLabel, RT_STR_TUPLE(s_szDevicePath)) == 0)
1216 {
1217 PCRTUTF16 pwsz = &wszLabel[RT_ELEMENTS(s_szDevicePath) - 1];
1218 Assert(pwsz[-1] == ';');
1219 if ( (pwsz[0] & ~(RTUTF16)0x20) == (wszFileSystem[0] & ~(RTUTF16)0x20)
1220 && pwsz[1] == ':'
1221 && pwsz[2] == '\\')
1222 {
1223 if (RTUtf16NICmpAscii(&pwsz[3], RT_STR_TUPLE("VBoxSvr\\")) == 0)
1224 {
1225 pwsz += 3 + 8;
1226 char *pszMountedName = NULL;
1227 rc = RTUtf16ToUtf8(pwsz, &pszMountedName);
1228 if (RT_SUCCESS(rc))
1229 {
1230 if (RTStrICmp(pszMountedName, pszName) == 0)
1231 {
1232 rc = VINF_SUCCESS;
1233 VGSvcVerbose(2, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' (using QueryDosDeviceW).\n",
1234 pszName, pszMountPoint);
1235 }
1236 else
1237 {
1238 VGSvcVerbose(2, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' (using QueryDosDeviceW), not '%s'...\n",
1239 pszMountedName, pszMountPoint, pszName);
1240 rc = VERR_RESOURCE_BUSY;
1241 }
1242 RTStrFree(pszMountedName);
1243 }
1244 else
1245 {
1246 VGSvcVerbose(2, "vbsvcAutomounterQueryMountPoint: RTUtf16ToUtf8 failed: %Rrc\n", rc);
1247 AssertRC(rc);
1248 rc = VERR_RESOURCE_BUSY;
1249 }
1250 }
1251 }
1252 }
1253 }
1254 else
1255 rc = VERR_ACCESS_DENIED;
1256 }
1257 RTUtf16Free(pwszMountPoint);
1258 }
1259 else
1260 {
1261 VGSvcError("vbsvcAutomounterQueryMountPoint: RTStrToUtf16(%s,) -> %Rrc\n", pszMountPoint, rc);
1262 rc = VWRN_NOT_FOUND;
1263 }
1264 return rc;
1265
1266#elif defined(RT_OS_OS2)
1267 /*
1268 * Query file system attachment info for the given drive letter.
1269 */
1270 union
1271 {
1272 FSQBUFFER2 FsQueryBuf;
1273 char achPadding[512];
1274 } uBuf;
1275 RT_ZERO(uBuf);
1276
1277 ULONG cbBuf = sizeof(uBuf);
1278 APIRET rcOs2 = DosQueryFSAttach(pszMountPoint, 0, FSAIL_QUERYNAME, &uBuf.FsQueryBuf, &cbBuf);
1279 int rc;
1280 if (rcOs2 == NO_ERROR)
1281 {
1282 const char *pszFsdName = (const char *)&uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
1283 if ( uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
1284 && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
1285 {
1286 const char *pszMountedName = (const char *)&pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
1287 if (RTStrICmp(pszMountedName, pszName) == 0)
1288 {
1289 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1290 pszName, pszMountPoint);
1291 rc = VINF_SUCCESS;
1292 }
1293 else
1294 {
1295 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1296 pszMountedName, pszMountPoint, pszName);
1297 rc = VERR_RESOURCE_BUSY;
1298 }
1299 }
1300 else
1301 {
1302 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' type %u mount at '%s', not '%s'...\n",
1303 pszFsdName, uBuf.FsQueryBuf.iType, pszMountPoint, pszName);
1304 rc = VERR_ACCESS_DENIED;
1305 }
1306 }
1307 else
1308 {
1309 rc = VWRN_NOT_FOUND;
1310 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: DosQueryFSAttach(%s) -> %u\n", pszMountPoint, rcOs2);
1311 AssertMsgStmt(rcOs2 != ERROR_BUFFER_OVERFLOW && rcOs2 != ERROR_INVALID_PARAMETER,
1312 ("%s -> %u\n", pszMountPoint, rcOs2), rc = VERR_ACCESS_DENIED);
1313 }
1314 return rc;
1315
1316#elif defined(RT_OS_LINUX)
1317 /*
1318 * Scan one of the mount table file for the mount point and then
1319 * match file system and device/share.
1320 */
1321 FILE *pFile = setmntent("/proc/mounts", "r");
1322 int rc = errno;
1323 if (!pFile)
1324 pFile = setmntent(_PATH_MOUNTED, "r");
1325 if (pFile)
1326 {
1327 rc = VWRN_NOT_FOUND;
1328 struct mntent *pEntry;
1329 while ((pEntry = getmntent(pFile)) != NULL)
1330 if (RTPathCompare(pEntry->mnt_dir, pszMountPoint) == 0)
1331 {
1332 if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
1333 {
1334 if (RTStrICmp(pEntry->mnt_fsname, pszName) == 0)
1335 {
1336 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1337 pszName, pszMountPoint);
1338 rc = VINF_SUCCESS;
1339 }
1340 else
1341 {
1342 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1343 pEntry->mnt_fsname, pszMountPoint, pszName);
1344 rc = VERR_RESOURCE_BUSY;
1345 }
1346 }
1347 else
1348 {
1349 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
1350 pEntry->mnt_type, pEntry->mnt_fsname, pszMountPoint, pszName);
1351 rc = VERR_ACCESS_DENIED;
1352 }
1353 /* We continue searching in case of stacked mounts, we want the last one. */
1354 }
1355 endmntent(pFile);
1356 }
1357 else
1358 {
1359 VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '/proc/mounts' (errno=%d) or '%s' (errno=%d)\n",
1360 rc, _PATH_MOUNTED, errno);
1361 rc = VERR_ACCESS_DENIED;
1362 }
1363 return rc;
1364
1365#elif defined(RT_OS_SOLARIS)
1366 /*
1367 * Similar to linux.
1368 */
1369 int rc;
1370 FILE *pFile = fopen(_PATH_MOUNTED, "r");
1371 if (pFile)
1372 {
1373 rc = VWRN_NOT_FOUND;
1374 struct mnttab Entry;
1375 while (getmntent(pFile, &Entry) == 0)
1376 if (RTPathCompare(Entry.mnt_mountp, pszMountPoint) == 0)
1377 {
1378 if (strcmp(Entry.mnt_fstype, "vboxfs") == 0)
1379 {
1380 if (RTStrICmp(Entry.mnt_special, pszName) == 0)
1381 {
1382 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s'.\n",
1383 pszName, pszMountPoint);
1384 rc = VINF_SUCCESS;
1385 }
1386 else
1387 {
1388 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
1389 Entry.mnt_special, pszMountPoint, pszName);
1390 rc = VERR_RESOURCE_BUSY;
1391 }
1392 }
1393 else
1394 {
1395 VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
1396 Entry.mnt_fstype, Entry.mnt_special, pszMountPoint, pszName);
1397 rc = VERR_ACCESS_DENIED;
1398 }
1399 /* We continue searching in case of stacked mounts, we want the last one. */
1400 }
1401 fclose(pFile);
1402 }
1403 else
1404 {
1405 VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
1406 rc = VERR_ACCESS_DENIED;
1407 }
1408 return rc;
1409#else
1410# error "PORTME"
1411#endif
1412}
1413
1414
1415/**
1416 * Worker for vbsvcAutomounterMountNewEntry that does the OS mounting.
1417 *
1418 * @returns IPRT status code.
1419 * @param pEntry The entry to try mount.
1420 */
1421static int vbsvcAutomounterMountIt(PVBSVCAUTOMOUNTERENTRY pEntry)
1422{
1423 VGSvcVerbose(3, "vbsvcAutomounterMountIt: Trying to mount '%s' (idRoot=%#x) on '%s'...\n",
1424 pEntry->pszName, pEntry->idRoot, pEntry->pszActualMountPoint);
1425#ifdef RT_OS_WINDOWS
1426 /*
1427 * Attach the shared folder using WNetAddConnection2W.
1428 *
1429 * According to google we should get a drive symlink in \\GLOBAL?? when
1430 * we are running under the system account. Otherwise it will be a session
1431 * local link (\\??).
1432 */
1433 Assert(RT_C_IS_UPPER(pEntry->pszActualMountPoint[0]) && pEntry->pszActualMountPoint[1] == ':' && pEntry->pszActualMountPoint[2] == '\0');
1434 RTUTF16 wszDrive[4] = { (RTUTF16)pEntry->pszActualMountPoint[0], ':', '\0', '\0' };
1435
1436 RTUTF16 wszPrefixedName[RTPATH_MAX];
1437 int rc = RTUtf16CopyAscii(wszPrefixedName, RT_ELEMENTS(wszPrefixedName), "\\\\VBoxSvr\\");
1438 AssertRC(rc);
1439
1440 size_t const offName = RTUtf16Len(wszPrefixedName);
1441 PRTUTF16 pwszName = &wszPrefixedName[offName];
1442 rc = RTStrToUtf16Ex(pEntry->pszName, RTSTR_MAX, &pwszName, sizeof(wszPrefixedName) - offName, NULL);
1443 if (RT_FAILURE(rc))
1444 {
1445 VGSvcError("vbsvcAutomounterMountIt: RTStrToUtf16Ex failed on '%s': %Rrc\n", pEntry->pszName, rc);
1446 return rc;
1447 }
1448
1449 VGSvcVerbose(3, "vbsvcAutomounterMountIt: wszDrive='%ls', wszPrefixedName='%ls'\n",
1450 wszDrive, wszPrefixedName);
1451
1452 NETRESOURCEW NetRsrc;
1453 RT_ZERO(NetRsrc);
1454 NetRsrc.dwType = RESOURCETYPE_DISK;
1455 NetRsrc.lpLocalName = wszDrive;
1456 NetRsrc.lpRemoteName = wszPrefixedName;
1457 NetRsrc.lpProvider = L"VirtualBox Shared Folders"; /* Only try our provider. */
1458 NetRsrc.lpComment = pwszName;
1459
1460 DWORD dwErr = WNetAddConnection2W(&NetRsrc, NULL /*pwszPassword*/, NULL /*pwszUserName*/, 0 /*dwFlags*/);
1461 if (dwErr == NO_ERROR)
1462 {
1463 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1464 pEntry->pszName, pEntry->pszActualMountPoint);
1465 return VINF_SUCCESS;
1466 }
1467 VGSvcError("vbsvcAutomounterMountIt: Failed to attach '%s' to '%s': %Rrc (%u)\n",
1468 pEntry->pszName, pEntry->pszActualMountPoint, RTErrConvertFromWin32(dwErr), dwErr);
1469 return VERR_OPEN_FAILED;
1470
1471#elif defined(RT_OS_OS2)
1472 /*
1473 * It's a rather simple affair on OS/2.
1474 *
1475 * In order to be able to detect our mounts we add a 2nd string after
1476 * the folder name that tags the attachment. The IFS will remember this
1477 * and return it when DosQueryFSAttach is called.
1478 *
1479 * Note! Kernel currently accepts limited 7-bit ASCII names. We could
1480 * change that to UTF-8 if we like as that means no extra string
1481 * encoding conversion fun here.
1482 */
1483 char szzNameAndTag[256];
1484 size_t cchName = strlen(pEntry->pszName);
1485 if (cchName + 1 + sizeof(g_szTag) <= sizeof(szzNameAndTag))
1486 {
1487 memcpy(szzNameAndTag, pEntry->pszName, cchName);
1488 szzNameAndTag[cchName] = '\0';
1489 memcpy(&szzNameAndTag[cchName + 1], g_szTag, sizeof(g_szTag));
1490
1491 APIRET rc = DosFSAttach(pEntry->pszActualMountPoint, "VBOXSF", szzNameAndTag, cchName + 1 + sizeof(g_szTag), FS_ATTACH);
1492 if (rc == NO_ERROR)
1493 {
1494 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1495 pEntry->pszName, pEntry->pszActualMountPoint);
1496 return VINF_SUCCESS;
1497 }
1498 VGSvcError("vbsvcAutomounterMountIt: DosFSAttach failed to attach '%s' to '%s': %u\n",
1499 pEntry->pszName, pEntry->pszActualMountPoint, rc);
1500 }
1501 else
1502 VGSvcError("vbsvcAutomounterMountIt: Share name for attach to '%s' is too long: %u chars - '%s'\n",
1503 pEntry->pszActualMountPoint, cchName, pEntry->pszName);
1504 return VERR_OPEN_FAILED;
1505
1506#else
1507 /*
1508 * Common work for unix-like systems: Get group, make sure mount directory exist.
1509 */
1510 int rc = RTDirCreateFullPath(pEntry->pszActualMountPoint,
1511 RTFS_UNIX_IRWXU | RTFS_UNIX_IXGRP | RTFS_UNIX_IRGRP | RTFS_UNIX_IXOTH | RTFS_UNIX_IROTH);
1512 if (RT_FAILURE(rc))
1513 {
1514 VGSvcError("vbsvcAutomounterMountIt: Failed to create mount path '%s' for share '%s': %Rrc\n",
1515 pEntry->pszActualMountPoint, pEntry->pszName, rc);
1516 return rc;
1517 }
1518
1519 gid_t gidMount;
1520 struct group *grp_vboxsf = getgrnam("vboxsf");
1521 if (grp_vboxsf)
1522 gidMount = grp_vboxsf->gr_gid;
1523 else
1524 {
1525 VGSvcError("vbsvcAutomounterMountIt: Group 'vboxsf' does not exist\n");
1526 gidMount = 0;
1527 }
1528
1529# if defined(RT_OS_LINUX)
1530 /*
1531 * Linux a bit more work...
1532 */
1533 struct vbsf_mount_info_new MntInfo;
1534 RT_ZERO(MntInfo);
1535 struct vbsf_mount_opts MntOpts;
1536 RT_ZERO(MntOpts);
1537 MntInfo.nullchar = '\0';
1538 MntInfo.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
1539 MntInfo.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
1540 MntInfo.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
1541 MntInfo.length = sizeof(MntInfo);
1542 MntInfo.ttl = MntOpts.ttl = -1 /*default*/;
1543 MntInfo.msDirCacheTTL= MntOpts.msDirCacheTTL = -1 /*default*/;
1544 MntInfo.msInodeTTL = MntOpts.msInodeTTL = -1 /*default*/;
1545 MntInfo.cMaxIoPages = MntOpts.cMaxIoPages = 0 /*default*/;
1546 MntInfo.cbDirBuf = MntOpts.cbDirBuf = 0 /*default*/;
1547 MntInfo.enmCacheMode = MntOpts.enmCacheMode = kVbsfCacheMode_Default;
1548 MntInfo.uid = MntOpts.uid = 0;
1549 MntInfo.gid = MntOpts.gid = gidMount;
1550 MntInfo.dmode = MntOpts.dmode = 0770;
1551 MntInfo.fmode = MntOpts.fmode = 0770;
1552 MntInfo.dmask = MntOpts.dmask = 0000;
1553 MntInfo.fmask = MntOpts.fmask = 0000;
1554 memcpy(MntInfo.szTag, g_szTag, sizeof(g_szTag)); AssertCompile(sizeof(MntInfo.szTag) >= sizeof(g_szTag));
1555 rc = RTStrCopy(MntInfo.name, sizeof(MntInfo.name), pEntry->pszName);
1556 if (RT_FAILURE(rc))
1557 {
1558 VGSvcError("vbsvcAutomounterMountIt: Share name '%s' is too long for the MntInfo.name field!\n", pEntry->pszName);
1559 return rc;
1560 }
1561
1562 errno = 0;
1563 unsigned long fFlags = MS_NODEV;
1564 rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, "vboxsf", fFlags, &MntInfo);
1565 if (rc == 0)
1566 {
1567 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1568 pEntry->pszName, pEntry->pszActualMountPoint);
1569
1570 errno = 0;
1571 rc = vbsfmount_complete(pEntry->pszName, pEntry->pszActualMountPoint, fFlags, &MntOpts);
1572 if (rc != 0) /* Ignorable. /etc/mtab is probably a link to /proc/mounts. */
1573 VGSvcVerbose(1, "vbsvcAutomounterMountIt: vbsfmount_complete failed: %s (%d/%d)\n",
1574 rc == 1 ? "open_memstream" : rc == 2 ? "setmntent" : rc == 3 ? "addmntent" : "unknown", rc, errno);
1575 return VINF_SUCCESS;
1576 }
1577 else if (errno == EINVAL)
1578 VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s' because it is probably mounted elsewhere arleady! (%d,%d)\n",
1579 pEntry->pszName, pEntry->pszActualMountPoint, rc, errno);
1580 else
1581 VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s': %s (%d,%d)\n",
1582 pEntry->pszName, pEntry->pszActualMountPoint, strerror(errno), rc, errno);
1583 return VERR_WRITE_ERROR;
1584
1585# elif defined(RT_OS_SOLARIS)
1586 /*
1587 * Solaris is rather simple compared to linux.
1588 *
1589 * The ',VBoxService=auto' option (g_szTag) is ignored by the kernel but helps
1590 * us identify our own mounts on restart. See vbsvcAutomounterPopulateTable().
1591 *
1592 * Note! Must pass MAX_MNTOPT_STR rather than cchOpts to mount, as it may fail
1593 * with EOVERFLOW in vfs_buildoptionstr() during domount() otherwise.
1594 */
1595 char szOpts[MAX_MNTOPT_STR] = { '\0', };
1596 ssize_t cchOpts = RTStrPrintf2(szOpts, sizeof(szOpts),
1597 "uid=0,gid=%d,dmode=0770,fmode=0770,dmask=0000,fmask=0000,tag=%s", gidMount, g_szTag);
1598 if (cchOpts <= 0)
1599 {
1600 VGSvcError("vbsvcAutomounterMountIt: szOpts overflow! %zd\n", cchOpts);
1601 return VERR_BUFFER_OVERFLOW;
1602 }
1603
1604 rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, MS_OPTIONSTR, "vboxfs",
1605 NULL /*dataptr*/, 0 /* datalen */, szOpts, MAX_MNTOPT_STR);
1606 if (rc == 0)
1607 {
1608 VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
1609 pEntry->pszName, pEntry->pszActualMountPoint);
1610 return VINF_SUCCESS;
1611 }
1612
1613 rc = errno;
1614 VGSvcError("vbsvcAutomounterMountIt: mount failed for '%s' on '%s' (szOpts=%s): %s (%d)\n",
1615 pEntry->pszName, pEntry->pszActualMountPoint, szOpts, strerror(rc), rc);
1616 return VERR_OPEN_FAILED;
1617
1618# else
1619# error "PORTME!"
1620# endif
1621#endif
1622}
1623
1624
1625/**
1626 * Attempts to mount the given shared folder, adding it to the mount table on
1627 * success.
1628 *
1629 * @returns iTable + 1 on success, iTable on failure.
1630 * @param pTable The mount table.
1631 * @param iTable The mount table index at which to add the mount.
1632 * @param pszName The name of the shared folder mapping.
1633 * @param pszMntPt The mount point (hint) specified by the host.
1634 * @param fFlags The shared folder flags, SHFL_MIF_XXX.
1635 * @param idRoot The root ID.
1636 * @param uRootIdVersion The root ID version.
1637 * @param fAutoMntPt Whether to try automatically assign a mount point if
1638 * pszMntPt doesn't work out. This is set in pass \#3.
1639 */
1640static uint32_t vbsvcAutomounterMountNewEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable,
1641 const char *pszName, const char *pszMntPt, uint64_t fFlags,
1642 uint32_t idRoot, uint32_t uRootIdVersion, bool fAutoMntPt)
1643{
1644 VGSvcVerbose(3, "vbsvcAutomounterMountNewEntry: #%u: '%s' at '%s'%s\n",
1645 iTable, pszName, pszMntPt, fAutoMntPt ? " auto-assign" : "");
1646
1647 /*
1648 * First we need to figure out the actual mount point.
1649 */
1650 char szActualMountPoint[RTPATH_MAX];
1651
1652#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
1653 /*
1654 * Drive letter based. We only care about the first two characters
1655 * and ignore the rest (see further down).
1656 */
1657 char chNextLetter = 'Z';
1658 if (RT_C_IS_ALPHA(pszMntPt[0]) && pszMntPt[1] == ':')
1659 szActualMountPoint[0] = RT_C_TO_UPPER(pszMntPt[0]);
1660 else if (!fAutoMntPt)
1661 return iTable;
1662 else
1663 szActualMountPoint[0] = chNextLetter--;
1664 szActualMountPoint[1] = ':';
1665 szActualMountPoint[2] = '\0';
1666
1667 int rc;
1668 for (;;)
1669 {
1670 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1671 if (rc == VWRN_NOT_FOUND)
1672 break;
1673
1674 /* next */
1675 if (chNextLetter == 'A' || !fAutoMntPt)
1676 return iTable;
1677 szActualMountPoint[0] = chNextLetter--;
1678 }
1679
1680#else
1681 /*
1682 * Path based #1: Host specified mount point.
1683 */
1684
1685 /* Skip DOS drive letter if there is a UNIX mount point path following it: */
1686 if ( pszMntPt[0] != '/'
1687 && pszMntPt[0] != '\0'
1688 && pszMntPt[1] == ':'
1689 && pszMntPt[2] == '/')
1690 pszMntPt += 2;
1691
1692 /* Try specified mount point if it starts with a UNIX slash: */
1693 int rc = VERR_ACCESS_DENIED;
1694 if (*pszMntPt == '/')
1695 {
1696 rc = RTPathAbs(pszMntPt, szActualMountPoint, sizeof(szActualMountPoint));
1697 if (RT_SUCCESS(rc))
1698 {
1699 static const char * const s_apszBlacklist[] =
1700 { "/", "/dev", "/bin", "/sbin", "/lib", "/etc", "/var", "/tmp", "/usr", "/usr/bin", "/usr/sbin", "/usr/lib" };
1701 for (size_t i = 0; i < RT_ELEMENTS(s_apszBlacklist); i++)
1702 if (strcmp(szActualMountPoint, s_apszBlacklist[i]) == 0)
1703 {
1704 rc = VERR_ACCESS_DENIED;
1705 break;
1706 }
1707 if (RT_SUCCESS(rc))
1708 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1709 }
1710 }
1711 if (rc != VWRN_NOT_FOUND)
1712 {
1713 if (!fAutoMntPt)
1714 return iTable;
1715
1716 /*
1717 * Path based #2: Mount dir + prefix + share.
1718 */
1719 rc = vbsvcAutomounterQueryMountDirAndPrefix(szActualMountPoint, sizeof(szActualMountPoint));
1720 if (RT_SUCCESS(rc))
1721 {
1722 /* Append a sanitized share name: */
1723 size_t const offShare = strlen(szActualMountPoint);
1724 size_t offDst = offShare;
1725 size_t offSrc = 0;
1726 for (;;)
1727 {
1728 char ch = pszName[offSrc++];
1729 if (ch == ' ' || ch == '/' || ch == '\\' || ch == ':' || ch == '$')
1730 ch = '_';
1731 else if (!ch)
1732 break;
1733 else if (ch < 0x20 || ch == 0x7f)
1734 continue;
1735 if (offDst < sizeof(szActualMountPoint) - 1)
1736 szActualMountPoint[offDst++] = ch;
1737 }
1738 szActualMountPoint[offDst] = '\0';
1739 if (offDst > offShare)
1740 {
1741 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1742 if (rc != VWRN_NOT_FOUND)
1743 {
1744 /*
1745 * Path based #3: Mount dir + prefix + share + _ + number.
1746 */
1747 if (offDst + 2 >= sizeof(szActualMountPoint))
1748 return iTable;
1749
1750 szActualMountPoint[offDst++] = '_';
1751 for (uint32_t iTry = 1; iTry < 10 && rc != VWRN_NOT_FOUND; iTry++)
1752 {
1753 szActualMountPoint[offDst] = '0' + iTry;
1754 szActualMountPoint[offDst + 1] = '\0';
1755 rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
1756 }
1757 if (rc != VWRN_NOT_FOUND)
1758 return iTable;
1759 }
1760 }
1761 else
1762 VGSvcError("vbsvcAutomounterMountNewEntry: Bad share name: %.*Rhxs", strlen(pszName), pszName);
1763 }
1764 else
1765 VGSvcError("vbsvcAutomounterMountNewEntry: Failed to construct basic auto mount point for '%s'", pszName);
1766 }
1767#endif
1768
1769 /*
1770 * Prepare a table entry and ensure space in the table..
1771 */
1772 if (pTable->cEntries + 1 > pTable->cAllocated)
1773 {
1774 void *pvEntries = RTMemRealloc(pTable->papEntries, sizeof(pTable->papEntries[0]) * (pTable->cAllocated + 8));
1775 if (!pvEntries)
1776 {
1777 VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for growing table (size %u)\n", pTable->cAllocated);
1778 return iTable;
1779 }
1780 pTable->cAllocated += 8;
1781 pTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvEntries;
1782 }
1783
1784 PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
1785 if (pEntry)
1786 {
1787 pEntry->idRoot = idRoot;
1788 pEntry->uRootIdVersion = uRootIdVersion;
1789 pEntry->fFlags = fFlags;
1790 pEntry->pszName = RTStrDup(pszName);
1791 pEntry->pszMountPoint = RTStrDup(pszMntPt);
1792 pEntry->pszActualMountPoint = RTStrDup(szActualMountPoint);
1793 if (pEntry->pszName && pEntry->pszMountPoint && pEntry->pszActualMountPoint)
1794 {
1795 /*
1796 * Now try mount it.
1797 */
1798 rc = vbsvcAutomounterMountIt(pEntry);
1799 if (RT_SUCCESS(rc))
1800 {
1801 uint32_t cToMove = pTable->cEntries - iTable;
1802 if (cToMove > 0)
1803 memmove(&pTable->papEntries[iTable + 1], &pTable->papEntries[iTable], cToMove * sizeof(pTable->papEntries[0]));
1804 pTable->papEntries[iTable] = pEntry;
1805 pTable->cEntries++;
1806 return iTable + 1;
1807 }
1808 }
1809 else
1810 VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
1811 RTMemFree(pEntry->pszActualMountPoint);
1812 RTMemFree(pEntry->pszMountPoint);
1813 RTMemFree(pEntry->pszName);
1814 RTMemFree(pEntry);
1815 }
1816 else
1817 VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
1818 return iTable;
1819}
1820
1821
1822
1823/**
1824 * Does the actual unmounting.
1825 *
1826 * @returns Exactly one of the following IPRT status codes;
1827 * @retval VINF_SUCCESS if successfully umounted or nothing was mounted there.
1828 * @retval VERR_TRY_AGAIN if the shared folder is busy.
1829 * @retval VERR_RESOURCE_BUSY if a different shared folder is mounted there.
1830 * @retval VERR_ACCESS_DENIED if a non-shared folder file system is mounted
1831 * there.
1832 *
1833 * @param pszMountPoint The mount point.
1834 * @param pszName The shared folder (mapping) name.
1835 */
1836static int vbsvcAutomounterUnmount(const char *pszMountPoint, const char *pszName)
1837{
1838 /*
1839 * Retry for 5 seconds in a hope that busy mounts will quiet down.
1840 */
1841 for (unsigned iTry = 0; ; iTry++)
1842 {
1843 /*
1844 * Check what's mounted there before we start umounting stuff.
1845 */
1846 int rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
1847 if (rc == VINF_SUCCESS)
1848 { /* pszName is mounted there */ }
1849 else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
1850 return VINF_SUCCESS;
1851 else
1852 {
1853 Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
1854 return VERR_RESOURCE_BUSY;
1855 }
1856
1857 /*
1858 * Do host specific unmounting.
1859 */
1860#ifdef RT_OS_WINDOWS
1861 Assert(RT_C_IS_UPPER(pszMountPoint[0]) && pszMountPoint[1] == ':' && pszMountPoint[2] == '\0');
1862 RTUTF16 const wszDrive[4] = { (RTUTF16)pszMountPoint[0], ':', '\0', '\0' };
1863 DWORD dwErr = WNetCancelConnection2W(wszDrive, 0 /*dwFlags*/, FALSE /*fForce*/);
1864 if (dwErr == NO_ERROR)
1865 return VINF_SUCCESS;
1866 VGSvcVerbose(2, "vbsvcAutomounterUnmount: WNetCancelConnection2W returns %u for '%s' ('%s')\n", dwErr, pszMountPoint, pszName);
1867 if (dwErr == ERROR_NOT_CONNECTED)
1868 return VINF_SUCCESS;
1869
1870#elif defined(RT_OS_OS2)
1871 APIRET rcOs2 = DosFSAttach(pszMountPoint, "VBOXSF", NULL, 0, FS_DETACH);
1872 if (rcOs2 == NO_ERROR)
1873 return VINF_SUCCESS;
1874 VGSvcVerbose(2, "vbsvcAutomounterUnmount: DosFSAttach failed on '%s' ('%s'): %u\n", pszMountPoint, pszName, rcOs2);
1875 if (rcOs2 == ERROR_INVALID_FSD_NAME)
1876 return VERR_ACCESS_DENIED;
1877 if ( rcOs2 == ERROR_INVALID_DRIVE
1878 || rcOs2 == ERROR_INVALID_PATH)
1879 return VERR_TRY_AGAIN;
1880
1881#else
1882 int rc2 = umount(pszMountPoint);
1883 if (rc2 == 0)
1884 {
1885 /* Remove the mount directory if not directly under the root dir. */
1886 RTPATHPARSED Parsed = { 0 };
1887 RTPathParse(pszMountPoint, &Parsed, sizeof(Parsed), RTPATH_STR_F_STYLE_HOST);
1888 if (Parsed.cComps >= 3)
1889 RTDirRemove(pszMountPoint);
1890
1891 return VINF_SUCCESS;
1892 }
1893 rc2 = errno;
1894 VGSvcVerbose(2, "vbsvcAutomounterUnmount: umount failed on '%s' ('%s'): %d\n", pszMountPoint, pszName, rc2);
1895 if (rc2 != EBUSY && rc2 != EAGAIN)
1896 return VERR_ACCESS_DENIED;
1897#endif
1898
1899 /*
1900 * Check what's mounted there before we start delaying.
1901 */
1902 RTThreadSleep(8); /* fudge */
1903 rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
1904 if (rc == VINF_SUCCESS)
1905 { /* pszName is mounted there */ }
1906 else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
1907 return VINF_SUCCESS;
1908 else
1909 {
1910 Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
1911 return VERR_RESOURCE_BUSY;
1912 }
1913
1914 if (iTry >= 5)
1915 return VERR_TRY_AGAIN;
1916 RTThreadSleep(1000);
1917 }
1918}
1919
1920
1921/**
1922 * Unmounts a mount table entry and evicts it from the table if successful.
1923 *
1924 * @returns The next iTable (same value on success, +1 on failure).
1925 * @param pTable The mount table.
1926 * @param iTable The table entry.
1927 * @param pszReason Why we're here.
1928 */
1929static uint32_t vbsvcAutomounterUnmountEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable, const char *pszReason)
1930{
1931 Assert(iTable < pTable->cEntries);
1932 PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
1933 VGSvcVerbose(2, "vbsvcAutomounterUnmountEntry: #%u: '%s' at '%s' (reason: %s)\n",
1934 iTable, pEntry->pszName, pEntry->pszActualMountPoint, pszReason);
1935
1936 /*
1937 * Do we need to umount the entry? Return if unmount fails and we .
1938 */
1939 if (pEntry->pszActualMountPoint)
1940 {
1941 int rc = vbsvcAutomounterUnmount(pEntry->pszActualMountPoint, pEntry->pszName);
1942 if (rc == VERR_TRY_AGAIN)
1943 {
1944 VGSvcVerbose(1, "vbsvcAutomounterUnmountEntry: Keeping '%s' -> '%s' (VERR_TRY_AGAIN)\n",
1945 pEntry->pszActualMountPoint, pEntry->pszName);
1946 return iTable + 1;
1947 }
1948 }
1949
1950 /*
1951 * Remove the entry by shifting up the ones after it.
1952 */
1953 pTable->cEntries -= 1;
1954 uint32_t cAfter = pTable->cEntries - iTable;
1955 if (cAfter)
1956 memmove(&pTable->papEntries[iTable], &pTable->papEntries[iTable + 1], cAfter * sizeof(pTable->papEntries[0]));
1957 pTable->papEntries[pTable->cEntries] = NULL;
1958
1959 RTStrFree(pEntry->pszActualMountPoint);
1960 pEntry->pszActualMountPoint = NULL;
1961 RTStrFree(pEntry->pszMountPoint);
1962 pEntry->pszMountPoint = NULL;
1963 RTStrFree(pEntry->pszName);
1964 pEntry->pszName = NULL;
1965 RTMemFree(pEntry);
1966
1967 return iTable;
1968}
1969
1970
1971/**
1972 * @callback_method_impl{FNRTSORTCMP, For sorting the mappings by ID. }
1973 */
1974static DECLCALLBACK(int) vbsvcSharedFolderMappingCompare(void const *pvElement1, void const *pvElement2, void *pvUser)
1975{
1976 RT_NOREF_PV(pvUser);
1977 PVBGLR3SHAREDFOLDERMAPPING pMapping1 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement1;
1978 PVBGLR3SHAREDFOLDERMAPPING pMapping2 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement2;
1979 return pMapping1->u32Root < pMapping2->u32Root ? -1 : pMapping1->u32Root != pMapping2->u32Root ? 1 : 0;
1980}
1981
1982
1983/**
1984 * Refreshes the mount table.
1985 *
1986 * @returns true if we've processed the current config, false if we failed to
1987 * query the mappings.
1988 * @param pTable The mount table to refresh.
1989 */
1990static bool vbsvcAutomounterRefreshTable(PVBSVCAUTOMOUNTERTABLE pTable)
1991{
1992 /*
1993 * Query the root IDs of all auto-mountable shared folder mappings.
1994 */
1995 uint32_t cMappings = 0;
1996 PVBGLR3SHAREDFOLDERMAPPING paMappings = NULL;
1997 int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
1998 if (RT_FAILURE(rc))
1999 {
2000 VGSvcError("vbsvcAutomounterRefreshTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
2001 return false;
2002 }
2003
2004 /*
2005 * Walk the table and the mappings in parallel, so we have to make sure
2006 * they are both sorted by root ID.
2007 */
2008 if (cMappings > 1)
2009 RTSortShell(paMappings, cMappings, sizeof(paMappings[0]), vbsvcSharedFolderMappingCompare, NULL);
2010
2011 /*
2012 * Pass #1: Do all the umounting.
2013 *
2014 * By doing the umount pass separately from the mount pass, we can
2015 * better handle changing involving the same mount points (switching
2016 * mount points between two shares, new share on same mount point but
2017 * with lower root ID, ++).
2018 */
2019 uint32_t iTable = 0;
2020 for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
2021 {
2022 /*
2023 * Unmount table entries up to idRootSrc.
2024 */
2025 uint32_t const idRootSrc = paMappings[iSrc].u32Root;
2026 while ( iTable < pTable->cEntries
2027 && pTable->papEntries[iTable]->idRoot < idRootSrc)
2028 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped");
2029
2030 /*
2031 * If the paMappings entry and the mount table entry has the same
2032 * root ID, umount if anything has changed or if we cannot query
2033 * the mapping data.
2034 */
2035 if (iTable < pTable->cEntries)
2036 {
2037 PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
2038 if (pEntry->idRoot == idRootSrc)
2039 {
2040 uint32_t uRootIdVer = UINT32_MAX;
2041 uint64_t fFlags = 0;
2042 char *pszName = NULL;
2043 char *pszMntPt = NULL;
2044 rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
2045 &pszName, &pszMntPt, &fFlags, &uRootIdVer);
2046 if (RT_FAILURE(rc))
2047 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "VbglR3SharedFolderQueryFolderInfo failed");
2048 else if (pEntry->uRootIdVersion != uRootIdVer)
2049 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "root ID version changed");
2050 else if (RTPathCompare(pEntry->pszMountPoint, pszMntPt) != 0)
2051 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "mount point changed");
2052 else if (RTStrICmp(pEntry->pszName, pszName) != 0)
2053 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "name changed");
2054 else
2055 {
2056 VGSvcVerbose(3, "vbsvcAutomounterRefreshTable: Unchanged: %s -> %s\n", pEntry->pszMountPoint, pEntry->pszName);
2057 iTable++;
2058 }
2059 if (RT_SUCCESS(rc))
2060 {
2061 RTStrFree(pszName);
2062 RTStrFree(pszMntPt);
2063 }
2064 }
2065 }
2066 }
2067
2068 while (iTable < pTable->cEntries)
2069 iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped (tail)");
2070
2071 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u entries in mount table after pass #1.\n", pTable->cEntries);
2072
2073 /*
2074 * Pass #2: Try mount new folders that has mount points assigned.
2075 * Pass #3: Try mount new folders not mounted in pass #2.
2076 */
2077 for (uint32_t iPass = 2; iPass <= 3; iPass++)
2078 {
2079 iTable = 0;
2080 for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
2081 {
2082 uint32_t const idRootSrc = paMappings[iSrc].u32Root;
2083
2084 /*
2085 * Skip tabel entries we couldn't umount in pass #1.
2086 */
2087 while ( iTable < pTable->cEntries
2088 && pTable->papEntries[iTable]->idRoot < idRootSrc)
2089 {
2090 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Skipping idRoot=%u %s\n",
2091 iPass, iSrc, iTable, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
2092 iTable++;
2093 }
2094
2095 /*
2096 * New share?
2097 */
2098 if ( iTable >= pTable->cEntries
2099 || pTable->papEntries[iTable]->idRoot != idRootSrc)
2100 {
2101 uint32_t uRootIdVer = UINT32_MAX;
2102 uint64_t fFlags = 0;
2103 char *pszName = NULL;
2104 char *pszMntPt = NULL;
2105 rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
2106 &pszName, &pszMntPt, &fFlags, &uRootIdVer);
2107 if (RT_SUCCESS(rc))
2108 {
2109 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Mounting idRoot=%u/%u %s\n", iPass, iSrc, iTable,
2110 idRootSrc, iTable >= pTable->cEntries ? UINT32_MAX : pTable->papEntries[iTable]->idRoot, pszName);
2111 iTable = vbsvcAutomounterMountNewEntry(pTable, iTable, pszName, pszMntPt, fFlags,
2112 idRootSrc, uRootIdVer, iPass == 3);
2113
2114 RTStrFree(pszName);
2115 RTStrFree(pszMntPt);
2116 }
2117 else
2118 VGSvcVerbose(1, "vbsvcAutomounterRefreshTable: VbglR3SharedFolderQueryFolderInfo failed: %Rrc\n", rc);
2119 }
2120 else
2121 VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: idRootSrc=%u vs idRoot=%u %s\n", iPass, iSrc,
2122 iTable, idRootSrc, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
2123 }
2124 }
2125
2126 VbglR3SharedFolderFreeMappings(paMappings);
2127 return true;
2128}
2129
2130
2131/**
2132 * @interface_method_impl{VBOXSERVICE,pfnWorker}
2133 */
2134static DECLCALLBACK(int) vbsvcAutomounterWorker(bool volatile *pfShutdown)
2135{
2136 /*
2137 * Tell the control thread that it can continue spawning services.
2138 */
2139 RTThreadUserSignal(RTThreadSelf());
2140
2141 /* Divert old hosts to original auto-mount code. */
2142 if (!g_fHostSupportsWaitAndInfoQuery)
2143 return vbsvcAutoMountWorkerOld(pfShutdown);
2144
2145 /*
2146 * Initialize the state in case we're restarted...
2147 */
2148 VBSVCAUTOMOUNTERTABLE MountTable = { 0, 0, NULL };
2149 int rc = vbsvcAutomounterPopulateTable(&MountTable);
2150 if (RT_FAILURE(rc))
2151 {
2152 VGSvcError("vbsvcAutomounterWorker: vbsvcAutomounterPopulateTable failed (%Rrc), quitting!\n", rc);
2153 return rc;
2154 }
2155
2156 /*
2157 * Work loop.
2158 */
2159 uint32_t uConfigVer = UINT32_MAX;
2160 uint32_t uNewVersion = 0;
2161 bool fForceRefresh = true;
2162 while (!*pfShutdown)
2163 {
2164 /*
2165 * Update the mounts.
2166 */
2167 if ( uConfigVer != uNewVersion
2168 || fForceRefresh)
2169 {
2170 fForceRefresh = !vbsvcAutomounterRefreshTable(&MountTable);
2171 uConfigVer = uNewVersion;
2172 }
2173
2174 /*
2175 * Wait for more to do.
2176 */
2177 if (!*pfShutdown)
2178 {
2179 uNewVersion = uConfigVer - 1;
2180 VGSvcVerbose(2, "vbsvcAutomounterWorker: Waiting with uConfigVer=%u\n", uConfigVer);
2181 rc = VbglR3SharedFolderWaitForMappingsChanges(g_idClientSharedFolders, uConfigVer, &uNewVersion);
2182 VGSvcVerbose(2, "vbsvcAutomounterWorker: Woke up with uNewVersion=%u and rc=%Rrc\n", uNewVersion, rc);
2183
2184 /* Delay a little before doing a table refresh so the GUI can finish
2185 all its updates. Delay a little longer on non-shutdown failure to
2186 avoid eating too many CPU cycles if something goes wrong here... */
2187 if (!*pfShutdown)
2188 RTSemEventMultiWait(g_hAutoMountEvent, RT_SUCCESS(rc) ? 256 : 1000);
2189 }
2190 }
2191
2192 /*
2193 * Destroy the mount table.
2194 */
2195 while (MountTable.cEntries-- > 0)
2196 RTMemFree(MountTable.papEntries[MountTable.cEntries]);
2197 MountTable.papEntries = NULL;
2198
2199 VGSvcVerbose(3, "vbsvcAutomounterWorker: Finished\n");
2200 return VINF_SUCCESS;
2201}
2202
2203
2204/**
2205 * @interface_method_impl{VBOXSERVICE,pfnStop}
2206 */
2207static DECLCALLBACK(void) vbsvcAutomounterStop(void)
2208{
2209 RTSemEventMultiSignal(g_hAutoMountEvent);
2210 if (g_fHostSupportsWaitAndInfoQuery)
2211 VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
2212}
2213
2214
2215/**
2216 * @interface_method_impl{VBOXSERVICE,pfnTerm}
2217 */
2218static DECLCALLBACK(void) vbsvcAutomounterTerm(void)
2219{
2220 VGSvcVerbose(3, "vbsvcAutoMountTerm\n");
2221
2222 if (g_fHostSupportsWaitAndInfoQuery)
2223 VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
2224
2225 VbglR3SharedFolderDisconnect(g_idClientSharedFolders);
2226 g_idClientSharedFolders = 0;
2227
2228 if (g_hAutoMountEvent != NIL_RTSEMEVENTMULTI)
2229 {
2230 RTSemEventMultiDestroy(g_hAutoMountEvent);
2231 g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
2232 }
2233}
2234
2235
2236/**
2237 * The 'automount' service description.
2238 */
2239VBOXSERVICE g_AutoMount =
2240{
2241 /* pszName. */
2242 "automount",
2243 /* pszDescription. */
2244 "Automounter for Shared Folders",
2245 /* pszUsage. */
2246 NULL,
2247 /* pszOptions. */
2248 NULL,
2249 /* methods */
2250 VGSvcDefaultPreInit,
2251 VGSvcDefaultOption,
2252 vbsvcAutomounterInit,
2253 vbsvcAutomounterWorker,
2254 vbsvcAutomounterStop,
2255 vbsvcAutomounterTerm
2256};
2257
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