Index: trunk/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk	(revision 40268)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk	(revision 40269)
@@ -5,5 +5,5 @@
 
 #
-# Copyright (C) 2006-2007 Oracle Corporation
+# Copyright (C) 2012 Oracle Corporation
 #
 # This file is part of VirtualBox Open Source Edition (OSE), as
@@ -20,6 +20,6 @@
 
 # Include sub-makefile(s).
-include $(PATH_SUB_CURRENT)/redirector/Makefile.kmk
+include $(PATH_SUB_CURRENT)/np/Makefile.kmk
+include $(PATH_SUB_CURRENT)/driver/Makefile.kmk
 
 include	$(KBUILD_PATH)/subfooter.kmk
-
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/Makefile.kmk
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/Makefile.kmk	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/Makefile.kmk	(revision 40269)
@@ -0,0 +1,69 @@
+# $Id$
+## @file
+# Sub-Makefile for the VirtualBox Windows Guest Shared Folders FSD.
+#
+
+#
+# Copyright (C) 2006-2007 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
+
+#
+# VBoxSF
+#
+SYSMODS += VBoxSF
+VBoxSF_TEMPLATE    = VBOXGUESTR0
+VBoxSF_DEFS        = LOG_TO_BACKDOOR VBOX_WITH_HGCM IN_RING0
+#VBoxSF_DEFS       += LOG_ENABLED
+
+VBoxSF_SDKS.x86    = WINDDKW2K
+VBoxSF_SDKS.amd64  = WINDDKWLH
+
+VBoxSF_INCS        = \
+	../../../common/VBoxGuestLib
+VBoxSF_LDFLAGS.x86   = -Entry:DriverEntry@8
+VBoxSF_LDFLAGS.amd64 = -Entry:DriverEntry
+VBoxSF_CFLAGS      = -wd4005
+VBoxSF_SOURCES     =  \
+	file.c \
+	info.c \
+	vbsf.c \
+	net.c \
+	path.c \
+	vbsfhlp.c \
+ 	VBoxSF.rc
+
+VBoxSF_LIBS.x86  = \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/fre/rxce.lib \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/fre/rdbsslib.lib \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/fre/copysup.lib \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/ntoskrnl.lib \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/hal.lib \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/ksecdd.lib \
+	$(PATH_SDK_WINDDKW2K_LIB.x86)/BufferOverflowK.lib
+
+VBoxSF_LIBS.amd64  = \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/rxce.lib \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/rdbsslib.lib \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/copysup.lib \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/ntoskrnl.lib \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/hal.lib \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/ksecdd.lib \
+	$(PATH_SDK_WINDDKWLH_LIB.amd64)/BufferOverflowK.lib
+
+VBoxSF_LIBS = \
+	$(VBOX_LIB_VBGL_R0) \
+	$(VBOX_LIB_IPRT_GUEST_R0)
+
+include	$(KBUILD_PATH)/subfooter.kmk
+
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/VBoxSF.inf
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/VBoxSF.inf	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/VBoxSF.inf	(revision 40269)
@@ -0,0 +1,72 @@
+;
+; INF file for installing the VirtualBox Windows guest driver
+;
+; Copyright (C) 2006-2007 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.
+;
+
+[Version]
+Signature="$Windows NT$"
+Class=System
+ClassGuid={ce4a90b5-1d8c-435d-b349-232ce55cb17f}
+Provider=%ORACLE%
+;edit-DriverVer=08/26/2008,2.00.0000
+DriverPackageType=Network
+;cat CatalogFile=VBoxSF.cat
+
+;cat [SourceDisksNames]
+;cat 1 = %VBoxSF.MediaDesc%
+;cat
+;cat [SourceDisksFiles]
+;cat VBoxSF.sys = 1
+
+[DestinationDirs]
+DefaultDestDir      = 12 ; drivers
+VBoxMRXNP_CopyFiles = 11 ; system32
+
+[Manufacturer]
+;x86   %ORACLE%=VBoxSF
+;amd64 %ORACLE%=VBoxSF, NTamd64
+
+;x86   [VBoxSF]
+;amd64 [VBoxSF.NTamd64]
+%VBoxSF.DeviceDesc%=VBoxSF_Install,PCI\VEN_80ee&DEV_cafe
+
+[VBoxSF_Install]
+CopyFiles = VBoxSF_CopyFiles, VBoxMRXNP_CopyFiles
+AddReg = VBoxMRXNP_Add_Reg
+
+[VBoxSF_CopyFiles]
+VBoxSF.sys
+
+[VBoxMRXNP_CopyFiles]
+VBoxMRXNP.dll
+
+[VBoxSF_Install.Services]
+AddService = VBoxSF, 0x00000002, VBoxSF_ServiceInstallSection
+DelService = VBoxMRXNP, 0x00000004
+
+[VBoxSF_ServiceInstallSection]
+DisplayName    = %VBoxSF_svcdesc%
+ServiceType    = 0x00000001 ; kernel driver
+StartType      = 0x00000003 ; demand start
+ErrorControl   = 0x00000001 ; normal error handling
+ServiceBinary  = %12%\VBoxSF.sys
+
+[VBoxMRXNP_Add_Reg]
+HKLM, SOFTWARE\Microsoft\Windows\CurrentVersion\Run, VBoxMRXNP, 0x00000000, %11%\VBoxMRXNP.exe
+
+[Strings]
+ORACLE = "Oracle Corporation"
+VBoxSF.DeviceDesc = "VirtualBox Device"
+VBoxSF_svcdesc = "VirtualBox Shared Folders Driver"
+VBoxMRXNP_svcdesc = "VirtualBox Network Provider Service"
+
+
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/VBoxSF.rc
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/VBoxSF.rc	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/VBoxSF.rc	(revision 40269)
@@ -0,0 +1,50 @@
+/* $Id$ */
+/** @file
+ * VBoxSF - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2006-2012 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.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+   FILEVERSION          VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0
+   PRODUCTVERSION       VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0
+   FILEFLAGSMASK        0x3fL
+   FILEFLAGS            0x0L
+   FILEOS               0x40004L
+   FILETYPE             0x2L
+   FILESUBTYPE          0x0L
+BEGIN
+   BLOCK "StringFileInfo"
+   BEGIN
+      BLOCK "040904b0"
+      BEGIN
+         VALUE "CompanyName",      VBOX_RC_COMPANY_NAME
+         VALUE "FileDescription",  "VirtualBox Shared Folders Minirdr\0"
+         VALUE "FileVersion",      VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+         VALUE "InternalName",     "VBoxSF.sys\0"
+         VALUE "LegalCopyright",   VBOX_RC_LEGAL_COPYRIGHT
+         VALUE "OriginalFilename", "VBoxSF.sys\0"
+         VALUE "ProductName",      VBOX_PRODUCT " Guest Additions\0"
+         VALUE "ProductVersion",   VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD ".r" VBOX_SVN_REV "\0"
+      END
+   END
+   BLOCK "VarFileInfo"
+   BEGIN
+      VALUE "Translation", 0x409, 1200
+   END
+END
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/file.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/file.c	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/file.c	(revision 40269)
@@ -0,0 +1,399 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver file routines
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "vbsf.h"
+#include <iprt/fs.h>
+
+static NTSTATUS vbsfReadInternal(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+
+    PMDL BufferMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
+    uint32_t ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
+    RXVBO ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
+
+    PVOID pbUserBuffer = RxLowIoGetBufferAddress(RxContext);
+
+    int vboxRC;
+
+    BOOLEAN AsyncIo = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+    LONGLONG FileSize;
+
+    RxGetFileSizeWithLock((PFCB)capFcb, &FileSize);
+
+    Log(("VBOXSF: vbsfReadInternal: AsyncIo = %d, Fcb->FileSize = 0x%RX64\n",
+         AsyncIo, capFcb->Header.FileSize.QuadPart));
+    Log(("VBOXSF: vbsfReadInternal: UserBuffer %p, BufferMdl %p\n",
+         pbUserBuffer, BufferMdl));
+    Log(("VBOXSF: vbsfReadInternal: ByteCount 0x%X, ByteOffset 0x%RX64, FileSize 0x%RX64\n",
+         ByteCount, ByteOffset, FileSize));
+
+    /* @todo check if this is necessary. */
+#if (NTDDI_VERSION >= NTDDI_VISTA)      /* Correct spelling for Vista 6001 SDK. */
+    if (!FlagOn(capFcb->FcbState, FCB_STATE_READCACHING_ENABLED))
+#else
+    if (!FlagOn(capFcb->FcbState, FCB_STATE_READCACHEING_ENABLED))
+#endif
+    {
+        if (ByteOffset >= FileSize)
+        {
+            Log(("VBOXSF: vbsfReadInternal: EOF\n"));
+            return STATUS_END_OF_FILE;
+        }
+
+        if (ByteCount > FileSize - ByteOffset)
+        {
+            ByteCount = (ULONG)(FileSize - ByteOffset);
+        }
+    }
+
+    /* @todo read 0 bytes == always success? */
+    if (   BufferMdl == NULL
+        || ByteCount == 0)
+    {
+        AssertFailed();
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* @todo Split large reads. */
+    vboxRC = vboxCallRead(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                          ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */);
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+
+    if (Status != STATUS_SUCCESS)
+    {
+        /* Nothing read. */
+        ByteCount = 0;
+    }
+
+    RxContext->InformationToReturn = ByteCount;
+
+    Log(("VBOXSF: vbsfReadInternal: Status = 0x%08X, ByteCount = 0x%X\n",
+         Status, ByteCount));
+
+    return Status;
+}
+
+
+static VOID vbsfReadWorker(VOID *pv)
+{
+    PRX_CONTEXT RxContext = (PRX_CONTEXT)pv;
+
+    Log(("VBOXSF: vbsfReadWorker: calling the worker\n"));
+
+    RxContext->IoStatusBlock.Status = vbsfReadInternal(RxContext);
+
+    Log(("VBOXSF: vbsfReadWorker: Status 0x%08X\n",
+         RxContext->IoStatusBlock.Status));
+
+    RxLowIoCompletion(RxContext);
+}
+
+
+NTSTATUS VBoxMRxRead(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue,
+                                               vbsfReadWorker,
+                                               RxContext);
+
+    Log(("VBOXSF: MRxRead: RxDispatchToWorkerThread: Status 0x%08X\n",
+         Status));
+
+    if (Status == STATUS_SUCCESS)
+    {
+        Status = STATUS_PENDING;
+    }
+
+    return Status;
+}
+
+static NTSTATUS vbsfWriteInternal(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PLOWIO_CONTEXT LowIoContext  = &RxContext->LowIoContext;
+
+    PMDL BufferMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
+    uint32_t ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
+    RXVBO ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
+
+    PVOID pbUserBuffer = RxLowIoGetBufferAddress(RxContext);
+
+    int vboxRC;
+
+    BOOLEAN AsyncIo = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+    LONGLONG FileSize;
+
+    RxGetFileSizeWithLock((PFCB)capFcb, &FileSize);
+
+    Log(("VBOXSF: vbsfWriteInternal: AsyncIo = %d, Fcb->FileSize = 0x%RX64\n",
+         AsyncIo, capFcb->Header.FileSize.QuadPart));
+    Log(("VBOXSF: vbsfWriteInternal: UserBuffer %p, BufferMdl %p\n",
+         pbUserBuffer, BufferMdl));
+    Log(("VBOXSF: vbsfWriteInternal: ByteCount is 0x%X, ByteOffset is 0x%RX64, FileSize 0x%RX64\n",
+         ByteCount, ByteOffset, FileSize));
+
+    /* @todo allow to write 0 bytes. */
+    if (   BufferMdl == NULL
+        || ByteCount == 0)
+    {
+        AssertFailed();
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* @todo Split large writes. */
+    vboxRC = vboxCallWrite(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                           ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */);
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+
+    if (Status != STATUS_SUCCESS)
+    {
+        /* Nothing written. */
+        ByteCount = 0;
+    }
+
+    RxContext->InformationToReturn = ByteCount;
+
+    Log(("VBOXSF: vbsfWriteInternal: Status = 0x%08X, ByteCount = 0x%X\n",
+         Status, ByteCount));
+
+    return Status;
+}
+
+static VOID vbsfWriteWorker(VOID *pv)
+{
+    PRX_CONTEXT RxContext = (PRX_CONTEXT)pv;
+
+    Log(("VBOXSF: vbsfWriteWorker: calling the worker\n"));
+
+    RxContext->IoStatusBlock.Status = vbsfWriteInternal(RxContext);
+
+    Log(("VBOXSF: vbsfWriteWorker: Status 0x%08X\n",
+         RxContext->IoStatusBlock.Status));
+
+    RxLowIoCompletion(RxContext);
+}
+
+
+NTSTATUS VBoxMRxWrite(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue,
+                                               vbsfWriteWorker,
+                                               RxContext);
+
+    Log(("VBOXSF: MRxWrite: RxDispatchToWorkerThread: Status 0x%08X\n",
+         Status));
+
+    if (Status == STATUS_SUCCESS)
+    {
+        Status = STATUS_PENDING;
+    }
+
+    return Status;
+}
+
+
+NTSTATUS VBoxMRxLocks(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+    uint32_t fu32Lock = 0;
+    int vboxRC;
+
+    Log(("VBOXSF: MRxLocks: Operation %d\n",
+         LowIoContext->Operation));
+
+    switch (LowIoContext->Operation)
+    {
+        default:
+            AssertMsgFailed(("VBOXSF: MRxLocks: Unsupported lock/unlock type %d detected!\n",
+                             LowIoContext->Operation));
+            return STATUS_NOT_IMPLEMENTED;
+
+        case LOWIO_OP_UNLOCK_MULTIPLE:
+            /* @todo Remove multiple locks listed in LowIoContext.ParamsFor.Locks.LockList. */
+            Log(("VBOXSF: MRxLocks: Unsupported LOWIO_OP_UNLOCK_MULTIPLE!\n",
+                 LowIoContext->Operation));
+            return STATUS_NOT_IMPLEMENTED;
+
+        case LOWIO_OP_SHAREDLOCK:
+            fu32Lock = SHFL_LOCK_SHARED | SHFL_LOCK_PARTIAL;
+            break;
+
+        case LOWIO_OP_EXCLUSIVELOCK:
+            fu32Lock = SHFL_LOCK_EXCLUSIVE | SHFL_LOCK_PARTIAL;
+            break;
+
+        case LOWIO_OP_UNLOCK:
+            fu32Lock = SHFL_LOCK_CANCEL | SHFL_LOCK_PARTIAL;
+            break;
+    }
+
+    if (LowIoContext->ParamsFor.Locks.Flags & LOWIO_LOCKSFLAG_FAIL_IMMEDIATELY)
+    {
+        fu32Lock |= SHFL_LOCK_NOWAIT;
+    }
+    else
+    {
+        fu32Lock |= SHFL_LOCK_WAIT;
+    }
+
+    vboxRC = vboxCallLock(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                          LowIoContext->ParamsFor.Locks.ByteOffset, LowIoContext->ParamsFor.Locks.Length, fu32Lock);
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+
+    Log(("VBOXSF: MRxLocks: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS VBoxMRxCompleteBufferingStateChangeRequest(IN OUT PRX_CONTEXT RxContext,
+                                                    IN OUT PMRX_SRV_OPEN SrvOpen,
+                                                    IN PVOID pContext)
+{
+    Log(("VBOXSF: MRxCompleteBufferingStateChangeRequest: not implemented\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxFlush (IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    int vboxRC;
+
+    Log(("VBOXSF: MRxFlush\n"));
+
+    /* Do the actual flushing of file buffers */
+    vboxRC = vboxCallFlush(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+
+    Log(("VBOXSF: MRxFlush: Returned 0x%08X\n", 
+         Status));
+    return Status;
+}
+
+NTSTATUS vbsfSetEndOfFile(IN OUT struct _RX_CONTEXT * RxContext,
+                          IN OUT PLARGE_INTEGER pNewFileSize,
+                          OUT PLARGE_INTEGER pNewAllocationSize)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PSHFLFSOBJINFO pObjInfo;
+    uint32_t cbBuffer;
+    int vboxRC;
+
+    Log(("VBOXSF: vbsfSetEndOfFile: New size = %RX64 (%p), pNewAllocationSize = %p\n",
+         pNewFileSize->QuadPart, pNewFileSize, pNewAllocationSize));
+
+    Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension);
+
+    cbBuffer = sizeof(SHFLFSOBJINFO);
+    pObjInfo = (SHFLFSOBJINFO *)vbsfAllocNonPagedMem(cbBuffer);
+    if (pObjInfo == NULL)
+    {
+        AssertFailed();
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(pObjInfo, cbBuffer);
+    pObjInfo->cbObject = pNewFileSize->QuadPart;
+
+    vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                            SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer, (PSHFLDIRINFO)pObjInfo);
+
+    Log(("VBOXSF: vbsfSetEndOfFile: vboxCallFSInfo returned %Rrc\n",
+         vboxRC));
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+    if (Status == STATUS_SUCCESS)
+    {
+        Log(("VBOXSF: vbsfSetEndOfFile: vboxCallFSInfo new allocation size = %RX64\n",
+             pObjInfo->cbAllocated));
+
+        /* Return new allocation size */
+        pNewAllocationSize->QuadPart = pObjInfo->cbAllocated;
+    }
+
+    if (pObjInfo)
+    {
+        vbsfFreeNonPagedMem(pObjInfo);
+    }
+
+    Log(("VBOXSF: vbsfSetEndOfFile: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS VBoxMRxExtendStub(IN OUT struct _RX_CONTEXT * RxContext,
+                           IN OUT PLARGE_INTEGER pNewFileSize,
+                           OUT PLARGE_INTEGER pNewAllocationSize)
+{
+    /* Note: On Windows hosts vbsfSetEndOfFile returns ACCESS_DENIED if the file has been
+     *       opened in APPEND mode. Writes to a file will extend it anyway, therefore it is
+     *       better to not call the host at all and tell the caller that the file was extended.
+     */
+    Log(("VBOXSF: MRxExtendStub: new size = %RX64\n",
+         pNewFileSize->QuadPart));
+
+    pNewAllocationSize->QuadPart = pNewFileSize->QuadPart;
+
+    return STATUS_SUCCESS;
+}
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/info.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/info.c	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/info.c	(revision 40269)
@@ -0,0 +1,1554 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver query and set information routines
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "vbsf.h"
+
+/** Macro for copying a SHFLSTRING file name into a FILE_DIRECTORY_INFORMATION structure. */
+#define INIT_FILE_NAME(obj, str) \
+    do { \
+        ULONG cbLength = (str).u16Length; \
+        (obj)->FileNameLength = cbLength; \
+        RtlCopyMemory((obj)->FileName, &(str).String.ucs2[0], cbLength + 2); \
+    } while (0)
+
+NTSTATUS VBoxMRxQueryDirectory(IN OUT PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFobx;
+    RxCaptureFcb;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+    PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
+    FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
+    PCHAR pInfoBuffer = (PCHAR)RxContext->Info.Buffer;
+    LONG cbMaxSize = RxContext->Info.Length;
+    LONG *pLengthRemaining = (LONG *)&RxContext->Info.LengthRemaining;
+
+    LONG cbToCopy;
+    int vboxRC;
+    uint8_t *pHGCMBuffer;
+    uint32_t index, fSFFlags, cFiles, u32BufSize;
+    LONG cbHGCMBuffer;
+    PSHFLDIRINFO pDirEntry;
+
+    ULONG *pNextOffset = 0;
+    PSHFLSTRING ParsedPath = 0;
+
+    Log(("VBOXSF: MrxQueryDirectory: FileInformationClass %d, pVBoxFobx %p, hFile %RX64, pInfoBuffer %p\n",
+         FileInformationClass, pVBoxFobx, pVBoxFobx->hFile, pInfoBuffer));
+
+    if (NULL == pVBoxFobx)
+    {
+        Log(("VBOXSF: MrxQueryDirectory: pVBoxFobx is invalid!\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (NULL == DirectoryName)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (DirectoryName->Length == 0)
+    {
+        Log(("VBOXSF: MrxQueryDirectory: DirectoryName = \\ (null string)\n"));
+    }
+    else
+    {
+        Log(("VBOXSF: MrxQueryDirectory: DirectoryName = %.*ls\n",
+             DirectoryName->Length / sizeof(WCHAR), DirectoryName->Buffer));
+    }
+
+    if (NULL == Template)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (Template->Length == 0)
+    {
+        Log(("VBOXSF: MrxQueryDirectory: Template = \\ (null string)\n"));
+    }
+    else
+    {
+        Log(("VBOXSF: MrxQueryDirectory: Template = %.*ls\n",
+             Template->Length / sizeof(WCHAR), Template->Buffer));
+    }
+
+    cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE);
+
+    Log(("VBOXSF: MrxQueryDirectory: Allocating cbHGCMBuffer = %d\n",
+         cbHGCMBuffer));
+
+    pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+    if (pHGCMBuffer == NULL)
+    {
+        AssertFailed();
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Assume start from the beginning. */
+    index = 0;
+    if (RxContext->QueryDirectory.IndexSpecified == TRUE)
+    {
+        Log(("VBOXSF: MrxQueryDirectory: Index specified %d\n",
+             index));
+        index = RxContext->QueryDirectory.FileIndex;
+    }
+
+    fSFFlags = SHFL_LIST_NONE;
+    if (RxContext->QueryDirectory.ReturnSingleEntry == TRUE)
+    {
+        Log(("VBOXSF: MrxQueryDirectory: Query single entry\n"));
+        fSFFlags |= SHFL_LIST_RETURN_ONE;
+    }
+
+    if (Template->Length)
+    {
+        ULONG ParsedPathSize, len;
+
+        /* Calculate length required for parsed path. */
+        ParsedPathSize = sizeof(*ParsedPath) + (DirectoryName->Length + Template->Length + 3 * sizeof(WCHAR));
+
+        Log(("VBOXSF: MrxQueryDirectory: ParsedPathSize = %d\n",
+             ParsedPathSize));
+
+        ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+        if (!ParsedPath)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto end;
+        }
+
+        RtlZeroMemory(ParsedPath, ParsedPathSize);
+        ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+        ParsedPath->u16Size = DirectoryName->Length + Template->Length + sizeof(WCHAR);
+        ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* Without terminating null. */
+
+        len = 0;
+        if (DirectoryName->Length)
+        {
+            /* Copy directory name into ParsedPath. */
+            RtlCopyMemory(ParsedPath->String.ucs2, DirectoryName->Buffer, DirectoryName->Length);
+            len = DirectoryName->Length / sizeof(WCHAR);
+
+            /* Add terminating backslash. */
+            ParsedPath->String.ucs2[len] = L'\\';
+            len++;
+            ParsedPath->u16Length += sizeof(WCHAR);
+            ParsedPath->u16Size += sizeof(WCHAR);
+        }
+        RtlCopyMemory (&ParsedPath->String.ucs2[len], Template->Buffer, Template->Length);
+
+        Log(("VBOXSF: MrxQueryDirectory: ParsedPath = %.*ls\n",
+             ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
+    }
+
+    cFiles = 0;
+
+    /* vboxCallDirInfo requires a pointer to uint32_t. */
+    u32BufSize = cbHGCMBuffer;
+
+    Log(("VBOXSF: MrxQueryDirectory: CallDirInfo: File = 0x%08x, Flags = 0x%08x, Index = %d, u32BufSize = %d\n",
+         pVBoxFobx->hFile, fSFFlags, index, u32BufSize));
+    vboxRC = vboxCallDirInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                             ParsedPath, fSFFlags, index, &u32BufSize, (PSHFLDIRINFO)pHGCMBuffer, &cFiles);
+    Log(("VBOXSF: MrxQueryDirectory: u32BufSize after CallDirInfo = %d, rc = %Rrc\n",
+         u32BufSize, vboxRC));
+
+    switch (vboxRC)
+    {
+        case VINF_SUCCESS:
+            /* Nothing to do here. */
+            break;
+
+        case VERR_NO_TRANSLATION:
+            Log(("VBOXSF: MrxQueryDirectory: Host could not translate entry!\n"));
+            break;
+
+        case VERR_NO_MORE_FILES:
+            if (cFiles <= 0) /* VERR_NO_MORE_FILES appears at the first lookup when just returning the current dir ".".
+                              * So we also have to check for the cFiles counter. */
+            {
+                /* Not an error, but we have to handle the return value. */
+                Log(("VBOXSF: MrxQueryDirectory: Host reported no more files!\n"));
+
+                if (RxContext->QueryDirectory.InitialQuery)
+                {
+                    /* First call. MSDN on FindFirstFile: "If the function fails because no matching files
+                     * can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND."
+                     * So map this rc to file not found.
+                     */
+                    Status = STATUS_NO_SUCH_FILE;
+                }
+                else
+                {
+                    /* Search continued. */
+                    Status = STATUS_NO_MORE_FILES;
+                }
+            }
+            break;
+
+        case VERR_FILE_NOT_FOUND:
+            Status = STATUS_NO_SUCH_FILE;
+            Log(("VBOXSF: MrxQueryDirectory: no such file!\n"));
+            break;
+
+        default:
+            Status = VBoxErrorToNTStatus(vboxRC);
+            Log(("VBOXSF: MrxQueryDirectory: Error %Rrc from CallDirInfo (cFiles=%d)!\n",
+                 vboxRC, cFiles));
+            break;
+    }
+
+    if (Status != STATUS_SUCCESS)
+    {
+        goto end;
+    }
+
+    /* Verify that the returned buffer length is not greater than the original one. */
+    if (u32BufSize > (uint32_t)cbHGCMBuffer)
+    {
+        Log(("VBOXSF: MrxQueryDirectory: returned buffer size (%u) is invalid!!!\n",
+             u32BufSize));
+        Status = STATUS_INVALID_NETWORK_RESPONSE;
+        goto end;
+    }
+
+    /* How many bytes remain in the buffer. */
+    cbHGCMBuffer = u32BufSize;
+
+    pDirEntry = (PSHFLDIRINFO)pHGCMBuffer;
+    Status = STATUS_SUCCESS;
+
+    Log(("VBOXSF: MrxQueryDirectory: cFiles=%d, Length=%d\n",
+         cFiles, cbHGCMBuffer));
+
+    while ((*pLengthRemaining) && (cFiles > 0) && (pDirEntry != NULL))
+    {
+        int cbEntry = RT_OFFSETOF(SHFLDIRINFO, name.String) + pDirEntry->name.u16Size;
+
+        if (cbEntry > cbHGCMBuffer)
+        {
+            Log(("VBOXSF: MrxQueryDirectory: Entry size (%d) exceeds the buffer size (%d)!!!\n",
+                 cbEntry, cbHGCMBuffer));
+            Status = STATUS_INVALID_NETWORK_RESPONSE;
+            goto end;
+        }
+
+        switch (FileInformationClass)
+        {
+            case FileDirectoryInformation:
+            {
+                PFILE_DIRECTORY_INFORMATION pInfo = (PFILE_DIRECTORY_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryDirectory: FileDirectoryInformation\n"));
+
+                cbToCopy = sizeof(FILE_DIRECTORY_INFORMATION);
+                /* Struct already contains one char for null terminator. */
+                cbToCopy += pDirEntry->name.u16Size;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->CreationTime.QuadPart   = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+                    pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+                    pInfo->LastWriteTime.QuadPart  = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+                    pInfo->ChangeTime.QuadPart     = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+                    pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+                    pInfo->EndOfFile.QuadPart      = pDirEntry->Info.cbObject;
+                    pInfo->FileIndex               = index;
+                    pInfo->FileAttributes          = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+                    INIT_FILE_NAME(pInfo, pDirEntry->name);
+
+                    /* Align to 8 byte boundary */
+                    cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
+                    pInfo->NextEntryOffset = cbToCopy;
+                    pNextOffset = &pInfo->NextEntryOffset;
+                }
+                else
+                {
+                    pInfo->NextEntryOffset = 0; /* last item */
+                    Status = STATUS_BUFFER_OVERFLOW;
+                }
+                break;
+            }
+
+            case FileFullDirectoryInformation:
+            {
+                PFILE_FULL_DIR_INFORMATION pInfo = (PFILE_FULL_DIR_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryDirectory: FileFullDirectoryInformation\n"));
+
+                cbToCopy = sizeof(FILE_FULL_DIR_INFORMATION);
+                /* Struct already contains one char for null terminator. */
+                cbToCopy += pDirEntry->name.u16Size;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->CreationTime.QuadPart   = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+                    pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+                    pInfo->LastWriteTime.QuadPart  = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+                    pInfo->ChangeTime.QuadPart     = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+                    pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+                    pInfo->EndOfFile.QuadPart      = pDirEntry->Info.cbObject;
+                    pInfo->EaSize                  = 0;
+                    pInfo->FileIndex               = index;
+                    pInfo->FileAttributes          = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+                    INIT_FILE_NAME(pInfo, pDirEntry->name);
+
+                    /* Align to 8 byte boundary */
+                    cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
+                    pInfo->NextEntryOffset = cbToCopy;
+                    pNextOffset = &pInfo->NextEntryOffset;
+                }
+                else
+                {
+                    pInfo->NextEntryOffset = 0; /* last item */
+                    Status = STATUS_BUFFER_OVERFLOW;
+                }
+                break;
+            }
+
+            case FileBothDirectoryInformation:
+            {
+                PFILE_BOTH_DIR_INFORMATION pInfo = (PFILE_BOTH_DIR_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation\n"));
+
+                cbToCopy = sizeof(FILE_BOTH_DIR_INFORMATION);
+                /* struct already contains one char for null terminator */
+                cbToCopy += pDirEntry->name.u16Size;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->CreationTime.QuadPart   = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+                    pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+                    pInfo->LastWriteTime.QuadPart  = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+                    pInfo->ChangeTime.QuadPart     = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+                    pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+                    pInfo->EndOfFile.QuadPart      = pDirEntry->Info.cbObject;
+                    pInfo->EaSize                  = 0;
+                    pInfo->ShortNameLength         = 0; /* @todo ? */
+                    pInfo->FileIndex               = index;
+                    pInfo->FileAttributes          = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+                    INIT_FILE_NAME(pInfo, pDirEntry->name);
+
+                    Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation cbAlloc = %x cbObject = %x\n",
+                         pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
+                    Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation cbToCopy = %d, name size=%d name len=%d\n",
+                         cbToCopy, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
+                    Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation File name %.*ls (DirInfo)\n",
+                         pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
+                    Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation File name %.*ls (DirEntry)\n",
+                         pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
+
+                    /* Align to 8 byte boundary. */
+                    cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
+                    pInfo->NextEntryOffset = cbToCopy;
+                    pNextOffset = &pInfo->NextEntryOffset;
+                }
+                else
+                {
+                    pInfo->NextEntryOffset = 0; /* Last item. */
+                    Status = STATUS_BUFFER_OVERFLOW;
+                }
+                break;
+            }
+
+            case FileIdBothDirectoryInformation:
+            {
+                PFILE_ID_BOTH_DIR_INFORMATION pInfo = (PFILE_ID_BOTH_DIR_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation\n"));
+
+                cbToCopy = sizeof(FILE_ID_BOTH_DIR_INFORMATION);
+                /* struct already contains one char for null terminator */
+                cbToCopy += pDirEntry->name.u16Size;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->CreationTime.QuadPart   = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+                    pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+                    pInfo->LastWriteTime.QuadPart  = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+                    pInfo->ChangeTime.QuadPart     = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+                    pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+                    pInfo->EndOfFile.QuadPart      = pDirEntry->Info.cbObject;
+                    pInfo->EaSize                  = 0;
+                    pInfo->ShortNameLength         = 0; /* @todo ? */
+                    pInfo->EaSize                  = 0;
+                    pInfo->FileId.QuadPart         = 0;
+                    pInfo->FileAttributes          = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+                    INIT_FILE_NAME(pInfo, pDirEntry->name);
+
+                    Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation cbAlloc = 0x%RX64 cbObject = 0x%RX64\n",
+                         pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
+                    Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation cbToCopy = %d, name size=%d name len=%d\n",
+                         cbToCopy, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
+                    Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirInfo)\n",
+                         pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
+                    Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirEntry)\n",
+                         pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
+
+                    /* Align to 8 byte boundary. */
+                    cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
+                    pInfo->NextEntryOffset = cbToCopy;
+                    pNextOffset = &pInfo->NextEntryOffset;
+                }
+                else
+                {
+                    pInfo->NextEntryOffset = 0; /* Last item. */
+                    Status = STATUS_BUFFER_OVERFLOW;
+                }
+                break;
+            }
+
+            case FileNamesInformation:
+            {
+                PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryDirectory: FileNamesInformation\n"));
+
+                cbToCopy = sizeof(FILE_NAMES_INFORMATION);
+                /* Struct already contains one char for null terminator. */
+                cbToCopy += pDirEntry->name.u16Size;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->FileIndex = index;
+
+                    INIT_FILE_NAME(pInfo, pDirEntry->name);
+
+                    Log(("VBOXSF: MrxQueryDirectory: FileNamesInformation: File name [%.*ls]\n",
+                         pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
+
+                    /* Align to 8 byte boundary. */
+                    cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
+                    pInfo->NextEntryOffset = cbToCopy;
+                    pNextOffset = &pInfo->NextEntryOffset;
+                }
+                else
+                {
+                    pInfo->NextEntryOffset = 0; /* Last item. */
+                    Status = STATUS_BUFFER_OVERFLOW;
+                }
+                break;
+            }
+
+            default:
+                Log(("VBOXSF: MrxQueryDirectory: Not supported FileInformationClass %d!\n",
+                     FileInformationClass));
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+        }
+
+        cbHGCMBuffer -= cbEntry;
+        pDirEntry = (PSHFLDIRINFO)((uintptr_t)pDirEntry + cbEntry);
+
+        Log(("VBOXSF: MrxQueryDirectory: %d bytes left in HGCM buffer\n",
+             cbHGCMBuffer));
+
+        if (*pLengthRemaining >= cbToCopy)
+        {
+            pInfoBuffer += cbToCopy;
+            *pLengthRemaining -= cbToCopy;
+        }
+        else
+        {
+            break;
+        }
+
+        if (RxContext->QueryDirectory.ReturnSingleEntry)
+        {
+            break;
+        }
+
+        /* More left? */
+        if (cbHGCMBuffer <= 0)
+        {
+            break;
+        }
+
+        index++; /* File Index. */
+
+        cFiles--;
+    }
+
+    if (pNextOffset)
+    {
+        *pNextOffset = 0; /* Last pInfo->NextEntryOffset should be set to zero! */
+    }
+
+end:
+    if (pHGCMBuffer)
+    {
+        vbsfFreeNonPagedMem(pHGCMBuffer);
+    }
+
+    if (ParsedPath)
+    {
+        vbsfFreeNonPagedMem(ParsedPath);
+    }
+
+    Log(("VBOXSF: MrxQueryDirectory: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS VBoxMRxQueryVolumeInfo(IN OUT PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
+    PVOID pInfoBuffer = RxContext->Info.Buffer;
+    ULONG cbInfoBuffer = RxContext->Info.LengthRemaining;
+    ULONG cbToCopy = 0;
+
+    Log(("VBOXSF: MrxQueryVolumeInfo: pInfoBuffer = %p, cbInfoBuffer = %d\n",
+         RxContext->Info.Buffer, RxContext->Info.LengthRemaining));
+    Log(("VBOXSF: MrxQueryVolumeInfo: vboxFobx = %p, Handle = 0x%RX64\n",
+         pVBoxFobx, pVBoxFobx? pVBoxFobx->hFile: 0));
+
+    Status = STATUS_INVALID_PARAMETER;
+
+    switch (FsInformationClass)
+    {
+        case FileFsVolumeInformation:
+        {
+            PFILE_FS_VOLUME_INFORMATION pInfo = (PFILE_FS_VOLUME_INFORMATION)pInfoBuffer;
+
+            PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+            PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+
+            PWCHAR pRootName;
+            ULONG cbRootName;
+
+            PSHFLVOLINFO pShflVolInfo;
+            uint32_t cbHGCMBuffer;
+            uint8_t *pHGCMBuffer;
+            int vboxRC;
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation\n"));
+
+            if (pVBoxFobx == NULL)
+            {
+                Log(("VBOXSF: MrxQueryVolumeInfo: pVBoxFobx is NULL!\n"));
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            cbRootName = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
+            cbRootName -= sizeof(WCHAR); /* Remove the leading backslash. */
+            pRootName = pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR));
+            pRootName++; /* Remove the leading backslash. */
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: Root name = %.*ls\n",
+                 cbRootName / sizeof(WCHAR), pRootName));
+
+            cbToCopy = sizeof(FILE_FS_VOLUME_INFORMATION);
+            cbToCopy += VBOX_VOLNAME_PREFIX_SIZE;
+            cbToCopy += cbRootName;
+
+            if (cbInfoBuffer < cbToCopy)
+            {
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            RtlZeroMemory(pInfo, sizeof(FILE_FS_VOLUME_INFORMATION));
+
+            /* Query serial number. */
+            cbHGCMBuffer = sizeof(SHFLVOLINFO);
+            pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+            if (pHGCMBuffer == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                                    SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
+
+            if (vboxRC != VINF_SUCCESS)
+            {
+                Status = VBoxErrorToNTStatus(vboxRC);
+                vbsfFreeNonPagedMem(pHGCMBuffer);
+                break;
+            }
+
+            pShflVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
+            pInfo->VolumeSerialNumber = pShflVolInfo->ulSerial;
+            vbsfFreeNonPagedMem(pHGCMBuffer);
+
+            pInfo->VolumeCreationTime.QuadPart = 0;
+            pInfo->VolumeLabelLength = VBOX_VOLNAME_PREFIX_SIZE + cbRootName;
+            pInfo->SupportsObjects = FALSE;
+
+            RtlCopyMemory(&pInfo->VolumeLabel[0], VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE);
+            RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)], pRootName, cbRootName);
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: VolumeLabelLength %d\n",
+                 pInfo->VolumeLabelLength));
+
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case FileFsLabelInformation:
+        {
+            PFILE_FS_LABEL_INFORMATION pInfo = (PFILE_FS_LABEL_INFORMATION)pInfoBuffer;
+
+            PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+            PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+
+            PWCHAR pRootName;
+            ULONG cbRootName;
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsLabelInformation\n"));
+
+            cbRootName = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
+            cbRootName -= sizeof(WCHAR); /* Remove the leading backslash. */
+            pRootName = pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR));
+            pRootName++; /* Remove the leading backslash. */
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsLabelInformation: Root name = %.*ls\n",
+                 cbRootName / sizeof(WCHAR), pRootName));
+
+            cbToCopy = sizeof(FILE_FS_LABEL_INFORMATION);
+            cbToCopy += VBOX_VOLNAME_PREFIX_SIZE;
+            cbToCopy += cbRootName;
+
+            if (cbInfoBuffer < cbToCopy)
+            {
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            RtlZeroMemory(pInfo, sizeof(FILE_FS_LABEL_INFORMATION));
+
+            pInfo->VolumeLabelLength = VBOX_VOLNAME_PREFIX_SIZE + cbRootName;
+
+            RtlCopyMemory(&pInfo->VolumeLabel[0], VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE);
+            RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)], pRootName, cbRootName);
+
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case FileFsFullSizeInformation:
+        case FileFsSizeInformation:
+        {
+            PFILE_FS_FULL_SIZE_INFORMATION pFullSizeInfo = (PFILE_FS_FULL_SIZE_INFORMATION)pInfoBuffer;
+            PFILE_FS_SIZE_INFORMATION pSizeInfo = (PFILE_FS_SIZE_INFORMATION)pInfoBuffer;
+
+            uint32_t cbHGCMBuffer;
+            uint8_t *pHGCMBuffer;
+            int vboxRC;
+            PSHFLVOLINFO pShflVolInfo;
+
+            LARGE_INTEGER TotalAllocationUnits;
+            LARGE_INTEGER AvailableAllocationUnits;
+            ULONG         SectorsPerAllocationUnit;
+            ULONG         BytesPerSector;
+
+            if (FsInformationClass == FileFsFullSizeInformation)
+            {
+                Log(("VBOXSF: MrxQueryVolumeInfo: FileFsFullSizeInformation\n"));
+                cbToCopy = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
+            }
+            else
+            {
+                Log(("VBOXSF: MrxQueryVolumeInfo: FileFsSizeInformation\n"));
+                cbToCopy = sizeof(FILE_FS_SIZE_INFORMATION);
+            }
+
+            if (pVBoxFobx == NULL)
+            {
+                Log(("VBOXSF: MrxQueryVolumeInfo: pVBoxFobx is NULL!\n"));
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            if (cbInfoBuffer < cbToCopy)
+            {
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            RtlZeroMemory(pInfoBuffer, cbToCopy);
+
+            cbHGCMBuffer = sizeof(SHFLVOLINFO);
+            pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+            if (pHGCMBuffer == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                                    SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
+
+            if (vboxRC != VINF_SUCCESS)
+            {
+                Status = VBoxErrorToNTStatus(vboxRC);
+                vbsfFreeNonPagedMem(pHGCMBuffer);
+                break;
+            }
+
+            pShflVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
+
+            TotalAllocationUnits.QuadPart     = pShflVolInfo->ullTotalAllocationBytes / pShflVolInfo->ulBytesPerAllocationUnit;
+            AvailableAllocationUnits.QuadPart = pShflVolInfo->ullAvailableAllocationBytes / pShflVolInfo->ulBytesPerAllocationUnit;
+            SectorsPerAllocationUnit          = pShflVolInfo->ulBytesPerAllocationUnit / pShflVolInfo->ulBytesPerSector;
+            BytesPerSector                    = pShflVolInfo->ulBytesPerSector;
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: TotalAllocationUnits     0x%RX64\n", TotalAllocationUnits.QuadPart));
+            Log(("VBOXSF: MrxQueryVolumeInfo: AvailableAllocationUnits 0x%RX64\n", AvailableAllocationUnits.QuadPart));
+            Log(("VBOXSF: MrxQueryVolumeInfo: SectorsPerAllocationUnit 0x%X\n", SectorsPerAllocationUnit));
+            Log(("VBOXSF: MrxQueryVolumeInfo: BytesPerSector           0x%X\n", BytesPerSector));
+
+            if (FsInformationClass == FileFsFullSizeInformation)
+            {
+                pFullSizeInfo->TotalAllocationUnits           = TotalAllocationUnits;
+                pFullSizeInfo->CallerAvailableAllocationUnits = AvailableAllocationUnits;
+                pFullSizeInfo->ActualAvailableAllocationUnits = AvailableAllocationUnits;
+                pFullSizeInfo->SectorsPerAllocationUnit       = SectorsPerAllocationUnit;
+                pFullSizeInfo->BytesPerSector                 = BytesPerSector;
+            }
+            else
+            {
+                pSizeInfo->TotalAllocationUnits     = TotalAllocationUnits;
+                pSizeInfo->AvailableAllocationUnits = AvailableAllocationUnits;
+                pSizeInfo->SectorsPerAllocationUnit = SectorsPerAllocationUnit;
+                pSizeInfo->BytesPerSector           = BytesPerSector;
+            }
+
+            vbsfFreeNonPagedMem(pHGCMBuffer);
+
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case FileFsDeviceInformation:
+        {
+            PFILE_FS_DEVICE_INFORMATION pInfo = (PFILE_FS_DEVICE_INFORMATION)pInfoBuffer;
+            PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsDeviceInformation: Type = %d\n",
+                 NetRoot->DeviceType));
+
+            cbToCopy = sizeof(FILE_FS_DEVICE_INFORMATION);
+
+            if (cbInfoBuffer < cbToCopy)
+            {
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            pInfo->DeviceType = NetRoot->DeviceType;
+            pInfo->Characteristics = FILE_REMOTE_DEVICE;
+
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case FileFsAttributeInformation:
+        {
+            PFILE_FS_ATTRIBUTE_INFORMATION pAttribInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)pInfoBuffer;
+
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsAttributeInformation\n"));
+
+            cbToCopy = sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
+            cbToCopy += sizeof(MRX_VBOX_FILESYS_NAME_U) - sizeof(WCHAR);
+
+            if (cbInfoBuffer < cbToCopy)
+            {
+                Status = STATUS_BUFFER_TOO_SMALL;
+                break;
+            }
+
+            pAttribInfo->FileSystemAttributes = 0; /** @todo set unicode, case sensitive etc? */
+            pAttribInfo->MaximumComponentNameLength = 255; /** @todo should query from the host */
+            pAttribInfo->FileSystemNameLength = sizeof(MRX_VBOX_FILESYS_NAME_U);
+            RtlCopyMemory(pAttribInfo->FileSystemName, MRX_VBOX_FILESYS_NAME_U, sizeof(MRX_VBOX_FILESYS_NAME_U));
+
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case FileFsControlInformation:
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsControlInformation: not supported\n"));
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+
+        case FileFsObjectIdInformation:
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsObjectIdInformation: not supported\n"));
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+
+        case FileFsMaximumInformation:
+            Log(("VBOXSF: MrxQueryVolumeInfo: FileFsMaximumInformation: not supported\n"));
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+
+        default:
+            Log(("VBOXSF: MrxQueryVolumeInfo: Not supported FsInformationClass %d!\n",
+                 FsInformationClass));
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+    }
+
+    if (Status == STATUS_SUCCESS)
+    {
+        RxContext->Info.LengthRemaining = cbInfoBuffer - cbToCopy;
+    }
+    else if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        Log(("VBOXSF: MrxQueryVolumeInfo: Insufficient buffer size %d, required %d\n",
+             cbInfoBuffer, cbToCopy));
+        RxContext->InformationToReturn = cbToCopy;
+    }
+
+    Log(("VBOXSF: MrxQueryVolumeInfo: cbToCopy = %d, LengthRemaining = %d, Status = 0x%08X\n",
+         cbToCopy, RxContext->Info.LengthRemaining, Status));
+
+    return Status;
+}
+
+NTSTATUS VBoxMRxQueryFileInfo(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+    FILE_INFORMATION_CLASS FunctionalityRequested = RxContext->Info.FileInformationClass;
+    PCHAR pInfoBuffer = (PCHAR)RxContext->Info.Buffer;
+    uint32_t cbInfoBuffer = RxContext->Info.Length;
+    ULONG *pLengthRemaining = (PULONG) & RxContext->Info.LengthRemaining;
+
+    int vboxRC = 0;
+
+    ULONG cbToCopy = 0;
+    uint8_t *pHGCMBuffer = 0;
+    uint32_t cbHGCMBuffer;
+    PSHFLFSOBJINFO pFileEntry = NULL;
+
+    if (NULL == pLengthRemaining)
+    {
+        Log(("VBOXSF: MrxQueryFileInfo: length pointer is NULL!\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Log(("VBOXSF: MrxQueryFileInfo: InfoBuffer = %p, Size = %d bytes, LenRemain = %d bytes\n",
+         pInfoBuffer, cbInfoBuffer, *pLengthRemaining));
+
+    if (NULL == pVBoxFobx)
+    {
+        Log(("VBOXSF: MrxQueryFileInfo: pVBoxFobx is NULL!\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (NULL == pInfoBuffer)
+    {
+        Log(("VBOXSF: MrxQueryFileInfo: pInfoBuffer is NULL!\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (pVBoxFobx->FileStandardInfo.Directory == TRUE)
+    {
+        Log(("VBOXSF: MrxQueryFileInfo: Directory -> Copy info retrieved during the create call\n"));
+        Status = STATUS_SUCCESS;
+
+        switch (FunctionalityRequested)
+        {
+            case FileBasicInformation:
+            {
+                PFILE_BASIC_INFORMATION pInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileBasicInformation\n"));
+
+                cbToCopy = sizeof(FILE_BASIC_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    *pInfo = pVBoxFobx->FileBasicInfo;
+                    Log(("VBOXSF: MrxQueryFileInfo: FileBasicInformation: File attributes: 0x%x\n",
+                         pInfo->FileAttributes));
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileStandardInformation:
+            {
+                PFILE_STANDARD_INFORMATION pInfo = (PFILE_STANDARD_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileStandardInformation\n"));
+
+                cbToCopy = sizeof(FILE_STANDARD_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    *pInfo = pVBoxFobx->FileStandardInfo;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileNamesInformation:
+            {
+                PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileNamesInformation\n"));
+
+                cbToCopy = sizeof(FILE_NAMES_INFORMATION);
+                /* And size in bytes of the WCHAR name. */
+                cbToCopy += FileName->Length;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->FileNameLength = FileName->Length;
+
+                    RtlCopyMemory(pInfo->FileName, FileName->Buffer, FileName->Length);
+                    pInfo->FileName[FileName->Length] = 0; /* FILE_NAMES_INFORMATION had space for the nul. */
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileInternalInformation:
+            {
+                PFILE_INTERNAL_INFORMATION pInfo = (PFILE_INTERNAL_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileInternalInformation\n"));
+
+                cbToCopy = sizeof(FILE_INTERNAL_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    /* A 8-byte file reference number for the file. */
+                    pInfo->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+            case FileEaInformation:
+            {
+                PFILE_EA_INFORMATION pInfo = (PFILE_EA_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileEaInformation\n"));
+
+                cbToCopy = sizeof(FILE_EA_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->EaSize = 0;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileNetworkOpenInformation:
+            {
+                PFILE_NETWORK_OPEN_INFORMATION pInfo = (PFILE_NETWORK_OPEN_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileNetworkOpenInformation\n"));
+
+                cbToCopy = sizeof(FILE_NETWORK_OPEN_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->CreationTime   = pVBoxFobx->FileBasicInfo.CreationTime;
+                    pInfo->LastAccessTime = pVBoxFobx->FileBasicInfo.LastAccessTime;
+                    pInfo->LastWriteTime  = pVBoxFobx->FileBasicInfo.LastWriteTime;
+                    pInfo->ChangeTime     = pVBoxFobx->FileBasicInfo.ChangeTime;
+                    pInfo->AllocationSize.QuadPart = 0;
+                    pInfo->EndOfFile.QuadPart      = 0;
+                    pInfo->FileAttributes = pVBoxFobx->FileBasicInfo.FileAttributes;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileStreamInformation:
+                Log(("VBOXSF: MrxQueryFileInfo: FileStreamInformation: not supported\n"));
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+
+            default:
+                Log(("VBOXSF: MrxQueryFileInfo: Not supported FunctionalityRequested %d!\n",
+                     FunctionalityRequested));
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+        }
+    }
+    else /* Entry is a file. */
+    {
+        cbHGCMBuffer = RT_MAX(cbInfoBuffer, PAGE_SIZE);
+        pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+
+        if (pHGCMBuffer == NULL)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension);
+        vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                                SHFL_INFO_GET | SHFL_INFO_FILE, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
+
+        if (vboxRC != VINF_SUCCESS)
+        {
+            Status = VBoxErrorToNTStatus(vboxRC);
+            goto end;
+        }
+
+        pFileEntry = (PSHFLFSOBJINFO)pHGCMBuffer;
+        Status = STATUS_SUCCESS;
+
+        switch (FunctionalityRequested)
+        {
+            case FileBasicInformation:
+            {
+                PFILE_BASIC_INFORMATION pInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileBasicInformation\n"));
+
+                cbToCopy = sizeof(FILE_BASIC_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->CreationTime.QuadPart   = RTTimeSpecGetNtTime(&pFileEntry->BirthTime); /* Ridiculous name. */
+                    pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->AccessTime);
+                    pInfo->LastWriteTime.QuadPart  = RTTimeSpecGetNtTime(&pFileEntry->ModificationTime);
+                    pInfo->ChangeTime.QuadPart     = RTTimeSpecGetNtTime(&pFileEntry->ChangeTime);
+                    pInfo->FileAttributes          = VBoxToNTFileAttributes(pFileEntry->Attr.fMode);
+
+                    Log(("VBOXSF: MrxQueryFileInfo: FileBasicInformation: File attributes = 0x%x\n",
+                         pInfo->FileAttributes));
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileStandardInformation:
+            {
+                PFILE_STANDARD_INFORMATION pInfo = (PFILE_STANDARD_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileStandardInformation\n"));
+
+                cbToCopy = sizeof(FILE_STANDARD_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated;
+                    pInfo->EndOfFile.QuadPart      = pFileEntry->cbObject;
+                    pInfo->NumberOfLinks           = 1; /* @todo 0? */
+                    pInfo->DeletePending           = FALSE;
+
+                    if (pFileEntry->Attr.fMode & RTFS_DOS_DIRECTORY)
+                    {
+                        pInfo->Directory = TRUE;
+                    }
+                    else
+                    {
+                        pInfo->Directory = FALSE;
+                    }
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileNamesInformation:
+            {
+                PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileNamesInformation\n"));
+
+                cbToCopy = sizeof(FILE_NAMES_INFORMATION);
+                /* And size in bytes of the WCHAR name. */
+                cbToCopy += FileName->Length;
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    RtlZeroMemory(pInfo, cbToCopy);
+
+                    pInfo->FileNameLength = FileName->Length;
+
+                    RtlCopyMemory(pInfo->FileName, FileName->Buffer, FileName->Length);
+                    pInfo->FileName[FileName->Length] = 0; /* FILE_NAMES_INFORMATION had space for the nul. */
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileInternalInformation:
+            {
+                PFILE_INTERNAL_INFORMATION pInfo = (PFILE_INTERNAL_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileInternalInformation\n"));
+
+                cbToCopy = sizeof(FILE_INTERNAL_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    /* A 8-byte file reference number for the file. */
+                    pInfo->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileEaInformation:
+            {
+                PFILE_EA_INFORMATION pInfo = (PFILE_EA_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileEaInformation\n"));
+
+                cbToCopy = sizeof(FILE_EA_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->EaSize = 0;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileAttributeTagInformation:
+            {
+                PFILE_ATTRIBUTE_TAG_INFORMATION pInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileAttributeTagInformation\n"));
+
+                cbToCopy = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode);
+                    pInfo->ReparseTag = 0;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileEndOfFileInformation:
+            {
+                PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileEndOfFileInformation\n"));
+
+                cbToCopy = sizeof(FILE_END_OF_FILE_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->EndOfFile.QuadPart = pFileEntry->cbObject;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileAllocationInformation:
+            {
+                PFILE_ALLOCATION_INFORMATION pInfo = (PFILE_ALLOCATION_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileAllocationInformation\n"));
+
+                cbToCopy = sizeof(FILE_ALLOCATION_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated;
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileNetworkOpenInformation:
+            {
+                PFILE_NETWORK_OPEN_INFORMATION pInfo = (PFILE_NETWORK_OPEN_INFORMATION)pInfoBuffer;
+                Log(("VBOXSF: MrxQueryFileInfo: FileNetworkOpenInformation\n"));
+
+                cbToCopy = sizeof(FILE_NETWORK_OPEN_INFORMATION);
+
+                if (*pLengthRemaining >= cbToCopy)
+                {
+                    pInfo->CreationTime.QuadPart   = RTTimeSpecGetNtTime(&pFileEntry->BirthTime); /* Ridiculous name. */
+                    pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->AccessTime);
+                    pInfo->LastWriteTime.QuadPart  = RTTimeSpecGetNtTime(&pFileEntry->ModificationTime);
+                    pInfo->ChangeTime.QuadPart     = RTTimeSpecGetNtTime(&pFileEntry->ChangeTime);
+                    pInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated;
+                    pInfo->EndOfFile.QuadPart      = pFileEntry->cbObject;
+                    pInfo->FileAttributes          = VBoxToNTFileAttributes(pFileEntry->Attr.fMode);
+                }
+                else
+                {
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                }
+                break;
+            }
+
+            case FileStreamInformation:
+                Log(("VBOXSF: MrxQueryFileInfo: FileStreamInformation: not supported\n"));
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+
+            default:
+                Log(("VBOXSF: MrxQueryFileInfo: Not supported FunctionalityRequested %d!\n",
+                     FunctionalityRequested));
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+        }
+    }
+
+    if (Status == STATUS_SUCCESS)
+    {
+        if (*pLengthRemaining < cbToCopy)
+        {
+            /* This situation must be already taken into account by the above code. */
+            AssertMsgFailed(("VBOXSF: MrxQueryFileInfo: Length remaining is below 0! (%d - %d)!\n",
+                             *pLengthRemaining, cbToCopy));
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+        else
+        {
+            pInfoBuffer += cbToCopy;
+            *pLengthRemaining -= cbToCopy;
+        }
+    }
+
+end:
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        Log(("VBOXSF: MrxQueryFileInfo: Buffer too small %d, required %d!\n",
+             *pLengthRemaining, cbToCopy));
+        RxContext->InformationToReturn = cbToCopy;
+    }
+
+    if (pHGCMBuffer)
+    {
+        vbsfFreeNonPagedMem(pHGCMBuffer);
+    }
+
+    if (Status == STATUS_SUCCESS)
+    {
+        Log(("VBOXSF: MrxQueryFileInfo: Remaining length = %d\n",
+             *pLengthRemaining));
+    }
+
+    Log(("VBOXSF: MrxQueryFileInfo: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS VBoxMRxSetFileInfo(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    FILE_INFORMATION_CLASS FunctionalityRequested = RxContext->Info.FileInformationClass;
+    PVOID pInfoBuffer = (PVOID)RxContext->Info.Buffer;
+
+    int vboxRC;
+
+    uint8_t *pHGCMBuffer = NULL;
+    uint32_t cbBuffer = 0;
+
+    Log(("VBOXSF: MrxSetFileInfo: pInfoBuffer %p\n",
+         pInfoBuffer));
+
+    switch (FunctionalityRequested)
+    {
+        case FileBasicInformation:
+        {
+            PFILE_BASIC_INFORMATION pInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer;
+            PSHFLFSOBJINFO pSHFLFileInfo;
+
+            Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: CreationTime   %RX64\n", pInfo->CreationTime.QuadPart));
+            Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: LastAccessTime %RX64\n", pInfo->LastAccessTime.QuadPart));
+            Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: LastWriteTime  %RX64\n", pInfo->LastWriteTime.QuadPart));
+            Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: ChangeTime     %RX64\n", pInfo->ChangeTime.QuadPart));
+            Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: FileAttributes %RX32\n", pInfo->FileAttributes));
+
+            /* When setting file attributes, a value of -1 indicates to the server that it MUST NOT change this attribute
+             * for all subsequent operations on the same file handle.
+             */
+            if (pInfo->CreationTime.QuadPart == -1)
+            {
+                pVBoxFobx->fKeepCreationTime = TRUE;
+            }
+            if (pInfo->LastAccessTime.QuadPart == -1)
+            {
+                pVBoxFobx->fKeepLastAccessTime = TRUE;
+            }
+            if (pInfo->LastWriteTime.QuadPart == -1)
+            {
+                pVBoxFobx->fKeepLastWriteTime = TRUE;
+            }
+            if (pInfo->ChangeTime.QuadPart == -1)
+            {
+                pVBoxFobx->fKeepChangeTime = TRUE;
+            }
+
+            cbBuffer = sizeof(SHFLFSOBJINFO);
+            pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbBuffer);
+            if (pHGCMBuffer == NULL)
+            {
+                AssertFailed();
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+            RtlZeroMemory(pHGCMBuffer, cbBuffer);
+            pSHFLFileInfo = (PSHFLFSOBJINFO)pHGCMBuffer;
+
+            Log(("VBOXSF: MrxSetFileInfo: FileBasicInformation: keeps %d %d %d %d\n",
+                 pVBoxFobx->fKeepCreationTime, pVBoxFobx->fKeepLastAccessTime, pVBoxFobx->fKeepLastWriteTime, pVBoxFobx->fKeepChangeTime));
+
+            /* The properties, that need to be changed, are set to something other than zero */
+            if (pInfo->CreationTime.QuadPart && !pVBoxFobx->fKeepCreationTime)
+            {
+                RTTimeSpecSetNtTime(&pSHFLFileInfo->BirthTime, pInfo->CreationTime.QuadPart);
+            }
+            if (pInfo->LastAccessTime.QuadPart && !pVBoxFobx->fKeepLastAccessTime)
+            {
+                RTTimeSpecSetNtTime(&pSHFLFileInfo->AccessTime, pInfo->LastAccessTime.QuadPart);
+            }
+            if (pInfo->LastWriteTime.QuadPart && !pVBoxFobx->fKeepLastWriteTime)
+            {
+                RTTimeSpecSetNtTime(&pSHFLFileInfo->ModificationTime, pInfo->LastWriteTime.QuadPart);
+            }
+            if (pInfo->ChangeTime.QuadPart && !pVBoxFobx->fKeepChangeTime)
+            {
+                RTTimeSpecSetNtTime(&pSHFLFileInfo->ChangeTime, pInfo->ChangeTime.QuadPart);
+            }
+            if (pInfo->FileAttributes)
+            {
+                pSHFLFileInfo->Attr.fMode = NTToVBoxFileAttributes(pInfo->FileAttributes);
+            }
+
+            Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension);
+            vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile,
+                                    SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer, (PSHFLDIRINFO)pSHFLFileInfo);
+
+            if (vboxRC != VINF_SUCCESS)
+            {
+                Status = VBoxErrorToNTStatus(vboxRC);
+                goto end;
+            }
+            else
+            {
+                /* Update our internal copy. Ignore zero fields! */
+                if (pInfo->CreationTime.QuadPart && !pVBoxFobx->fKeepCreationTime)
+                {
+                    pVBoxFobx->FileBasicInfo.CreationTime = pInfo->CreationTime;
+                }
+                if (pInfo->LastAccessTime.QuadPart && !pVBoxFobx->fKeepLastAccessTime)
+                {
+                    pVBoxFobx->FileBasicInfo.LastAccessTime = pInfo->LastAccessTime;
+                }
+                if (pInfo->LastWriteTime.QuadPart && !pVBoxFobx->fKeepLastWriteTime)
+                {
+                    pVBoxFobx->FileBasicInfo.LastWriteTime = pInfo->LastWriteTime;
+                }
+                if (pInfo->ChangeTime.QuadPart && !pVBoxFobx->fKeepChangeTime)
+                {
+                    pVBoxFobx->FileBasicInfo.ChangeTime = pInfo->ChangeTime;
+                }
+                if (pInfo->FileAttributes)
+                {
+                    pVBoxFobx->FileBasicInfo.FileAttributes = pInfo->FileAttributes;
+                }
+            }
+
+            break;
+        }
+
+        case FileDispositionInformation:
+        {
+            PFILE_DISPOSITION_INFORMATION pInfo = (PFILE_DISPOSITION_INFORMATION)pInfoBuffer;
+
+            Log(("VBOXSF: MrxSetFileInfo: FileDispositionInformation: Delete = %d\n",
+                 pInfo->DeleteFile));
+
+            if (pInfo->DeleteFile && capFcb->OpenCount == 1)
+            {
+                Status = vbsfRemove(RxContext);
+            }
+            else
+            {
+                Status = STATUS_SUCCESS;
+            }
+            break;
+        }
+
+        case FilePositionInformation:
+        {
+            PFILE_POSITION_INFORMATION pInfo = (PFILE_POSITION_INFORMATION)pInfoBuffer;
+
+            Log(("VBOXSF: MrxSetFileInfo: FilePositionInformation: CurrentByteOffset = 0x%RX64. Unsupported!\n",
+                 pInfo->CurrentByteOffset.QuadPart));
+
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+
+        case FileAllocationInformation:
+        {
+            PFILE_ALLOCATION_INFORMATION pInfo = (PFILE_ALLOCATION_INFORMATION)pInfoBuffer;
+
+            Log(("VBOXSF: MrxSetFileInfo: FileAllocationInformation: new AllocSize = 0x%RX64, FileSize = 0x%RX64\n",
+                 pInfo->AllocationSize.QuadPart, capFcb->Header.FileSize.QuadPart));
+
+            /* Check if the new allocation size changes the file size. */
+            if (pInfo->AllocationSize.QuadPart > capFcb->Header.FileSize.QuadPart)
+            {
+                /* Ignore this request and return success. Shared folders do not distinguish between
+                 * AllocationSize and FileSize.
+                 */
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                /* Treat the request as a EndOfFile update. */
+                LARGE_INTEGER NewAllocationSize;
+                Status = vbsfSetEndOfFile(RxContext, &pInfo->AllocationSize, &NewAllocationSize);
+            }
+
+            break;
+        }
+
+        case FileEndOfFileInformation:
+        {
+            PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)pInfoBuffer;
+            LARGE_INTEGER NewAllocationSize;
+
+            Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation: new EndOfFile 0x%RX64, FileSize = 0x%RX64\n",
+                 pInfo->EndOfFile.QuadPart, capFcb->Header.FileSize.QuadPart));
+
+            Status = vbsfSetEndOfFile(RxContext, &pInfo->EndOfFile, &NewAllocationSize);
+
+            Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation: AllocSize = 0x%RX64, Status 0x%08X\n",
+                 NewAllocationSize.QuadPart, Status));
+
+            break;
+        }
+
+        case FileLinkInformation:
+        {
+            PFILE_LINK_INFORMATION pInfo = (PFILE_LINK_INFORMATION )pInfoBuffer;
+
+            Log(("VBOXSF: MrxSetFileInfo: FileLinkInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = [%.*ls]. Not implemented!\n",
+                 pInfo->ReplaceIfExists, pInfo->RootDirectory, pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
+
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+        }
+
+        case FileRenameInformation:
+        {
+            PFILE_RENAME_INFORMATION pInfo = (PFILE_RENAME_INFORMATION)pInfoBuffer;
+
+            Log(("VBOXSF: MrxSetFileInfo: FileRenameInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = [%.*ls]\n",
+                 pInfo->ReplaceIfExists, pInfo->RootDirectory, pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
+
+            Status = vbsfRename(RxContext, FileRenameInformation, pInfoBuffer, RxContext->Info.Length);
+            break;
+        }
+
+        default:
+            Log(("VBOXSF: MrxSetFileInfo: Not supported FunctionalityRequested %d!\n",
+                 FunctionalityRequested));
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+    }
+
+end:
+    if (pHGCMBuffer)
+    {
+        vbsfFreeNonPagedMem(pHGCMBuffer);
+    }
+
+    Log(("VBOXSF: MrxSetFileInfo: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS VBoxMRxSetFileInfoAtCleanup(IN PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxSetFileInfoAtCleanup\n"));
+    return STATUS_SUCCESS;
+}
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/net.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/net.c	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/net.c	(revision 40269)
@@ -0,0 +1,484 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver network redirector subsystem routines
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "vbsf.h"
+
+NTSTATUS VBoxMRxUpdateNetRootState(IN OUT PMRX_NET_ROOT pNetRoot)
+{
+    Log(("VBOXSF: MRxUpdateNetRootState\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+static void vbsfUpdateNetRoot(PMRX_NET_ROOT pNetRoot)
+{
+    Log(("VBOXSF: vbsfUpdateNetRoot: NetRoot = 0x%x Type = 0x%x\n",
+         pNetRoot, pNetRoot->Type));
+
+    switch (pNetRoot->Type)
+    {
+        case NET_ROOT_DISK:
+            pNetRoot->DeviceType = RxDeviceType(DISK);
+            break;
+        case NET_ROOT_PIPE:
+            pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
+            break;
+        case NET_ROOT_COMM:
+            pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
+            break;
+        case NET_ROOT_PRINT:
+            pNetRoot->DeviceType = RxDeviceType(PRINTER);
+            break;
+        case NET_ROOT_MAILSLOT:
+            pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
+            break;
+        case NET_ROOT_WILD:
+            /* We get this type when for example Windows Media player opens an MP3 file.
+             * This NetRoot has the same remote path (\\vboxsrv\dir) as other NetRoots,
+             * which were created earlier and which were NET_ROOT_DISK.
+             *
+             * In the beginning of the function (UpdateNetRoot) the DDK sample sets
+             * pNetRoot->Type of newly created NetRoots using a value previously
+             * pstored in a NetRootExtension. One NetRootExtensions is used for a single
+             * remote path and reused by a few NetRoots, if they point to the same path.
+             *
+             * To simplify things we just set the type to DISK here (we do not support
+             * anything else anyway), and update the DeviceType correspondingly.
+             */
+            pNetRoot->Type = NET_ROOT_DISK;
+            pNetRoot->DeviceType = RxDeviceType(DISK);
+            break;
+        default:
+            AssertMsgFailed(("VBOXSF: vbsfUpdateNetRoot: Invalid net root type! Type = 0x%x\n",
+                             pNetRoot->Type));
+            break;
+    }
+
+    Log(("VBOXSF: vbsfUpdateNetRoot: leaving pNetRoot->DeviceType = 0x%x\n",
+         pNetRoot->DeviceType));
+}
+
+NTSTATUS VBoxMRxCreateVNetRoot(IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
+{
+    NTSTATUS Status;
+
+    PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(pCreateNetRootContext->RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot);
+
+    PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
+    PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+
+    BOOLEAN fInitializeNetRoot = FALSE;
+
+    Log(("VBOXSF: MRxCreateVNetRoot: pNetRoot = %p, pNetRootExtension = %p, name = [%.*ls]\n",
+         pNetRoot, pNetRootExtension, pNetRoot->pNetRootName->Length / sizeof(WCHAR), pNetRoot->pNetRootName->Buffer));
+
+    /* IMPORTANT:
+     *
+     * This function must always call 'pCreateNetRootContext->Callback(pCreateNetRootContext)' before
+     * returning and then return STATUS_PENDING. Otherwise Win64 will hang.
+     */
+
+    if (pNetRoot->Type == NET_ROOT_PIPE)
+    {
+        /* VBoxSF claims everything which starts with '\vboxsrv'.
+         *
+         * So sometimes the system tries to open \vboxsrv\ipc$ pipe for DFS
+         * and fails the application call if an unexpected code is returned.
+         *
+         * According to MSDN: The Windows client returns STATUS_MORE_PROCESSING_REQUIRED to the calling
+         * application to indicate that the path does not correspond to a DFS Namespace.
+         */
+        pVNetRoot->Context = NULL;
+
+        if (pNetRoot->pNetRootName->Length >= 13 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv\ipc$' unicode string. */
+        {
+            const WCHAR *Suffix = &pNetRoot->pNetRootName->Buffer[8]; /* Number of chars in '\vboxsrv' */
+
+            if (   Suffix[0] == L'\\'
+                && (Suffix[1] == L'I' || Suffix[1] == L'i')
+                && (Suffix[2] == L'P' || Suffix[2] == L'p')
+                && (Suffix[3] == L'C' || Suffix[3] == L'c')
+                && Suffix[4] == L'$'
+               )
+            {
+                if (   pNetRoot->pNetRootName->Length == 13 * sizeof (WCHAR)
+                    || (Suffix[5] == L'\\' || Suffix[5] == 0)
+                   )
+                {
+                    /* It is '\vboxsrv\IPC$[\*]'. */
+                    Log(("VBOXSF: MRxCreateVNetRoot: IPC$\n"));
+                    Status = STATUS_MORE_PROCESSING_REQUIRED;
+                    goto l_Exit;
+                }
+            }
+        }
+
+        /* Fail all other pipe open requests. */
+        Log(("VBOXSF: MRxCreateVNetRoot: Pipe open not supported!\n"));
+        Status = STATUS_NOT_SUPPORTED;
+        goto l_Exit;
+    }
+    else if (pNetRoot->Type == NET_ROOT_MAILSLOT)
+    {
+        Log(("VBOXSF: MRxCreateVNetRoot: Mailslot open not supported!\n"));
+        pVNetRoot->Context = NULL;
+        Status = STATUS_NOT_SUPPORTED;
+        goto l_Exit;
+    }
+
+    if (pNetRoot->Context == NULL)
+    {
+        /* MRxNetRootSize is not zero in VBoxSF, so it is expected
+         * that the Context, which is NetRootExtension, is already allocated.
+         */
+        Log(("VBOXSF: MRxCreateVNetRoot: NULL netroot context\n"));
+        pVNetRoot->Context = NULL;
+        Status = STATUS_NOT_SUPPORTED;
+        goto l_Exit;
+    }
+
+    /* Detect an already initialized NetRoot.
+     * pNetRootExtension is actually the pNetRoot->Context and it is not NULL.
+     */
+    fInitializeNetRoot = (pNetRootExtension->phgcmClient == NULL);
+
+    Status = STATUS_SUCCESS;
+
+    if (fInitializeNetRoot)
+    {
+        PWCHAR pRootName;
+        ULONG RootNameLength;
+        int vboxRC;
+        PSHFLSTRING ParsedPath = 0;
+        ULONG ParsedPathSize;
+
+        Log(("VBOXSF: MRxCreateVNetRoot: initialize NET_ROOT\n"));
+
+        pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
+
+        RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
+        if (!RootNameLength)
+        {
+            /* Refuse a netroot path with an empty shared folder name */
+            Log(("VBOXSF: MRxCreateVNetRoot: Empty shared folder name!\n"));
+            pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
+
+            Status = STATUS_BAD_NETWORK_NAME;
+            goto l_Exit;
+        }
+
+        RootNameLength -= sizeof(WCHAR); /* Remove leading backslash. */
+
+        pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
+        pRootName++; /* Remove leading backslash. */
+
+        if (pNetRootExtension->phgcmClient == NULL)
+        {
+            Log(("VBOXSF: MRxCreateVNetRoot: Initialize netroot length = %d, name = %.*ls\n",
+                 RootNameLength, RootNameLength / sizeof(WCHAR), pRootName));
+
+            /* Calculate length required for parsed path.
+             */
+            ParsedPathSize = sizeof(*ParsedPath) + RootNameLength + sizeof(WCHAR);
+
+            ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+            if (!ParsedPath)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto l_Exit;
+            }
+            memset(ParsedPath, 0, ParsedPathSize);
+
+            ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+            ParsedPath->u16Size = (uint16_t)RootNameLength + sizeof(WCHAR);
+            ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */
+            RtlCopyMemory(ParsedPath->String.ucs2, pRootName, ParsedPath->u16Length);
+
+            vboxRC = vboxCallMapFolder(&pDeviceExtension->hgcmClient, ParsedPath, &pNetRootExtension->map);
+            vbsfFreeNonPagedMem(ParsedPath);
+            if (vboxRC != VINF_SUCCESS)
+            {
+                Log(("VBOXSF: MRxCreateVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
+                Status = STATUS_BAD_NETWORK_NAME;
+            }
+            else
+            {
+                Status = STATUS_SUCCESS;
+                pNetRootExtension->phgcmClient = &pDeviceExtension->hgcmClient;
+            }
+        }
+    }
+    else
+    {
+        Log(("VBOXSF: MRxCreateVNetRoot: Creating V_NET_ROOT on existing NET_ROOT!\n"));
+    }
+
+    vbsfUpdateNetRoot(pNetRoot);
+
+l_Exit:
+    if (Status != STATUS_PENDING)
+    {
+        Log(("VBOXSF: MRxCreateVNetRoot: Returning 0x%08X\n",
+             Status));
+        pCreateNetRootContext->VirtualNetRootStatus = Status;
+        if (fInitializeNetRoot)
+        {
+            pCreateNetRootContext->NetRootStatus = Status;
+        }
+        else
+        {
+            pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
+        }
+
+        /* Inform RDBSS. */
+        pCreateNetRootContext->Callback(pCreateNetRootContext);
+
+        /* RDBSS expects this. */
+        Status = STATUS_PENDING;
+    }
+
+    Log(("VBOXSF: MRxCreateVNetRoot: Returned STATUS_PENDING\n"));
+    return Status;
+}
+
+NTSTATUS VBoxMRxFinalizeVNetRoot(IN PMRX_V_NET_ROOT pVNetRoot,
+                                 IN PBOOLEAN ForceDisconnect)
+{
+    Log(("VBOXSF: MRxFinalizeVNetRoot: V_NET_ROOT %p, NET_ROOT %p\n",
+         pVNetRoot, pVNetRoot->pNetRoot));
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxFinalizeNetRoot(IN PMRX_NET_ROOT pNetRoot,
+                                IN PBOOLEAN ForceDisconnect)
+{
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(pNetRoot);
+
+    Log(("VBOXSF: MRxFinalizeNetRoot: NET_ROOT %p\n",
+         pNetRoot));
+
+    if (pNetRootExtension->phgcmClient)
+    {
+        int vboxRC = vboxCallUnmapFolder(pNetRootExtension->phgcmClient, &pNetRootExtension->map);
+        if (vboxRC != VINF_SUCCESS)
+        {
+            Log(("VBOXSF: MRxFinalizeVNetRoot: vboxCallMapFolder failed with %d\n",
+                 vboxRC));
+        }
+        pNetRootExtension->phgcmClient = NULL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+VOID VBoxMRxExtractNetRootName(IN PUNICODE_STRING FilePathName,
+                               IN PMRX_SRV_CALL SrvCall,
+                               OUT PUNICODE_STRING NetRootName,
+                               OUT PUNICODE_STRING RestOfName OPTIONAL)
+{
+    int cChars = FilePathName->Length/sizeof(WCHAR);
+    int iNetRoot;
+    int i;
+
+    /* Split "\vboxsvr\share\path" to
+     * NetRootName = "\share"
+     * RestOfName = "\path"
+     *
+     * Note that SrvCall->pSrvCallName contains "\vboxsrv".
+     */
+
+    Log(("VBOXSF: MRxExtractNetRootName: [%.*ls], RestOfName %p\n",
+         FilePathName->Length/sizeof(WCHAR), FilePathName->Buffer, RestOfName));
+
+    /* Assume that the server prefix is OK.
+     * iNetRoot points to the first char after server name, the delimiter.
+     */
+    iNetRoot = SrvCall->pSrvCallName->Length/sizeof(WCHAR);
+
+    /* Find the NetRoot length: end of FilePathName or the next delimiter. */
+    i = iNetRoot;
+    while (i < cChars)
+    {
+        if (   FilePathName->Buffer[i] == L'\\'
+            && i > iNetRoot)
+        {
+            break;
+        }
+        i++;
+    }
+
+    Log(("VBOXSF: MRxExtractNetRootName: cChars %d, iNetRoot %d, iRest %d\n",
+         cChars, iNetRoot, i));
+
+    NetRootName->Buffer = &FilePathName->Buffer[iNetRoot];
+    NetRootName->Length = (USHORT)((i - iNetRoot) * sizeof(WCHAR));
+    NetRootName->MaximumLength = NetRootName->Length;
+
+    Log(("VBOXSF: MRxExtractNetRootName: Srv = %.*ls, Root = %.*ls\n",
+         SrvCall->pSrvCallName->Length / sizeof(WCHAR), SrvCall->pSrvCallName->Buffer,
+         NetRootName->Length / sizeof(WCHAR), NetRootName->Buffer));
+
+    if (RestOfName)
+    {
+        RestOfName->Buffer = &FilePathName->Buffer[i];
+        RestOfName->Length = (USHORT)((cChars - i) * sizeof(WCHAR));
+        RestOfName->MaximumLength = RestOfName->Length;
+
+        Log(("VBOXSF: MRxExtractNetRootName: Rest = %.*ls\n",
+             RestOfName->Length / sizeof(WCHAR), RestOfName->Buffer));
+    }
+}
+
+static VOID vbsfExecuteCreateSrvCall(PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
+{
+    NTSTATUS Status;
+    PWCHAR pSrvName = 0;
+    BOOLEAN Verifier;
+
+    PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext;
+    PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure);
+    PMRX_SRV_CALL pSrvCall = SrvCalldownStructure->SrvCall;
+
+    /* Validate the server name with the test name of 'vboxsvr'. */
+    Log(("VBOXSF: vbsfExecuteCreateSrvCall: Connection Name %.*ls Length: %d, pSrvCall = %p\n",
+         pSrvCall->pSrvCallName->Length / sizeof(WCHAR), pSrvCall->pSrvCallName->Buffer, pSrvCall->pSrvCallName->Length, pSrvCall));
+
+    if (pSrvCall->pPrincipalName && pSrvCall->pPrincipalName->Length)
+    {
+        Log(("VBOXSF: vbsfExecuteCreateSrvCall: Principal name = %.*ls\n",
+             pSrvCall->pPrincipalName->Length / sizeof(WCHAR), pSrvCall->pPrincipalName->Buffer));
+    }
+
+    if (pSrvCall->pDomainName && pSrvCall->pDomainName->Length)
+    {
+        Log(("VBOXSF: vbsfExecuteCreateSrvCall: Domain name = %.*ls\n",
+             pSrvCall->pDomainName->Length / sizeof(WCHAR), pSrvCall->pDomainName->Buffer));
+    }
+
+    if (pSrvCall->pSrvCallName->Length >= 14)
+    {
+        pSrvName = pSrvCall->pSrvCallName->Buffer;
+
+        Verifier = (pSrvName[0] == L'\\');
+        Verifier &= (pSrvName[1] == L'V') || (pSrvName[1] == L'v');
+        Verifier &= (pSrvName[2] == L'B') || (pSrvName[2] == L'b');
+        Verifier &= (pSrvName[3] == L'O') || (pSrvName[3] == L'o');
+        Verifier &= (pSrvName[4] == L'X') || (pSrvName[4] == L'x');
+        Verifier &= (pSrvName[5] == L'S') || (pSrvName[5] == L's');
+        /* Both vboxsvr & vboxsrv are now accepted */
+        if ((pSrvName[6] == L'V') || (pSrvName[6] == L'v'))
+        {
+            Verifier &= (pSrvName[6] == L'V') || (pSrvName[6] == L'v');
+            Verifier &= (pSrvName[7] == L'R') || (pSrvName[7] == L'r');
+        }
+        else
+        {
+            Verifier &= (pSrvName[6] == L'R') || (pSrvName[6] == L'r');
+            Verifier &= (pSrvName[7] == L'V') || (pSrvName[7] == L'v');
+        }
+        Verifier &= (pSrvName[8] == L'\\') || (pSrvName[8] == 0);
+    }
+    else
+    {
+        Verifier = FALSE;
+    }
+
+    if (Verifier)
+    {
+        Log(("VBOXSF: vbsfExecuteCreateSrvCall: Verifier succeeded!\n"));
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        Log(("VBOXSF: vbsfExecuteCreateSrvCall: Verifier failed!\n"));
+        Status = STATUS_BAD_NETWORK_PATH;
+    }
+
+    SCCBC->Status = Status;
+    SrvCalldownStructure->CallBack(SCCBC);
+}
+
+NTSTATUS VBoxMRxCreateSrvCall(PMRX_SRV_CALL pSrvCall,
+                              PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
+{
+    PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
+
+    Log(("VBOXSF: MRxCreateSrvCall: %p.\n",
+         pSrvCall));
+
+    if (IoGetCurrentProcess() == RxGetRDBSSProcess())
+    {
+        Log(("VBOXSF: MRxCreateSrvCall: Called in context of RDBSS process\n"));
+
+        vbsfExecuteCreateSrvCall(pCallbackContext);
+    }
+    else
+    {
+        NTSTATUS Status;
+
+        Log(("VBOXSF: MRxCreateSrvCall: Dispatching to worker thread\n"));
+
+        Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue,
+                                          (PWORKER_THREAD_ROUTINE)vbsfExecuteCreateSrvCall,
+                                          pCallbackContext);
+
+        if (Status == STATUS_SUCCESS)
+        {
+            Log(("VBOXSF: MRxCreateSrvCall: queued\n"));
+        }
+        else
+        {
+            pCallbackContext->Status = Status;
+            SrvCalldownStructure->CallBack(pCallbackContext);
+        }
+    }
+
+    /* RDBSS expect this. */
+    return STATUS_PENDING;
+}
+
+NTSTATUS VBoxMRxFinalizeSrvCall (PMRX_SRV_CALL pSrvCall,
+                                 BOOLEAN Force)
+{
+    Log(("VBOXSF: MRxFinalizeSrvCall %p, ctx = %p.\n",
+         pSrvCall, pSrvCall->Context));
+
+    pSrvCall->Context = NULL;
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxSrvCallWinnerNotify(IN PMRX_SRV_CALL pSrvCall,
+                                    IN BOOLEAN ThisMinirdrIsTheWinner,
+                                    IN OUT PVOID pSrvCallContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    Log(("VBOXSF: MRxSrvCallWinnerNotify: pSrvCall %p, pSrvCall->Ctx %p, winner %d, context %p\n",
+         pSrvCall, pSrvCall->Context, ThisMinirdrIsTheWinner, pSrvCallContext));
+
+    /* Set it to not NULL. */
+    pSrvCall->Context = pSrvCall;
+
+    return STATUS_SUCCESS;
+}
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/path.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/path.c	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/path.c	(revision 40269)
@@ -0,0 +1,914 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver path related routines
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "vbsf.h"
+
+static UNICODE_STRING UnicodeBackslash = { 2, 4, L"\\" };
+
+static NTSTATUS vbsfProcessCreate(PRX_CONTEXT RxContext,
+                                  PUNICODE_STRING RemainingName,
+                                  FILE_BASIC_INFORMATION *pFileBasicInfo,
+                                  FILE_STANDARD_INFORMATION *pFileStandardInfo,
+                                  PVOID EaBuffer,
+                                  ULONG EaLength,
+                                  ULONG *pulCreateAction,
+                                  SHFLHANDLE *pHandle)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+
+    int vboxRC = VINF_SUCCESS;
+
+    /* Various boolean flags. */
+    struct
+    {
+        ULONG CreateDirectory :1;
+        ULONG OpenDirectory :1;
+        ULONG DirectoryFile :1;
+        ULONG NonDirectoryFile :1;
+        ULONG DeleteOnClose :1;
+        ULONG TemporaryFile :1;
+    } bf;
+
+    ACCESS_MASK DesiredAccess;
+    ULONG Options;
+    UCHAR FileAttributes;
+    ULONG ShareAccess;
+    ULONG CreateDisposition;
+    SHFLCREATEPARMS *pCreateParms = NULL;
+
+    if (EaLength)
+    {
+        Log(("VBOXSF: vbsfProcessCreate: Unsupported: extended attributes!\n"));
+        Status = STATUS_NOT_SUPPORTED;
+        goto failure;
+    }
+
+    if (BooleanFlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE))
+    {
+        Log(("VBOXSF: vbsfProcessCreate: Unsupported: paging file!\n"));
+        Status = STATUS_NOT_IMPLEMENTED;
+        goto failure;
+    }
+
+    Log(("VBOXSF: vbsfProcessCreate: FileAttributes = 0x%08x\n",
+         RxContext->Create.NtCreateParameters.FileAttributes));
+    Log(("VBOXSF: vbsfProcessCreate: CreateOptions = 0x%08x\n",
+         RxContext->Create.NtCreateParameters.CreateOptions));
+
+    RtlZeroMemory (&bf, sizeof (bf));
+
+    DesiredAccess = RxContext->Create.NtCreateParameters.DesiredAccess;
+    Options = RxContext->Create.NtCreateParameters.CreateOptions & FILE_VALID_OPTION_FLAGS;
+    FileAttributes = (UCHAR)(RxContext->Create.NtCreateParameters.FileAttributes & ~FILE_ATTRIBUTE_NORMAL);
+    ShareAccess = RxContext->Create.NtCreateParameters.ShareAccess;
+
+    /* We do not support opens by file ids. */
+    if (FlagOn(Options, FILE_OPEN_BY_FILE_ID))
+    {
+        Log(("VBOXSF: vbsfProcessCreate: Unsupported: file open by id!\n"));
+        Status = STATUS_NOT_IMPLEMENTED;
+        goto failure;
+    }
+
+    /* Mask out unsupported attribute bits. */
+    FileAttributes &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE);
+
+    bf.DirectoryFile = BooleanFlagOn(Options, FILE_DIRECTORY_FILE);
+    bf.NonDirectoryFile = BooleanFlagOn(Options, FILE_NON_DIRECTORY_FILE);
+    bf.DeleteOnClose = BooleanFlagOn(Options, FILE_DELETE_ON_CLOSE);
+    if (bf.DeleteOnClose)
+        Log(("VBOXSF: vbsfProcessCreate: Delete on close!\n"));
+
+    CreateDisposition = RxContext->Create.NtCreateParameters.Disposition;
+
+    bf.CreateDirectory = (BOOLEAN)(bf.DirectoryFile && ((CreateDisposition == FILE_CREATE) || (CreateDisposition == FILE_OPEN_IF)));
+    bf.OpenDirectory = (BOOLEAN)(bf.DirectoryFile && ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OPEN_IF)));
+    bf.TemporaryFile = BooleanFlagOn(RxContext->Create.NtCreateParameters.FileAttributes, FILE_ATTRIBUTE_TEMPORARY);
+
+    if (FlagOn(capFcb->FcbState, FCB_STATE_TEMPORARY))
+        bf.TemporaryFile = TRUE;
+
+    Log(("VBOXSF: vbsfProcessCreate: bf.TemporaryFile %d, bf.CreateDirectory %d, bf.DirectoryFile = %d\n",
+         (ULONG)bf.TemporaryFile, (ULONG)bf.CreateDirectory, (ULONG)bf.DirectoryFile));
+
+    /* Check consistency in specified flags. */
+    if (bf.TemporaryFile && bf.CreateDirectory) /* Directories with temporary flag set are not allowed! */
+    {
+        Log(("VBOXSF: vbsfProcessCreate: Not allowed: Temporary directories!\n"));
+        Status = STATUS_INVALID_PARAMETER;
+        goto failure;
+    }
+
+    if (bf.DirectoryFile && bf.NonDirectoryFile)
+    {
+        Log(("VBOXSF: vbsfProcessCreate: Unsupported combination: dir && !dir\n"));
+        Status = STATUS_INVALID_PARAMETER;
+        goto failure;
+    }
+
+    /* Initialize create parameters. */
+    pCreateParms = (SHFLCREATEPARMS *)vbsfAllocNonPagedMem(sizeof(SHFLCREATEPARMS));
+    if (!pCreateParms)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto failure;
+    }
+
+    RtlZeroMemory(pCreateParms, sizeof (SHFLCREATEPARMS));
+
+    pCreateParms->Handle = SHFL_HANDLE_NIL;
+    pCreateParms->Result = SHFL_NO_RESULT;
+
+    if (bf.DirectoryFile)
+    {
+        if (CreateDisposition != FILE_CREATE && CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF)
+        {
+            Log(("VBOXSF: vbsfProcessCreate: Invalid disposition 0x%08X for directory!\n",
+                 CreateDisposition));
+            Status = STATUS_INVALID_PARAMETER;
+            goto failure;
+        }
+
+        pCreateParms->CreateFlags |= SHFL_CF_DIRECTORY;
+    }
+
+    Log(("VBOXSF: vbsfProcessCreate: CreateDisposition = 0x%08X\n",
+         CreateDisposition));
+
+    switch (CreateDisposition)
+    {
+        case FILE_SUPERSEDE:
+            pCreateParms->CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
+            Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
+            break;
+
+        case FILE_OPEN:
+            pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
+            Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n"));
+            break;
+
+        case FILE_CREATE:
+            pCreateParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
+            Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
+            break;
+
+        case FILE_OPEN_IF:
+            pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
+            Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
+            break;
+
+        case FILE_OVERWRITE:
+            pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
+            Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n"));
+            break;
+
+        case FILE_OVERWRITE_IF:
+            pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
+            Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
+            break;
+
+        default:
+            Log(("VBOXSF: vbsfProcessCreate: Unexpected create disposition: 0x%08X\n",
+                 CreateDisposition));
+            Status = STATUS_INVALID_PARAMETER;
+            goto failure;
+    }
+
+    Log(("VBOXSF: vbsfProcessCreate: DesiredAccess = 0x%08X\n",
+         DesiredAccess));
+    Log(("VBOXSF: vbsfProcessCreate: ShareAccess   = 0x%08X\n",
+         ShareAccess));
+
+    if (DesiredAccess & FILE_READ_DATA)
+    {
+        Log(("VBOXSF: vbsfProcessCreate: FILE_READ_DATA\n"));
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_READ;
+    }
+
+    if (DesiredAccess & FILE_WRITE_DATA)
+    {
+        Log(("VBOXSF: vbsfProcessCreate: FILE_WRITE_DATA\n"));
+        /* FILE_WRITE_DATA means write access regardless of FILE_APPEND_DATA bit.
+         */
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE;
+    }
+    else if (DesiredAccess & FILE_APPEND_DATA)
+    {
+        Log(("VBOXSF: vbsfProcessCreate: FILE_APPEND_DATA\n"));
+        /* FILE_APPEND_DATA without FILE_WRITE_DATA means append only mode.
+         *
+         * Both write and append access flags are required for shared folders,
+         * as on Windows FILE_APPEND_DATA implies write access.
+         */
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE | SHFL_CF_ACCESS_APPEND;
+    }
+
+    if (DesiredAccess & FILE_READ_ATTRIBUTES)
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_READ;
+    if (DesiredAccess & FILE_WRITE_ATTRIBUTES)
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_WRITE;
+
+    if (ShareAccess & (FILE_SHARE_READ | FILE_SHARE_WRITE))
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYNONE;
+    else if (ShareAccess & FILE_SHARE_READ)
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYWRITE;
+    else if (ShareAccess & FILE_SHARE_WRITE)
+        pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYREAD;
+    else pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYALL;
+
+    /* Set initial allocation size. */
+    pCreateParms->Info.cbObject = RxContext->Create.NtCreateParameters.AllocationSize.QuadPart;
+
+    if (FileAttributes == 0)
+        FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+    pCreateParms->Info.Attr.fMode = NTToVBoxFileAttributes(FileAttributes);
+
+    {
+        PSHFLSTRING ParsedPath;
+        ULONG ParsedPathSize;
+
+        /* Calculate length required for parsed path.
+         */
+        ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR));
+
+        Log(("VBOXSF: vbsfProcessCreate: ParsedPathSize = %d\n",
+             ParsedPathSize));
+
+        ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+        if (ParsedPath == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto failure;
+        }
+
+        ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+        ParsedPath->u16Size = RemainingName->Length + sizeof(WCHAR);
+        ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */
+        RtlCopyMemory (ParsedPath->String.ucs2, RemainingName->Buffer, ParsedPath->u16Length);
+        Log(("VBOXSF: ParsedPath: %.*ls\n",
+             ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
+
+        /* Call host. */
+        Log(("VBOXSF: vbsfProcessCreate: vboxCallCreate called.\n"));
+        vboxRC = vboxCallCreate(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, pCreateParms);
+
+        vbsfFreeNonPagedMem(ParsedPath);
+    }
+
+    Log(("VBOXSF: vbsfProcessCreate: vboxCallCreate returns vboxRC = %Rrc, Result = 0x%x\n",
+         vboxRC, pCreateParms->Result));
+
+    if (RT_FAILURE(vboxRC))
+    {
+        /* Map some VBoxRC to STATUS codes expected by the system. */
+        switch (vboxRC)
+        {
+            case VERR_ALREADY_EXISTS:
+            {
+                *pulCreateAction = FILE_EXISTS;
+                Status = STATUS_OBJECT_NAME_COLLISION;
+                goto failure;
+            } break;
+
+            /* On POSIX systems, the "mkdir" command returns VERR_FILE_NOT_FOUND when
+               doing a recursive directory create. Handle this case. */
+            case VERR_FILE_NOT_FOUND:
+            {
+                pCreateParms->Result = SHFL_PATH_NOT_FOUND;
+            } break;
+
+            default:
+            {
+                *pulCreateAction = FILE_DOES_NOT_EXIST;
+                Status = VBoxErrorToNTStatus(vboxRC);
+                goto failure;
+            } break;
+        }
+    }
+
+    /*
+     * The request succeeded. Analyze host response,
+     */
+    switch (pCreateParms->Result)
+    {
+        case SHFL_PATH_NOT_FOUND:
+        {
+            /* Path to object does not exist. */
+            Log(("VBOXSF: vbsfProcessCreate: Path not found\n"));
+            *pulCreateAction = FILE_DOES_NOT_EXIST;
+            Status = STATUS_OBJECT_PATH_NOT_FOUND;
+            goto failure;
+        }
+
+        case SHFL_FILE_NOT_FOUND:
+        {
+            Log(("VBOXSF: vbsfProcessCreate: File not found\n"));
+            *pulCreateAction = FILE_DOES_NOT_EXIST;
+            if (pCreateParms->Handle == SHFL_HANDLE_NIL)
+            {
+                Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                goto failure;
+            }
+
+            Log(("VBOXSF: vbsfProcessCreate: File not found but have a handle!\n"));
+            Status = STATUS_UNSUCCESSFUL;
+            goto failure;
+
+            break;
+        }
+
+        case SHFL_FILE_EXISTS:
+        {
+            Log(("VBOXSF: vbsfProcessCreate: File exists, Handle = 0x%RX64\n",
+                 pCreateParms->Handle));
+            if (pCreateParms->Handle == SHFL_HANDLE_NIL)
+            {
+                *pulCreateAction = FILE_EXISTS;
+                if (CreateDisposition == FILE_CREATE)
+                {
+                    /* File was not opened because we requested a create. */
+                    Status = STATUS_OBJECT_NAME_COLLISION;
+                    goto failure;
+                }
+
+                /* Actually we should not go here, unless we have no rights to open the object. */
+                Log(("VBOXSF: vbsfProcessCreate: Existing file was not opened!\n"));
+                Status = STATUS_ACCESS_DENIED;
+                goto failure;
+            }
+
+            *pulCreateAction = FILE_OPENED;
+
+            /* Existing file was opened. Go check flags and create FCB. */
+            break;
+        }
+
+        case SHFL_FILE_CREATED:
+        {
+            /* A new file was created. */
+
+            Assert(pCreateParms->Handle != SHFL_HANDLE_NIL);
+
+            *pulCreateAction = FILE_CREATED;
+
+            /* Go check flags and create FCB. */
+            break;
+        }
+
+        case SHFL_FILE_REPLACED:
+        {
+            /* Existing file was replaced or overwriting. */
+
+            Assert(pCreateParms->Handle != SHFL_HANDLE_NIL);
+
+            if (CreateDisposition == FILE_SUPERSEDE)
+            {
+                *pulCreateAction = FILE_SUPERSEDED;
+            }
+            else
+            {
+                *pulCreateAction = FILE_OVERWRITTEN;
+            }
+            /* Go check flags and create FCB. */
+            break;
+        }
+
+        default:
+        {
+            Log(("VBOXSF: vbsfProcessCreate: Invalid CreateResult from host (0x%08X)\n",
+                 pCreateParms->Result));
+            *pulCreateAction = FILE_DOES_NOT_EXIST;
+            Status = STATUS_OBJECT_PATH_NOT_FOUND;
+            goto failure;
+        }
+    }
+
+    /* Check flags. */
+    if (bf.NonDirectoryFile && FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY))
+    {
+        /* Caller wanted only a file, but the object is a directory. */
+        Log(("VBOXSF: vbsfProcessCreate: File is a directory!\n"));
+        Status = STATUS_FILE_IS_A_DIRECTORY;
+        goto failure;
+    }
+
+    if (bf.DirectoryFile && !FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY))
+    {
+        /* Caller wanted only a directory, but the object is not a directory. */
+        Log(("VBOXSF: vbsfProcessCreate: File is not a directory!\n"));
+        Status = STATUS_NOT_A_DIRECTORY;
+        goto failure;
+    }
+
+    *pHandle = pCreateParms->Handle;
+
+    /* Translate attributes */
+    pFileBasicInfo->FileAttributes = VBoxToNTFileAttributes(pCreateParms->Info.Attr.fMode);
+
+    /* Translate file times */
+    pFileBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.BirthTime); /* ridiculous name */
+    pFileBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.AccessTime);
+    pFileBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.ModificationTime);
+    pFileBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.ChangeTime);
+
+    if (!FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY))
+    {
+        pFileStandardInfo->AllocationSize.QuadPart = pCreateParms->Info.cbAllocated;
+        pFileStandardInfo->EndOfFile.QuadPart = pCreateParms->Info.cbObject;
+        pFileStandardInfo->Directory = FALSE;
+
+        Log(("VBOXSF: vbsfProcessCreate: AllocationSize = 0x%RX64, EndOfFile = 0x%RX64\n",
+             pCreateParms->Info.cbAllocated, pCreateParms->Info.cbObject));
+    }
+    else
+    {
+        pFileStandardInfo->AllocationSize.QuadPart = 0;
+        pFileStandardInfo->EndOfFile.QuadPart = 0;
+        pFileStandardInfo->Directory = TRUE;
+    }
+    pFileStandardInfo->NumberOfLinks = 0;
+    pFileStandardInfo->DeletePending = FALSE;
+
+    vbsfFreeNonPagedMem(pCreateParms);
+
+    return Status;
+
+failure:
+
+    Log(("VBOXSF: vbsfProcessCreate: Returned with status = 0x%08X\n",
+          Status));
+
+    if (pCreateParms && pCreateParms->Handle != SHFL_HANDLE_NIL)
+    {
+        vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pCreateParms->Handle);
+        *pHandle = SHFL_HANDLE_NIL;
+    }
+
+    if (pCreateParms)
+    {
+        vbsfFreeNonPagedMem(pCreateParms);
+    }
+
+    return Status;
+}
+
+NTSTATUS VBoxMRxCreate(IN OUT PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
+    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+
+    FILE_BASIC_INFORMATION FileBasicInfo;
+    FILE_STANDARD_INFORMATION FileStandardInfo;
+
+    ULONG CreateAction = FILE_CREATED;
+    SHFLHANDLE Handle = SHFL_HANDLE_NIL;
+    PMRX_VBOX_FOBX pVBoxFobx;
+
+    Log(("VBOXSF: MRxCreate: name ptr %p length=%d\n",
+         RemainingName, RemainingName->Length));
+
+    if (RemainingName->Length)
+    {
+        Log(("VBOXSF: MRxCreate: Attempt to open %.*ls\n",
+             RemainingName->Length/sizeof(WCHAR), RemainingName->Buffer));
+    }
+    else
+    {
+        if (FlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
+        {
+            Log(("VBOXSF: MRxCreate: Empty name -> Only backslash used\n"));
+            RemainingName = &UnicodeBackslash;
+        }
+    }
+
+    if (   pNetRoot->Type != NET_ROOT_WILD
+        && pNetRoot->Type != NET_ROOT_DISK)
+    {
+        Log(("VBOXSF: MRxCreate: netroot type %d not supported\n",
+             pNetRoot->Type));
+        Status = STATUS_NOT_IMPLEMENTED;
+        goto Exit;
+    }
+
+    FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+    Status = vbsfProcessCreate(RxContext,
+                               RemainingName,
+                               &FileBasicInfo,
+                               &FileStandardInfo,
+                               RxContext->Create.EaBuffer,
+                               RxContext->Create.EaLength,
+                               &CreateAction,
+                               &Handle);
+
+    if (Status != STATUS_SUCCESS)
+    {
+        Log(("VBOXSF: MRxCreate: vbsfProcessCreate failed 0x%08X\n",
+             Status));
+        goto Exit;
+    }
+
+    Log(("VBOXSF: MRxCreate: EOF is 0x%RX64 AllocSize is 0x%RX64\n",
+         FileStandardInfo.EndOfFile.QuadPart, FileStandardInfo.AllocationSize.QuadPart));
+
+    RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
+    if (RxContext->pFobx == NULL)
+    {
+        Log(("VBOXSF: MRxCreate: RxCreateNetFobx failed\n"));
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Exit;
+    }
+
+    Log(("VBOXSF: MRxCreate: CreateAction = 0x%08X\n",
+         CreateAction));
+
+    RxContext->Create.ReturnedCreateInformation = CreateAction;
+
+    if (capFcb->OpenCount == 0)
+    {
+        FCB_INIT_PACKET InitPacket;
+        RxFormInitPacket(InitPacket,
+                         &FileBasicInfo.FileAttributes,
+                         &FileStandardInfo.NumberOfLinks,
+                         &FileBasicInfo.CreationTime,
+                         &FileBasicInfo.LastAccessTime,
+                         &FileBasicInfo.LastWriteTime,
+                         &FileBasicInfo.ChangeTime,
+                         &FileStandardInfo.AllocationSize,
+                         &FileStandardInfo.EndOfFile,
+                         &FileStandardInfo.EndOfFile);
+        RxFinishFcbInitialization(capFcb, RDBSS_STORAGE_NTC(FileTypeFile), &InitPacket);
+    }
+
+    SrvOpen->BufferingFlags = 0;
+
+    RxContext->pFobx->OffsetOfNextEaToReturn = 1;
+
+    pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+
+    Log(("VBOXSF: MRxCreate: VBoxFobx = %p\n",
+         pVBoxFobx));
+
+    if (!pVBoxFobx)
+    {
+        Log(("VBOXSF: MRxCreate: no VBoxFobx!\n"));
+        AssertFailed();
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Exit;
+    }
+
+    pVBoxFobx->hFile = Handle;
+    pVBoxFobx->pSrvCall = RxContext->Create.pSrvCall;
+    pVBoxFobx->FileStandardInfo = FileStandardInfo;
+    pVBoxFobx->FileBasicInfo = FileBasicInfo;
+    pVBoxFobx->fKeepCreationTime = FALSE;
+    pVBoxFobx->fKeepLastAccessTime = FALSE;
+    pVBoxFobx->fKeepLastWriteTime = FALSE;
+    pVBoxFobx->fKeepChangeTime = FALSE;
+
+    if (!RxIsFcbAcquiredExclusive(capFcb))
+    {
+        RxAcquireExclusiveFcbResourceInMRx(capFcb);
+    }
+
+    Log(("VBOXSF: MRxCreate: NetRoot is %p, Fcb is %p, SrvOpen is %p, Fobx is %p\n",
+         pNetRoot, capFcb, SrvOpen, RxContext->pFobx));
+    Log(("VBOXSF: MRxCreate: return 0x%08X\n",
+         Status));
+
+Exit:
+    return Status;
+}
+
+NTSTATUS VBoxMRxComputeNewBufferingState(IN OUT PMRX_SRV_OPEN pMRxSrvOpen,
+                                         IN PVOID pMRxContext,
+                                         OUT PULONG pNewBufferingState)
+{
+    Log(("VBOXSF: MRxComputeNewBufferingState\n"));
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS VBoxMRxDeallocateForFcb(IN OUT PMRX_FCB pFcb)
+{
+    Log(("VBOXSF: MRxDeallocateForFcb\n"));
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxDeallocateForFobx(IN OUT PMRX_FOBX pFobx)
+{
+    Log(("VBOXSF: MRxDeallocateForFobx\n"));
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxTruncate(IN PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxTruncate\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxCleanupFobx(IN PRX_CONTEXT RxContext)
+{
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+
+    Log(("VBOXSF: MRxCleanupFobx: pVBoxFobx = %p, Handle = 0x%RX64\n",
+          pVBoxFobx, pVBoxFobx? pVBoxFobx->hFile: 0));
+
+    if (NULL == pVBoxFobx)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxForceClosed(IN PMRX_SRV_OPEN pSrvOpen)
+{
+    Log(("VBOXSF: MRxForceClosed\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxCloseSrvOpen(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+    PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
+
+    int vboxRC = 0;
+    PUNICODE_STRING RemainingName = NULL;
+
+    Log(("VBOXSF: MRxCloseSrvOpen: capFcb = %p, capFobx = %p, pVBoxFobx = %p, pSrvOpen = %p\n",
+          capFcb, capFobx, pVBoxFobx, pSrvOpen));
+
+    RemainingName = pSrvOpen->pAlreadyPrefixedName;
+
+    Log(("VBOXSF: MRxCloseSrvOpen: Remaining name = %.*ls, Len = %d\n",
+         RemainingName->Length / sizeof(WCHAR), RemainingName->Buffer, RemainingName->Length));
+
+    if (NULL == pVBoxFobx)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (FlagOn(pSrvOpen->Flags, (SRVOPEN_FLAG_FILE_RENAMED | SRVOPEN_FLAG_FILE_DELETED)))
+    {
+        /* If we renamed or delete the file/dir, then it's already closed */
+        Assert(pVBoxFobx->hFile == SHFL_HANDLE_NIL);
+        Log(("VBOXSF: MRxCloseSrvOpen: File was renamed, handle 0x%RX64 ignore close.\n",
+             pVBoxFobx->hFile));
+        return STATUS_SUCCESS;
+    }
+
+    /* Close file */
+    if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
+    {
+        vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+        pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+    }
+
+    if (capFcb->FcbState & FCB_STATE_DELETE_ON_CLOSE)
+    {
+        Log(("VBOXSF: MRxCloseSrvOpen: Delete on close. Open count = %d\n",
+             capFcb->OpenCount));
+
+        /* Remove file or directory if delete action is pending. */
+        if (capFcb->OpenCount == 0)
+        {
+            Status = vbsfRemove(RxContext);
+        }
+    }
+
+    return Status;
+}
+
+NTSTATUS vbsfRemove(IN PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+
+    int vboxRC;
+    PSHFLSTRING ParsedPath = NULL;
+    ULONG ParsedPathSize;
+
+    Log(("VBOXSF: vbsfRemove: Delete %.*ls. open count = %d\n",
+         RemainingName->Length / sizeof(WCHAR), RemainingName->Buffer, capFcb->OpenCount));
+
+    /* Close file first if not already done. */
+    if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
+    {
+        vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+        pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+    }
+
+    /* Calculate length required for parsed path.
+     */
+    ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR));
+
+    Log(("VBOXSF: vbsfRemove: ParsedPathSize %d\n",
+         ParsedPathSize));
+
+    ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+    if (!ParsedPath)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+    Log(("VBOXSF: vbsfRemove: Setup ParsedPath\n"));
+    ParsedPath->u16Size = RemainingName->Length + sizeof(WCHAR);
+    ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */
+    RtlCopyMemory(ParsedPath->String.ucs2, RemainingName->Buffer, ParsedPath->u16Length);
+
+    /* Call host. */
+    vboxRC = vboxCallRemove(&pDeviceExtension->hgcmClient, &pNetRootExtension->map,
+                            ParsedPath,
+                            (pVBoxFobx->FileStandardInfo.Directory) ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE);
+
+    if (ParsedPath)
+    {
+        vbsfFreeNonPagedMem(ParsedPath);
+    }
+
+    if (vboxRC == VINF_SUCCESS)
+    {
+        SetFlag(capFobx->pSrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED);
+    }
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+    if (vboxRC != VINF_SUCCESS)
+    {
+        Log(("VBOXSF: vbsfRemove: vboxCallRemove failed with %Rrc\n",
+             vboxRC));
+    }
+
+    Log(("VBOXSF: vbsfRemove: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS vbsfRename(IN PRX_CONTEXT RxContext,
+                       IN FILE_INFORMATION_CLASS FileInformationClass,
+                       IN PVOID pBuffer,
+                       IN ULONG BufferLength)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    RxCaptureFcb;
+    RxCaptureFobx;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
+    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+    PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
+
+    PFILE_RENAME_INFORMATION RenameInformation = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
+    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(pSrvOpen, capFcb);
+
+    int vboxRC;
+    PSHFLSTRING SrcPath = 0, DestPath = 0;
+    ULONG ParsedPathSize, flags;
+
+    Assert(FileInformationClass == FileRenameInformation);
+
+    Log(("VBOXSF: vbsfRename: FileName = %.*ls\n",
+         RenameInformation->FileNameLength / sizeof(WCHAR), &RenameInformation->FileName[0]));
+
+    /* Must close the file before renaming it! */
+    if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
+    {
+        vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+        pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+    }
+
+    /* Mark it as renamed, so we do nothing during close */
+    SetFlag(pSrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED);
+
+    /* Calculate length required for destination path. */
+    ParsedPathSize = sizeof(*DestPath) + (RenameInformation->FileNameLength + sizeof(WCHAR));
+
+    Log(("VBOXSF: vbsfRename: ParsedPathSize = %d\n",
+         ParsedPathSize));
+
+    DestPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+
+    if (NULL == DestPath)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(DestPath, ParsedPathSize);
+    ShflStringInitBuffer(DestPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+    Log(("VBOXSF: vbsfRename: Setting up destination path\n"));
+
+    DestPath->u16Size = (USHORT)(RenameInformation->FileNameLength + sizeof(WCHAR));
+    DestPath->u16Length = DestPath->u16Size - sizeof(WCHAR); /* without terminating null */
+    RtlCopyMemory(DestPath->String.ucs2, RenameInformation->FileName, DestPath->u16Length);
+
+    Log(("VBOXSF: vbsfRename: Destination path = %.*ls\n",
+         DestPath->u16Length / sizeof(WCHAR), &DestPath->String.ucs2[0]));
+
+    /* Calculate length required for source path */
+    ParsedPathSize = sizeof(*DestPath) + (RemainingName->Length + sizeof(WCHAR));
+
+    Log(("VBOXSF: vbsfRename: ParsedPathSize = %d\n", ParsedPathSize));
+
+    SrcPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+
+    if (NULL == SrcPath)
+    {
+        vbsfFreeNonPagedMem(DestPath);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(SrcPath, ParsedPathSize);
+    ShflStringInitBuffer(SrcPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+    Log(("VBOXSF: vbsfRename: Setting up source path\n"));
+
+    SrcPath->u16Size = RemainingName->Length + sizeof(WCHAR);
+    SrcPath->u16Length = SrcPath->u16Size - sizeof(WCHAR); /* without terminating null */
+    RtlCopyMemory(SrcPath->String.ucs2, RemainingName->Buffer, SrcPath->u16Length);
+
+    Log(("VBOXSF: vbsfRename: Source path = %.*ls\n",
+         SrcPath->u16Length / sizeof(WCHAR), &SrcPath->String.ucs2[0]));
+
+    /* Call host. */
+    flags = pVBoxFobx->FileStandardInfo.Directory? SHFL_RENAME_DIR : SHFL_RENAME_FILE;
+    if (RenameInformation->ReplaceIfExists)
+    {
+        flags |= SHFL_RENAME_REPLACE_IF_EXISTS;
+    }
+
+    Log(("VBOXSF: vbsfRename: Calling vboxCallRename\n"));
+    vboxRC = vboxCallRename(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, SrcPath, DestPath, flags);
+
+    vbsfFreeNonPagedMem(SrcPath);
+    vbsfFreeNonPagedMem(DestPath);
+
+    Status = VBoxErrorToNTStatus(vboxRC);
+    if (vboxRC != VINF_SUCCESS)
+    {
+        Log(("VBOXSF: vbsfRename: vboxCallRename failed with %Rrc\n",
+             vboxRC));
+    }
+
+    Log(("VBOXSF: vbsfRename: Returned 0x%08X\n",
+         Status));
+    return Status;
+}
+
+NTSTATUS VBoxMRxShouldTryToCollapseThisOpen(IN PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxShouldTryToCollapseThisOpen\n"));
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS VBoxMRxCollapseOpen(IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxCollapseOpen\n"));
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vboxsf.ini
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vboxsf.ini	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vboxsf.ini	(revision 40269)
@@ -0,0 +1,16 @@
+\registry\machine\system\currentcontrolset\services\VBoxSF
+    Description = VBoxSF
+    DisplayName = VBoxSF
+    ErrorControl = REG_DWORD 0x00000001
+    Group = Network
+    ImagePath = System32\DRIVERS\VBoxSF.sys
+    LastLoadStatus = REG_DWORD 0
+    Start = REG_DWORD 0x00000001
+    Type = REG_DWORD 0x00000002
+
+\registry\machine\system\currentcontrolset\services\VBoxSF\NetworkProvider
+    DeviceName = \Device\VBoxMiniRdr
+    Name = VirtualBox Shared Folders
+    ProviderPath = System32\VBoxMRXNP.dll
+
+
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.c	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.c	(revision 40269)
@@ -0,0 +1,1385 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver initialization and generic routines
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "vbsf.h"
+
+/*
+ * The current state of the driver.
+ */
+typedef enum _MRX_VBOX_STATE_
+{
+    MRX_VBOX_STARTABLE,
+    MRX_VBOX_START_IN_PROGRESS,
+    MRX_VBOX_STARTED
+} MRX_VBOX_STATE, *PMRX_VBOX_STATE;
+
+static MRX_VBOX_STATE VBoxMRxState = MRX_VBOX_STARTABLE;
+
+/*
+ * The VBoxSF dispatch table.
+ */
+static struct _MINIRDR_DISPATCH VBoxMRxDispatch;
+
+/*
+ * The VBoxSF device object.
+ */
+PRDBSS_DEVICE_OBJECT VBoxMRxDeviceObject;
+
+static NTSTATUS VBoxMRxFsdDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+    UCHAR MajorFunctionCode = IrpSp->MajorFunction;
+    ULONG MinorFunctionCode = IrpSp->MinorFunction;
+
+    Log(("VBOXSF: MRxFsdDispatch: major %d, minor %d: %s\n",
+         MajorFunctionCode, MinorFunctionCode, MajorFunctionString(MajorFunctionCode, MinorFunctionCode)));
+
+    if (DeviceObject != (PDEVICE_OBJECT)VBoxMRxDeviceObject)
+    {
+        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        Log(("VBOXSF: MRxFsdDispatch: Invalid device request detected %p %p\n",
+             DeviceObject, (PDEVICE_OBJECT)VBoxMRxDeviceObject));
+
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    Status = RxFsdDispatch((PRDBSS_DEVICE_OBJECT)VBoxMRxDeviceObject, Irp);
+
+    Log(("VBOXSF: MRxFsdDispatch: Returned 0x%X\n",
+         Status));
+    return Status;
+}
+
+static void VBoxMRxUnload(IN PDRIVER_OBJECT DriverObject)
+{
+    NTSTATUS Status;
+    UNICODE_STRING UserModeDeviceName;
+
+    Log(("VBOXSF: MRxUnload\n"));
+
+    if (VBoxMRxDeviceObject)
+    {
+        PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension;
+        pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)VBoxMRxDeviceObject + sizeof(RDBSS_DEVICE_OBJECT));
+        vboxDisconnect (&pDeviceExtension->hgcmClient);
+    }
+
+    vboxUninit();
+
+    if (VBoxMRxDeviceObject)
+    {
+        PRX_CONTEXT RxContext;
+        RxContext = RxCreateRxContext(NULL, VBoxMRxDeviceObject, RX_CONTEXT_FLAG_IN_FSP);
+
+        if (RxContext != NULL)
+        {
+            Status = RxStopMinirdr(RxContext, &RxContext->PostRequest);
+
+            if (Status == STATUS_SUCCESS)
+            {
+                MRX_VBOX_STATE State;
+
+                State = (MRX_VBOX_STATE)InterlockedCompareExchange((LONG *)&VBoxMRxState, MRX_VBOX_STARTABLE, MRX_VBOX_STARTED);
+
+                if (State != MRX_VBOX_STARTABLE)
+                {
+                    Status = STATUS_REDIRECTOR_STARTED;
+                }
+            }
+
+            RxDereferenceAndDeleteRxContext(RxContext);
+        }
+        else
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RxUnregisterMinirdr(VBoxMRxDeviceObject);
+    }
+
+    RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U);
+    Status = IoDeleteSymbolicLink(&UserModeDeviceName);
+    if (Status != STATUS_SUCCESS)
+    {
+        Log(("VBOXSF: MRxUnload: IoDeleteSymbolicLink Status 0x%08X\n",
+             Status));
+    }
+
+    RxUnload(DriverObject);
+
+    Log(("VBOXSF: MRxUnload: VBoxSF.sys driver object %p unloaded\n",
+         DriverObject));
+}
+
+static void vbsfInitMRxDispatch(void)
+{
+    Log(("VBOXSF: vbsfInitMRxDispatch: Called.\n"));
+
+    ZeroAndInitializeNodeType(&VBoxMRxDispatch, RDBSS_NTC_MINIRDR_DISPATCH, sizeof(MINIRDR_DISPATCH));
+
+    VBoxMRxDispatch.MRxFlags = (RDBSS_MANAGE_NET_ROOT_EXTENSION | RDBSS_MANAGE_FOBX_EXTENSION);
+
+    VBoxMRxDispatch.MRxSrvCallSize = 0;
+    VBoxMRxDispatch.MRxNetRootSize = sizeof(MRX_VBOX_NETROOT_EXTENSION);
+    VBoxMRxDispatch.MRxVNetRootSize = 0;
+    VBoxMRxDispatch.MRxFcbSize = 0;
+    VBoxMRxDispatch.MRxSrvOpenSize = 0;
+    VBoxMRxDispatch.MRxFobxSize = sizeof(MRX_VBOX_FOBX);
+
+    VBoxMRxDispatch.MRxStart = VBoxMRxStart;
+    VBoxMRxDispatch.MRxStop = VBoxMRxStop;
+
+    VBoxMRxDispatch.MRxCreate = VBoxMRxCreate;
+    VBoxMRxDispatch.MRxCollapseOpen = VBoxMRxCollapseOpen;
+    VBoxMRxDispatch.MRxShouldTryToCollapseThisOpen = VBoxMRxShouldTryToCollapseThisOpen;
+    VBoxMRxDispatch.MRxFlush = VBoxMRxFlush;
+    VBoxMRxDispatch.MRxTruncate = VBoxMRxTruncate;
+    VBoxMRxDispatch.MRxCleanupFobx = VBoxMRxCleanupFobx;
+    VBoxMRxDispatch.MRxCloseSrvOpen = VBoxMRxCloseSrvOpen;
+    VBoxMRxDispatch.MRxDeallocateForFcb = VBoxMRxDeallocateForFcb;
+    VBoxMRxDispatch.MRxDeallocateForFobx = VBoxMRxDeallocateForFobx;
+    VBoxMRxDispatch.MRxForceClosed = VBoxMRxForceClosed;
+
+    VBoxMRxDispatch.MRxQueryDirectory = VBoxMRxQueryDirectory;
+    VBoxMRxDispatch.MRxQueryFileInfo = VBoxMRxQueryFileInfo;
+    VBoxMRxDispatch.MRxSetFileInfo = VBoxMRxSetFileInfo;
+    VBoxMRxDispatch.MRxSetFileInfoAtCleanup = VBoxMRxSetFileInfoAtCleanup;
+    VBoxMRxDispatch.MRxQueryEaInfo = VBoxMRxQueryEaInfo;
+    VBoxMRxDispatch.MRxSetEaInfo = VBoxMRxSetEaInfo;
+    VBoxMRxDispatch.MRxQuerySdInfo = VBoxMRxQuerySdInfo;
+    VBoxMRxDispatch.MRxSetSdInfo = VBoxMRxSetSdInfo;
+    VBoxMRxDispatch.MRxQueryVolumeInfo = VBoxMRxQueryVolumeInfo;
+
+    VBoxMRxDispatch.MRxComputeNewBufferingState = VBoxMRxComputeNewBufferingState;
+
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_READ] = VBoxMRxRead;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_WRITE] = VBoxMRxWrite;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK] = VBoxMRxLocks;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK] = VBoxMRxLocks;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK] = VBoxMRxLocks;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = VBoxMRxLocks;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_FSCTL] = VBoxMRxFsCtl;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_IOCTL] = VBoxMRxIoCtl;
+    VBoxMRxDispatch.MRxLowIOSubmit[LOWIO_OP_NOTIFY_CHANGE_DIRECTORY] = VBoxMRxNotifyChangeDirectory;
+
+    VBoxMRxDispatch.MRxExtendForCache = VBoxMRxExtendStub;
+    VBoxMRxDispatch.MRxExtendForNonCache = VBoxMRxExtendStub;
+    VBoxMRxDispatch.MRxCompleteBufferingStateChangeRequest = VBoxMRxCompleteBufferingStateChangeRequest;
+
+    VBoxMRxDispatch.MRxCreateVNetRoot = VBoxMRxCreateVNetRoot;
+    VBoxMRxDispatch.MRxFinalizeVNetRoot = VBoxMRxFinalizeVNetRoot;
+    VBoxMRxDispatch.MRxFinalizeNetRoot = VBoxMRxFinalizeNetRoot;
+    VBoxMRxDispatch.MRxUpdateNetRootState = VBoxMRxUpdateNetRootState;
+    VBoxMRxDispatch.MRxExtractNetRootName = VBoxMRxExtractNetRootName;
+
+    VBoxMRxDispatch.MRxCreateSrvCall = VBoxMRxCreateSrvCall;
+    VBoxMRxDispatch.MRxSrvCallWinnerNotify = VBoxMRxSrvCallWinnerNotify;
+    VBoxMRxDispatch.MRxFinalizeSrvCall = VBoxMRxFinalizeSrvCall;
+
+    VBoxMRxDispatch.MRxDevFcbXXXControlFile = VBoxMRxDevFcbXXXControlFile;
+
+    Log(("VBOXSF: vbsfInitMRxDispatch: Success.\n"));
+    return;
+}
+
+static BOOL vboxIsPrefixOK (const WCHAR *FilePathName, ULONG PathNameLength)
+{
+    BOOL PrefixOK;
+
+    /* The FilePathName here looks like: \vboxsrv\... */
+    if (PathNameLength >= 8 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv' unicode string. */
+    {
+        PrefixOK =  (FilePathName[0] == L'\\');
+        PrefixOK &= (FilePathName[1] == L'V') || (FilePathName[1] == L'v');
+        PrefixOK &= (FilePathName[2] == L'B') || (FilePathName[2] == L'b');
+        PrefixOK &= (FilePathName[3] == L'O') || (FilePathName[3] == L'o');
+        PrefixOK &= (FilePathName[4] == L'X') || (FilePathName[4] == L'x');
+        PrefixOK &= (FilePathName[5] == L'S') || (FilePathName[5] == L's');
+        /* Both vboxsvr & vboxsrv are now accepted */
+        if ((FilePathName[6] == L'V') || (FilePathName[6] == L'v'))
+        {
+            PrefixOK &= (FilePathName[6] == L'V') || (FilePathName[6] == L'v');
+            PrefixOK &= (FilePathName[7] == L'R') || (FilePathName[7] == L'r');
+        }
+        else
+        {
+            PrefixOK &= (FilePathName[6] == L'R') || (FilePathName[6] == L'r');
+            PrefixOK &= (FilePathName[7] == L'V') || (FilePathName[7] == L'v');
+        }
+        if (PathNameLength > 8 * sizeof (WCHAR))
+        {
+            /* There is something after '\vboxsrv'. */
+            PrefixOK &= (FilePathName[8] == L'\\') || (FilePathName[8] == 0);
+        }
+    }
+    else
+    {
+        PrefixOK = FALSE;
+    }
+
+    return PrefixOK;
+}
+
+static NTSTATUS VBoxMRXDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    QUERY_PATH_REQUEST *pReq = NULL;
+    QUERY_PATH_REQUEST_EX *pReqEx = NULL;
+    QUERY_PATH_RESPONSE *pResp = NULL;
+
+    BOOL PrefixOK = FALSE;
+
+    PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+
+    /* Make a local copy, it will be needed after the Irp completion. */
+    ULONG IoControlCode = pStack->Parameters.DeviceIoControl.IoControlCode;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)pDevObj + sizeof(RDBSS_DEVICE_OBJECT));
+
+    Log(("VBOXSF: MRXDeviceControl: pDevObj %p, pDeviceExtension %p, code %x\n",
+         pDevObj, pDevObj->DeviceExtension, IoControlCode));
+
+    switch (IoControlCode)
+    {
+        case IOCTL_REDIR_QUERY_PATH_EX: /* Vista */
+        case IOCTL_REDIR_QUERY_PATH:    /* XP and earlier */
+        {
+            /* This IOCTL is intercepted for 2 reasons:
+             * 1) Claim the vboxsvr and vboxsrv prefixes. All name-based operations for them
+             *    will be routed to the VBox provider automatically without any prefix resolution
+             *    since the prefix is already in the prefix cache.
+             * 2) Reject other prefixes immediately to speed up the UNC path resolution a bit,
+             *    because RDBSS will not be involved then.
+             */
+
+            const WCHAR *FilePathName = NULL;
+            ULONG PathNameLength = 0;
+
+            if (pIrp->RequestorMode != KernelMode)
+            {
+                /* MSDN: Network redirectors should only honor kernel-mode senders of this IOCTL, by verifying
+                 * that RequestorMode member of the IRP structure is KernelMode.
+                 */
+                Log(("VBOXSF: MRxDeviceControl: IOCTL_REDIR_QUERY_PATH(_EX): not kernel mode!!!\n",
+                      pStack->Parameters.DeviceIoControl.InputBufferLength));
+                /* Continue to RDBSS. */
+                break;
+            }
+
+            if (IoControlCode == IOCTL_REDIR_QUERY_PATH)
+            {
+                Log(("VBOXSF: MRxDeviceControl: IOCTL_REDIR_QUERY_PATH: Called (pid %x).\n", IoGetCurrentProcess()));
+
+                if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST))
+                {
+                    Log(("VBOXSF: MRxDeviceControl: IOCTL_REDIR_QUERY_PATH: short input buffer %d.\n",
+                          pStack->Parameters.DeviceIoControl.InputBufferLength));
+                    /* Continue to RDBSS. */
+                    break;
+                }
+
+                pReq = (QUERY_PATH_REQUEST *)pStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+                Log(("VBOXSF: MRxDeviceControl: PathNameLength = %d.\n", pReq->PathNameLength));
+                Log(("VBOXSF: MRxDeviceControl: SecurityContext = %p.\n", pReq->SecurityContext));
+                Log(("VBOXSF: MRxDeviceControl: FilePathName = %.*ls.\n", pReq->PathNameLength / sizeof (WCHAR), pReq->FilePathName));
+
+                FilePathName = pReq->FilePathName;
+                PathNameLength = pReq->PathNameLength;
+            }
+            else
+            {
+                Log(("VBOXSF: MRxDeviceControl: IOCTL_REDIR_QUERY_PATH_EX: Called.\n"));
+
+                if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST_EX))
+                {
+                    Log(("VBOXSF: MRxDeviceControl: IOCTL_REDIR_QUERY_PATH_EX: short input buffer %d.\n",
+                          pStack->Parameters.DeviceIoControl.InputBufferLength));
+                    /* Continue to RDBSS. */
+                    break;
+                }
+
+                pReqEx = (QUERY_PATH_REQUEST_EX *)pStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+                Log(("VBOXSF: MRxDeviceControl: pSecurityContext = %p.\n", pReqEx->pSecurityContext));
+                Log(("VBOXSF: MRxDeviceControl: EaLength = %d.\n", pReqEx->EaLength));
+                Log(("VBOXSF: MRxDeviceControl: pEaBuffer = %p.\n", pReqEx->pEaBuffer));
+                Log(("VBOXSF: MRxDeviceControl: PathNameLength = %d.\n", pReqEx->PathName.Length));
+                Log(("VBOXSF: MRxDeviceControl: FilePathName = %.*ls.\n", pReqEx->PathName.Length / sizeof (WCHAR), pReqEx->PathName.Buffer));
+
+                FilePathName = pReqEx->PathName.Buffer;
+                PathNameLength = pReqEx->PathName.Length;
+            }
+
+            pResp = (QUERY_PATH_RESPONSE *)pIrp->UserBuffer;
+
+            PrefixOK = vboxIsPrefixOK (FilePathName, PathNameLength);
+            Log(("VBOXSF: MRxDeviceControl PrefixOK %d\n", PrefixOK));
+
+            if (!PrefixOK)
+            {
+                /* Immediately fail the IOCTL with STATUS_BAD_NETWORK_NAME as recommended by MSDN.
+                 * No need to involve RDBSS.
+                 */
+                Status = STATUS_BAD_NETWORK_NAME;
+
+                pIrp->IoStatus.Status = Status;
+                pIrp->IoStatus.Information = 0;
+
+                IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+                Log(("VBOXSF: MRxDeviceControl: returned STATUS_BAD_NETWORK_NAME\n"));
+                return Status;
+            }
+
+            Log(("VBOXSF: MRxDeviceControl pResp %p verifying the path.\n", pResp));
+            if (pResp)
+            {
+                /* Always claim entire \vboxsrv prefix. The LengthAccepted initially is equal to entire path.
+                 * Here it is assigned to the length of \vboxsrv prefix.
+                 */
+                pResp->LengthAccepted = 8 * sizeof (WCHAR);
+
+                Status = STATUS_SUCCESS;
+
+                pIrp->IoStatus.Status = Status;
+                pIrp->IoStatus.Information = 0;
+
+                IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+                Log(("VBOXSF: MRxDeviceControl: claiming the path.\n"));
+                return Status;
+            }
+
+            /* No pResp pointer, should not happen. Just a precaution. */
+            Status = STATUS_INVALID_PARAMETER;
+
+            pIrp->IoStatus.Status = Status;
+            pIrp->IoStatus.Information = 0;
+
+            IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+            Log(("VBOXSF: MRxDeviceControl: returned STATUS_INVALID_PARAMETER\n"));
+            return Status;
+        }
+
+        default:
+            break;
+    }
+
+    /* Pass the IOCTL to RDBSS. */
+    if (pDeviceExtension && pDeviceExtension->pfnRDBSSDeviceControl)
+    {
+        Log(("VBOXSF: MRxDeviceControl calling RDBSS %p\n", pDeviceExtension->pfnRDBSSDeviceControl));
+        Status = pDeviceExtension->pfnRDBSSDeviceControl (pDevObj, pIrp);
+        Log(("VBOXSF: MRxDeviceControl RDBSS status 0x%08X\n", Status));
+    }
+    else
+    {
+        /* No RDBSS, should not happen. Just a precaution. */
+        Status = STATUS_NOT_IMPLEMENTED;
+
+        pIrp->IoStatus.Status = Status;
+        pIrp->IoStatus.Information = 0;
+
+        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+        Log(("VBOXSF: MRxDeviceControl: returned STATUS_NOT_IMPLEMENTED\n"));
+    }
+
+    return Status;
+}
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,
+                     IN PUNICODE_STRING RegistryPath)
+{
+    NTSTATUS Status;
+    UNICODE_STRING VBoxMRxName;
+    UNICODE_STRING UserModeDeviceName;
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension;
+    ULONG i;
+    int vboxRC;
+    VBSFCLIENT hgcmClient;
+
+    Log(("VBOXSF: DriverEntry: Driver object %p\n", DriverObject));
+
+    if (DriverObject == NULL)
+    {
+        Log(("VBOXSF: DriverEntry: driver object is NULL.\n"));
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Initialize VBox subsystem. */
+    vboxRC = vboxInit();
+    if (RT_FAILURE(vboxRC))
+    {
+        Log(("VBOXSF: DriverEntry: ERROR while initializing VBox subsystem (%Rrc)!\n",
+             vboxRC));
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Connect the HGCM client */
+    RT_ZERO(hgcmClient);
+    vboxRC = vboxConnect(&hgcmClient);
+    if (RT_FAILURE(vboxRC))
+    {
+        Log(("VBOXSF: DriverEntry: ERROR while connecting to host (%Rrc)!\n",
+             vboxRC));
+        vboxUninit();
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Init the driver object. */
+    DriverObject->DriverUnload = VBoxMRxUnload;
+    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+    {
+        DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)VBoxMRxFsdDispatch;
+    }
+
+    /* Forward to RDBSS. */
+    Status = RxDriverEntry(DriverObject, RegistryPath);
+    if (Status != STATUS_SUCCESS)
+    {
+        Log(("VBOXSF: DriverEntry: RxDriverEntry failed: 0x%08X\n", Status));
+        goto failure;
+    }
+
+    __try
+    {
+        Log(("VBOXSF: DriverEntry: RxRegisterMinirdr: calling VBoxMRxDeviceObject %p\n",
+             VBoxMRxDeviceObject));
+
+        RtlInitUnicodeString(&VBoxMRxName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
+
+        /* Don use RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS or else
+         * UNC mappings don't work (including Windows explorer browsing).
+         */
+        Status = RxRegisterMinirdr(&VBoxMRxDeviceObject,
+                                   DriverObject,
+                                   &VBoxMRxDispatch,
+                                   RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS,
+                                   &VBoxMRxName,
+                                   sizeof(MRX_VBOX_DEVICE_EXTENSION),
+                                   FILE_DEVICE_NETWORK_FILE_SYSTEM,
+                                   FILE_REMOTE_DEVICE);
+
+        Log(("VBOXSF: DriverEntry: RxRegisterMinirdr: returned 0x%08X VBoxMRxDeviceObject %p\n",
+             Status, VBoxMRxDeviceObject));
+
+        if (Status!=STATUS_SUCCESS)
+        {
+            Log(("VBOXSF: DriverEntry: RxRegisterMinirdr failed: 0x%08X\n", Status ));
+            try_return(Status);
+        }
+
+        /* Init the device extension.
+         * NOTE: the device extension actually points to fields
+         * in the RDBSS_DEVICE_OBJECT. Our space is past the end
+         * of this struct!!
+         */
+        pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)VBoxMRxDeviceObject + sizeof(RDBSS_DEVICE_OBJECT));
+
+        pDeviceExtension->pDeviceObject = VBoxMRxDeviceObject;
+
+        for (i = 0; i < RT_ELEMENTS(pDeviceExtension->cLocalConnections); i++)
+        {
+            pDeviceExtension->cLocalConnections[i] = FALSE;
+        }
+
+        /* Mutex for synchronizining our connection list */
+        ExInitializeFastMutex(&pDeviceExtension->mtxLocalCon);
+
+        /* The device object has been created. Need to setup a symbolic
+         * link so that the device may be accessed from a Win32 user mode
+         * application.
+         */
+
+        RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U);
+        Log(("VBOXSF: DriverEntry: Calling IoCreateSymbolicLink\n"));
+        Status = IoCreateSymbolicLink(&UserModeDeviceName, &VBoxMRxName);
+        if (Status != STATUS_SUCCESS)
+        {
+            Log(("VBOXSF: DriverEntry: IoCreateSymbolicLink: 0x%08X\n",
+                 Status));
+            try_return(Status);
+        }
+        Log(("VBOXSF: DriverEntry: Symbolic link created.\n"));
+
+        /*
+         * Build the dispatch tables for the minirdr
+         */
+        vbsfInitMRxDispatch();
+
+    try_exit:
+         ;
+    }
+    __finally
+    {
+        ;
+    }
+
+    if (Status != STATUS_SUCCESS)
+    {
+        Log(("VBOXSF: DriverEntry: VBoxSF.sys failed to start with Status = 0x%08X\n",
+             Status));
+        goto failure;
+    }
+
+    pDeviceExtension->hgcmClient = hgcmClient;
+
+    /* The redirector driver must intercept the IOCTL to avoid VBOXSVR name resolution
+     * by other redirectors. These additional name resolutions cause long delays.
+     */
+    Log(("VBOXSF: DriverEntry: VBoxMRxDeviceObject = %p, rdbss %p, devext %p\n",
+         VBoxMRxDeviceObject, DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL], pDeviceExtension));
+    pDeviceExtension->pfnRDBSSDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxMRXDeviceControl;
+
+    /* @todo start the redirector here RxStartMiniRdr. */
+
+    Log(("VBOXSF: DriverEntry: Init successful!\n"));
+    return STATUS_SUCCESS;
+
+failure:
+
+    Log(("VBOXSF: DriverEntry: Failure! Status = 0x%08X\n", Status));
+
+    vboxDisconnect(&hgcmClient);
+    vboxUninit();
+
+    if (VBoxMRxDeviceObject)
+    {
+        RxUnregisterMinirdr(VBoxMRxDeviceObject);
+        VBoxMRxDeviceObject = NULL;
+    }
+
+    return Status;
+}
+
+NTSTATUS VBoxMRxStart(PRX_CONTEXT RxContext, IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject)
+{
+    NTSTATUS Status;
+    MRX_VBOX_STATE CurrentState;
+
+    Log(("VBOXSF: MRxStart\n"));
+
+    CurrentState = (MRX_VBOX_STATE)InterlockedCompareExchange((PLONG)&VBoxMRxState, MRX_VBOX_STARTED, MRX_VBOX_START_IN_PROGRESS);
+
+    if (CurrentState == MRX_VBOX_START_IN_PROGRESS)
+    {
+        Log(("VBOXSF: MRxStart: Start in progress -> started\n"));
+        Status = STATUS_SUCCESS;
+    }
+    else if (VBoxMRxState == MRX_VBOX_STARTED)
+    {
+        Log(("VBOXSF: MRxStart: Already started\n"));
+        Status = STATUS_REDIRECTOR_STARTED;
+    }
+    else
+    {
+        Log(("VBOXSF: MRxStart: Bad state! VBoxMRxState = %d\n", VBoxMRxState));
+        Status = STATUS_UNSUCCESSFUL;
+    }
+
+    return Status;
+}
+
+NTSTATUS VBoxMRxStop(PRX_CONTEXT RxContext, IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject)
+{
+    Log(("VBOXSF: MRxStop\n"));
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxIoCtl(IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxIoCtl: IoControlCode = 0x%08X\n",
+         RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode));
+    return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSYSAPI NTSTATUS NTAPI ZwSetSecurityObject(IN HANDLE Handle,
+                                            IN SECURITY_INFORMATION SecurityInformation,
+                                            IN PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+NTSTATUS VBoxMRxDevFcbXXXControlFile(IN OUT PRX_CONTEXT RxContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    RxCaptureFobx;
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+
+    Log(("VBOXSF: MRxDevFcbXXXControlFile: MajorFunction = 0x%02X\n",
+         RxContext->MajorFunction));
+
+    switch (RxContext->MajorFunction)
+    {
+        case IRP_MJ_FILE_SYSTEM_CONTROL:
+        {
+            Log(("VBOXSF: MRxDevFcbXXXControlFile: IRP_MN_USER_FS_REQUEST: 0x%08X\n",
+                 LowIoContext->ParamsFor.FsCtl.MinorFunction));
+
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+        }
+
+        case IRP_MJ_DEVICE_CONTROL:
+        {
+            switch (LowIoContext->ParamsFor.IoCtl.IoControlCode)
+            {
+                case IOCTL_MRX_VBOX_ADDCONN:
+                {
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_ADDCONN\n"));
+                    Status = vbsfCreateConnection(RxContext, &RxContext->PostRequest);
+                } break;
+
+                case IOCTL_MRX_VBOX_DELCONN:
+                {
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_DELCONN\n"));
+                    Status = vbsfDeleteConnection(RxContext, &RxContext->PostRequest);
+                } break;
+
+                case IOCTL_MRX_VBOX_GETLIST:
+                {
+                    ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+                    uint8_t *pu8Out = (uint8_t *)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST\n"));
+
+                    if (NULL == pDeviceExtension)
+                    {
+                        RxContext->InformationToReturn = 0;
+                        break;
+                    }
+
+                    if ((cbOut >= _MRX_MAX_DRIVE_LETTERS) && (NULL != pu8Out))
+                    {
+                        BOOLEAN fLocked = FALSE;
+
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST: Copying local connections\n"));
+
+                        fLocked = ExTryToAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+                        RtlCopyMemory(pu8Out, pDeviceExtension->cLocalConnections, _MRX_MAX_DRIVE_LETTERS);
+
+                        if (fLocked)
+                        {
+                            ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+                        }
+
+                        RxContext->InformationToReturn = _MRX_MAX_DRIVE_LETTERS;
+                    }
+                    else
+                    {
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST: cbOut is too small %d bytes\n",
+                             cbOut));
+                        RxContext->InformationToReturn = 0;
+                    }
+
+                    Status = STATUS_SUCCESS;
+                    break;
+                }
+
+                /*
+                 * Returns the root IDs of shared folder mappings.
+                 */
+                case IOCTL_MRX_VBOX_GETGLOBALLIST:
+                {
+                    ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+                    uint8_t *pu8Out = (uint8_t *)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALLIST\n"));
+
+                    RxContext->InformationToReturn = 0;
+
+                    if (NULL == pDeviceExtension)
+                    {
+                        break;
+                    }
+
+                    if ((cbOut >= _MRX_MAX_DRIVE_LETTERS) && (NULL != pu8Out))
+                    {
+                        SHFLMAPPING mappings[_MRX_MAX_DRIVE_LETTERS];
+                        uint32_t cMappings = RT_ELEMENTS(mappings);
+
+                        int vboxRC = vboxCallQueryMappings(&pDeviceExtension->hgcmClient, mappings, &cMappings);
+
+                        if (vboxRC == VINF_SUCCESS)
+                        {
+                            uint32_t i;
+
+                            RtlZeroMemory(pu8Out, _MRX_MAX_DRIVE_LETTERS);
+
+                            for (i = 0; i < RT_MIN(cMappings, cbOut); i++)
+                            {
+                                pu8Out[i] = mappings[i].root;
+                                pu8Out[i] |= 0x80; /* mark active */ /** @todo fix properly */
+                            }
+
+                            RxContext->InformationToReturn = _MRX_MAX_DRIVE_LETTERS;
+                        }
+                        else
+                        {
+                            Status = VBoxErrorToNTStatus(vboxRC);
+                            Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALLIST failed: 0x%08X\n",
+                                 Status));
+                        }
+                    }
+
+                    Status = STATUS_SUCCESS;
+                    break;
+                }
+
+                /*
+                 * Translates a local connection name (e.g. drive "S:") to the
+                 * corresponding remote name (e.g. \\vboxsrv\share).
+                 */
+                case IOCTL_MRX_VBOX_GETCONN:
+                {
+                    ULONG cbConnectName = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
+                    PWCHAR pwcConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+
+                    ULONG cbRemoteName = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+                    PWCHAR pwcRemoteName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: ConnectName = %.*ls, Len = %d, RemoteName = 0x%p, Len = %d\n",
+                         cbConnectName / sizeof(WCHAR), pwcConnectName, cbConnectName, pwcRemoteName, cbRemoteName));
+
+                    if (NULL == pDeviceExtension)
+                    {
+                        Status = STATUS_INVALID_PARAMETER;
+                        break;
+                    }
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Looking up connection name and connections\n"));
+
+                    if ((cbConnectName > sizeof(WCHAR)) && (NULL != pwcConnectName))
+                    {
+                        ULONG cbLocalConnectionName;
+
+                        uint32_t idx = *pwcConnectName - L'A';
+
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index = %d\n", idx));
+
+                        if (idx >= RTL_NUMBER_OF(pDeviceExtension->wszLocalConnectionName))
+                        {
+                            Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index is invalid!\n"));
+                            Status = STATUS_INVALID_PARAMETER;
+                            break;
+                        }
+
+                        ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+                        if (NULL == pDeviceExtension->wszLocalConnectionName[idx])
+                        {
+                            Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: LocalConnectionName is NULL!\n"));
+                            ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+                            Status = STATUS_BAD_NETWORK_NAME;
+                            break;
+                        }
+
+                        cbLocalConnectionName = pDeviceExtension->wszLocalConnectionName[idx]->Length;
+
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: LocalConnectionName = %.*ls\n",
+                             cbLocalConnectionName / sizeof(WCHAR), pDeviceExtension->wszLocalConnectionName[idx]->Buffer));
+
+                        if ((pDeviceExtension->cLocalConnections[idx]) && (cbLocalConnectionName <= cbRemoteName))
+                        {
+                            RtlZeroMemory(pwcRemoteName, cbRemoteName);
+                            RtlCopyMemory(pwcRemoteName, pDeviceExtension->wszLocalConnectionName[idx]->Buffer, cbLocalConnectionName);
+
+                            Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Remote name = %.*ls, Len = %d\n",
+                                 cbLocalConnectionName / sizeof(WCHAR), pwcRemoteName, cbLocalConnectionName));
+
+                            RxContext->InformationToReturn = cbLocalConnectionName;
+                        }
+                        else
+                        {
+                            Status = STATUS_BUFFER_TOO_SMALL;
+                            RxContext->InformationToReturn = cbLocalConnectionName;
+                        }
+
+                        ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+                    }
+                    else
+                    {
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: bad connect name!n"));
+                        Status = STATUS_BAD_NETWORK_NAME;
+                    }
+
+                    break;
+                }
+
+                case IOCTL_MRX_VBOX_GETGLOBALCONN:
+                {
+                    ULONG ReturnedSize = 0;
+
+                    uint8_t *pConnectId = (uint8_t *)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+                    ULONG cbRemoteName = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+                    PWCHAR pwcRemoteName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+                    int vboxRC;
+
+                    PSHFLSTRING pString;
+                    uint32_t cbString;
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALCONN: Connection ID = %d, RemoteName = 0x%x, Len = %d\n",
+                         *pConnectId, pwcRemoteName, cbRemoteName));
+
+                    cbString = sizeof(SHFLSTRING) + cbRemoteName;
+                    pString = (PSHFLSTRING)vbsfAllocNonPagedMem(cbString);
+                    if (!pString)
+                    {
+                        Status = STATUS_INSUFFICIENT_RESOURCES;
+                        break;
+                    }
+                    memset(pString, 0, cbString);
+                    ShflStringInitBuffer(pString, cbRemoteName);
+
+                    vboxRC = vboxCallQueryMapName(&pDeviceExtension->hgcmClient,
+                                                  (*pConnectId) & ~0x80 /** @todo fix properly */,
+                                                  pString,
+                                                  cbString);
+                    if (   vboxRC == VINF_SUCCESS
+                        && pString->u16Length < cbRemoteName)
+                    {
+                        ReturnedSize = pString->u16Length;
+                        RtlCopyMemory(pwcRemoteName, pString->String.ucs2, pString->u16Length);
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALCONN: Returned name = %.*ls, Len = %d\n",
+                             ReturnedSize / sizeof(WCHAR), pwcRemoteName, ReturnedSize));
+                        Status = STATUS_SUCCESS;
+                    }
+                    else
+                    {
+                        Status = STATUS_BAD_NETWORK_NAME;
+                    }
+
+                    vbsfFreeNonPagedMem(pString);
+
+                    RxContext->InformationToReturn = ReturnedSize;
+                } break;
+
+                case IOCTL_MRX_VBOX_START:
+                {
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: capFobx %p\n",
+                         capFobx));
+
+                    switch (VBoxMRxState)
+                    {
+                        case MRX_VBOX_STARTABLE:
+
+                            /* The correct sequence of start events issued by the workstation
+                             * service would have avoided this. We can recover from this
+                             * by actually invoking RxStartMiniRdr.
+                             */
+                            if (capFobx)
+                            {
+                                Status = STATUS_INVALID_DEVICE_REQUEST;
+                                break;;
+                            }
+
+                            /* Set global VBoxMRxState variable to MRX_VBOX_STARTABLE and fall through to the next case. */
+                            InterlockedCompareExchange((PLONG) & VBoxMRxState, MRX_VBOX_START_IN_PROGRESS, MRX_VBOX_STARTABLE);
+
+                            /* Lack of break is intentional. */
+
+                        case MRX_VBOX_START_IN_PROGRESS:
+                            Status = RxStartMinirdr(RxContext, &RxContext->PostRequest);
+
+                            if (Status == STATUS_REDIRECTOR_STARTED)
+                            {
+                                Status = STATUS_SUCCESS;
+                            }
+                            else if (Status == STATUS_PENDING && RxContext->PostRequest == TRUE)
+                            {
+                                Status = STATUS_MORE_PROCESSING_REQUIRED;
+                            }
+
+                            /* Allow restricted users to use shared folders; works only in XP and Vista. (@@todo hack) */
+                            if (Status == STATUS_SUCCESS)
+                            {
+                                SECURITY_DESCRIPTOR SecurityDescriptor;
+                                OBJECT_ATTRIBUTES InitializedAttributes;
+                                HANDLE hDevice;
+                                IO_STATUS_BLOCK IoStatusBlock;
+                                UNICODE_STRING UserModeDeviceName;
+
+                                RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U);
+
+                                /* Create empty security descriptor */
+                                RtlZeroMemory (&SecurityDescriptor, sizeof (SecurityDescriptor));
+                                Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
+                                if (Status != STATUS_SUCCESS)
+                                {
+                                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: RtlCreateSecurityDescriptor failed with 0x%08X!\n",
+                                         Status));
+                                    return Status;
+                                }
+
+                                RtlZeroMemory (&InitializedAttributes, sizeof (InitializedAttributes));
+                                InitializeObjectAttributes(&InitializedAttributes, &UserModeDeviceName, OBJ_KERNEL_HANDLE, 0, 0);
+
+                                /* Open our symbolic link device name */
+                                Status = ZwOpenFile(&hDevice, WRITE_DAC, &InitializedAttributes, &IoStatusBlock, 0, 0);
+                                if (Status != STATUS_SUCCESS)
+                                {
+                                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwOpenFile %ls failed with 0x%08X!\n",
+                                         DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U, Status));
+                                    return Status;
+                                }
+
+                                /* Override the discretionary access control list (DACL) settings */
+                                Status = ZwSetSecurityObject(hDevice, DACL_SECURITY_INFORMATION, &SecurityDescriptor);
+                                if (Status != STATUS_SUCCESS)
+                                {
+                                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwSetSecurityObject failed with 0x%08X!\n",
+                                         Status));
+                                    return Status;
+                                }
+
+                                Status = ZwClose(hDevice);
+                                if (Status != STATUS_SUCCESS)
+                                {
+                                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwClose failed with 0x%08X\n",
+                                         Status));
+                                    return Status;
+                                }
+                            }
+                            break;
+
+                        case MRX_VBOX_STARTED:
+                            Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_STARTED: Already started\n"));
+                            Status = STATUS_SUCCESS;
+                            break;
+
+                        default:
+                            Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Invalid state (%d)!\n",
+                                 VBoxMRxState));
+                            Status = STATUS_INVALID_PARAMETER;
+                            break;
+                    }
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Returned 0x%08X\n",
+                         Status));
+                    break;
+                }
+
+                case IOCTL_MRX_VBOX_STOP:
+                {
+                    MRX_VBOX_STATE CurrentState;
+
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: capFobx %p\n",
+                         capFobx));
+
+                    if (capFobx)
+                    {
+                        Status = STATUS_INVALID_DEVICE_REQUEST;
+                        break;
+                    }
+
+                    if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0)
+                    {
+                        Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Open handles = %d\n",
+                             RxContext->RxDeviceObject->NumberOfActiveFcbs));
+                        Status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
+                        break;
+                    }
+
+                    CurrentState = (MRX_VBOX_STATE)InterlockedCompareExchange((PLONG) & VBoxMRxState, MRX_VBOX_STARTABLE, MRX_VBOX_STARTED);
+
+                    Status = RxStopMinirdr(RxContext, &RxContext->PostRequest);
+                    Log(("VBOXSF: MRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Returned 0x%08X\n",
+                         Status));
+
+                    if (Status == STATUS_PENDING && RxContext->PostRequest == TRUE)
+                    {
+                        Status = STATUS_MORE_PROCESSING_REQUIRED;
+                    }
+
+                } break;
+
+                default:
+                    Status = STATUS_INVALID_DEVICE_REQUEST;
+                    break;
+            } break;
+        }
+
+        case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+        {
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+        }
+
+        default:
+            Log(("VBOXSF: MRxDevFcbXXXControlFile: unimplemented major function 0x%02X\n",
+                 RxContext->MajorFunction));
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+    }
+
+    Log(("VBOXSF: MRxDevFcbXXXControlFile: Status = 0x%08X, Info = 0x%08X\n",
+         Status, RxContext->InformationToReturn));
+
+    return Status;
+}
+
+static HANDLE vbsfOpenConnectionHandle(PUNICODE_STRING ConnectionName)
+{
+    NTSTATUS Status;
+    IO_STATUS_BLOCK IoStatusBlock;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+
+    HANDLE Handle = INVALID_HANDLE_VALUE;
+
+    Log(("VBOXSF: vbsfOpenConnectionHandle: ConnectionName = %.*ls\n",
+         ConnectionName->Length / sizeof(WCHAR), ConnectionName->Buffer));
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               ConnectionName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    Status = ZwCreateFile(&Handle,
+                          SYNCHRONIZE,
+                          &ObjectAttributes,
+                          &IoStatusBlock,
+                          NULL,
+                          FILE_ATTRIBUTE_NORMAL,
+                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                          FILE_OPEN_IF,
+                          FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
+                          NULL,
+                          0);
+
+    if (   Status != STATUS_SUCCESS
+        || Handle == INVALID_HANDLE_VALUE)
+    {
+        Log(("VBOXSF: vbsfOpenConnectionHandle: ZwCreateFile failed status 0x%08X or invalid handle!\n",
+             Status));
+        Handle = INVALID_HANDLE_VALUE;
+    }
+
+    return Handle;
+}
+
+NTSTATUS vbsfCreateConnection(IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension;
+
+    PLOWIO_CONTEXT LowIoContext;
+    ULONG cbConnectName;
+    PWCHAR pwcConnectName;
+
+    HANDLE Handle;
+    UNICODE_STRING FileName;
+
+    Log(("VBOXSF: vbsfCreateConnection\n"));
+
+    if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT))
+    {
+        Log(("VBOXSF: vbsfCreateConnection: post to file system process\n"));
+        *PostToFsp = TRUE;
+        return STATUS_PENDING;
+    }
+
+    pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+
+    LowIoContext = &RxContext->LowIoContext;
+    cbConnectName = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
+    pwcConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+
+    if (pDeviceExtension == NULL)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (cbConnectName == 0 || pwcConnectName == NULL)
+    {
+        Log(("VBOXSF: vbsfCreateConnection: Connection name / length is invalid!\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Log(("VBOXSF: vbsfCreateConnection: Name = %.*ls, Len = %d\n",
+         cbConnectName / sizeof(WCHAR), pwcConnectName, cbConnectName));
+
+    FileName.Buffer = pwcConnectName;
+    FileName.Length = (USHORT)cbConnectName;
+    FileName.MaximumLength = (USHORT)cbConnectName;
+
+    Handle = vbsfOpenConnectionHandle(&FileName);
+
+    if (Handle != INVALID_HANDLE_VALUE)
+    {
+        PWCHAR pwc;
+        ULONG i;
+
+        ZwClose(Handle);
+
+        /* Skip the "\Device\VBoxMiniRdr\;X:" of the string "\Device\VBoxMiniRdr\;X:\vboxsrv\sf" */
+        pwc = pwcConnectName;
+        for (i = 0; i < cbConnectName; i += sizeof(WCHAR))
+        {
+            if (*pwc == L':')
+            {
+                break;
+            }
+            pwc++;
+        }
+
+        if (i >= sizeof(WCHAR) && i < cbConnectName)
+        {
+            pwc--; /* Go back to the drive letter, "X" for example. */
+
+            if (*pwc >= L'A' && *pwc <= L'Z') /* Are we in range? */
+            {
+                uint32_t idx = *pwc - L'A'; /* Get the index based on the driver letter numbers (26). */
+
+                if (idx >= RTL_NUMBER_OF(pDeviceExtension->cLocalConnections))
+                {
+                    Log(("VBOXSF: vbsfCreateConnection: Index 0x%x is invalid!\n",
+                         idx));
+                    Status = STATUS_BAD_NETWORK_NAME;
+                }
+                else
+                {
+                    ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+                    if (pDeviceExtension->wszLocalConnectionName[idx] != NULL)
+                    {
+                        Log(("VBOXSF: vbsfCreateConnection: LocalConnectionName at index %d is NOT empty!\n",
+                             idx));
+                    }
+
+                    pDeviceExtension->wszLocalConnectionName[idx] = (PUNICODE_STRING)vbsfAllocNonPagedMem(sizeof(UNICODE_STRING) + cbConnectName);
+
+                    if (pDeviceExtension->wszLocalConnectionName[idx] == NULL)
+                    {
+                        Log(("VBOXSF: vbsfCreateConnection: LocalConnectionName at index %d NOT allocated!\n", 
+                             idx));
+                        Status = STATUS_INSUFFICIENT_RESOURCES;
+                    }
+                    else
+                    {
+                        PUNICODE_STRING pRemoteName = pDeviceExtension->wszLocalConnectionName[idx];
+
+                        pRemoteName->Buffer = (PWSTR)(pRemoteName + 1);
+                        pRemoteName->Length = (USHORT)(cbConnectName - i - sizeof(WCHAR));
+                        pRemoteName->MaximumLength = pRemoteName->Length;
+                        RtlCopyMemory(&pRemoteName->Buffer[0], pwc+2, pRemoteName->Length);
+
+                        Log(("VBOXSF: vbsfCreateConnection: RemoteName %.*ls, Len = %d\n",
+                             pRemoteName->Length / sizeof(WCHAR), pRemoteName->Buffer, pRemoteName->Length));
+
+                        pDeviceExtension->cLocalConnections[idx] = TRUE;
+                    }
+
+                    ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+                }
+            }
+        }
+        else
+        {
+            Log(("VBOXSF: vbsfCreateConnection: bad format\n"));
+            Status = STATUS_BAD_NETWORK_NAME;
+        }
+    }
+    else
+    {
+        Log(("VBOXSF: vbsfCreateConnection: connection was not found\n"));
+        Status = STATUS_BAD_NETWORK_NAME;
+    }
+
+    return Status;
+}
+
+NTSTATUS vbsfDeleteConnection(IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp)
+{
+    NTSTATUS Status;
+    UNICODE_STRING FileName;
+    HANDLE Handle;
+    PLOWIO_CONTEXT LowIoContext;
+    PWCHAR pwcConnectName;
+    ULONG cbConnectName;
+    PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension;
+
+    if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT))
+    {
+        Log(("VBOXSF: vbsfDeleteConnection: post to file system process\n"));
+        *PostToFsp = TRUE;
+        return STATUS_PENDING;
+    }
+
+    LowIoContext = &RxContext->LowIoContext;
+    pwcConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+    cbConnectName = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
+
+    pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext);
+
+    Log(("VBOXSF: vbsfDeleteConnection: pwcConnectName = %.*ls\n",
+         cbConnectName / sizeof(WCHAR), pwcConnectName));
+
+    FileName.Buffer = pwcConnectName;
+    FileName.Length = (USHORT)cbConnectName;
+    FileName.MaximumLength = (USHORT)cbConnectName;
+
+    Handle = vbsfOpenConnectionHandle(&FileName);
+
+    if (Handle != INVALID_HANDLE_VALUE)
+    {
+        PFILE_OBJECT pFileObject;
+        Status = ObReferenceObjectByHandle(Handle, 0L, NULL, KernelMode, (PVOID *)&pFileObject, NULL);
+
+        Log(("VBOXSF: vbsfDeleteConnection: ObReferenceObjectByHandle Status 0x%08X\n",
+             Status));
+
+        if (NT_SUCCESS(Status))
+        {
+            PFOBX Fobx = (PFOBX)pFileObject->FsContext2;
+
+            if (NodeType(Fobx) == RDBSS_NTC_V_NETROOT)
+            {
+                PV_NET_ROOT VNetRoot = (PV_NET_ROOT)Fobx;
+
+                Status = RxFinalizeConnection(VNetRoot->NetRoot, VNetRoot, TRUE);
+            }
+            else
+            {
+                Log(("VBOXSF: vbsfDeleteConnection: wrong FsContext2\n"));
+                Status = STATUS_INVALID_DEVICE_REQUEST;
+            }
+
+            ObDereferenceObject(pFileObject);
+        }
+
+        ZwClose(Handle);
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        PWCHAR pwc;
+        ULONG i;
+
+        /* Skip the "\Device\VBoxMiniRdr\;X:" of the string "\Device\VBoxMiniRdr\;X:\vboxsrv\sf" */
+        pwc = pwcConnectName;
+        for (i = 0; i < cbConnectName; i += sizeof(WCHAR))
+        {
+            if (*pwc == L':')
+            {
+                break;
+            }
+            pwc++;
+        }
+
+        if (i >= sizeof(WCHAR) && i < cbConnectName)
+        {
+            pwc--;
+
+            if (*pwc >= L'A' && *pwc <= L'Z')
+            {
+                uint32_t idx = *pwc - L'A';
+
+                if (idx >= RTL_NUMBER_OF(pDeviceExtension->cLocalConnections))
+                {
+                    Log(("VBOXSF: vbsfDeleteConnection: Index 0x%x is invalid!\n",
+                         idx));
+                    Status = STATUS_BAD_NETWORK_NAME;
+                }
+                else
+                {
+                    ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+                    pDeviceExtension->cLocalConnections[idx] = FALSE;
+
+                    /* Free saved name */
+                    if (pDeviceExtension->wszLocalConnectionName[idx])
+                    {
+                        vbsfFreeNonPagedMem(pDeviceExtension->wszLocalConnectionName[idx]);
+                        pDeviceExtension->wszLocalConnectionName[idx] = NULL;
+                    }
+
+                    ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+                }
+            }
+        }
+        else
+        {
+            Log(("VBOXSF: vbsfCreateConnection: bad format\n"));
+            Status = STATUS_BAD_NETWORK_NAME;
+        }
+    }
+
+    return Status;
+}
+
+NTSTATUS VBoxMRxQueryEaInfo(IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxQueryEaInfo: Ea buffer len remaining is %d\n",
+         RxContext->Info.LengthRemaining));
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxSetEaInfo(IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxSetEaInfo\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxFsCtl (IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxFsCtl\n"));
+    return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSTATUS VBoxMRxNotifyChangeDirectory(IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxNotifyChangeDirectory\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxQuerySdInfo(IN OUT PRX_CONTEXT RxContext)
+{
+    Log(("VBOXSF: MRxQuerySdInfo\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxSetSdInfo(IN OUT struct _RX_CONTEXT * RxContext)
+{
+    Log(("VBOXSF: MRxSetSdInfo\n"));
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * WML stubs which are referenced by rdbsslib.
+ */
+NTSTATUS WmlTinySystemControl(void)
+{
+    return STATUS_WMI_GUID_NOT_FOUND;
+}
+
+ULONG WmlTrace(void)
+{
+    return STATUS_SUCCESS;
+}
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.h	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.h	(revision 40269)
@@ -0,0 +1,198 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver header file
+ */
+
+/*
+ * Copyright (C) 2012 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 VBSF_H
+#define VBSF_H
+
+/*
+ * This must be defined before including RX headers.
+ */
+#define MINIRDR__NAME VBoxMRx
+#define ___MINIRDR_IMPORTS_NAME (VBoxMRxDeviceObject->RdbssExports)
+
+/*
+ * System and RX headers.
+ */
+#include <ntifs.h>
+#include <windef.h>
+
+#include "rx.h"
+
+/*
+ * VBox shared folders.
+ */
+#include "vbsfhlp.h"
+#include "vbsfshared.h"
+
+extern PRDBSS_DEVICE_OBJECT VBoxMRxDeviceObject;
+
+/*
+ * Maximum drive letters (A - Z).
+ */
+#define _MRX_MAX_DRIVE_LETTERS 26
+
+/*
+ * The shared folders device extension.
+ */
+typedef struct _MRX_VBOX_DEVICE_EXTENSION
+{
+    /* The shared folders device object pointer. */
+    PRDBSS_DEVICE_OBJECT pDeviceObject;
+
+    /*
+     * Keep a list of local connections used.
+     * The size (_MRX_MAX_DRIVE_LETTERS = 26) of the array presents the available drive letters C: - Z: of Windows.
+     */
+    CHAR cLocalConnections[_MRX_MAX_DRIVE_LETTERS];
+    PUNICODE_STRING wszLocalConnectionName[_MRX_MAX_DRIVE_LETTERS];
+    FAST_MUTEX mtxLocalCon;
+
+    /* The HGCM client information. */
+    VBSFCLIENT hgcmClient;
+
+    /* Saved pointer to the original IRP_MJ_DEVICE_CONTROL handler. */
+    NTSTATUS (* pfnRDBSSDeviceControl) (PDEVICE_OBJECT pDevObj, PIRP pIrp);
+
+} MRX_VBOX_DEVICE_EXTENSION, *PMRX_VBOX_DEVICE_EXTENSION;
+
+/*
+ * The shared folders NET_ROOT extension.
+ */
+typedef struct _MRX_VBOX_NETROOT_EXTENSION
+{
+    /* The pointert to HGCM client information in device extension. */
+    VBSFCLIENT *phgcmClient;
+
+    /* The shared folder map handle of this netroot. */
+    VBSFMAP map;
+} MRX_VBOX_NETROOT_EXTENSION, *PMRX_VBOX_NETROOT_EXTENSION;
+
+/*
+ * The shared folders file extension.
+ */
+typedef struct _MRX_VBOX_FOBX_
+{
+    SHFLHANDLE hFile;
+    PMRX_SRV_CALL pSrvCall;
+    FILE_BASIC_INFORMATION FileBasicInfo;
+    FILE_STANDARD_INFORMATION FileStandardInfo;
+    BOOLEAN fKeepCreationTime;
+    BOOLEAN fKeepLastAccessTime;
+    BOOLEAN fKeepLastWriteTime;
+    BOOLEAN fKeepChangeTime;
+} MRX_VBOX_FOBX, *PMRX_VBOX_FOBX;
+
+#define VBoxMRxGetDeviceExtension(RxContext) \
+        (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
+
+#define VBoxMRxGetNetRootExtension(pNetRoot) \
+        (((pNetRoot) == NULL) ? NULL : (PMRX_VBOX_NETROOT_EXTENSION)((pNetRoot)->Context))
+
+#define VBoxMRxGetSrvOpenExtension(pSrvOpen)  \
+        (((pSrvOpen) == NULL) ? NULL : (PMRX_VBOX_SRV_OPEN)((pSrvOpen)->Context))
+
+#define VBoxMRxGetFileObjectExtension(pFobx)  \
+        (((pFobx) == NULL) ? NULL : (PMRX_VBOX_FOBX)((pFobx)->Context))
+
+/*
+ * Prototypes for the dispatch table routines.
+ */
+NTSTATUS VBoxMRxStart(IN OUT struct _RX_CONTEXT * RxContext,
+                      IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject);
+NTSTATUS VBoxMRxStop(IN OUT struct _RX_CONTEXT * RxContext,
+                     IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject);
+
+NTSTATUS VBoxMRxCreate(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxCollapseOpen(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxShouldTryToCollapseThisOpen(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxFlush(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxTruncate(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxCleanupFobx(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxCloseSrvOpen(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxDeallocateForFcb(IN OUT PMRX_FCB pFcb);
+NTSTATUS VBoxMRxDeallocateForFobx(IN OUT PMRX_FOBX pFobx);
+NTSTATUS VBoxMRxForceClosed(IN OUT PMRX_SRV_OPEN SrvOpen);
+
+NTSTATUS VBoxMRxQueryDirectory(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxQueryFileInfo(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxSetFileInfo(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxSetFileInfoAtCleanup(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxQueryEaInfo(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxSetEaInfo(IN OUT struct _RX_CONTEXT * RxContext);
+NTSTATUS VBoxMRxQuerySdInfo(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxSetSdInfo(IN OUT struct _RX_CONTEXT * RxContext);
+NTSTATUS VBoxMRxQueryVolumeInfo(IN OUT PRX_CONTEXT RxContext);
+
+NTSTATUS VBoxMRxComputeNewBufferingState(IN OUT PMRX_SRV_OPEN pSrvOpen,
+                                         IN PVOID pMRxContext,
+                                         OUT ULONG *pNewBufferingState);
+
+NTSTATUS VBoxMRxRead(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxWrite(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxLocks(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxFsCtl(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxIoCtl(IN OUT PRX_CONTEXT RxContext);
+NTSTATUS VBoxMRxNotifyChangeDirectory(IN OUT PRX_CONTEXT RxContext);
+
+NTSTATUS VBoxMRxExtendStub(IN OUT struct _RX_CONTEXT * RxContext,
+                           IN OUT PLARGE_INTEGER pNewFileSize,
+                           OUT PLARGE_INTEGER pNewAllocationSize);
+NTSTATUS VBoxMRxCompleteBufferingStateChangeRequest(IN OUT PRX_CONTEXT RxContext,
+                                                    IN OUT PMRX_SRV_OPEN SrvOpen,
+                                                    IN PVOID pContext);
+
+NTSTATUS VBoxMRxCreateVNetRoot(IN OUT PMRX_CREATENETROOT_CONTEXT pContext);
+NTSTATUS VBoxMRxFinalizeVNetRoot(IN OUT PMRX_V_NET_ROOT pVirtualNetRoot,
+                                 IN PBOOLEAN ForceDisconnect);
+NTSTATUS VBoxMRxFinalizeNetRoot(IN OUT PMRX_NET_ROOT pNetRoot,
+                                IN PBOOLEAN ForceDisconnect);
+NTSTATUS VBoxMRxUpdateNetRootState(IN PMRX_NET_ROOT pNetRoot);
+VOID VBoxMRxExtractNetRootName(IN PUNICODE_STRING FilePathName,
+                               IN PMRX_SRV_CALL SrvCall,
+                               OUT PUNICODE_STRING NetRootName,
+                               OUT PUNICODE_STRING RestOfName OPTIONAL);
+
+NTSTATUS VBoxMRxCreateSrvCall(PMRX_SRV_CALL pSrvCall,
+                              PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext);
+NTSTATUS VBoxMRxSrvCallWinnerNotify(IN OUT PMRX_SRV_CALL pSrvCall,
+                                    IN BOOLEAN ThisMinirdrIsTheWinner,
+                                    IN OUT PVOID pSrvCallContext);
+NTSTATUS VBoxMRxFinalizeSrvCall(PMRX_SRV_CALL pSrvCall,
+                                BOOLEAN Force);
+
+NTSTATUS VBoxMRxDevFcbXXXControlFile(IN OUT PRX_CONTEXT RxContext);
+
+/*
+ * Support functions.
+ */
+NTSTATUS vbsfDeleteConnection(IN PRX_CONTEXT RxContext,
+                              OUT PBOOLEAN PostToFsp);
+NTSTATUS vbsfCreateConnection(IN PRX_CONTEXT RxContext,
+                              OUT PBOOLEAN PostToFsp);
+
+NTSTATUS vbsfSetEndOfFile(IN OUT struct _RX_CONTEXT * RxContext,
+                          IN OUT PLARGE_INTEGER pNewFileSize,
+                          OUT PLARGE_INTEGER pNewAllocationSize);
+NTSTATUS vbsfRename(IN PRX_CONTEXT RxContext,
+                    IN FILE_INFORMATION_CLASS FileInformationClass,
+                    IN PVOID pBuffer,
+                    IN ULONG BufferLength);
+NTSTATUS vbsfRemove(IN PRX_CONTEXT RxContext);
+
+#endif /* VBSF_H */
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfhlp.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfhlp.c	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfhlp.c	(revision 40269)
@@ -0,0 +1,435 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver system helpers
+ */
+ 
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <ntifs.h>
+#include <ntdddisk.h>
+
+#include "vbsfhlp.h"
+
+#ifdef DEBUG
+static int s_iAllocRefCount = 0;
+#endif
+
+void vbsfHlpSleep (ULONG ulMillies)
+{
+    KEVENT event;
+    LARGE_INTEGER dueTime;
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    dueTime.QuadPart = -10000 * (int)ulMillies;
+
+    KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &dueTime);
+}
+
+/**
+ * Convert VBox IRT file attributes to NT file attributes
+ *
+ * @returns NT file attributes
+ * @param   fMode       IRT file attributes
+ *
+ */
+uint32_t VBoxToNTFileAttributes (uint32_t fMode)
+{
+    uint32_t FileAttributes = 0;
+
+    if (fMode & RTFS_DOS_READONLY)
+        FileAttributes |= FILE_ATTRIBUTE_READONLY;
+    if (fMode & RTFS_DOS_HIDDEN)
+        FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+    if (fMode & RTFS_DOS_SYSTEM)
+        FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
+    if (fMode & RTFS_DOS_DIRECTORY)
+        FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+    if (fMode & RTFS_DOS_ARCHIVED)
+        FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
+    if (fMode & RTFS_DOS_NT_TEMPORARY)
+        FileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
+    if (fMode & RTFS_DOS_NT_SPARSE_FILE)
+        FileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE;
+    if (fMode & RTFS_DOS_NT_REPARSE_POINT)
+        FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
+    if (fMode & RTFS_DOS_NT_COMPRESSED)
+        FileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
+    /*    if (fMode & RTFS_DOS_NT_OFFLINE) */
+    if (fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED)
+        FileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+    if (fMode & RTFS_DOS_NT_ENCRYPTED)
+        FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
+    if (fMode & RTFS_DOS_NT_NORMAL)
+    {
+        FileAttributes |= FILE_ATTRIBUTE_NORMAL;
+    }
+    return FileAttributes;
+}
+
+/**
+ * Convert VBox IRT file attributes to NT file attributes
+ *
+ * @returns NT file attributes
+ * @param   fMode       IRT file attributes
+ *
+ */
+uint32_t NTToVBoxFileAttributes (uint32_t fMode)
+{
+    uint32_t FileAttributes = 0;
+
+    if (fMode & FILE_ATTRIBUTE_READONLY)
+        FileAttributes |= RTFS_DOS_READONLY;
+    if (fMode & FILE_ATTRIBUTE_HIDDEN)
+        FileAttributes |= RTFS_DOS_HIDDEN;
+    if (fMode & FILE_ATTRIBUTE_SYSTEM)
+        FileAttributes |= RTFS_DOS_SYSTEM;
+    if (fMode & FILE_ATTRIBUTE_DIRECTORY)
+        FileAttributes |= RTFS_DOS_DIRECTORY;
+    if (fMode & FILE_ATTRIBUTE_ARCHIVE)
+        FileAttributes |= RTFS_DOS_ARCHIVED;
+    if (fMode & FILE_ATTRIBUTE_TEMPORARY)
+        FileAttributes |= RTFS_DOS_NT_TEMPORARY;
+    if (fMode & FILE_ATTRIBUTE_SPARSE_FILE)
+        FileAttributes |= RTFS_DOS_NT_SPARSE_FILE;
+    if (fMode & FILE_ATTRIBUTE_REPARSE_POINT)
+        FileAttributes |= RTFS_DOS_NT_REPARSE_POINT;
+    if (fMode & FILE_ATTRIBUTE_COMPRESSED)
+        FileAttributes |= RTFS_DOS_NT_COMPRESSED;
+    if (fMode & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+        FileAttributes |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
+    if (fMode & FILE_ATTRIBUTE_ENCRYPTED)
+        FileAttributes |= RTFS_DOS_NT_ENCRYPTED;
+    if (fMode & FILE_ATTRIBUTE_NORMAL)
+    {
+        FileAttributes |= RTFS_DOS_NT_NORMAL;
+    }
+    return FileAttributes;
+}
+
+NTSTATUS vbsfHlpCreateDriveLetter (WCHAR Letter, UNICODE_STRING *pDeviceName)
+{
+    UNICODE_STRING driveName;
+    RtlInitUnicodeString(&driveName,L"\\??\\_:" );
+
+    /* Replace '_' with actual drive letter */
+    driveName.Buffer[driveName.Length/sizeof(WCHAR) - 2] = Letter;
+
+    return IoCreateSymbolicLink (&driveName, pDeviceName);
+}
+
+NTSTATUS vbsfHlpDeleteDriveLetter (WCHAR Letter)
+{
+    UNICODE_STRING driveName;
+    RtlInitUnicodeString(&driveName,L"\\??\\_:" );
+
+    /* Replace '_' with actual drive letter */
+    driveName.Buffer[driveName.Length/sizeof(WCHAR) - 2] = Letter;
+
+    return IoDeleteSymbolicLink (&driveName);
+}
+
+    /**
+     * Convert VBox error code to NT status code
+     *
+     * @returns NT status code
+     * @param   vboxRC          VBox error code
+     *
+     */
+NTSTATUS VBoxErrorToNTStatus (int vboxRC)
+{
+    NTSTATUS Status;
+
+    switch (vboxRC)
+    {
+    case VINF_SUCCESS:
+        Status = STATUS_SUCCESS;
+        break;
+
+    case VERR_ACCESS_DENIED:
+        Status = STATUS_ACCESS_DENIED;
+        break;
+
+    case VERR_NO_MORE_FILES:
+        Status = STATUS_NO_MORE_FILES;
+        break;
+
+    case VERR_PATH_NOT_FOUND:
+        Status = STATUS_OBJECT_PATH_NOT_FOUND;
+        break;
+
+    case VERR_FILE_NOT_FOUND:
+        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        break;
+
+    case VERR_DIR_NOT_EMPTY:
+        Status = STATUS_DIRECTORY_NOT_EMPTY;
+        break;
+
+    case VERR_SHARING_VIOLATION:
+        Status = STATUS_SHARING_VIOLATION;
+        break;
+
+    case VERR_FILE_LOCK_VIOLATION:
+        Status = STATUS_FILE_LOCK_CONFLICT;
+        break;
+
+    case VERR_FILE_LOCK_FAILED:
+        Status = STATUS_LOCK_NOT_GRANTED;
+        break;
+
+    case VINF_BUFFER_OVERFLOW:
+        Status = STATUS_BUFFER_OVERFLOW;
+        break;
+
+    case VERR_EOF:
+    case VINF_EOF:
+        Status = STATUS_END_OF_FILE;
+        break;
+
+    case VERR_READ_ERROR:
+    case VERR_WRITE_ERROR:
+    case VERR_FILE_IO_ERROR:
+        Status = STATUS_UNEXPECTED_IO_ERROR;
+        break;
+
+    case VERR_WRITE_PROTECT:
+        Status = STATUS_MEDIA_WRITE_PROTECTED;
+        break;
+
+    case VERR_ALREADY_EXISTS:
+        Status = STATUS_OBJECT_NAME_COLLISION;
+        break;
+
+    case VERR_NOT_A_DIRECTORY:
+        Status = STATUS_NOT_A_DIRECTORY;
+        break;
+
+    case VERR_SEEK:
+        Status = STATUS_INVALID_PARAMETER;
+        break;
+
+    case VERR_INVALID_PARAMETER:
+        Status = STATUS_INVALID_PARAMETER;
+        break;
+
+    case VERR_NOT_SUPPORTED:
+        Status = STATUS_NOT_SUPPORTED;
+        break;
+
+    default:
+        /* @todo error handling */
+        Status = STATUS_INVALID_PARAMETER;
+        Log(("Unexpected vbox error %Rrc\n",
+             vboxRC));
+        break;
+    }
+    return Status;
+}
+
+PVOID vbsfAllocNonPagedMem (ULONG ulSize)
+{
+    PVOID pMemory = NULL;
+
+#ifdef DEBUG
+    s_iAllocRefCount = s_iAllocRefCount + 1;
+    Log(("vbsfAllocNonPagedMem: RefCnt after incrementing: %d\n", s_iAllocRefCount));
+#endif
+
+    /* Tag is reversed (a.k.a "SHFL") to display correctly in debuggers, so search for "SHFL" */
+    pMemory = ExAllocatePoolWithTag(NonPagedPool, ulSize, 'LFHS');
+
+    if (NULL != pMemory)
+    {
+        RtlZeroMemory(pMemory, ulSize);
+#ifdef DEBUG
+        Log(("vbsfAllocNonPagedMem: Allocated %d bytes of memory at %p.\n", ulSize, pMemory));
+#endif
+    }
+    else
+    {
+#ifdef DEBUG
+        Log(("vbsfAllocNonPagedMem: ERROR: Could not allocate %d bytes of memory!\n", ulSize));
+#endif
+    }
+
+    return pMemory;
+}
+
+void vbsfFreeNonPagedMem (PVOID lpMem)
+{
+#ifdef DEBUG
+    s_iAllocRefCount = s_iAllocRefCount - 1;
+    Log(("vbsfFreeNonPagedMem: RefCnt after decrementing: %d\n", s_iAllocRefCount));
+#endif
+
+    Assert(lpMem);
+
+    /* MSDN: The ExFreePoolWithTag routine issues a bug check if the specified value for Tag does not match the tag value passed
+     to the routine that originally allocated the memory block. Otherwise, the behavior of this routine is identical to ExFreePool. */
+    ExFreePoolWithTag(lpMem, 'LFHS');
+    lpMem = NULL;
+}
+
+#if 0 //def DEBUG
+/**
+ * Callback for RTLogFormatV which writes to the backdoor.
+ * See PFNLOGOUTPUT() for details.
+ */
+static DECLCALLBACK(size_t) rtLogBackdoorOutput(void *pv, const char *pachChars, size_t cbChars)
+{
+    RTLogWriteUser(pachChars, cbChars);
+    return cbChars;
+}
+
+int RTLogBackdoorPrintf1(const char *pszFormat, ...)
+{
+    va_list args;
+
+    LARGE_INTEGER time;
+
+    KeQueryTickCount(&time);
+
+    RTLogBackdoorPrintf("T=%RX64 ", time.QuadPart);
+    va_start(args, pszFormat);
+    RTLogFormatV(rtLogBackdoorOutput, NULL, pszFormat, args);
+    va_end(args);
+
+    return 0;
+}
+#endif
+
+#if defined(DEBUG) || defined (LOG_ENABLED)
+static PCHAR PnPMinorFunctionString(LONG MinorFunction)
+{
+    switch (MinorFunction)
+    {
+        case IRP_MN_START_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_START_DEVICE";
+        case IRP_MN_QUERY_REMOVE_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_REMOVE_DEVICE";
+        case IRP_MN_REMOVE_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_REMOVE_DEVICE";
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_CANCEL_REMOVE_DEVICE";
+        case IRP_MN_STOP_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_STOP_DEVICE";
+        case IRP_MN_QUERY_STOP_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_STOP_DEVICE";
+        case IRP_MN_CANCEL_STOP_DEVICE:
+            return "IRP_MJ_PNP - IRP_MN_CANCEL_STOP_DEVICE";
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_DEVICE_RELATIONS";
+        case IRP_MN_QUERY_INTERFACE:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_INTERFACE";
+        case IRP_MN_QUERY_CAPABILITIES:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_CAPABILITIES";
+        case IRP_MN_QUERY_RESOURCES:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_RESOURCES";
+        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
+        case IRP_MN_QUERY_DEVICE_TEXT:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_DEVICE_TEXT";
+        case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+            return "IRP_MJ_PNP - IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
+        case IRP_MN_READ_CONFIG:
+            return "IRP_MJ_PNP - IRP_MN_READ_CONFIG";
+        case IRP_MN_WRITE_CONFIG:
+            return "IRP_MJ_PNP - IRP_MN_WRITE_CONFIG";
+        case IRP_MN_EJECT:
+            return "IRP_MJ_PNP - IRP_MN_EJECT";
+        case IRP_MN_SET_LOCK:
+            return "IRP_MJ_PNP - IRP_MN_SET_LOCK";
+        case IRP_MN_QUERY_ID:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_ID";
+        case IRP_MN_QUERY_PNP_DEVICE_STATE:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_PNP_DEVICE_STATE";
+        case IRP_MN_QUERY_BUS_INFORMATION:
+            return "IRP_MJ_PNP - IRP_MN_QUERY_BUS_INFORMATION";
+        case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+            return "IRP_MJ_PNP - IRP_MN_DEVICE_USAGE_NOTIFICATION";
+        case IRP_MN_SURPRISE_REMOVAL:
+            return "IRP_MJ_PNP - IRP_MN_SURPRISE_REMOVAL";
+        default:
+            return "IRP_MJ_PNP - unknown_pnp_irp";
+    }
+}
+
+PCHAR MajorFunctionString(UCHAR MajorFunction, LONG MinorFunction)
+{
+    switch (MinorFunction)
+    {
+    case IRP_MJ_CREATE:
+        return "IRP_MJ_CREATE";
+    case IRP_MJ_CREATE_NAMED_PIPE:
+        return "IRP_MJ_CREATE_NAMED_PIPE";
+    case IRP_MJ_CLOSE:
+        return "IRP_MJ_CLOSE";
+    case IRP_MJ_READ:
+        return "IRP_MJ_READ";
+    case IRP_MJ_WRITE:
+        return "IRP_MJ_WRITE";
+    case IRP_MJ_QUERY_INFORMATION:
+        return "IRP_MJ_QUERY_INFORMATION";
+    case IRP_MJ_SET_INFORMATION:
+        return "IRP_MJ_SET_INFORMATION";
+    case IRP_MJ_QUERY_EA:
+        return "IRP_MJ_QUERY_EA";
+    case IRP_MJ_SET_EA:
+        return "IRP_MJ_SET_EA";
+    case IRP_MJ_FLUSH_BUFFERS:
+        return "IRP_MJ_FLUSH_BUFFERS";
+    case IRP_MJ_QUERY_VOLUME_INFORMATION:
+        return "IRP_MJ_QUERY_VOLUME_INFORMATION";
+    case IRP_MJ_SET_VOLUME_INFORMATION:
+        return "IRP_MJ_SET_VOLUME_INFORMATION";
+    case IRP_MJ_DIRECTORY_CONTROL:
+        return "IRP_MJ_DIRECTORY_CONTROL";
+    case IRP_MJ_FILE_SYSTEM_CONTROL:
+        return "IRP_MJ_FILE_SYSTEM_CONTROL";
+    case IRP_MJ_DEVICE_CONTROL:
+        return "IRP_MJ_DEVICE_CONTROL";
+    case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+        return "IRP_MJ_INTERNAL_DEVICE_CONTROL";
+    case IRP_MJ_SHUTDOWN:
+        return "IRP_MJ_SHUTDOWN";
+    case IRP_MJ_LOCK_CONTROL:
+        return "IRP_MJ_LOCK_CONTROL";
+    case IRP_MJ_CLEANUP:
+        return "IRP_MJ_CLEANUP";
+    case IRP_MJ_CREATE_MAILSLOT:
+        return "IRP_MJ_CREATE_MAILSLOT";
+    case IRP_MJ_QUERY_SECURITY:
+        return "IRP_MJ_QUERY_SECURITY";
+    case IRP_MJ_SET_SECURITY:
+        return "IRP_MJ_SET_SECURITY";
+    case IRP_MJ_POWER:
+        return "IRP_MJ_POWER";
+    case IRP_MJ_SYSTEM_CONTROL:
+        return "IRP_MJ_SYSTEM_CONTROL";
+    case IRP_MJ_DEVICE_CHANGE:
+        return "IRP_MJ_DEVICE_CHANGE";
+    case IRP_MJ_QUERY_QUOTA:
+        return "IRP_MJ_QUERY_QUOTA";
+    case IRP_MJ_SET_QUOTA:
+        return "IRP_MJ_SET_QUOTA";
+    case IRP_MJ_PNP:
+        return PnPMinorFunctionString(MinorFunction);
+
+    default:
+        return "unknown_pnp_irp";
+    }
+}
+#endif
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfhlp.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfhlp.h	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfhlp.h	(revision 40269)
@@ -0,0 +1,71 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver helpers
+ */
+
+/*
+ * Copyright (C) 2012 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 __VBSFHLP__H
+#define __VBSFHLP__H
+
+#include <ntifs.h>
+#include <ntverp.h>
+
+#include "VBoxGuestR0LibSharedFolders.h"
+
+/* Windows version identifier
+typedef enum
+{
+    UNKNOWN_WINVERSION = 0, WINNT4 = 1, WIN2K = 2, WINXP = 3
+} winVersion_t;
+
+void vbsfHlpSleep (ULONG ulMillies);
+NTSTATUS vbsfHlpCreateDriveLetter (WCHAR Letter, UNICODE_STRING *pDeviceName);
+NTSTATUS vbsfHlpDeleteDriveLetter (WCHAR Letter);
+
+/**
+ * Convert VBox IRT file attributes to NT file attributes
+ *
+ * @returns NT file attributes
+ * @param   fMode       IRT file attributes
+ *
+ */
+uint32_t VBoxToNTFileAttributes (uint32_t fMode);
+
+/**
+ * Convert VBox IRT file attributes to NT file attributes
+ *
+ * @returns NT file attributes
+ * @param   fMode       IRT file attributes
+ *
+ */
+uint32_t NTToVBoxFileAttributes (uint32_t fMode);
+
+/**
+ * Convert VBox error code to NT status code
+ *
+ * @returns NT status code
+ * @param   vboxRC          VBox error code
+ *
+ */
+NTSTATUS VBoxErrorToNTStatus (int vboxRC);
+
+PVOID vbsfAllocNonPagedMem (ULONG ulSize);
+void vbsfFreeNonPagedMem (PVOID lpMem);
+
+#if defined(DEBUG) || defined (LOG_ENABLED)
+PCHAR MajorFunctionString(UCHAR MajorFunction, LONG MinorFunction);
+#endif
+
+#endif /* __VBSFHLP__H */
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfshared.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfshared.h	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsfshared.h	(revision 40269)
@@ -0,0 +1,54 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver header file shared with the network provider dll
+ */
+
+/*
+ * Copyright (C) 2012 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 VBSFSHARED_H
+#define VBSFSHARED_H
+
+/* The network provider name for shared folders. */
+#define MRX_VBOX_PROVIDER_NAME_U L"VirtualBox Shared Folders"
+
+/* The filesystem name for shared folders. */
+#define MRX_VBOX_FILESYS_NAME_U L"VBoxSharedFolderFS"
+
+/* The redirector device name. */
+#define DD_MRX_VBOX_FS_DEVICE_NAME_U L"\\Device\\VBoxMiniRdr"
+
+#define VBOX_VOLNAME_PREFIX     L"VBOX_"
+#define VBOX_VOLNAME_PREFIX_SIZE  (sizeof(VBOX_VOLNAME_PREFIX) - sizeof(VBOX_VOLNAME_PREFIX[0]))
+
+/* Name of symbolic link, which is used by the user mode dll to open the driver. */
+#define DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U     L"\\??\\VBoxMiniRdrDN"
+#define DD_MRX_VBOX_USERMODE_DEV_NAME_U            L"\\\\.\\VBoxMiniRdrDN"
+
+#define IOCTL_MRX_VBOX_BASE FILE_DEVICE_NETWORK_FILE_SYSTEM
+
+#define _MRX_VBOX_CONTROL_CODE(request, method, access) \
+                CTL_CODE(IOCTL_MRX_VBOX_BASE, request, method, access)
+
+/* VBoxSF IOCTL codes. */
+#define IOCTL_MRX_VBOX_ADDCONN       _MRX_VBOX_CONTROL_CODE(100, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_GETCONN       _MRX_VBOX_CONTROL_CODE(101, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_DELCONN       _MRX_VBOX_CONTROL_CODE(102, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_GETLIST       _MRX_VBOX_CONTROL_CODE(103, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_GETGLOBALLIST _MRX_VBOX_CONTROL_CODE(104, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_GETGLOBALCONN _MRX_VBOX_CONTROL_CODE(105, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_START         _MRX_VBOX_CONTROL_CODE(106, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_STOP          _MRX_VBOX_CONTROL_CODE(107, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif /* VBSFSHARED_H */
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/np/Makefile.kmk
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/np/Makefile.kmk	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/np/Makefile.kmk	(revision 40269)
@@ -0,0 +1,48 @@
+# $Id$
+## @file
+# Sub-Makefile for the VirtualBox Windows Guest Shared Folders Network Provider.
+#
+
+#
+# Copyright (C) 2012 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
+
+DLLS += VBoxMRXNP
+VBoxMRXNP_TEMPLATE    = VBOXGUESTR3DLL
+VBoxMRXNP_SDKS        = WINDDK
+VBoxMRXNP_DEFS        = LOG_TO_BACKDOOR _WIN32_WINNT=0x0500 UNICODE WIN32_LEAN_AND_MEAN=1
+#VBoxMRXNP_DEFS       += LOG_ENABLED
+
+VBoxMRXNP_SOURCES     = \
+	vboxmrxnp.cpp \
+	vboxmrxnp.rc \
+	vboxmrxnp.def
+
+VBoxMRXNP_LIBS     = \
+	$(VBOX_LIB_IPRT_GUEST_R3) \
+	$(VBOX_LIB_VBGL_R3) \
+	$(VBOX_LIB_IPRT_GUEST_R3)
+
+#
+# VBoxMRXNP-x86 - x86 version of VBoxMRXNP built for amd64 build
+#
+DLLS.win.amd64 += VBoxMRXNP-x86
+VBoxMRXNP-x86_EXTENDS = VBoxMRXNP
+VBoxMRXNP-x86_BLD_TRG_ARCH = x86
+VBoxMRXNP-x86_LIBS = \
+	$(VBOX_LIB_IPRT_GUEST_R3_X86) \
+	$(VBOX_LIB_VBGL_R3_X86)
+VBoxMRXNP-x86_DEFS = $(VBoxMRXNP_DEFS) VBOX_WOW64
+
+include	$(KBUILD_PATH)/subfooter.kmk
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.cpp	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.cpp	(revision 40269)
@@ -0,0 +1,1616 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * Network provider dll
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <windows.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winsvc.h>
+#include <winnetwk.h>
+#include <npapi.h>
+#include <devioctl.h>
+#include <stdio.h>
+
+#include "..\driver\vbsfshared.h"
+
+#include <iprt/alloc.h>
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+#include <iprt/log.h>
+#include <VBox/version.h>
+#include <VBox/VMMDev.h>
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/Log.h>
+
+#define MRX_VBOX_SERVER_NAME_U     L"VBOXSVR"
+#define MRX_VBOX_SERVER_NAME_ALT_U L"VBOXSRV"
+
+#define WNNC_DRIVER(major, minor) (major * 0x00010000 + minor)
+
+static WCHAR vboxToUpper(WCHAR wc)
+{
+    /* The CharUpper parameter is a pointer to a null-terminated string,
+     * or specifies a single character. If the high-order word of this
+     * parameter is zero, the low-order word must contain a single character to be converted.
+     */
+    return (WCHAR)CharUpper((LPTSTR)wc);
+}
+
+static DWORD vbsfIOCTL(ULONG IoctlCode,
+                       PVOID InputDataBuf,
+                       ULONG InputDataLen,
+                       PVOID OutputDataBuf,
+                       PULONG pOutputDataLen)
+{
+    ULONG cbOut = 0;
+
+    if (!pOutputDataLen)
+    {
+        pOutputDataLen = &cbOut;
+    }
+
+    ULONG dwStatus = WN_SUCCESS;
+
+    HANDLE DeviceHandle = CreateFile(DD_MRX_VBOX_USERMODE_DEV_NAME_U,
+                                     GENERIC_READ | GENERIC_WRITE,
+                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                     (LPSECURITY_ATTRIBUTES)NULL,
+                                     OPEN_EXISTING,
+                                     0,
+                                     (HANDLE)NULL);
+
+    if (INVALID_HANDLE_VALUE != DeviceHandle)
+    {
+        BOOL fSuccess = DeviceIoControl(DeviceHandle,
+                                        IoctlCode,
+                                        InputDataBuf,
+                                        InputDataLen,
+                                        OutputDataBuf,
+                                        *pOutputDataLen,
+                                        pOutputDataLen,
+                                        NULL);
+
+        if (!fSuccess)
+        {
+            dwStatus = GetLastError();
+
+            Log(("VBOXNP: vbsfIOCTL: DeviceIoctl last error = %d\n", dwStatus));
+        }
+
+        CloseHandle(DeviceHandle);
+    }
+    else
+    {
+        dwStatus = GetLastError();
+
+        static int sLogged = 0;
+        if (!sLogged)
+        {
+            LogRel(("VBOXNP: vbsfIOCTL: Error opening device, last error = %d\n",
+                    dwStatus));
+            sLogged++;
+        }
+    }
+
+    return dwStatus;
+}
+
+DWORD APIENTRY NPGetCaps(DWORD nIndex)
+{
+    DWORD rc = 0;
+
+    Log(("VBOXNP: GetNetCaps: Index = 0x%x\n", nIndex));
+
+    switch (nIndex)
+    {
+        case WNNC_SPEC_VERSION:
+        {
+            rc = WNNC_SPEC_VERSION51;
+        } break;
+
+        case WNNC_NET_TYPE:
+        {
+            rc = WNNC_NET_RDR2SAMPLE;
+        } break;
+
+        case WNNC_DRIVER_VERSION:
+        {
+            rc = WNNC_DRIVER(1, 0);
+        } break;
+
+        case WNNC_CONNECTION:
+        {
+            vbsfIOCTL(IOCTL_MRX_VBOX_START, NULL, 0, NULL, NULL);
+
+            rc = WNNC_CON_GETCONNECTIONS |
+                 WNNC_CON_CANCELCONNECTION |
+                 WNNC_CON_ADDCONNECTION |
+                 WNNC_CON_ADDCONNECTION3;
+        } break;
+
+        case WNNC_ENUMERATION:
+        {
+            rc = WNNC_ENUM_LOCAL |
+                 WNNC_ENUM_GLOBAL |
+                 WNNC_ENUM_SHAREABLE;
+        } break;
+
+        case WNNC_START:
+        {
+            rc = WNNC_WAIT_FOR_START;
+            break;
+        }
+
+        case WNNC_DIALOG:
+        {
+            rc = WNNC_DLG_GETRESOURCEPARENT |
+                 WNNC_DLG_GETRESOURCEINFORMATION;
+        } break;
+
+        case WNNC_USER:
+        case WNNC_ADMIN:
+        default:
+        {
+            rc = 0;
+        } break;
+    }
+
+    return rc;
+}
+
+DWORD APIENTRY NPLogonNotify(PLUID lpLogonId,
+                             LPCWSTR lpAuthentInfoType,
+                             LPVOID lpAuthentInfo,
+                             LPCWSTR lpPreviousAuthentInfoType,
+                             LPVOID lpPreviousAuthentInfo,
+                             LPWSTR lpStationName,
+                             LPVOID StationHandle,
+                             LPWSTR *lpLogonScript)
+{
+    Log(("VBOXNP: NPLogonNotify\n"));
+    *lpLogonScript = NULL;
+    return WN_SUCCESS;
+}
+
+DWORD APIENTRY NPPasswordChangeNotify(LPCWSTR lpAuthentInfoType,
+                                      LPVOID lpAuthentInfo,
+                                      LPCWSTR lpPreviousAuthentInfoType,
+                                      LPVOID lpPreviousAuthentInfo,
+                                      LPWSTR lpStationName,
+                                      LPVOID StationHandle,
+                                      DWORD dwChangeInfo)
+{
+    Log(("VBOXNP: NPPasswordChangeNotify\n"));
+
+    SetLastError(WN_NOT_SUPPORTED);
+    return WN_NOT_SUPPORTED;
+}
+
+DWORD APIENTRY NPAddConnection(LPNETRESOURCE lpNetResource,
+                               LPWSTR lpPassword,
+                               LPWSTR lpUserName)
+{
+    Log(("VBOXNP: NPAddConnection\n"));
+    return NPAddConnection3(NULL, lpNetResource, lpPassword, lpUserName, 0);
+}
+
+DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
+                                LPNETRESOURCE lpNetResource,
+                                LPWSTR lpPassword,
+                                LPWSTR lpUserName,
+                                DWORD dwFlags)
+{
+    DWORD dwStatus = WN_SUCCESS;
+    WCHAR ConnectionName[256];
+    WCHAR LocalName[3];
+    BOOLEAN fLocalName = TRUE;
+
+    Log(("VBOXNP: NPAddConnection3: dwFlags = 0x%x\n", dwFlags));
+    Log(("VBOXNP: NPAddConnection3: Local Name:  %ls\n", lpNetResource->lpLocalName ));
+    Log(("VBOXNP: NPAddConnection3: Remote Name: %ls\n", lpNetResource->lpRemoteName ));
+
+    if (   lpNetResource->dwType != RESOURCETYPE_DISK
+        && lpNetResource->dwType != RESOURCETYPE_ANY)
+    {
+        Log(("VBOXNP: NPAddConnection3: Incorrect net resource type %d\n", lpNetResource->dwType));
+        return WN_BAD_NETNAME;
+    }
+
+    /* Build connection name: \Device\VBoxMiniRdr\;%DriveLetter%:\vboxsvr\share */
+
+    lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
+    lstrcat(ConnectionName, L"\\;");
+
+    if (lpNetResource->lpLocalName == NULL)
+    {
+        LocalName[0] = L'\0';
+        fLocalName = FALSE;
+    }
+    else
+    {
+        if (   lpNetResource->lpLocalName[0]
+            && lpNetResource->lpLocalName[1] == L':')
+        {
+            LocalName[0] = vboxToUpper(lpNetResource->lpLocalName[0]);
+            LocalName[1] = L':';
+            LocalName[2] = L'\0';
+
+            lstrcat(ConnectionName, LocalName);
+        }
+        else
+        {
+            dwStatus = WN_BAD_LOCALNAME;
+        }
+    }
+
+    
+    if (dwStatus == WN_SUCCESS)
+    {
+        /* Append the remote name. */
+        if (   lpNetResource->lpRemoteName
+            && lpNetResource->lpRemoteName[0] == L'\\'
+            && lpNetResource->lpRemoteName[1] == L'\\' )
+        {
+            /* No need for (lstrlen + 1), because 'lpNetResource->lpRemoteName' leading \ is not copied. */
+            if (lstrlen(ConnectionName) + lstrlen(lpNetResource->lpRemoteName) <= sizeof(ConnectionName) / sizeof(WCHAR))
+            {
+                lstrcat(ConnectionName, &lpNetResource->lpRemoteName[1]);
+            }
+            else
+            {
+                dwStatus = WN_BAD_NETNAME;
+            }
+        }
+        else
+        {
+            dwStatus = WN_BAD_NETNAME;
+        }
+    }
+
+    Log(("VBOXNP: NPAddConnection3: ConnectionName: [%ls], len %d, dwStatus 0x%08X\n",
+         ConnectionName, (lstrlen(ConnectionName) + 1) * sizeof(WCHAR), dwStatus));
+
+    if (dwStatus == WN_SUCCESS)
+    {
+        WCHAR wszTmp[128];
+
+        SetLastError(NO_ERROR);
+
+        if (   fLocalName
+            && QueryDosDevice(LocalName, wszTmp, sizeof(wszTmp) / sizeof(WCHAR)))
+        {
+            Log(("VBOXNP: NPAddConnection3: Connection [%ls] already connected.\n",
+                 ConnectionName));
+            dwStatus = WN_ALREADY_CONNECTED;
+        }
+        else
+        {
+            if (   !fLocalName
+                || GetLastError() == ERROR_FILE_NOT_FOUND)
+            {
+                dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_ADDCONN,
+                                     ConnectionName,
+                                     (lstrlen(ConnectionName) + 1) * sizeof(WCHAR),
+                                     NULL,
+                                     NULL);
+
+                if (dwStatus == WN_SUCCESS)
+                {
+                    if (   fLocalName
+                        && !DefineDosDevice(DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM,
+                                            lpNetResource->lpLocalName,
+                                            ConnectionName))
+                    {
+                        dwStatus = GetLastError();
+                    }
+                }
+                else
+                {
+                    dwStatus = WN_BAD_NETNAME;
+                }
+            }
+            else
+            {
+                dwStatus = WN_ALREADY_CONNECTED;
+            }
+        }
+    }
+
+    Log(("VBOXNP: NPAddConnection3: Returned 0x%08X\n",
+         dwStatus));
+    return dwStatus;
+}
+
+DWORD APIENTRY NPCancelConnection(LPWSTR lpName,
+                                  BOOL fForce)
+{
+    DWORD dwStatus = WN_NOT_CONNECTED;
+
+    Log(("VBOXNP: NPCancelConnection: Name = %ls\n",
+         lpName));
+
+    if (lpName && lpName[0] != 0)
+    {
+        WCHAR ConnectionName[256];
+
+        if (lpName[1] == L':')
+        {
+            WCHAR RemoteName[128];
+            WCHAR LocalName[3];
+
+            LocalName[0] = vboxToUpper(lpName[0]);
+            LocalName[1] = L':';
+            LocalName[2] = L'\0';
+
+            ULONG cbOut = sizeof(RemoteName) - sizeof(WCHAR); /* Trailing NULL. */
+
+            dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETCONN,
+                                 LocalName,
+                                 sizeof(LocalName),
+                                 (PVOID)RemoteName,
+                                 &cbOut);
+
+            if (   dwStatus == WN_SUCCESS
+                && cbOut > 0)
+            {
+                RemoteName[cbOut / sizeof(WCHAR)] = L'\0';
+
+                if (lstrlen(DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen(LocalName) + lstrlen(RemoteName) + 1 > sizeof(ConnectionName) / sizeof(WCHAR))
+                {
+                    dwStatus = WN_BAD_NETNAME;
+                }
+                else
+                {
+                    lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
+                    lstrcat(ConnectionName, L"\\;");
+                    lstrcat(ConnectionName, LocalName);
+                    lstrcat(ConnectionName, RemoteName);
+
+                    dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_DELCONN,
+                                         ConnectionName,
+                                         (lstrlen(ConnectionName) + 1) * sizeof(WCHAR),
+                                         NULL,
+                                         NULL);
+
+                    if (dwStatus == WN_SUCCESS)
+                    {
+                        if (!DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
+                                             LocalName,
+                                             ConnectionName))
+                        {
+                            dwStatus = GetLastError();
+                        }
+                    }
+                }
+            }
+            else
+            {
+                dwStatus = WN_NOT_CONNECTED;
+            }
+        }
+        else
+        {
+            BOOLEAN Verifier;
+
+            Verifier  = ( lpName[0] == L'\\' );
+            Verifier &= ( lpName[1] == L'V' ) || ( lpName[1] == L'v' );
+            Verifier &= ( lpName[2] == L'B' ) || ( lpName[2] == L'b' );
+            Verifier &= ( lpName[3] == L'O' ) || ( lpName[3] == L'o' );
+            Verifier &= ( lpName[4] == L'X' ) || ( lpName[4] == L'x' );
+            Verifier &= ( lpName[5] == L'S' ) || ( lpName[5] == L's' );
+            /* Both vboxsvr & vboxsrv are now accepted */
+            if (( lpName[6] == L'V' ) || ( lpName[6] == L'v'))
+            {
+                Verifier &= ( lpName[6] == L'V' ) || ( lpName[6] == L'v' );
+                Verifier &= ( lpName[7] == L'R' ) || ( lpName[7] == L'r' );
+            }
+            else
+            {
+                Verifier &= ( lpName[6] == L'R' ) || ( lpName[6] == L'r' );
+                Verifier &= ( lpName[7] == L'V' ) || ( lpName[7] == L'v' );
+            }
+            Verifier &= ( lpName[8] == L'\\') || ( lpName[8] == 0 );
+
+            if (Verifier)
+            {
+                /* Full remote path */
+                if (lstrlen(DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen(lpName) + 1 > sizeof(ConnectionName) / sizeof(WCHAR))
+                {
+                    dwStatus = WN_BAD_NETNAME;
+                }
+                else
+                {
+                    lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
+                    lstrcat(ConnectionName, L"\\;");
+                    lstrcat(ConnectionName, lpName);
+
+                    dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_DELCONN,
+                                         ConnectionName,
+                                         (lstrlen(ConnectionName) + 1) * sizeof(WCHAR),
+                                         NULL,
+                                         NULL);
+                }
+            }
+            else
+            {
+                dwStatus = WN_NOT_CONNECTED;
+            }
+        }
+    }
+
+    Log(("VBOXNP: NPCancelConnection: Returned 0x%08X\n",
+         dwStatus));
+    return dwStatus;
+}
+
+DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName,
+                               LPWSTR lpRemoteName,
+                               LPDWORD lpBufferSize)
+{
+    DWORD dwStatus = WN_NOT_CONNECTED;
+
+    WCHAR RemoteName[128];
+    ULONG cbOut = 0;
+
+    Log(("VBOXNP: NPGetConnection: lpLocalName = %ls\n",
+         lpLocalName));
+
+    if (lpLocalName && lpLocalName[0] != 0)
+    {
+        if (lpLocalName[1] == L':')
+        {
+            WCHAR LocalName[3];
+
+            cbOut = sizeof(RemoteName) - sizeof(WCHAR);
+            RemoteName[cbOut / sizeof(WCHAR)] = 0;
+
+            LocalName[0] = vboxToUpper(lpLocalName[0]);
+            LocalName[1] = L':';
+            LocalName[2] = L'\0';
+
+            dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETCONN,
+                                 LocalName,
+                                 sizeof(LocalName),
+                                 (PVOID)RemoteName,
+                                 &cbOut);
+
+            if (dwStatus != NO_ERROR)
+            {
+                /* The device specified by lpLocalName is not redirected by this provider. */
+                dwStatus = WN_NOT_CONNECTED;
+            }
+            else
+            {
+                RemoteName[cbOut / sizeof(WCHAR)] = 0;
+
+                if (cbOut == 0)
+                {
+                    dwStatus = WN_NO_NETWORK;
+                }
+            }
+        }
+    }
+
+    if (dwStatus == WN_SUCCESS)
+    {
+        Log(("VBOXNP: NPGetConnection: RemoteName: %ls\n",
+             RemoteName));
+
+        ULONG cbRemoteName = (lstrlen(RemoteName) + 1) * sizeof (WCHAR); /* Including the trailing 0. */
+
+        DWORD len = sizeof(WCHAR) + cbRemoteName; /* Including the leading '\'. */
+
+        if (*lpBufferSize >= len)
+        {
+            lpRemoteName[0] = L'\\';
+            CopyMemory(&lpRemoteName[1], RemoteName, cbRemoteName);
+
+            Log(("VBOXNP: NPGetConnection: returning lpRemoteName: %ls\n",
+                 lpRemoteName));
+        }
+        else
+        {
+            if (*lpBufferSize != 0)
+            {
+                /* Log only real errors. Do not log a 0 bytes try. */
+                Log(("VBOXNP: NPGetConnection: Buffer overflow: *lpBufferSize = %d, len = %d\n",
+                     *lpBufferSize, len));
+            }
+
+            dwStatus = WN_MORE_DATA;
+        }
+
+        *lpBufferSize = len;
+    }
+
+    if ((dwStatus != WN_SUCCESS) &&
+        (dwStatus != WN_MORE_DATA))
+    {
+        Log(("VBOXNP: NPGetConnection: Returned error 0x%08X\n",
+             dwStatus));
+    }
+
+    return dwStatus;
+}
+
+static const WCHAR *vboxSkipServerPrefix(const WCHAR *lpRemoteName, const WCHAR *lpPrefix)
+{
+    while (*lpPrefix)
+    {
+        if (vboxToUpper(*lpPrefix) != vboxToUpper(*lpRemoteName))
+        {
+            /* Not a prefix */
+            return NULL;
+        }
+
+        lpPrefix++;
+        lpRemoteName++;
+    }
+
+    return lpRemoteName;
+}
+
+static const WCHAR *vboxSkipServerName(const WCHAR *lpRemoteName)
+{
+    int cLeadingBackslashes = 0;
+    while (*lpRemoteName == L'\\')
+    {
+        lpRemoteName++;
+        cLeadingBackslashes++;
+    }
+
+    if (cLeadingBackslashes == 0 || cLeadingBackslashes == 2)
+    {
+        const WCHAR *lpAfterPrefix = vboxSkipServerPrefix(lpRemoteName, MRX_VBOX_SERVER_NAME_U);
+
+        if (!lpAfterPrefix)
+        {
+            lpAfterPrefix = vboxSkipServerPrefix(lpRemoteName, MRX_VBOX_SERVER_NAME_ALT_U);
+        }
+
+        return lpAfterPrefix;
+    }
+
+    return NULL;
+}
+
+/* Enumerate shared folders as hierarchy:
+ * VBOXSVR(container)
+ * +--------------------+
+ * |                     \
+ * Folder1(connectable)  FolderN(connectable)
+ */
+typedef struct _NPENUMCTX
+{
+    ULONG index; /* Index of last entry returned. */
+    DWORD dwScope;
+    DWORD dwOriginalScope;
+    DWORD dwType;
+    DWORD dwUsage;
+    bool fRoot;
+} NPENUMCTX;
+
+DWORD APIENTRY NPOpenEnum(DWORD dwScope,
+                          DWORD dwType,
+                          DWORD dwUsage,
+                          LPNETRESOURCE lpNetResource,
+                          LPHANDLE lphEnum)
+{
+    DWORD dwStatus;
+
+    Log(("VBOXNP: NPOpenEnum: dwScope 0x%08X, dwType 0x%08X, dwUsage 0x%08X, lpNetResource %p\n",
+         dwScope, dwType, dwUsage, lpNetResource));
+
+    if (dwUsage == 0)
+    {
+        /* The bitmask may be zero to match all of the flags. */
+        dwUsage = RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER;
+    }
+
+    *lphEnum = NULL;
+
+    /* Allocate the context structure. */
+    NPENUMCTX *pCtx = (NPENUMCTX *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NPENUMCTX));
+
+    if (pCtx == NULL)
+    {
+        dwStatus = WN_OUT_OF_MEMORY;
+    }
+    else
+    {
+        if (lpNetResource && lpNetResource->lpRemoteName)
+        {
+            Log(("VBOXNP: NPOpenEnum: lpRemoteName %ls\n",
+                 lpNetResource->lpRemoteName));
+        }
+
+        switch (dwScope)
+        {
+            case 6: /* Advertised as WNNC_ENUM_SHAREABLE. This returns C$ system shares.
+                     * NpEnumResource will return NO_MORE_ENTRIES.
+                     */
+            {
+                if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
+                {
+                    /* If it is NULL or if the lpRemoteName field of the NETRESOURCE is NULL,
+                     * the provider should enumerate the top level of its network.
+                     * But system shares can't be on top level.
+                     */
+                    dwStatus = WN_NOT_CONTAINER;
+                    break;
+                }
+
+                const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName);
+                if (   lpAfterName == NULL
+                    || (*lpAfterName != L'\\' && *lpAfterName != 0))
+                {
+                    dwStatus = WN_NOT_CONTAINER;
+                    break;
+                }
+
+                /* Valid server name. */
+
+                pCtx->index = 0;
+                pCtx->dwScope = 6;
+                pCtx->dwOriginalScope = dwScope;
+                pCtx->dwType = dwType;
+                pCtx->dwUsage = dwUsage;
+
+                dwStatus = WN_SUCCESS;
+                break;
+            }
+            case RESOURCE_GLOBALNET: /* All resources on the network. */
+            {
+                if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
+                {
+                    /* If it is NULL or if the lpRemoteName field of the NETRESOURCE is NULL,
+                     * the provider should enumerate the top level of its network.
+                     */
+                    pCtx->fRoot = true;
+                }
+                else
+                {
+                    /* Enumerate lpNetResource->lpRemoteName container, which can be only the VBOXSVR container. */
+                    const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName);
+                    if (   lpAfterName == NULL
+                        || (*lpAfterName != L'\\' && *lpAfterName != 0))
+                    {
+                        dwStatus = WN_NOT_CONTAINER;
+                        break;
+                    }
+
+                    /* Valid server name. */
+                    pCtx->fRoot = false;
+                }
+
+                pCtx->index = 0;
+                pCtx->dwScope = RESOURCE_GLOBALNET;
+                pCtx->dwOriginalScope = dwScope;
+                pCtx->dwType = dwType;
+                pCtx->dwUsage = dwUsage;
+
+                dwStatus = WN_SUCCESS;
+                break;
+            }
+
+            case RESOURCE_CONNECTED: /* All currently connected resources. */
+            case RESOURCE_CONTEXT: /* The interpretation of this is left to the provider. Treat this as RESOURCE_GLOBALNET. */
+            {
+                pCtx->index = 0;
+                pCtx->dwScope = RESOURCE_CONNECTED;
+                pCtx->dwOriginalScope = dwScope;
+                pCtx->dwType = dwType;
+                pCtx->dwUsage = dwUsage;
+                pCtx->fRoot = false; /* Actually ignored for RESOURCE_CONNECTED. */
+
+                dwStatus = WN_SUCCESS;
+                break;
+            }
+
+            default:
+                Log(("VBOXNP: NPOpenEnum: unsupported scope 0x%lx\n",
+                     dwScope));
+                dwStatus = WN_NOT_SUPPORTED;
+                break;
+        }
+    }
+
+    if (dwStatus != WN_SUCCESS)
+    {
+        Log(("VBOXNP: NPOpenEnum: Returned error 0x%08X\n", 
+             dwStatus));
+        if (pCtx)
+        {
+            HeapFree(GetProcessHeap(), 0, pCtx);
+        }
+    }
+    else
+    {
+        Log(("VBOXNP: NPOpenEnum: pCtx %p\n",
+             pCtx));
+        *lphEnum = pCtx;
+    }
+
+    return dwStatus;
+}
+
+DWORD APIENTRY NPEnumResource(HANDLE hEnum,
+                              LPDWORD lpcCount,
+                              LPVOID lpBuffer,
+                              LPDWORD lpBufferSize)
+{
+    DWORD dwStatus = WN_SUCCESS;
+    NPENUMCTX *pCtx = (NPENUMCTX *)hEnum;
+
+    BYTE ConnectionList[26];
+    ULONG cbOut;
+    WCHAR LocalName[3];
+    WCHAR RemoteName[128];
+    int cbRemoteName;
+
+    ULONG cbEntry = 0;
+
+    Log(("VBOXNP: NPEnumResource: hEnum %p, lpcCount %p, lpBuffer %p, lpBufferSize %p.\n",
+         hEnum, lpcCount, lpBuffer, lpBufferSize));
+
+    if (pCtx == NULL)
+    {
+        Log(("VBOXNP: NPEnumResource: WN_BAD_HANDLE\n"));
+        return WN_BAD_HANDLE;
+    }
+
+    if (lpcCount == NULL || lpBuffer == NULL)
+    {
+        Log(("VBOXNP: NPEnumResource: WN_BAD_VALUE\n"));
+        return WN_BAD_VALUE;
+    }
+
+    Log(("VBOXNP: NPEnumResource: *lpcCount 0x%x, *lpBufferSize 0x%x, pCtx->index %d\n",
+         *lpcCount, *lpBufferSize, pCtx->index));
+
+    LPNETRESOURCE pNetResource = (LPNETRESOURCE)lpBuffer;
+    ULONG cbRemaining = *lpBufferSize;
+    ULONG cEntriesCopied = 0;
+    PWCHAR pStrings = (PWCHAR)((PBYTE)lpBuffer + *lpBufferSize);
+    PWCHAR pDst;
+
+    if (pCtx->dwScope == RESOURCE_CONNECTED)
+    {
+        Log(("VBOXNP: NPEnumResource: RESOURCE_CONNECTED\n"));
+
+        memset(ConnectionList, 0, sizeof(ConnectionList));
+        cbOut = sizeof(ConnectionList);
+
+        dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETLIST,
+                             NULL, 0,
+                             ConnectionList,
+                             &cbOut);
+
+        if (dwStatus == WN_SUCCESS && cbOut > 0)
+        {
+            while (cEntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList))
+            {
+                if (ConnectionList[pCtx->index])
+                {
+                    LocalName[0] = L'A' + (WCHAR)pCtx->index;
+                    LocalName[1] = L':';
+                    LocalName[2] = L'\0';
+                    memset(RemoteName, 0, sizeof(RemoteName));
+                    cbOut = sizeof(RemoteName);
+
+                    dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETCONN,
+                                         LocalName,
+                                         sizeof(LocalName),
+                                         RemoteName,
+                                         &cbOut);
+
+                    if (dwStatus != WN_SUCCESS || cbOut == 0)
+                    {
+                        dwStatus = WN_NO_MORE_ENTRIES;
+                        break;
+                    }
+
+                    /* How many bytes is needed for the current NETRESOURCE data. */
+                    cbRemoteName = (lstrlen(RemoteName) + 1) * sizeof(WCHAR);
+                    cbEntry = sizeof(NETRESOURCE);
+                    cbEntry += sizeof(LocalName);
+                    cbEntry += sizeof(WCHAR) + cbRemoteName; /* Leading \. */
+                    cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U);
+
+                    if (cbEntry > cbRemaining)
+                    {
+                        break;
+                    }
+
+                    cbRemaining -= cbEntry;
+
+                    memset(pNetResource, 0, sizeof (*pNetResource));
+
+                    pNetResource->dwScope = RESOURCE_CONNECTED;
+                    pNetResource->dwType = RESOURCETYPE_DISK;
+                    pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+                    pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+                    /* Reserve the space in the string area. */
+                    pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+                    pDst = pStrings;
+
+                    pNetResource->lpLocalName = pDst;
+                    *pDst++ = L'A' + (WCHAR)pCtx->index;
+                    *pDst++ = L':';
+                    *pDst++ = L'\0';
+
+                    pNetResource->lpRemoteName = pDst;
+                    *pDst++ = L'\\';
+                    CopyMemory(pDst, RemoteName, cbRemoteName);
+                    pDst += cbRemoteName / sizeof(WCHAR);
+                    
+                    pNetResource->lpComment = NULL;
+
+                    pNetResource->lpProvider = pDst;
+                    CopyMemory(pDst, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+
+                    Log(("VBOXNP: NPEnumResource: lpRemoteName: %ls\n",
+                         pNetResource->lpRemoteName));
+
+                    cEntriesCopied++;
+                    pNetResource++;
+                }
+
+                pCtx->index++;
+            }
+        }
+        else
+        {
+            dwStatus = WN_NO_MORE_ENTRIES;
+        }
+    }
+    else if (pCtx->dwScope == RESOURCE_GLOBALNET)
+    {
+        Log(("VBOXNP: NPEnumResource: RESOURCE_GLOBALNET: root %d\n", pCtx->fRoot));
+
+        if (pCtx->fRoot)
+        {
+            /* VBOXSVR container. */
+            if (pCtx->index > 0)
+            {
+                dwStatus = WN_NO_MORE_ENTRIES;
+            }
+            else
+            {
+                /* Return VBOXSVR server.
+                 * Determine the space needed for this entry.
+                 */
+                cbEntry = sizeof(NETRESOURCE);
+                cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + the server name */
+                cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U);
+
+                if (cbEntry > cbRemaining)
+                {
+                    /* Do nothing. */
+                }
+                else
+                {
+                    cbRemaining -= cbEntry;
+
+                    memset(pNetResource, 0, sizeof (*pNetResource));
+
+                    pNetResource->dwScope = RESOURCE_GLOBALNET;
+                    pNetResource->dwType = RESOURCETYPE_ANY;
+                    pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+                    pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
+
+                    pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+                    pDst = pStrings;
+
+                    pNetResource->lpLocalName = NULL;
+
+                    pNetResource->lpRemoteName = pDst;
+                    *pDst++ = L'\\';
+                    *pDst++ = L'\\';
+                    CopyMemory(pDst, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U));
+                    pDst += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR);
+
+                    pNetResource->lpComment = NULL;
+
+                    pNetResource->lpProvider = pDst;
+                    CopyMemory(pDst, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+
+                    cEntriesCopied++;
+
+                    pCtx->index++;
+                }
+            }
+        }
+        else
+        {
+            /* Shares of VBOXSVR. */
+            memset(ConnectionList, 0, sizeof (ConnectionList));
+            cbOut = sizeof(ConnectionList);
+
+            dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETGLOBALLIST,
+                                 NULL,
+                                 0,
+                                 ConnectionList,
+                                 &cbOut);
+
+            if (dwStatus == WN_SUCCESS && cbOut > 0)
+            {
+                while (cEntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList))
+                {
+                    if (ConnectionList[pCtx->index])
+                    {
+                        memset(RemoteName, 0, sizeof(RemoteName));
+                        cbOut = sizeof(RemoteName);
+
+                        dwStatus = vbsfIOCTL(IOCTL_MRX_VBOX_GETGLOBALCONN,
+                                             &ConnectionList[pCtx->index],
+                                             sizeof(ConnectionList[pCtx->index]),
+                                             RemoteName,
+                                             &cbOut);
+
+                        if (dwStatus != WN_SUCCESS || cbOut == 0)
+                        {
+                            dwStatus = WN_NO_MORE_ENTRIES;
+                            break;
+                        }
+
+                        /* How many bytes is needed for the current NETRESOURCE data. */
+                        cbRemoteName = (lstrlen(RemoteName) + 1) * sizeof(WCHAR);
+                        cbEntry = sizeof(NETRESOURCE);
+                        /* Remote name: \\ + vboxsvr + \ + name. */
+                        cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U) + cbRemoteName;
+                        cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U);
+
+                        if (cbEntry > cbRemaining)
+                        {
+                            break;
+                        }
+
+                        cbRemaining -= cbEntry;
+
+                        memset(pNetResource, 0, sizeof (*pNetResource));
+
+                        pNetResource->dwScope = pCtx->dwOriginalScope;
+                        pNetResource->dwType = RESOURCETYPE_DISK;
+                        pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+                        pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+                        pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+                        pDst = pStrings;
+
+                        pNetResource->lpLocalName = NULL;
+
+                        pNetResource->lpRemoteName = pDst;
+                        *pDst++ = L'\\';
+                        *pDst++ = L'\\';
+                        CopyMemory(pDst, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof(WCHAR));
+                        pDst += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
+                        *pDst++ = L'\\';
+                        CopyMemory(pDst, RemoteName, cbRemoteName);
+                        pDst += cbRemoteName / sizeof(WCHAR);
+
+                        pNetResource->lpComment = NULL;
+
+                        pNetResource->lpProvider = pDst;
+                        CopyMemory(pDst, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+
+                        Log(("VBOXNP: NPEnumResource: lpRemoteName: %ls\n",
+                             pNetResource->lpRemoteName));
+
+                        cEntriesCopied++;
+                        pNetResource++;
+                    }
+
+                    pCtx->index++;
+                }
+            }
+            else
+            {
+                dwStatus = WN_NO_MORE_ENTRIES;
+            }
+        }
+    }
+    else if (pCtx->dwScope == 6)
+    {
+        Log(("VBOXNP: NPEnumResource: dwScope 6\n"));
+        dwStatus = WN_NO_MORE_ENTRIES;
+    }
+    else
+    {
+        Log(("VBOXNP: NPEnumResource: invalid dwScope 0x%x\n",
+             pCtx->dwScope));
+        return WN_BAD_HANDLE;
+    }
+
+    *lpcCount = cEntriesCopied;
+
+    if (cEntriesCopied == 0 && dwStatus == WN_SUCCESS)
+    {
+        if (pCtx->index >= RTL_NUMBER_OF(ConnectionList))
+        {
+            dwStatus = WN_NO_MORE_ENTRIES;
+        }
+        else
+        {
+            Log(("VBOXNP: NPEnumResource: More Data Needed - %d\n",
+                 cbEntry));
+            *lpBufferSize = cbEntry;
+            dwStatus = WN_MORE_DATA;
+        }
+    }
+
+    Log(("VBOXNP: NPEnumResource: Entries returned %d, dwStatus 0x%08X\n",
+         cEntriesCopied, dwStatus));
+    return dwStatus;
+}
+
+DWORD APIENTRY NPCloseEnum(HANDLE hEnum)
+{
+    DWORD dwStatus = WN_SUCCESS;
+    NPENUMCTX *pCtx = (NPENUMCTX *)hEnum;
+
+    Log(("VBOXNP: NPCloseEnum: hEnum %p\n",
+         hEnum));
+
+    if (pCtx)
+    {
+        HeapFree(GetProcessHeap(), 0, pCtx);
+    }
+
+    Log(("VBOXNP: NPCloseEnum: returns\n"));
+    return WN_SUCCESS;
+}
+
+DWORD APIENTRY NPGetResourceParent(LPNETRESOURCE lpNetResource,
+                                   LPVOID lpBuffer,
+                                   LPDWORD lpBufferSize)
+{
+    Log(("VBOXNP: NPGetResourceParent: lpNetResource %p, lpBuffer %p, lpBufferSize %p\n",
+         lpNetResource, lpBuffer, lpBufferSize));
+
+    /* Construct a new NETRESOURCE which is syntactically a parent of lpNetResource,
+     * then call NPGetResourceInformation to actually fill the buffer.
+     */
+    if (!lpNetResource || !lpNetResource->lpRemoteName || !lpBufferSize)
+    {
+        return WN_BAD_NETNAME;
+    }
+
+    const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName);
+    if (   lpAfterName == NULL
+        || (*lpAfterName != L'\\' && *lpAfterName != 0))
+    {
+        Log(("VBOXNP: NPGetResourceParent: WN_BAD_NETNAME\n"));
+        return WN_BAD_NETNAME;
+    }
+
+    DWORD RemoteNameLength = lstrlen(lpNetResource->lpRemoteName);
+
+    DWORD cbEntry = sizeof (NETRESOURCE);
+    cbEntry += (RemoteNameLength + 1) * sizeof (WCHAR);
+
+    NETRESOURCE *pParent = (NETRESOURCE *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbEntry);
+
+    if (!pParent)
+    {
+        return WN_OUT_OF_MEMORY;
+    }
+
+    pParent->lpRemoteName = (WCHAR *)((PBYTE)pParent + sizeof (NETRESOURCE));
+    lstrcpy(pParent->lpRemoteName, lpNetResource->lpRemoteName);
+
+    /* Remove last path component of the pParent->lpRemoteName. */
+    WCHAR *pLastSlash = pParent->lpRemoteName + RemoteNameLength;
+    if (*pLastSlash == L'\\')
+    {
+        /* \\server\share\path\, skip last slash immediately. */
+        pLastSlash--;
+    }
+
+    while (pLastSlash != pParent->lpRemoteName)
+    {
+        if (*pLastSlash == L'\\')
+        {
+            break;
+        }
+
+        pLastSlash--;
+    }
+
+    DWORD dwStatus = WN_SUCCESS;
+
+    if (   pLastSlash == pParent->lpRemoteName
+        || pLastSlash == pParent->lpRemoteName + 1)
+    {
+        /* It is a leading backslash. Construct "no parent" NETRESOURCE. */
+        NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
+
+        cbEntry = sizeof(NETRESOURCE);
+        cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* remote name */
+        cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+        if (cbEntry > *lpBufferSize)
+        {
+            Log(("VBOXNP: NPGetResourceParent: WN_MORE_DATA 0x%x\n", cbEntry));
+            *lpBufferSize = cbEntry;
+            dwStatus = WN_MORE_DATA;
+        }
+        else
+        {
+            memset (pNetResource, 0, sizeof (*pNetResource));
+
+            pNetResource->dwType = RESOURCETYPE_ANY;
+            pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
+            pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
+
+            WCHAR *pStrings = (WCHAR *)((PBYTE)lpBuffer + *lpBufferSize);
+            pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+
+            pNetResource->lpRemoteName = pStrings;
+            CopyMemory (pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+            pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+            pNetResource->lpProvider = pStrings;
+            CopyMemory (pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+            pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+            Log(("VBOXNP: NPGetResourceParent: no parent, strings %p/%p\n",
+                 pStrings, (PBYTE)lpBuffer + *lpBufferSize));
+        }
+    }
+    else
+    {
+        /* Make the parent remote name and get its information. */
+        *pLastSlash = 0;
+
+        LPWSTR lpSystem = NULL;
+        dwStatus = NPGetResourceInformation (pParent, lpBuffer, lpBufferSize, &lpSystem);
+    }
+
+    if (pParent)
+    {
+        HeapFree(GetProcessHeap(), 0, pParent);
+    }
+
+    return dwStatus;
+}
+
+DWORD APIENTRY NPGetResourceInformation(LPNETRESOURCE lpNetResource,
+                                        LPVOID lpBuffer,
+                                        LPDWORD lpBufferSize,
+                                        LPWSTR *lplpSystem)
+{
+    Log(("VBOXNP: NPGetResourceInformation: lpNetResource %p, lpBuffer %p, lpBufferSize %p, lplpSystem %p\n",
+         lpNetResource, lpBuffer, lpBufferSize, lplpSystem));
+
+    if (   lpNetResource == NULL
+        || lpNetResource->lpRemoteName == NULL
+        || lpBufferSize == NULL)
+    {
+        Log(("VBOXNP: NPGetResourceInformation: WN_BAD_VALUE\n"));
+        return WN_BAD_VALUE;
+    }
+
+    Log(("VBOXNP: NPGetResourceInformation: lpRemoteName %ls, *lpBufferSize 0x%x\n",
+         lpNetResource->lpRemoteName, *lpBufferSize));
+
+    const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName);
+    if (   lpAfterName == NULL
+        || (*lpAfterName != L'\\' && *lpAfterName != 0))
+    {
+        Log(("VBOXNP: NPGetResourceInformation: WN_BAD_NETNAME\n"));
+        return WN_BAD_NETNAME;
+    }
+
+    if (lpNetResource->dwType != 0 && lpNetResource->dwType != RESOURCETYPE_DISK)
+    {
+        /* The caller passed in a nonzero dwType that does not match
+         * the actual type of the network resource.
+         */
+        return WN_BAD_DEV_TYPE;
+    }
+
+    /*
+     * If the input remote resource name was "\\server\share\dir1\dir2",
+     * then the output NETRESOURCE contains information about the resource "\\server\share".
+     * The lpRemoteName, lpProvider, dwType, dwDisplayType, and dwUsage fields are returned
+     * containing values, all other fields being set to NULL.
+     */
+    DWORD cbEntry;
+    WCHAR *pStrings = (WCHAR *)((PBYTE)lpBuffer + *lpBufferSize);
+    NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
+
+    /* Check what kind of the resource is that by parsing path components.
+     * lpAfterName points to first WCHAR after a valid server name.
+     */
+
+    if (lpAfterName[0] == 0 || lpAfterName[1] == 0)
+    {
+        /* "\\VBOXSVR" or "\\VBOXSVR\" */
+        cbEntry = sizeof(NETRESOURCE);
+        cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name */
+        cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+        if (cbEntry > *lpBufferSize)
+        {
+            Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", cbEntry));
+            *lpBufferSize = cbEntry;
+            return WN_MORE_DATA;
+        }
+
+        memset(pNetResource, 0, sizeof (*pNetResource));
+
+        pNetResource->dwType = RESOURCETYPE_ANY;
+        pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+        pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
+
+        pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+
+        pNetResource->lpRemoteName = pStrings;
+        *pStrings++ = L'\\';
+        *pStrings++ = L'\\';
+        CopyMemory (pStrings, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U));
+        pStrings += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR);
+
+        pNetResource->lpProvider = pStrings;
+        CopyMemory (pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+        pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+        Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n",
+             pNetResource->lpRemoteName, pStrings, (PBYTE)lpBuffer + *lpBufferSize));
+
+        if (lplpSystem)
+        {
+            *lplpSystem = NULL;
+        }
+
+        return WN_SUCCESS;
+    }
+
+    /* *lpAfterName == L'\\', could be share or share + path.
+     * Check if there are more path components after the share name.
+     */
+    const WCHAR *lp = lpAfterName + 1;
+    while (*lp && *lp != L'\\')
+    {
+        lp++;
+    }
+
+    if (*lp == 0)
+    {
+        /* It is a share only: \\vboxsvr\share */
+        cbEntry = sizeof(NETRESOURCE);
+        cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */
+        cbEntry += (DWORD)((lp - lpAfterName) * sizeof(WCHAR)); /* The share name with leading \\ */
+        cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+        if (cbEntry > *lpBufferSize)
+        {
+            Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", cbEntry));
+            *lpBufferSize = cbEntry;
+            return WN_MORE_DATA;
+        }
+
+        memset(pNetResource, 0, sizeof (*pNetResource));
+
+        pNetResource->dwType = RESOURCETYPE_DISK;
+        pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+        pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+        pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+
+        pNetResource->lpRemoteName = pStrings;
+        *pStrings++ = L'\\';
+        *pStrings++ = L'\\';
+        CopyMemory(pStrings, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR));
+        pStrings += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
+        CopyMemory (pStrings, lpAfterName, (lp - lpAfterName + 1) * sizeof(WCHAR));
+        pStrings += lp - lpAfterName + 1;
+
+        pNetResource->lpProvider = pStrings;
+        CopyMemory(pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+        pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+        Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n",
+             pNetResource->lpRemoteName, pStrings, (PBYTE)lpBuffer + *lpBufferSize));
+
+        if (lplpSystem)
+        {
+            *lplpSystem = NULL;
+        }
+
+        return WN_SUCCESS;
+    }
+
+    /* \\vboxsvr\share\path */
+    cbEntry = sizeof(NETRESOURCE);
+    cbEntry += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */
+    cbEntry += (DWORD)((lp - lpAfterName) * sizeof(WCHAR)); /* The share name with leading \\ */
+    cbEntry += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+    cbEntry += (lstrlen(lp) + 1) * sizeof (WCHAR); /* path string for lplpSystem */
+
+    if (cbEntry > *lpBufferSize)
+    {
+        Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", cbEntry));
+        *lpBufferSize = cbEntry;
+        return WN_MORE_DATA;
+    }
+
+    memset(pNetResource, 0, sizeof (*pNetResource));
+
+    pNetResource->dwType = RESOURCETYPE_DISK;
+    pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+    pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+    pStrings = (PWCHAR)((PBYTE)pStrings - (cbEntry - sizeof(NETRESOURCE)));
+
+    /* The server + share. */
+    pNetResource->lpRemoteName = pStrings;
+    *pStrings++ = L'\\';
+    *pStrings++ = L'\\';
+    CopyMemory (pStrings, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR));
+    pStrings += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
+    CopyMemory(pStrings, lpAfterName, (lp - lpAfterName) * sizeof(WCHAR));
+    pStrings += lp - lpAfterName;
+    *pStrings++ = 0;
+
+    pNetResource->lpProvider = pStrings;
+    CopyMemory(pStrings, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+    pStrings += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+    if (lplpSystem)
+    {
+        *lplpSystem = pStrings;
+    }
+
+    lstrcpy(pStrings, lp);
+    pStrings += lstrlen(lp) + 1;
+
+    Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n",
+         pNetResource->lpRemoteName, pStrings, (PBYTE)lpBuffer + *lpBufferSize));
+    Log(("VBOXNP: NPGetResourceInformation: *lplpSystem: %ls\n", *lplpSystem));
+
+    return WN_SUCCESS;
+}
+
+DWORD APIENTRY NPGetUniversalName(LPCWSTR lpLocalPath,
+                                  DWORD dwInfoLevel,
+                                  LPVOID lpBuffer,
+                                  LPDWORD lpBufferSize)
+{
+    DWORD dwStatus;
+
+    DWORD BufferRequired = 0;
+    DWORD RemoteNameLength = 0;
+    DWORD RemainingPathLength = 0;
+
+    WCHAR LocalDrive[3];
+
+    const WCHAR *lpRemainingPath;
+    WCHAR *lpString;
+
+    Log(("VBOXNP: NPGetUniversalName: lpLocalPath = %ls, InfoLevel = %d, *lpBufferSize = %d\n",
+         lpLocalPath, dwInfoLevel, *lpBufferSize));
+
+    /* Check is input parameter is OK. */
+    if (   dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL
+        && dwInfoLevel != REMOTE_NAME_INFO_LEVEL)
+    {
+        Log(("VBOXNP: NPGetUniversalName: Bad dwInfoLevel value: %d\n",
+             dwInfoLevel));
+        return WN_BAD_LEVEL;
+    }
+
+    /* The 'lpLocalPath' is "X:\something". Extract the "X:" to pass to NPGetConnection. */
+    if (   lpLocalPath == NULL
+        || lpLocalPath[0] == 0
+        || lpLocalPath[1] != L':')
+    {
+        Log(("VBOXNP: NPGetUniversalName: Bad lpLocalPath.\n"));
+        return WN_BAD_LOCALNAME;
+    }
+
+    LocalDrive[0] = lpLocalPath[0];
+    LocalDrive[1] = lpLocalPath[1];
+    LocalDrive[2] = 0;
+
+    /* Length of the original path without the driver letter, including trailing NULL. */
+    lpRemainingPath = &lpLocalPath[2];
+    RemainingPathLength = (DWORD)((wcslen(lpRemainingPath) + 1) * sizeof(WCHAR));
+
+    /* Build the required structure in place of the supplied buffer. */
+    if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL)
+    {
+        LPUNIVERSAL_NAME_INFOW pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)lpBuffer;
+
+        BufferRequired = sizeof (UNIVERSAL_NAME_INFOW);
+
+        if (*lpBufferSize >= BufferRequired)
+        {
+            /* Enough place for the structure. */
+            pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(UNIVERSAL_NAME_INFOW));
+
+            /* At least so many bytes are available for obtaining the remote name. */
+            RemoteNameLength = *lpBufferSize - BufferRequired;
+        }
+        else
+        {
+            RemoteNameLength = 0;
+        }
+
+        /* Put the remote name directly to the buffer if possible and get the name length. */
+        dwStatus = NPGetConnection(LocalDrive,
+                                   RemoteNameLength? pUniversalNameInfo->lpUniversalName: NULL,
+                                   &RemoteNameLength);
+
+        if (   dwStatus != WN_SUCCESS
+            && dwStatus != WN_MORE_DATA)
+        {
+            if (dwStatus != WN_NOT_CONNECTED)
+            {
+                Log(("VBOXNP: NPGetUniversalName: NPGetConnection returned error 0x%lx\n",
+                     dwStatus));
+            }
+            return dwStatus;
+        }
+
+        if (RemoteNameLength < sizeof (WCHAR))
+        {
+            Log(("VBOXNP: NPGetUniversalName: Remote name is empty.\n"));
+            return WN_NO_NETWORK;
+        }
+
+        /* Adjust for actual remote name length. */
+        BufferRequired += RemoteNameLength;
+
+        /* And for required place for remaining path. */
+        BufferRequired += RemainingPathLength;
+
+        if (*lpBufferSize < BufferRequired)
+        {
+            Log(("VBOXNP: NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n",
+                 BufferRequired));
+            *lpBufferSize = BufferRequired;
+            return WN_MORE_DATA;
+        }
+
+        /* Enough memory in the buffer. Add '\' and remaining path to the remote name. */
+        lpString = &pUniversalNameInfo->lpUniversalName[RemoteNameLength / sizeof (WCHAR)];
+        lpString--; /* Trailing NULL */
+
+        CopyMemory(lpString, lpRemainingPath, RemainingPathLength);
+    }
+    else
+    {
+        LPREMOTE_NAME_INFOW pRemoteNameInfo = (LPREMOTE_NAME_INFOW)lpBuffer;
+        WCHAR *lpDelimiter;
+
+        BufferRequired = sizeof (REMOTE_NAME_INFOW);
+
+        if (*lpBufferSize >= BufferRequired)
+        {
+            /* Enough place for the structure. */
+            pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW));
+            pRemoteNameInfo->lpConnectionName = NULL;
+            pRemoteNameInfo->lpRemainingPath = NULL;
+
+            /* At least so many bytes are available for obtaining the remote name. */
+            RemoteNameLength = *lpBufferSize - BufferRequired;
+        }
+        else
+        {
+            RemoteNameLength = 0;
+        }
+
+        /* Put the remote name directly to the buffer if possible and get the name length. */
+        dwStatus = NPGetConnection(LocalDrive, RemoteNameLength? pRemoteNameInfo->lpUniversalName: NULL, &RemoteNameLength);
+
+        if (   dwStatus != WN_SUCCESS
+            && dwStatus != WN_MORE_DATA)
+        {
+            if (dwStatus != WN_NOT_CONNECTED)
+            {
+                Log(("VBOXNP: NPGetUniversalName: NPGetConnection returned error 0x%lx\n", dwStatus));
+            }
+            return dwStatus;
+        }
+
+        if (RemoteNameLength < sizeof (WCHAR))
+        {
+            Log(("VBOXNP: NPGetUniversalName: Remote name is empty.\n"));
+            return WN_NO_NETWORK;
+        }
+
+        /* Adjust for actual remote name length. */
+        BufferRequired += RemoteNameLength;
+
+        /* And for required place for remaining path. */
+        BufferRequired += RemainingPathLength;
+
+        /* lpConnectionName, which is the remote name. */
+        BufferRequired += RemoteNameLength;
+
+        /* lpRemainingPath. */
+        BufferRequired += RemainingPathLength;
+
+        if (*lpBufferSize < BufferRequired)
+        {
+            Log(("VBOXNP: NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n",
+                 BufferRequired));
+            *lpBufferSize = BufferRequired;
+            return WN_MORE_DATA;
+        }
+
+        /* Enough memory in the buffer. Add \ and remaining path to the remote name. */
+        lpString = &pRemoteNameInfo->lpUniversalName[RemoteNameLength / sizeof (WCHAR)];
+        lpString--; /* Trailing NULL */
+
+        lpDelimiter = lpString; /* Delimiter will be inserted later. For now keep the NULL terminated string. */
+
+        CopyMemory( lpString, lpRemainingPath, RemainingPathLength);
+        lpString += RemainingPathLength / sizeof (WCHAR);
+
+        *lpDelimiter = 0;
+
+        pRemoteNameInfo->lpConnectionName = lpString;
+        CopyMemory( lpString, pRemoteNameInfo->lpUniversalName, RemoteNameLength);
+        lpString += RemoteNameLength / sizeof (WCHAR);
+
+        pRemoteNameInfo->lpRemainingPath = lpString;
+        CopyMemory( lpString, lpRemainingPath, RemainingPathLength);
+
+        *lpDelimiter = L'\\';
+    }
+
+    Log(("VBOXNP: NPGetUniversalName: WN_SUCCESS\n"));
+    return WN_SUCCESS;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hDLLInst,
+                    DWORD fdwReason,
+                    LPVOID lpvReserved)
+{
+    BOOL fReturn = TRUE;
+
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            RTR3InitDll(0);
+            VbglR3Init();
+            LogRel(("VBOXNP: DLL loaded.\n"));
+            break;
+
+        case DLL_PROCESS_DETACH:
+            LogRel(("VBOXNP: DLL unloaded.\n"));
+            VbglR3Term();
+            /// @todo RTR3Term();
+            break;
+
+        case DLL_THREAD_ATTACH:
+            break;
+
+        case DLL_THREAD_DETACH:
+            break;
+
+        default:
+            break;
+    }
+
+    return fReturn;
+}
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.def
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.def	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.def	(revision 40269)
@@ -0,0 +1,29 @@
+;
+; Copyright (C) 2012 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.
+;
+
+LIBRARY	VBOXMRXNP
+
+EXPORTS
+	NPGetCaps			        @13
+	NPAddConnection			    @17
+	NPAddConnection3		    @38
+	NPCancelConnection		    @18
+	NPGetConnection			    @12
+	NPOpenEnum			        @33
+	NPEnumResource			    @34
+	NPCloseEnum			        @35
+	NPGetUniversalName		    @40
+	NPGetResourceParent		    @41
+	NPGetResourceInformation	@52
+	NPLogonNotify			    @500
+	NPPasswordChangeNotify		@501
+
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.rc
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.rc	(revision 40269)
+++ trunk/src/VBox/Additions/WINNT/SharedFolders/np/vboxmrxnp.rc	(revision 40269)
@@ -0,0 +1,55 @@
+/* $Id$ */
+/** @file
+ * VBoxMRXNP - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+   FILEVERSION          VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0
+   PRODUCTVERSION       VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0
+   FILEFLAGSMASK        0x3fL
+   FILEFLAGS            0x0L
+   FILEOS               0x40004L
+   FILETYPE             0x2L
+   FILESUBTYPE          0x0L
+BEGIN
+   BLOCK "StringFileInfo"
+   BEGIN
+      BLOCK "040904b0"
+      BEGIN
+         VALUE "CompanyName",      VBOX_RC_COMPANY_NAME
+         VALUE "FileDescription",  "VirtualBox Shared Folders Minirdr NP\0"
+         VALUE "FileVersion",      VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+         VALUE "InternalName",     "VBoxMRXNP.DLL\0"
+         VALUE "LegalCopyright",   VBOX_RC_LEGAL_COPYRIGHT
+#ifdef VBOX_WOW64
+         VALUE "OriginalFilename", "VBoxMRXNP-x86.DLL\0"
+#else
+         VALUE "OriginalFilename", "VBoxMRXNP.DLL\0"
+#endif
+         VALUE "ProductName",      VBOX_PRODUCT " Guest Additions\0"
+         VALUE "ProductVersion",   VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD ".r" VBOX_SVN_REV "\0"
+      END
+   END
+   BLOCK "VarFileInfo"
+   BEGIN
+      VALUE "Translation", 0x409, 1200
+   END
+END
+
Index: trunk/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk
===================================================================
--- trunk/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk	(revision 40268)
+++ 	(revision )
@@ -1,26 +1,0 @@
-# $Id$
-## @file
-# Sub-Makefile for the Windows guest shared folder redirectory.
-#
-
-#
-# Copyright (C) 2006-2007 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
-
-# Include sub-makefiles.
-include $(PATH_SUB_CURRENT)/dll/Makefile.kmk
-include $(PATH_SUB_CURRENT)/sys/Makefile.kmk
-
-include	$(KBUILD_PATH)/subfooter.kmk
-
