summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedFolders/testcase
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedFolders/testcase')
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk94
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp1332
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h130
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp442
-rw-r--r--src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp134
5 files changed, 2132 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk b/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk
new file mode 100644
index 00000000..7096d4e8
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/Makefile.kmk
@@ -0,0 +1,94 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the Shared Folders Host Service testcases.
+#
+
+#
+# Copyright (C) 2006-2019 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# Structure size testcase.
+#
+PROGRAMS += tstShflSizes
+TESTING += $(tstShflSizes_0_OUTDIR)/tstShflSizes.run
+ifndef VBOX_ONLY_SDK
+ ifeq ($(KBUILD_TARGET),$(KBUILD_HOST))
+ if1of ($(KBUILD_TARGET_ARCH).$(KBUILD_HOST_ARCH), x86.x86 amd64.amd64 x86.amd64)
+ OTHERS += $(tstShflSizes_0_OUTDIR)/tstShflSizes.run
+ endif
+ endif
+endif
+tstShflSizes_TEMPLATE = VBOXR3AUTOTST
+tstShflSizes_DEFS = VBOX_WITH_HGCM
+tstShflSizes_SOURCES = tstShflSizes.cpp
+tstShflSizes_CLEAN = $(tstShflSizes_0_OUTDIR)/tstShflSizes.run
+
+$$(tstShflSizes_0_OUTDIR)/tstShflSizes.run: $$(tstShflSizes_1_STAGE_TARGET)
+ $(tstShflSizes_1_STAGE_TARGET) quiet
+ $(QUIET)$(APPEND) -t "$@" "done"
+
+
+ifdef VBOX_WITH_TESTCASES
+#
+# Case conversion testcase.
+#
+PROGRAMS += tstShflCase
+tstShflCase_TEMPLATE = VBOXR3TSTEXE
+tstShflCase_DEFS = VBOX_WITH_HGCM
+tstShflCase_SOURCES = tstShflCase.cpp
+tstShflCase_LIBS = $(LIB_RUNTIME)
+
+#
+# HGCM service testcase.
+#
+
+PROGRAMS += tstSharedFolderService
+tstSharedFolderService_TEMPLATE = VBOXR3TSTEXE
+tstSharedFolderService_DEFS = VBOX_WITH_HGCM UNITTEST
+tstSharedFolderService_INCS = ..
+tstSharedFolderService_SOURCES = \
+ tstSharedFolderService.cpp \
+ ../mappings.cpp \
+ ../VBoxSharedFoldersSvc.cpp \
+ ../shflhandle.cpp \
+ ../vbsfpathabs.cpp \
+ ../vbsfpath.cpp \
+ ../vbsf.cpp
+tstSharedFolderService_LDFLAGS.darwin = \
+ -framework Carbon
+tstSharedFolderService_LIBS = $(LIB_RUNTIME)
+
+if 0 # Cannot define two RT_OS_XXX macros!
+# As there are differences between the Windows build of the service and others,
+# we do an additional build with RT_OS_WINDOWS defined on non-Windows targets.
+PROGRAMS += \
+ tstSharedFolderService \
+ $(if $(eq $(KBUILD_TARGET),win),,tstSharedFolderService-win)
+tstSharedFolderService-win_TEMPLATE = $(tstSharedFolderService_TEMPLATE)
+tstSharedFolderService-win_DEFS = \
+ $(tstSharedFolderService_DEFS) \
+ RT_OS_WINDOWS
+tstSharedFolderService-win_INCS = $(tstSharedFolderService_INCS)
+tstSharedFolderService-win_SOURCES = $(tstSharedFolderService_SOURCES)
+tstSharedFolderService-win_LDFLAGS.darwin = \
+ $(tstSharedFolderService_LDFLAGS.darwin)
+tstSharedFolderService-win_LIBS = $(tstSharedFolderService_LIBS)
+endif
+
+endif # VBOX_WITH_TESTCASES
+
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp
new file mode 100644
index 00000000..9706ded0
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.cpp
@@ -0,0 +1,1332 @@
+/* $Id: tstSharedFolderService.cpp $ */
+/** @file
+ * Testcase for the shared folder service vbsf API.
+ *
+ * Note that this is still very threadbare (there is an awful lot which should
+ * really be tested, but it already took too long to produce this much). The
+ * idea is that anyone who makes changes to the shared folders service and who
+ * cares about unit testing them should add tests to the skeleton framework to
+ * exercise the bits they change before and after changing them.
+ */
+
+/*
+ * Copyright (C) 2011-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+
+#include "tstSharedFolderService.h"
+#include "vbsf.h"
+
+#include <iprt/fs.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
+#include <iprt/symlink.h>
+#include <iprt/stream.h>
+#include <iprt/test.h>
+#include <iprt/string.h>
+#include <iprt/utf16.h>
+
+#include "teststubs.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static RTTEST g_hTest = NIL_RTTEST;
+
+
+/*********************************************************************************************************************************
+* Declarations *
+*********************************************************************************************************************************/
+extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
+
+
+/*********************************************************************************************************************************
+* Helpers *
+*********************************************************************************************************************************/
+
+/** Simple call handle structure for the guest call completion callback */
+struct VBOXHGCMCALLHANDLE_TYPEDEF
+{
+ /** Where to store the result code */
+ int32_t rc;
+};
+
+/** Call completion callback for guest calls. */
+static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
+{
+ callHandle->rc = rc;
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) stamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
+ STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
+{
+ RT_NOREF(pvInstance, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) stamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va)
+{
+ RT_NOREF(pvInstance, pszPatFmt, va);
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) infoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
+ PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
+{
+ RT_NOREF(pvInstance, pszName, pszDesc, pfnHandler, pvUser);
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) infoDeregister(void *pvInstance, const char *pszName)
+{
+ RT_NOREF(pvInstance, pszName);
+ return VINF_SUCCESS;
+}
+
+/**
+ * Initialise the HGCM service table as much as we need to start the
+ * service
+ * @param pTable the table to initialise
+ */
+void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
+{
+ pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
+ pTable->u32Version = VBOX_HGCM_SVC_VERSION;
+ pHelpers->pfnCallComplete = callComplete;
+ pHelpers->pfnStamRegisterV = stamRegisterV;
+ pHelpers->pfnStamDeregisterV = stamDeregisterV;
+ pHelpers->pfnInfoRegister = infoRegister;
+ pHelpers->pfnInfoDeregister = infoDeregister;
+ pTable->pHelpers = pHelpers;
+}
+
+#define LLUIFY(a) ((unsigned long long)(a))
+
+static void bufferFromString(void *pvDest, size_t cb, const char *pcszSrc)
+{
+ char *pchDest = (char *)pvDest;
+
+ Assert((cb) > 0);
+ strncpy((pchDest), (pcszSrc), (cb) - 1);
+ (pchDest)[(cb) - 1] = 0;
+}
+
+static void bufferFromPath(void *pvDest, size_t cb, const char *pcszSrc)
+{
+ char *psz;
+
+ bufferFromString(pvDest, cb, pcszSrc);
+ for (psz = (char *)pvDest; psz && psz < (char *)pvDest + cb; ++psz)
+ if (*psz == '\\')
+ *psz = '/';
+}
+
+#define ARRAY_FROM_PATH(a, b) \
+ do { \
+ void *p=(a); NOREF(p); \
+ Assert((a) == p); /* Constant parameter */ \
+ Assert(sizeof((a)) > 0); \
+ bufferFromPath(a, sizeof(a), b); \
+ } while (0)
+
+
+/*********************************************************************************************************************************
+* Stub functions and data *
+*********************************************************************************************************************************/
+static bool g_fFailIfNotLowercase = false;
+
+static RTDIR g_testRTDirClose_hDir = NIL_RTDIR;
+
+extern int testRTDirClose(RTDIR hDir)
+{
+ /* RTPrintf("%s: hDir=%p\n", __PRETTY_FUNCTION__, hDir); */
+ g_testRTDirClose_hDir = hDir;
+ return VINF_SUCCESS;
+}
+
+static char testRTDirCreatePath[256];
+//static RTFMODE testRTDirCreateMode; - unused
+
+extern int testRTDirCreate(const char *pszPath, RTFMODE fMode, uint32_t fCreate)
+{
+ RT_NOREF2(fMode, fCreate);
+ /* RTPrintf("%s: pszPath=%s, fMode=0x%llx\n", __PRETTY_FUNCTION__, pszPath,
+ LLUIFY(fMode)); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ ARRAY_FROM_PATH(testRTDirCreatePath, pszPath);
+ return 0;
+}
+
+static char testRTDirOpenName[256];
+static struct TESTDIRHANDLE
+{
+ int iEntry;
+ int iDir;
+} g_aTestDirHandles[4];
+static int g_iNextDirHandle = 0;
+static RTDIR testRTDirOpen_hDir;
+
+extern int testRTDirOpen(RTDIR *phDir, const char *pszPath)
+{
+ /* RTPrintf("%s: pszPath=%s\n", __PRETTY_FUNCTION__, pszPath); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ ARRAY_FROM_PATH(testRTDirOpenName, pszPath);
+ *phDir = testRTDirOpen_hDir;
+ testRTDirOpen_hDir = NIL_RTDIR;
+ if (!*phDir && g_fFailIfNotLowercase)
+ *phDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ if (*phDir)
+ {
+ struct TESTDIRHANDLE *pRealDir = (struct TESTDIRHANDLE *)*phDir;
+ pRealDir->iEntry = 0;
+ pRealDir->iDir = 0;
+ const char *pszSlash = pszPath - 1;
+ while ((pszSlash = strpbrk(pszSlash + 1, "\\/")) != NULL)
+ pRealDir->iDir += 1;
+ /*RTPrintf("opendir %s = %d \n", pszPath, pRealDir->iDir);*/
+ }
+ return VINF_SUCCESS;
+}
+
+/** @todo Do something useful with the last two arguments. */
+extern int testRTDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER, uint32_t)
+{
+ /* RTPrintf("%s: pszPath=%s\n", __PRETTY_FUNCTION__, pszPath); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ ARRAY_FROM_PATH(testRTDirOpenName, pszPath);
+ *phDir = testRTDirOpen_hDir;
+ testRTDirOpen_hDir = NIL_RTDIR;
+ if (!*phDir && g_fFailIfNotLowercase)
+ *phDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ if (*phDir)
+ {
+ struct TESTDIRHANDLE *pRealDir = (struct TESTDIRHANDLE *)*phDir;
+ pRealDir->iEntry = 0;
+ pRealDir->iDir = 0;
+ const char *pszSlash = pszPath - 1;
+ while ((pszSlash = strpbrk(pszSlash + 1, "\\/")) != NULL)
+ pRealDir->iDir += 1;
+ pRealDir->iDir -= 1;
+ /*RTPrintf("openfiltered %s = %d\n", pszPath, pRealDir->iDir);*/
+ }
+ return VINF_SUCCESS;
+}
+
+static RTDIR g_testRTDirQueryInfo_hDir;
+static RTTIMESPEC testRTDirQueryInfoATime;
+
+extern int testRTDirQueryInfo(RTDIR hDir, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
+{
+ RT_NOREF1(enmAdditionalAttribs);
+ /* RTPrintf("%s: hDir=%p, enmAdditionalAttribs=0x%llx\n", __PRETTY_FUNCTION__,
+ hDir, LLUIFY(enmAdditionalAttribs)); */
+ g_testRTDirQueryInfo_hDir = hDir;
+ RT_ZERO(*pObjInfo);
+ pObjInfo->AccessTime = testRTDirQueryInfoATime;
+ RT_ZERO(testRTDirQueryInfoATime);
+ return VINF_SUCCESS;
+}
+
+extern int testRTDirRemove(const char *pszPath)
+{
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+static RTDIR g_testRTDirReadEx_hDir;
+
+extern int testRTDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
+ RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ RT_NOREF4(pDirEntry, pcbDirEntry, enmAdditionalAttribs, fFlags);
+ /* RTPrintf("%s: hDir=%p, pcbDirEntry=%d, enmAdditionalAttribs=%llu, fFlags=0x%llx\n",
+ __PRETTY_FUNCTION__, hDir, pcbDirEntry ? (int) *pcbDirEntry : -1,
+ LLUIFY(enmAdditionalAttribs), LLUIFY(fFlags)); */
+ g_testRTDirReadEx_hDir = hDir;
+ if (g_fFailIfNotLowercase && hDir != NIL_RTDIR)
+ {
+ struct TESTDIRHANDLE *pRealDir = (struct TESTDIRHANDLE *)hDir;
+ if (pRealDir->iDir == 2) /* /test/mapping/ */
+ {
+ if (pRealDir->iEntry == 0)
+ {
+ pRealDir->iEntry++;
+ RT_ZERO(*pDirEntry);
+ pDirEntry->Info.Attr.fMode = RTFS_TYPE_DIRECTORY | RTFS_DOS_DIRECTORY | RTFS_UNIX_IROTH | RTFS_UNIX_IXOTH;
+ pDirEntry->cbName = 4;
+ pDirEntry->cwcShortName = 4;
+ strcpy(pDirEntry->szName, "test");
+ RTUtf16CopyAscii(pDirEntry->wszShortName, RT_ELEMENTS(pDirEntry->wszShortName), "test");
+ /*RTPrintf("readdir: 'test'\n");*/
+ return VINF_SUCCESS;
+ }
+ }
+ else if (pRealDir->iDir == 3) /* /test/mapping/test/ */
+ {
+ if (pRealDir->iEntry == 0)
+ {
+ pRealDir->iEntry++;
+ RT_ZERO(*pDirEntry);
+ pDirEntry->Info.Attr.fMode = RTFS_TYPE_FILE | RTFS_DOS_NT_NORMAL | RTFS_UNIX_IROTH | RTFS_UNIX_IXOTH;
+ pDirEntry->cbName = 4;
+ pDirEntry->cwcShortName = 4;
+ strcpy(pDirEntry->szName, "file");
+ RTUtf16CopyAscii(pDirEntry->wszShortName, RT_ELEMENTS(pDirEntry->wszShortName), "file");
+ /*RTPrintf("readdir: 'file'\n");*/
+ return VINF_SUCCESS;
+ }
+ }
+ /*else RTPrintf("%s: iDir=%d\n", pRealDir->iDir);*/
+ }
+ return VERR_NO_MORE_FILES;
+}
+
+static RTTIMESPEC testRTDirSetTimesATime;
+
+extern int testRTDirSetTimes(RTDIR hDir, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+ PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+ RT_NOREF4(hDir, pModificationTime, pChangeTime, pBirthTime);
+ /* RTPrintf("%s: hDir=%p, *pAccessTime=%lli, *pModificationTime=%lli, *pChangeTime=%lli, *pBirthTime=%lli\n",
+ __PRETTY_FUNCTION__, hDir,
+ pAccessTime ? (long long)RTTimeSpecGetNano(pAccessTime) : -1,
+ pModificationTime
+ ? (long long)RTTimeSpecGetNano(pModificationTime) : -1,
+ pChangeTime ? (long long)RTTimeSpecGetNano(pChangeTime) : -1,
+ pBirthTime ? (long long)RTTimeSpecGetNano(pBirthTime) : -1); */
+ if (pAccessTime)
+ testRTDirSetTimesATime = *pAccessTime;
+ else
+ RT_ZERO(testRTDirSetTimesATime);
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileCloseFile;
+
+extern int testRTFileClose(RTFILE File)
+{
+ /* RTPrintf("%s: File=%p\n", __PRETTY_FUNCTION__, File); */
+ g_testRTFileCloseFile = File;
+ return 0;
+}
+
+extern int testRTFileDelete(const char *pszFilename)
+{
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszFilename, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+static RTFILE g_testRTFileFlushFile;
+
+extern int testRTFileFlush(RTFILE File)
+{
+ /* RTPrintf("%s: File=%p\n", __PRETTY_FUNCTION__, File); */
+ g_testRTFileFlushFile = File;
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileLockFile;
+static unsigned testRTFileLockfLock;
+static int64_t testRTFileLockOffset;
+static uint64_t testRTFileLockSize;
+
+extern int testRTFileLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
+{
+ /* RTPrintf("%s: hFile=%p, fLock=%u, offLock=%lli, cbLock=%llu\n",
+ __PRETTY_FUNCTION__, hFile, fLock, (long long) offLock,
+ LLUIFY(cbLock)); */
+ g_testRTFileLockFile = hFile;
+ testRTFileLockfLock = fLock;
+ testRTFileLockOffset = offLock;
+ testRTFileLockSize = cbLock;
+ return VINF_SUCCESS;
+}
+
+static char testRTFileOpenName[256];
+static uint64_t testRTFileOpenFlags;
+static RTFILE testRTFileOpenpFile;
+
+extern int testRTFileOpen(PRTFILE pFile, const char *pszFilename, uint64_t fOpen)
+{
+ /* RTPrintf("%s, pszFilename=%s, fOpen=0x%llx\n", __PRETTY_FUNCTION__,
+ pszFilename, LLUIFY(fOpen)); */
+ ARRAY_FROM_PATH(testRTFileOpenName, pszFilename);
+ testRTFileOpenFlags = fOpen;
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszFilename, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ *pFile = testRTFileOpenpFile;
+ testRTFileOpenpFile = 0;
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileQueryInfoFile;
+static RTTIMESPEC testRTFileQueryInfoATime;
+static uint32_t testRTFileQueryInfoFMode;
+
+extern int testRTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
+{
+ RT_NOREF1(enmAdditionalAttribs);
+ /* RTPrintf("%s, hFile=%p, enmAdditionalAttribs=0x%llx\n",
+ __PRETTY_FUNCTION__, hFile, LLUIFY(enmAdditionalAttribs)); */
+ g_testRTFileQueryInfoFile = hFile;
+ RT_ZERO(*pObjInfo);
+ pObjInfo->AccessTime = testRTFileQueryInfoATime;
+ RT_ZERO(testRTDirQueryInfoATime);
+ pObjInfo->Attr.fMode = testRTFileQueryInfoFMode;
+ testRTFileQueryInfoFMode = 0;
+ return VINF_SUCCESS;
+}
+
+static const char *testRTFileReadData;
+
+extern int testRTFileRead(RTFILE File, void *pvBuf, size_t cbToRead, size_t *pcbRead)
+{
+ RT_NOREF1(File);
+ /* RTPrintf("%s : File=%p, cbToRead=%llu\n", __PRETTY_FUNCTION__, File,
+ LLUIFY(cbToRead)); */
+ bufferFromPath(pvBuf, cbToRead, testRTFileReadData);
+ if (pcbRead)
+ *pcbRead = RT_MIN(cbToRead, strlen(testRTFileReadData) + 1);
+ testRTFileReadData = 0;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFileSeek(RTFILE hFile, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
+{
+ RT_NOREF3(hFile, offSeek, uMethod);
+ /* RTPrintf("%s : hFile=%p, offSeek=%llu, uMethod=%u\n", __PRETTY_FUNCTION__,
+ hFile, LLUIFY(offSeek), uMethod); */
+ if (poffActual)
+ *poffActual = 0;
+ return VINF_SUCCESS;
+}
+
+static uint64_t testRTFileSetFMode;
+
+extern int testRTFileSetMode(RTFILE File, RTFMODE fMode)
+{
+ RT_NOREF1(File);
+ /* RTPrintf("%s: fMode=%llu\n", __PRETTY_FUNCTION__, LLUIFY(fMode)); */
+ testRTFileSetFMode = fMode;
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileSetSizeFile;
+static RTFOFF testRTFileSetSizeSize;
+
+extern int testRTFileSetSize(RTFILE File, uint64_t cbSize)
+{
+ /* RTPrintf("%s: File=%llu, cbSize=%llu\n", __PRETTY_FUNCTION__, LLUIFY(File),
+ LLUIFY(cbSize)); */
+ g_testRTFileSetSizeFile = File;
+ testRTFileSetSizeSize = (RTFOFF) cbSize; /* Why was this signed before? */
+ return VINF_SUCCESS;
+}
+
+static RTTIMESPEC testRTFileSetTimesATime;
+
+extern int testRTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+ PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+ RT_NOREF4(File, pModificationTime, pChangeTime, pBirthTime);
+ /* RTPrintf("%s: pFile=%p, *pAccessTime=%lli, *pModificationTime=%lli, *pChangeTime=%lli, *pBirthTime=%lli\n",
+ __PRETTY_FUNCTION__,
+ pAccessTime ? (long long)RTTimeSpecGetNano(pAccessTime) : -1,
+ pModificationTime
+ ? (long long)RTTimeSpecGetNano(pModificationTime) : -1,
+ pChangeTime ? (long long)RTTimeSpecGetNano(pChangeTime) : -1,
+ pBirthTime ? (long long)RTTimeSpecGetNano(pBirthTime) : -1); */
+ if (pAccessTime)
+ testRTFileSetTimesATime = *pAccessTime;
+ else
+ RT_ZERO(testRTFileSetTimesATime);
+ return VINF_SUCCESS;
+}
+
+static RTFILE g_testRTFileUnlockFile;
+static int64_t testRTFileUnlockOffset;
+static uint64_t testRTFileUnlockSize;
+
+extern int testRTFileUnlock(RTFILE File, int64_t offLock, uint64_t cbLock)
+{
+ /* RTPrintf("%s: hFile=%p, ofLock=%lli, cbLock=%llu\n", __PRETTY_FUNCTION__,
+ File, (long long) offLock, LLUIFY(cbLock)); */
+ g_testRTFileUnlockFile = File;
+ testRTFileUnlockOffset = offLock;
+ testRTFileUnlockSize = cbLock;
+ return VINF_SUCCESS;
+}
+
+static char testRTFileWriteData[256];
+
+extern int testRTFileWrite(RTFILE File, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
+{
+ RT_NOREF2(File, cbToWrite);
+ /* RTPrintf("%s: File=%p, pvBuf=%.*s, cbToWrite=%llu\n", __PRETTY_FUNCTION__,
+ File, cbToWrite, (const char *)pvBuf, LLUIFY(cbToWrite)); */
+ ARRAY_FROM_PATH(testRTFileWriteData, (const char *)pvBuf);
+ if (pcbWritten)
+ *pcbWritten = strlen(testRTFileWriteData) + 1;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties)
+{
+ RT_NOREF1(pszFsPath);
+ /* RTPrintf("%s, pszFsPath=%s\n", __PRETTY_FUNCTION__, pszFsPath);
+ RT_ZERO(*pProperties); */
+ pProperties->cbMaxComponent = 256;
+ pProperties->fCaseSensitive = true;
+ return VINF_SUCCESS;
+}
+
+extern int testRTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
+{
+ RT_NOREF2(pszFsPath, pu32Serial);
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+extern int testRTFsQuerySizes(const char *pszFsPath, PRTFOFF pcbTotal, RTFOFF *pcbFree, uint32_t *pcbBlock, uint32_t *pcbSector)
+{
+ RT_NOREF5(pszFsPath, pcbTotal, pcbFree, pcbBlock, pcbSector);
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+extern int testRTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ RT_NOREF2(enmAdditionalAttribs, fFlags);
+ /* RTPrintf("%s: pszPath=%s, enmAdditionalAttribs=0x%x, fFlags=0x%x\n",
+ __PRETTY_FUNCTION__, pszPath, (unsigned) enmAdditionalAttribs,
+ (unsigned) fFlags); */
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszPath, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RT_ZERO(*pObjInfo);
+ return VINF_SUCCESS;
+}
+
+extern int testRTSymlinkDelete(const char *pszSymlink, uint32_t fDelete)
+{
+ RT_NOREF2(pszSymlink, fDelete);
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszSymlink, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+extern int testRTSymlinkRead(const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead)
+{
+ if (g_fFailIfNotLowercase && !RTStrIsLowerCased(strpbrk(pszSymlink, "/\\")))
+ return VERR_FILE_NOT_FOUND;
+ RT_NOREF4(pszSymlink, pszTarget, cbTarget, fRead);
+ RTPrintf("%s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+
+/*********************************************************************************************************************************
+* Tests *
+*********************************************************************************************************************************/
+
+/* Sub-tests for testMappingsQuery(). */
+void testMappingsQuerySimple(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryTooFewBuffers(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryAutoMount(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryArrayWrongSize(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMappingsQueryName(). */
+void testMappingsQueryNameValid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryNameInvalid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMappingsQueryNameBadBuffer(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMapFolder(). */
+void testMapFolderValid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderInvalid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderTwice(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderDelimiter(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderCaseSensitive(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderCaseInsensitive(RTTEST hTest) { RT_NOREF1(hTest); }
+void testMapFolderBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testUnmapFolder(). */
+void testUnmapFolderValid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testUnmapFolderInvalid(RTTEST hTest) { RT_NOREF1(hTest); }
+void testUnmapFolderBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testCreate(). */
+void testCreateBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testClose(). */
+void testCloseBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testRead(). */
+void testReadBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testWrite(). */
+void testWriteBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testLock(). */
+void testLockBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testFlush(). */
+void testFlushBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testDirList(). */
+void testDirListBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testReadLink(). */
+void testReadLinkBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testFSInfo(). */
+void testFSInfoBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testRemove(). */
+void testRemoveBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testRename(). */
+void testRenameBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testSymlink(). */
+void testSymlinkBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMappingsAdd(). */
+void testMappingsAddBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+/* Sub-tests for testMappingsRemove(). */
+void testMappingsRemoveBadParameters(RTTEST hTest) { RT_NOREF1(hTest); }
+
+union TESTSHFLSTRING
+{
+ SHFLSTRING string;
+ char acData[256];
+};
+
+static void fillTestShflString(union TESTSHFLSTRING *pDest,
+ const char *pcszSource)
+{
+ const size_t cchSource = strlen(pcszSource);
+ AssertRelease( cchSource * 2 + 2
+ < sizeof(*pDest) - RT_UOFFSETOF(SHFLSTRING, String));
+ pDest->string.u16Length = (uint16_t)(cchSource * sizeof(RTUTF16));
+ pDest->string.u16Size = pDest->string.u16Length + sizeof(RTUTF16);
+ /* Copy pcszSource ASCIIZ, including the trailing 0, to the UTF16 pDest->string.String.ucs2. */
+ for (unsigned i = 0; i <= cchSource; ++i)
+ pDest->string.String.ucs2[i] = (uint16_t)pcszSource[i];
+}
+
+static SHFLROOT initWithWritableMapping(RTTEST hTest,
+ VBOXHGCMSVCFNTABLE *psvcTable,
+ VBOXHGCMSVCHELPERS *psvcHelpers,
+ const char *pcszFolderName,
+ const char *pcszMapping,
+ bool fCaseSensitive = true)
+{
+ VBOXHGCMSVCPARM aParms[RT_MAX(SHFL_CPARMS_ADD_MAPPING,
+ SHFL_CPARMS_MAP_FOLDER)];
+ union TESTSHFLSTRING FolderName;
+ union TESTSHFLSTRING Mapping;
+ union TESTSHFLSTRING AutoMountPoint;
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+ int rc;
+
+ initTable(psvcTable, psvcHelpers);
+ AssertReleaseRC(VBoxHGCMSvcLoad(psvcTable));
+ AssertRelease( psvcTable->pvService
+ = RTTestGuardedAllocTail(hTest, psvcTable->cbClient));
+ RT_BZERO(psvcTable->pvService, psvcTable->cbClient);
+ fillTestShflString(&FolderName, pcszFolderName);
+ fillTestShflString(&Mapping, pcszMapping);
+ fillTestShflString(&AutoMountPoint, "");
+ HGCMSvcSetPv(&aParms[0], &FolderName, RT_UOFFSETOF(SHFLSTRING, String)
+ + FolderName.string.u16Size);
+ HGCMSvcSetPv(&aParms[1], &Mapping, RT_UOFFSETOF(SHFLSTRING, String)
+ + Mapping.string.u16Size);
+ HGCMSvcSetU32(&aParms[2], 1);
+ HGCMSvcSetPv(&aParms[3], &AutoMountPoint, SHFLSTRING_HEADER_SIZE + AutoMountPoint.string.u16Size);
+ rc = psvcTable->pfnHostCall(psvcTable->pvService, SHFL_FN_ADD_MAPPING,
+ SHFL_CPARMS_ADD_MAPPING, aParms);
+ AssertReleaseRC(rc);
+ HGCMSvcSetPv(&aParms[0], &Mapping, RT_UOFFSETOF(SHFLSTRING, String)
+ + Mapping.string.u16Size);
+ HGCMSvcSetU32(&aParms[1], 0); /* root */
+ HGCMSvcSetU32(&aParms[2], '/'); /* delimiter */
+ HGCMSvcSetU32(&aParms[3], fCaseSensitive);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_MAP_FOLDER,
+ SHFL_CPARMS_MAP_FOLDER, aParms, 0);
+ AssertReleaseRC(callHandle.rc);
+ return aParms[1].u.uint32;
+}
+
+/** @todo Mappings should be automatically removed by unloading the service,
+ * but unloading is currently a no-op! */
+static void unmapAndRemoveMapping(RTTEST hTest, VBOXHGCMSVCFNTABLE *psvcTable,
+ SHFLROOT root, const char *pcszFolderName)
+{
+ RT_NOREF1(hTest);
+ VBOXHGCMSVCPARM aParms[RT_MAX(SHFL_CPARMS_UNMAP_FOLDER,
+ SHFL_CPARMS_REMOVE_MAPPING)];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+ union TESTSHFLSTRING FolderName;
+ int rc;
+
+ HGCMSvcSetU32(&aParms[0], root);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_UNMAP_FOLDER,
+ SHFL_CPARMS_UNMAP_FOLDER, aParms, 0);
+ AssertReleaseRC(callHandle.rc);
+ fillTestShflString(&FolderName, pcszFolderName);
+ HGCMSvcSetPv(&aParms[0], &FolderName, RT_UOFFSETOF(SHFLSTRING, String)
+ + FolderName.string.u16Size);
+ rc = psvcTable->pfnHostCall(psvcTable->pvService, SHFL_FN_REMOVE_MAPPING,
+ SHFL_CPARMS_REMOVE_MAPPING, aParms);
+ AssertReleaseRC(rc);
+}
+
+static int createFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT Root,
+ const char *pcszFilename, uint32_t fCreateFlags,
+ SHFLHANDLE *pHandle, SHFLCREATERESULT *pResult)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_CREATE];
+ union TESTSHFLSTRING Path;
+ SHFLCREATEPARMS CreateParms;
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ fillTestShflString(&Path, pcszFilename);
+ RT_ZERO(CreateParms);
+ CreateParms.CreateFlags = fCreateFlags;
+ HGCMSvcSetU32(&aParms[0], Root);
+ HGCMSvcSetPv(&aParms[1], &Path, RT_UOFFSETOF(SHFLSTRING, String)
+ + Path.string.u16Size);
+ HGCMSvcSetPv(&aParms[2], &CreateParms, sizeof(CreateParms));
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_CREATE,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (RT_FAILURE(callHandle.rc))
+ return callHandle.rc;
+ if (pHandle)
+ *pHandle = CreateParms.Handle;
+ if (pResult)
+ *pResult = CreateParms.Result;
+ return VINF_SUCCESS;
+}
+
+static int readFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT Root,
+ SHFLHANDLE hFile, uint64_t offSeek, uint32_t cbRead,
+ uint32_t *pcbRead, void *pvBuf, uint32_t cbBuf)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_READ];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], Root);
+ HGCMSvcSetU64(&aParms[1], (uint64_t) hFile);
+ HGCMSvcSetU64(&aParms[2], offSeek);
+ HGCMSvcSetU32(&aParms[3], cbRead);
+ HGCMSvcSetPv(&aParms[4], pvBuf, cbBuf);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_READ,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (pcbRead)
+ *pcbRead = aParms[3].u.uint32;
+ return callHandle.rc;
+}
+
+static int writeFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT Root,
+ SHFLHANDLE hFile, uint64_t offSeek, uint32_t cbWrite,
+ uint32_t *pcbWritten, const void *pvBuf, uint32_t cbBuf)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_WRITE];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], Root);
+ HGCMSvcSetU64(&aParms[1], (uint64_t) hFile);
+ HGCMSvcSetU64(&aParms[2], offSeek);
+ HGCMSvcSetU32(&aParms[3], cbWrite);
+ HGCMSvcSetPv(&aParms[4], (void *)pvBuf, cbBuf);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_WRITE,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (pcbWritten)
+ *pcbWritten = aParms[3].u.uint32;
+ return callHandle.rc;
+}
+
+static int flushFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_FLUSH];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_FLUSH,
+ SHFL_CPARMS_FLUSH, aParms, 0);
+ return callHandle.rc;
+}
+
+static int listDir(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle, uint32_t fFlags,
+ const char *pcszPath, void *pvBuf, uint32_t cbBuf,
+ uint32_t resumePoint, uint32_t *pcFiles)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_LIST];
+ union TESTSHFLSTRING Path;
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ HGCMSvcSetU32(&aParms[2], fFlags);
+ HGCMSvcSetU32(&aParms[3], cbBuf);
+ if (pcszPath)
+ {
+ fillTestShflString(&Path, pcszPath);
+ HGCMSvcSetPv(&aParms[4], &Path, RT_UOFFSETOF(SHFLSTRING, String)
+ + Path.string.u16Size);
+ }
+ else
+ HGCMSvcSetPv(&aParms[4], NULL, 0);
+ HGCMSvcSetPv(&aParms[5], pvBuf, cbBuf);
+ HGCMSvcSetU32(&aParms[6], resumePoint);
+ HGCMSvcSetU32(&aParms[7], 0);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_LIST,
+ RT_ELEMENTS(aParms), aParms, 0);
+ if (pcFiles)
+ *pcFiles = aParms[7].u.uint32;
+ return callHandle.rc;
+}
+
+static int sfInformation(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle, uint32_t fFlags, uint32_t cb,
+ SHFLFSOBJINFO *pInfo)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_INFORMATION];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ HGCMSvcSetU32(&aParms[2], fFlags);
+ HGCMSvcSetU32(&aParms[3], cb);
+ HGCMSvcSetPv(&aParms[4], pInfo, cb);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_INFORMATION,
+ RT_ELEMENTS(aParms), aParms, 0);
+ return callHandle.rc;
+}
+
+static int lockFile(VBOXHGCMSVCFNTABLE *psvcTable, SHFLROOT root,
+ SHFLHANDLE handle, int64_t offLock, uint64_t cbLock,
+ uint32_t fFlags)
+{
+ VBOXHGCMSVCPARM aParms[SHFL_CPARMS_LOCK];
+ VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
+
+ HGCMSvcSetU32(&aParms[0], root);
+ HGCMSvcSetU64(&aParms[1], handle);
+ HGCMSvcSetU64(&aParms[2], offLock);
+ HGCMSvcSetU64(&aParms[3], cbLock);
+ HGCMSvcSetU32(&aParms[4], fFlags);
+ psvcTable->pfnCall(psvcTable->pvService, &callHandle, 0,
+ psvcTable->pvService, SHFL_FN_LOCK,
+ RT_ELEMENTS(aParms), aParms, 0);
+ return callHandle.rc;
+}
+
+void testCreateFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ SHFLCREATERESULT Result;
+ int rc;
+
+ RTTestSub(hTest, "Create file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ, NULL,
+ &Result);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/file"),
+ (hTest, "pszFilename=%s\n", &testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest, testRTFileOpenFlags == 0x181,
+ (hTest, "fOpen=%llu\n", LLUIFY(testRTFileOpenFlags)));
+ RTTEST_CHECK_MSG(hTest, Result == SHFL_FILE_CREATED,
+ (hTest, "Result=%d\n", (int) Result));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile,
+ (hTest, "File=%u\n", (uintptr_t)g_testRTFileCloseFile));
+}
+
+void testCreateFileSimpleCaseInsensitive(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ SHFLCREATERESULT Result;
+ int rc;
+
+ g_fFailIfNotLowercase = true;
+
+ RTTestSub(hTest, "Create file case insensitive");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname", false /*fCaseSensitive*/);
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/TesT/FilE", SHFL_CF_ACCESS_READ, NULL,
+ &Result);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/file"),
+ (hTest, "pszFilename=%s\n", &testRTFileOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest, testRTFileOpenFlags == 0x181,
+ (hTest, "fOpen=%llu\n", LLUIFY(testRTFileOpenFlags)));
+ RTTEST_CHECK_MSG(hTest, Result == SHFL_FILE_CREATED,
+ (hTest, "Result=%d\n", (int) Result));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile,
+ (hTest, "File=%u\n", (uintptr_t)g_testRTFileCloseFile));
+
+ g_fFailIfNotLowercase = false;
+}
+
+void testCreateDirSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ RTDIR hDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ SHFLCREATERESULT Result;
+ int rc;
+
+ RTTestSub(hTest, "Create directory simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTDirOpen_hDir = hDir;
+ rc = createFile(&svcTable, Root, "test/dir",
+ SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ, NULL, &Result);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&testRTDirCreatePath[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/dir"),
+ (hTest, "pszPath=%s\n", &testRTDirCreatePath[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(&testRTDirOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0],
+ "/test/mapping/test/dir"),
+ (hTest, "pszFilename=%s\n", &testRTDirOpenName[RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS ? 2 : 0]));
+ RTTEST_CHECK_MSG(hTest, Result == SHFL_FILE_CREATED,
+ (hTest, "Result=%d\n", (int) Result));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirClose_hDir == hDir, (hTest, "hDir=%p\n", g_testRTDirClose_hDir));
+}
+
+void testReadFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ SHFLHANDLE Handle;
+ const char *pcszReadData = "Data to read";
+ char acBuf[sizeof(pcszReadData) + 10];
+ uint32_t cbRead;
+ int rc;
+
+ RTTestSub(hTest, "Read file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ testRTFileReadData = pcszReadData;
+ rc = readFile(&svcTable, Root, Handle, 0, (uint32_t)strlen(pcszReadData) + 1,
+ &cbRead, acBuf, (uint32_t)sizeof(acBuf));
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strncmp(acBuf, pcszReadData, sizeof(acBuf)),
+ (hTest, "pvBuf=%.*s\n", sizeof(acBuf), acBuf));
+ RTTEST_CHECK_MSG(hTest, cbRead == strlen(pcszReadData) + 1,
+ (hTest, "cbRead=%llu\n", LLUIFY(cbRead)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+}
+
+void testWriteFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ SHFLHANDLE Handle;
+ const char *pcszWrittenData = "Data to write";
+ uint32_t cbToWrite = (uint32_t)strlen(pcszWrittenData) + 1;
+ uint32_t cbWritten;
+ int rc;
+
+ RTTestSub(hTest, "Write file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = writeFile(&svcTable, Root, Handle, 0, cbToWrite, &cbWritten,
+ pcszWrittenData, cbToWrite);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest,
+ !strcmp(testRTFileWriteData, pcszWrittenData),
+ (hTest, "pvBuf=%s\n", testRTFileWriteData));
+ RTTEST_CHECK_MSG(hTest, cbWritten == cbToWrite,
+ (hTest, "cbWritten=%llu\n", LLUIFY(cbWritten)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+}
+
+void testFlushFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Flush file simple");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = flushFile(&svcTable, Root, Handle);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileFlushFile == hcFile, (hTest, "File=%u\n", g_testRTFileFlushFile));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+}
+
+void testDirListEmpty(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ RTDIR hDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ SHFLHANDLE Handle;
+ union
+ {
+ SHFLDIRINFO DirInfo;
+ uint8_t abBuffer[sizeof(SHFLDIRINFO) + 2 * sizeof(RTUTF16)];
+ } Buf;
+ uint32_t cFiles;
+ int rc;
+
+ RTTestSub(hTest, "List empty directory");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTDirOpen_hDir = hDir;
+ rc = createFile(&svcTable, Root, "test/dir",
+ SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ, &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = listDir(&svcTable, Root, Handle, 0, NULL, &Buf.DirInfo, sizeof(Buf), 0, &cFiles);
+ RTTEST_CHECK_RC(hTest, rc, VERR_NO_MORE_FILES);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirReadEx_hDir == hDir, (hTest, "Dir=%p\n", g_testRTDirReadEx_hDir));
+ RTTEST_CHECK_MSG(hTest, cFiles == 0,
+ (hTest, "cFiles=%llu\n", LLUIFY(cFiles)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirClose_hDir == hDir, (hTest, "hDir=%p\n", g_testRTDirClose_hDir));
+}
+
+void testFSInfoQuerySetFMode(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ const uint32_t fMode = 0660;
+ SHFLFSOBJINFO Info;
+ int rc;
+
+ RTTestSub(hTest, "Query and set file size");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ SHFLHANDLE Handle = SHFL_HANDLE_NIL;
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK_RETV(hTest, rc);
+
+ RT_ZERO(Info);
+ testRTFileQueryInfoFMode = fMode;
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info),
+ &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileQueryInfoFile == hcFile, (hTest, "File=%u\n", g_testRTFileQueryInfoFile));
+ RTTEST_CHECK_MSG(hTest, Info.Attr.fMode == fMode,
+ (hTest, "cbObject=%llu\n", LLUIFY(Info.cbObject)));
+ RT_ZERO(Info);
+ Info.Attr.fMode = fMode;
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_FILE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, testRTFileSetFMode == fMode,
+ (hTest, "Size=%llu\n", LLUIFY(testRTFileSetFMode)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+}
+
+void testFSInfoQuerySetDirATime(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTDIR hDir = (RTDIR)&g_aTestDirHandles[g_iNextDirHandle++ % RT_ELEMENTS(g_aTestDirHandles)];
+ const int64_t ccAtimeNano = 100000;
+ SHFLFSOBJINFO Info;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Query and set directory atime");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTDirOpen_hDir = hDir;
+ rc = createFile(&svcTable, Root, "test/dir",
+ SHFL_CF_DIRECTORY | SHFL_CF_ACCESS_READ, &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&testRTDirQueryInfoATime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info),
+ &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirQueryInfo_hDir == hDir, (hTest, "Dir=%p\n", g_testRTDirQueryInfo_hDir));
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&Info.AccessTime) == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&Info.AccessTime))));
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&Info.AccessTime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_FILE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&testRTDirSetTimesATime)
+ == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&testRTDirSetTimesATime))));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTDirClose_hDir == hDir, (hTest, "hDir=%p\n", g_testRTDirClose_hDir));
+}
+
+void testFSInfoQuerySetFileATime(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ const int64_t ccAtimeNano = 100000;
+ SHFLFSOBJINFO Info;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Query and set file atime");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&testRTFileQueryInfoATime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_FILE, sizeof(Info),
+ &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileQueryInfoFile == hcFile, (hTest, "File=%u\n", g_testRTFileQueryInfoFile));
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&Info.AccessTime) == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&Info.AccessTime))));
+ RT_ZERO(Info);
+ RTTimeSpecSetNano(&Info.AccessTime, ccAtimeNano);
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_FILE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, RTTimeSpecGetNano(&testRTFileSetTimesATime)
+ == ccAtimeNano,
+ (hTest, "ATime=%llu\n",
+ LLUIFY(RTTimeSpecGetNano(&testRTFileSetTimesATime))));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+}
+
+void testFSInfoQuerySetEndOfFile(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ const RTFOFF cbNew = 50000;
+ SHFLFSOBJINFO Info;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Set end of file position");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RT_ZERO(Info);
+ Info.cbObject = cbNew;
+ rc = sfInformation(&svcTable, Root, Handle, SHFL_INFO_SET | SHFL_INFO_SIZE,
+ sizeof(Info), &Info);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileSetSizeFile == hcFile, (hTest, "File=%u\n", g_testRTFileSetSizeFile));
+ RTTEST_CHECK_MSG(hTest, testRTFileSetSizeSize == cbNew,
+ (hTest, "Size=%llu\n", LLUIFY(testRTFileSetSizeSize)));
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+}
+
+void testLockFileSimple(RTTEST hTest)
+{
+ VBOXHGCMSVCFNTABLE svcTable;
+ VBOXHGCMSVCHELPERS svcHelpers;
+ SHFLROOT Root;
+ const RTFILE hcFile = (RTFILE) 0x10000;
+ const int64_t offLock = 50000;
+ const uint64_t cbLock = 4000;
+ SHFLHANDLE Handle;
+ int rc;
+
+ RTTestSub(hTest, "Simple file lock and unlock");
+ Root = initWithWritableMapping(hTest, &svcTable, &svcHelpers,
+ "/test/mapping", "testname");
+ testRTFileOpenpFile = hcFile;
+ rc = createFile(&svcTable, Root, "/test/file", SHFL_CF_ACCESS_READ,
+ &Handle, NULL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+ rc = lockFile(&svcTable, Root, Handle, offLock, cbLock, SHFL_LOCK_SHARED);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+#ifdef RT_OS_WINDOWS /* Locking is a no-op elsewhere. */
+ RTTEST_CHECK_MSG(hTest, g_testRTFileLockFile == hcFile, (hTest, "File=%u\n", g_testRTFileLockFile));
+ RTTEST_CHECK_MSG(hTest, testRTFileLockfLock == 0,
+ (hTest, "fLock=%u\n", testRTFileLockfLock));
+ RTTEST_CHECK_MSG(hTest, testRTFileLockOffset == offLock,
+ (hTest, "Offs=%llu\n", (long long) testRTFileLockOffset));
+ RTTEST_CHECK_MSG(hTest, testRTFileLockSize == cbLock,
+ (hTest, "Size=%llu\n", LLUIFY(testRTFileLockSize)));
+#endif
+ rc = lockFile(&svcTable, Root, Handle, offLock, cbLock, SHFL_LOCK_CANCEL);
+ RTTEST_CHECK_RC_OK(hTest, rc);
+#ifdef RT_OS_WINDOWS
+ RTTEST_CHECK_MSG(hTest, g_testRTFileUnlockFile == hcFile, (hTest, "File=%u\n", g_testRTFileUnlockFile));
+ RTTEST_CHECK_MSG(hTest, testRTFileUnlockOffset == offLock,
+ (hTest, "Offs=%llu\n",
+ (long long) testRTFileUnlockOffset));
+ RTTEST_CHECK_MSG(hTest, testRTFileUnlockSize == cbLock,
+ (hTest, "Size=%llu\n", LLUIFY(testRTFileUnlockSize)));
+#endif
+ unmapAndRemoveMapping(hTest, &svcTable, Root, "testname");
+ AssertReleaseRC(svcTable.pfnDisconnect(NULL, 0, svcTable.pvService));
+ AssertReleaseRC(svcTable.pfnUnload(NULL));
+ RTTestGuardedFree(hTest, svcTable.pvService);
+ RTTEST_CHECK_MSG(hTest, g_testRTFileCloseFile == hcFile, (hTest, "File=%u\n", g_testRTFileCloseFile));
+}
+
+
+/*********************************************************************************************************************************
+* Main code *
+*********************************************************************************************************************************/
+
+static void testAPI(RTTEST hTest)
+{
+ testMappingsQuery(hTest);
+ testMappingsQueryName(hTest);
+ testMapFolder(hTest);
+ testUnmapFolder(hTest);
+ testCreate(hTest);
+ testClose(hTest);
+ testRead(hTest);
+ testWrite(hTest);
+ testLock(hTest);
+ testFlush(hTest);
+ testDirList(hTest);
+ testReadLink(hTest);
+ testFSInfo(hTest);
+ testRemove(hTest);
+ testRename(hTest);
+ testSymlink(hTest);
+ testMappingsAdd(hTest);
+ testMappingsRemove(hTest);
+ /* testSetStatusLed(hTest); */
+}
+
+int main(int argc, char **argv)
+{
+ RT_NOREF1(argc);
+ RTEXITCODE rcExit = RTTestInitAndCreate(RTPathFilename(argv[0]), &g_hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(g_hTest);
+ testAPI(g_hTest);
+ return RTTestSummaryAndDestroy(g_hTest);
+}
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h
new file mode 100644
index 00000000..93a9995a
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstSharedFolderService.h
@@ -0,0 +1,130 @@
+/** @file
+ * VBox Shared Folders testcase stub redefinitions.
+ */
+
+/*
+ * Copyright (C) 2011-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VBOX_INCLUDED_SRC_SharedFolders_testcase_tstSharedFolderService_h
+#define VBOX_INCLUDED_SRC_SharedFolders_testcase_tstSharedFolderService_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+/* Grumble... if the coding style let us use the anonymous "struct RTTESTINT *"
+ * instead of "PRTTEST" here we wouldn't need to unnecessarily include this. */
+#include <iprt/test.h>
+
+void testMappingsQuery(RTTEST hTest);
+/* Sub-tests for testMappingsQuery(). */
+void testMappingsQuerySimple(RTTEST hTest);
+void testMappingsQueryTooFewBuffers(RTTEST hTest);
+void testMappingsQueryAutoMount(RTTEST hTest);
+void testMappingsQueryArrayWrongSize(RTTEST hTest);
+
+void testMappingsQueryName(RTTEST hTest);
+/* Sub-tests for testMappingsQueryName(). */
+void testMappingsQueryNameValid(RTTEST hTest);
+void testMappingsQueryNameInvalid(RTTEST hTest);
+void testMappingsQueryNameBadBuffer(RTTEST hTest);
+
+void testMapFolder(RTTEST hTest);
+/* Sub-tests for testMapFolder(). */
+void testMapFolderValid(RTTEST hTest);
+void testMapFolderInvalid(RTTEST hTest);
+void testMapFolderTwice(RTTEST hTest);
+void testMapFolderDelimiter(RTTEST hTest);
+void testMapFolderCaseSensitive(RTTEST hTest);
+void testMapFolderCaseInsensitive(RTTEST hTest);
+void testMapFolderBadParameters(RTTEST hTest);
+
+void testUnmapFolder(RTTEST hTest);
+/* Sub-tests for testUnmapFolder(). */
+void testUnmapFolderValid(RTTEST hTest);
+void testUnmapFolderInvalid(RTTEST hTest);
+void testUnmapFolderBadParameters(RTTEST hTest);
+
+void testCreate(RTTEST hTest);
+/* Sub-tests for testCreate(). */
+void testCreateFileSimple(RTTEST hTest);
+void testCreateFileSimpleCaseInsensitive(RTTEST hTest);
+void testCreateDirSimple(RTTEST hTest);
+void testCreateBadParameters(RTTEST hTest);
+
+void testClose(RTTEST hTest);
+/* Sub-tests for testClose(). */
+void testCloseBadParameters(RTTEST hTest);
+
+void testRead(RTTEST hTest);
+/* Sub-tests for testRead(). */
+void testReadBadParameters(RTTEST hTest);
+void testReadFileSimple(RTTEST hTest);
+
+void testWrite(RTTEST hTest);
+/* Sub-tests for testWrite(). */
+void testWriteBadParameters(RTTEST hTest);
+void testWriteFileSimple(RTTEST hTest);
+
+void testLock(RTTEST hTest);
+/* Sub-tests for testLock(). */
+void testLockBadParameters(RTTEST hTest);
+void testLockFileSimple(RTTEST hTest);
+
+void testFlush(RTTEST hTest);
+/* Sub-tests for testFlush(). */
+void testFlushBadParameters(RTTEST hTest);
+void testFlushFileSimple(RTTEST hTest);
+
+void testDirList(RTTEST hTest);
+/* Sub-tests for testDirList(). */
+void testDirListBadParameters(RTTEST hTest);
+void testDirListEmpty(RTTEST hTest);
+
+void testReadLink(RTTEST hTest);
+/* Sub-tests for testReadLink(). */
+void testReadLinkBadParameters(RTTEST hTest);
+
+void testFSInfo(RTTEST hTest);
+/* Sub-tests for testFSInfo(). */
+void testFSInfoBadParameters(RTTEST hTest);
+void testFSInfoQuerySetFMode(RTTEST hTest);
+void testFSInfoQuerySetDirATime(RTTEST hTest);
+void testFSInfoQuerySetFileATime(RTTEST hTest);
+void testFSInfoQuerySetEndOfFile(RTTEST hTest);
+
+void testRemove(RTTEST hTest);
+/* Sub-tests for testRemove(). */
+void testRemoveBadParameters(RTTEST hTest);
+
+void testRename(RTTEST hTest);
+/* Sub-tests for testRename(). */
+void testRenameBadParameters(RTTEST hTest);
+
+void testSymlink(RTTEST hTest);
+/* Sub-tests for testSymlink(). */
+void testSymlinkBadParameters(RTTEST hTest);
+
+void testMappingsAdd(RTTEST hTest);
+/* Sub-tests for testMappingsAdd(). */
+void testMappingsAddBadParameters(RTTEST hTest);
+
+void testMappingsRemove(RTTEST hTest);
+/* Sub-tests for testMappingsRemove(). */
+void testMappingsRemoveBadParameters(RTTEST hTest);
+
+#if 0 /* Where should this go? */
+void testSetStatusLed(RTTEST hTest);
+/* Sub-tests for testStatusLed(). */
+void testSetStatusLedBadParameters(RTTEST hTest);
+#endif
+
+#endif /* !VBOX_INCLUDED_SRC_SharedFolders_testcase_tstSharedFolderService_h */
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp b/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp
new file mode 100644
index 00000000..6920f8dd
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp
@@ -0,0 +1,442 @@
+/** @file
+ * Testcase for shared folder case conversion code.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#define LOG_ENABLED
+#include <VBox/shflsvc.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/fs.h>
+#include <iprt/dir.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/uni.h>
+#include <stdio.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* Override slash for non-windows hosts. */
+#undef RTPATH_DELIMITER
+#define RTPATH_DELIMITER '\\'
+
+/* Use our own RTPath and RTDir methods. */
+#define RTPathQueryInfo rtPathQueryInfo
+#define RTDirOpenFiltered rtDirOpenFiltered
+#define RTDirClose rtDirClose
+#define RTDirReadEx rtDirReadEx
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static int iDirList = 0;
+static int iDirFile = 0;
+
+static const char *g_apszDirs[] =
+{
+ "c:",
+ "c:\\test dir",
+ "c:\\test dir\\SUBDIR",
+};
+
+static const char *g_apszDirsC[] =
+{
+ ".",
+ "..",
+ "test dir"
+};
+
+static const char *g_apszTestdirEntries[] =
+{
+ ".",
+ "..",
+ "SUBDIR",
+ "a.bat",
+ "aTestJe.bat",
+ "aTestje.bat",
+ "b.bat",
+ "c.bat",
+ "d.bat",
+ "e.bat",
+ "f.bat",
+ "g.bat",
+ "h.bat",
+ "x.bat",
+ "z.bat",
+};
+
+static const char *g_apszSUBDIREntries[] =
+{
+ ".",
+ "..",
+ "a.bat",
+ "aTestJe.bat",
+ "aTestje.bat",
+ "b.bat",
+ "c.bat",
+ "d.bat",
+ "e.bat",
+ "f.bat",
+ "g.bat",
+ "h.bat",
+ "x.bat",
+ "z.bat",
+};
+
+int rtDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags)
+{
+ RT_NOREF2(enmFilter, fFlags);
+ if (!strcmp(pszPath, "c:\\*"))
+ iDirList = 1;
+ else if (!strcmp(pszPath, "c:\\test dir\\*"))
+ iDirList = 2;
+ else if (!strcmp(pszPath, "c:\\test dir\\SUBDIR\\*"))
+ iDirList = 3;
+ else
+ AssertFailed();
+
+ *phDir = (RTDIR)1;
+ return VINF_SUCCESS;
+}
+
+int rtDirClose(RTDIR hDir)
+{
+ RT_NOREF1(hDir);
+ iDirFile = 0;
+ return VINF_SUCCESS;
+}
+
+int rtDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
+{
+ RT_NOREF4(hDir, pcbDirEntry, enmAdditionalAttribs, fFlags);
+ switch (iDirList)
+ {
+ case 1:
+ if (iDirFile == RT_ELEMENTS(g_apszDirsC))
+ return VERR_NO_MORE_FILES;
+ pDirEntry->cbName = (uint16_t)strlen(g_apszDirsC[iDirFile]);
+ strcpy(pDirEntry->szName, g_apszDirsC[iDirFile++]);
+ break;
+ case 2:
+ if (iDirFile == RT_ELEMENTS(g_apszTestdirEntries))
+ return VERR_NO_MORE_FILES;
+ pDirEntry->cbName = (uint16_t)strlen(g_apszTestdirEntries[iDirFile]);
+ strcpy(pDirEntry->szName, g_apszTestdirEntries[iDirFile++]);
+ break;
+ case 3:
+ if (iDirFile == RT_ELEMENTS(g_apszSUBDIREntries))
+ return VERR_NO_MORE_FILES;
+ pDirEntry->cbName = (uint16_t)strlen(g_apszSUBDIREntries[iDirFile]);
+ strcpy(pDirEntry->szName, g_apszSUBDIREntries[iDirFile++]);
+ break;
+ }
+ return VINF_SUCCESS;
+}
+
+int rtPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
+{
+ RT_NOREF2(pObjInfo, enmAdditionalAttribs);
+ int cMax;
+
+ /* first try g_apszDirs */
+ for (unsigned int i=0;i<RT_ELEMENTS(g_apszDirs);i++)
+ {
+ if(!strcmp(pszPath, g_apszDirs[i]))
+ return VINF_SUCCESS;
+ }
+
+ const char **papszDirList;
+ switch (iDirList)
+ {
+ case 1:
+ cMax = RT_ELEMENTS(g_apszDirsC);
+ papszDirList = g_apszDirsC;
+ break;
+ case 2:
+ cMax = RT_ELEMENTS(g_apszTestdirEntries);
+ papszDirList = g_apszTestdirEntries;
+ break;
+ case 3:
+ cMax = RT_ELEMENTS(g_apszSUBDIREntries);
+ papszDirList = g_apszSUBDIREntries;
+ break;
+ default:
+ return VERR_FILE_NOT_FOUND;
+ }
+ for (int i = 0; i < cMax; i++)
+ {
+ if (!strcmp(pszPath, papszDirList[i]))
+ return VINF_SUCCESS;
+ }
+ return VERR_FILE_NOT_FOUND;
+}
+
+static int vbsfCorrectCasing(char *pszFullPath, char *pszStartComponent)
+{
+ PRTDIRENTRYEX pDirEntry = NULL;
+ uint32_t cbDirEntry;
+ size_t cbComponent;
+ int rc = VERR_FILE_NOT_FOUND;
+ RTDIR hSearch = NIL_RTDIR;
+ char szWildCard[4];
+
+ Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
+
+ cbComponent = strlen(pszStartComponent);
+
+ cbDirEntry = 4096;
+ pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
+ if (pDirEntry == 0)
+ {
+ AssertFailed();
+ return VERR_NO_MEMORY;
+ }
+
+ /** @todo this is quite inefficient, especially for directories with many files */
+ Assert(pszFullPath < pszStartComponent-1);
+ Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
+ *(pszStartComponent-1) = 0;
+ strcpy(pDirEntry->szName, pszFullPath);
+ szWildCard[0] = RTPATH_DELIMITER;
+ szWildCard[1] = '*';
+ szWildCard[2] = 0;
+ strcat(pDirEntry->szName, szWildCard);
+
+ rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0 /*fFlags*/);
+ *(pszStartComponent-1) = RTPATH_DELIMITER;
+ if (RT_FAILURE(rc))
+ goto end;
+
+ for(;;)
+ {
+ size_t cbDirEntrySize = cbDirEntry;
+
+ rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if (rc == VERR_NO_MORE_FILES)
+ break;
+
+ if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
+ {
+ AssertFailed();
+ if (rc != VERR_NO_TRANSLATION)
+ break;
+ else
+ continue;
+ }
+
+ Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
+ if ( pDirEntry->cbName == cbComponent
+ && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
+ {
+ Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
+ strcpy(pszStartComponent, &pDirEntry->szName[0]);
+ rc = VINF_SUCCESS;
+ break;
+ }
+ }
+ if (RT_FAILURE(rc))
+ Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
+
+end:
+ if (pDirEntry)
+ RTMemFree(pDirEntry);
+
+ if (hSearch)
+ RTDirClose(hSearch);
+ return rc;
+}
+
+
+
+int testCase(char *pszFullPath, bool fWildCard = false)
+{
+ int rc;
+ RTFSOBJINFO info;
+ char *pszWildCardComponent = NULL;
+
+ if (fWildCard)
+ {
+ /* strip off the last path component, that contains the wildcard(s) */
+ size_t len = strlen(pszFullPath);
+ char *src = pszFullPath + len - 1;
+
+ while(src > pszFullPath)
+ {
+ if (*src == RTPATH_DELIMITER)
+ break;
+ src--;
+ }
+ if (*src == RTPATH_DELIMITER)
+ {
+ bool fHaveWildcards = false;
+ char *temp = src;
+
+ while(*temp)
+ {
+ char uc = *temp;
+ /** @todo should depend on the guest OS */
+ if (uc == '*' || uc == '?' || uc == '>' || uc == '<' || uc == '"')
+ {
+ fHaveWildcards = true;
+ break;
+ }
+ temp++;
+ }
+
+ if (fHaveWildcards)
+ {
+ pszWildCardComponent = src;
+ *pszWildCardComponent = 0;
+ }
+ }
+ }
+
+ rc = RTPathQueryInfo(pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
+ if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
+ {
+ size_t len = strlen(pszFullPath);
+ char *src = pszFullPath + len - 1;
+
+ Log(("Handle case insensitive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
+
+ /* Find partial path that's valid */
+ while(src > pszFullPath)
+ {
+ if (*src == RTPATH_DELIMITER)
+ {
+ *src = 0;
+ rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
+ *src = RTPATH_DELIMITER;
+ if (rc == VINF_SUCCESS)
+ {
+#ifdef DEBUG
+ *src = 0;
+ Log(("Found valid partial path %s\n", pszFullPath));
+ *src = RTPATH_DELIMITER;
+#endif
+ break;
+ }
+ }
+
+ src--;
+ }
+ Assert(*src == RTPATH_DELIMITER && RT_SUCCESS(rc));
+ if ( *src == RTPATH_DELIMITER
+ && RT_SUCCESS(rc))
+ {
+ src++;
+ for(;;)
+ {
+ char *end = src;
+ bool fEndOfString = true;
+
+ while(*end)
+ {
+ if (*end == RTPATH_DELIMITER)
+ break;
+ end++;
+ }
+
+ if (*end == RTPATH_DELIMITER)
+ {
+ fEndOfString = false;
+ *end = 0;
+ rc = RTPathQueryInfo(src, &info, RTFSOBJATTRADD_NOTHING);
+ Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
+ }
+ else
+ if (end == src)
+ rc = VINF_SUCCESS; /* trailing delimiter */
+ else
+ rc = VERR_FILE_NOT_FOUND;
+
+ if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
+ {
+ /* path component is invalid; try to correct the casing */
+ rc = vbsfCorrectCasing(pszFullPath, src);
+ if (RT_FAILURE(rc))
+ {
+ if (!fEndOfString)
+ *end = RTPATH_DELIMITER;
+ break;
+ }
+ }
+
+ if (fEndOfString)
+ break;
+
+ *end = RTPATH_DELIMITER;
+ src = end + 1;
+ }
+ if (RT_FAILURE(rc))
+ Log(("Unable to find suitable component rc=%d\n", rc));
+ }
+ else
+ rc = VERR_FILE_NOT_FOUND;
+
+ }
+ if (pszWildCardComponent)
+ *pszWildCardComponent = RTPATH_DELIMITER;
+
+ if (RT_SUCCESS(rc))
+ Log(("New valid path %s\n", pszFullPath));
+ else
+ Log(("Old invalid path %s\n", pszFullPath));
+ return rc;
+}
+
+
+int main()
+{
+ char szTest[128];
+
+ RTR3InitExeNoArguments(0);
+ RTLogFlush(NULL);
+ RTLogDestinations(NULL, "stdout");
+ RTLogGroupSettings(NULL, "misc=~0");
+ RTLogFlags(NULL, "unbuffered");
+
+ strcpy(szTest, "c:\\test Dir\\z.bAt");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\z.bAt");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\SUBDIR\\z.bAt");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\SUBDiR\\atestje.bat");
+ testCase(szTest);
+ strcpy(szTest, "c:\\TEST dir\\subDiR\\aTestje.baT");
+ testCase(szTest);
+ strcpy(szTest, "c:\\TEST dir\\subDiR\\*");
+ testCase(szTest, true);
+ strcpy(szTest, "c:\\TEST dir\\subDiR\\");
+ testCase(szTest ,true);
+ strcpy(szTest, "c:\\test dir\\SUBDIR\\");
+ testCase(szTest);
+ strcpy(szTest, "c:\\test dir\\invalid\\SUBDIR\\test.bat");
+ testCase(szTest);
+ return 0;
+}
+
diff --git a/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp b/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp
new file mode 100644
index 00000000..ab4e6a91
--- /dev/null
+++ b/src/VBox/HostServices/SharedFolders/testcase/tstShflSizes.cpp
@@ -0,0 +1,134 @@
+/** @file
+ * tstShflSize - Testcase for shared folder structure sizes.
+ * Run this on Linux and Windows, then compare.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <VBox/shflsvc.h>
+#include <iprt/string.h>
+#include <stdio.h>
+
+#define STRUCT(t, size) \
+ do { \
+ if (fPrintChecks) \
+ printf(" STRUCT(" #t ", %d);\n", (int)sizeof(t)); \
+ else if ((size) != sizeof(t)) \
+ { \
+ printf("%30s: %d expected %d!\n", #t, (int)sizeof(t), (size)); \
+ cErrors++; \
+ } \
+ else if (!fQuiet)\
+ printf("%30s: %d\n", #t, (int)sizeof(t)); \
+ } while (0)
+
+
+int main(int argc, char **argv)
+{
+ unsigned cErrors = 0;
+
+ /*
+ * Prints the code below if any argument was giving.
+ */
+ bool fQuiet = argc == 2 && !strcmp(argv[1], "quiet");
+ bool fPrintChecks = !fQuiet && argc != 1;
+
+ printf("tstShflSizes: TESTING\n");
+
+ /*
+ * The checks.
+ */
+ STRUCT(SHFLROOT, 4);
+ STRUCT(SHFLHANDLE, 8);
+ STRUCT(SHFLSTRING, 6);
+ STRUCT(SHFLCREATERESULT, 4);
+ STRUCT(SHFLCREATEPARMS, 108);
+ STRUCT(SHFLMAPPING, 8);
+ STRUCT(SHFLDIRINFO, 128);
+ STRUCT(SHFLVOLINFO, 40);
+ STRUCT(SHFLFSOBJATTR, 44);
+ STRUCT(SHFLFSOBJINFO, 92);
+#ifdef VBOX_WITH_64_BITS_GUESTS
+/* The size of the guest structures depends on the current architecture bit count (ARCH_BITS)
+ * because the HGCMFunctionParameter structure differs in 32 and 64 bit guests.
+ * The host VMMDev device takes care about this.
+ *
+ * Therefore this testcase verifies whether structure sizes are correct for the current ARCH_BITS.
+ */
+# if ARCH_BITS == 64
+ STRUCT(VBoxSFQueryMappings, 88);
+ STRUCT(VBoxSFQueryMapName, 72);
+ STRUCT(VBoxSFMapFolder_Old, 88);
+ STRUCT(VBoxSFMapFolder, 104);
+ STRUCT(VBoxSFUnmapFolder, 56);
+ STRUCT(VBoxSFCreate, 88);
+ STRUCT(VBoxSFClose, 72);
+ STRUCT(VBoxSFRead, 120);
+ STRUCT(VBoxSFWrite, 120);
+ STRUCT(VBoxSFLock, 120);
+ STRUCT(VBoxSFFlush, 72);
+ STRUCT(VBoxSFList, 168);
+ STRUCT(VBoxSFInformation, 120);
+ STRUCT(VBoxSFRemove, 88);
+ STRUCT(VBoxSFRename, 104);
+# elif ARCH_BITS == 32
+ STRUCT(VBoxSFQueryMappings, 24+52);
+ STRUCT(VBoxSFQueryMapName, 24+40); /* this was changed from 52 in 21976 after VBox-1.4. */
+ STRUCT(VBoxSFMapFolder_Old, 24+52);
+ STRUCT(VBoxSFMapFolder, 24+64);
+ STRUCT(VBoxSFUnmapFolder, 24+28);
+ STRUCT(VBoxSFCreate, 24+52);
+ STRUCT(VBoxSFClose, 24+40);
+ STRUCT(VBoxSFRead, 24+76);
+ STRUCT(VBoxSFWrite, 24+76);
+ STRUCT(VBoxSFLock, 24+76);
+ STRUCT(VBoxSFFlush, 24+40);
+ STRUCT(VBoxSFList, 24+112);
+ STRUCT(VBoxSFInformation, 24+76);
+ STRUCT(VBoxSFRemove, 24+52);
+ STRUCT(VBoxSFRename, 24+64);
+# else
+# error "Unsupported ARCH_BITS"
+# endif /* ARCH_BITS */
+#else
+ STRUCT(VBoxSFQueryMappings, 24+52);
+ STRUCT(VBoxSFQueryMapName, 24+40); /* this was changed from 52 in 21976 after VBox-1.4. */
+ STRUCT(VBoxSFMapFolder_Old, 24+52);
+ STRUCT(VBoxSFMapFolder, 24+64);
+ STRUCT(VBoxSFUnmapFolder, 24+28);
+ STRUCT(VBoxSFCreate, 24+52);
+ STRUCT(VBoxSFClose, 24+40);
+ STRUCT(VBoxSFRead, 24+76);
+ STRUCT(VBoxSFWrite, 24+76);
+ STRUCT(VBoxSFLock, 24+76);
+ STRUCT(VBoxSFFlush, 24+40);
+ STRUCT(VBoxSFList, 24+112);
+ STRUCT(VBoxSFInformation, 24+76);
+ STRUCT(VBoxSFRemove, 24+52);
+ STRUCT(VBoxSFRename, 24+64);
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+
+ /*
+ * The summary.
+ */
+ if (!cErrors)
+ printf("tstShflSizes: SUCCESS\n");
+ else
+ printf("tstShflSizes: FAILURE - %d errors\n", cErrors);
+ return !!cErrors;
+}
+