summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2010-08-13 11:17:20 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2010-08-13 11:17:20 +0000
commitdb20805d61e95087717e46334b9d7c13748b8c22 (patch)
treebc42c4e05e9a39df7c7ba48788ae04190c322a32 /src
parent861da90197c13f11483eb93c4f9ba1ad4af73de5 (diff)
downloadVirtualBox-svn-db20805d61e95087717e46334b9d7c13748b8c22.tar.gz
Windows Additions: export shared folders and installer to OSE
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@31634 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src')
-rw-r--r--src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF11
-rw-r--r--src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt19
-rw-r--r--src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk53
-rw-r--r--src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp141
-rw-r--r--src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc43
-rw-r--r--src/VBox/Additions/WINNT/Installer/Loader/resource.h13
-rw-r--r--src/VBox/Additions/WINNT/Installer/Makefile.kmk207
-rw-r--r--src/VBox/Additions/WINNT/Installer/RegCleanup.cpp83
-rw-r--r--src/VBox/Additions/WINNT/Installer/RegCleanup.rc40
-rw-r--r--src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh149
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBCoInst.cpp331
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBCoInst.def15
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBCoInst.rc40
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp2200
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc40
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi1126
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh438
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh258
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh209
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh345
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh89
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh562
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp472
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc40
-rw-r--r--src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au359
-rw-r--r--src/VBox/Additions/WINNT/Installer/dumplog.nsh50
-rw-r--r--src/VBox/Additions/WINNT/Installer/iexplore.icobin0 -> 25214 bytes
-rw-r--r--src/VBox/Additions/WINNT/Installer/servicepack.nsh29
-rw-r--r--src/VBox/Additions/WINNT/Installer/strstr.nsh306
-rw-r--r--src/VBox/Additions/WINNT/Installer/welcome.bmpbin0 -> 154542 bytes
-rw-r--r--src/VBox/Additions/WINNT/Installer/winver.nsh103
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk20
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk21
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk36
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp63
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp2146
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def24
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h43
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc41
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk90
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf77
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc40
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c76
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c741
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c157
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c109
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c1684
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c1771
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c173
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h76
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h463
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h50
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c456
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c110
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h119
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c1526
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h39
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm92
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup0
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def134
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c99
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h32
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c189
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c129
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c243
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c51
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini16
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h70
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c343
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h61
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c138
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h80
-rw-r--r--src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c175
73 files changed, 19474 insertions, 0 deletions
diff --git a/src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF b/src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF
new file mode 100644
index 00000000000..b1c22a22d8e
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/ISO/AUTORUN.INF
@@ -0,0 +1,11 @@
+;
+; Copyright (C) 2006-2010 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+[autorun]
+open=VBoxWindowsAdditions.exe
+icon=VBoxWindowsAdditions.exe
+label=VirtualBox Guest Additions
diff --git a/src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt b/src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt
new file mode 100644
index 00000000000..d362d2a78d5
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/ISO/ReadmeDrivers.txt
@@ -0,0 +1,19 @@
+Oracle VM VirtualBox Guest Additions
+
+Where have the Windows drivers gone?
+- The Windows Guest Additions drivers were removed from this directory to
+ save space on your hard drive. To get the files you have to extract them
+ from the Windows Guest Additions installers:
+
+ To extract the 32-bit drivers to "C:\Drivers", do the following:
+ VBoxWindowsAdditions-x86 /extract /D=C:\Drivers
+
+ For the 64-bit drivers:
+ VBoxWindowsAdditions-amd64 /extract /D=C:\Drivers
+
+ Note: The extraction routine will create an additional sub directory
+ with the selected architecture (x86 or amd64) to prevent mixing up
+ the drivers.
+
+ To get further help with the command line parameteres of the installer,
+ type: VBoxWindowsAdditions-<arch> /?
diff --git a/src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk b/src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk
new file mode 100644
index 00000000000..f37c069d72e
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/Loader/Makefile.kmk
@@ -0,0 +1,53 @@
+# $Id$
+## @file
+# Sub-Makefile for the Guest Additions loader.
+#
+
+#
+# Copyright (C) 2008 Oracle Corporation
+#
+# Oracle Corporation confidential
+# All rights reserved
+#
+
+SUB_DEPTH = ../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# This has to be 32-bit, so don't include it in the 64-bit build.
+if "$(KBUILD_TARGET_ARCH)" == "x86"
+ PROGRAMS.x86 += VBoxWindowsAdditions
+ VBoxWindowsAdditions_TEMPLATE= VBOXGUESTR3EXE
+ VBoxWindowsAdditions_DEFS = _WIN32_WINNT=0x0400 _UNICODE UNICODE
+ VBoxWindowsAdditions_SOURCES = \
+ VBoxWindowsAdditions.cpp \
+ VBoxWindowsAdditions.rc
+
+ VBoxWindowsAdditions_LDFLAGS = \
+ /DISALLOWLIB:msvcrt.lib \
+ /DISALLOWLIB:msvcprt.lib \
+ /DISALLOWLIB:libcmt.lib
+
+ VBoxWindowsAdditions_LIBS = \
+ $(PATH_TOOL_$(TEMPLATE_VBOXR3EXE_TOOL)_LIB)/oldnames.lib \
+ $(PATH_TOOL_$(TEMPLATE_VBOXR3EXE_TOOL)_LIB)/libcmt.lib \
+ $(PATH_TOOL_$(TEMPLATE_VBOXR3EXE_TOOL)_LIB)/libcpmt.lib
+
+ # Version stuff.
+ VBoxWindowsAdditions.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
+ VBoxWindowsAdditions.cpp_DEPS = $(VBOX_SVN_REV_KMK)
+
+ # The icon location is configurable.
+ VBoxWindowsAdditions.rc_INCS += $(PATH_VBoxWindowsAdditions)
+ VBoxWindowsAdditions.rc_DEPS += $(PATH_VBoxWindowsAdditions)/VBoxWindowsAdditions-icon.rc
+ VBoxWindowsAdditions.rc_CLEAN = $(PATH_VBoxWindowsAdditions)/VBoxWindowsAdditions-icon.rc
+
+
+ # Icon include file.
+$$(PATH_VBoxWindowsAdditions)/VBoxWindowsAdditions-icon.rc: $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) Makefile.kmk | $$(dir $$@)
+ $(RM) -f $@
+ $(APPEND) $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))"'
+
+endif # x86 only
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp
new file mode 100644
index 00000000000..5568c02504f
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp
@@ -0,0 +1,141 @@
+/* $Id$ */
+/** @file
+ * VBoxWindowsAdditions - The Windows Guest Additions Loader
+ */
+
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#include <windows.h>
+#include <stdio.h>
+#include <tchar.h>
+
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+
+LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+BOOL IsWow64 ()
+{
+ BOOL bIsWow64 = FALSE;
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
+
+ if (NULL != fnIsWow64Process)
+ {
+ if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
+ {
+ _tprintf(_T("ERROR: Could not determine process type!\n"));
+
+ /* Error in retrieving process type - assume that we're running on 32bit. */
+ return FALSE;
+ }
+ }
+ return bIsWow64;
+}
+
+int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ int iRet = 0;
+
+ LPWSTR *pszArgList = NULL;
+ int nArgs = 0;
+
+ TCHAR szCurDir[_MAX_PATH + 1] = { 0 };
+ GetCurrentDirectory(_MAX_PATH, szCurDir);
+
+ SHELLEXECUTEINFOW TempInfo = { 0 };
+ TempInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+
+ TCHAR szModule[_MAX_PATH + 1] = { 0 };
+ TCHAR szApp[_MAX_PATH + 1] = { 0 };
+ TCHAR szProg[_MAX_PATH + 1] = { 0 };
+
+ pszArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);
+ if (0 == GetModuleFileName(NULL, szModule, _MAX_PATH))
+ {
+ /* Module not found, use a default name. */
+ _stprintf(szModule, _T("%ws"), (pszArgList != NULL) ? pszArgList[0] : _T("VBoxWindowsAdditions.exe"));
+ }
+
+ TCHAR* pcExt = wcsrchr(szModule, _T('.'));
+ if (NULL != pcExt)
+ wcsncpy(szApp, szModule, (pcExt - szModule));
+
+ if (IsWow64()) /* 64bit Windows. */
+ {
+ _stprintf(szProg, _T("%ws-amd64.exe"), szApp);
+ }
+ else /* 32bit Windows. */
+ {
+ _stprintf(szProg, _T("%ws-x86.exe"), szApp);
+ }
+
+ /* Construct parameter list. */
+ TCHAR *pszParams = (TCHAR*)LocalAlloc(LPTR, _MAX_PATH*sizeof(TCHAR));
+ TCHAR szDelim = _T(' ');
+
+ if (pszParams)
+ {
+ wcsncat(pszParams, szProg,
+ __min(wcslen(szProg),_MAX_PATH-wcslen(pszParams)));
+ wcsncat(pszParams, &szDelim,
+ __min(1,_MAX_PATH-wcslen(pszParams)));
+
+ if (nArgs > 1)
+ {
+ for (int i=0; i<nArgs-1; i++)
+ {
+ if (i > 0)
+ {
+ wcsncat(pszParams, &szDelim,
+ __min(1,_MAX_PATH-wcslen(pszParams)));
+ }
+ wcsncat(pszParams, pszArgList[i+1],
+ __min(wcslen(pszArgList[i+1]),_MAX_PATH-wcslen(pszParams)));
+ }
+ }
+ }
+
+ /* Struct for ShellExecute. */
+ TempInfo.fMask = 0;
+ TempInfo.hwnd = NULL;
+ TempInfo.lpVerb =L"runas" ;
+ TempInfo.lpFile = szProg;
+ TempInfo.lpParameters = pszParams;
+ TempInfo.lpDirectory = szCurDir;
+ TempInfo.nShow = SW_NORMAL;
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ DWORD dwRes = 0;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ dwRes = CreateProcessW(szProg, pszParams, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+ if (!dwRes && GetLastError() == 740) /* 740 = ERROR_ELEVATION_REQUIRED -> Only for Windows Vista. */
+ {
+ if (FALSE == ::ShellExecuteExW(&TempInfo))
+ {
+ _tprintf (_T("ERROR: Could not launch program! Code: %ld\n"), GetLastError());
+ iRet = 1;
+ }
+ }
+
+ if (pszParams)
+ LocalFree(pszParams);
+
+ if (pszArgList)
+ LocalFree(pszArgList);
+
+ return iRet;
+}
+
diff --git a/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc
new file mode 100644
index 00000000000..48a3ce1fc05
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.rc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+#include "resource.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 Guest Additions Loader\0"
+ VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ VALUE "InternalName", "VBoxWindowsAdditions\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", "VBoxWindowsAdditions.exe\0"
+ VALUE "ProductName", "VirtualBox Guest Additions Loader\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#include "VBoxWindowsAdditions-icon.rc"
diff --git a/src/VBox/Additions/WINNT/Installer/Loader/resource.h b/src/VBox/Additions/WINNT/Installer/Loader/resource.h
new file mode 100644
index 00000000000..d46682ee14a
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/Loader/resource.h
@@ -0,0 +1,13 @@
+/* $Id$ */
+/** @file
+ * AutoStartMenu - resource header file.
+ */
+
+/*
+ * Copyright (C) 2008 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#define IDI_VIRTUALBOX 101
diff --git a/src/VBox/Additions/WINNT/Installer/Makefile.kmk b/src/VBox/Additions/WINNT/Installer/Makefile.kmk
new file mode 100644
index 00000000000..a5bb601c737
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/Makefile.kmk
@@ -0,0 +1,207 @@
+# $Id$
+## @file
+# Sub-Makefile for the Windows Guest Additions Installer.
+#
+
+#
+# Copyright (C) 2006-2007 Oracle Corporation
+#
+# Oracle Corporation confidential
+# All rights reserved
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# Include Sub-Makefiles.
+include $(PATH_SUB_CURRENT)/Loader/Makefile.kmk
+
+# Globals
+VBOX_PATH_WIN_ADD_INS_SRC := $(PATH_SUB_CURRENT)
+VBOX_PATH_ADDITIONS.win.x86 := $(PATH_OUT_BASE)/win.x86/$(KBUILD_TYPE)/bin/additions
+
+## @todo VBOX_WIN_ADD_INS_OUT_DIR := $(PATH_TARGET)/Additions/Installer/win
+
+DLLS += VBCoInst
+VBCoInst_TEMPLATE = VBOXGUESTR3DLL
+ifdef VBOX_SIGN_ADDITIONS # (See the parent makefile.)
+ VBCoInst_NOINST = true
+endif
+VBCoInst_DEFS = _WIN32_WINNT=0x0400 WIN32_LEAN_AND_MEAN=1 UNICODE
+VBCoInst_LDFLAGS = /subsystem:console,4.10
+VBCoInst_SOURCES = \
+ VBCoInst.cpp \
+ VBCoInst.def \
+ VBCoInst.rc
+
+PROGRAMS += VBoxDrvInst
+VBoxDrvInst_TEMPLATE= VBOXGUESTR3EXE
+VBoxDrvInst_DEFS = _WIN32_WINNT=0x0400 _UNICODE UNICODE
+VBoxDrvInst_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
+VBoxDrvInst_DEPS = $(VBOX_SVN_REV_KMK)
+VBoxDrvInst_SDKS = WINPSDK W2K3DDK
+VBoxDrvInst_LIBS = \
+ $(PATH_SDK_W2K3DDK_LIB)/setupapi.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/newdev.lib
+VBoxDrvInst_SOURCES = \
+ VBoxDrvInst.cpp \
+ VBoxDrvInst.rc
+
+PROGRAMS += VBoxGuestDrvInst
+VBoxGuestDrvInst_TEMPLATE= VBOXGUESTR3EXE
+VBoxGuestDrvInst_DEFS = _WIN32_WINNT=0x0400 UNICODE
+VBoxGuestDrvInst_SOURCES = \
+ VBoxGuestDrvInst.cpp \
+ VBoxGuestDrvInst.rc
+
+PROGRAMS += RegCleanup
+RegCleanup_TEMPLATE = VBOXGUESTR3EXE
+RegCleanup_DEFS = _WIN32_WINNT=0x0400 UNICODE
+RegCleanup_SOURCES = \
+ RegCleanup.cpp \
+ RegCleanup.rc
+
+
+#
+# The installer.
+#
+PACKING += $(PATH_BIN)/additions/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH).exe
+OTHER_CLEAN += \
+ $(PATH_BIN)/additions/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH).exe \
+ $(PATH_BIN)/additions/VBoxWHQLFake.exe
+
+DRIVER_FILES := \
+ $(PATH_BIN)/additions/VBoxGuestDrvInst.exe \
+ $(PATH_BIN)/additions/RegCleanup.exe \
+ $(PATH_BIN)/additions/VBoxMouse.sys \
+ $(PATH_BIN)/additions/VBoxGuest.sys \
+ $(PATH_BIN)/additions/VBoxVideo.sys \
+ $(PATH_BIN)/additions/VBoxDisp.dll \
+ $(PATH_BIN)/additions/VBoxSF.sys \
+ $(PATH_BIN)/additions/VBoxMRXNP.dll \
+ $(PATH_BIN)/additions/VBoxTray.exe \
+ $(PATH_BIN)/additions/VBoxControl.exe \
+ $(PATH_BIN)/additions/VBoxWHQLFake.exe \
+ $(PATH_BIN)/additions/VBoxService.exe
+ifeq ($(KBUILD_TARGET_ARCH),x86)
+DRIVER_FILES += \
+ $(PATH_BIN)/additions/VBoxMouseNT.sys \
+ $(PATH_BIN)/additions/VBoxGuestNT.sys
+endif
+DRIVER_FILES += \
+ $(PATH_BIN)/additions/VBoxVideo.inf \
+ $(PATH_BIN)/additions/VBoxGuest.inf
+ifdef VBOX_SIGN_ADDITIONS
+DRIVER_FILES += \
+ $(PATH_BIN)/additions/VBoxVideo.cat \
+ $(PATH_BIN)/additions/VBoxGuest.cat
+endif
+ifdef VBOX_WITH_CROGL
+DRIVER_FILES += \
+ $(PATH_BIN)/additions/VBoxOGLarrayspu.dll \
+ $(PATH_BIN)/additions/VBoxOGLcrutil.dll \
+ $(PATH_BIN)/additions/VBoxOGLerrorspu.dll \
+ $(PATH_BIN)/additions/VBoxOGLpackspu.dll \
+ $(PATH_BIN)/additions/VBoxOGLpassthroughspu.dll \
+ $(PATH_BIN)/additions/VBoxOGLfeedbackspu.dll \
+ $$(PATH_BIN)/additions/VBoxOGL.dll
+ ifeq ($(KBUILD_TARGET_ARCH),amd64)
+ # Also include 32-bit DLLs on 64-bit guests to enable
+ # running 32-bit OpenGL apps on that.
+ DRIVER_FILES += \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLarrayspu.dll \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLcrutil.dll \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLerrorspu.dll \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLpackspu.dll \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLpassthroughspu.dll \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGLfeedbackspu.dll \
+ $(VBOX_PATH_ADDITIONS.win.x86)/VBoxOGL.dll
+ endif
+endif
+
+VB_WIN_ADD_NSIS_ENV := \
+ -E 'PATH_OUT=$(subst /,\,$(PATH_OUT))' \
+ -E 'PATH_TARGET=$(subst /,\,$(PATH_TARGET))' \
+ -E 'VBOX_PATH_ADDITIONS_WIN_X86=$(subst /,\,$(VBOX_PATH_ADDITIONS.win.x86))' \
+ -E 'VBOX_VENDOR=$(VBOX_VENDOR)' \
+ -E 'VBOX_VENDOR_SHORT=$(VBOX_VENDOR_SHORT)' \
+ -E 'VBOX_PRODUCT=$(VBOX_PRODUCT)' \
+ -E 'VBOX_C_YEAR=$(VBOX_C_YEAR)' \
+ -E 'VBOX_VERSION_STRING=$(VBOX_VERSION_STRING)' \
+ -E 'VBOX_VERSION_MAJOR=$(VBOX_VERSION_MAJOR)' \
+ -E 'VBOX_VERSION_MINOR=$(VBOX_VERSION_MINOR)' \
+ -E 'VBOX_VERSION_BUILD=$(VBOX_VERSION_BUILD)' \
+ -E 'VBOX_SVN_REV=$(VBOX_SVN_REV)' \
+ -E 'VBOX_WINDOWS_ADDITIONS_ICON_FILE=$(subst /,\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))' \
+ -E 'VBOX_NSIS_ICON_FILE=$(subst /,\,$(VBOX_NSIS_ICON_FILE))' \
+ -E 'VBOX_WITH_CROGL=$(if $(VBOX_WITH_CROGL),1,0)' \
+ -E 'VBOX_BRAND_WIN_ADD_INST_DLGBMP=$(subst /,\,$(VBOX_BRAND_WIN_ADD_INST_DLGBMP))' \
+ -E 'VBOX_BRAND_LICENSE_RTF=$(subst /,\,$(VBOX_BRAND_LICENSE_RTF))' \
+ $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES),-E 'VBOX_BRAND_$(lang)_LICENSE_RTF=$(VBOX_BRAND_$(lang)_LICENSE_RTF)') \
+ -E 'BUILD_TYPE=$(KBUILD_TYPE)' \
+ -E 'BUILD_TARGET_ARCH=$(KBUILD_TARGET_ARCH)'
+
+ifdef VBOX_SIGNING_MODE
+#
+# This is a hack to sign the uninstaller.
+# See http://nsis.sourceforge.net/Signing_an_Uninstaller for more details.
+#
+OTHER_CLEAN += $(PATH_TARGET)/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH)-uninst.exe
+
+$(PATH_TARGET)/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH)-uninst.exe: \
+ $(PATH_SUB_CURRENT)/VBoxGuestAdditions.nsi \
+ $(DRIVER_FILES) \
+ $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) \
+ $(VBOX_NSIS_ICON_FILE) \
+ $(VBOX_VERSION_STAMP)\
+ | $$(dir $$@)
+ $(call MSG_L1,Creating $@, from $<)
+ $(QUIET)$(REDIRECT) -C $(VBOX_PATH_WIN_ADD_INS_SRC) \
+ $(VB_WIN_ADD_NSIS_ENV) \
+ -- $(EXEC_X86_WIN32) $(VBOX_PATH_NSIS)/makensis.exe /NOCD /V2 \
+ $(if $(VBOX_SIGN_ADDITIONS),'/DVBOX_SIGN_ADDITIONS=1') \
+ $(if $(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_INSTALLER_ADD_LANGUAGES=1') \
+ $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_BRAND_$(lang)_LICENSE_RTF=1') \
+ '/DUNINSTALLER_ONLY=1' \
+ '$(subst /,\,$<)'
+
+OTHER_CLEAN += $(PATH_TARGET)/uninst.exe
+$(PATH_TARGET)/uninst.exe: $(PATH_TARGET)/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH)-uninst.exe | $$(dir $$@)
+ $(call MSG_L1,Creating $@, from $<)
+ $(QUIET)$(RM) -f $@
+ - $<
+ $(TEST) -f $@
+ $(call VBOX_SIGN_FILE_FN,$@)
+endif
+
+WHQLFAKE := $(PATH_SUB_CURRENT)/VBoxWHQLFake.au3
+
+$(PATH_BIN)/additions/VBoxWHQLFake.exe:
+ $(call MSG_L1,Creating $@, from $<)
+ $(QUIET)$(EXEC_X86_WIN32) $(VBOX_PATH_AUTOIT3)/Aut2Exe/Aut2exe.exe \
+ /in $(WHQLFAKE) \
+ /out $(PATH_BIN)/additions/VBoxWHQLFake.exe \
+ /icon $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) \
+ /comp 4 \
+ /unicode
+
+$(PATH_BIN)/additions/VBoxWindowsAdditions-$(KBUILD_TARGET_ARCH).exe: \
+ $(PATH_SUB_CURRENT)/VBoxGuestAdditions.nsi \
+ $(DRIVER_FILES) \
+ $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) \
+ $(VBOX_NSIS_ICON_FILE) \
+ $(if $(VBOX_SIGNING_MODE),$(PATH_TARGET)/uninst.exe) \
+ $(VBOX_VERSION_STAMP)
+ $(call MSG_L1,Creating $@, from $<)
+ $(QUIET)$(REDIRECT) -C $(VBOX_PATH_WIN_ADD_INS_SRC) \
+ $(VB_WIN_ADD_NSIS_ENV) \
+ -- $(EXEC_X86_WIN32) $(VBOX_PATH_NSIS)/makensis.exe /NOCD /V2 \
+ $(if $(VBOX_SIGN_ADDITIONS),'/DVBOX_SIGN_ADDITIONS=1') \
+ $(if $(VBOX_SIGNING_MODE),'/DEXTERNAL_UNINSTALLER=1') \
+ $(if $(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_INSTALLER_ADD_LANGUAGES=1') \
+ $(foreach lang,$(VBOX_INSTALLER_ADD_LANGUAGES),'/DVBOX_BRAND_$(lang)_LICENSE_RTF=1') \
+ '$(subst /,\,$<)'
+ $(call VBOX_SIGN_FILE_FN,$@)
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/WINNT/Installer/RegCleanup.cpp b/src/VBox/Additions/WINNT/Installer/RegCleanup.cpp
new file mode 100644
index 00000000000..c2393c9d85d
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/RegCleanup.cpp
@@ -0,0 +1,83 @@
+/** @file
+ *
+ * delinvalid - remove "InvalidDisplay" key on NT4
+ *
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+/*
+ Purpose:
+
+ Delete the "InvalidDisplay" key which causes the display
+ applet to be started on every boot. For some reason this key
+ isn't removed after setting the proper resolution and even not when
+ doing a driver reinstall. Removing it doesn't seem to do any harm.
+ The key is inserted by windows on first reboot after installing
+ the VBox video driver using the VirtualBox utility.
+ It's not inserted when using the Display applet for installation.
+ There seems to be a subtle problem with the VirtualBox util.
+ */
+
+//#define _UNICODE
+
+#include <windows.h>
+#include <setupapi.h>
+#include <regstr.h>
+#include <DEVGUID.h>
+#include <stdio.h>
+
+#include "tchar.h"
+#include "string.h"
+
+/*******************************************************************************
+ * Defined Constants And Macros *
+ *******************************************************************************/
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+BOOL isNT4 (void)
+{
+ OSVERSIONINFO OSversion;
+
+ OSversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ ::GetVersionEx(&OSversion);
+
+ switch (OSversion.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32s:
+ case VER_PLATFORM_WIN32_WINDOWS:
+ return FALSE;
+ case VER_PLATFORM_WIN32_NT:
+ if (OSversion.dwMajorVersion == 4)
+ return TRUE;
+ else return FALSE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+ int rc = 0;
+
+ /* This program is only for installing drivers on NT4 */
+ if (!isNT4())
+ {
+ printf("This program only runs on NT4\n");
+ return -1;
+ }
+
+ /* Delete the "InvalidDisplay" key which causes the display
+ applet to be started on every boot. For some reason this key
+ isn't removed after setting the proper resolution and even not when
+ doing a driverreinstall. */
+ RegDeleteKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\InvalidDisplay"));
+ RegDeleteKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\NewDisplay"));
+
+ return rc;
+}
diff --git a/src/VBox/Additions/WINNT/Installer/RegCleanup.rc b/src/VBox/Additions/WINNT/Installer/RegCleanup.rc
new file mode 100644
index 00000000000..50b8339783c
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/RegCleanup.rc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#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 RegCleanup\0"
+ VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ VALUE "InternalName", "VBoxRegCleanup\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", "VBoxRegCleanup.exe\0"
+ VALUE "ProductName", "VirtualBox Guest Additions\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh b/src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh
new file mode 100644
index 00000000000..480221d5e43
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/ReplaceDLL.nsh
@@ -0,0 +1,149 @@
+
+
+; Macro - Upgrade DLL File
+; Written by Joost Verburg
+; ------------------------
+;
+; Parameters:
+; LOCALFILE - Location of the new DLL file (on the compiler system)
+; DESTFILE - Location of the DLL file that should be upgraded
+; (on the user's system)
+; TEMPBASEDIR - Directory on the user's system to store a temporary file
+; when the system has to be rebooted.
+; For Win9x support, this should be on the same volume as the
+; DESTFILE!
+; The Windows temp directory could be located on any volume,
+; so you cannot use this directory.
+;
+; Define REPLACEDLL_NOREGISTER if you want to upgrade a DLL that does not
+; have to be registered.
+;
+; Note: If you want to support Win9x, you can only use
+; short filenames (8.3).
+;
+; Example of usage:
+; !insertmacro ReplaceDLL "dllname.dll" "$SYSDIR\dllname.dll" "$SYSDIR"
+;
+
+!macro ReplaceDLL LOCALFILE DESTFILE TEMPBASEDIR
+
+ Push $R0
+ Push $R1
+ Push $R2
+ Push $R3
+ Push $R4
+ Push $R5
+
+ ;------------------------
+ ;Unique number for labels
+
+ !define REPLACEDLL_UNIQUE ${__LINE__}
+
+ ;------------------------
+ ;Copy the parameters used on run-time to a variable
+ ;This allows the usage of variables as paramter
+
+ StrCpy $R4 "${DESTFILE}"
+ StrCpy $R5 "${TEMPBASEDIR}"
+
+ ;------------------------
+ ;Check file and version
+ ;
+ IfFileExists $R4 0 replacedll.copy_${REPLACEDLL_UNIQUE}
+
+ ;ClearErrors
+ ; GetDLLVersionLocal "${LOCALFILE}" $R0 $R1
+ ; GetDLLVersion $R4 $R2 $R3
+ ;IfErrors replacedll.upgrade_${REPLACEDLL_UNIQUE}
+ ;
+ ;IntCmpU $R0 $R2 0 replacedll.done_${REPLACEDLL_UNIQUE}
+ ; replacedll.upgrade_${REPLACEDLL_UNIQUE}
+ ;IntCmpU $R1 $R3 replacedll.done_${REPLACEDLL_UNIQUE}
+ ; replacedll.done_${REPLACEDLL_UNIQUE}
+ ; replacedll.upgrade_${REPLACEDLL_UNIQUE}
+
+ ;------------------------
+ ;Let's replace the DLL!
+
+ SetOverwrite try
+
+ ;replacedll.upgrade_${REPLACEDLL_UNIQUE}:
+ !ifndef REPLACEDLL_NOREGISTER
+ ;Unregister the DLL
+ UnRegDLL $R4
+ !endif
+
+ ;------------------------
+ ;Try to copy the DLL directly
+
+ ClearErrors
+ StrCpy $R0 $R4
+ Call :replacedll.file_${REPLACEDLL_UNIQUE}
+ IfErrors 0 replacedll.noreboot_${REPLACEDLL_UNIQUE}
+
+ ;------------------------
+ ;DLL is in use. Copy it to a temp file and Rename it on reboot.
+
+ GetTempFileName $R0 $R5
+ Call :replacedll.file_${REPLACEDLL_UNIQUE}
+ Rename /REBOOTOK $R0 $R4
+
+ ;------------------------
+ ;Register the DLL on reboot
+
+ !ifndef REPLACEDLL_NOREGISTER
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \
+ "Register $R4" 'rundll32.exe "$R4",DllRegisterServer'
+ !endif
+
+ Goto replacedll.done_${REPLACEDLL_UNIQUE}
+
+ ;------------------------
+ ;DLL does not exist - just extract
+
+ replacedll.copy_${REPLACEDLL_UNIQUE}:
+ StrCpy $R0 $R4
+ Call :replacedll.file_${REPLACEDLL_UNIQUE}
+
+ ;------------------------
+ ;Register the DLL
+
+ replacedll.noreboot_${REPLACEDLL_UNIQUE}:
+ !ifndef REPLACEDLL_NOREGISTER
+ RegDLL $R4
+ !endif
+
+ ;------------------------
+ ;Done
+
+ replacedll.done_${REPLACEDLL_UNIQUE}:
+
+ Pop $R5
+ Pop $R4
+ Pop $R3
+ Pop $R2
+ Pop $R1
+ Pop $R0
+
+ ;------------------------
+ ;End
+
+ Goto replacedll.end_${REPLACEDLL_UNIQUE}
+
+ ;------------------------
+ ;Called to extract the DLL
+
+ replacedll.file_${REPLACEDLL_UNIQUE}:
+ File /oname=$R0 "${LOCALFILE}"
+ Return
+
+ replacedll.end_${REPLACEDLL_UNIQUE}:
+
+ ;------------------------
+ ;Restore settings
+
+ SetOverwrite lastused
+
+ !undef REPLACEDLL_UNIQUE
+
+!macroend
diff --git a/src/VBox/Additions/WINNT/Installer/VBCoInst.cpp b/src/VBox/Additions/WINNT/Installer/VBCoInst.cpp
new file mode 100644
index 00000000000..4dda8a1e99b
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBCoInst.cpp
@@ -0,0 +1,331 @@
+// 45678901234567890123456789012345678901234567890123456789012345678901234567890
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1999.
+//
+// File: COINST.C
+//
+// Contents: co-installer hook.
+//
+// Notes: For a complete description of CoInstallers, please see the
+// Microsoft Windows 2000 DDK Documentation
+//
+// Author: keithga 4 June 1999
+//
+// Revision History:
+// Added FriendlyName interface (Eliyas Yakub Aug 2, 1999)
+//
+//----------------------------------------------------------------------------
+
+#undef UNICODE
+#if !defined(_UNICODE) && defined(UNICODE)
+#define _UNICODE
+#endif
+
+#include <windows.h>
+#include <setupapi.h>
+#include <stdio.h>
+#include <tchar.h>
+
+// #define LOG_ENABLED
+
+#ifdef LOG_ENABLED
+#include <stdio.h>
+
+static VOID _dprintf(LPSTR String, ...)
+{
+ va_list va;
+
+ va_start(va, String);
+
+ CHAR Buffer[1024];
+ if (strlen(String) < 1000)
+ {
+ _vsntprintf (Buffer, sizeof(Buffer), String, va);
+
+ FILE *f = fopen ("\\coinst.log", "ab");
+ if (f)
+ {
+ fprintf (f, "%s", Buffer);
+ fclose (f);
+ }
+ }
+
+ va_end (va);
+}
+#define dprintf(a) _dprintf a
+#else
+#define dprintf(a) do {} while (0)
+#endif /* LOG_ENABLED */
+
+//+---------------------------------------------------------------------------
+//
+// WARNING!
+//
+// A Coinstaller must not generate any popup to the user.
+// it should provide appropriate defaults.
+//
+// OutputDebugString should be fine...
+//
+#if DBG
+#define DbgOut(Text) OutputDebugString(TEXT("CoInstaller: " Text "\n"))
+#else
+#define DbgOut(Text)
+#endif
+
+/** strip the filename and leave the slash. */
+void StripFilename (TCHAR *psz)
+{
+ TCHAR *pchSep = NULL;
+ TCHAR *pch = psz;
+
+ /* strip of the filename. */
+ for (; *pch; pch++)
+ {
+ if (*pch == '\\' || *pch == '/' || *pch == ':')
+ pchSep = pch + 1;
+ }
+ if (pchSep)
+ *pchSep = '\0';
+ else
+ {
+ psz[0] = '.';
+ psz[1] = '\0';
+ }
+}
+
+/**
+ Check the installation type.
+ This function checks if the currently used
+ INF file not OEMxx.inf. If yes, the user installs the guest additions by hand,
+ if no this is an automated installation.
+ */
+BOOL CheckForNormalInstall (TCHAR *psz)
+{
+ TCHAR *pchSep = NULL;
+ TCHAR *pch = psz;
+
+ /* strip of the filename. */
+ for (; *pch; pch++)
+ {
+ if (*pch == '\\' || *pch == '/' || *pch == ':')
+ pchSep = pch + 1;
+ }
+ if (pchSep)
+ {
+ if (*pchSep == 'o' || *pchSep == 'O')
+ return FALSE;
+ return TRUE;
+ }
+ return TRUE; /* We shouldn't end here... */
+}
+
+ULONG startMouseInstallation (TCHAR *pszVBoxGuestInfName)
+{
+ TCHAR szAppCmd[MAX_PATH];
+ STARTUPINFO sInfo = { 0 };
+ PROCESS_INFORMATION pInfo = { 0 };
+ BOOL fNotAutomated;
+
+ dprintf(("startMouseInstallation: filename = %s\n", pszVBoxGuestInfName));
+
+ /* Check if we do an automated install */
+ fNotAutomated = CheckForNormalInstall(pszVBoxGuestInfName);
+
+ StripFilename(pszVBoxGuestInfName);
+
+ dprintf(("startMouseInstallation: fNotAutomated = %d, filename = %s\n", fNotAutomated, pszVBoxGuestInfName));
+
+ if (fNotAutomated)
+ {
+ /* This is a normal guest installation done by inserting the ISO */
+ _sntprintf(szAppCmd, sizeof(szAppCmd), TEXT("rundll32.exe SETUPAPI.DLL,InstallHinfSection VBoxMouse 132 %sVBoxMouse.inf"), pszVBoxGuestInfName);
+
+ sInfo.cb = sizeof(STARTUPINFO);
+
+ if (CreateProcess(NULL, szAppCmd, NULL, //lpProcessAttributes
+ NULL, //lpThreadAttributes
+ FALSE, //bInheritHandles
+ 0, //dwCreationFlags
+ NULL, //lpEnvironment
+ NULL, //lpCurrentDirectory,
+ &sInfo, //lpStartupInfo,
+ &pInfo)) //lpProcessInformation
+ {
+ DWORD dwExitCode = 0;
+
+ /* Wait for rundll32 to finish and then check the exit code; only then do we know if it succeeded or not! */
+ WaitForSingleObject(pInfo.hProcess, INFINITE);
+ if (GetExitCodeProcess(pInfo.hProcess, &dwExitCode) != 0 && dwExitCode == 0)
+ {
+ //
+ // hook the filter into the mouse class
+ //
+
+ dprintf(("startMouseInstallation: hooking\n"));
+
+ // first determine the GUID of the Mouse class
+ GUID guid;
+ DWORD numGuids;
+ if (SetupDiClassGuidsFromNameEx("Mouse", &guid, 1, &numGuids, NULL, NULL) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+ {
+ // get the corresponding class registry key
+ HKEY hkey = SetupDiOpenClassRegKeyEx(&guid, KEY_READ | KEY_WRITE, DIOCR_INSTALLER, NULL, NULL);
+ if (hkey)
+ {
+ // hardcoded value, ours + the standard filter
+ RegSetValueEx(hkey, "UpperFilters", 0, REG_MULTI_SZ, (const BYTE*)"VBoxMouse\0mouclass\0\0", 20);
+ RegCloseKey(hkey);
+ }
+ }
+ CloseHandle(pInfo.hProcess);
+ CloseHandle(pInfo.hThread);
+ dprintf(("startMouseInstallation: return ok\n"));
+ return 0;
+ }
+ CloseHandle(pInfo.hProcess);
+ CloseHandle(pInfo.hThread);
+ } /* CreateProcess() */
+ } /* fNotAutomated */
+ else
+ {
+ /* This is an automated installation */
+
+ //
+ // hook the filter into the mouse class
+ //
+
+ dprintf(("startMouseInstallation: automated\n"));
+
+ // first determine the GUID of the Mouse class
+ GUID guid;
+ DWORD numGuids;
+ if (SetupDiClassGuidsFromNameEx("Mouse", &guid, 1, &numGuids, NULL, NULL) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+ {
+ // get the corresponding class registry key
+ HKEY hkey = SetupDiOpenClassRegKeyEx(&guid, KEY_READ | KEY_WRITE, DIOCR_INSTALLER, NULL, NULL);
+ if (hkey)
+ {
+ // hardcoded value, ours + the standard filter
+ RegSetValueEx(hkey, "UpperFilters", 0, REG_MULTI_SZ, (const BYTE*)"VBoxMouse\0mouclass\0\0", 20);
+ RegCloseKey(hkey);
+ }
+ }
+ return 0;
+ }
+
+ /* bitch to debug output */
+ return -1;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: VBoxCoInstaller
+//
+// Purpose: Responds to co-installer messages
+//
+// Arguments:
+// InstallFunction [in]
+// DeviceInfoSet [in]
+// DeviceInfoData [in]
+// Context [inout]
+//
+// Returns: NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or an error code.
+//
+// This co-installer is used to install the mouse filter after installation of
+// the VBoxGuest driver
+extern "C"
+HRESULT WINAPI
+VBoxCoInstaller (
+ IN DI_FUNCTION InstallFunction,
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
+ IN OUT PCOINSTALLER_CONTEXT_DATA Context
+)
+{
+ dprintf((__DATE__ __TIME__ "VBoxCoInstaller InstallFunction 0x%02X\n", InstallFunction));
+
+ switch (InstallFunction)
+ {
+ case DIF_INSTALLDEVICE:
+ {
+ SP_DEVINSTALL_PARAMS DeviceInstallParams;
+ DeviceInstallParams.cbSize = sizeof (DeviceInstallParams);
+
+ if (!SetupDiGetDeviceInstallParams (DeviceInfoSet,
+ DeviceInfoData,
+ &DeviceInstallParams))
+ {
+ dprintf(("Failed to get DeviceInstallParams\n"));
+ return NO_ERROR;
+ }
+
+ /* Reboot the system and do not dynamically load the driver. */
+ DeviceInstallParams.Flags |= DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG;
+
+ if (!SetupDiSetDeviceInstallParams (DeviceInfoSet,
+ DeviceInfoData,
+ &DeviceInstallParams))
+ {
+ dprintf(("Failed to set DeviceInstallParams\n"));
+ return NO_ERROR;
+ }
+
+ return NO_ERROR;
+ }
+
+ // case DIF_REMOVE:
+ // {
+ // return NO_ERROR;
+ // } break;
+#if 0
+ /* This request is only sent when the installation of the VBoxGuest
+ succeeded. Because VBoxMouse needs VBoxGuest to work this is
+ a nice installation prerequisite check, too. */
+ case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
+ {
+ SP_DRVINFO_DATA DriverInfoData;
+ SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
+ HRESULT Status;
+
+ /* Get the path to the VBoxGuest INF. The VBoxMouse INF is in the same
+ directory. */
+ DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
+ if (!SetupDiGetSelectedDriver(DeviceInfoSet,
+ DeviceInfoData,
+ &DriverInfoData))
+ {
+ return NO_ERROR; /* Should return an error here? */
+ }
+
+ DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+ if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
+ DeviceInfoData,
+ &DriverInfoData,
+ &DriverInfoDetailData,
+ sizeof(SP_DRVINFO_DETAIL_DATA),
+ NULL))
+ {
+ if ((Status = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)
+ {
+ // We don't need the extended information. Ignore.
+ }
+ else
+ {
+ return NO_ERROR; /* Should return an error here? */
+ }
+ }
+
+ startMouseInstallation(DriverInfoDetailData.InfFileName);
+ break;
+ }
+#endif
+
+ default:
+ break;
+ }
+
+ return NO_ERROR;
+}
+
diff --git a/src/VBox/Additions/WINNT/Installer/VBCoInst.def b/src/VBox/Additions/WINNT/Installer/VBCoInst.def
new file mode 100644
index 00000000000..a607398dff6
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBCoInst.def
@@ -0,0 +1,15 @@
+;
+; VBCoInst -- Guest Additions Driver Co Installation Module
+; Copyright (C) 2006-2007 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+LIBRARY VBCOINST
+
+EXPORTS
+ VBoxCoInstaller
+
+
+
diff --git a/src/VBox/Additions/WINNT/Installer/VBCoInst.rc b/src/VBox/Additions/WINNT/Installer/VBCoInst.rc
new file mode 100644
index 00000000000..6577985bded
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBCoInst.rc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#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 CoInst\0"
+ VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ VALUE "InternalName", "VBoxCoInst\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", "VBoxCoInst.exe\0"
+ VALUE "ProductName", "VirtualBox Guest Additions\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp
new file mode 100644
index 00000000000..21f5a2ae200
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp
@@ -0,0 +1,2200 @@
+/*++
+
+ Copyright (c) Microsoft Corporation. All rights reserved.
+
+ Module Name:
+
+ VBoxDrvInst.cpp
+
+ Abstract:
+
+ Command-line interface for installing / uninstalling device drivers
+ with a given Hardware-ID (and .INF-file).
+
+ --*/
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#include <VBox/version.h>
+
+#include <windows.h>
+#include <setupapi.h>
+#include <newdev.h>
+#include <regstr.h>
+#include <cfgmgr32.h>
+#include <devguid.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <string.h>
+
+/*#define _DEBUG*/
+
+typedef int (*fnCallback) (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context);
+
+struct IdEntry
+{
+ LPCTSTR szString; /* string looking for */
+ LPCTSTR szWild; /* first wild character if any */
+ BOOL bInstanceId;
+};
+
+#define INSTANCEID_PREFIX_CHAR TEXT('@') /* character used to prefix instance ID's */
+#define CLASS_PREFIX_CHAR TEXT('=') /* character used to prefix class name */
+#define WILD_CHAR TEXT('*') /* wild character */
+#define QUOTE_PREFIX_CHAR TEXT('\'') /* prefix character to ignore wild characters */
+#define SPLIT_COMMAND_SEP TEXT(":=") /* whole word, indicates end of id's */
+
+/* @todo Split this program into several modules:
+
+ - Main
+ - Utility functions
+ - Dynamic API loading
+ - Installation / uninstallation routines
+ - ...
+ */
+
+/* Exit codes */
+#define EXIT_OK (0)
+#define EXIT_REBOOT (1)
+#define EXIT_FAIL (2)
+#define EXIT_USAGE (3)
+
+/* Dynamic loaded libs */
+HMODULE g_hSetupAPI = NULL;
+HMODULE g_hNewDev = NULL;
+HMODULE g_hCfgMgr = NULL;
+
+/* Function pointers for dynamic loading of some API calls NT4 hasn't ... */
+typedef BOOL (WINAPI *fnSetupDiCreateDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceName, LPGUID ClassGuid, PCTSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
+ PSP_DEVINFO_DATA DeviceInfoData);
+fnSetupDiCreateDeviceInfo g_pfnSetupDiCreateDeviceInfo = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiOpenDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData);
+fnSetupDiOpenDeviceInfo g_pfnSetupDiOpenDeviceInfo = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiEnumDeviceInfo) (HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
+fnSetupDiEnumDeviceInfo g_pfnSetupDiEnumDeviceInfo = NULL;
+
+/***/
+
+typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoList) (LPGUID ClassGuid, HWND hwndParent);
+fnSetupDiCreateDeviceInfoList g_pfnSetupDiCreateDeviceInfoList = NULL;
+
+typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoListEx) (LPGUID ClassGuid, HWND hwndParent, PCTSTR MachineName, PVOID Reserved);
+fnSetupDiCreateDeviceInfoListEx g_pfnSetupDiCreateDeviceInfoListEx = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiDestroyDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
+fnSetupDiDestroyDriverInfoList g_pfnSetupDiDestroyDriverInfoList = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiDestroyDeviceInfoList) (HDEVINFO DeviceInfoSet);
+fnSetupDiDestroyDeviceInfoList g_pfnSetupDiDestroyDeviceInfoList = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiGetDeviceInfoListDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData);
+fnSetupDiGetDeviceInfoListDetail g_pfnSetupDiGetDeviceInfoListDetail = NULL;
+
+/***/
+
+typedef BOOL (WINAPI *fnSetupDiSetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, CONST BYTE *PropertyBuffer, DWORD PropertyBufferSize);
+fnSetupDiSetDeviceRegistryProperty g_pfnSetupDiSetDeviceRegistryProperty = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiGetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer,
+ DWORD PropertyBufferSize, PDWORD RequiredSize);
+fnSetupDiGetDeviceRegistryProperty g_pfnSetupDiGetDeviceRegistryProperty = NULL;
+
+/***/
+
+typedef BOOL (WINAPI *fnSetupDiCallClassInstaller) (DI_FUNCTION InstallFunction, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData);
+fnSetupDiCallClassInstaller g_pfnSetupDiCallClassInstaller = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiClassGuidsFromNameEx) (PCTSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize, PCTSTR MachineName, PVOID Reserved);
+fnSetupDiClassGuidsFromNameEx g_pfnSetupDiClassGuidsFromNameEx = NULL;
+
+typedef HDEVINFO (WINAPI *fnSetupDiGetClassDevsEx) (LPGUID ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved);
+fnSetupDiGetClassDevsEx g_pfnSetupDiGetClassDevsEx = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiSetClassInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_CLASSINSTALL_HEADER ClassInstallParams, DWORD ClassInstallParamsSize);
+fnSetupDiSetClassInstallParams g_pfnSetupDiSetClassInstallParams = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiGetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
+fnSetupDiGetDeviceInstallParams g_pfnSetupDiGetDeviceInstallParams = NULL;
+
+typedef HKEY (WINAPI *fnSetupDiOpenDevRegKey) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired);
+fnSetupDiOpenDevRegKey g_pfnSetupDiOpenDevRegKey = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiBuildDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
+fnSetupDiBuildDriverInfoList g_pfnSetupDiBuildDriverInfoList = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiEnumDriverInfo) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType, DWORD MemberIndex, PSP_DRVINFO_DATA DriverInfoData);
+fnSetupDiEnumDriverInfo g_pfnSetupDiEnumDriverInfo = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiGetDriverInfoDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData, PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
+ DWORD DriverInfoDetailDataSize, PDWORD RequiredSize);
+fnSetupDiGetDriverInfoDetail g_pfnSetupDiGetDriverInfoDetail = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiSetSelectedDriver) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData);
+fnSetupDiSetSelectedDriver g_pfnSetupDiSetSelectedDriver = NULL;
+
+typedef BOOL (WINAPI *fnSetupDiSetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
+fnSetupDiSetDeviceInstallParams g_pfnSetupDiSetDeviceInstallParams = NULL;
+
+typedef CONFIGRET (WINAPI *fnCM_Get_Device_ID_Ex) (DEVINST dnDevInst, PTCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
+fnCM_Get_Device_ID_Ex g_pfnCM_Get_Device_ID_Ex = NULL;
+
+typedef BOOL (WINAPI* fnSetupCopyOEMInf) (PCTSTR SourceInfFileName, PCTSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PTSTR DestinationInfFileName,
+ DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent);
+fnSetupCopyOEMInf g_pfnSetupCopyOEMInf = NULL;
+
+typedef BOOL (WINAPI* fnUpdateDriverForPlugAndPlayDevices) (HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
+fnUpdateDriverForPlugAndPlayDevices g_pfnUpdateDriverForPlugAndPlayDevices = NULL;
+
+#define VBOX_LOAD_API( a_hModule, a_Func ) \
+{ \
+ g_pfn##a_Func = (fn##a_Func)GetProcAddress(a_hModule, "##a_Func"); \
+ _tprintf (_T("API call ##a_Func loaded: %p\n"), g_pfn##a_Func); \
+}
+
+int LoadAPICalls ()
+{
+ int rc = ERROR_SUCCESS;
+ OSVERSIONINFO OSinfo;
+ OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
+ GetVersionEx(&OSinfo);
+
+#ifdef _DEBUG
+ _tprintf (_T("Loading API calls ...\n"));
+#endif
+
+ /* Use unicode calls where available. */
+ if (OSinfo.dwMajorVersion >= 5) /* APIs available only on W2K and up! */
+ {
+ g_hSetupAPI = LoadLibrary(_T("SetupAPI"));
+ if (NULL == g_hSetupAPI)
+ {
+ _tprintf(_T("ERROR: SetupAPI.dll not found! Return code: %d\n"), GetLastError());
+ rc = ERROR_NOT_INSTALLED;
+ }
+ else
+ {
+ g_pfnSetupDiCreateDeviceInfoList = (fnSetupDiCreateDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoList");
+ g_pfnSetupDiCreateDeviceInfo = (fnSetupDiCreateDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoW");
+ g_pfnSetupDiSetDeviceRegistryProperty = (fnSetupDiSetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceRegistryPropertyW");
+ g_pfnSetupDiCallClassInstaller = (fnSetupDiCallClassInstaller)GetProcAddress(g_hSetupAPI, "SetupDiCallClassInstaller");
+ g_pfnSetupDiDestroyDeviceInfoList = (fnSetupDiDestroyDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDeviceInfoList");
+ g_pfnSetupDiClassGuidsFromNameEx = (fnSetupDiClassGuidsFromNameEx)GetProcAddress(g_hSetupAPI, "SetupDiClassGuidsFromNameExW");
+ g_pfnSetupDiGetDeviceRegistryProperty = (fnSetupDiGetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceRegistryPropertyW");
+ g_pfnSetupDiGetClassDevsEx = (fnSetupDiGetClassDevsEx)GetProcAddress(g_hSetupAPI, "SetupDiGetClassDevsExW");
+ g_pfnSetupDiCreateDeviceInfoListEx = (fnSetupDiCreateDeviceInfoListEx)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoListExW");
+ g_pfnSetupDiOpenDeviceInfo = (fnSetupDiOpenDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiOpenDeviceInfoW");
+ g_pfnSetupDiGetDeviceInfoListDetail = (fnSetupDiGetDeviceInfoListDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInfoListDetailW");
+ g_pfnSetupDiEnumDeviceInfo = (fnSetupDiEnumDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDeviceInfo");
+ g_pfnSetupDiSetClassInstallParams = (fnSetupDiSetClassInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetClassInstallParamsW");
+ g_pfnSetupDiGetDeviceInstallParams = (fnSetupDiGetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInstallParamsW");
+ g_pfnSetupDiOpenDevRegKey = (fnSetupDiOpenDevRegKey)GetProcAddress(g_hSetupAPI, "SetupDiOpenDevRegKey");
+ g_pfnSetupDiBuildDriverInfoList = (fnSetupDiBuildDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiBuildDriverInfoList");
+ g_pfnSetupDiEnumDriverInfo = (fnSetupDiEnumDriverInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDriverInfoW");
+ g_pfnSetupDiGetDriverInfoDetail = (fnSetupDiGetDriverInfoDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDriverInfoDetailW");
+ g_pfnSetupDiDestroyDriverInfoList = (fnSetupDiDestroyDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDriverInfoList");
+ g_pfnSetupDiSetSelectedDriver = (fnSetupDiSetSelectedDriver)GetProcAddress(g_hSetupAPI, "SetupDiSetSelectedDriverW");
+ g_pfnSetupDiSetDeviceInstallParams = (fnSetupDiSetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceInstallParamsW");
+ g_pfnSetupCopyOEMInf = (fnSetupCopyOEMInf)GetProcAddress(g_hSetupAPI, "SetupCopyOEMInfW");
+ }
+
+ if (rc == ERROR_SUCCESS)
+ {
+ g_hNewDev = LoadLibrary(_T("NewDev"));
+ if (NULL != g_hNewDev)
+ {
+ g_pfnUpdateDriverForPlugAndPlayDevices = (fnUpdateDriverForPlugAndPlayDevices)GetProcAddress(g_hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
+ }
+ else
+ {
+ _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError());
+ rc = ERROR_FILE_NOT_FOUND;
+ }
+ }
+
+ if (rc == ERROR_SUCCESS)
+ {
+ g_hCfgMgr = LoadLibrary(_T("CfgMgr32"));
+ if (NULL != g_hCfgMgr)
+ {
+ g_pfnCM_Get_Device_ID_Ex = (fnCM_Get_Device_ID_Ex)GetProcAddress(g_hCfgMgr, "CM_Get_Device_ID_ExW");
+ }
+ else
+ {
+ _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError());
+ rc = ERROR_FILE_NOT_FOUND;
+ }
+ }
+ }
+ else if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0. */
+ {
+ /* Nothing to do here yet. */
+ }
+ else /* Other platforms */
+ {
+ _tprintf(_T("ERROR: Platform not supported yet!\n"));
+ rc = ERROR_NOT_SUPPORTED;
+ }
+
+ return rc;
+}
+
+void FreeAPICalls ()
+{
+#ifdef _DEBUG
+ _tprintf (_T("Freeing API calls ...\n"));
+#endif
+
+ if (NULL != g_hSetupAPI)
+ FreeLibrary(g_hSetupAPI);
+
+ if (NULL != g_hNewDev)
+ FreeLibrary(g_hNewDev);
+
+ if (NULL != g_hCfgMgr)
+ FreeLibrary(g_hCfgMgr);
+}
+
+bool GetErrorMsg (DWORD a_dwLastError, _TCHAR* a_pszMsg, DWORD a_dwBufSize)
+{
+ if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_dwLastError, 0, a_pszMsg, a_dwBufSize, NULL) == 0)
+ {
+ _stprintf(a_pszMsg, _T("Unknown error!\n"), a_dwLastError);
+ return false;
+ }
+ else
+ {
+ _TCHAR* p = _tcschr(a_pszMsg, _T('\r'));
+
+ if (p != NULL)
+ *p = _T('\0');
+ }
+
+ return true;
+}
+
+/* @todo Add exception handling instead of crappy goto's! */
+
+int CreateDevice (_TCHAR* a_pszHwID, GUID a_devClass)
+{
+ int iRet = EXIT_OK;
+ HDEVINFO devInfoSet;
+ SP_DEVINFO_DATA devInfoData;
+ DWORD dwErr = 0;
+ _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 };
+
+ _tprintf(_T("Creating device ...\n"));
+
+ devInfoSet = g_pfnSetupDiCreateDeviceInfoList(&a_devClass, NULL);
+ if (devInfoSet == INVALID_HANDLE_VALUE)
+ {
+ _tprintf(_T("Could not build device info list!\n"));
+ return EXIT_FAIL;
+ }
+
+ devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+ if (FALSE == g_pfnSetupDiCreateDeviceInfo(devInfoSet, a_pszHwID, &a_devClass, NULL, NULL, DICD_GENERATE_ID, &devInfoData))
+ {
+ dwErr = GetLastError();
+
+ switch (dwErr)
+ {
+
+ case ERROR_DEVINST_ALREADY_EXISTS:
+
+ _tprintf(_T("Device already exists.\n"));
+ break;
+
+ case ERROR_CLASS_MISMATCH:
+
+ _tprintf(_T("ERROR: Device does not match to class ID!\n"));
+ break;
+
+ case ERROR_INVALID_USER_BUFFER:
+
+ _tprintf(_T("ERROR: Invalid user buffer!\n"));
+ break;
+
+ case ERROR_INVALID_DEVINST_NAME:
+
+ _tprintf(_T("ERROR: Invalid device instance name!\n"));
+ break;
+
+ default:
+
+ GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
+ _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
+ break;
+ }
+
+ iRet = EXIT_FAIL;
+ goto InstallCleanup;
+ }
+
+ if (FALSE == g_pfnSetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)a_pszHwID, (DWORD)((_tcsclen(a_pszHwID) + 2) * sizeof(_TCHAR))))
+ {
+ dwErr = GetLastError();
+ _tprintf(_T("Could not set device registry info!\n"));
+ iRet = EXIT_FAIL;
+ goto InstallCleanup;
+ }
+
+ if (FALSE == g_pfnSetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))
+ {
+ dwErr = GetLastError();
+ _tprintf(_T("Could not register device!\n"));
+ iRet = EXIT_FAIL;
+ goto InstallCleanup;
+ }
+
+ InstallCleanup: g_pfnSetupDiDestroyDeviceInfoList(devInfoSet);
+
+ return iRet;
+}
+
+int InstallDriver (_TCHAR* a_pszInfFile, _TCHAR* a_pszHwID, _TCHAR* a_pszDevClass)
+{
+ DWORD dwErr = 0;
+ BOOL bReboot = FALSE;
+
+ _TCHAR szInf[_MAX_PATH] = { 0 }; /* Full path + .INF file */
+ _TCHAR szInfPath[_MAX_PATH] = { 0 }; /* Full path to .INF file */
+ GUID devClassArr[32]; /* The device class GUID array */
+ DWORD dwReqSize = 0; /* Number of GUIDs in array after lookup */
+
+ _tprintf(_T("Installing driver ...\n"));
+ _tprintf(_T("HardwareID: %ws\n"), a_pszHwID);
+ _tprintf(_T("Device class name: %ws\n"), a_pszDevClass);
+
+ /* Retrieve GUID of device class */
+ /* Not used here: g_pfnSetupDiClassNameFromGuidEx( ... ) */
+ if (FALSE == g_pfnSetupDiClassGuidsFromNameEx(a_pszDevClass, devClassArr, 32, &dwReqSize, NULL, NULL))
+ {
+ _tprintf(_T("Could not retrieve device class GUID! Error: %ld\n"), GetLastError());
+ return EXIT_FAIL;
+ }
+ else
+ {
+ /* Do not fail if dwReqSize is 0. For whatever reason Windows Server 2008 Core does not have the "Media"
+ device class installed. Maybe they stripped down too much? :-/ */
+ if (dwReqSize <= 0)
+ {
+ _tprintf(_T("WARNING: No device class with this name found! ReqSize: %ld, Error: %ld\n"), dwReqSize, GetLastError());
+ }
+ else
+ {
+ _tprintf(_T("Number of GUIDs found: %ld\n"), dwReqSize);
+ }
+
+ /* Not needed for now!
+ if (EXIT_FAIL == CreateDevice (a_pszHwID, devClassArr[0]))
+ return EXIT_FAIL;*/
+ }
+
+ _TCHAR* pcFile = NULL;
+ if (0 == GetFullPathName(a_pszInfFile, _MAX_PATH, szInf, &pcFile))
+ {
+ dwErr = GetLastError();
+
+ _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n"));
+ return EXIT_FAIL;
+ }
+
+ /* Extract path from path+INF */
+ if (pcFile != NULL)
+ _tcsnccpy(szInfPath, szInf, pcFile - szInf);
+
+ _tprintf(_T("INF-File: %ws\n"), szInf);
+ _tprintf(_T("INF-Path: %ws\n"), szInfPath);
+
+ _tprintf(_T("Updating driver for plug'n play devices ...\n"));
+ if (!g_pfnUpdateDriverForPlugAndPlayDevices(NULL, a_pszHwID, szInf, INSTALLFLAG_FORCE, &bReboot))
+ {
+ DWORD dwErr = GetLastError();
+ _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 };
+
+ if (dwErr == ERROR_NO_SUCH_DEVINST)
+ {
+ _TCHAR szDestInf[_MAX_PATH] = { 0 };
+ _tprintf(_T("The device is not plugged in (yet), pre-installing drivers ...\n"));
+
+ if (FALSE == g_pfnSetupCopyOEMInf(szInf, szInfPath, SPOST_PATH, 0, szDestInf, sizeof(szDestInf), NULL, NULL))
+ {
+ dwErr = GetLastError();
+ GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
+ _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
+ return EXIT_FAIL;
+ }
+
+ _tprintf(_T("OK. Installed to: %ws\n"), szDestInf);
+ return EXIT_OK;
+ }
+
+ switch (dwErr)
+ {
+
+ case ERROR_INVALID_FLAGS:
+
+ _tprintf(_T("ERROR: The value specified for InstallFlags is invalid!\n"));
+ break;
+
+ case ERROR_NO_MORE_ITEMS:
+
+ _tprintf(
+ _T(
+ "ERROR: The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag!\n"));
+ break;
+
+ case ERROR_FILE_NOT_FOUND:
+
+ _tprintf(_T("ERROR: File not found!\n"));
+ break;
+
+ case ERROR_IN_WOW64:
+
+ _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!"));
+ break;
+
+ case ERROR_NO_DRIVER_SELECTED:
+
+ _tprintf(_T("ERROR: No driver in .INF-file selected!\n"));
+ break;
+
+ case ERROR_SECTION_NOT_FOUND:
+
+ _tprintf(_T("ERROR: Section in .INF-file was not found!\n"));
+ break;
+
+ default:
+
+ /* Try error lookup with GetErrorMsg() */
+ GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
+ _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
+ break;
+ }
+
+ return EXIT_FAIL;
+ }
+
+ _tprintf(_T("Installation successful.\n"));
+
+ return EXIT_OK;
+}
+
+/*++
+
+ Routine Description:
+
+ Determine if this is instance id or hardware id and if there's any wildcards
+ instance ID is prefixed by '@'
+ wildcards are '*'
+
+
+ Arguments:
+
+ Id - ptr to string to check
+
+ Return Value:
+
+ IdEntry
+
+ --*/
+IdEntry GetIdType (LPCTSTR Id)
+{
+ IdEntry Entry;
+
+ Entry.bInstanceId = FALSE;
+ Entry.szWild = NULL;
+ Entry.szString = Id;
+
+ if (Entry.szString[0] == INSTANCEID_PREFIX_CHAR)
+ {
+ Entry.bInstanceId = TRUE;
+ Entry.szString = CharNext(Entry.szString);
+ }
+ if (Entry.szString[0] == QUOTE_PREFIX_CHAR)
+ {
+ /* prefix to treat rest of string literally */
+ Entry.szString = CharNext(Entry.szString);
+ }
+ else
+ {
+ /* see if any wild characters exist */
+ Entry.szWild = _tcschr(Entry.szString, WILD_CHAR);
+ }
+ return Entry;
+}
+
+/*++
+
+ Routine Description:
+
+ Get an index array pointing to the MultiSz passed in
+
+ Arguments:
+
+ MultiSz - well formed multi-sz string
+
+ Return Value:
+
+ array of strings. last entry+1 of array contains NULL
+ returns NULL on failure
+
+ --*/
+LPTSTR * GetMultiSzIndexArray (LPTSTR MultiSz)
+{
+ LPTSTR scan;
+ LPTSTR * array;
+ int elements;
+
+ for (scan = MultiSz, elements = 0; scan[0]; elements++)
+ {
+ scan += lstrlen(scan) + 1;
+ }
+ array = new LPTSTR[elements + 2];
+ if (!array)
+ {
+ return NULL;
+ }
+ array[0] = MultiSz;
+ array++;
+ if (elements)
+ {
+ for (scan = MultiSz, elements = 0; scan[0]; elements++)
+ {
+ array[elements] = scan;
+ scan += lstrlen(scan) + 1;
+ }
+ }
+ array[elements] = NULL;
+ return array;
+}
+
+/*++
+
+ Routine Description:
+
+ Deletes the string array allocated by GetDevMultiSz/GetRegMultiSz/GetMultiSzIndexArray
+
+ Arguments:
+
+ Array - pointer returned by GetMultiSzIndexArray
+
+ Return Value:
+
+ None
+
+ --*/
+void DelMultiSz (LPTSTR * Array)
+{
+ if (Array)
+ {
+ Array--;
+ if (Array[0])
+ {
+ delete[] Array[0];
+ }
+ delete[] Array;
+ }
+}
+
+/*++
+
+ Routine Description:
+
+ Get a multi-sz device property
+ and return as an array of strings
+
+ Arguments:
+
+ Devs - HDEVINFO containing DevInfo
+ DevInfo - Specific device
+ Prop - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS
+
+ Return Value:
+
+ array of strings. last entry+1 of array contains NULL
+ returns NULL on failure
+
+ --*/
+LPTSTR * GetDevMultiSz (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Prop)
+{
+ LPTSTR buffer;
+ DWORD size;
+ DWORD reqSize;
+ DWORD dataType;
+ LPTSTR * array;
+ DWORD szChars;
+
+ size = 8192; /* initial guess, nothing magic about this */
+ buffer = new TCHAR[(size / sizeof(TCHAR)) + 2];
+ if (!buffer)
+ {
+ return NULL;
+ }
+ while (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, Prop, &dataType, (LPBYTE)buffer, size, &reqSize))
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ goto failed;
+ }
+ if (dataType != REG_MULTI_SZ)
+ {
+ goto failed;
+ }
+ size = reqSize;
+ delete[] buffer;
+ buffer = new TCHAR[(size / sizeof(TCHAR)) + 2];
+ if (!buffer)
+ {
+ goto failed;
+ }
+ }
+ szChars = reqSize / sizeof(TCHAR);
+ buffer[szChars] = TEXT('\0');
+ buffer[szChars + 1] = TEXT('\0');
+ array = GetMultiSzIndexArray(buffer);
+ if (array)
+ {
+ return array;
+ }
+
+ failed: if (buffer)
+ {
+ delete[] buffer;
+ }
+ return NULL;
+}
+
+/*++
+
+ Routine Description:
+
+ Compare a single item against wildcard
+ I'm sure there's better ways of implementing this
+ Other than a command-line management tools
+ it's a bad idea to use wildcards as it implies
+ assumptions about the hardware/instance ID
+ eg, it might be tempting to enumerate root\* to
+ find all root devices, however there is a CfgMgr
+ API to query status and determine if a device is
+ root enumerated, which doesn't rely on implementation
+ details.
+
+ Arguments:
+
+ Item - item to find match for eg a\abcd\c
+ MatchEntry - eg *\*bc*\*
+
+ Return Value:
+
+ TRUE if any match, otherwise FALSE
+
+ --*/
+BOOL WildCardMatch (LPCTSTR Item, const IdEntry & MatchEntry)
+{
+ LPCTSTR scanItem;
+ LPCTSTR wildMark;
+ LPCTSTR nextWild;
+ size_t matchlen;
+
+ /* Before attempting anything else,
+ try and compare everything up to first wild */
+ //
+ if (!MatchEntry.szWild)
+ {
+ return _tcsicmp(Item, MatchEntry.szString) ? FALSE : TRUE;
+ }
+ if (_tcsnicmp(Item, MatchEntry.szString, MatchEntry.szWild - MatchEntry.szString) != 0)
+ {
+ return FALSE;
+ }
+ wildMark = MatchEntry.szWild;
+ scanItem = Item + (MatchEntry.szWild - MatchEntry.szString);
+
+ for (; wildMark[0];)
+ {
+ /* If we get here, we're either at or past a wildcard */
+ if (wildMark[0] == WILD_CHAR)
+ {
+ /* So skip wild chars */
+ wildMark = CharNext(wildMark);
+ continue;
+ }
+
+ /* Find next wild-card */
+ nextWild = _tcschr(wildMark, WILD_CHAR);
+
+ if (nextWild)
+ {
+ /* Substring */
+ matchlen = nextWild - wildMark;
+ }
+ else
+ {
+ /* Last portion of match */
+ size_t scanlen = lstrlen(scanItem);
+ matchlen = lstrlen(wildMark);
+
+ if (scanlen < matchlen)
+ {
+ return FALSE;
+ }
+
+ return _tcsicmp(scanItem + scanlen - matchlen, wildMark) ? FALSE : TRUE;
+ }
+
+ if (_istalpha(wildMark[0]))
+ {
+ /* Scan for either lower or uppercase version of first character */
+ TCHAR u = _totupper(wildMark[0]);
+ TCHAR l = _totlower(wildMark[0]);
+ while (scanItem[0] && scanItem[0] != u && scanItem[0] != l)
+ {
+ scanItem = CharNext(scanItem);
+ }
+
+ if (!scanItem[0])
+ {
+ /* Ran out of string */
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Scan for first character (no case) */
+ scanItem = _tcschr(scanItem, wildMark[0]);
+ if (!scanItem)
+ {
+ /* Ran out of string */
+ return FALSE;
+ }
+ }
+
+ /* Try and match the sub-string at wildMark against scanItem */
+ if (_tcsnicmp(scanItem, wildMark, matchlen) != 0)
+ {
+ /* Nope, try again */
+ scanItem = CharNext(scanItem);
+ continue;
+ }
+
+ /* Substring matched */
+ scanItem += matchlen;
+ wildMark += matchlen;
+ }
+ return (wildMark[0] ? FALSE : TRUE);
+}
+
+/*++
+
+ Routine Description:
+
+ Compares all strings in Array against Id
+ Use WildCardMatch to do real compare
+
+ Arguments:
+
+ Array - pointer returned by GetDevMultiSz
+ MatchEntry - string to compare against
+
+ Return Value:
+
+ TRUE if any match, otherwise FALSE
+
+ --*/
+BOOL WildCompareHwIds (LPTSTR * Array, const IdEntry & MatchEntry)
+{
+ if (Array)
+ {
+ while (Array[0])
+ {
+ if (WildCardMatch(Array[0], MatchEntry))
+ {
+ return TRUE;
+ }
+ Array++;
+ }
+ }
+ return FALSE;
+}
+
+/*++
+
+ Routine Description:
+
+ Generic enumerator for devices that will be passed the following arguments:
+ <id> [<id>...]
+ =<class> [<id>...]
+ where <id> can either be @instance-id, or hardware-id and may contain wildcards
+ <class> is a class name
+
+ Arguments:
+
+ BaseName - name of executable
+ Machine - name of machine to enumerate
+ Flags - extra enumeration flags (eg DIGCF_PRESENT)
+ argc/argv - remaining arguments on command line
+ Callback - function to call for each hit
+ Context - data to pass function for each hit
+
+ Return Value:
+
+ EXIT_xxxx
+
+ --*/
+int EnumerateDevices (LPCTSTR BaseName, LPCTSTR Machine, DWORD Flags, int argc, LPTSTR argv[], fnCallback Callback, LPVOID Context)
+{
+ HDEVINFO devs = INVALID_HANDLE_VALUE;
+ IdEntry * templ = NULL;
+ int failcode = EXIT_FAIL;
+ int retcode;
+ int argIndex;
+ DWORD devIndex;
+ SP_DEVINFO_DATA devInfo;
+ SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
+ BOOL doSearch = FALSE;
+ BOOL match;
+ BOOL all = FALSE;
+ GUID cls;
+ DWORD numClass = 0;
+ int skip = 0;
+
+ if (!argc)
+ {
+ return EXIT_USAGE;
+ }
+
+ templ = new IdEntry[argc];
+ if (!templ)
+ {
+ goto final;
+ }
+
+ /* Determine if a class is specified */
+ if (argc > skip && argv[skip][0] == CLASS_PREFIX_CHAR && argv[skip][1])
+ {
+ if (!g_pfnSetupDiClassGuidsFromNameEx(argv[skip] + 1, &cls, 1, &numClass, Machine, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ goto final;
+ }
+ if (!numClass)
+ {
+ failcode = EXIT_OK;
+ goto final;
+ }
+ skip++;
+ }
+
+ if (argc > skip && argv[skip][0] == WILD_CHAR && !argv[skip][1])
+ {
+ /* Catch convinient case of specifying a single argument '*' */
+ all = TRUE;
+ skip++;
+ }
+ else if (argc <= skip)
+ {
+ /* At least one parameter, but no <id>'s */
+ all = TRUE;
+ }
+
+ /* Determine if any instance id's were specified */
+
+ /* Note, if =<class> was specified with no id's
+ we'll mark it as not doSearch
+ but will go ahead and add them all */
+ for (argIndex = skip; argIndex < argc; argIndex++)
+ {
+ templ[argIndex] = GetIdType(argv[argIndex]);
+ if (templ[argIndex].szWild || !templ[argIndex].bInstanceId)
+ {
+ /* Anything other than simple bInstanceId's require a search */
+ doSearch = TRUE;
+ }
+ }
+ if (doSearch || all)
+ {
+ /* Add all id's to list
+ If there's a class, filter on specified class */
+ devs = g_pfnSetupDiGetClassDevsEx(numClass ? &cls : NULL, NULL, NULL, (numClass ? 0 : DIGCF_ALLCLASSES) | Flags, NULL, Machine, NULL);
+
+ }
+ else
+ {
+ /* Blank list, we'll add instance id's by hand */
+ devs = g_pfnSetupDiCreateDeviceInfoListEx(numClass ? &cls : NULL, NULL, Machine, NULL);
+ }
+ if (devs == INVALID_HANDLE_VALUE)
+ {
+ goto final;
+ }
+ for (argIndex = skip; argIndex < argc; argIndex++)
+ {
+ /* Add explicit instances to list (even if enumerated all,
+ this gets around DIGCF_PRESENT)
+ do this even if wildcards appear to be detected since they
+ might actually be part of the instance ID of a non-present device */
+ if (templ[argIndex].bInstanceId)
+ {
+ g_pfnSetupDiOpenDeviceInfo(devs, templ[argIndex].szString, NULL, 0, NULL);
+ }
+ }
+
+ devInfoListDetail.cbSize = sizeof(devInfoListDetail);
+ if (!g_pfnSetupDiGetDeviceInfoListDetail(devs, &devInfoListDetail))
+ {
+ goto final;
+ }
+
+ /* Now enumerate them */
+ if (all)
+ {
+ doSearch = FALSE;
+ }
+
+ devInfo.cbSize = sizeof(devInfo);
+ for (devIndex = 0; g_pfnSetupDiEnumDeviceInfo(devs, devIndex, &devInfo); devIndex++)
+ {
+
+ if (doSearch)
+ {
+ for (argIndex = skip, match = FALSE; (argIndex < argc) && !match; argIndex++)
+ {
+ TCHAR devID[MAX_DEVICE_ID_LEN];
+ LPTSTR *hwIds = NULL;
+ LPTSTR *compatIds = NULL;
+
+ /* Determine instance ID */
+ if (g_pfnCM_Get_Device_ID_Ex(devInfo.DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle) != CR_SUCCESS)
+ {
+ devID[0] = TEXT('\0');
+ }
+
+ if (templ[argIndex].bInstanceId)
+ {
+ /* Match on the instance ID */
+ if (WildCardMatch(devID, templ[argIndex]))
+ match = TRUE;
+
+ }
+ else
+ {
+ /* Determine hardware ID's and search for matches */
+ hwIds = GetDevMultiSz(devs, &devInfo, SPDRP_HARDWAREID);
+ compatIds = GetDevMultiSz(devs, &devInfo, SPDRP_COMPATIBLEIDS);
+
+ if (WildCompareHwIds(hwIds, templ[argIndex]) || WildCompareHwIds(compatIds, templ[argIndex]))
+ {
+ match = TRUE;
+ }
+ }
+ DelMultiSz(hwIds);
+ DelMultiSz(compatIds);
+ }
+ }
+ else
+ {
+ match = TRUE;
+ }
+ if (match)
+ {
+ retcode = Callback(devs, &devInfo, devIndex, Context);
+ if (retcode)
+ {
+ failcode = retcode;
+ goto final;
+ }
+ }
+ }
+
+ failcode = EXIT_OK;
+
+ final: if (templ)
+ {
+ delete[] templ;
+ }
+ if (devs != INVALID_HANDLE_VALUE)
+ {
+ g_pfnSetupDiDestroyDeviceInfoList(devs);
+ }
+ return failcode;
+
+}
+
+/*++
+
+ Routine Description:
+
+ Callback for use by Remove
+ Invokes DIF_REMOVE
+ uses g_pfnSetupDiCallClassInstaller so cannot be done for remote devices
+ Don't use CM_xxx API's, they bypass class/co-installers and this is bad.
+
+ Arguments:
+
+ Devs )_ uniquely identify the device
+ DevInfo )
+ Index - index of device
+ Context - GenericContext
+
+ Return Value:
+
+ EXIT_xxxx
+
+ --*/
+int UninstallCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
+{
+ SP_REMOVEDEVICE_PARAMS rmdParams;
+ SP_DEVINSTALL_PARAMS devParams;
+ LPCTSTR action = NULL;
+
+ /* Need hardware ID before trying to remove, as we wont have it after */
+ TCHAR devID[MAX_DEVICE_ID_LEN];
+ SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
+
+ devInfoListDetail.cbSize = sizeof(devInfoListDetail);
+
+ if ((!g_pfnSetupDiGetDeviceInfoListDetail(Devs, &devInfoListDetail)) || (g_pfnCM_Get_Device_ID_Ex(DevInfo->DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle)
+ != CR_SUCCESS))
+ {
+ /* Skip this */
+ return EXIT_OK;
+ }
+
+ rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+ rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
+ rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
+ rmdParams.HwProfile = 0;
+
+ if (!g_pfnSetupDiSetClassInstallParams(Devs, DevInfo, &rmdParams.ClassInstallHeader, sizeof(rmdParams)) || !g_pfnSetupDiCallClassInstaller(DIF_REMOVE, Devs, DevInfo))
+ {
+ /* Failed to invoke DIF_REMOVE, TODO! */
+ _tprintf(_T("Failed to invoke interface!\n"));
+ return EXIT_FAIL;
+ }
+
+ /* See if device needs reboot */
+ devParams.cbSize = sizeof(devParams);
+ if (g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &devParams) && (devParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)))
+ {
+ /* Reboot required */
+ _tprintf(_T("To fully uninstall, a reboot is required!\n"));
+ }
+ else
+ {
+ /* Appears to have succeeded */
+ _tprintf(_T("Uninstall succeeded!\n"));
+ }
+
+ return EXIT_OK;
+}
+
+/*++
+
+ Routine Description:
+
+ Find the driver that is associated with the current device
+ We can do this either the quick way (available in WinXP)
+ or the long way that works in Win2k.
+
+ Arguments:
+
+ Devs )_ uniquely identify device
+ DevInfo )
+
+ Return Value:
+
+ TRUE if we managed to determine and select current driver
+
+ --*/
+BOOL FindCurrentDriver (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, PSP_DRVINFO_DATA DriverInfoData)
+{
+ SP_DEVINSTALL_PARAMS deviceInstallParams;
+ WCHAR SectionName[LINE_LEN];
+ WCHAR DrvDescription[LINE_LEN];
+ WCHAR MfgName[LINE_LEN];
+ WCHAR ProviderName[LINE_LEN];
+ HKEY hKey = NULL;
+ DWORD RegDataLength;
+ DWORD RegDataType;
+ DWORD c;
+ BOOL match = FALSE;
+ long regerr;
+
+ ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams));
+ deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+
+ if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
+ {
+ printf("Could not retrieve install params!");
+ return FALSE;
+ }
+
+#ifdef DI_FLAGSEX_INSTALLEDDRIVER
+
+ /* Set the flags that tell g_pfnSetupDiBuildDriverInfoList to just put the
+ currently installed driver node in the list, and that it should allow
+ excluded drivers. This flag introduced in WinXP. */
+ deviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
+
+ if (g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
+ {
+ /* We were able to specify this flag, so proceed the easy way
+ We should get a list of no more than 1 driver */
+ if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER))
+ {
+ return FALSE;
+ }
+ if (!g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, 0, DriverInfoData))
+ {
+ return FALSE;
+ }
+
+ /* We've selected the current driver */
+ return TRUE;
+ }
+
+ deviceInstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
+
+#endif
+
+ /* The following method works in Win2k, but it's slow and painful.
+ First, get driver key - if it doesn't exist, no driver */
+ hKey = g_pfnSetupDiOpenDevRegKey(Devs, DevInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ
+ );
+
+ if (hKey == INVALID_HANDLE_VALUE)
+ {
+
+ _tprintf(_T("No associated driver found in registry!"));
+
+ /* No such value exists, so there can't be an associated driver */
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ /* Obtain path of INF - we'll do a search on this specific INF */
+ RegDataLength = sizeof(deviceInstallParams.DriverPath); /* Bytes!!! */
+ regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFPATH, NULL, &RegDataType, (PBYTE)deviceInstallParams.DriverPath, &RegDataLength);
+
+ if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
+ {
+
+ _tprintf(_T("No associated .inf path found in registry!"));
+
+ /* No such value exists, so no associated driver */
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ /* Obtain name of Provider to fill into DriverInfoData */
+ RegDataLength = sizeof(ProviderName); /* Bytes!!! */
+ regerr = RegQueryValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, NULL, &RegDataType, (PBYTE)ProviderName, &RegDataLength);
+
+ if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
+ {
+ /* No such value exists, so we don't have a valid associated driver */
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ /* Obtain name of section - for final verification */
+ RegDataLength = sizeof(SectionName); /* Bytes!!! */
+ regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)SectionName, &RegDataLength);
+
+ if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
+ {
+ /* No such value exists, so we don't have a valid associated driver */
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ /* Driver description (need not be same as device description) - for final verification */
+ RegDataLength = sizeof(DrvDescription); /* Bytes!!! */
+ regerr = RegQueryValueEx(hKey, REGSTR_VAL_DRVDESC, NULL, &RegDataType, (PBYTE)DrvDescription, &RegDataLength);
+
+ RegCloseKey(hKey);
+
+ if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
+ {
+ /* No such value exists, so we don't have a valid associated driver */
+ return FALSE;
+ }
+
+ /* Manufacturer (via SPDRP_MFG, don't access registry directly!) */
+ if (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, SPDRP_MFG, NULL, /* Datatype is guaranteed to always be REG_SZ */
+ (PBYTE)MfgName, sizeof(MfgName), /* Bytes!!! */
+ NULL))
+ {
+ /* No such value exists, so we don't have a valid associated driver */
+ return FALSE;
+ }
+
+ /* Now search for drivers listed in the INF */
+ deviceInstallParams.Flags |= DI_ENUMSINGLEINF;
+ deviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
+
+ if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
+ {
+ return FALSE;
+ }
+ if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER))
+ {
+ return FALSE;
+ }
+
+ /* Find the entry in the INF that was used to install the driver for this device */
+ for (c = 0; g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, c, DriverInfoData); c++)
+ {
+ if ((_tcscmp(DriverInfoData->MfgName, MfgName) == 0) && (_tcscmp(DriverInfoData->ProviderName, ProviderName) == 0))
+ {
+ /* These two fields match, try more detailed info to ensure we have the exact driver entry used */
+ SP_DRVINFO_DETAIL_DATA detail;
+ detail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+ if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, DriverInfoData, &detail, sizeof(detail), NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+ {
+ continue;
+ }
+ if ((_tcscmp(detail.SectionName, SectionName) == 0) && (_tcscmp(detail.DrvDescription, DrvDescription) == 0))
+ {
+ match = TRUE;
+ break;
+ }
+ }
+ }
+ if (!match)
+ {
+ g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
+ }
+ return match;
+}
+
+/*++
+
+ Routine Description:
+
+ if Context provided, Simply count
+ otherwise dump files indented 2
+
+ Arguments:
+
+ Context - DWORD Count
+ Notification - SPFILENOTIFY_QUEUESCAN
+ Param1 - scan
+
+ Return Value:
+
+ none
+
+ --*/
+UINT DumpDeviceDriversCallback (IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2)
+{
+ LPDWORD count = (LPDWORD)Context;
+ LPTSTR file = (LPTSTR)Param1;
+ if (count)
+ {
+ count[0]++;
+ }
+ else
+ {
+ _tprintf(TEXT("%s\n"), file);
+ }
+
+ return NO_ERROR;
+}
+
+/*++
+
+ Routine Description:
+
+ Dump information about what files were installed for driver package
+ <tab>Installed using OEM123.INF section [abc.NT]
+ <tab><tab>file...
+
+ Arguments:
+
+ Devs )_ uniquely identify device
+ DevInfo )
+
+ Return Value:
+
+ none
+
+ --*/
+int DeleteOEMInfCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
+{
+ /* Do this by 'searching' for the current driver
+ mimmicing a copy-only install to our own file queue
+ and then parsing that file queue */
+ SP_DEVINSTALL_PARAMS deviceInstallParams;
+ SP_DRVINFO_DATA driverInfoData;
+ SP_DRVINFO_DETAIL_DATA driverInfoDetail;
+ HSPFILEQ queueHandle = INVALID_HANDLE_VALUE;
+ DWORD count;
+ DWORD scanResult;
+ int success = EXIT_FAIL;
+
+ ZeroMemory(&driverInfoData,sizeof(driverInfoData));
+ driverInfoData.cbSize = sizeof(driverInfoData);
+
+ if (!FindCurrentDriver(Devs, DevInfo, &driverInfoData))
+ return EXIT_FAIL;
+
+ _tprintf(_T("Driver files found!\n"));
+
+ /* Get useful driver information */
+ driverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+ if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ /* No information about driver or section */
+ _tprintf(_T("No information about driver or section!\n"));
+ goto final;
+ }
+
+ if (!driverInfoDetail.InfFileName[0] || !driverInfoDetail.SectionName[0])
+ {
+ _tprintf(_T("Driver or section name is empty!\n"));
+ goto final;
+ }
+
+ _tprintf(_T("Desc: %s\n"), driverInfoDetail.DrvDescription);
+ _tprintf(_T("SecName: %s\n"), driverInfoDetail.SectionName);
+ _tprintf(_T("INF-File: %s\n"), driverInfoDetail.InfFileName);
+
+ /* Pretend to do the file-copy part of a driver install
+ to determine what files are used
+ the specified driver must be selected as the active driver */
+ if (!g_pfnSetupDiSetSelectedDriver(Devs, DevInfo, &driverInfoData))
+ goto final;
+
+ /* Create a file queue so we can look at this queue later */
+ queueHandle = SetupOpenFileQueue();
+
+ if (queueHandle == (HSPFILEQ)INVALID_HANDLE_VALUE)
+ {
+ goto final;
+ }
+
+ /* Modify flags to indicate we're providing our own queue */
+ ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams));
+ deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
+ goto final;
+
+ /* We want to add the files to the file queue, not install them! */
+ deviceInstallParams.FileQueue = queueHandle;
+ deviceInstallParams.Flags |= DI_NOVCP;
+
+ if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
+ goto final;
+
+ /* Now fill queue with files that are to be installed this involves all class/co-installers */
+ if (!g_pfnSetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, Devs, DevInfo))
+ goto final;
+
+ /* We now have a list of delete/rename/copy files
+ iterate the copy queue twice - 1st time to get # of files
+ 2nd time to get files (WinXP has API to get # of files, but we want this to work
+ on Win2k too */
+ count = 0;
+ scanResult = 0;
+
+ /* Call once to count (NOT YET IMPLEMENTED!) */
+ //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,&count,&scanResult);
+ //FormatToStream(stdout, count ? MSG_DUMP_DRIVER_FILES : MSG_DUMP_NO_DRIVER_FILES, count, driverInfoDetail.InfFileName, driverInfoDetail.SectionName);
+
+ /* Call again to dump the files (NOT YET IMPLEMENTED!) */
+ //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,NULL,&scanResult);
+
+ if (!DeleteFile(driverInfoDetail.InfFileName))
+ scanResult = GetLastError();
+ else
+ {
+ DWORD index = 0;
+
+ index = lstrlen(driverInfoDetail.InfFileName);
+ if (index > 3)
+ {
+ lstrcpy(driverInfoDetail.InfFileName + index - 3, TEXT( "pnf" ) );
+
+ if (!DeleteFile(driverInfoDetail.InfFileName))
+ scanResult = GetLastError();
+ }
+ }
+
+ success = EXIT_OK;
+
+ final:
+
+ g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
+
+ if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE)
+ {
+ SetupCloseFileQueue(queueHandle);
+ }
+
+ if (EXIT_OK != success)
+ {
+ _tprintf(_T("Something went wrong while delete the OEM INF-files!\n\n"));
+ }
+
+ return success;
+
+}
+
+int UninstallDriver (_TCHAR* a_pszHwID)
+{
+ _tprintf(_T("Uninstalling device: %ws\n"), a_pszHwID);
+
+ _tprintf(_T("Removing driver files ...\n\n"));
+ int iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, DeleteOEMInfCallback, NULL);
+
+ if (EXIT_OK != iRet)
+ return iRet;
+
+ _tprintf(_T("Uninstalling driver ...\n\n"));
+ iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, UninstallCallback, NULL);
+
+ return iRet;
+}
+
+int ExecuteInfFile (_TCHAR* a_pszSection, int a_iMode, _TCHAR* a_pszInf)
+{
+ _tprintf(_T("Executing INF-File: %ws (%ws) ...\n"), a_pszInf, a_pszSection);
+
+ /* Executed by the installer that already has proper privileges. */
+ _TCHAR szCommandLine[_MAX_PATH + 1] = { 0 };
+ swprintf(szCommandLine, sizeof(szCommandLine), TEXT( "%ws %d %ws" ), a_pszSection, a_iMode, a_pszInf);
+
+#ifdef _DEBUG
+ _tprintf (_T( "Commandline: %ws\n"), szCommandLine);
+#endif
+
+ InstallHinfSection(NULL, NULL, szCommandLine, SW_SHOW);
+
+ return EXIT_OK;
+}
+
+int AddNetworkProvider (TCHAR* a_pszProvider, int a_iOrder)
+{
+ TCHAR szKeyValue[512] = { 0 };
+ TCHAR szNewKeyValue[512] = { 0 };
+ HKEY hKey = NULL;
+ DWORD disp, dwType;
+ int rc;
+
+ _tprintf(_T("Adding network provider: %ws (Order = %d)\n"), a_pszProvider, a_iOrder);
+
+ /* Note: HWOrder is not accessible in Windows 2000; it is updated automatically anyway. */
+ TCHAR *pszKey = _T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
+
+ rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
+ if (rc != ERROR_SUCCESS)
+ {
+ _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc);
+ return EXIT_FAIL;
+ }
+ DWORD cbKeyValue = sizeof(szKeyValue);
+
+ rc = RegQueryValueEx(hKey, _T("ProviderOrder"), NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
+ if (rc != ERROR_SUCCESS || dwType != REG_SZ)
+ {
+ _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType);
+ return EXIT_FAIL;
+ }
+
+#ifdef _DEBUG
+ _tprintf(_T("Key value: %ws\n"), szKeyValue);
+#endif
+
+ /* Create entire new list. */
+ int iPos = 0;
+
+ TCHAR* pszToken = wcstok(szKeyValue, _T(","));
+ TCHAR* pszNewToken = NULL;
+ while (pszToken != NULL)
+ {
+ pszNewToken = wcstok(NULL, _T(","));
+
+ /* Append new provider name (at beginning if a_iOrder=0). */
+ if (iPos == a_iOrder)
+ {
+ wcscat(szNewKeyValue, a_pszProvider);
+ wcscat(szNewKeyValue, _T(","));
+ iPos++;
+ }
+
+ if (0 != wcsicmp(pszToken, a_pszProvider))
+ {
+ wcscat(szNewKeyValue, pszToken);
+ wcscat(szNewKeyValue, _T(","));
+ iPos++;
+ }
+
+#ifdef _DEBUG
+ _tprintf (_T("Temp new key value: %ws\n"), szNewKeyValue);
+#endif
+
+ pszToken = pszNewToken;
+ }
+
+ /* Append as last item if needed. */
+ if (a_iOrder >= iPos)
+ wcscat(szNewKeyValue, a_pszProvider);
+
+ /* Last char a delimiter? Cut off ... */
+ if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
+ szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
+
+ size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
+
+ _tprintf(_T("New provider list (%u bytes): %ws\n"), iNewLen, szNewKeyValue);
+
+ rc = RegSetValueExW(hKey, _T("ProviderOrder"), 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
+ return EXIT_FAIL;
+ }
+
+ rc = RegCloseKey(hKey);
+
+ if (rc == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Network provider successfully installed!\n"), rc);
+ rc = EXIT_OK;
+ }
+
+ return rc;
+}
+
+int AddStringToMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToAdd, int a_iOrder)
+{
+ TCHAR szKeyValue[512] = { 0 };
+ TCHAR szNewKeyValue[512] = { 0 };
+ HKEY hKey = NULL;
+ DWORD disp, dwType;
+ int rc = 0;
+
+ _tprintf(_T("Adding MULTI_SZ string: %ws to %ws\\%ws (Order = %d)\n"), a_pszValueToAdd, a_pszSubKey, a_pszKeyValue, a_iOrder);
+
+ rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, a_pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
+ if (rc != ERROR_SUCCESS)
+ {
+ _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), a_pszSubKey, rc);
+ return EXIT_FAIL;
+ }
+ DWORD cbKeyValue = sizeof(szKeyValue);
+
+ rc = RegQueryValueEx(hKey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
+ if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
+ {
+ _tprintf(_T("RegQueryValueEx failed with %d, dwType = 0x%x!\n"), rc, dwType);
+ return EXIT_FAIL;
+ }
+
+ /* Look if the network provider is already in the list. */
+ int iPos = 0;
+ size_t cb = 0;
+
+ /* Replace delimiting "\0"'s with "," to make tokenizing work. */
+ for (int i=0; i<cbKeyValue/sizeof(TCHAR);i++)
+ if (szKeyValue[i] == '\0') szKeyValue[i] = ',';
+
+ TCHAR* pszToken = wcstok(szKeyValue, _T(","));
+ TCHAR* pszNewToken = NULL;
+ TCHAR* pNewKeyValuePos = szNewKeyValue;
+ while (pszToken != NULL)
+ {
+ pszNewToken = wcstok(NULL, _T(","));
+
+ /* Append new value (at beginning if a_iOrder=0). */
+ if (iPos == a_iOrder)
+ {
+ memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR));
+
+ cb += (wcslen(a_pszValueToAdd) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */
+ pNewKeyValuePos += wcslen(a_pszValueToAdd) + 1;
+ iPos++;
+ }
+
+ if (0 != wcsicmp(pszToken, a_pszValueToAdd))
+ {
+ memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));
+ cb += (wcslen(pszToken) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */
+ pNewKeyValuePos += wcslen(pszToken) + 1;
+ iPos++;
+ }
+
+ pszToken = pszNewToken;
+ }
+
+ /* Append as last item if needed. */
+ if (a_iOrder >= iPos)
+ {
+ memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR));
+ cb += wcslen(a_pszValueToAdd) * sizeof(TCHAR); /* Add trailing zero as well. */
+ }
+
+ rc = RegSetValueExW(hKey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
+ return EXIT_FAIL;
+ }
+
+ rc = RegCloseKey(hKey);
+
+ if (rc == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Value successfully written (%u bytes)!\n"), cb);
+ rc = EXIT_OK;
+ }
+
+ return rc;
+}
+
+int RemoveStringFromMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToRemove)
+{
+ // @todo Make string sizes dynamically allocated!
+
+ TCHAR szKeyValue[1024];
+ HKEY hkey;
+ DWORD disp, dwType;
+ int rc;
+
+ TCHAR *pszKey = a_pszSubKey;
+
+ _tprintf(_T("Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), a_pszValueToRemove, a_pszSubKey, a_pszKeyValue);
+
+ rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
+ if (rc != ERROR_SUCCESS)
+ {
+ _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc);
+ return EXIT_FAIL;
+ }
+ DWORD cbKeyValue = sizeof(szKeyValue);
+
+ rc = RegQueryValueEx(hkey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
+ if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
+ {
+ _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType);
+ return EXIT_FAIL;
+ }
+
+#ifdef _DEBUG
+ _tprintf(_T("Current key len: %d\n"), cbKeyValue);
+#endif
+
+ TCHAR szCurString[1024] = { 0 };
+ TCHAR szFinalString[1024] = { 0 };
+ int iIndex = 0;
+ int iNewIndex = 0;
+ for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
+ {
+ if (szKeyValue[i] != _T('\0'))
+ szCurString[iIndex++] = szKeyValue[i];
+
+ if ((!szKeyValue[i] == _T('\0')) && szKeyValue[i + 1] == _T('\0'))
+ {
+ if (NULL == wcsstr(szCurString, a_pszValueToRemove))
+ {
+ wcscat(&szFinalString[iNewIndex], szCurString);
+
+ if (iNewIndex == 0)
+ iNewIndex = iIndex;
+ else iNewIndex += iIndex;
+
+ szFinalString[++iNewIndex] = _T('\0');
+ }
+
+ iIndex = 0;
+ ZeroMemory( szCurString, sizeof(szCurString));
+ }
+ }
+
+ szFinalString[++iNewIndex] = _T('\0');
+
+#ifdef _DEBUG
+ _tprintf(_T("New key len: %d\n"), iNewIndex * sizeof(TCHAR));
+ _tprintf(_T("New key value: %ws\n"), szFinalString);
+#endif
+
+ rc = RegSetValueExW(hkey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
+
+ if (rc != ERROR_SUCCESS)
+ {
+ _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
+ return EXIT_FAIL;
+ }
+
+ rc = RegCloseKey(hkey);
+
+ if (rc == ERROR_SUCCESS)
+ {
+ _tprintf(_T("Value successfully removed!\n"), rc);
+ rc = EXIT_OK;
+ }
+
+ return rc;
+}
+
+int CreateService (TCHAR* a_pszStartStopName,
+ TCHAR* a_pszDisplayName,
+ int a_iServiceType,
+ int a_iStartType,
+ TCHAR* a_pszBinPath,
+ TCHAR* a_pszLoadOrderGroup,
+ TCHAR* a_pszDependencies,
+ TCHAR* a_pszLogonUser,
+ TCHAR* a_pszLogonPw)
+{
+ int rc = ERROR_SUCCESS;
+
+ _tprintf(_T("Installing service %ws (%ws) ...\n"), a_pszDisplayName, a_pszStartStopName);
+
+ SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (hSCManager == NULL)
+ {
+ _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
+ return EXIT_FAIL;
+ }
+
+ /* Fixup end of multistring */
+ TCHAR szDepend[ _MAX_PATH ] = { 0 }; /* @todo Use dynamically allocated string here! */
+ if (a_pszDependencies != NULL)
+ {
+ _tcsnccpy (szDepend, a_pszDependencies, wcslen(a_pszDependencies));
+ DWORD len = (DWORD)wcslen (szDepend);
+ szDepend [len + 1] = 0;
+
+ /* Replace comma separator on null separator */
+ for (DWORD i = 0; i < len; i++)
+ {
+ if (',' == szDepend [i])
+ szDepend [i] = 0;
+ }
+ }
+
+ DWORD dwTag = 0xDEADBEAF;
+ SC_HANDLE hService = CreateService (hSCManager, // SCManager database
+ a_pszStartStopName, // name of service
+ a_pszDisplayName, // name to display
+ SERVICE_ALL_ACCESS, // desired access
+ a_iServiceType, // service type
+ a_iStartType, // start type
+ SERVICE_ERROR_NORMAL, // error control type
+ a_pszBinPath, // service's binary
+ a_pszLoadOrderGroup, // ordering group
+ (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL, // tag identifier
+ (a_pszDependencies != NULL) ? szDepend : NULL, // dependencies
+ (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL, // account
+ (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL); // password
+ if (NULL == hService)
+ {
+ DWORD dwErr = GetLastError();
+ switch (dwErr)
+ {
+
+ case ERROR_SERVICE_EXISTS:
+ {
+ _tprintf(_T("Service already exists. No installation required. Updating the service config.\n"));
+
+ hService = OpenService (hSCManager, // SCManager database
+ a_pszStartStopName, // name of service
+ SERVICE_ALL_ACCESS); // desired access
+ if (NULL == hService)
+ {
+ dwErr = GetLastError();
+ _tprintf(_T("Could not open service! Error: %ld\n"), dwErr);
+ }
+ else
+ {
+ BOOL Result = ChangeServiceConfig (hService, // service handle
+ a_iServiceType, // service type
+ a_iStartType, // start type
+ SERVICE_ERROR_NORMAL, // error control type
+ a_pszBinPath, // service's binary
+ a_pszLoadOrderGroup, // ordering group
+ (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL, // tag identifier
+ (a_pszDependencies != NULL) ? szDepend : NULL, // dependencies
+ (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL, // account
+ (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL, // password
+ a_pszDisplayName); // name to display
+ if (Result)
+ {
+ _tprintf(_T("The service config has been successfully updated.\n"));
+ }
+ else
+ {
+ dwErr = GetLastError();
+ _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr);
+ }
+
+ CloseServiceHandle (hService);
+ }
+
+ /* This entire branch do not return an error to avoid installations failures,
+ * if updating service parameters. Better to have a running system with old
+ * parameters and the failure information in the installation log.
+ */
+ break;
+ }
+
+ case ERROR_INVALID_PARAMETER:
+
+ _tprintf(_T("Invalid parameter specified!\n"));
+ rc = EXIT_FAIL;
+ break;
+
+ default:
+
+ _tprintf(_T("Could not create service! Error: %ld\n"), dwErr);
+ rc = EXIT_FAIL;
+ break;
+ }
+
+ if (rc == EXIT_FAIL)
+ goto cleanup;
+ }
+ else
+ {
+ CloseServiceHandle (hService);
+ _tprintf(_T("Installation of service successful!\n"));
+ }
+
+cleanup:
+
+ if (hSCManager != NULL)
+ CloseServiceHandle (hSCManager);
+
+ return rc;
+}
+
+int DelService (TCHAR* a_pszStartStopName)
+{
+ int rc = ERROR_SUCCESS;
+
+ _tprintf(_T("Deleting service '%ws' ...\n"), a_pszStartStopName);
+
+ SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ SC_HANDLE hService = NULL;
+ if (hSCManager == NULL)
+ {
+ _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
+ rc = EXIT_FAIL;
+ }
+ else
+ {
+ hService = OpenService(hSCManager, a_pszStartStopName, SERVICE_ALL_ACCESS);
+ if (NULL == hService)
+ {
+ _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError());
+ rc = EXIT_FAIL;
+ }
+ }
+
+ if (hService != NULL)
+ {
+ if (LockServiceDatabase(hSCManager))
+ {
+ if (FALSE == DeleteService(hService))
+ {
+ DWORD dwErr = GetLastError();
+ switch (dwErr)
+ {
+
+ case ERROR_SERVICE_MARKED_FOR_DELETE:
+
+ _tprintf(_T("Service '%ws' already marked for deletion.\n"), a_pszStartStopName);
+ break;
+
+ default:
+
+ _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError());
+ rc = EXIT_FAIL;
+ break;
+ }
+ }
+ else
+ {
+ _tprintf(_T("Service '%ws' successfully removed!\n"), a_pszStartStopName);
+ }
+ UnlockServiceDatabase(hSCManager);
+ }
+ else
+ {
+ _tprintf(_T("Unable to lock service database! Error: %ld\n"), GetLastError());
+ rc = EXIT_FAIL;
+ }
+ CloseServiceHandle(hService);
+ }
+
+ if (hSCManager != NULL)
+ CloseServiceHandle(hSCManager);
+
+ return rc;
+}
+
+DWORD RegistryWrite(HKEY hRootKey,
+ const _TCHAR *pszSubKey,
+ const _TCHAR *pszValueName,
+ DWORD dwType,
+ const BYTE *pbData,
+ DWORD cbData)
+{
+ DWORD lRet;
+ HKEY hKey;
+ lRet = RegCreateKeyEx (hRootKey,
+ pszSubKey,
+ 0, /* Reserved */
+ NULL, /* lpClass [in, optional] */
+ 0, /* dwOptions [in] */
+ KEY_WRITE,
+ NULL, /* lpSecurityAttributes [in, optional] */
+ &hKey,
+ NULL); /* lpdwDisposition [out, optional] */
+ if (lRet != ERROR_SUCCESS)
+ {
+ _tprintf(_T("Could not open registry key! Error: %ld\n"), GetLastError());
+ }
+ else
+ {
+ lRet = RegSetValueEx(hKey, pszValueName, 0, dwType, (BYTE*)pbData, cbData);
+ if (lRet != ERROR_SUCCESS)
+ _tprintf(_T("Could not write to registry! Error: %ld\n"), GetLastError());
+ RegCloseKey(hKey);
+
+ }
+ return lRet;
+}
+
+void PrintHelp (void)
+{
+ _tprintf(_T("Installs / Uninstalls VirtualBox drivers for Windows XP/2K/Vista\n"));
+ _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
+ _tprintf(_T("Syntax:\n"));
+ _tprintf(_T("\tTo install: VBoxDrvInst /i <HardwareID> <INF-File> <Device Class>\n"));
+ _tprintf(_T("\tTo uninstall: VBoxDrvInst /u <HardwareID>\n"));
+ _tprintf(_T("\tTo execute an INF-File: VBoxDrvInst /inf <INF-File>\n"));
+ _tprintf(_T("\tTo add a network provider: VBoxDrvInst /addnetprovider <Name> [Order]\n\n"));
+ _tprintf(_T("\tTo write registry values: VBoxDrvInst /registry write <root> <sub key> <key name> <key type> <value> [type] [size]\n\n"));
+ _tprintf(_T("Examples:\n"));
+ _tprintf(_T("\tVBoxDrvInst /i \"PCI\\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00\" VBoxVideo.inf Display\n"));
+ _tprintf(_T("\tVBoxDrvInst /addnetprovider VboxSF 1\n\n"));
+}
+
+int __cdecl _tmain (int argc, _TCHAR* argv[])
+{
+ int rc;
+ OSVERSIONINFO OSinfo;
+
+ _TCHAR szHwID[_MAX_PATH] = { 0 }; /* Hardware ID. */
+ _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/
+ _TCHAR szDevClass[_MAX_PATH] = { 0 }; /* Device class. */
+ _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */
+
+ rc = LoadAPICalls();
+ if ( rc == ERROR_SUCCESS
+ && argc >= 2)
+ {
+ OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
+ GetVersionEx(&OSinfo);
+
+ if (0 == _tcsicmp(argv[1], _T("/i")))
+ {
+ if (argc < 5)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ if (OSinfo.dwMajorVersion < 5)
+ {
+ _tprintf(_T("ERROR: Platform not supported yet!\n"));
+ rc = ERROR_NOT_SUPPORTED;
+ }
+
+ if (rc == ERROR_SUCCESS)
+ {
+ _stprintf(szHwID, _T("%ws"), argv[2]);
+ _stprintf(szINF, _T("%ws"), argv[3]);
+ _stprintf(szDevClass, _T("%ws"), argv[4]);
+
+ rc = InstallDriver(szINF, szHwID, szDevClass);
+ }
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/u")))
+ {
+ if (argc < 3)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ if (OSinfo.dwMajorVersion < 5)
+ {
+ _tprintf(_T("ERROR: Platform not supported yet!\n"));
+ rc = ERROR_NOT_SUPPORTED;
+ }
+
+ if (rc == ERROR_SUCCESS)
+ {
+ _stprintf(szHwID, _T("%ws"), argv[2]);
+ rc = UninstallDriver(szHwID);
+ }
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/inf")))
+ {
+ if (argc < 3)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ if (OSinfo.dwMajorVersion < 5)
+ {
+ _tprintf(_T("ERROR: Platform not supported yet!\n"));
+ rc = ERROR_NOT_SUPPORTED;
+ }
+
+ if (rc == ERROR_SUCCESS)
+ {
+ _stprintf(szINF, _T("%ws"), argv[2]);
+ rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);
+ }
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/addnetprovider")))
+ {
+ if (argc < 3)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+
+ int iOrder = 0;
+ if (argc > 3)
+ iOrder = _ttoi(argv[3]);
+ _stprintf(szProvider, _T("%ws"), argv[2]);
+ rc = AddNetworkProvider(szProvider, iOrder);
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/reg_addmultisz")))
+ {
+ if (argc < 6)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ rc = AddStringToMultiSZ(argv[2], argv[3], argv[4], _ttoi(argv[5]));
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/reg_delmultisz")))
+ {
+ if (argc < 5)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ rc = RemoveStringFromMultiSZ(argv[2], argv[3], argv[4]);
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/createsvc")))
+ {
+ if (argc < 7)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ rc = CreateService(
+ argv[2],
+ argv[3],
+ _ttoi(argv[4]),
+ _ttoi(argv[5]),
+ argv[6],
+ (argc > 7) ? argv[7] : NULL,
+ (argc > 8) ? argv[8] : NULL,
+ (argc > 9) ? argv[9] : NULL,
+ (argc > 10) ? argv[10] : NULL);
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/delsvc")))
+ {
+ if (argc < 3)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ rc = DelService(argv[2]);
+ }
+ }
+ else if (0 == _tcsicmp(argv[1], _T("/registry")))
+ {
+ if (argc < 8)
+ {
+ rc = EXIT_USAGE;
+ }
+ else
+ {
+ /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
+ if (0 == _tcsicmp(argv[2], _T("write")))
+ {
+ HKEY hRootKey = HKEY_LOCAL_MACHINE; /** @todo needs to be expanded (argv[3]) */
+ DWORD dwValSize;
+ BYTE *pbVal = NULL;
+ DWORD dwVal;
+
+ if (argc > 8)
+ {
+ if (0 == _tcsicmp(argv[8], _T("dword")))
+ {
+ dwVal = _ttol(argv[7]);
+ pbVal = (BYTE*)&dwVal;
+ dwValSize = sizeof(DWORD);
+ }
+ }
+ if (pbVal == NULL) /* By default interpret value as string */
+ {
+ pbVal = (BYTE*)argv[7];
+ dwValSize = _tcslen(argv[7]);
+ }
+ if (argc > 9)
+ dwValSize = _ttol(argv[9]); /* Get the size in bytes of the value we want to write */
+ rc = RegistryWrite(hRootKey,
+ argv[4], /* Sub key */
+ argv[5], /* Value name */
+ REG_BINARY, /** @todo needs to be expanded (argv[6]) */
+ pbVal, /* The value itself */
+ dwValSize); /* Size of the value */
+ }
+ /*else if (0 == _tcsicmp(argv[2], _T("read")))
+ {
+ }
+ else if (0 == _tcsicmp(argv[2], _T("del")))
+ {
+ }*/
+ else
+ rc = EXIT_USAGE;
+ }
+ }
+ }
+
+ if (rc == EXIT_USAGE)
+ PrintHelp();
+
+ FreeAPICalls();
+ return rc;
+}
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc
new file mode 100644
index 00000000000..d750d3db90f
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.rc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#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 Driver Installer\0"
+ VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ VALUE "InternalName", "VBoxDrvInst\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", "VBoxDrvInst.exe\0"
+ VALUE "ProductName", "VirtualBox Guest Additions\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi
new file mode 100644
index 00000000000..a5e4252bda7
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditions.nsi
@@ -0,0 +1,1126 @@
+
+!if $%BUILD_TYPE% == "debug"
+ !define _DEBUG ; Turn this on to get extra output
+!endif
+
+; Defines for special functions
+!define WHQL_FAKE ; Turns on the faking of non WHQL signed / approved drivers.
+ ; Needs the VBoxWHQLFake.exe in the additions output directory!
+
+!define VENDOR_ROOT_KEY "SOFTWARE\$%VBOX_VENDOR_SHORT%"
+
+!define PRODUCT_NAME "$%VBOX_PRODUCT% Guest Additions"
+!define PRODUCT_DESC "$%VBOX_PRODUCT% Guest Additions"
+!define PRODUCT_VERSION "$%VBOX_VERSION_MAJOR%.$%VBOX_VERSION_MINOR%.$%VBOX_VERSION_BUILD%.0"
+!define PRODUCT_PUBLISHER " $%VBOX_VENDOR%"
+!define PRODUCT_COPYRIGHT "(C) $%VBOX_C_YEAR% $%VBOX_VENDOR%"
+!define PRODUCT_OUTPUT "VBoxWindowsAdditions-$%BUILD_TARGET_ARCH%.exe"
+!define PRODUCT_WEB_SITE "http://www.virtualbox.org"
+!define PRODUCT_INSTALL_KEY "${VENDOR_ROOT_KEY}\VirtualBox Guest Additions"
+!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+!define PRODUCT_UNINST_ROOT_KEY "HKLM"
+
+VIProductVersion "${PRODUCT_VERSION}"
+VIAddVersionKey "FileVersion" "$%VBOX_VERSION_STRING%"
+VIAddVersionKey "ProductName" "${PRODUCT_NAME}"
+VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}"
+VIAddVersionKey "CompanyName" "${PRODUCT_PUBLISHER}"
+VIAddVersionKey "FileDescription" "${PRODUCT_DESC}"
+VIAddVersionKey "LegalCopyright" "${PRODUCT_COPYRIGHT}"
+VIAddVersionKey "InternalName" "${PRODUCT_OUTPUT}"
+
+; This registry key will hold the mouse driver path before install (NT4 only)
+!define ORG_MOUSE_PATH "MousePath"
+
+!include "LogicLib.nsh"
+!include "FileFunc.nsh"
+ !insertmacro GetParameters
+ !insertmacro GetOptions
+!include "WordFunc.nsh"
+ !insertmacro WordFind
+ !insertmacro StrFilter
+
+!include "nsProcess.nsh"
+!include "Library.nsh"
+!include "strstr.nsh" ; Function "strstr"
+!include "servicepack.nsh" ; Function "GetServicePack"
+!include "winver.nsh" ; Function for determining Windows version
+!define REPLACEDLL_NOREGISTER ; Replace in use DLL function
+!include "ReplaceDLL.nsh"
+!include "dumplog.nsh" ; Dump log to file function
+
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ !include "x64.nsh"
+!endif
+
+; Use modern UI (MUI)
+!include "MUI.nsh"
+
+; MUI Settings
+!define MUI_WELCOMEFINISHPAGE_BITMAP "$%VBOX_BRAND_WIN_ADD_INST_DLGBMP%"
+!define MUI_ABORTWARNING
+!define MUI_WELCOMEPAGE_TITLE_3LINES "Welcome to the ${PRODUCT_NAME} Additions Setup"
+
+; API defines
+!define SM_CLEANBOOT 67
+
+; Icons
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ !define MUI_ICON "$%VBOX_NSIS_ICON_FILE%"
+ !define MUI_UNICON "$%VBOX_NSIS_ICON_FILE%"
+!else ; 64-bit
+ !define MUI_ICON "$%VBOX_WINDOWS_ADDITIONS_ICON_FILE%"
+ !define MUI_UNICON "$%VBOX_WINDOWS_ADDITIONS_ICON_FILE%"
+!endif
+
+; Welcome page
+!insertmacro MUI_PAGE_WELCOME
+; License page
+!insertmacro MUI_PAGE_LICENSE "$(VBOX_LICENSE)"
+!define MUI_LICENSEPAGE_RADIOBUTTONS
+; Directory page
+!insertmacro MUI_PAGE_DIRECTORY
+; Components Page
+!insertmacro MUI_PAGE_COMPONENTS
+; Instfiles page
+!insertmacro MUI_PAGE_INSTFILES
+
+!ifndef _DEBUG
+ !define MUI_FINISHPAGE_TITLE_3LINES ; Have a bit more vertical space for text
+ !insertmacro MUI_PAGE_FINISH ; Only show in release mode - useful information for debugging!
+!endif
+
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_INSTFILES
+
+; Define languages we will use
+!insertmacro MUI_LANGUAGE "English"
+!insertmacro MUI_LANGUAGE "French"
+!insertmacro MUI_LANGUAGE "German"
+
+; Set branding text which appears on the horizontal line at the bottom
+BrandingText "VirtualBox Windows Additions"
+
+; Set license language
+LicenseLangString VBOX_LICENSE ${LANG_ENGLISH} "$%VBOX_BRAND_LICENSE_RTF%"
+
+; If license files not available (OSE / PUEL) build, then use the English one as default.
+!ifdef VBOX_BRAND_fr_FR_LICENSE_RTF
+ LicenseLangString VBOX_LICENSE ${LANG_FRENCH} "$%VBOX_BRAND_fr_FR_LICENSE_RTF%"
+!else
+ LicenseLangString VBOX_LICENSE ${LANG_FRENCH} "$%VBOX_BRAND_LICENSE_RTF%"
+!endif
+!ifdef VBOX_BRAND_de_DE_LICENSE_RTF
+ LicenseLangString VBOX_LICENSE ${LANG_GERMAN} "$%VBOX_BRAND_de_DE_LICENSE_RTF%"
+!else
+ LicenseLangString VBOX_LICENSE ${LANG_GERMAN} "$%VBOX_BRAND_LICENSE_RTF%"
+!endif
+
+!insertmacro MUI_RESERVEFILE_LANGDLL
+; MUI end ------
+
+; Language files
+!include "Languages\English.nsh"
+!include "Languages\French.nsh"
+!include "Languages\German.nsh"
+
+; Variables and output files
+Name "${PRODUCT_NAME} $%VBOX_VERSION_STRING%"
+!ifdef UNINSTALLER_ONLY
+!echo "Uninstaller only!"
+OutFile "$%PATH_TARGET%\VBoxWindowsAdditions-$%BUILD_TARGET_ARCH%-uninst.exe"
+!else
+OutFile "VBoxWindowsAdditions-$%BUILD_TARGET_ARCH%.exe"
+!endif
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ InstallDir "$PROGRAMFILES32\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions"
+!else ; 64-bit
+ InstallDir "$PROGRAMFILES64\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions"
+!endif
+
+InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
+ShowInstDetails show
+ShowUnInstDetails show
+RequestExecutionLevel highest
+
+Var g_iSystemMode ; Current system mode (0 = Normal boot, 1 = Fail-safe boot, 2 = Fail-safe with network boot)
+Var g_strSystemDir ; Windows system directory
+Var g_strCurUser ; Current user using the system
+Var g_strAddVerMaj ; Installed Guest Additions: Major version
+Var g_strAddVerMin ; Installed Guest Additions: Minor version
+Var g_strAddVerBuild ; Installed Guest Additions: Build number
+Var g_strAddVerRev ; Installed Guest Additions: SVN revision
+Var g_strWinVersion ; Current Windows version we're running on
+Var g_bLogEnable ; Do logging when installing? "true" or "false"
+Var g_bFakeWHQL ; Cmd line: Fake Windows to install non WHQL certificated drivers (only for W2K and XP currently!!) ("/unsig_drv")
+Var g_bUninstall ; Cmd line: Just uninstall any previous Guest Additions and exit
+Var g_bRebootOnExit ; Cmd line: Auto-Reboot on successful installation. Good for unattended installations ("/reboot")
+Var g_iScreenBpp ; Cmd line: Screen depth ("/depth=X")
+Var g_iScreenX ; Cmd line: Screen resolution X ("/resx=X")
+Var g_iScreenY ; Cmd line: Screen resolution Y ("/resy=Y")
+Var g_iSfOrder ; Cmd line: Order of Shared Folders network provider (0=first, 1=second, ...)
+Var g_bNoVideoDrv ; Cmd line: Do not install the VBoxVideo driver
+Var g_bNoGuestDrv ; Cmd line: Do not install the VBoxGuest driver
+Var g_bNoMouseDrv ; Cmd line: Do not install the VBoxMouse driver
+Var g_bWithAutoLogon ; Cmd line: Install VBoxGINA / VBoxCredProv for auto logon support
+Var g_bWithD3D ; Cmd line: Install Direct3D support
+Var g_bOnlyExtract ; Cmd line: Only extract all files, do *not* install them. Only valid with param "/D" (target directory)
+
+; Platform parts of this installer
+!include "VBoxGuestAdditionsCommon.nsh"
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit only
+!include "VBoxGuestAdditionsNT4.nsh"
+!endif
+!include "VBoxGuestAdditionsW2KXP.nsh"
+!include "VBoxGuestAdditionsVista.nsh"
+!include "VBoxGuestAdditionsUninstall.nsh" ; Product uninstallation
+!include "VBoxGuestAdditionsUninstallOld.nsh" ; Uninstallation of deprecated versions which must be removed first
+
+Function HandleCommandLine
+
+ Push $0 ; Command line (without process name)
+ Push $1 ; Number of parameters
+ Push $2 ; Current parameter index
+ Push $3 ; Current parameter pair (name=value)
+ Push $4 ; Current parameter name
+ Push $5 ; Current parameter value (if present)
+
+ StrCpy $1 "0" ; Init param counter
+ StrCpy $2 "1" ; Init current param counter
+
+ ${GetParameters} $0 ; Extract command line
+ ${If} $0 == "" ; If no parameters at all exit
+ Goto exit
+ ${EndIf}
+
+ ; Enable for debugging
+ ;MessageBox MB_OK "CmdLine: $0"
+
+ ${WordFind} $0 " " "#" $1 ; Get number of parameters in cmd line
+ ${If} $0 == $1 ; If result matches the input then
+ StrCpy $1 "1" ; no delimeter was found. Correct to 1 word total.
+ ${EndIf}
+
+ ${While} $2 <= $1 ; Loop through all params
+
+ ${WordFind} $0 " " "+$2" $3 ; Get current name=value pair
+ ${WordFind} $3 "=" "+1" $4 ; Get current param name
+ ${WordFind} $3 "=" "+2" $5 ; Get current param value
+
+ ${StrFilter} $4 "-" "" "" $4 ; Transfor param name to lowercase
+
+ ; Enable for debugging
+ ;MessageBox MB_OK "#$2 of #$1, param='$3', name=$4, val=$5"
+
+ ${Switch} $4
+
+ ${Case} '/d' ; NSIS: /D=<instdir> switch, skip
+ ${Break}
+
+ ${Case} '/depth'
+ ${Case} 'depth'
+ StrCpy $g_iScreenBpp $5
+ ${Break}
+
+ ${Case} '/extract'
+ StrCpy $g_bOnlyExtract "true"
+ ${Break}
+
+ ${Case} '/help'
+ ${Case} '/H'
+ ${Case} '/h'
+ ${Case} '/?'
+ Goto usage
+ ${Break}
+
+ ${Case} '/l'
+ ${Case} '/log'
+ ${Case} '/logging'
+ StrCpy $g_bLogEnable "true"
+ ${Break}
+
+ ${Case} '/ncrc' ; NSIS: /NCRC switch, skip
+ ${Break}
+
+ ${Case} '/no_videodrv'
+ StrCpy $g_bNoVideoDrv "true"
+ ${Break}
+
+ ${Case} '/no_guestdrv'
+ StrCpy $g_bNoGuestDrv "true"
+ ${Break}
+
+ ${Case} '/no_mousedrv'
+ StrCpy $g_bNoMouseDrv "true"
+ ${Break}
+
+ ${Case} '/reboot'
+ StrCpy $g_bRebootOnExit "true"
+ ${Break}
+
+ ${Case} '/s' ; NSIS: /S switch, skip
+ ${Break}
+
+ ${Case} '/sforder'
+ ${Case} 'sforder'
+ StrCpy $g_iSfOrder $5
+ ${Break}
+
+ !ifdef WHQL_FAKE
+ ${Case} '/unsig_drv'
+ StrCpy $g_bFakeWHQL "true"
+ ${Break}
+ !endif
+
+ ${Case} '/uninstall'
+ StrCpy $g_bUninstall "true"
+ ${Break}
+
+ ${Case} '/with_autologon'
+ StrCpy $g_bWithAutoLogon "true"
+ ${Break}
+
+ !if $%VBOX_WITH_CROGL% == "1"
+ ${Case} '/with_d3d'
+ ${Case} '/with_direct3d'
+ StrCpy $g_bWithD3D "true"
+ ${Break}
+ !endif
+
+ ${Case} '/xres'
+ ${Case} 'xres'
+ StrCpy $g_iScreenX $5
+ ${Break}
+
+ ${Case} '/yres'
+ ${Case} 'yres'
+ StrCpy $g_iScreenY $5
+ ${Break}
+
+ ${Default} ; Unknown parameter, print usage message
+ goto usage
+ ${Break}
+
+ ${EndSwitch}
+ IntOp $2 $2 + 1
+
+ ${EndWhile}
+ Goto exit
+
+usage:
+
+ MessageBox MB_OK "${PRODUCT_NAME} Installer$\r$\n$\r$\n \
+ Usage: VBoxWindowsAdditions-$%BUILD_TARGET_ARCH% [OPTIONS] [/l] [/S] [/D=<PATH>]$\r$\n$\r$\n \
+ Options:$\r$\n \
+ /depth=BPP$\tSets the guest's display color depth (bits per pixel)$\r$\n \
+ /extract$\t$\tOnly extract installation files$\r$\n \
+ /uninstall$\t$\tJust uninstalls the Guest Additions and exits$\r$\n \
+ /with_autologon$\tInstalls auto-logon support$\r$\n \
+ /with_d3d$\tInstalls D3D support$\r$\n \
+ /xres=X$\t$\tSets the guest's display resolution (width in pixels)$\r$\n \
+ /yres=Y$\t$\tSets the guest's display resolution (height in pixels)$\r$\n \
+ $\r$\n \
+ Installer parameters:$\r$\n \
+ /l$\t$\tEnables logging$\r$\n \
+ /S$\t$\tSilent install$\r$\n \
+ /D=<PATH>$\tSets the default install path$\r$\n \
+ $\r$\n \
+ Note: Order of options and installer parameters are mandatory."
+
+ ; No stack restore needed, we're about to quit
+ Quit
+
+done:
+
+ IfSilent 0 +2
+ LogText "Installer is in silent mode!"
+
+ LogText "Property: XRes: $g_iScreenX"
+ LogText "Property: YRes: $g_iScreenY"
+ LogText "Property: BPP: $g_iScreenBpp"
+ LogText "Property: Logging enabled: $g_bLogEnable"
+
+exit:
+
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+
+Function CheckForOldGuestAdditions
+
+ Push $0
+ Push $1
+ Push $2
+
+begin:
+
+sun_check:
+
+ ; Check for old "Sun VirtualBox Guest Additions"
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" sun_xvm_check ; If string is empty, Sun additions are probably not installed (anymore).
+
+ MessageBox MB_YESNO $(VBOX_SUN_FOUND) /SD IDYES IDYES sun_uninstall
+ Pop $2
+ Pop $1
+ Pop $0
+ MessageBox MB_ICONSTOP $(VBOX_SUN_ABORTED) /SD IDOK
+ Quit
+
+sun_uninstall:
+
+ Call Uninstall_Sun
+ Goto success
+
+sun_xvm_check:
+
+ ; Check for old "innotek" Guest Additions" before rebranding to "Sun"
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" innotek_check ; If string is empty, Sun xVM additions are probably not installed (anymore).
+
+ MessageBox MB_YESNO $(VBOX_SUN_FOUND) /SD IDYES IDYES sun_xvm_uninstall
+ Pop $2
+ Pop $1
+ Pop $0
+ MessageBox MB_ICONSTOP $(VBOX_SUN_ABORTED) /SD IDOK
+ Quit
+
+sun_xvm_uninstall:
+
+ Call Uninstall_SunXVM
+ Goto success
+
+innotek_check:
+
+ ; Check for old "innotek" Guest Additions" before rebranding to "Sun"
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit ; If string is empty, Guest Additions are probably not installed (anymore).
+
+ MessageBox MB_YESNO $(VBOX_INNOTEK_FOUND) /SD IDYES IDYES innotek_uninstall
+ Pop $2
+ Pop $1
+ Pop $0
+ MessageBox MB_ICONSTOP $(VBOX_INNOTEK_ABORTED) /SD IDOK
+ Quit
+
+innotek_uninstall:
+
+ Call Uninstall_Innotek
+ Goto success
+
+success:
+
+ ; Nothing to do here yet
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+
+Function CheckArchitecture
+
+ System::Call "kernel32::GetCurrentProcess() i .s"
+ System::Call "kernel32::IsWow64Process(i s, *i .r0)"
+ DetailPrint "Running on 64bit: $0"
+
+!if $%BUILD_TARGET_ARCH% == "amd64" ; 64-bit
+ IntCmp $0 0 not_32bit_platform
+!else ; 32-bit
+ IntCmp $0 1 not_64bit_platform
+!endif
+
+ Goto exit
+
+not_32bit_platform:
+
+ MessageBox MB_ICONSTOP $(VBOX_NOTICE_ARCH_AMD64) /SD IDOK
+ Quit
+
+not_64bit_platform:
+
+ MessageBox MB_ICONSTOP $(VBOX_NOTICE_ARCH_X86) /SD IDOK
+ Quit
+
+exit:
+
+FunctionEnd
+
+Function PrepareForUpdate
+
+ StrCmp $g_strAddVerMaj "1" v1 ; Handle major version "v1.x"
+ StrCmp $g_strAddVerMaj "2" v2 ; Handle major version "v2.x"
+ StrCmp $g_strAddVerMaj "3" v3 ; Handle major version "v3.x"
+ Goto exit
+
+v3:
+
+ Goto exit
+
+v2:
+
+ Goto exit
+
+v1:
+
+ StrCmp $g_strAddVerMin "5" v1_5 ; Handle major version "v1.5.x"
+ StrCmp $g_strAddVerMin "6" v1_6 ; Handle major version "v1.6.x"
+
+v1_5:
+
+ Goto exit
+
+v1_6:
+
+ Goto exit
+
+exit:
+
+FunctionEnd
+
+Function Common_CopyFiles
+
+ SetOutPath "$INSTDIR"
+ SetOverwrite on
+
+ FILE "$%PATH_OUT%\bin\additions\VBoxDrvInst.exe"
+
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.cat"
+!endif
+
+ FILE "iexplore.ico"
+
+FunctionEnd
+
+; Main Files
+Section $(VBOX_COMPONENT_MAIN) SEC01
+
+ SectionIn RO ; Section cannot be unselected (read-only)
+
+ SetOutPath "$INSTDIR"
+ SetOverwrite on
+
+ ; Because this NSIS installer is always built in 32-bit mode, we have to
+ ; do some tricks for the Windows paths
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ ; Because the next two lines will crash at the license page (??) we have to re-enable that here again
+ ${DisableX64FSRedirection}
+ SetRegView 64
+!endif
+
+ StrCpy $g_strSystemDir "$SYSDIR"
+ DetailPrint "System Directory: $g_strSystemDir"
+
+ Call EnableLog
+ Call PrepareForUpdate
+
+ DetailPrint "Version: $%VBOX_VERSION_STRING%"
+ ${If} $g_strAddVerMaj != ""
+ DetailPrint "Previous version: $g_strAddVerMaj.$g_strAddVerMin.$g_strAddVerBuild (Rev $g_strAddVerRev)"
+ ${Else}
+ DetailPrint "No previous version of ${PRODUCT_NAME} detected."
+ ${EndIf}
+ DetailPrint "Handled Windows version: $g_strWinVersion"
+
+!ifdef _DEBUG
+ DetailPrint "Debug!"
+!endif
+
+ ; Which OS we are using?
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ StrCmp $g_strWinVersion "nt4" nt4
+!endif
+ StrCmp $g_strWinVersion "2k" w2k
+ StrCmp $g_strWinVersion "vista" vista
+
+ Goto notsupported
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+nt4: ; Windows NT4
+
+ Call GetServicePack
+ Pop $R0 ; Major version
+ Pop $R1 ; Minor version
+
+ ; At least Service Pack 6 installed?
+ StrCmp $R0 "6" +3
+ MessageBox MB_YESNO $(VBOX_NT4_NO_SP6) /SD IDYES IDYES +2
+ Quit
+
+ ; Copy some common files ...
+ Call Common_CopyFiles
+
+ Call NT_Main
+ goto success
+!endif
+
+vista: ; Windows Vista (fall through, needs stuff from w2k label, too)
+
+ ; Copy some common files ...
+ Call Common_CopyFiles
+
+ Call W2K_Main ; First install stuff from Windows 2000 / XP
+ Call Vista_Main ; ... and some specific stuff for Vista
+ goto success
+
+w2k: ; Windows 2000 and XP ...
+
+ ; Copy some common files ...
+ Call Common_CopyFiles
+
+ Call W2K_Main
+ goto success
+
+notsupported:
+
+ MessageBox MB_ICONSTOP $(VBOX_PLATFORM_UNSUPPORTED) /SD IDOK
+ goto exit
+
+success:
+
+ ; Write a registry key with version and installation path for later lookup
+ WriteRegStr HKLM "${PRODUCT_INSTALL_KEY}" "Version" "$%VBOX_VERSION_STRING%"
+ WriteRegStr HKLM "${PRODUCT_INSTALL_KEY}" "Revision" "$%VBOX_SVN_REV%"
+ WriteRegStr HKLM "${PRODUCT_INSTALL_KEY}" "InstallDir" "$INSTDIR"
+
+!ifndef _DEBUG
+ SetRebootFlag true ; This will show a reboot page at end of installation
+!endif
+
+exit:
+
+ Call WriteLogUI
+
+SectionEnd
+
+; Auto-logon support (section is hidden at the moment -- only can be enabled via command line switch)
+Section /o -$(VBOX_COMPONENT_AUTOLOGON) SEC02
+
+ ; Because this NSIS installer is always built in 32-bit mode, we have to
+ ; do some tricks for the Windows paths.
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ ; Because the next two lines will crash at the license page (??) we have to re-enable that here again
+ ${DisableX64FSRedirection}
+ SetRegView 64
+!endif
+
+ Call GetWindowsVersion
+ Pop $R0 ; Windows Version
+
+ DetailPrint "Installing auto-logon support ..."
+
+ ; Another GINA already is installed? Check if this is ours, otherwise let the user decide (unless it's a silent setup)
+ ; whether to replace it with the VirtualBox one or not.
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL"
+ ${If} $0 != ""
+ ${If} $0 != "VBoxGINA.dll"
+ MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1 $(VBOX_COMPONENT_AUTOLOGON_WARN_3RDPARTY) /SD IDYES IDYES install
+ goto exit
+ ${EndIf}
+ ${EndIf}
+
+install:
+
+ ; Do we need VBoxCredProv or VBoxGINA?
+ ${If} $R0 == 'Vista'
+ ${OrIf} $R0 == '7'
+ !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxCredProv.dll" "$g_strSystemDir\VBoxCredProv.dll" "$INSTDIR"
+ WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}" "" "VBoxCredProv" ; adding to (default) key
+ WriteRegStr HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}" "" "VBoxCredProv" ; adding to (Default) key
+ WriteRegStr HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}\InprocServer32" "" "VBoxCredProv.dll" ; adding to (Default) key
+ WriteRegStr HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}\InprocServer32" "ThreadingModel" "Apartment"
+ ${Else}
+ !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxGINA.dll" "$g_strSystemDir\VBoxGINA.dll" "$INSTDIR"
+ WriteRegStr HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL" "VBoxGINA.dll"
+ ${EndIf}
+
+exit:
+
+SectionEnd
+
+; Prepares the access rights for replacing a WRP protected file
+Function PrepareWRPFile
+
+ Pop $0
+ IfFileExists "$g_strSystemDir\takeown.exe" 0 +2
+ nsExec::ExecToLog '"$g_strSystemDir\takeown.exe" /F "$0"'
+ AccessControl::SetFileOwner "$0" "(S-1-5-32-545)"
+ Pop $1
+ DetailPrint "Setting file owner for '$0': $1"
+ AccessControl::GrantOnFile "$0" "(S-1-5-32-545)" "FullAccess"
+ Pop $1
+ DetailPrint "Setting access rights for '$0': $1"
+
+FunctionEnd
+
+; Direct3D support
+!if $%VBOX_WITH_CROGL% == "1"
+Section /o $(VBOX_COMPONENT_D3D) SEC03
+
+ Push $R0
+
+ Call GetWindowsVersion
+ Pop $R0 ; Windows Version
+
+ ; If we're not in safe mode, print a warning and do nothing here
+ ${If} $g_iSystemMode == '0'
+ DetailPrint "System is not in safe mode, D3D support will not be installed!"
+ Return
+ ${EndIf}
+
+ ; Do not install on < XP
+ ${If} $R0 == 'NT 3'
+ ${OrIf} $R0 == 'NT 4'
+ ${OrIf} $R0 == '2000'
+ ${OrIf} $R0 == ''
+ DetailPrint "Direct3D guest support not available on this platform!"
+ Return
+ ${EndIf}
+
+ !define LIBRARY_IGNORE_VERSION ; Install in every case
+ SetOverwrite on
+
+ ${If} $g_strSystemDir == ''
+ StrCpy $g_strSystemDir "$SYSDIR"
+ ${EndIf}
+
+ ; crOpenGL: Do *not* install 64-bit files - they don't work yet (use !define LIBRARY_X64 later)
+ ; Only 32-bit apps on 64-bit work (see next block)
+ !if $%BUILD_TARGET_ARCH% == "x86"
+ SetOutPath $g_strSystemDir
+ DetailPrint "Installing Direct3D support ..."
+ FILE "$%PATH_OUT%\bin\additions\libWine.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxD3D8.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxD3D9.dll"
+ FILE "$%PATH_OUT%\bin\additions\wined3d.dll"
+
+ ; Update DLL cache
+ SetOutPath "$g_strSystemDir\dllcache"
+ IfFileExists "$g_strSystemDir\dllcache\msd3d8.dll" +1
+ CopyFiles /SILENT "$g_strSystemDir\dllcache\d3d8.dll" "$g_strSystemDir\dllcache\msd3d8.dll"
+ IfFileExists "$g_strSystemDir\dllcache\msd3d9.dll" +1
+ CopyFiles /SILENT "$g_strSystemDir\dllcache\d3d9.dll" "$g_strSystemDir\dllcache\msd3d9.dll"
+
+ Push "$g_strSystemDir\dllcache\d3d8.dll"
+ Call PrepareWRPFile
+
+ Push "$g_strSystemDir\dllcache\d3d9.dll"
+ Call PrepareWRPFile
+
+ ; Exchange DLLs
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\dllcache\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\dllcache\d3d9.dll" "$TEMP"
+
+ ; If exchange above failed, do it on reboot
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\dllcache\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\dllcache\d3d9.dll" "$TEMP"
+
+ ; Save original DLLs ...
+ SetOutPath $g_strSystemDir
+ IfFileExists "$g_strSystemDir\msd3d8.dll" +1
+ CopyFiles /SILENT "$g_strSystemDir\d3d8.dll" "$g_strSystemDir\msd3d8.dll"
+ IfFileExists "$g_strSystemDir\msd3d8.dll" +1
+ CopyFiles /SILENT "$g_strSystemDir\d3d9.dll" "$g_strSystemDir\msd3d9.dll"
+
+ Push "$g_strSystemDir\d3d8.dll"
+ Call PrepareWRPFile
+
+ Push "$g_strSystemDir\d3d9.dll"
+ Call PrepareWRPFile
+
+ ; Exchange DLLs
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\d3d9.dll" "$TEMP"
+
+ ; If exchange above failed, do it on reboot
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d8.dll" "$g_strSystemDir\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%PATH_OUT%\bin\additions\d3d9.dll" "$g_strSystemDir\d3d9.dll" "$TEMP"
+ !endif
+
+ !if $%BUILD_TARGET_ARCH% == "amd64"
+ ; Only 64-bit installer: Also copy 32-bit DLLs on 64-bit target arch in
+ ; Wow64 node (32-bit sub system)
+ ${EnableX64FSRedirection}
+ SetOutPath $SYSDIR
+ DetailPrint "Installing Direct3D support (Wow64) ..."
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\libWine.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D8.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D9.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\wined3d.dll"
+
+ ; Update DLL cache
+ SetOutPath "$SYSDIR\dllcache"
+ IfFileExists "$SYSDIR\dllcache\msd3d8.dll" +1
+ CopyFiles /SILENT "$SYSDIR\dllcache\d3d8.dll" "$SYSDIR\dllcache\msd3d8.dll"
+ IfFileExists "$SYSDIR\dllcache\msd3d9.dll" +1
+ CopyFiles /SILENT "$SYSDIR\dllcache\d3d9.dll" "$SYSDIR\dllcache\msd3d9.dll"
+
+ Push "$SYSDIR\dllcache\d3d8.dll"
+ Call PrepareWRPFile
+
+ Push "$SYSDIR\dllcache\d3d9.dll"
+ Call PrepareWRPFile
+
+ ; Exchange DLLs
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\dllcache\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\dllcache\d3d9.dll" "$TEMP"
+
+ ; If exchange above failed, do it on reboot
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\dllcache\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\dllcache\d3d9.dll" "$TEMP"
+
+ ; Save original DLLs ...
+ SetOutPath $SYSDIR
+ IfFileExists "$SYSDIR\dllcache\msd3d8.dll" +1
+ CopyFiles /SILENT "$SYSDIR\d3d8.dll" "$SYSDIR\msd3d8.dll"
+ IfFileExists "$SYSDIR\dllcache\msd3d9.dll" +1
+ CopyFiles /SILENT "$SYSDIR\d3d9.dll" "$SYSDIR\msd3d9.dll"
+
+ Push "$SYSDIR\d3d8.dll"
+ Call PrepareWRPFile
+
+ Push "$SYSDIR\d3d9.dll"
+ Call PrepareWRPFile
+
+ ; Exchange DLLs
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED NOREBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\d3d9.dll" "$TEMP"
+
+ ; If exchange above failed, do it on reboot
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll" "$SYSDIR\d3d8.dll" "$TEMP"
+ !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll" "$SYSDIR\d3d9.dll" "$TEMP"
+
+ ${DisableX64FSRedirection}
+ !endif ; amd64
+ Goto done
+
+error:
+ ; @todo
+ Goto exit
+
+done:
+ MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_WFP_WARN_REPLACE) /SD IDOK
+ Goto exit
+
+ Pop $R0
+
+exit:
+
+SectionEnd
+!endif ; VBOX_WITH_CROGL
+
+;Assign language strings to sections
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} $(VBOX_COMPONENT_MAIN_DESC)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SEC02} $(VBOX_COMPONENT_AUTOLOGON_DESC)
+!if $%VBOX_WITH_CROGL% == "1"
+ !insertmacro MUI_DESCRIPTION_TEXT ${SEC03} $(VBOX_COMPONENT_D3D_DESC)
+!endif
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+Section -Content
+
+ WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
+
+SectionEnd
+
+Section -StartMenu
+
+ CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" "" "$INSTDIR\iexplore.ico"
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\uninst.exe"
+
+SectionEnd
+
+; This section is called after all the files are in place
+Section -Post
+
+!ifdef _DEBUG
+ DetailPrint "Doing post install ..."
+!endif
+
+!ifdef EXTERNAL_UNINSTALLER
+ SetOutPath "$INSTDIR"
+ FILE "$%PATH_TARGET%\uninst.exe"
+!else
+ WriteUninstaller "$INSTDIR\uninst.exe"
+!endif
+
+ ; Write uninstaller in "Add / Remove programs"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+
+ ; Tune TcpWindowSize for a better network throughput
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" "TcpWindowSize" 64240
+
+ DetailPrint "Installation completed."
+
+SectionEnd
+
+; This function is called when a critical error occured
+Function .onInstFailed
+
+ MessageBox MB_ICONSTOP $(VBOX_ERROR_INST_FAILED) /SD IDOK
+ StrCpy $g_bLogEnable "true"
+ Call WriteLogUI
+ SetErrorLevel 1
+
+FunctionEnd
+
+; This function is called when installation was successful!
+Function .onInstSuccess
+
+ ; Nothing to do here yet ...
+
+FunctionEnd
+
+; This function is called at the very beginning of installer execution
+Function .onInit
+
+ ; Init values
+ StrCpy $g_iSystemMode "0"
+ StrCpy $g_strAddVerMaj "0"
+ StrCpy $g_strAddVerMin "0"
+ StrCpy $g_strAddVerBuild "0"
+ StrCpy $g_strAddVerRev "0"
+
+ StrCpy $g_bLogEnable "false"
+ StrCpy $g_bFakeWHQL "false"
+ StrCpy $g_bUninstall "false"
+ StrCpy $g_bRebootOnExit "false"
+ StrCpy $g_iScreenX "0"
+ StrCpy $g_iScreenY "0"
+ StrCpy $g_iScreenBpp "0"
+ StrCpy $g_iSfOrder "0"
+ StrCpy $g_bNoVideoDrv "false"
+ StrCpy $g_bNoGuestDrv "false"
+ StrCpy $g_bNoMouseDrv "false"
+ StrCpy $g_bWithAutoLogon "false"
+ StrCpy $g_bWithD3D "false"
+ StrCpy $g_bOnlyExtract "false"
+
+ SetErrorLevel 0
+ ClearErrors
+
+!ifndef UNINSTALLER_ONLY
+
+ ; Handle command line
+ Call HandleCommandLine
+
+ ; Retrieve Windows version and store result in $g_strWinVersion
+ Call GetWindowsVer
+
+ ; Retrieve system mode and store result in
+ System::Call 'user32::GetSystemMetrics(i ${SM_CLEANBOOT}) i .r0'
+ StrCpy $g_iSystemMode $0
+ DetailPrint "System mode: $g_iSystemMode"
+
+ ; Get user Name
+ AccessControl::GetCurrentUserName
+ Pop $g_strCurUser
+ DetailPrint "Current user: $g_strCurUser"
+
+ ; Only uninstall?
+ StrCmp $g_bUninstall "true" uninstall
+
+ ; Only extract files?
+ StrCmp $g_bOnlyExtract "true" extract_files
+
+ ; Set section bits
+ ${If} $g_bWithAutoLogon == "true" ; Auto-logon support
+ SectionSetFlags ${SEC02} ${SF_SELECTED}
+ ${EndIf}
+!if $%VBOX_WITH_CROGL% == "1"
+ ${If} $g_bWithD3D == "true" ; D3D support
+ SectionSetFlags ${SEC03} ${SF_SELECTED}
+ ${EndIf}
+!endif
+
+ ; Display language selection dialog (will be hidden in silent mode!)
+ !ifdef VBOX_INSTALLER_ADD_LANGUAGES
+ !insertmacro MUI_LANGDLL_DISPLAY
+ !endif
+
+ ; Do some checks before we actually start ...
+ Call IsUserAdmin
+
+ ; Check if there's already another instance of the installer is running -
+ ; important for preventing NT4 to spawn the installer twice
+ System::Call 'kernel32::CreateMutexA(i 0, i 0, t "VBoxGuestInstaller") ?e'
+ Pop $R0
+ StrCmp $R0 0 +1 exit
+
+ ; Check for correct architecture
+ Call CheckArchitecture
+
+ ; Because this NSIS installer is always built in 32-bit mode, we have to
+ ; do some tricks for the Windows paths for checking for old additions
+ ; in block below.
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ ${DisableX64FSRedirection}
+ SetRegView 64
+!endif
+
+ ; Check for old additions
+ Call CheckForOldGuestAdditions
+ Call GetAdditionsVersion
+
+ ; Due to some bug in NSIS the license page won't be displayed if we're in
+ ; 64-bit registry view, so as a workaround switch back to 32-bit (Wow6432Node)
+ ; mode for now.
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ ${EnableX64FSRedirection}
+ SetRegView 32
+!endif
+
+ Goto done
+
+uninstall:
+
+ Call Uninstall_Innotek
+ Call Uninstall
+ MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_UNINST_SUCCESS) /SD IDOK
+ Goto exit
+
+extract_files:
+
+ Call ExtractFiles
+ MessageBox MB_OK|MB_ICONINFORMATION $(VBOX_EXTRACTION_COMPLETE) /SD IDOK
+ Goto exit
+
+!else ; UNINSTALLER_ONLY
+
+ ;
+ ; If UNINSTALLER_ONLY is defined, we're only interested in uninst.exe
+ ; so we can sign it.
+ ;
+ ; Note that the Quit causes the exit status to be 2 instead of 0.
+ ;
+ WriteUninstaller "$%PATH_TARGET%\uninst.exe"
+ Goto exit
+
+!endif ; UNINSTALLER_ONLY
+
+exit: ; Abort installer for some reason
+
+ Quit
+
+done:
+
+FunctionEnd
+
+;
+; The uninstaller is built separately when doing code signing.
+; For some reason NSIS still finds the Uninstall section even
+; when EXTERNAL_UNINSTALLER is defined. This causes a silly warning.
+;
+!ifndef EXTERNAL_UNINSTALLER
+
+Function un.onUninstSuccess
+
+ HideWindow
+ MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_UNINST_SUCCESS) /SD IDOK
+
+FunctionEnd
+
+Function un.onInit
+
+ Call un.IsUserAdmin
+
+ MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 $(VBOX_UNINST_CONFIRM) /SD IDYES IDYES proceed
+ Quit
+
+proceed:
+
+ ; Because this NSIS installer is always built in 32-bit mode, we have to
+ ; do some tricks for the Windows paths.
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ ${DisableX64FSRedirection}
+ SetRegView 64
+!endif
+
+ ; Set system directory.
+ StrCpy $g_strSystemDir "$SYSDIR"
+
+ ; Retrieve Windows version we're running on and store it in $g_strWinVersion
+ Call un.GetWindowsVer
+
+FunctionEnd
+
+Function .onSelChange
+
+ Push $0
+
+ ; Section: D3D
+ SectionGetFlags ${SEC03} $0
+
+ ${If} $0 == ${SF_SELECTED}
+ ; If we're not in safe mode, print a warning and don't install D3D support
+ ${If} $g_iSystemMode == '0'
+ IntOp $0 $0 & ${SECTION_OFF} ; Unselect section again
+ SectionSetFlags ${SEC03} $0
+ MessageBox MB_ICONINFORMATION|MB_OK $(VBOX_COMPONENT_D3D_NO_SM) /SD IDOK
+ Return
+ ${EndIf}
+ ${EndIf}
+
+ Pop $0
+
+FunctionEnd
+
+Section Uninstall
+
+!ifdef _DEBUG
+ ; Enable logging
+ Call un.EnableLog
+!endif
+
+ ; Because this NSIS installer is always built in 32-bit mode, we have to
+ ; do some tricks for the Windows paths.
+!if $%BUILD_TARGET_ARCH% == "amd64"
+ ; Do *not* add this line in .onInit - it will crash at the license page (??) because of a weird NSIS bug.
+ ${DisableX64FSRedirection}
+ SetRegView 64
+!endif
+
+ ; Call the uninstall main function.
+ Call un.Uninstall
+
+ ; ... and remove the local install directory
+ Call un.UninstallInstDir
+
+!ifndef _DEBUG
+ SetAutoClose true
+ MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 $(VBOX_REBOOT_REQUIRED) /SD IDNO IDYES restart
+ StrCmp $g_bRebootOnExit "true" restart
+!endif
+
+ Goto exit
+
+restart:
+
+ DetailPrint "Rebooting ..."
+ Reboot
+
+exit:
+
+SectionEnd
+
+; !EXTERNAL_UNINSTALLER
+!endif
+
+;Direct the output to our bin dir
+!cd "$%PATH_OUT%\bin\additions"
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh
new file mode 100644
index 00000000000..be1101d1e92
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsCommon.nsh
@@ -0,0 +1,438 @@
+
+!ifndef UNINSTALLER_ONLY
+Function ExtractFiles
+
+ ; @todo: Use a define for all the file specs to group the files per module
+ ; and keep the redundancy low.
+
+ Push $0
+ StrCpy "$0" "$INSTDIR\$%BUILD_TARGET_ARCH%"
+
+ ; Video driver
+ SetOutPath "$0\VBoxVideo"
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.cat"
+!endif
+ FILE "$%PATH_OUT%\bin\additions\VBoxDisp.dll"
+
+!if $%VBOX_WITH_CROGL% == "1"
+ ; crOpenGL
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLarrayspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLcrutil.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLerrorspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLpackspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLpassthroughspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLfeedbackspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGL.dll"
+
+ ; Do *not* install 64-bit d3d files - they don't work yet.
+ !if $%BUILD_TARGET_ARCH% == "x86"
+ SetOutPath "$0\VBoxVideo\OpenGL"
+ FILE "$%PATH_OUT%\bin\additions\d3d8.dll"
+ FILE "$%PATH_OUT%\bin\additions\d3d9.dll"
+ FILE "$%PATH_OUT%\bin\additions\libWine.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxD3D8.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxD3D9.dll"
+ FILE "$%PATH_OUT%\bin\additions\wined3d.dll"
+ !endif
+
+ !if $%BUILD_TARGET_ARCH% == "amd64"
+ ; Only 64-bit installer: Also copy 32-bit DLLs on 64-bit target
+ SetOutPath "$0\VBoxVideo\OpenGL\SysWow64"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d8.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\d3d9.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\libWine.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLarrayspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLcrutil.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLerrorspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpackspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpassthroughspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLfeedbackspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGL.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D8.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxD3D9.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\wined3d.dll"
+ !endif
+!endif
+
+ ; Mouse driver
+ SetOutPath "$0\VBoxMouse"
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouse.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouse.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouse.cat"
+!endif
+
+!if $%BUILD_TARGET_ARCH% == "x86"
+ SetOutPath "$0\VBoxMouse\NT4"
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouseNT.sys"
+!endif
+
+ ; Guest driver
+ SetOutPath "$0\VBoxGuest"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuest.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuest.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuest.cat"
+!endif
+ FILE "$%PATH_OUT%\bin\additions\VBCoInst.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxTray.exe"
+ FILE "$%PATH_OUT%\bin\additions\VBoxHook.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxControl.exe"
+
+!if $%BUILD_TARGET_ARCH% == "x86"
+ SetOutPath "$0\VBoxGuest\NT4"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuestNT.sys"
+!endif
+
+ ; VBoxService
+ SetOutPath "$0\Bin"
+ FILE "$%PATH_OUT%\bin\additions\VBoxService.exe"
+!if $%BUILD_TARGET_ARCH% == "x86"
+ FILE "$%PATH_OUT%\bin\additions\VBoxServiceNT.exe"
+!endif
+
+ ; Shared Folders
+ SetOutPath "$0\VBoxSF"
+ FILE "$%PATH_OUT%\bin\additions\VBoxSF.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxMRXNP.dll"
+
+ ; AMD PCNet driver
+ SetOutPath "$0\Network\AMD"
+ FILE "..\Network\AMD\netamd.inf"
+ FILE "..\Network\AMD\pcntpci5.cat"
+ FILE "..\Network\AMD\PCNTPCI5.sys"
+
+ ; Auto-Logon
+ SetOutPath "$0\AutoLogon"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGINA.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxCredProv.dll"
+
+ ; Misc tools
+ SetOutPath "$0\Tools"
+ FILE "$%PATH_OUT%\bin\additions\VBoxDrvInst.exe"
+
+!if $%BUILD_TARGET_ARCH% == "x86"
+ SetOutPath "$0\Tools\NT4"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuestDrvInst.exe"
+ FILE "$%PATH_OUT%\bin\additions\RegCleanup.exe"
+!endif
+
+ Pop $0
+
+FunctionEnd
+!endif ; UNINSTALLER_ONLY
+
+!macro EnableLog un
+Function ${un}EnableLog
+
+!ifdef _DEBUG
+ Goto log
+!endif
+
+ StrCmp $g_bLogEnable "true" log
+ Goto exit
+
+log:
+
+ LogSet on
+ LogText "Start logging."
+
+exit:
+
+FunctionEnd
+!macroend
+!insertmacro EnableLog ""
+!insertmacro EnableLog "un."
+
+!macro WriteLogUI un
+Function ${un}WriteLogUI
+
+ IfSilent exit
+
+!ifdef _DEBUG
+ Goto log
+!endif
+
+ StrCmp $g_bLogEnable "true" log
+ Goto exit
+
+log:
+
+ ; Dump log to see what happend
+ StrCpy $0 "$INSTDIR\${un}install_ui.log"
+ Push $0
+ Call ${un}DumpLog
+
+exit:
+
+FunctionEnd
+!macroend
+!insertmacro WriteLogUI ""
+!insertmacro WriteLogUI "un."
+
+!macro GetWindowsVer un
+Function ${un}GetWindowsVer
+
+ ; Check if we are running on w2k or above. For other windows versions (>XP) it may be necessary to change winver.nsh
+ ; Get the Windows version
+ Call ${un}GetWindowsVersion
+ Pop $R3 ; Windows Version
+
+ Push $R3 ; The windows version string
+ Push "NT" ; String to search for. Win 2k family returns no string containing 'NT'
+ Call ${un}StrStr
+ Pop $R0
+ StrCmp $R0 '' no_nt4 ; Not NT 3.XX or 4.XX
+
+ ; Ok we know it is NT. Must be a string like NT X.XX
+ Push $R3 ; The windows version string
+ Push "4." ; String to search for
+ Call ${un}StrStr
+ Pop $R0
+ StrCmp $R0 "" no_nt4 nt4 ; If empty -> not NT 4
+
+no_nt4:
+
+ StrCmp $R3 "2000" w2k_xp
+ StrCmp $R3 "XP" w2k_xp
+ StrCmp $R3 "2003" w2k_xp
+ StrCmp $R3 "Vista" vista
+ StrCmp $R3 "7" vista
+ Goto unknown
+
+nt4: ; NT 4.0
+
+ StrCpy $g_strWinVersion "nt4"
+ goto exit
+
+w2k_xp: ; NT 5.0, 5.1 or 5.2
+
+ StrCpy $g_strWinVersion "2k"
+ goto exit
+
+vista: ; NT 6.0 or 6.1 (Vista or Windows 7)
+
+ StrCpy $g_strWinVersion "vista"
+ goto exit
+
+unknown:
+
+ StrCpy $g_strWinVersion "unknown"
+ goto exit
+
+exit:
+
+FunctionEnd
+!macroend
+
+; Insert function as an installer and uninstaller function.
+!insertmacro GetWindowsVer ""
+!insertmacro GetWindowsVer "un."
+
+!macro GetAdditionsVersion un
+Function ${un}GetAdditionsVersion
+
+ Push $0
+ Push $1
+
+ ; Get additions version
+ ReadRegStr $0 HKLM "SOFTWARE\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions" "Version"
+
+ ; Get revision
+ ReadRegStr $g_strAddVerRev HKLM "SOFTWARE\$%VBOX_VENDOR_SHORT%\VirtualBox Guest Additions" "Revision"
+
+ ; Extract major version
+ Push "$0" ; String
+ Push "." ; SubString
+ Push ">" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $g_strAddVerMaj
+
+ ; Extract minor version
+ Push "$0" ; String
+ Push "." ; SubString
+ Push ">" ; SearchDirection
+ Push ">" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; Got first part (e.g. "1.5")
+
+ Push "$1" ; String
+ Push "." ; SubString
+ Push ">" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $g_strAddVerMin ; Extracted second part (e.g. "5" from "1.5")
+
+ ; Extract build number
+ Push "$0" ; String
+ Push "." ; SubString
+ Push "<" ; SearchDirection
+ Push ">" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $g_strAddVerBuild
+
+exit:
+
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+
+; Insert function as an installer and uninstaller function.
+!insertmacro GetAdditionsVersion ""
+!insertmacro GetAdditionsVersion "un."
+
+!macro IsUserAdmin un
+Function ${un}IsUserAdmin
+
+ ; Check if current user has admin rights
+ UserInfo::GetAccountType
+ Pop $0
+ StrCmp $0 "Admin" is_admin 0
+ MessageBox MB_ICONSTOP $(VBOX_NOADMIN)
+ Abort
+
+is_admin:
+
+FunctionEnd
+!macroend
+
+; Insert function as an installer and uninstaller function.
+!insertmacro IsUserAdmin ""
+!insertmacro IsUserAdmin "un."
+
+!macro StopVBoxService un
+Function ${un}StopVBoxService
+
+ Push $0 ; Temp results
+ Push $1
+ Push $2 ; Image name of VBoxService
+ Push $3 ; Safety counter
+
+ StrCpy $3 "0" ; Init counter
+ DetailPrint "Stopping VBoxService ..."
+
+svc_stop:
+
+ LogText "Stopping VBoxService (as service) ..."
+ ${If} $g_strWinVersion == "nt4"
+ nsExec::Exec '"$SYSDIR\net.exe" stop VBoxService'
+ ${Else}
+ nsExec::Exec '"$SYSDIR\SC.exe" stop VBoxService'
+ ${EndIf}
+ Sleep "1000" ; Wait a bit
+
+exe_stop:
+
+!ifdef _DEBUG
+ DetailPrint "Stopping VBoxService (as exe) ..."
+!endif
+
+exe_stop_loop:
+
+ IntCmp $3 10 exit ; Only try this loop 10 times max
+ IntOp $3 $3 + 1 ; Increment
+
+ LogText "Try: $3"
+
+ ${If} $g_strWinVersion == "nt4"
+ StrCpy $2 "VBoxServiceNT.exe"
+ ${Else}
+ StrCpy $2 "VBoxService.exe"
+ ${EndIf}
+
+ ${nsProcess::FindProcess} $2 $0
+ StrCmp $0 0 0 exit
+
+ ${nsProcess::KillProcess} $2 $0
+ Sleep "1000" ; Wait a bit
+ Goto exe_stop_loop
+
+exit:
+
+ DetailPrint "Stopping VBoxService done."
+
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+
+; Insert function as an installer and uninstaller function.
+!insertmacro StopVBoxService ""
+!insertmacro StopVBoxService "un."
+
+!macro StopVBoxTray un
+Function ${un}StopVBoxTray
+
+ Push $0 ; Temp results
+ Push $1 ; Safety counter
+
+ StrCpy $1 "0" ; Init counter
+ DetailPrint "Stopping VBoxTray ..."
+
+exe_stop:
+
+ IntCmp $1 10 exit ; Only try this loop 10 times max
+ IntOp $1 $1 + 1 ; Increment
+
+ ${nsProcess::FindProcess} "VBoxTray.exe" $0
+ StrCmp $0 0 0 exit
+
+ ${nsProcess::KillProcess} "VBoxTray.exe" $0
+ Sleep "1000" ; Wait a bit
+ Goto exe_stop
+
+exit:
+
+ DetailPrint "Stopping VBoxTray done."
+
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+
+; Insert function as an installer and uninstaller function.
+!insertmacro StopVBoxTray ""
+!insertmacro StopVBoxTray "un."
+
+!macro WriteRegBinR ROOT KEY NAME VALUE
+ WriteRegBin "${ROOT}" "${KEY}" "${NAME}" "${VALUE}"
+!macroend
+
+!macro AbortShutdown un
+Function ${un}AbortShutdown
+
+ Push $0
+
+ ; Try to abort the shutdown
+ nsExec::ExecToLog '"$g_strSystemDir\shutdown.exe" -a' $0
+
+ Pop $0
+
+FunctionEnd
+!macroend
+
+; Insert function as an installer and uninstaller function.
+!insertmacro AbortShutdown ""
+!insertmacro AbortShutdown "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh
new file mode 100644
index 00000000000..313702a9f99
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsNT4.nsh
@@ -0,0 +1,258 @@
+
+Function NT_SetVideoResolution
+
+ ; Check for all required parameters
+ StrCmp $g_iScreenX "0" missingParms
+ StrCmp $g_iScreenY "0" missingParms
+ StrCmp $g_iScreenBpp "0" missingParms
+ Goto haveParms
+
+missingParms:
+
+ DetailPrint "Missing display parameters for NT, setting default (640x480, 8 BPP) ..."
+
+ StrCpy $g_iScreenX '640' ; Default value
+ StrCpy $g_iScreenY '480' ; Default value
+ StrCpy $g_iScreenBpp '8' ; Default value
+
+ ; Write setting into registry to show the desktop applet on next boot
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\GraphicsDrivers\NewDisplay" "" ""
+
+haveParms:
+
+ DetailPrint "Setting display parameters for NT ($g_iScreenXx$g_iScreenY, $g_iScreenBpp BPP) ..."
+
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.BitsPerPel" $g_iScreenBpp
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.Flags" 0x00000000
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.VRefresh" 0x00000001
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.XPanning" 0x00000000
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.XResolution" $g_iScreenX
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.YPanning" 0x00000000
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\vboxvideo\Device0" "DefaultSettings.YResolution" $g_iScreenY
+
+FunctionEnd
+
+Function NT_SaveMouseDriverInfo
+
+ Push $0
+
+ ; !!! NOTE !!!
+ ; Due to some re-branding (see functions Uninstall_Sun, Uninstall_Innotek and
+ ; Uninstall_SunXVM) the installer *has* to transport the very first saved i8042prt
+ ; value to the current installer's "uninstall" directory in both mentioned
+ ; functions above, otherwise NT4 will be screwed because it then would store
+ ; "VBoxMouseNT.sys" as the original i8042prt driver which obviously isn't there
+ ; after uninstallation anymore.
+ ; !!! NOTE !!!
+
+ ; Save current mouse driver info so we may restore it on uninstallation
+ ; But first check if we already installed the additions otherwise we will
+ ; overwrite it with the VBoxMouseNT.sys
+ ReadRegStr $0 HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ StrCmp $0 "" 0 exists
+
+ DetailPrint "Saving mouse driver info ..."
+ ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath"
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+ Goto exit
+
+exists:
+
+ DetailPrint "Mouse driver info already saved."
+ Goto exit
+
+exit:
+
+!ifdef _DEBUG
+ DetailPrint "Mouse driver info: $0"
+!endif
+
+ Pop $0
+
+FunctionEnd
+
+Function NT_Prepare
+
+ ; Stop / kill VBoxService
+ Call StopVBoxService
+
+ ; Stop / kill VBoxTray
+ Call StopVBoxTray
+
+ ; Delete VBoxService from registry
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService"
+
+ ; Delete old VBoxService.exe from install directory (replaced by VBoxTray.exe)
+ Delete /REBOOTOK "$INSTDIR\VBoxService.exe"
+
+FunctionEnd
+
+Function NT_CopyFiles
+
+ DetailPrint "Copying files..."
+
+ SetOutPath "$INSTDIR"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuestDrvInst.exe"
+ FILE "$%PATH_OUT%\bin\additions\RegCleanup.exe"
+
+ ; The files to install for NT 4, they go into the system directories
+ SetOutPath "$SYSDIR"
+ FILE "$%PATH_OUT%\bin\additions\VBoxDisp.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxTray.exe"
+ FILE "$%PATH_OUT%\bin\additions\VBoxHook.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxControl.exe"
+
+ ; VBoxService
+ FILE "$%PATH_OUT%\bin\additions\VBoxServiceNT.exe"
+
+ ; The drivers into the "drivers" directory
+ SetOutPath "$SYSDIR\drivers"
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouseNT.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuestNT.sys"
+ ;FILE "$%PATH_OUT%\bin\additions\VBoxSFNT.sys" ; Shared Folders not available on NT4!
+
+FunctionEnd
+
+Function NT_InstallFiles
+
+ DetailPrint "Installing Drivers..."
+
+ ; Install guest driver
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxGuest" "VBoxGuest Support Driver" 1 1 "$SYSDIR\drivers\VBoxGuestNT.sys" "Base"'
+
+ ; Bugfix: Set "Start" to 1, otherwise, VBoxGuest won't start on boot-up!
+ ; Bugfix: Correct invalid "ImagePath" (\??\C:\WINNT\...)
+ WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\VBoxGuest" "Start" 1
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxGuest" "ImagePath" "System32\Drivers\VBoxGuestNT.sys"
+
+ ; Run VBoxTray when Windows NT starts
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray" '"$SYSDIR\VBoxTray.exe"'
+
+ ; Video driver
+ nsExec::ExecToLog '"$INSTDIR\VBoxGuestDrvInst.exe" /i'
+ Pop $0 ; Ret value
+ IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+ DetailPrint "Installing VirtualBox service ..."
+
+ ; Create the VBoxService service
+ ; No need to stop/remove the service here! Do this only on uninstallation!
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxService" "VirtualBox Guest Additions Service" 16 2 "system32\VBoxServiceNT.exe" "Base"'
+
+ ; Create the Shared Folders service ...
+ ;nsSCM::Install /NOUNLOAD "VBoxSF" "VirtualBox Shared Folders" 1 1 "$SYSDIR\drivers\VBoxSFNT.sys" "Network" "" "" ""
+ ;Pop $0 ; Ret value
+
+!ifdef _DEBUG
+ ;DetailPrint "SCM::Install VBoxSFNT.sys: $0"
+!endif
+
+ ;IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+ ; ... and the link to the network provider
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "DeviceName" "\Device\VBoxMiniRdr"
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "Name" "VirtualBox Shared Folders"
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "ProviderPath" "$SYSDIR\VBoxMRXNP.dll"
+
+ ; Add the shared folders network provider
+ ;nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider VBoxSF'
+ ;Pop $0 ; Ret value
+
+!ifdef _DEBUG
+ ;DetailPrint "VBoxDrvInst::AddProvider VBoxSF: $0"
+!endif
+
+ ;IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+ Goto done
+
+error:
+ Abort "ERROR: Could not install files for Windows NT! Installation aborted."
+
+done:
+
+FunctionEnd
+
+Function NT_Main
+
+ SetOutPath "$INSTDIR"
+
+ Call NT_Prepare
+ Call NT_CopyFiles
+
+ ; This removes the flag "new display driver installed on the next bootup
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "VBoxGuestInst" '"$INSTDIR\RegCleanup.exe"'
+
+ Call NT_SaveMouseDriverInfo
+ Call NT_InstallFiles
+ Call NT_SetVideoResolution
+
+ ; Write mouse driver name to registry overwriting the default name
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" "System32\DRIVERS\VBoxMouseNT.sys"
+
+FunctionEnd
+
+!macro NT_UninstallInstDir un
+Function ${un}NT_UninstallInstDir
+
+ ; Delete remaining files
+ Delete /REBOOTOK "$INSTDIR\VBoxGuestDrvInst.exe"
+ Delete /REBOOTOK "$INSTDIR\RegCleanup.exe"
+
+FunctionEnd
+!macroend
+!insertmacro NT_UninstallInstDir ""
+!insertmacro NT_UninstallInstDir "un."
+
+!macro NT_Uninstall un
+Function ${un}NT_Uninstall
+
+ Push $0
+
+ ; Remove the guest driver service
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxGuest'
+ Delete /REBOOTOK "$SYSDIR\drivers\VBoxGuestNT.sys"
+
+ ; Delete the VBoxService service
+ Call ${un}StopVBoxService
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxService'
+ Pop $0 ; Ret value
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService"
+ Delete /REBOOTOK "$SYSDIR\VBoxServiceNT.exe"
+
+ ; Delete the VBoxTray app
+ Call ${un}StopVBoxTray
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "VBoxTrayDel" "$SYSDIR\cmd.exe /c del /F /Q $SYSDIR\VBoxTray.exe"
+ Delete /REBOOTOK "$SYSDIR\VBoxTray.exe" ; If it can't be removed cause it's running, try next boot with "RunOnce" key above!
+ Delete /REBOOTOK "$SYSDIR\VBoxHook.dll"
+
+ ; Delete the VBoxControl utility
+ Delete /REBOOTOK "$SYSDIR\VBoxControl.exe"
+
+ ; Delete the VBoxVideo service
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxVideo'
+
+ ; Delete the VBox video driver files
+ Delete /REBOOTOK "$SYSDIR\drivers\VBoxVideo.sys"
+ Delete /REBOOTOK "$SYSDIR\VBoxDisp.dll"
+
+ ; Get original mouse driver info and restore it
+ ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ; If we still got our driver stored in $0 then this will *never* work, so
+ ; warn the user and set it to the default driver to not screw up NT4 here
+ ${If} $0 == "System32\DRIVERS\VBoxMouseNT.sys"
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" "System32\DRIVERS\i8042prt.sys"
+ DetailPrint "Old mouse driver is set to VBoxMouseNT.sys, defaulting to i8042prt.sys ..."
+ ${Else}
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ${EndIf}
+ Delete /REBOOTOK "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro NT_Uninstall ""
+!insertmacro NT_Uninstall "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh
new file mode 100644
index 00000000000..24954530129
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstall.nsh
@@ -0,0 +1,209 @@
+
+; @todo Replace this crappy stuff with a "VBoxDrvInst /delnetprovider".
+!macro RemoveFromProvider un
+Function ${un}RemoveFromProvider
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+ Push $4
+ Push $5
+ Push $6
+
+ ReadRegStr $1 HKLM "$R0" "ProviderOrder"
+ StrCpy $5 $1 1 -1 # copy last char
+ StrCmp $5 "," +2 # if last char != ,
+ StrCpy $1 "$1," # append ,
+ Push $1
+ Push "$0,"
+ Call ${un}StrStr ; Find `$0,` in $1
+ Pop $2 ; pos of our dir
+ StrCmp $2 "" unRemoveFromPath_done
+ ; else, it is in path
+ # $0 - path to add
+ # $1 - path var
+ StrLen $3 "$0,"
+ StrLen $4 $2
+ StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
+ StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
+ StrCpy $3 $5$6
+
+ StrCpy $5 $3 1 -1 # copy last char
+ StrCmp $5 "," 0 +2 # if last char == ,
+ StrCpy $3 $3 -1 # remove last char
+
+ WriteRegStr HKLM "$R0" "ProviderOrder" $3
+
+unRemoveFromPath_done:
+ Pop $6
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+!macroend
+!insertmacro RemoveFromProvider ""
+!insertmacro RemoveFromProvider "un."
+
+!macro RemoveProvider un
+Function ${un}RemoveProvider
+ Push $R0
+ StrCpy $R0 "VBoxSF"
+ Push $R0
+ StrCpy $R0 "SYSTEM\CurrentControlSet\Control\NetworkProvider\HWOrder"
+ Call ${un}RemoveFromProvider
+ StrCpy $R0 "VBoxSF"
+ Push $R0
+ StrCpy $R0 "SYSTEM\CurrentControlSet\Control\NetworkProvider\Order"
+ Call ${un}RemoveFromProvider
+ Pop $R0
+FunctionEnd
+!macroend
+!insertmacro RemoveProvider ""
+!insertmacro RemoveProvider "un."
+
+!macro UninstallCommon un
+Function ${un}UninstallCommon
+
+ Delete /REBOOTOK "$INSTDIR\install.log"
+ Delete /REBOOTOK "$INSTDIR\uninst.exe"
+ Delete /REBOOTOK "$INSTDIR\${PRODUCT_NAME}.url"
+
+ ; Remove common files
+ Delete /REBOOTOK "$INSTDIR\VBoxDrvInst.exe"
+
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.cat"
+!endif
+
+ Delete /REBOOTOK "$INSTDIR\VBoxGINA.dll"
+ Delete /REBOOTOK "$INSTDIR\iexplore.ico"
+
+ ; Delete registry keys
+ DeleteRegKey /ifempty HKLM "${PRODUCT_INSTALL_KEY}"
+ DeleteRegKey /ifempty HKLM "${VENDOR_ROOT_KEY}"
+
+ ; Delete desktop & start menu entries
+ Delete "$DESKTOP\${PRODUCT_NAME} Guest Additions.lnk"
+ Delete "$SMPROGRAMS\${PRODUCT_NAME} Guest Additions\Uninstall.lnk"
+ Delete "$SMPROGRAMS\${PRODUCT_NAME} Guest Additions\Website.lnk"
+ RMDIR "$SMPROGRAMS\${PRODUCT_NAME} Guest Additions"
+
+ ; Delete Guest Additions directory (only if completely empty)
+ RMDir /REBOOTOK "$INSTDIR"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\$%VBOX_VENDOR_SHORT%"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\$%VBOX_VENDOR_SHORT%"
+!endif
+
+ ; Remove registry entries
+ DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+
+FunctionEnd
+!macroend
+!insertmacro UninstallCommon ""
+!insertmacro UninstallCommon "un."
+
+!macro Uninstall un
+Function ${un}Uninstall
+
+ DetailPrint "Uninstalling system files ..."
+ DetailPrint "Handled Windows version: $g_strWinVersion"
+ DetailPrint "System Directory: $g_strSystemDir"
+
+ ; Which OS are we using?
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ StrCmp $g_strWinVersion "nt4" nt4
+!endif
+ StrCmp $g_strWinVersion "2k" w2k
+ StrCmp $g_strWinVersion "vista" vista
+
+ Goto notsupported
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+nt4:
+
+ Call ${un}NT_Uninstall
+ goto common
+!endif
+
+w2k:
+
+ Call ${un}W2K_Uninstall
+ goto common
+
+vista:
+
+ Call ${un}W2K_Uninstall
+ Call ${un}Vista_Uninstall
+ goto common
+
+notsupported:
+
+ MessageBox MB_ICONSTOP $(VBOX_PLATFORM_UNSUPPORTED) /SD IDOK
+ Goto exit
+
+common:
+
+exit:
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall ""
+!insertmacro Uninstall "un."
+
+!macro UninstallInstDir un
+Function ${un}UninstallInstDir
+
+ DetailPrint "Uninstalling directory ..."
+ DetailPrint "Handled Windows version: $g_strWinVersion"
+ DetailPrint "System Directory: $g_strSystemDir"
+
+ ; Which OS are we using?
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ StrCmp $g_strWinVersion "nt4" nt4
+!endif
+ StrCmp $g_strWinVersion "2k" w2k
+ StrCmp $g_strWinVersion "vista" vista
+
+ Goto notsupported
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+nt4:
+
+ Call ${un}NT_UninstallInstDir
+ goto common
+!endif
+
+w2k:
+
+ Call ${un}W2K_UninstallInstDir
+ goto common
+
+vista:
+
+ Call ${un}W2K_UninstallInstDir
+ Call ${un}Vista_UninstallInstDir
+ goto common
+
+notsupported:
+
+ MessageBox MB_ICONSTOP $(VBOX_PLATFORM_UNSUPPORTED) /SD IDOK
+ Goto exit
+
+common:
+
+ Call ${un}UninstallCommon
+
+exit:
+
+FunctionEnd
+!macroend
+!insertmacro UninstallInstDir ""
+!insertmacro UninstallInstDir "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh
new file mode 100644
index 00000000000..e3f4d992fd0
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsUninstallOld.nsh
@@ -0,0 +1,345 @@
+
+!macro Uninstall_RunExtUnInstaller un
+Function ${un}Uninstall_RunExtUnInstaller
+
+ Pop $0
+ Push $1
+ Push $2
+
+ ; Try to run the current uninstaller
+ StrCpy $1 "$0\uninst.exe"
+ IfFileExists "$1" run 0
+ MessageBox MB_OK "VirtualBox Guest Additions uninstaller not found! Path = $1" /SD IDOK
+ StrCpy $0 1 ; Tell the caller that we were not able to start the uninstaller
+ Goto exit
+
+run:
+
+ ; Always try to run in silent mode
+ Goto run_uninst_silent
+
+run_uninst_silent:
+
+ ExecWait '"$1" /S _?=$0' $2 ; Silently run uninst.exe in it's dir and don't copy it to a temp. location
+ Goto handle_result
+
+run_uninst:
+
+ ExecWait '"$1" _?=$0' $2 ; Run uninst.exe in it's dir and don't copy it to a temp. location
+ Goto handle_result
+
+handle_result:
+
+ ; Note that here a race might going on after the user clicked on
+ ; "Reboot now" in the installer ran above and this installer cleaning
+ ; up aftwards.
+
+ ; ... so try to abort the current reboot / shutdown caused by the installer ran before
+ Call ${un}AbortShutdown
+
+;!ifdef _DEBUG
+; MessageBox MB_OK 'Debug Message: Uninstaller was called, result is: $2' /SD IDOK
+;!endif
+
+ ${Switch} $2 ; Check exit codes
+ ${Case} 1 ; Aborted by user
+ StrCpy $0 1 ; Tell the caller that we were aborted by the user
+ ${Break}
+ ${Case} 2 ; Aborted by script (that might be okay)
+ StrCpy $0 0 ; All went well
+ ${Break}
+ ${Default} ; Normal exixt
+ StrCpy $0 0 ; All went well
+ ${Break}
+ ${EndSwitch}
+ Goto exit
+
+exit:
+
+ Pop $2
+ Pop $1
+ Push $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_RunExtUnInstaller ""
+!insertmacro Uninstall_RunExtUnInstaller "un."
+
+!macro Uninstall_WipeInstallationDirectory un
+Function ${un}Uninstall_WipeInstallationDirectory
+
+ Pop $0
+ Push $1
+ Push $2
+
+ ; Do some basic sanity checks for not screwing up too fatal ...
+ DetailPrint "Removing old installation directory ($0) ..."
+ ${If} $0 != $PROGRAMFILES
+ ${AndIf} $0 != $PROGRAMFILES32
+ ${AndIf} $0 != $PROGRAMFILES64
+ ${AndIf} $0 != $COMMONFILES32
+ ${AndIf} $0 != $COMMONFILES64
+ ${AndIf} $0 != $WINDIR
+ ${AndIf} $0 != $SYSDIR
+ DetailPrint "Wiping ($0) ..."
+ Goto wipe
+ ${EndIf}
+ Goto wipe_abort
+
+wipe:
+
+ RMDir /r /REBOOTOK "$0"
+ StrCpy $0 0 ; All went well
+ Goto exit
+
+wipe_abort:
+
+ DetailPrint "Won't remove directory ($0)!"
+ StrCpy $0 1 ; Signal some failure
+ Goto exit
+
+exit:
+
+ Pop $2
+ Pop $1
+ Push $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_WipeInstallationDirectory ""
+!insertmacro Uninstall_WipeInstallationDirectory "un."
+
+; This function cleans up an old Sun installation
+!macro Uninstall_Sun un
+Function ${un}Uninstall_Sun
+
+ Push $0
+ Push $1
+ Push $2
+
+ ; Get current installation path
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit
+
+ ; Extract path
+ Push "$0" ; String
+ Push "\" ; SubString
+ Push "<" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; $1 only contains the full path
+
+ StrCmp $1 "" exit
+
+ ; Save current i8042prt info to new uninstall registry path
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions" ${ORG_MOUSE_PATH}
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+
+ ; Try to wipe current installation directory
+ Push $1 ; Push uninstaller path to stack
+ Call ${un}Uninstall_WipeInstallationDirectory
+ Pop $2 ; Get uninstaller exit code from stack
+ StrCmp $2 0 common exit ; Only process common part if exit code is 0, otherwise exit
+
+common:
+
+ ; Make sure everything is cleaned up in case the old uninstaller did forget something
+ DeleteRegKey HKLM "SOFTWARE\Sun\VirtualBox Guest Additions"
+ DeleteRegKey /ifempty HKLM "SOFTWARE\Sun"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun VirtualBox Guest Additions"
+ Delete /REBOOTOK "$1\netamd.inf"
+ Delete /REBOOTOK "$1\pcntpci5.cat"
+ Delete /REBOOTOK "$1\PCNTPCI5.sys"
+
+ ; Try to remove old installation directory if empty
+ RMDir /r /REBOOTOK "$SMPROGRAMS\Sun VirtualBox Guest Additions"
+ RMDir /REBOOTOK "$1"
+
+ ; Get original mouse driver info and restore it
+ ;ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ;Delete "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\Sun"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\Sun"
+!endif
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_Sun ""
+!insertmacro Uninstall_Sun "un."
+
+; This function cleans up an old xVM Sun installation
+!macro Uninstall_SunXVM un
+Function ${un}Uninstall_SunXVM
+
+ Push $0
+ Push $1
+ Push $2
+
+ ; Get current installation path
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit
+
+ ; Extract path
+ Push "$0" ; String
+ Push "\" ; SubString
+ Push "<" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; $1 only contains the full path
+
+ StrCmp $1 "" exit
+
+ ; Save current i8042prt info to new uninstall registry path
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions" ${ORG_MOUSE_PATH}
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+
+ ; Try to wipe current installation directory
+ Push $1 ; Push uninstaller path to stack
+ Call ${un}Uninstall_WipeInstallationDirectory
+ Pop $2 ; Get uninstaller exit code from stack
+ StrCmp $2 0 common exit ; Only process common part if exit code is 0, otherwise exit
+
+common:
+
+ ; Make sure everything is cleaned up in case the old uninstaller did forget something
+ DeleteRegKey HKLM "SOFTWARE\Sun\xVM VirtualBox Guest Additions"
+ DeleteRegKey /ifempty HKLM "SOFTWARE\Sun"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Sun xVM VirtualBox Guest Additions"
+ Delete /REBOOTOK "$1\netamd.inf"
+ Delete /REBOOTOK "$1\pcntpci5.cat"
+ Delete /REBOOTOK "$1\PCNTPCI5.sys"
+
+ ; Try to remove old installation directory if empty
+ RMDir /r /REBOOTOK "$SMPROGRAMS\Sun xVM VirtualBox Guest Additions"
+ RMDir /REBOOTOK "$1"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\Sun"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\Sun"
+!endif
+
+ ; Get original mouse driver info and restore it
+ ;ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ;Delete "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_SunXVM ""
+!insertmacro Uninstall_SunXVM "un."
+
+; This function cleans up an old innotek installation.
+!macro Uninstall_Innotek un
+Function ${un}Uninstall_Innotek
+
+ Push $0
+ Push $1
+ Push $2
+
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions" "UninstallString"
+ StrCmp $0 "" exit
+
+ ; Extract path
+ Push "$0" ; String
+ Push "\" ; SubString
+ Push "<" ; SearchDirection
+ Push "<" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "0" ; Loops
+ Push "0" ; CaseSensitive
+ Call ${un}StrStrAdv
+ Pop $1 ; $1 only contains the full path
+
+ StrCmp $1 "" exit
+
+ ; Save current i8042prt info to new uninstall registry path
+ ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions" ${ORG_MOUSE_PATH}
+ WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH} $0
+
+ ; Try to wipe current installation directory
+ Push $1 ; Push uninstaller path to stack
+ Call ${un}Uninstall_WipeInstallationDirectory
+ Pop $2 ; Get uninstaller exit code from stack
+ StrCmp $2 0 common exit ; Only process common part if exit code is 0, otherwise exit
+
+common:
+
+ ; Remove left over files which were not entirely catched by the formerly running
+ ; uninstaller
+ DeleteRegKey HKLM "SOFTWARE\innotek\VirtualBox Guest Additions"
+ DeleteRegKey HKLM "SOFTWARE\innotek"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\innotek VirtualBox Guest Additions"
+ Delete /REBOOTOK "$1\VBoxGuestDrvInst.exe"
+ Delete /REBOOTOK "$1\VBoxMouseInst.exe"
+ Delete /REBOOTOK "$1\VBoxSFDrvInst.exe"
+ Delete /REBOOTOK "$1\RegCleanup.exe"
+ Delete /REBOOTOK "$1\VBoxService.exe"
+ Delete /REBOOTOK "$1\VBoxMouseInst.exe"
+ Delete /REBOOTOK "$1\innotek VirtualBox Guest Additions.url"
+ Delete /REBOOTOK "$1\uninst.exe"
+ Delete /REBOOTOK "$1\iexplore.ico"
+ Delete /REBOOTOK "$1\install.log"
+ Delete /REBOOTOK "$1\VBCoInst.dll"
+ Delete /REBOOTOK "$1\VBoxControl.exe"
+ Delete /REBOOTOK "$1\VBoxDisp.dll"
+ Delete /REBOOTOK "$1\VBoxGINA.dll"
+ Delete /REBOOTOK "$1\VBoxGuest.cat"
+ Delete /REBOOTOK "$1\VBoxGuest.inf"
+ Delete /REBOOTOK "$1\VBoxGuest.sys"
+ Delete /REBOOTOK "$1\VBoxMouse.inf"
+ Delete /REBOOTOK "$1\VBoxMouse.sys"
+ Delete /REBOOTOK "$1\VBoxVideo.cat"
+ Delete /REBOOTOK "$1\VBoxVideo.inf"
+ Delete /REBOOTOK "$1\VBoxVideo.sys"
+
+ ; Try to remove old installation directory if empty
+ RMDir /r /REBOOTOK "$SMPROGRAMS\innotek VirtualBox Guest Additions"
+ RMDir /REBOOTOK "$1"
+
+ ; Delete vendor installation directory (only if completely empty)
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ RMDir /REBOOTOK "$PROGRAMFILES32\innotek"
+!else ; 64-bit
+ RMDir /REBOOTOK "$PROGRAMFILES64\innotek"
+!endif
+
+ ; Get original mouse driver info and restore it
+ ;ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ${ORG_MOUSE_PATH}
+ ;WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\i8042prt" "ImagePath" $0
+ ;Delete "$SYSDIR\drivers\VBoxMouseNT.sys"
+
+exit:
+
+ Pop $2
+ Pop $1
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro Uninstall_Innotek ""
+!insertmacro Uninstall_Innotek "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh
new file mode 100644
index 00000000000..3807c94275f
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsVista.nsh
@@ -0,0 +1,89 @@
+
+Function Vista_CopyFiles
+
+ SetOutPath "$INSTDIR"
+ SetOverwrite on
+
+ ; The files are for Vista only, they go into the application directory
+
+ ; VBoxNET drivers are not tested yet - commented out until officially supported and released
+ ;FILE "$%PATH_OUT%\bin\additions\VBoxNET.inf"
+ ;FILE "$%PATH_OUT%\bin\additions\VBoxNET.sys"
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ ; AMD PCNet network driver
+ FILE "..\Network\AMD\netamd.inf"
+ FILE "..\Network\AMD\pcntpci5.cat"
+ FILE "..\Network\AMD\PCNTPCI5.sys"
+!endif
+
+FunctionEnd
+
+Function Vista_InstallFiles
+
+ DetailPrint "Installing Drivers for Vista / Windows 7 ..."
+
+ SetOutPath "$INSTDIR"
+
+ ; VBoxNET drivers are not tested yet - commented out until officially supported and released
+ ;nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_1022&DEV_2000&SUBSYS_20001022&REV_40" "$INSTDIR\VBoxNET.inf" "Net"'
+ ;Pop $0 ; Ret value
+ ;IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+ ;Goto done
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ ; AMD PCnet drivers
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_1022&DEV_2000&SUBSYS_20001022&REV_40" "$INSTDIR\netamd.inf" "Net"'
+ Pop $0 ; Ret value
+ IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+!endif
+
+ Goto done
+
+error:
+ Abort "ERROR: Could not install files for Vista / Windows 7! Installation aborted."
+
+done:
+
+FunctionEnd
+
+Function Vista_Main
+
+ Call Vista_CopyFiles
+ Call Vista_InstallFiles
+
+FunctionEnd
+
+!macro Vista_UninstallInstDir un
+Function ${un}Vista_UninstallInstDir
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ Delete /REBOOTOK "$INSTDIR\netamd.inf"
+ Delete /REBOOTOK "$INSTDIR\pcntpci5.cat"
+ Delete /REBOOTOK "$INSTDIR\PCNTPCI5.sys"
+!endif
+
+FunctionEnd
+!macroend
+!insertmacro Vista_UninstallInstDir ""
+!insertmacro Vista_UninstallInstDir "un."
+
+!macro Vista_Uninstall un
+Function ${un}Vista_Uninstall
+
+ ; Remove credential provider
+ DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}"
+ DeleteRegKey HKCR "CLSID\{275D3BCC-22BB-4948-A7F6-3A3054EBA92B}"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxCredProv.dll"
+
+!if $%BUILD_TARGET_ARCH% == "x86" ; 32-bit
+ ; Remove network card driver
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /u "PCI\VEN_1022&DEV_2000&SUBSYS_20001022&REV_40"'
+ Pop $0 ; Ret value
+ ; @todo Add error handling here!
+!endif
+
+FunctionEnd
+!macroend
+!insertmacro Vista_Uninstall ""
+!insertmacro Vista_Uninstall "un."
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh
new file mode 100644
index 00000000000..ff9d13ea591
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestAdditionsW2KXP.nsh
@@ -0,0 +1,562 @@
+
+Function W2K_SetVideoResolution
+
+ ; NSIS only supports global vars, even in functions -- great
+ Var /GLOBAL i
+ Var /GLOBAL tmp
+ Var /GLOBAL tmppath
+ Var /GLOBAL win_ver
+ Var /GLOBAL dev_id
+ Var /GLOBAL dev_desc
+
+ ; Check for all required parameters
+ StrCmp $g_iScreenX "0" exit
+ StrCmp $g_iScreenY "0" exit
+ StrCmp $g_iScreenBpp "0" exit
+
+ Call GetWindowsVersion
+ Pop $win_ver ; Now contains Windows version
+
+ DetailPrint "Setting display parameters ($g_iScreenXx$g_iScreenY, $g_iScreenBpp BPP) ..."
+
+ ; Enumerate all video devices (up to 32 at the moment, use key "MaxObjectNumber" key later)
+ ${For} $i 0 32
+
+ ReadRegStr $tmp HKLM "HARDWARE\DEVICEMAP\VIDEO" "\Device\Video$i"
+ StrCmp $tmp "" dev_not_found
+
+ ; Extract path to video settings
+ ; Ex: \Registry\Machine\System\CurrentControlSet\Control\Video\{28B74D2B-F0A9-48E0-8028-D76F6BB1AE65}\0000
+ ; Or: \Registry\Machine\System\CurrentControlSet\Control\Video\vboxvideo\Device0
+ ; Result: Machine\System\CurrentControlSet\Control\Video\{28B74D2B-F0A9-48E0-8028-D76F6BB1AE65}\0000
+ Push "$tmp" ; String
+ Push "\" ; SubString
+ Push ">" ; SearchDirection
+ Push ">" ; StrInclusionDirection
+ Push "0" ; IncludeSubString
+ Push "2" ; Loops
+ Push "0" ; CaseSensitive
+ Call StrStrAdv
+ Pop $tmppath ; $1 only contains the full path
+ StrCmp $tmppath "" dev_not_found
+
+ ; Get device description
+ ReadRegStr $dev_desc HKLM "$tmppath" "Device Description"
+!ifdef _DEBUG
+ DetailPrint "Registry path: $tmppath"
+ DetailPrint "Registry path to device name: $temp"
+!endif
+ DetailPrint "Detected video device: $dev_desc"
+
+ ${If} $dev_desc == "VirtualBox Graphics Adapter"
+ DetailPrint "VirtualBox video device found!"
+ Goto dev_found
+ ${EndIf}
+ ${Next}
+ Goto dev_not_found
+
+dev_found:
+
+ ; If we're on Windows 2000, skip the ID detection ...
+ StrCmp $win_ver "2000" change_res
+ Goto dev_found_detect_id
+
+dev_found_detect_id:
+
+ StrCpy $i 0 ; Start at index 0
+ DetailPrint "Detecting device ID ..."
+
+dev_found_detect_id_loop:
+
+ ; Resolve real path to hardware instance "{GUID}"
+ EnumRegKey $dev_id HKLM "SYSTEM\CurrentControlSet\Control\Video" $i
+ StrCmp $dev_id "" dev_not_found ; No more entries? Jump out
+!ifdef _DEBUG
+ DetailPrint "Got device ID: $dev_id"
+!endif
+ ReadRegStr $dev_desc HKLM "SYSTEM\CurrentControlSet\Control\Video\$dev_id\0000" "Device Description" ; Try to read device name
+ ${If} $dev_desc == "VirtualBox Graphics Adapter"
+ DetailPrint "Device ID of $dev_desc: $dev_id"
+ Goto change_res
+ ${EndIf}
+
+ IntOp $i $i + 1 ; Increment index
+ goto dev_found_detect_id_loop
+
+dev_not_found:
+
+ DetailPrint "No VirtualBox video device (yet) detected! No custom mode set."
+ Goto exit
+
+change_res:
+
+!ifdef _DEBUG
+ DetailPrint "Device description: $dev_desc"
+ DetailPrint "Device ID: $dev_id"
+!endif
+
+ Var /GLOBAL reg_path_device
+ Var /GLOBAL reg_path_monitor
+
+ DetailPrint "Custom mode set: Platform is '$win_ver'."
+ ${If} $win_ver == "2000"
+ ${OrIf} $win_ver == "Vista"
+ StrCpy $reg_path_device "SYSTEM\CurrentControlSet\SERVICES\VBoxVideo\Device0"
+ StrCpy $reg_path_monitor "SYSTEM\CurrentControlSet\SERVICES\VBoxVideo\Device0\Mon00000001"
+ ${ElseIf} $win_ver == "XP"
+ ${OrIf} $win_ver == "7"
+ StrCpy $reg_path_device "SYSTEM\CurrentControlSet\Control\Video\$dev_id\0000"
+ StrCpy $reg_path_monitor "SYSTEM\CurrentControlSet\Control\VIDEO\$dev_id\0000\Mon00000001"
+ ${Else}
+ DetailPrint "Custom mode set: Platform '$win_ver' not supported yet."
+ Goto exit
+ ${EndIf}
+
+ ; Write the new value in the adapter config (VBoxVideo.sys) using hex values in binary format
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /registry write HKLM $reg_path_device CustomXRes REG_BIN $g_iScreenX DWORD'
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /registry write HKLM $reg_path_device CustomYRes REG_BIN $g_iScreenY DWORD'
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /registry write HKLM $reg_path_device CustomBPP REG_BIN $g_iScreenBpp DWORD'
+
+ ; ... and tell Windows to use that mode on next start!
+ WriteRegDWORD HKCC $reg_path_device "DefaultSettings.XResolution" "$g_iScreenX"
+ WriteRegDWORD HKCC $reg_path_device "DefaultSettings.YResolution" "$g_iScreenY"
+ WriteRegDWORD HKCC $reg_path_device "DefaultSettings.BitsPerPixel" "$g_iScreenBpp"
+
+ WriteRegDWORD HKCC $reg_path_monitor "DefaultSettings.XResolution" "$g_iScreenX"
+ WriteRegDWORD HKCC $reg_path_monitor "DefaultSettings.YResolution" "$g_iScreenY"
+ WriteRegDWORD HKCC $reg_path_monitor "DefaultSettings.BitsPerPixel" "$g_iScreenBpp"
+
+ DetailPrint "Custom mode set to $g_iScreenXx$g_iScreenY, $g_iScreenBpp BPP on next restart."
+
+exit:
+
+FunctionEnd
+
+Function W2K_Prepare
+
+ ; Stop / kill VBoxService
+ Call StopVBoxService
+
+ ; Stop / kill VBoxTray
+ Call StopVBoxTray
+
+ ; Delete VBoxService from registry
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService"
+
+ ; Delete old VBoxService.exe from install directory (replaced by VBoxTray.exe)
+ Delete /REBOOTOK "$INSTDIR\VBoxService.exe"
+
+FunctionEnd
+
+Function W2K_CopyFiles
+
+ SetOutPath "$INSTDIR"
+
+ ; Video driver
+ FILE "$%PATH_OUT%\bin\additions\VBoxVideo.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxDisp.dll"
+
+ ; Mouse driver
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouse.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouse.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ FILE "$%PATH_OUT%\bin\additions\VBoxMouse.cat"
+!endif
+
+ ; Guest driver
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuest.sys"
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuest.inf"
+!ifdef VBOX_SIGN_ADDITIONS
+ FILE "$%PATH_OUT%\bin\additions\VBoxGuest.cat"
+!endif
+
+ ; Guest driver files
+ FILE "$%PATH_OUT%\bin\additions\VBCoInst.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxTray.exe"
+ FILE "$%PATH_OUT%\bin\additions\VBoxControl.exe" ; Not used by W2K and up, but required by the .INF file
+
+ ; WHQL fake
+!ifdef WHQL_FAKE
+ FILE "$%PATH_OUT%\bin\additions\VBoxWHQLFake.exe"
+!endif
+
+ SetOutPath $g_strSystemDir
+
+ ; VBoxService
+ FILE "$%PATH_OUT%\bin\additions\VBoxService.exe" ; Only used by W2K and up (for Shared Folders at the moment)
+
+!if $%VBOX_WITH_CROGL% == "1"
+ ; crOpenGL
+ SetOutPath $g_strSystemDir
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLarrayspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLcrutil.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLerrorspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLpackspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLpassthroughspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGLfeedbackspu.dll"
+ FILE "$%PATH_OUT%\bin\additions\VBoxOGL.dll"
+
+ !if $%BUILD_TARGET_ARCH% == "amd64"
+ ; Only 64-bit installer: Also copy 32-bit DLLs on 64-bit target arch in
+ ; Wow64 node (32-bit sub system).
+ ${EnableX64FSRedirection}
+ SetOutPath $SYSDIR
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLarrayspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLcrutil.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLerrorspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpackspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLpassthroughspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGLfeedbackspu.dll"
+ FILE "$%VBOX_PATH_ADDITIONS_WIN_X86%\VBoxOGL.dll"
+ ${DisableX64FSRedirection}
+ !endif
+
+!endif ; VBOX_WITH_CROGL
+
+FunctionEnd
+
+!ifdef WHQL_FAKE
+
+Function W2K_WHQLFakeOn
+
+ StrCmp $g_bFakeWHQL "true" do
+ Goto exit
+
+do:
+
+ DetailPrint "Turning off WHQL protection..."
+ nsExec::ExecToLog '"$INSTDIR\VBoxWHQLFake.exe" "ignore"'
+
+exit:
+
+FunctionEnd
+
+Function W2K_WHQLFakeOff
+
+ StrCmp $g_bFakeWHQL "true" do
+ Goto exit
+
+do:
+
+ DetailPrint "Turning back on WHQL protection..."
+ nsExec::ExecToLog '"$INSTDIR\VBoxWHQLFake.exe" "warn"'
+
+exit:
+
+FunctionEnd
+
+!endif
+
+Function W2K_InstallFiles
+
+ ; The Shared Folder IFS goes to the system directory
+ FILE /oname=$g_strSystemDir\drivers\VBoxSF.sys "$%PATH_OUT%\bin\additions\VBoxSF.sys"
+ !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxMRXNP.dll" "$g_strSystemDir\VBoxMRXNP.dll" "$INSTDIR"
+ AccessControl::GrantOnFile "$g_strSystemDir\VBoxMRXNP.dll" "(BU)" "GenericRead"
+
+ ; The VBoxTray hook DLL also goes to the system directory; it might be locked
+ !insertmacro ReplaceDLL "$%PATH_OUT%\bin\additions\VBoxHook.dll" "$g_strSystemDir\VBoxHook.dll" "$INSTDIR"
+ AccessControl::GrantOnFile "$g_strSystemDir\VBoxHook.dll" "(BU)" "GenericRead"
+
+ DetailPrint "Installing Drivers..."
+
+drv_video:
+
+ StrCmp $g_bNoVideoDrv "true" drv_guest
+ SetOutPath "$INSTDIR"
+ DetailPrint "Installing video driver ..."
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00" "$INSTDIR\VBoxVideo.inf" "Display"'
+ Pop $0 ; Ret value
+ LogText "Video driver result: $0"
+ IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+drv_guest:
+
+ StrCmp $g_bNoGuestDrv "true" drv_mouse
+ DetailPrint "Installing guest driver ..."
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /i "PCI\VEN_80EE&DEV_CAFE&SUBSYS_00000000&REV_00" "$INSTDIR\VBoxGuest.inf" "Media"'
+ Pop $0 ; Ret value
+ LogText "Guest driver result: $0"
+ IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+drv_mouse:
+
+ StrCmp $g_bNoMouseDrv "true" vbox_service
+ DetailPrint "Installing mouse filter ..."
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /inf "$INSTDIR\VBoxMouse.inf"'
+ Pop $0 ; Ret value
+ LogText "Mouse driver returned: $0"
+ IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+vbox_service:
+
+ DetailPrint "Installing VirtualBox service ..."
+
+ ; Create the VBoxService service
+ ; No need to stop/remove the service here! Do this only on uninstallation!
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxService" "VirtualBox Guest Additions Service" 16 2 "system32\VBoxService.exe" "Base"'
+ Pop $0 ; Ret value
+ LogText "VBoxService returned: $0"
+
+ ; Set service description
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxService" "Description" "Manages VM runtime information, time synchronization, remote sysprep execution and miscellaneous utilities for guest operating systems."
+
+sf:
+
+ DetailPrint "Installing Shared Folders service ..."
+
+ ; Create the Shared Folders service ...
+ ; No need to stop/remove the service here! Do this only on uninstallation!
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /createsvc "VBoxSF" "VirtualBox Shared Folders" 2 1 "system32\drivers\VBoxSF.sys" "NetworkProvider"'
+
+ ; ... and the link to the network provider
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "DeviceName" "\Device\VBoxMiniRdr"
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "Name" "VirtualBox Shared Folders"
+ WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\VBoxSF\NetworkProvider" "ProviderPath" "$SYSDIR\VBoxMRXNP.dll"
+
+ ; Add default network providers (if not present or corrupted)
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider WebClient'
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider LanmanWorkstation'
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider RDPNP'
+
+ ; Add the shared folders network provider
+ DetailPrint "Adding network provider (Order = $g_iSfOrder) ..."
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /addnetprovider VBoxSF $g_iSfOrder'
+ Pop $0 ; Ret value
+ IntCmp $0 0 +1 error error ; Check ret value (0=OK, 1=Error)
+
+!if $%VBOX_WITH_CROGL% == "1"
+cropengl:
+
+ DetailPrint "Installing 3D OpenGL support ..."
+ WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Version" 2
+ WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "DriverVersion" 1
+ WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Flags" 1
+ WriteRegStr HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Dll" "VBoxOGL.dll"
+
+ ; Write additional keys required for Windows 7 & XP 64-bit (but for 32-bit stuff)
+ Push $R0
+ Call GetWindowsVersion
+ Pop $R0 ; Windows Version
+ ${If} $R0 == '7'
+ ${OrIf} $R0 == 'XP'
+ WriteRegDWORD HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Version" 2
+ WriteRegDWORD HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "DriverVersion" 1
+ WriteRegDWORD HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Flags" 1
+ WriteRegStr HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL" "Dll" "VBoxOGL.dll"
+ ${EndIf}
+ Pop $R0
+!endif
+
+ Goto done
+
+error:
+
+ Abort "ERROR: Could not install files for Windows 2000 / XP / Vista! Installation aborted."
+
+done:
+
+FunctionEnd
+
+Function W2K_Main
+
+ SetOutPath "$INSTDIR"
+ SetOverwrite on
+
+ Call W2K_Prepare
+ Call W2K_CopyFiles
+
+!ifdef WHQL_FAKE
+ Call W2K_WHQLFakeOn
+!endif
+
+ Call W2K_InstallFiles
+
+!ifdef WHQL_FAKE
+ Call W2K_WHQLFakeOff
+!endif
+
+ Call W2K_SetVideoResolution
+
+FunctionEnd
+
+!macro W2K_UninstallInstDir un
+Function ${un}W2K_UninstallInstDir
+
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.sys"
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.inf"
+ Delete /REBOOTOK "$INSTDIR\VBoxVideo.cat"
+ Delete /REBOOTOK "$INSTDIR\VBoxDisp.dll"
+
+ Delete /REBOOTOK "$INSTDIR\VBoxMouse.sys"
+ Delete /REBOOTOK "$INSTDIR\VBoxMouse.inf"
+ Delete /REBOOTOK "$INSTDIR\VBoxMouse.cat"
+
+ Delete /REBOOTOK "$INSTDIR\VBoxTray.exe"
+
+ Delete /REBOOTOK "$INSTDIR\VBoxGuest.sys"
+ Delete /REBOOTOK "$INSTDIR\VBoxGuest.inf"
+ Delete /REBOOTOK "$INSTDIR\VBoxGuest.cat"
+
+ Delete /REBOOTOK "$INSTDIR\VBCoInst.dll"
+ Delete /REBOOTOK "$INSTDIR\VBoxControl.exe"
+ Delete /REBOOTOK "$INSTDIR\VBoxService.exe" ; File from an older installation maybe, not present here anymore
+
+ ; WHQL fake
+!ifdef WHQL_FAKE
+ Delete /REBOOTOK "$INSTDIR\VBoxWHQLFake.exe"
+!endif
+
+ ; Log file
+ Delete /REBOOTOK "$INSTDIR\install.log"
+ Delete /REBOOTOK "$INSTDIR\install_ui.log"
+
+FunctionEnd
+!macroend
+!insertmacro W2K_UninstallInstDir ""
+!insertmacro W2K_UninstallInstDir "un."
+
+!macro W2K_Uninstall un
+Function ${un}W2K_Uninstall
+
+ Push $0
+
+ ; Remove VirtualBox graphics adapter & PCI base drivers
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /u "PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00"'
+ Pop $0 ; Ret value
+ ; @todo Add error handling here!
+
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /u "PCI\VEN_80EE&DEV_CAFE&SUBSYS_00000000&REV_00"'
+ Pop $0 ; Ret value
+ ; @todo Add error handling here!
+
+ ; @todo restore old drivers
+
+ ; Remove video driver
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxVideo'
+ Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxVideo.sys"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxDisp.dll"
+
+ ; Remove mouse driver
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxMouse'
+ Pop $0 ; Ret value
+ Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxMouse.sys"
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /reg_delmultisz "SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}" "UpperFilters" "VBoxMouse"'
+ Pop $0 ; Ret value
+ ; @todo Add error handling here!
+
+ ; Delete the VBoxService service
+ Call ${un}StopVBoxService
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxService'
+ Pop $0 ; Ret value
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxService"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxService.exe"
+
+ ; GINA
+ Delete /REBOOTOK "$g_strSystemDir\VBoxGINA.dll"
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL"
+ ${If} $0 == "VBoxGINA.dll"
+ DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon" "GinaDLL"
+ ${EndIf}
+
+ ; Delete VBoxTray
+ Call ${un}StopVBoxTray
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray"
+
+ ; Remove guest driver
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxGuest'
+ Pop $0 ; Ret value
+ Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxGuest.sys"
+ Delete /REBOOTOK "$g_strSystemDir\vbcoinst.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxTray.exe"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxHook.dll"
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "VBoxTray" ; Remove VBoxTray autorun
+ Delete /REBOOTOK "$g_strSystemDir\VBoxControl.exe"
+
+ ; Remove shared folders driver
+ call ${un}RemoveProvider ; Remove Shared Folders network provider from registry
+ ; @todo Add a /delnetprovider to VBoxDrvInst for doing this job!
+ nsExec::ExecToLog '"$INSTDIR\VBoxDrvInst.exe" /delsvc VBoxSF'
+ Delete /REBOOTOK "$g_strSystemDir\VBoxMRXNP.dll" ; The network provider DLL will be locked
+ Delete /REBOOTOK "$g_strSystemDir\drivers\VBoxSF.sys"
+
+!if $%VBOX_WITH_CROGL% == "1"
+
+ DetailPrint "Removing 3D graphics support ..."
+ !if $%BUILD_TARGET_ARCH% == "x86"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGLarrayspu.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGLcrutil.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGLerrorspu.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGLpackspu.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGLpassthroughspu.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGLfeedbackspu.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxOGL.dll"
+
+ ; Remove D3D stuff
+ ; @todo add a feature flag to only remove if installed explicitly
+ Delete /REBOOTOK "$g_strSystemDir\libWine.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxD3D8.dll"
+ Delete /REBOOTOK "$g_strSystemDir\VBoxD3D9.dll"
+ Delete /REBOOTOK "$g_strSystemDir\wined3d.dll"
+ ; Update DLL cache
+ IfFileExists "$g_strSystemDir\dllcache\msd3d8.dll" 0 +2
+ Delete /REBOOTOK "$g_strSystemDir\dllcache\d3d8.dll"
+ Rename /REBOOTOK "$g_strSystemDir\dllcache\msd3d8.dll" "$g_strSystemDir\dllcache\d3d8.dll"
+ IfFileExists g_strSystemDir\dllcache\msd3d9.dll" 0 +2
+ Delete /REBOOTOK "$g_strSystemDir\dllcache\d3d9.dll"
+ Rename /REBOOTOK "$g_strSystemDir\dllcache\msd3d9.dll" "$g_strSystemDir\dllcache\d3d9.dll"
+ ; Restore original DX DLLs
+ IfFileExists "$g_strSystemDir\msd3d8.dll" 0 +2
+ Delete /REBOOTOK "$g_strSystemDir\d3d8.dll"
+ Rename /REBOOTOK "$g_strSystemDir\msd3d8.dll" "$g_strSystemDir\d3d8.dll"
+ IfFileExists "$g_strSystemDir\msd3d9.dll" 0 +2
+ Delete /REBOOTOK "$g_strSystemDir\d3d9.dll"
+ Rename /REBOOTOK "$g_strSystemDir\msd3d9.dll" "$g_strSystemDir\d3d9.dll"
+
+ !else ; amd64
+
+ ; Only 64-bit installer: Also remove 32-bit DLLs on 64-bit target arch in Wow64 node
+ ${EnableX64FSRedirection}
+ Delete /REBOOTOK "$SYSDIR\VBoxOGLarrayspu.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxOGLcrutil.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxOGLerrorspu.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxOGLpackspu.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxOGLpassthroughspu.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxOGLfeedbackspu.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxOGL.dll"
+
+ ; Remove D3D stuff
+ ; @todo add a feature flag to only remove if installed explicitly
+ Delete /REBOOTOK "$SYSDIR\libWine.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxD3D8.dll"
+ Delete /REBOOTOK "$SYSDIR\VBoxD3D9.dll"
+ Delete /REBOOTOK "$SYSDIR\wined3d.dll"
+ ; Update DLL cache
+ IfFileExists "$SYSDIR\dllcache\msd3d8.dll" 0 +2
+ Delete /REBOOTOK "$SYSDIR\dllcache\d3d8.dll"
+ Rename /REBOOTOK "$SYSDIR\dllcache\msd3d8.dll" "$SYSDIR\dllcache\d3d8.dll"
+ IfFileExists "$SYSDIR\dllcache\msd3d9.dll" 0 +2
+ Delete /REBOOTOK "$SYSDIR\dllcache\d3d9.dll"
+ Rename /REBOOTOK "$SYSDIR\dllcache\msd3d9.dll" "$SYSDIR\dllcache\d3d9.dll"
+ ; Restore original DX DLLs
+ IfFileExists "$SYSDIR\msd3d8.dll" 0 +2
+ Delete /REBOOTOK "$SYSDIR\d3d8.dll"
+ Rename /REBOOTOK "$SYSDIR\msd3d8.dll" "$SYSDIR\d3d8.dll"
+ IfFileExists "$SYSDIR\msd3d9.dll" 0 +2
+ Delete /REBOOTOK "$SYSDIR\d3d9.dll"
+ Rename /REBOOTOK "$SYSDIR\msd3d9.dll" "$SYSDIR\d3d9.dll"
+ DeleteRegKey HKLM "SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL"
+ ${DisableX64FSRedirection}
+ !endif ; amd64
+
+ DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\VBoxOGL"
+
+!endif ; VBOX_WITH_CROGL
+
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro W2K_Uninstall ""
+!insertmacro W2K_Uninstall "un."
+
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp
new file mode 100644
index 00000000000..8651d850255
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.cpp
@@ -0,0 +1,472 @@
+/** @file
+ *
+ * instdrvmain - Install guest drivers on NT4
+ *
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+/**
+ * @todo
+ * The spacing in this file is horrible! Here are some simple rules:
+ * - tabs are forbidden
+ * - indentation is 4 spaces
+ */
+
+
+#include <windows.h>
+#include <setupapi.h>
+#include <regstr.h>
+#include <DEVGUID.h>
+#include <stdio.h>
+
+#include "tchar.h"
+#include "string.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+
+/** The video service name. */
+#define VBOXGUEST_VIDEO_NAME "VBoxVideo"
+
+/** The video inf file name */
+#define VBOXGUEST_VIDEO_INF_NAME "VBoxVideo.inf"
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+/**
+ * Do some cleanup of data we used. Called by installVideoDriver()
+ */
+void closeAndDestroy(HDEVINFO hDevInfo, HINF hInf)
+{
+ SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ SetupCloseInfFile(hInf);
+}
+
+
+/**
+ * Install the VBox video driver.
+ *
+ * @returns TRUE on success.
+ * @returns FALSE on failure.
+ * @param szDriverDir The base directory where we find the INF.
+ */
+BOOL installVideoDriver(TCHAR* szDriverDir)
+{
+ HDEVINFO hDevInfo;
+ SP_DEVINSTALL_PARAMS DeviceInstallParams={0};
+ SP_DRVINFO_DATA drvInfoData={0};
+ SP_DRVINFO_DETAIL_DATA DriverInfoDetailData={0};
+
+ DWORD cbReqSize;
+
+ /* Vars used for reading the INF */
+ HINF hInf;
+ TCHAR szServiceSection[LINE_LEN];
+ INFCONTEXT serviceContext;
+ TCHAR szServiceData[LINE_LEN];
+ TCHAR deviceRegStr[1000];//I'm lazy here. 1000 ought to be enough for everybody...
+
+ SP_DEVINFO_DATA deviceInfoData;
+ DWORD configFlags;
+
+ HKEY hkey;
+ DWORD disp;
+ TCHAR regKeyName[LINE_LEN];
+
+ BOOL rc;
+
+ /* Create an empty list */
+ hDevInfo = SetupDiCreateDeviceInfoList((LPGUID) &GUID_DEVCLASS_DISPLAY,
+ NULL);
+
+ if (hDevInfo == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ memset(&DeviceInstallParams, 0, sizeof(SP_DEVINSTALL_PARAMS));
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+
+ rc=SetupDiGetDeviceInstallParams(hDevInfo,
+ NULL,
+ &DeviceInstallParams);
+
+ if(!rc)
+ return FALSE;
+
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ DeviceInstallParams.Flags |= DI_NOFILECOPY | /* We did our own file copying */
+ DI_DONOTCALLCONFIGMG |
+ DI_ENUMSINGLEINF; /* .DriverPath specifies an inf file */
+
+
+ /* Path to inf file */
+ wsprintf(DeviceInstallParams.DriverPath,
+ TEXT("%ws\\%ws"),
+ szDriverDir, TEXT(VBOXGUEST_VIDEO_INF_NAME));
+
+ rc=SetupDiSetDeviceInstallParams(hDevInfo,
+ NULL,
+ &DeviceInstallParams);
+ if(!rc)
+ return FALSE;
+
+ /* Read the drivers from the inf file */
+ if (!SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER))
+ {
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return FALSE;
+ }
+
+ /* Get the first found driver.
+ Our Inf file only contains one so this is fine */
+ drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
+ if(FALSE==SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
+ 0, &drvInfoData)){
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return FALSE;
+ }
+
+ /* Get necessary driver details */
+ DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+ if (!(!SetupDiGetDriverInfoDetail(hDevInfo,
+ NULL,
+ &drvInfoData,
+ &DriverInfoDetailData,
+ DriverInfoDetailData.cbSize,
+ &cbReqSize)
+ &&GetLastError()== ERROR_INSUFFICIENT_BUFFER) )
+ {
+ SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return FALSE;
+ }
+
+ hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
+ NULL, INF_STYLE_WIN4, NULL);
+
+ if (hInf == INVALID_HANDLE_VALUE)
+ {
+ SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return FALSE;
+ }
+
+ /* First install the service */
+ wsprintf(szServiceSection, TEXT("%ws.Services"),
+ DriverInfoDetailData.SectionName);
+
+ if(!SetupFindFirstLine(hInf, szServiceSection, NULL, &serviceContext))
+ {
+ /* No service line?? Can't be... */
+ closeAndDestroy(hDevInfo, hInf);
+ return FALSE;
+ }
+
+ /* Get the name */
+ SetupGetStringField(&serviceContext,
+ 1,
+ szServiceData,
+ sizeof(szServiceData),
+ NULL);
+
+ wsprintf(deviceRegStr, TEXT("Root\\LEGACY_%ws\\0000"), szServiceData);
+
+ memset(&deviceInfoData, 0, sizeof(SP_DEVINFO_DATA));
+ deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+
+ if (SetupDiOpenDeviceInfo(hDevInfo, deviceRegStr, NULL, 0, &deviceInfoData) //Check for existing
+ ||(SetupDiCreateDeviceInfo(hDevInfo, deviceRegStr, //Create new
+ (LPGUID) &GUID_DEVCLASS_DISPLAY,
+ NULL, //Do we need a description here?
+ NULL, //No user interface
+ 0,
+ &deviceInfoData) &&
+ SetupDiRegisterDeviceInfo(hDevInfo,
+ &deviceInfoData,
+ 0,
+ NULL,
+ NULL,
+ NULL)) )
+ {
+ /* We created a new key in the registry */
+
+ memset(&DeviceInstallParams, 0,sizeof(SP_DEVINSTALL_PARAMS));
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+
+ SetupDiGetDeviceInstallParams(hDevInfo,
+ &deviceInfoData,
+ &DeviceInstallParams);
+
+ DeviceInstallParams.Flags |= DI_NOFILECOPY | //We already copied the files
+ DI_DONOTCALLCONFIGMG |
+ DI_ENUMSINGLEINF; //Use our INF file only
+
+ /* Path to inf file */
+ wsprintf(DeviceInstallParams.DriverPath,
+ TEXT("%ws\\%ws"),
+ szDriverDir, TEXT(VBOXGUEST_VIDEO_INF_NAME));
+
+ SetupDiSetDeviceInstallParams(hDevInfo,
+ &deviceInfoData,
+ &DeviceInstallParams);
+
+
+ if(!SetupDiBuildDriverInfoList(hDevInfo,
+ &deviceInfoData,
+ SPDIT_CLASSDRIVER))
+ {
+ closeAndDestroy(hDevInfo, hInf);
+ return FALSE;
+ }
+
+ drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
+ if (!SetupDiEnumDriverInfo(hDevInfo,
+ &deviceInfoData,
+ SPDIT_CLASSDRIVER,
+ 0,
+ &drvInfoData))
+ {
+ closeAndDestroy(hDevInfo, hInf);
+ return FALSE;
+ }
+
+ if(!SetupDiSetSelectedDriver(hDevInfo,
+ &deviceInfoData,
+ &drvInfoData))
+ {
+ closeAndDestroy(hDevInfo, hInf);
+ return FALSE;
+ }
+
+ if(!SetupDiInstallDevice(hDevInfo,
+ &deviceInfoData))
+ {
+ closeAndDestroy(hDevInfo, hInf);
+ return FALSE;
+ }
+ }
+
+ /* Make sure the device is enabled */
+ if (SetupDiGetDeviceRegistryProperty(hDevInfo,
+ &deviceInfoData, SPDRP_CONFIGFLAGS,
+ NULL, (LPBYTE) &configFlags,
+ sizeof(DWORD),
+ NULL)
+ && (configFlags & CONFIGFLAG_DISABLED))
+ {
+ configFlags &= ~CONFIGFLAG_DISABLED;
+
+ SetupDiSetDeviceRegistryProperty(hDevInfo,
+ &deviceInfoData,
+ SPDRP_CONFIGFLAGS,
+ (LPBYTE) &configFlags,
+ sizeof(DWORD));
+ }
+
+ wsprintf(regKeyName,
+ TEXT("System\\CurrentControlSet\\Services\\%ws\\Device%d"),
+ szServiceData, 0); //We only have one device
+
+ if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ regKeyName,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hkey,
+ &disp) == ERROR_SUCCESS)
+ {
+ /* Insert description */
+ RegSetValueEx(hkey,
+ TEXT("Device Description"),
+ 0,
+ REG_SZ,
+ (LPBYTE) DriverInfoDetailData.DrvDescription,
+ (lstrlen(DriverInfoDetailData.DrvDescription) + 1) *
+ sizeof(TCHAR) );
+
+ TCHAR szSoftwareSection[LINE_LEN];
+
+ wsprintf(szSoftwareSection,
+ TEXT("%ws.SoftwareSettings"),
+ szServiceData);
+
+ if (!SetupInstallFromInfSection(NULL,
+ hInf,
+ szSoftwareSection,
+ SPINST_REGISTRY,
+ hkey,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL))
+ {
+ RegCloseKey(hkey);
+ closeAndDestroy(hDevInfo, hInf);
+ return FALSE;
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ /* Install OpenGL stuff */
+ if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers"),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hkey,
+ &disp) == ERROR_SUCCESS)
+ {
+ /* Do installation here if ever necessary. Currently there is no OpenGL stuff */
+
+ RegCloseKey(hkey);
+ }
+
+
+ /* Cleanup */
+ closeAndDestroy(hDevInfo, hInf);
+
+#if 0
+ /* If this key is inserted into the registry, windows will show the desktop
+ applet on next boot. We decide in the installer if we want that so the code
+ is disabled here. */
+ /* Set registry keys so windows picks up the changes */
+ if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\NewDisplay"),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hkey,
+ &disp) == ERROR_SUCCESS)
+ {
+ RegCloseKey(hkey);
+ }
+#endif
+
+ /* We must reboot at some point */
+ if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\RebootNecessary"),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hkey,
+ &disp) == ERROR_SUCCESS)
+ {
+ RegCloseKey(hkey);
+ }
+
+ return TRUE;
+}
+
+
+void displayHelpAndExit(char *programName)
+{
+ printf("Installs VirtualBox Guest Additions for Windows NT 4.0\n\n");
+ printf("Syntax: %s [/i|/u]\n", programName);
+ printf("\n\t/i - perform Guest Additions installation\n");
+ printf("\t/u: - perform Guest Additions uninstallation\n");
+ exit(1);
+}
+
+/**
+ * Check if we are running on NT4.
+ *
+ * @returns TRUE if NT 4.
+ * @returns FALSE otherwise.
+ */
+BOOL isNT4(void)
+{
+ OSVERSIONINFO osVersion;
+
+ osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osVersion);
+
+ switch (osVersion.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32s:
+ case VER_PLATFORM_WIN32_WINDOWS:
+ return FALSE;
+ case VER_PLATFORM_WIN32_NT:
+ if (osVersion.dwMajorVersion == 4)
+ return TRUE;
+ else
+ return FALSE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/**
+ * Video driver uninstallation will be added later if necessary.
+ */
+int uninstallDrivers(void)
+{
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ BOOL rc=FALSE;
+ TCHAR szInstallDir[MAX_PATH];
+ HMODULE hExe = GetModuleHandle(NULL);
+
+ /** @todo r=bird:
+ * And by the way, we're only missing the coding style dmik uses now
+ * and this file would contain the complete set. */
+ if(2!=argc || (stricmp(argv[1], "/i") && stricmp(argv[1], "/u")))
+ displayHelpAndExit(argv[0]);
+
+ /* This program is only for installing drivers on NT4 */
+ if(!isNT4()){
+ printf("This program only runs on NT4\n");
+ return -1;
+ }
+
+ if (!GetModuleFileName(hExe, &szInstallDir[0], sizeof(szInstallDir)))
+ {
+ printf("GetModuleFileName failed! rc = %d\n", GetLastError());
+ return -1;
+ }
+
+ TCHAR *lastBackslash = wcsrchr(szInstallDir, L'\\');
+
+ if (!lastBackslash)
+ {
+ printf("Invalid path name!\n");
+ return -1;
+ }
+
+ *lastBackslash=L'\0';
+
+ /* Install video driver. Mouse driver installation is done by overwriting
+ the image path in the setup script. */
+ if(!stricmp(argv[1], "/i")){
+ rc=installVideoDriver(szInstallDir);
+ }
+ else{
+ /* No video driver uninstallation yet. Do we need it? */
+ }
+
+ if(FALSE==rc)
+ printf("Some failure occurred during driver installation.\n");
+ return !rc; /* Return != 0 on failure. */
+}
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc
new file mode 100644
index 00000000000..4e3769ffa26
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxGuestDrvInst.rc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#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 Guest Driver Installer\0"
+ VALUE "FileVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ VALUE "InternalName", "VBoxGuestDrvInst\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", "VBoxGuestDrvInst.exe\0"
+ VALUE "ProductName", "VirtualBox Guest Additions\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au3 b/src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au3
new file mode 100644
index 00000000000..f121d010024
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/VBoxWHQLFake.au3
@@ -0,0 +1,59 @@
+; VBoxFakeWHQL - Turns off / on the WHQL for installing unsigned drivers.
+; Currently only tested with Win2K / XP!
+;
+; Copyright (C) 2008-2010 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+; Strings for localization
+; When using an OS with another language, you have to provide the correct
+; strings for it. English and German is provided below.
+;
+; @todo Needs to be improved to handle the stuff without language strings in
+; the future!
+
+;$sysprop_Title = "System Properties"
+;$drvsig_Title = "Driver Signing Options"
+
+$sysprop_Title = "Systemeigenschaften"
+$drvsig_Title = "Treibersignaturoptionen"
+
+$ok_Title = "OK"
+
+If $CmdLine[0] < 1 Then
+ MsgBox ( 0, "ERROR", "Please specify 'ignore', 'warn' or 'block' as parameter!" )
+ Exit
+EndIf
+
+Run("control.exe sysdm.cpl")
+If WinWait($sysprop_Title, "", 5) = 0 Then
+ WinClose("[ACTIVE]", "")
+ Exit
+EndIf
+
+ControlCommand($sysprop_Title, "", "SysTabControl321", "TabRight", "")
+ControlCommand($sysprop_Title, "", "SysTabControl321", "TabRight", "")
+
+Sleep(200) ; Wait a while for tab switchig above
+ControlClick($sysprop_Title, "", 14007) ; Button 'Driver Signing'
+
+WinWait($drvsig_Title, "", 5)
+
+If $CmdLine[1] = "ignore" Then
+ ControlClick($drvsig_Title, "", 1000) ; 'Ignore' radio button
+ElseIf $CmdLine[1] = "warn" Then
+ ControlClick($drvsig_Title, "", 1001) ; 'Warn' radio button
+ElseIf $CmdLine[1] = "block" Then
+ ControlClick($drvsig_Title, "", 1002) ; 'Block' radio button
+Else
+ Exit
+EndIf
+
+ControlClick($drvsig_Title, "", 1) ; 'OK' button (ID=1) of dialog 'Driver Signing Options'
+
+WinWait($sysprop_Title, "", 5)
+ControlClick($sysprop_Title, "", 1) ; 'OK' button (ID=1) of 'System Properties'
+
+
diff --git a/src/VBox/Additions/WINNT/Installer/dumplog.nsh b/src/VBox/Additions/WINNT/Installer/dumplog.nsh
new file mode 100644
index 00000000000..059f189ae3f
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/dumplog.nsh
@@ -0,0 +1,50 @@
+!define LVM_GETITEMCOUNT 0x1004
+!define LVM_GETITEMTEXT 0x102D
+
+!macro DumpLog un
+Function ${un}DumpLog
+ Exch $5
+ Push $0
+ Push $1
+ Push $2
+ Push $3
+ Push $4
+ Push $6
+
+ FindWindow $0 "#32770" "" $HWNDPARENT
+ GetDlgItem $0 $0 1016
+ StrCmp $0 0 error
+ FileOpen $5 $5 "w"
+ StrCmp $5 0 error
+ SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
+ System::Alloc ${NSIS_MAX_STRLEN}
+ Pop $3
+ StrCpy $2 0
+ System::Call "*(i, i, i, i, i, i, i, i, i) i \
+ (0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
+ loop: StrCmp $2 $6 done
+ System::Call "User32::SendMessageA(i, i, i, i) i \
+ ($0, ${LVM_GETITEMTEXT}, $2, r1)"
+ System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
+ FileWrite $5 "$4$\r$\n"
+ IntOp $2 $2 + 1
+ Goto loop
+ done:
+ FileClose $5
+ System::Free $1
+ System::Free $3
+ Goto exit
+ error:
+ MessageBox MB_OK "Could not create Log-File!" /SD IDOK
+ exit:
+ Pop $6
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+ Exch $5
+FunctionEnd
+!macroend
+!insertmacro DumpLog ""
+!insertmacro DumpLog "un."
diff --git a/src/VBox/Additions/WINNT/Installer/iexplore.ico b/src/VBox/Additions/WINNT/Installer/iexplore.ico
new file mode 100644
index 00000000000..991256b6b0b
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/iexplore.ico
Binary files differ
diff --git a/src/VBox/Additions/WINNT/Installer/servicepack.nsh b/src/VBox/Additions/WINNT/Installer/servicepack.nsh
new file mode 100644
index 00000000000..f1eae515c51
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/servicepack.nsh
@@ -0,0 +1,29 @@
+;-------------------------------------------------------------------------------
+; GetServicePack
+; Author: Alessio Garbi (e-Project srl) <agarbi@e-project.it>
+;
+; input:
+; none
+; output:
+; top of stack: last service pack major version
+; top of stack-1: last service pack minor version
+; note:
+; If no service pack installed returns major ver "0" and minor ver "0"
+; Function tested with Win 95, 98SE, NT4, 2000, XP, 2003 (lang ITA and ENG)
+
+!macro GetServicePack un
+Function ${un}GetServicePack
+ Push $R0
+ Push $R1
+
+ ReadRegDWORD $R0 HKLM "System\CurrentControlSet\Control\Windows" "CSDVersion"
+ IntOp $R1 $R0 % 256 ;get minor version
+ IntOp $R0 $R0 / 256 ;get major version
+
+ Exch $R1
+ Exch
+ Exch $R0
+FunctionEnd
+!macroend
+!insertmacro GetServicePack ""
+!insertmacro GetServicePack "un."
diff --git a/src/VBox/Additions/WINNT/Installer/strstr.nsh b/src/VBox/Additions/WINNT/Installer/strstr.nsh
new file mode 100644
index 00000000000..58e25476b81
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/strstr.nsh
@@ -0,0 +1,306 @@
+; StrStr
+ ; input, top of stack = string to search for
+ ; top of stack-1 = string to search in
+ ; output, top of stack (replaces with the portion of the string remaining)
+ ; modifies no other variables.
+ ;
+ ; Usage:
+ ; Push "this is a long ass string"
+ ; Push "ass"
+ ; Call StrStr
+ ; Pop $R0
+ ; ($R0 at this point is "ass string")
+
+
+!macro StrStr un
+ Function ${un}StrStr
+ Exch $R1 ; st=haystack,old$R1, $R1=needle
+ Exch ; st=old$R1,haystack
+ Exch $R2 ; st=old$R1,old$R2, $R2=haystack
+ Push $R3
+ Push $R4
+ Push $R5
+ StrLen $R3 $R1
+ StrCpy $R4 0
+ ; $R1=needle
+ ; $R2=haystack
+ ; $R3=len(needle)
+ ; $R4=cnt
+ ; $R5=tmp
+ loop:
+ StrCpy $R5 $R2 $R3 $R4
+ StrCmp $R5 $R1 done
+ StrCmp $R5 "" done
+ IntOp $R4 $R4 + 1
+ Goto loop
+ done:
+ StrCpy $R1 $R2 "" $R4
+ Pop $R5
+ Pop $R4
+ Pop $R3
+ Pop $R2
+ Exch $R1
+ FunctionEnd
+!macroend
+!insertmacro StrStr ""
+!insertmacro StrStr "un."
+
+!macro StrStrAdv un
+Function ${un}StrStrAdv
+
+ ; After this point:
+ ; $0 = String (input)
+ ; $1 = SubString (input)
+ ; $2 = SearchDirection (input)
+ ; $3 = StrInclusionDirection (input)
+ ; $4 = IncludeSubString (input)
+ ; $5 = Loops (input)
+ ; $6 = CaseSensitive (input)
+ ; $7 = StringLength (temp)
+ ; $8 = StrToSearchLength (temp)
+ ; $9 = CurrentLoop (temp)
+ ; $R0 = EndCharPos (temp)
+ ; $R1 = StartCharPos (temp)
+ ; $R2 = ResultVar (output)
+ ; $R3 = Temp (temp)
+
+ ; Get input from user
+
+ Exch $6
+ Exch
+ Exch $5
+ Exch
+ Exch 2
+ Exch $4
+ Exch 2
+ Exch 3
+ Exch $3
+ Exch 3
+ Exch 4
+ Exch $2
+ Exch 4
+ Exch 5
+ Exch $1
+ Exch 5
+ Exch 6
+ Exch $0
+ Exch 6
+ Push $7
+ Push $8
+ Push $9
+ Push $R3
+ Push $R2
+ Push $R1
+ Push $R0
+
+ ; Clean $R0-$R3 variables
+ StrCpy $R0 ""
+ StrCpy $R1 ""
+ StrCpy $R2 ""
+ StrCpy $R3 ""
+
+ ; Verify if we have the correct values on the variables
+ ${If} $0 == ``
+ SetErrors ;AdvStrStr_StrToSearch not found
+ Goto AdvStrStr_End
+ ${EndIf}
+
+ ${If} $1 == ``
+ SetErrors ;No text to search
+ Goto AdvStrStr_End
+ ${EndIf}
+
+ ${If} $2 != <
+ StrCpy $2 >
+ ${EndIf}
+
+ ${If} $3 != <
+ StrCpy $3 >
+ ${EndIf}
+
+ ${If} $4 <> 0
+ StrCpy $4 1
+ ${EndIf}
+
+ ${If} $5 <= 0
+ StrCpy $5 0
+ ${EndIf}
+
+ ${If} $6 <> 1
+ StrCpy $6 0
+ ${EndIf}
+
+ ; Find "AdvStrStr_String" length
+ StrLen $7 $0
+
+ ; Then find "AdvStrStr_SubString" length
+ StrLen $8 $1
+
+ ; Now set up basic variables
+
+ ${If} $2 == <
+ IntOp $R1 $7 - $8
+ StrCpy $R2 $7
+ ${Else}
+ StrCpy $R1 0
+ StrCpy $R2 $8
+ ${EndIf}
+
+ StrCpy $9 0 ; First loop
+
+ ;Let's begin the search
+
+ ${Do}
+ ; Step 1: If the starting or ending numbers are negative
+ ; or more than AdvStrStr_StringLen, we return
+ ; error
+
+ ${If} $R1 < 0
+ StrCpy $R1 ``
+ StrCpy $R2 ``
+ StrCpy $R3 ``
+ SetErrors ;AdvStrStr_SubString not found
+ Goto AdvStrStr_End
+ ${ElseIf} $R2 > $7
+ StrCpy $R1 ``
+ StrCpy $R2 ``
+ StrCpy $R3 ``
+ SetErrors ;AdvStrStr_SubString not found
+ Goto AdvStrStr_End
+ ${EndIf}
+
+ ; Step 2: Start the search depending on
+ ; AdvStrStr_SearchDirection. Chop down not needed
+ ; characters.
+
+ ${If} $R1 <> 0
+ StrCpy $R3 $0 `` $R1
+ ${EndIf}
+
+ ${If} $R2 <> $7
+ ${If} $R1 = 0
+ StrCpy $R3 $0 $8
+ ${Else}
+ StrCpy $R3 $R3 $8
+ ${EndIf}
+ ${EndIf}
+
+ ; Step 3: Make sure that's the string we want
+
+ ; Case-Sensitive Support <- Use "AdvStrStr_Temp"
+ ; variable because it won't be used anymore
+
+ ${If} $6 == 1
+ System::Call `kernel32::lstrcmpA(ts, ts) i.s` `$R3` `$1`
+ Pop $R3
+ ${If} $R3 = 0
+ StrCpy $R3 1 ; Continue
+ ${Else}
+ StrCpy $R3 0 ; Break
+ ${EndIf}
+ ${Else}
+ ${If} $R3 == $1
+ StrCpy $R3 1 ; Continue
+ ${Else}
+ StrCpy $R3 0 ; Break
+ ${EndIf}
+ ${EndIf}
+
+ ; After the comparasion, confirm that it is the
+ ; value we want.
+
+ ${If} $R3 = 1
+
+ ;We found it, return except if the user has set up to
+ ;search for another one:
+ ${If} $9 >= $5
+
+ ;Now, let's see if the user wants
+ ;AdvStrStr_SubString to appear:
+ ${If} $4 == 0
+ ;Return depends on AdvStrStr_StrInclusionDirection
+ ${If} $3 == <
+ ; RTL
+ StrCpy $R0 $0 $R1
+ ${Else}
+ ; LTR
+ StrCpy $R0 $0 `` $R2
+ ${EndIf}
+ ${Break}
+ ${Else}
+ ;Return depends on AdvStrStr_StrInclusionDirection
+ ${If} $3 == <
+ ; RTL
+ StrCpy $R0 $0 $R2
+ ${Else}
+ ; LTR
+ StrCpy $R0 $0 `` $R1
+ ${EndIf}
+ ${Break}
+ ${EndIf}
+ ${Else}
+ ;If the user wants to have more loops, let's do it so!
+ IntOp $9 $9 + 1
+
+ ${If} $2 == <
+ IntOp $R1 $R1 - 1
+ IntOp $R2 $R2 - 1
+ ${Else}
+ IntOp $R1 $R1 + 1
+ IntOp $R2 $R2 + 1
+ ${EndIf}
+ ${EndIf}
+ ${Else}
+ ; Step 4: We didn't find it, so do steps 1 thru 3 again
+
+ ${If} $2 == <
+ IntOp $R1 $R1 - 1
+ IntOp $R2 $R2 - 1
+ ${Else}
+ IntOp $R1 $R1 + 1
+ IntOp $R2 $R2 + 1
+ ${EndIf}
+ ${EndIf}
+ ${Loop}
+
+ AdvStrStr_End:
+
+ ;Add 1 to AdvStrStr_EndCharPos to be supportable
+ ;by "StrCpy"
+
+ IntOp $R2 $R2 - 1
+
+ ;Return output to user
+
+ Exch $R0
+ Exch
+ Pop $R1
+ Exch
+ Pop $R2
+ Exch
+ Pop $R3
+ Exch
+ Pop $9
+ Exch
+ Pop $8
+ Exch
+ Pop $7
+ Exch
+ Pop $6
+ Exch
+ Pop $5
+ Exch
+ Pop $4
+ Exch
+ Pop $3
+ Exch
+ Pop $2
+ Exch
+ Pop $1
+ Exch
+ Pop $0
+
+FunctionEnd
+!macroend
+!insertmacro StrStrAdv ""
+!insertmacro StrStrAdv "un."
diff --git a/src/VBox/Additions/WINNT/Installer/welcome.bmp b/src/VBox/Additions/WINNT/Installer/welcome.bmp
new file mode 100644
index 00000000000..6596c58dd81
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/welcome.bmp
Binary files differ
diff --git a/src/VBox/Additions/WINNT/Installer/winver.nsh b/src/VBox/Additions/WINNT/Installer/winver.nsh
new file mode 100644
index 00000000000..16defa46c01
--- /dev/null
+++ b/src/VBox/Additions/WINNT/Installer/winver.nsh
@@ -0,0 +1,103 @@
+; GetWindowsVersion
+;
+; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
+; Updated by Joost Verburg
+;
+; Returns on top of stack
+;
+; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003, Vista)
+; or
+; '' (Unknown Windows Version)
+;
+; Usage:
+; Call GetWindowsVersion
+; Pop $R0
+; ; at this point $R0 is "NT 4.0" or whatnot
+
+!macro GetWindowsVersion un
+Function ${un}GetWindowsVersion
+
+ Push $R0
+ Push $R1
+
+ ClearErrors
+
+ ReadRegStr $R0 HKLM \
+ "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
+
+ IfErrors 0 lbl_winnt
+
+ ; we are not NT
+ ReadRegStr $R0 HKLM \
+ "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber
+
+ StrCpy $R1 $R0 1
+ StrCmp $R1 '4' 0 lbl_error
+
+ StrCpy $R1 $R0 3
+
+ StrCmp $R1 '4.0' lbl_win32_95
+ StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98
+
+ lbl_win32_95:
+ StrCpy $R0 '95'
+ Goto lbl_done
+
+ lbl_win32_98:
+ StrCpy $R0 '98'
+ Goto lbl_done
+
+ lbl_win32_ME:
+ StrCpy $R0 'ME'
+ Goto lbl_done
+
+ lbl_winnt:
+
+ StrCpy $R1 $R0 1
+
+ StrCmp $R1 '3' lbl_winnt_x
+ StrCmp $R1 '4' lbl_winnt_x
+
+ StrCpy $R1 $R0 3
+
+ StrCmp $R1 '5.0' lbl_winnt_2000
+ StrCmp $R1 '5.1' lbl_winnt_XP
+ StrCmp $R1 '5.2' lbl_winnt_2003
+ StrCmp $R1 '6.0' lbl_winnt_vista
+ StrCmp $R1 '6.1' lbl_winnt_7 lbl_error
+
+ lbl_winnt_x:
+ StrCpy $R0 "NT $R0" 6
+ Goto lbl_done
+
+ lbl_winnt_2000:
+ Strcpy $R0 '2000'
+ Goto lbl_done
+
+ lbl_winnt_XP:
+ Strcpy $R0 'XP'
+ Goto lbl_done
+
+ lbl_winnt_2003:
+ Strcpy $R0 '2003'
+ Goto lbl_done
+
+ lbl_winnt_vista:
+ Strcpy $R0 'Vista'
+ Goto lbl_done
+
+ lbl_winnt_7:
+ Strcpy $R0 '7'
+ Goto lbl_done
+
+ lbl_error:
+ Strcpy $R0 ''
+ lbl_done:
+
+ Pop $R1
+ Exch $R0
+
+FunctionEnd
+!macroend
+!insertmacro GetWindowsVersion ""
+!insertmacro GetWindowsVersion "un."
diff --git a/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk
new file mode 100644
index 00000000000..c00e77d3663
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/Makefile.kmk
@@ -0,0 +1,20 @@
+# $Id$
+## @file
+# Sub-Makefile for the Windows guest shared folders.
+#
+
+#
+# Copyright (C) 2006-2007 Oracle Corporation
+#
+# Oracle Corporation confidential
+# All rights reserved
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# Include sub-makefile(s).
+include $(PATH_SUB_CURRENT)/redirector/Makefile.kmk
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk
new file mode 100644
index 00000000000..6d53a1a3491
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/Makefile.kmk
@@ -0,0 +1,21 @@
+# $Id$
+## @file
+# Sub-Makefile for the Windows guest shared folder redirectory.
+#
+
+#
+# Copyright (C) 2006-2007 Oracle Corporation
+#
+# Oracle Corporation confidential
+# All rights reserved
+#
+
+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
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk
new file mode 100644
index 00000000000..8a3a74f1f24
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/Makefile.kmk
@@ -0,0 +1,36 @@
+# $Id$
+## @file
+# Sub-Makefile for the VirtualBox Windows Guest Shared Folders Network Provider.
+#
+
+#
+# Copyright (C) 2006-2007 Oracle Corporation
+#
+# Oracle Corporation confidential
+# All rights reserved
+#
+
+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_INCS = \
+ $(PATH_SUB_ROOT)/WINNT/SharedFolders/include
+
+VBoxMRXNP_SOURCES = \
+ dllmain.cpp \
+ vboxmrxp.cpp \
+ vboxmrxp.rc \
+ vboxmrxp.def
+
+VBoxMRXNP_LIBS = \
+ $(VBOX_LIB_IPRT_GUEST_R3) \
+ $(VBOX_LIB_VBGL_R3) \
+ $(VBOX_LIB_IPRT_GUEST_R3)
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp
new file mode 100644
index 00000000000..a084acfc06f
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/dllmain.cpp
@@ -0,0 +1,63 @@
+/*++
+
+Copyright (c) 1989-1999 Microsoft Corporation
+
+Module Name:
+
+ dllmain.c
+
+Abstract:
+
+ This module implements the initialization routines for network
+ provider interface
+
+Notes:
+
+ This module has been built and tested only in UNICODE environment
+
+--*/
+
+#include <windows.h>
+#include <process.h>
+
+#include "vboxmrxp.h"
+
+// NOTE:
+//
+// Function: DllMain
+//
+// Return: TRUE => Success
+// FALSE => Failure
+
+BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
+{
+ BOOL bStatus = TRUE;
+
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+
+ RTR3Init();
+ 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(bStatus);
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp
new file mode 100644
index 00000000000..ffb1094ced4
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.cpp
@@ -0,0 +1,2146 @@
+/*++
+
+ Copyright (c) 1989-1999 Microsoft Corporation
+
+ Module Name:
+
+ ifsmrxnp.c
+
+ Abstract:
+
+ This module implements the routines required for interaction with network
+ provider router interface in NT
+
+ Notes:
+
+ This module has been built and tested only in UNICODE environment
+
+ --*/
+
+#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 "vboxmrxp.h"
+
+#define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor )
+
+ULONG SendToMiniRdr (IN ULONG IoctlCode, IN PVOID InputDataBuf, IN ULONG InputDataLen, IN PVOID OutputDataBuf, IN PULONG pOutputDataLen)
+/*++
+
+ Routine Description:
+
+ This routine sends a device ioctl to the Mini Rdr.
+
+ Arguments:
+
+ IoctlCode - Function code for the Mini Rdr driver
+
+ InputDataBuf - Input buffer pointer
+
+ InputDataLen - Lenth of the input buffer
+
+ OutputDataBuf - Output buffer pointer
+
+ pOutputDataLen - Pointer to the length of the output buffer
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ --*/
+{
+ HANDLE DeviceHandle; // The mini rdr device handle
+ BOOL rc;
+ ULONG Status;
+ DWORD cbOut = 0;
+
+ if (!pOutputDataLen)
+ pOutputDataLen = &cbOut;
+
+ Status = WN_SUCCESS;
+
+ // Grab a handle to the redirector device object
+
+ 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)
+ {
+ rc = DeviceIoControl(DeviceHandle, IoctlCode, InputDataBuf, InputDataLen, OutputDataBuf, *pOutputDataLen, pOutputDataLen, NULL );
+
+ if (!rc)
+ {
+ Status = GetLastError();
+ Log(("VBOXNP: SendToMiniRdr: Returning error from DeviceIoctl! Status = %d \n", Status));
+ }
+ else
+ {
+ Log(("VBOXNP: SendToMiniRdr: The DeviceIoctl call succeded\n"));
+ }
+ CloseHandle(DeviceHandle);
+ }
+ else
+ {
+ Status = GetLastError();
+ static int sLogged = 0;
+ if (!sLogged)
+ {
+ LogRel(("VBOXNP: SendToMiniRdr: Error opening device! Status = %lx\n", Status));
+ sLogged++;
+ }
+ }
+
+ return Status;
+}
+
+DWORD APIENTRY
+NPGetCaps (DWORD nIndex)
+/*++
+
+ Routine Description:
+
+ This routine returns the capaboilities of the Null Mini redirector
+ network provider implementation
+
+ Arguments:
+
+ nIndex - category of capabilities desired
+
+ Return Value:
+
+ the appropriate capabilities
+
+ --*/
+{
+ DWORD rc = 0;
+
+ Log(("VBOXNP: GetNetCaps: Index = 0x%lx\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:
+ SendToMiniRdr(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 = 1;
+ 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)
+/*++
+
+ Routine Description:
+
+ This routine handles the logon notifications
+
+ Arguments:
+
+ lpLogonId -- the associated LUID
+
+ lpAuthenInfoType - the authentication information type
+
+ lpAuthenInfo - the authentication Information
+
+ lpPreviousAuthentInfoType - the previous aunthentication information type
+
+ lpPreviousAuthentInfo - the previous authentication information
+
+ lpStationName - the logon station name
+
+ LPVOID - logon station handle
+
+ lpLogonScript - the logon script to be executed.
+
+ Return Value:
+
+ WN_SUCCESS
+
+ Notes:
+
+ This capability has not been implemented in the sample.
+
+ --*/
+{
+ Log(("VBOXNP: NPLogonNotify: Called.\n"));
+ *lpLogonScript = NULL;
+
+ return WN_SUCCESS;
+}
+
+DWORD APIENTRY
+NPPasswordChangeNotify (LPCWSTR lpAuthentInfoType,
+ LPVOID lpAuthentInfo,
+ LPCWSTR lpPreviousAuthentInfoType,
+ LPVOID lpPreviousAuthentInfo,
+ LPWSTR lpStationName,
+ LPVOID StationHandle,
+ DWORD dwChangeInfo)
+/*++
+
+ Routine Description:
+
+ This routine handles the password change notifications
+
+ Arguments:
+
+ lpAuthenInfoType - the authentication information type
+
+ lpAuthenInfo - the authentication Information
+
+ lpPreviousAuthentInfoType - the previous aunthentication information type
+
+ lpPreviousAuthentInfo - the previous authentication information
+
+ lpStationName - the logon station name
+
+ LPVOID - logon station handle
+
+ dwChangeInfo - the password change information.
+
+ Return Value:
+
+ WN_NOT_SUPPORTED
+
+ Notes:
+
+ This capability has not been implemented in the sample.
+
+ --*/
+{
+ Log(("VBOXNP: NPPasswordChangeNotify: Called.\n"));
+ SetLastError(WN_NOT_SUPPORTED);
+
+ return WN_NOT_SUPPORTED;
+}
+
+DWORD APIENTRY
+NPAddConnection (LPNETRESOURCE lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
+/*++
+
+ Routine Description:
+
+ This routine adds a connection to the list of connections associated
+ with this network provider
+
+ Arguments:
+
+ lpNetResource - the NETRESOURCE struct
+
+ lpPassword - the password
+
+ lpUserName - the user name
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ --*/
+{
+ Log(("VBOXNP: NPAddConnection: Called.\n"));
+ return NPAddConnection3(NULL, lpNetResource, lpPassword, lpUserName, 0);
+}
+
+DWORD APIENTRY
+NPAddConnection3 (HWND hwndOwner, LPNETRESOURCE lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
+/*++
+
+ Routine Description:
+
+ This routine adds a connection to the list of connections associated
+ with this network provider
+
+ Arguments:
+
+ hwndOwner - the owner handle
+
+ lpNetResource - the NETRESOURCE struct
+
+ lpPassword - the password
+
+ lpUserName - the user name
+
+ dwFlags - flags for the connection
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ --*/
+{
+ DWORD Status;
+ WCHAR ConnectionName[128];
+ WCHAR wszScratch[128];
+ WCHAR LocalName[3];
+ DWORD CopyBytes = 0;
+ 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 ));
+
+ Status = WN_SUCCESS;
+
+ if (lpNetResource->dwType != RESOURCETYPE_DISK && lpNetResource->dwType != RESOURCETYPE_ANY)
+ {
+ Log(("VBOXNP: NPAddConnection3: Incorrect net resource type %d\n", lpNetResource->dwType));
+ return WN_BAD_NETNAME;
+ }
+
+ // \device\miniredirector\;<DriveLetter>:\Server\Share
+
+ if (lpNetResource->lpLocalName == NULL)
+ {
+ fLocalName = FALSE;
+ lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U );
+ lstrcat(ConnectionName,L"\\;" );
+ }
+ else
+ if ( lstrlen( lpNetResource->lpLocalName )> 1 )
+ {
+ if ( lpNetResource->lpLocalName[1] == L':' )
+ {
+ // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpNetResource->lpLocalName[0], 0 ) );
+ LocalName[0] = (WCHAR) toupper(lpNetResource->lpLocalName[0]);
+ LocalName[1] = L':';
+ LocalName[2] = L'\0';
+ lstrcpy( ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U );
+ lstrcat( ConnectionName, L"\\;" );
+ lstrcat( ConnectionName, LocalName );
+ }
+ else
+ Status = WN_BAD_LOCALNAME;
+ }
+ else
+ Status = WN_BAD_LOCALNAME;
+
+ // format proper server name
+ if ( lpNetResource->lpRemoteName[0] == L'\\' && lpNetResource->lpRemoteName[1] == L'\\' )
+ {
+ if (lstrlen (ConnectionName) + lstrlen (lpNetResource->lpRemoteName) <= sizeof (ConnectionName) / sizeof (WCHAR))
+ {
+ /* No need for (lstrlen + 1), because 'lpNetResource->lpRemoteName' leading \ is not copied. */
+ lstrcat( ConnectionName, lpNetResource->lpRemoteName + 1 );
+ }
+ else
+ {
+ Status = WN_BAD_NETNAME;
+ }
+ }
+ else
+ {
+ Status = WN_BAD_NETNAME;
+ }
+
+ Log(("VBOXNP: NPAddConnection3: Full Connect Name: %ls\n", ConnectionName ));
+ Log(("VBOXNP: NPAddConnection3: Full Connect Name Length: %d\n", ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ) ));
+
+ if ( Status == WN_SUCCESS )
+ {
+ if ( fLocalName
+ && QueryDosDevice( LocalName, wszScratch, sizeof (wszScratch) / sizeof (WCHAR) ))
+ {
+ Log(("VBOXNP: NPAddConnection3: Connection \"%ls\" already connected.\n", ConnectionName));
+ Status = WN_ALREADY_CONNECTED;
+ }
+ else
+ if ( !fLocalName
+ || GetLastError() == ERROR_FILE_NOT_FOUND)
+ {
+ Status = SendToMiniRdr( IOCTL_MRX_VBOX_ADDCONN, ConnectionName,
+ ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ),
+ NULL, &CopyBytes );
+
+ if (Status == WN_SUCCESS)
+ {
+ if ( fLocalName
+ && !DefineDosDevice( DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM,
+ lpNetResource->lpLocalName,
+ ConnectionName ) )
+ {
+ Status = GetLastError();
+ }
+ }
+ else Status = WN_BAD_NETNAME;
+ }
+ else Status = WN_ALREADY_CONNECTED;
+ }
+
+ Log(("VBOXNP: NPAddConnection3: Returned 0x%lx\n", Status));
+ return Status;
+}
+
+DWORD APIENTRY
+NPCancelConnection (LPWSTR lpName, BOOL fForce)
+/*++
+
+ Routine Description:
+
+ This routine cancels ( deletes ) a connection from the list of connections
+ associated with this network provider
+
+ Arguments:
+
+ lpName - name of the connection
+
+ fForce - forcefully delete the connection
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ --*/
+
+{
+ WCHAR LocalName[3];
+ WCHAR RemoteName[128];
+ WCHAR ConnectionName[128];
+ ULONG CopyBytes;
+ DWORD Status = WN_NOT_CONNECTED;
+
+ Log(("VBOXNP: NPCancelConnection: Name = %ls\n", lpName ));
+
+ if (lstrlen(lpName) > 1)
+ {
+ if (lpName[1] == L':')
+ {
+ // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpName[0], 0 ) );
+ LocalName[0] = (WCHAR)toupper(lpName[0]);
+ LocalName[1] = L':';
+ LocalName[2] = L'\0';
+
+ CopyBytes = sizeof (RemoteName) - sizeof (WCHAR); /* Trailing NULL. */
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, LocalName, sizeof(LocalName), (PVOID)RemoteName, &CopyBytes);
+ if (Status == WN_SUCCESS && CopyBytes > 0)
+ {
+ RemoteName[CopyBytes] = L'\0';
+
+ if (lstrlen (DD_MRX_VBOX_FS_DEVICE_NAME_U) + 2 + lstrlen (LocalName) + lstrlen (RemoteName) + 1 > sizeof (ConnectionName) / sizeof (WCHAR))
+ {
+ return WN_BAD_NETNAME;
+ }
+
+ lstrcpy(ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U );
+ lstrcat(ConnectionName,L"\\;" );
+ lstrcat( ConnectionName, LocalName );
+ lstrcat( ConnectionName, RemoteName );
+ CopyBytes = 0;
+ Status = SendToMiniRdr( IOCTL_MRX_VBOX_DELCONN, ConnectionName,
+ ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ),
+ NULL, &CopyBytes );
+ if ( Status == WN_SUCCESS )
+ {
+ if ( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
+ LocalName,
+ ConnectionName ) )
+ {
+ Status = GetLastError( );
+ }
+ }
+ }
+ else
+ {
+ Status = 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))
+ {
+ return WN_BAD_NETNAME;
+ }
+
+ lstrcpy( ConnectionName, DD_MRX_VBOX_FS_DEVICE_NAME_U );
+ lstrcat( ConnectionName, L"\\;" );
+ lstrcat( ConnectionName, lpName );
+ CopyBytes = 0;
+ Status = SendToMiniRdr( IOCTL_MRX_VBOX_DELCONN, ConnectionName,
+ ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ),
+ NULL, &CopyBytes );
+ }
+ else
+ Status = WN_NOT_CONNECTED;
+ }
+ }
+
+ Log(("VBOXNP: NPCancelConnection: Returned 0x%lx\n", Status));
+ return Status;
+}
+
+DWORD APIENTRY
+NPGetConnection (LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpBufferSize)
+/*++
+
+ Routine Description:
+
+ This routine returns the information associated with a connection
+
+ Arguments:
+
+ lpLocalName - local name associated with the connection
+
+ lpRemoteName - the remote name associated with the connection
+
+ lpBufferSize - the remote name buffer size
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ --*/
+{
+ DWORD Status, len;
+ ULONG CopyBytes;
+ WCHAR RemoteName[128];
+ WCHAR LocalName[3];
+
+ Status = WN_NOT_CONNECTED;
+
+ Log(("VBOXNP: NPGetConnection: Called\n" ));
+ Log(("VBOXNP: NPGetConnection: lpLocalName = %ls\n", lpLocalName));
+
+ if (lstrlen(lpLocalName) > 1)
+ {
+ if (lpLocalName[1] == L':')
+ {
+ CopyBytes = sizeof (RemoteName) - sizeof (WCHAR);
+ RemoteName[CopyBytes / sizeof (WCHAR)] = 0;
+ // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpLocalName[0], 0 ) );
+ LocalName[0] = (WCHAR)toupper(lpLocalName[0]);
+ LocalName[1] = L':';
+ LocalName[2] = L'\0';
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, LocalName, 3 * sizeof(WCHAR), (PVOID)RemoteName, &CopyBytes);
+ if (Status != NO_ERROR)
+ {
+ /* The device specified by lpLocalName is not redirected by this provider. */
+ Status = WN_NOT_CONNECTED;
+ }
+ }
+ }
+ if (Status == WN_SUCCESS)
+ {
+ if (CopyBytes > 0)
+ {
+ /* Return the local name (X:) instead of UNC path \\VBOXSVR\folder to prevent
+ * VBOXSVR name resolutions and therefore large delays.
+ */
+
+ Log(("VBOXNP: NPGetConnection: CopyBytes: %d, RemoteName: %ls\n", CopyBytes, RemoteName));
+
+ CopyBytes = (lstrlen (RemoteName) + 1) * sizeof (WCHAR); /* Including the trailing 0. */
+
+ len = sizeof(WCHAR) + CopyBytes; /* Including the leading '\'. */
+
+ if (*lpBufferSize >= len)
+ {
+ lpRemoteName[0] = L'\\';
+ CopyMemory( &lpRemoteName[1], RemoteName, CopyBytes );
+
+ 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));
+ }
+
+ Status = WN_MORE_DATA;
+ }
+
+ *lpBufferSize = len;
+ }
+ else
+ {
+ Status = WN_NO_NETWORK;
+ }
+ }
+
+ if ((Status != WN_SUCCESS) &&
+ (Status != WN_MORE_DATA))
+ {
+ Log(("VBOXNP: NPGetConnection: Returned error 0x%lx\n", Status));
+ }
+
+ return Status;
+}
+
+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 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;
+}
+
+#define NEWENUM
+
+#ifdef NEWENUM
+/* 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)
+/*++
+
+ Routine Description:
+
+ This routine opens a handle for enumeration of resources.
+
+ Arguments:
+
+ dwScope - the scope of enumeration (RESOURCE_CONNECTED, RESOURCE_GLOBALNET or RESOURCE_CONTEXT)
+
+ dwType - the type of resources to be enumerated (RESOURCETYPE_DISK only supported)
+
+ dwUsage - the usage parameter (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER, or zero to match all the flags)
+
+ lpNetResource - pointer to the container to perform the enumeration.
+ If dwScope is RESOURCE_CONNECTED or RESOURCE_CONTEXT, this parameter will be NULL.
+
+ lphEnum - aptr. for passing nack the enumeration handle
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ --*/
+{
+ DWORD Status;
+
+ 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)
+ {
+ Status = 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.
+ */
+ Status = WN_NOT_CONTAINER;
+ break;
+ }
+
+ const WCHAR *lpAfterName = vboxSkipServerName(lpNetResource->lpRemoteName);
+ if ( lpAfterName == NULL
+ || (*lpAfterName != L'\\' && *lpAfterName != 0))
+ {
+ Status = WN_NOT_CONTAINER;
+ break;
+ }
+
+ /* Valid server name. */
+
+ pCtx->index = 0;
+ pCtx->dwScope = 6;
+ pCtx->dwOriginalScope = dwScope;
+ pCtx->dwType = dwType;
+ pCtx->dwUsage = dwUsage;
+
+ Status = 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))
+ {
+ Status = 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;
+
+ Status = 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. */
+
+ Status = WN_SUCCESS;
+ break;
+ }
+
+ default:
+ Log(("VBOXNP: NPOpenEnum: unsupported scope 0x%lx\n", dwScope));
+ Status = WN_NOT_SUPPORTED;
+ break;
+ }
+ }
+
+ if (Status != WN_SUCCESS)
+ {
+ Log(("VBOXNP: NPOpenEnum: Returned error 0x%lx\n", Status));
+ if (pCtx)
+ {
+ HeapFree(GetProcessHeap(), 0, pCtx);
+ }
+ }
+ else
+ {
+ Log(("VBOXNP: NPOpenEnum: pCtx %p\n", pCtx));
+ *lphEnum = pCtx;
+ }
+
+ return (Status);
+}
+
+DWORD APIENTRY
+NPEnumResource (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
+/*++
+
+ Routine Description:
+
+ This routine uses the handle obtained by a call to NPOpenEnum for
+ enuerating the connected shares
+
+ Arguments:
+
+ hEnum - the enumeration handle
+
+ lpcCount - the number of resources requested/returned
+
+ lpBuffer - the buffer for passing back the NETRESOURCE entries
+
+ lpBufferSize - the size of the buffer
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries
+
+ WN_MORE_DATA - if more data is available
+
+ --*/
+{
+ DWORD Status = WN_SUCCESS;
+ NPENUMCTX *pCtx = (NPENUMCTX *)hEnum;
+
+ BYTE ConnectionList[26];
+ ULONG CopyBytes;
+ WCHAR LocalName[3];
+ WCHAR RemoteName[128];
+
+ ULONG SpaceNeeded;
+
+ 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 SpaceAvailable = *lpBufferSize;
+ ULONG EntriesCopied = 0;
+ PWCHAR StringZone = (PWCHAR)((PBYTE)lpBuffer + *lpBufferSize);
+
+ if (pCtx->dwScope == RESOURCE_CONNECTED)
+ {
+ Log(("VBOXNP: NPEnumResource: RESOURCE_CONNECTED\n"));
+
+ memset (ConnectionList, 0, sizeof (ConnectionList));
+ CopyBytes = sizeof(ConnectionList);
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETLIST, NULL, 0, ConnectionList, &CopyBytes);
+
+ if (Status == WN_SUCCESS && CopyBytes > 0)
+ {
+ while (EntriesCopied < *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));
+ CopyBytes = sizeof(RemoteName);
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, LocalName, sizeof(LocalName), RemoteName, &CopyBytes);
+
+ if (Status != WN_SUCCESS || CopyBytes == 0)
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ break;
+ }
+
+ // Determine the space needed for this entry...
+ SpaceNeeded = sizeof(NETRESOURCE); // resource struct
+ SpaceNeeded += 3 * sizeof(WCHAR); // local name
+ SpaceNeeded += 2 * sizeof(WCHAR) + CopyBytes; // remote name: \ + name + 0
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name
+
+ if (SpaceNeeded > SpaceAvailable)
+ {
+ break;
+ }
+
+ SpaceAvailable -= SpaceNeeded;
+
+ pNetResource->dwScope = RESOURCE_CONNECTED;
+ pNetResource->dwType = RESOURCETYPE_DISK;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+ // setup string area at opposite end of buffer
+ SpaceNeeded -= sizeof(NETRESOURCE);
+ StringZone = (PWCHAR)((PBYTE)StringZone - SpaceNeeded);
+ PWCHAR NewStringZone = StringZone;
+ // copy local name
+ pNetResource->lpLocalName = StringZone;
+ *StringZone++ = L'A' + (WCHAR)pCtx->index;
+ *StringZone++ = L':';
+ *StringZone++ = L'\0';
+ // copy remote name
+ pNetResource->lpRemoteName = StringZone;
+ *StringZone++ = L'\\';
+ CopyMemory( StringZone, RemoteName, CopyBytes );
+ StringZone += CopyBytes / sizeof(WCHAR);
+ *StringZone++ = L'\0';
+ // copy comment
+ pNetResource->lpComment = 0;
+ // copy provider name
+ pNetResource->lpProvider = StringZone;
+ CopyMemory(StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof (MRX_VBOX_PROVIDER_NAME_U));
+
+ EntriesCopied++;
+
+ // set new bottom of string zone
+ StringZone = NewStringZone;
+ Log(("VBOXNP: NPEnumResource: lpRemoteName: %ls\n", pNetResource->lpRemoteName));
+
+ pNetResource++;
+ }
+
+ pCtx->index++;
+ }
+ }
+ else
+ {
+ Status = 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)
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ else
+ {
+ /* Return VBOXSVR server.
+ * Determine the space needed for this entry.
+ */
+ SpaceNeeded = sizeof(NETRESOURCE);
+ SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name */
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+ if (SpaceNeeded > SpaceAvailable)
+ {
+ /* Do nothing. */
+ }
+ else
+ {
+ SpaceAvailable -= SpaceNeeded;
+
+ memset (pNetResource, 0, sizeof (*pNetResource));
+
+ pNetResource->dwScope = RESOURCE_GLOBALNET;
+ pNetResource->dwType = RESOURCETYPE_ANY;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
+
+ // setup string area at opposite end of buffer
+ SpaceNeeded -= sizeof(NETRESOURCE);
+ StringZone = (PWCHAR)((PBYTE)StringZone - SpaceNeeded);
+ // local name
+ pNetResource->lpLocalName = 0;
+ // remote name
+ pNetResource->lpRemoteName = StringZone;
+ *StringZone++ = L'\\';
+ *StringZone++ = L'\\';
+ CopyMemory( StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) );
+ StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR);
+ // comment
+ pNetResource->lpComment = 0;
+ // provider name
+ pNetResource->lpProvider = StringZone;
+ CopyMemory(StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof (MRX_VBOX_PROVIDER_NAME_U));
+
+ EntriesCopied++;
+
+ pCtx->index++;
+ }
+ }
+ }
+ else
+ {
+ /* Shares of VBOXSVR. */
+ memset (ConnectionList, 0, sizeof (ConnectionList));
+ CopyBytes = sizeof(ConnectionList);
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, ConnectionList, &CopyBytes);
+
+ if (Status == WN_SUCCESS && CopyBytes > 0)
+ {
+ while (EntriesCopied < *lpcCount && pCtx->index < RTL_NUMBER_OF(ConnectionList))
+ {
+ if (ConnectionList[pCtx->index])
+ {
+ memset (RemoteName, 0, sizeof (RemoteName));
+ CopyBytes = sizeof(RemoteName);
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALCONN, &ConnectionList[pCtx->index], sizeof(ConnectionList[pCtx->index]), RemoteName, &CopyBytes);
+
+ if (Status != WN_SUCCESS || CopyBytes == 0)
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ break;
+ }
+
+ // Determine the space needed for this entry...
+ SpaceNeeded = sizeof(NETRESOURCE); // resource struct
+ SpaceNeeded += 3 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U) + CopyBytes; /* remote name: \\ + vboxsvr + \ + name + 0. */
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name
+
+ if (SpaceNeeded > SpaceAvailable)
+ {
+ break;
+ }
+
+ SpaceAvailable -= SpaceNeeded;
+
+ pNetResource->dwScope = pCtx->dwOriginalScope;
+ pNetResource->dwType = RESOURCETYPE_DISK;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+ // setup string area at opposite end of buffer
+ SpaceNeeded -= sizeof(NETRESOURCE);
+ StringZone = (PWCHAR)((PBYTE)StringZone - SpaceNeeded);
+ PWCHAR NewStringZone = StringZone;
+ // copy local name
+ pNetResource->lpLocalName = 0;
+ // copy remote name
+ pNetResource->lpRemoteName = StringZone;
+ *StringZone++ = L'\\';
+ *StringZone++ = L'\\';
+ lstrcpy(StringZone, MRX_VBOX_SERVER_NAME_U );
+ StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
+ *StringZone++ = L'\\';
+ CopyMemory( StringZone, RemoteName, CopyBytes );
+ StringZone += CopyBytes / sizeof(WCHAR);
+ *StringZone++ = L'\0';
+ // copy comment
+ pNetResource->lpComment = 0;
+ // copy provider name
+ pNetResource->lpProvider = StringZone;
+ CopyMemory(StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof (MRX_VBOX_PROVIDER_NAME_U));
+
+ EntriesCopied++;
+
+ // set new bottom of string zone
+ StringZone = NewStringZone;
+ Log(("VBOXNP: NPEnumResource: lpRemoteName: %ls\n", pNetResource->lpRemoteName));
+
+ pNetResource++;
+ }
+
+ pCtx->index++;
+ }
+ }
+ else
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ }
+ }
+ else if (pCtx->dwScope == 6)
+ {
+ Log(("VBOXNP: NPEnumResource: dwScope 6\n"));
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ else
+ {
+ Log(("VBOXNP: NPEnumResource: invalid dwScope 0x%x\n", pCtx->dwScope));
+ return WN_BAD_HANDLE;
+ }
+
+ *lpcCount = EntriesCopied;
+
+ if (EntriesCopied == 0 && Status == WN_SUCCESS)
+ {
+ if (pCtx->index >= RTL_NUMBER_OF(ConnectionList))
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ else
+ {
+ Log(("VBOXNP: NPEnumResource: More Data Needed - %d\n", SpaceNeeded));
+ *lpBufferSize = SpaceNeeded;
+ Status = WN_MORE_DATA;
+ }
+ }
+
+ Log(("VBOXNP: NPEnumResource: Entries returned - %d, Status %d\n", EntriesCopied, Status));
+ return Status;
+}
+DWORD APIENTRY
+NPCloseEnum (HANDLE hEnum)
+/*++
+
+ Routine Description:
+
+ This routine closes the handle for enumeration of resources.
+
+ Arguments:
+
+ hEnum - the enumeration handle
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ --*/
+{
+ DWORD Status = 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;
+}
+#else
+DWORD APIENTRY
+NPOpenEnum (DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum)
+/*++
+
+ Routine Description:
+
+ This routine opens a handle for enumeration of resources. The only capability
+ implemented in the sample is for enumerating connected shares
+
+ Arguments:
+
+ dwScope - the scope of enumeration
+
+ dwType - the type of resources to be enumerated
+
+ dwUsage - the usage parameter
+
+ lpNetResource - a pointer to the desired NETRESOURCE struct.
+
+ lphEnum - aptr. for passing nack the enumeration handle
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ The sample only supports the notion of enumerating connected shares
+
+ The handle passed back is merely the index of the last entry returned
+
+ --*/
+{
+ DWORD Status;
+
+ Log(("VBOXNP: NPOpenEnum: Called.\n"));
+
+ *lphEnum = NULL;
+
+ switch (dwScope)
+ {
+ case RESOURCE_GLOBALNET:
+ case RESOURCE_CONNECTED:
+ {
+ DWORD *lpdwEnum = NULL;
+ lpdwEnum = (DWORD *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DWORD) * 2);
+
+ if (lpdwEnum != NULL)
+ {
+ lpdwEnum[0] = 0;
+ lpdwEnum[1] = dwScope;
+ *lphEnum = lpdwEnum;
+
+ Status = WN_SUCCESS;
+ }
+ else
+ {
+ Status = WN_OUT_OF_MEMORY;
+ }
+ break;
+ }
+ break;
+
+ case RESOURCE_CONTEXT:
+ default:
+ Status = WN_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Status != WN_SUCCESS)
+ Log(("VBOXNP: NPOpenEnum: Returned error 0x%lx\n", Status));
+
+ return (Status);
+}
+
+DWORD APIENTRY
+NPEnumResource (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
+/*++
+
+ Routine Description:
+
+ This routine uses the handle obtained by a call to NPOpenEnum for
+ enuerating the connected shares
+
+ Arguments:
+
+ hEnum - the enumeration handle
+
+ lpcCount - the number of resources returned
+
+ lpBuffer - the buffere for passing back the entries
+
+ lpBufferSize - the size of the buffer
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries
+
+ WN_MORE_DATA - if nmore data is available
+
+ Notes:
+
+ The sample only supports the notion of enumerating connected shares
+
+ The handle passed back is merely the index of the last entry returned
+
+ --*/
+{
+ DWORD Status = WN_SUCCESS;
+ BYTE byConnectionList[26];
+ ULONG CopyBytes;
+ ULONG EntriesCopied;
+ ULONG i;
+ LPNETRESOURCE pNetResource;
+ ULONG SpaceNeeded;
+ ULONG SpaceAvailable;
+ WCHAR wzLocalName[3];
+ WCHAR wzRemoteName[128];
+ PWCHAR pwcStringZone;
+ DWORD dwScope = 0;
+
+ Log(("VBOXNP: NPEnumResource: Called.\n"));
+
+ if ((lpcCount == NULL) || (lpBufferSize == NULL) || (lpBuffer == NULL))
+ {
+ Log(("VBOXNP: NPEnumResource: Has invalid parameter(s)!\n"));
+ return WN_NO_MORE_ENTRIES;
+ }
+
+ if (hEnum != NULL)
+ dwScope = ((DWORD*)hEnum)[1];
+
+ Log(("VBOXNP: NPEnumResource: Count Requested %d\n", *lpcCount));
+ Log(("VBOXNP: NPEnumResource: Scope %ld\n", dwScope));
+
+ pNetResource = (LPNETRESOURCE)lpBuffer;
+ SpaceAvailable = *lpBufferSize;
+ EntriesCopied = 0;
+ pwcStringZone = (PWCHAR)((PBYTE)lpBuffer + *lpBufferSize);
+
+ /*
+ * Returns the already connected resources of each driver letter (A-Z).
+ */
+ if (dwScope == RESOURCE_CONNECTED)
+ {
+ Log(("VBOXNP: NPEnumResource: Scope = Resource connected.\n"));
+
+ CopyBytes = 26;
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETLIST, NULL, 0, (PVOID)byConnectionList, &CopyBytes);
+
+ if (Status == WN_SUCCESS && CopyBytes > 0)
+ {
+ for (i = *((PULONG)hEnum); EntriesCopied < *lpcCount, i < 26; i++)
+ {
+ if (byConnectionList[i])
+ {
+ CopyBytes = 128;
+ wzLocalName[0] = L'A' + (WCHAR)i;
+ wzLocalName[1] = L':';
+ wzLocalName[2] = L'\0';
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETCONN, wzLocalName, 3 * sizeof(WCHAR), (PVOID)wzRemoteName, &CopyBytes);
+
+ // if something strange happended then just say there are no more entries
+ if (Status != WN_SUCCESS || CopyBytes == 0)
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ break;
+ }
+ // Determine the space needed for this entry...
+
+ SpaceNeeded = sizeof(NETRESOURCE); // resource struct
+ SpaceNeeded += 3 * sizeof(WCHAR); // local name
+ SpaceNeeded += 2 * sizeof(WCHAR) + CopyBytes; // remote name
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name
+
+ if (SpaceNeeded > SpaceAvailable)
+ {
+ break;
+ }
+ else
+ {
+ SpaceAvailable -= SpaceNeeded;
+
+ pNetResource->dwScope = RESOURCE_CONNECTED;
+ pNetResource->dwType = RESOURCETYPE_DISK;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ pNetResource->dwUsage = 0;
+
+ // setup string area at opposite end of buffer
+ SpaceNeeded -= sizeof(NETRESOURCE);
+ pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded);
+ // copy local name
+ pNetResource->lpLocalName = pwcStringZone;
+ *pwcStringZone++ = L'A' + (WCHAR)i;
+ *pwcStringZone++ = L':';
+ *pwcStringZone++ = L'\0';
+ // copy remote name
+ pNetResource->lpRemoteName = pwcStringZone;
+ *pwcStringZone++ = L'\\';
+ CopyMemory( pwcStringZone, wzRemoteName, CopyBytes );
+ pwcStringZone += CopyBytes / sizeof(WCHAR);
+ *pwcStringZone++ = L'\0';
+ // copy comment
+ pNetResource->lpComment = 0;
+ // copy provider name
+ pNetResource->lpProvider = pwcStringZone;
+ lstrcpy(pwcStringZone, MRX_VBOX_PROVIDER_NAME_U );
+
+ EntriesCopied++;
+ // set new bottom of string zone
+ pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded);
+ }
+ pNetResource++;
+ }
+ }
+ }
+ else
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ }
+ else if (dwScope == RESOURCE_GLOBALNET)
+ {
+ Log(("VBOXNP: NPEnumResource: Scope = Resource global net.\n"));
+
+ CopyBytes = 26;
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, (PVOID)byConnectionList, &CopyBytes);
+
+ if (Status == WN_SUCCESS && CopyBytes > 0)
+ {
+ for (i = *((PULONG)hEnum); EntriesCopied < *lpcCount, i < 26; i++)
+ {
+ if (byConnectionList[i])
+ {
+ CopyBytes = 128;
+
+ Status = SendToMiniRdr(IOCTL_MRX_VBOX_GETGLOBALCONN, &byConnectionList[i], sizeof(byConnectionList[i]), (PVOID)wzRemoteName, &CopyBytes);
+
+ // if something strange happended then just say there are no more entries
+ if (Status != WN_SUCCESS || CopyBytes == 0)
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ break;
+ }
+ // Determine the space needed for this entry...
+
+ SpaceNeeded = sizeof(NETRESOURCE); // resource struct
+ SpaceNeeded += 11 * sizeof(WCHAR) + CopyBytes; // remote name
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); // provider name
+
+ if (SpaceNeeded > SpaceAvailable)
+ {
+ break;
+ }
+ else
+ {
+ SpaceAvailable -= SpaceNeeded;
+
+ pNetResource->dwScope = RESOURCE_GLOBALNET;
+ pNetResource->dwType = RESOURCETYPE_DISK;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+ // setup string area at opposite end of buffer
+ SpaceNeeded -= sizeof(NETRESOURCE);
+ pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded);
+ // copy local name
+ pNetResource->lpLocalName = 0;
+ // copy remote name
+ pNetResource->lpRemoteName = pwcStringZone;
+ *pwcStringZone++ = L'\\';
+ *pwcStringZone++ = L'\\';
+ *pwcStringZone++ = L'V';
+ *pwcStringZone++ = L'B';
+ *pwcStringZone++ = L'O';
+ *pwcStringZone++ = L'X';
+ *pwcStringZone++ = L'S';
+ *pwcStringZone++ = L'V';
+ *pwcStringZone++ = L'R';
+ *pwcStringZone++ = L'\\';
+ CopyMemory( pwcStringZone, wzRemoteName, CopyBytes );
+ pwcStringZone += CopyBytes / sizeof(WCHAR);
+ *pwcStringZone++ = L'\0';
+ // copy comment
+ pNetResource->lpComment = 0;
+ // copy provider name
+ pNetResource->lpProvider = pwcStringZone;
+ lstrcpy(pwcStringZone, MRX_VBOX_PROVIDER_NAME_U );
+
+ EntriesCopied++;
+ // set new bottom of string zone
+ pwcStringZone = (PWCHAR)((PBYTE)pwcStringZone - SpaceNeeded);
+ Log(("VBOXNP: NPEnumResource: StringZone: %ls\n", pwcStringZone));
+ }
+ pNetResource++;
+ }
+ }
+ }
+ else
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ }
+ else return WN_NO_MORE_ENTRIES;
+
+ *lpcCount = EntriesCopied;
+ if (EntriesCopied == 0 && Status == WN_SUCCESS)
+ {
+ if (i > 25)
+ {
+ Status = WN_NO_MORE_ENTRIES;
+ }
+ else
+ {
+ Log(("VBOXNP: NPEnumResource: More Data Needed - %d\n", SpaceNeeded));
+ Status = WN_MORE_DATA;
+ *lpBufferSize = SpaceNeeded;
+ }
+ }
+ // update entry index
+ *(PULONG)hEnum = i;
+
+ Log(("VBOXNP: NPEnumResource: Entries returned - %d\n", EntriesCopied));
+
+ return Status;
+}
+
+DWORD APIENTRY
+NPCloseEnum (HANDLE hEnum)
+/*++
+
+ Routine Description:
+
+ This routine closes the handle for enumeration of resources.
+
+ Arguments:
+
+ hEnum - the enumeration handle
+
+ Return Value:
+
+ WN_SUCCESS if successful, otherwise the appropriate error
+
+ Notes:
+
+ The sample only supports the notion of enumerating connected shares
+
+ --*/
+{
+ Log(("VBOXNP: NPCloseEnum: Called.\n"));
+
+ if (NULL != (PVOID)hEnum)
+ HeapFree(GetProcessHeap(), 0, (PVOID)hEnum);
+
+ Log(("VBOXNP: NPCloseEnum: Memory freed.\n"));
+ return WN_SUCCESS;
+}
+#endif
+
+DWORD APIENTRY
+NPGetResourceParent (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize)
+/*++
+
+ Routine Description:
+
+ This routine returns the information about net resource parent
+
+ Arguments:
+
+ lpNetResource - the NETRESOURCE struct
+
+ lpBuffer - the buffer for passing back the parent information
+
+ lpBufferSize - the buffer size
+
+ Return Value:
+
+ Notes:
+
+ --*/
+{
+ Log(("VBOXNP: NPGetResourceParent: lpNetResource %p, lpBuffer %p, lpBufferSize %p\n",
+ lpNetResource, lpBuffer, lpBufferSize));
+ /* Contruct 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 SpaceNeeded = sizeof (NETRESOURCE);
+ SpaceNeeded += (RemoteNameLength + 1) * sizeof (WCHAR);
+
+ NETRESOURCE *pParent = (NETRESOURCE *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SpaceNeeded);
+
+ 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 Status = WN_SUCCESS;
+
+ if ( pLastSlash == pParent->lpRemoteName
+ || pLastSlash == pParent->lpRemoteName + 1)
+ {
+ /* It is a leading backslash. Construct "no parent" NETRESOURCE. */
+ NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer;
+
+ SpaceNeeded = sizeof(NETRESOURCE);
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* remote name */
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+ if (SpaceNeeded > *lpBufferSize)
+ {
+ Log(("VBOXNP: NPGetResourceParent: WN_MORE_DATA 0x%x\n", SpaceNeeded));
+ *lpBufferSize = SpaceNeeded;
+ Status = WN_MORE_DATA;
+ }
+ else
+ {
+ memset (pNetResource, 0, sizeof (*pNetResource));
+
+ pNetResource->dwType = RESOURCETYPE_ANY;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
+
+ /* Setup string area at opposite end of buffer. */
+ WCHAR *StringZone = (WCHAR *)((PBYTE)lpBuffer + *lpBufferSize);
+ StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE)));
+
+ pNetResource->lpRemoteName = StringZone;
+ CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+ StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+ /* Provider. */
+ pNetResource->lpProvider = StringZone;
+ CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+ StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+ Log(("VBOXNP: NPGetResourceParent: no parent, strings %p/%p\n",
+ StringZone, (PBYTE)lpBuffer + *lpBufferSize));
+ }
+ }
+ else
+ {
+ /* Make the parent remote name and get its information. */
+ *pLastSlash = 0;
+
+ LPWSTR lpSystem = NULL;
+ Status = NPGetResourceInformation (pParent, lpBuffer, lpBufferSize, &lpSystem);
+ }
+
+ if (pParent)
+ {
+ HeapFree(GetProcessHeap(), 0, pParent);
+ }
+ return Status;
+}
+
+DWORD APIENTRY
+NPGetResourceInformation (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize, LPWSTR *lplpSystem)
+/*
+
+ Routine Description:
+
+ Separates the part of a network resource accessed through the WNet API from the part accessed
+ through APIs specific to the resource type.
+
+ Arguments:
+
+ lpNetResource - network resource for which information is required.
+ The lpRemoteName field specifies the remote name of the resource.
+
+ lpBuffer - a single NETRESOURCE structure and associated strings. The lpRemoteName field should be
+ returned in the same format as that returned from an enumeration by the NPEnumResource
+ function, so that the caller can perform a case-sensitive string comparison.
+
+ lpBufferSize - the buffer size. If the buffer is too small for the result, the function places the
+ required buffer size at this location and returns the error WN_MORE_DATA.
+
+ lplpSystem - On a successful return, a pointer to a null-terminated string in the output buffer
+ specifying that part of the resource that is accessed through system APIs specific
+ to the resource type, rather than through the WNet API. If there is no such part,
+ lplpSystem is set to NULL.
+
+ */
+{
+ 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 SpaceNeeded;
+ WCHAR *StringZone = (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\" */
+ SpaceNeeded = sizeof(NETRESOURCE);
+ SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name */
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+ if (SpaceNeeded > *lpBufferSize)
+ {
+ Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", SpaceNeeded));
+ *lpBufferSize = SpaceNeeded;
+ return WN_MORE_DATA;
+ }
+
+ memset (pNetResource, 0, sizeof (*pNetResource));
+
+ pNetResource->dwType = RESOURCETYPE_ANY;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
+
+ /* Setup string area at opposite end of buffer. */
+ StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE)));
+
+ /* The remote name is the server. */
+ pNetResource->lpRemoteName = StringZone;
+ *StringZone++ = L'\\';
+ *StringZone++ = L'\\';
+ CopyMemory (StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U));
+ StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR);
+
+ /* Provider. */
+ pNetResource->lpProvider = StringZone;
+ CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+ StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+ Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n",
+ pNetResource->lpRemoteName, StringZone, (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 */
+ SpaceNeeded = sizeof(NETRESOURCE);
+ SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */
+ SpaceNeeded += (lp - lpAfterName) * sizeof(WCHAR); /* The share name with leading \\ */
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+
+ if (SpaceNeeded > *lpBufferSize)
+ {
+ Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", SpaceNeeded));
+ *lpBufferSize = SpaceNeeded;
+ return WN_MORE_DATA;
+ }
+
+ memset (pNetResource, 0, sizeof (*pNetResource));
+
+ pNetResource->dwType = RESOURCETYPE_DISK;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+ /* Setup string area at opposite end of buffer. */
+ StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE)));
+
+ /* The remote name is the server + share. */
+ pNetResource->lpRemoteName = StringZone;
+ *StringZone++ = L'\\';
+ *StringZone++ = L'\\';
+ CopyMemory (StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR));
+ StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
+ CopyMemory (StringZone, lpAfterName, (lp - lpAfterName + 1) * sizeof(WCHAR));
+ StringZone += lp - lpAfterName + 1;
+
+ /* Provider. */
+ pNetResource->lpProvider = StringZone;
+ CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+ StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+ Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n",
+ pNetResource->lpRemoteName, StringZone, (PBYTE)lpBuffer + *lpBufferSize));
+
+ if (lplpSystem)
+ {
+ *lplpSystem = NULL;
+ }
+ return WN_SUCCESS;
+ }
+
+ /* \\vboxsvr\share\path */
+ SpaceNeeded = sizeof(NETRESOURCE);
+ SpaceNeeded += 2 * sizeof(WCHAR) + sizeof(MRX_VBOX_SERVER_NAME_U); /* \\ + server name with trailing nul */
+ SpaceNeeded += (lp - lpAfterName) * sizeof(WCHAR); /* The share name with leading \\ */
+ SpaceNeeded += sizeof(MRX_VBOX_PROVIDER_NAME_U); /* provider name */
+ SpaceNeeded += (lstrlen(lp) + 1) * sizeof (WCHAR); /* path string for lplpSystem */
+
+ if (SpaceNeeded > *lpBufferSize)
+ {
+ Log(("VBOXNP: NPGetResourceInformation: WN_MORE_DATA 0x%x\n", SpaceNeeded));
+ *lpBufferSize = SpaceNeeded;
+ return WN_MORE_DATA;
+ }
+
+ memset (pNetResource, 0, sizeof (*pNetResource));
+
+ pNetResource->dwType = RESOURCETYPE_DISK;
+ pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ pNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+ /* Setup string area at opposite end of buffer. */
+ StringZone = (PWCHAR)((PBYTE)StringZone - (SpaceNeeded - sizeof(NETRESOURCE)));
+
+ /* The remote name is the server + share. */
+ pNetResource->lpRemoteName = StringZone;
+ *StringZone++ = L'\\';
+ *StringZone++ = L'\\';
+ CopyMemory (StringZone, MRX_VBOX_SERVER_NAME_U, sizeof(MRX_VBOX_SERVER_NAME_U) - sizeof (WCHAR));
+ StringZone += sizeof(MRX_VBOX_SERVER_NAME_U) / sizeof(WCHAR) - 1;
+ CopyMemory (StringZone, lpAfterName, (lp - lpAfterName) * sizeof(WCHAR));
+ StringZone += lp - lpAfterName;
+ *StringZone++ = 0;
+
+ /* Provider. */
+ pNetResource->lpProvider = StringZone;
+ CopyMemory (StringZone, MRX_VBOX_PROVIDER_NAME_U, sizeof(MRX_VBOX_PROVIDER_NAME_U));
+ StringZone += sizeof(MRX_VBOX_PROVIDER_NAME_U) / sizeof(WCHAR);
+
+ if (lplpSystem)
+ {
+ *lplpSystem = StringZone;
+ }
+
+ lstrcpy(StringZone, lp);
+ StringZone += lstrlen(lp) + 1;
+
+ Log(("VBOXNP: NPGetResourceInformation: lpRemoteName: %ls, strings %p/%p\n",
+ pNetResource->lpRemoteName, StringZone, (PBYTE)lpBuffer + *lpBufferSize));
+ Log(("VBOXNP: NPGetResourceInformation: *lplpSystem: %ls\n", *lplpSystem));
+
+ return WN_SUCCESS;
+}
+
+DWORD APIENTRY
+NPGetUniversalName (LPCWSTR lpLocalPath, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize)
+/*++
+
+ Routine Description:
+
+ This routine returns the information associated net resource
+
+ Arguments:
+
+ lpLocalPath - the local path name
+
+ dwInfoLevel - the desired info level
+
+ lpBuffer - the buffer for the univeral name
+
+ lpBufferSize - the buffer size
+
+ Return Value:
+
+ WN_SUCCESS if successful
+
+ Notes:
+
+ --*/
+{
+ 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;
+}
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def
new file mode 100644
index 00000000000..0c8e90d7db6
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.def
@@ -0,0 +1,24 @@
+;
+; Copyright (C) 2006-2007 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+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
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h
new file mode 100644
index 00000000000..83f9e73d2be
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.h
@@ -0,0 +1,43 @@
+/*++
+
+ Copyright (c) 1989-1999 Microsoft Corporation
+
+ Module Name:
+
+ nulmrxnp.h
+
+ Abstract:
+
+ This module includes all network provider router interface related
+ definitions for the sample
+
+ Notes:
+
+ This module has been built and tested only in UNICODE environment
+
+ --*/
+
+#ifndef _NULMRXNP_H_
+#define _NULMRXNP_H_
+
+#include "..\sys\nulmrx.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"
+
+typedef struct _NULMRXNP_ENUMERATION_HANDLE_
+{
+ INT LastIndex;
+} NULMRXNP_ENUMERATION_HANDLE, *PNULMRXNP_ENUMERATION_HANDLE;
+
+#endif
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc
new file mode 100644
index 00000000000..575a52ae1dd
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/dll/vboxmrxp.rc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#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
+ VALUE "OriginalFilename", "VBoxMRXNP.DLL\0"
+ VALUE "ProductName", "VirtualBox Guest Additions\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk
new file mode 100644
index 00000000000..ab375ee3c1e
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/Makefile.kmk
@@ -0,0 +1,90 @@
+# $Id$
+## @file
+# Sub-Makefile for the VirtualBox Windows Guest Shared Folders FSD.
+#
+
+#
+# Copyright (C) 2006-2007 Oracle Corporation
+#
+# Oracle Corporation confidential
+# All rights reserved
+#
+
+SUB_DEPTH = ../../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# rdbss
+#
+LIBRARIES += rdbss
+rdbss_TEMPLATE = VBOXGUESTR0
+rdbss_SOURCES = rdbss/rdbss.def
+
+#
+# VBoxSF
+#
+SYSMODS += VBoxSF
+VBoxSF_TEMPLATE = VBOXGUESTR0
+VBoxSF_DEFS = LOG_TO_BACKDOOR VBOX_WITH_HGCM IN_RING0 VBOX_GUEST
+VBoxSF_DEFS += VBOX_ASYNC_RW VBOX_FAIL_FASTIO
+
+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 = \
+ devctrl.c \
+ devfcb.c \
+ downlvli.c \
+ ea.c \
+ fileinfo.c \
+ init.c \
+ locks.c \
+ netroot.c \
+ notimpl.c \
+ openclos.c \
+ read.c \
+ rename.c \
+ srvcall.c \
+ transprt.c \
+ write.c \
+ vbsfhlp.c \
+ wmlkm.c \
+ rdbss_vbox.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)
+
+## Use with checked RDBSS libraries
+## $(PATH_SDK_W2K3DDKX86_LIB)/bufferoverflowk.lib \
+
+## rdbss.asm \
+## $(PATH_LIB)/rdbss$(VBOXW32GUEST_SUFF_LIB)
+
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf
new file mode 100644
index 00000000000..bd87205dad6
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.inf
@@ -0,0 +1,77 @@
+;
+; INF file for installing the VirtualBox Windows guest driver
+;
+; Copyright (C) 2006-2007 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+[Version]
+Signature="$Windows NT$"
+Class=System
+ClassGuid={ce4a90b5-1d8c-435d-b349-232ce55cb17f}
+Provider=%SUN%
+;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 %SUN%=VBoxSF
+;amd64 %SUN%=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
+
+[VBoxSF_Install.CoInstallers]
+AddReg = VBoxSF_Install_CoInstallers_reg
+CopyFiles = VBox_CoInstaller_CopyFiles
+
+[VBox_CoInstaller_CopyFiles]
+vbcoinst.dll
+
+[VBoxSF_Install_CoInstallers_reg]
+HKR,,CoInstallers32,0x00010000,"vbcoinst.dll,VBoxCoInstaller"
+
+[Strings]
+SUN = "Sun Microsystems, Inc."
+VBoxSF.DeviceDesc = "VirtualBox Device"
+VBoxSF_svcdesc = "VirtualBox Shared Folders Driver"
+VBoxMRXNP_svcdesc = "VirtualBox Network Provider Service"
+
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc
new file mode 100644
index 00000000000..cdff579ac9d
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/VBoxSF.rc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#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", "VirtualBox Guest Additions\0"
+ VALUE "ProductVersion", VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c
new file mode 100644
index 00000000000..e5198c486f7
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devctrl.c
@@ -0,0 +1,76 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ devctrl.c
+
+ Abstract:
+
+ This module implements DeviceIoControl operations.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// The local debug trace level
+//
+
+RXDT_DefineCategory (DEVCTRL);
+
+#define Dbg (DEBUG_TRACE_DEVCTRL)
+
+//
+// forwards & code allocation pragmas
+//
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, VBoxMRxIoCtl)
+#endif
+
+NTSTATUS VBoxMRxIoCtl (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine performs an IOCTL operation.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ Notes:
+
+
+ --*/
+{
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+#ifndef VBOX
+ UNICODE_STRING RootName;
+#endif
+ VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension);
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ ULONG IoControlCode = LowIoContext->ParamsFor.FsCtl.FsControlCode;
+ PUNICODE_STRING RemainingName = pSrvOpen->pAlreadyPrefixedName;
+#ifndef VBOX
+ UNICODE_STRING StatsFile;
+#endif
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+
+ Log(("VBOXSF: VBoxMRxIoCtl: IoControlCode = 0x%x\n", IoControlCode));
+ PAGED_CODE();
+
+ return Status;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c
new file mode 100644
index 00000000000..fdd67fc8dc3
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/devfcb.c
@@ -0,0 +1,741 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ devfcb.c
+
+ Abstract:
+
+ This module implements the mechanism for deleting an established connection
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+#include "rdbss_vbox.h"
+
+//
+// The local debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_DEVFCB)
+
+//#define FIXED_CONNECT_NAME L"\\;0:\\vboxsvr\\share"
+#define FIXED_CONNECT_NAME L"\\;0:"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, VBoxMRxDevFcbXXXControlFile)
+#endif
+
+NTSYSAPI
+NTSTATUS NTAPI
+ZwSetSecurityObject (IN HANDLE Handle, IN SECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+NTSTATUS VBoxMRxDevFcbXXXControlFile (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine handles all the device FCB related FSCTL's in the mini rdr
+
+ Arguments:
+
+ RxContext - Describes the Fsctl and Context.
+
+ Return Value:
+
+ a valid NTSTATUS code.
+
+ Notes:
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFobx;
+ UCHAR MajorFunctionCode = RxContext->MajorFunction;
+ VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension);
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ ULONG ControlCode = 0;
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: MajorFunctionCode = %x\n", MajorFunctionCode));
+
+ switch (MajorFunctionCode)
+ {
+ case IRP_MJ_FILE_SYSTEM_CONTROL:
+ {
+ switch (LowIoContext->ParamsFor.FsCtl.MinorFunction)
+ {
+ case IRP_MN_USER_FS_REQUEST:
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IRP_MN_USER_FS_REQUEST: ControlCode = %x\n", ControlCode));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+
+ default: //minor function != IRP_MN_USER_FS_REQUEST
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+ break;
+ }
+
+ case IRP_MJ_DEVICE_CONTROL:
+ {
+
+ ControlCode = LowIoContext->ParamsFor.IoCtl.IoControlCode;
+
+ switch (ControlCode)
+ {
+ case IOCTL_MRX_VBOX_ADDCONN:
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_ADDCONN\n"));
+ Status = VBoxMRxCreateConnection(RxContext, &RxContext->PostRequest);
+ break;
+
+ case IOCTL_MRX_VBOX_DELCONN:
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_DELCONN\n"));
+ Status = VBoxMRxDeleteConnection(RxContext, &RxContext->PostRequest);
+ break;
+
+ case IOCTL_MRX_VBOX_GETLIST:
+ {
+ ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+ PVOID pbOut = LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST\n"));
+
+ if ((cbOut >= _MRX_MAX_DRIVE_LETTERS) && (NULL != pbOut))
+ {
+ BOOLEAN GotMutex = FALSE;
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST: Copying local connections ...\n"));
+
+ if (NULL == pDeviceExtension)
+ break;
+
+ GotMutex = ExTryToAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+ RtlCopyMemory (pbOut, pDeviceExtension->cLocalConnections, _MRX_MAX_DRIVE_LETTERS);
+
+ if (GotMutex)
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+
+ RxContext->InformationToReturn = _MRX_MAX_DRIVE_LETTERS;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETLIST: Nothing to copy, 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 *pbOut = (uint8_t *)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALLIST\n"));
+
+ if (NULL == pDeviceExtension)
+ break;
+
+ RxContext->InformationToReturn = 0;
+ if ((cbOut >= _MRX_MAX_DRIVE_LETTERS) && (NULL != pbOut))
+ {
+ SHFLMAPPING mappings[_MRX_MAX_DRIVE_LETTERS];
+ uint32_t cMappings = RT_ELEMENTS(mappings);
+ int vboxRC;
+
+ vboxRC = vboxCallQueryMappings(&pDeviceExtension->hgcmClient, mappings, &cMappings);
+ if (vboxRC == VINF_SUCCESS)
+ {
+ uint32_t i;
+
+ RtlZeroMemory(pbOut, _MRX_MAX_DRIVE_LETTERS);
+ for (i = 0; i < RT_MIN(cMappings, cbOut); i++)
+ {
+ pbOut[i] = mappings[i].root;
+ pbOut[i] |= 0x80; /* mark active *//** @todo fix properly */
+ }
+
+ RxContext->InformationToReturn = _MRX_MAX_DRIVE_LETTERS;
+ }
+ else
+ {
+ Status = VBoxErrorToNTStatus(vboxRC);
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALLIST Error: 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 ulConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
+ PWCHAR pwcConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+
+ ULONG ulRemoteNameLen = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+ PULONG pulRemoteName = (PULONG)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+
+ Log(
+ ("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: ConnectName = %.*ls, Len = %d, RemoteName = 0x%x, Len = %d\n", ulConnectNameLen / sizeof(WCHAR), pwcConnectName, ulConnectNameLen, pulRemoteName, ulRemoteNameLen));
+
+ if (NULL == pDeviceExtension)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Insert the local connection name. */
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Looking up connection name and connections ...\n"));
+ if ((ulConnectNameLen > sizeof(WCHAR)) && (NULL != pwcConnectName))
+ {
+ ULONG ulLocalConnectionNameLen;
+
+ uint32_t idx = *pwcConnectName - L'A';
+
+ ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index = %d\n", idx));
+
+ if ((idx < 0) || (idx >= RTL_NUMBER_OF(pDeviceExtension->wszLocalConnectionName)))
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index is invalid!\n"));
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (NULL == pDeviceExtension->wszLocalConnectionName[idx])
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: LocalConnectionName is NULL!\n"));
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+ Status = STATUS_BAD_NETWORK_NAME;
+ break;
+ }
+
+ ulLocalConnectionNameLen = pDeviceExtension->wszLocalConnectionName[idx]->Length;
+
+ Log(
+ ("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: LocalConnectionName = %.*ls\n", ulLocalConnectionNameLen / sizeof(WCHAR), pDeviceExtension->wszLocalConnectionName[idx]->Buffer));
+
+ if ((pDeviceExtension->cLocalConnections[idx]) && (ulLocalConnectionNameLen <= ulRemoteNameLen))
+ {
+ RtlZeroMemory (pulRemoteName, ulRemoteNameLen);
+ RtlCopyMemory (pulRemoteName, pDeviceExtension->wszLocalConnectionName[idx]->Buffer, ulLocalConnectionNameLen);
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Remote name = %.*ls, Size = %d\n", ulLocalConnectionNameLen / sizeof(WCHAR), pulRemoteName, ulLocalConnectionNameLen));
+ RxContext->InformationToReturn = ulLocalConnectionNameLen;
+ }
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ RxContext->InformationToReturn = ulLocalConnectionNameLen;
+ }
+
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: No connection name found!\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 RemoteNameLen = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
+ PULONG RemoteName = (PULONG)LowIoContext->ParamsFor.IoCtl.pOutputBuffer;
+ PSHFLSTRING pString;
+ int vboxRC;
+ uint32_t cbString = sizeof(SHFLSTRING) + RemoteNameLen;
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALCONN: Connection ID = %d, RemoteName = 0x%x, Len = %d\n", *pConnectId, RemoteName, RemoteNameLen));
+
+ pString = (PSHFLSTRING)vbsfAllocNonPagedMem(cbString);
+ if (!pString)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ memset(pString, 0, cbString);
+ ShflStringInitBuffer(pString, RemoteNameLen); /** @todo r=andy This function does not have an effect ...? */
+
+ vboxRC = vboxCallQueryMapName(&pDeviceExtension->hgcmClient, (*pConnectId) & ~0x80 /** @todo fix properly */, pString, cbString);
+ if (vboxRC == VINF_SUCCESS)
+ {
+ if (pString->u16Length < RemoteNameLen)
+ {
+ ReturnedSize = pString->u16Length;
+ RtlCopyMemory( RemoteName, pString->String.ucs2, pString->u16Length);
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETGLOBALCONN: Returned name = %.*ls, Size = %d\n", ReturnedSize / sizeof(WCHAR), RemoteName, ReturnedSize));
+ }
+ }
+ else
+ Status = VBoxErrorToNTStatus(vboxRC);
+
+ vbsfFreeNonPagedMem(pString);
+
+ if (ReturnedSize)
+ {
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ Status = STATUS_BAD_NETWORK_NAME;
+ }
+ RxContext->InformationToReturn = ReturnedSize;
+ break;
+ }
+
+ case IOCTL_MRX_VBOX_START:
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Called.\n"));
+ 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 = VBoxRxStartMinirdr(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: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: RtlCreateSecurityDescriptor failed with 0x%x!\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: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwOpenFile %ls failed with 0x%x!\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: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwSetSecurityObject failed with 0x%x!\n", Status));
+ return Status;
+ }
+
+ Status = ZwClose(hDevice);
+ if (Status != STATUS_SUCCESS)
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_START_IN_PROGRESS: ZwClose failed with 0x%x\n", Status));
+ return Status;
+ }
+ }
+ break;
+
+ case MRX_VBOX_STARTED:
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: MRX_VBOX_STARTED: Already started\n"));
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Invalid state (%d)!\n", VBoxMRxState));
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_START: Returned 0x%x\n", Status));
+ break;
+ }
+
+ case IOCTL_MRX_VBOX_STOP:
+ {
+ MRX_VBOX_STATE CurrentState;
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Called.\n"));
+ if (capFobx)
+ {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0)
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: 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 = VBoxRxStopMinirdr(RxContext, &RxContext->PostRequest);
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_STOP: Returned 0x%x\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:
+ AssertMsgFailed(("VBOXSF: VBoxMRxDevFcbXXXControlFile: Unimplemented major function!"));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: Status = %08lx, Info = %08lx\n", Status, RxContext->InformationToReturn));
+ return Status;
+}
+
+HANDLE GetConnectionHandle (IN PUNICODE_STRING ConnectionName)
+{
+
+ NTSTATUS Status;
+ HANDLE Handle;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+#ifndef VBOX
+ UNICODE_STRING FileName;
+#endif
+
+ // Connection name should get checked to be certain our device is in the path
+
+ Log(("VBOXSF: GetConnectionHandle: Called.\n"));
+
+ InitializeObjectAttributes(&ObjectAttributes, ConnectionName, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ Status = ZwCreateFile(&Handle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, // Allocation size
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, // Ptr to EA Buffer
+ 0); // Length of EA buffer
+
+ Log(("VBOXSF: GetConnectionHandle: ZwCreateFile returned 0x%x\n", Status));
+
+ if ((STATUS_SUCCESS == Status) && (INVALID_HANDLE_VALUE != Handle))
+ {
+ Log(("VBOXSF: GetConnectionHandle: ZwCreateFile returned success\n"));
+ }
+ else
+ {
+ Handle = INVALID_HANDLE_VALUE;
+ Log(("VBOXSF: GetConnectionHandle: ZwCreateFile returned invalid handle!\n"));
+ }
+
+ return Handle;
+}
+
+NTSTATUS DoCreateConnection (IN PRX_CONTEXT RxContext, ULONG CreateDisposition)
+{
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ HANDLE Handle;
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
+ PWCHAR ConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+ UNICODE_STRING FileName;
+
+ VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension);
+
+ if (NULL == pDeviceExtension)
+ return STATUS_INVALID_PARAMETER;
+
+ if ((0 == ConnectNameLen) || (NULL == ConnectName))
+ {
+ Log(("VBOXSF: DoCreateConnection: Connection name / length is invalid!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // The sample code passes in only the filename in the Ioctl data buffer.
+ // An actual implementation could pass in stuff like EAs, security
+ // credentials, etc
+
+ Log(("VBOXSF: DoCreateConnection: Name = %.*ls, Length = %d\n", ConnectNameLen / sizeof(WCHAR), ConnectName, ConnectNameLen));
+
+ FileName.Buffer = ConnectName;
+ FileName.Length = (USHORT)ConnectNameLen;
+ FileName.MaximumLength = (USHORT)ConnectNameLen;
+
+ Handle = GetConnectionHandle(&FileName);
+
+ if (INVALID_HANDLE_VALUE != Handle)
+ {
+ PWCHAR pwcLC;
+ ULONG i;
+
+ Log(("VBOXSF: DoCreateConnection: GetConnectionHandle returned success!\n"));
+ ZwClose(Handle);
+
+ /* Skip the "\Device\VBoxMiniRdr\;X:" of the string "\Device\VBoxMiniRdr\;X:\vboxsrv\sf" */
+ pwcLC = (PWCHAR)ConnectName;
+ for (i = 0; i < ConnectNameLen && *pwcLC != L':'; i += sizeof(WCHAR), pwcLC++)
+ ;
+
+ if (i >= sizeof(WCHAR) && i < ConnectNameLen)
+ {
+ pwcLC--; /* Go back to the drive letter, "X" for example. */
+ if (*pwcLC >= L'A' && *pwcLC <= L'Z') /* Are we in range? */
+ {
+ uint32_t idx = *pwcLC - L'A'; /* Get the index based on the driver letter numbers (26). */
+ PUNICODE_STRING pRemoteName;
+
+ ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+ if ((idx < 0) || (idx >= RTL_NUMBER_OF(pDeviceExtension->cLocalConnections)))
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_MRX_VBOX_GETCONN: Index is invalid!\n"));
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+ return STATUS_BAD_NETWORK_NAME;
+ }
+
+ pDeviceExtension->cLocalConnections[idx] = TRUE;
+
+ if (NULL != pDeviceExtension->wszLocalConnectionName[idx])
+ Log(("VBOXSF: DoCreateConnection: LocalConnectionName at index %d is NOT empty!\n", idx));
+
+ /*pDeviceExtension->LocalConnectionName[idx] = (PUNICODE_STRING)ExAllocatePool(PagedPool, sizeof(UNICODE_STRING) + ConnectNameLen /* more than enough );*/
+ pDeviceExtension->wszLocalConnectionName[idx] = (PUNICODE_STRING)vbsfAllocNonPagedMem(sizeof(UNICODE_STRING) + ConnectNameLen);
+
+ if (NULL == pDeviceExtension->wszLocalConnectionName[idx])
+ Log(("VBOXSF: DoCreateConnection: LocalConnectionName at index %d NOT allocated!\n", idx));
+
+ pRemoteName = pDeviceExtension->wszLocalConnectionName[idx];
+
+ pRemoteName->Buffer = (PWSTR)(pRemoteName + 1);
+ pRemoteName->Length = (USHORT)(ConnectNameLen - i - sizeof(WCHAR));
+ pRemoteName->MaximumLength = pRemoteName->Length;
+ RtlCopyMemory(&pRemoteName->Buffer[0], pwcLC+2, pRemoteName->Length);
+
+ Log(("VBOXSF: DoCreateConnection: RemoteName %.*ls, Len = %d\n", pRemoteName->Length / sizeof(WCHAR), pRemoteName->Buffer, pRemoteName->Length));
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+ }
+ }
+ }
+ else
+ {
+ Log(("VBOXSF: DoCreateConnection: GetConnectionHandle returned failure!\n"));
+ Status = STATUS_BAD_NETWORK_NAME;
+ }
+
+ return (Status);
+}
+
+NTSTATUS VBoxMRxCreateConnection (IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp)
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+ IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers
+
+ Return Value:
+
+ RXSTATUS
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+ BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxCreateConnection: Called.\n"));
+
+ if (!Wait)
+ {
+ //just post right now!
+ *PostToFsp = TRUE;
+ return STATUS_PENDING;
+ }
+
+ Status = DoCreateConnection(RxContext, (ULONG)FILE_OPEN_IF);
+ return Status;
+}
+
+NTSTATUS DoDeleteConnection (PUNICODE_STRING FileName)
+{
+ HANDLE Handle;
+ NTSTATUS Status;
+ PFILE_OBJECT pFileObject;
+ PNET_ROOT NetRoot;
+ PV_NET_ROOT VNetRoot;
+ PFOBX Fobx;
+
+ Log(("VBOXSF: DoDeleteConnection: Called.\n"));
+
+ Handle = GetConnectionHandle(FileName);
+
+ if (INVALID_HANDLE_VALUE != Handle)
+ {
+ Log(("VBOXSF: DoDeleteConnection: GetConnectionHandle returned success\n"));
+
+ Status = ObReferenceObjectByHandle(Handle, 0L, NULL, KernelMode, (PVOID *)&pFileObject, NULL);
+
+ Log(("VBOXSF: DoDeleteConnection: ObReferenceObjectByHandle Status 0x%08X\n", Status));
+ if (NT_SUCCESS(Status))
+ {
+
+ // Got the FileObject. Now get an Fobx
+ Fobx = (PFOBX)pFileObject->FsContext2;
+ if (NodeType(Fobx) == RDBSS_NTC_V_NETROOT)
+ {
+ VNetRoot = (PV_NET_ROOT)(Fobx);
+ NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
+ Log(("Calling RxFinalizeConnection\n"));
+ Status = VBoxRxFinalizeConnection(NetRoot, VNetRoot, TRUE);
+ }
+ else
+ {
+ ASSERT(FALSE);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ ObDereferenceObject(pFileObject);
+ }
+
+ ZwClose(Handle);
+ }
+
+ return Status;
+}
+
+NTSTATUS VBoxMRxDeleteConnection (IN PRX_CONTEXT RxContext, OUT PBOOLEAN PostToFsp)
+/*++
+
+ Routine Description:
+
+ This routine deletes a single vnetroot.
+
+ Arguments:
+
+ IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers
+
+ Return Value:
+
+ RXSTATUS
+
+ --*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING FileName;
+ BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ PWCHAR ConnectName = (PWCHAR)LowIoContext->ParamsFor.IoCtl.pInputBuffer;
+ ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
+ VBoxMRxGetDeviceExtension(RxContext,pDeviceExtension);
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxDeleteConnection: ConnectName = %.*ls\n", ConnectNameLen / sizeof(WCHAR), ConnectName));
+
+ if (!Wait)
+ {
+ //just post right now!
+ *PostToFsp = TRUE;
+ return (STATUS_PENDING);
+ }
+
+ FileName.Buffer = ConnectName;
+ FileName.Length = (USHORT)ConnectNameLen;
+ FileName.MaximumLength = (USHORT)ConnectNameLen;
+
+ Status = DoDeleteConnection(&FileName);
+
+ if (NT_SUCCESS(Status))
+ {
+ PWCHAR pwcLC;
+ ULONG i;
+
+ for (i = 0, pwcLC = ConnectName; i < ConnectNameLen && *pwcLC != L':'; i += sizeof(WCHAR), pwcLC++)
+ ;
+
+ if (i >= sizeof(WCHAR) && i < ConnectNameLen)
+ {
+ pwcLC--;
+ if (*pwcLC >= L'A' && *pwcLC <= L'Z')
+ {
+ uint32_t idx = *pwcLC - L'A';
+
+ ExAcquireFastMutex(&pDeviceExtension->mtxLocalCon);
+
+ pDeviceExtension->cLocalConnections[idx] = FALSE;
+
+ /* Free saved name */
+ /*Assert(pDeviceExtension->LocalConnectionName[idx]);
+ ExFreePool(pDeviceExtension->LocalConnectionName[idx]);
+ pDeviceExtension->LocalConnectionName[idx] = NULL;*/
+ if (pDeviceExtension->wszLocalConnectionName[idx])
+ {
+ vbsfFreeNonPagedMem(pDeviceExtension->wszLocalConnectionName[idx]);
+ pDeviceExtension->wszLocalConnectionName[idx] = NULL;
+ }
+
+ ExReleaseFastMutex(&pDeviceExtension->mtxLocalCon);
+ }
+ }
+ }
+
+ return Status;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c
new file mode 100644
index 00000000000..2356e065816
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/downlvli.c
@@ -0,0 +1,157 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ DownLvlI.c
+
+ Abstract:
+
+ This module implements downlevel fileinfo, volinfo, and dirctrl.
+
+ --*/
+
+#include "precomp.h"
+#include <iprt/fs.h>
+#pragma hdrstop
+
+//
+// The local debug trace level
+//
+
+RXDT_DefineCategory (DOWNLVLI);
+#define Dbg (DEBUG_TRACE_DOWNLVLI)
+
+NTSTATUS VBoxMRxSetEndOfFile (IN OUT struct _RX_CONTEXT * RxContext, IN OUT PLARGE_INTEGER pNewFileSize, OUT PLARGE_INTEGER pNewAllocationSize)
+/*++
+
+ Routine Description:
+
+ This routine handles requests to truncate or extend the file
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PRTFSOBJINFO pObjInfo = 0;
+ uint32_t cbBuffer;
+ int vboxRC;
+
+ Log(("VBOXSF: VBoxMRxSetEndOfFile: New size = %RX64 (0x%x), pNewAllocationSize = 0x%x\n", pNewFileSize->QuadPart, pNewFileSize, pNewAllocationSize));
+
+ cbBuffer = sizeof(RTFSOBJINFO);
+ pObjInfo = (PRTFSOBJINFO)vbsfAllocNonPagedMem(cbBuffer);
+ if (pObjInfo == 0)
+ {
+ AssertFailed();
+ return STATUS_NO_MEMORY;
+ }
+ memset(pObjInfo, 0, cbBuffer);
+
+ pObjInfo->cbObject = pNewFileSize->QuadPart;
+ Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension);
+ vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer, (PSHFLDIRINFO)pObjInfo);
+ AssertRC(vboxRC);
+
+ Log(("VBOXSF: VBoxMRxSetEndOfFile: vboxCallFSInfo returned %d\n", vboxRC));
+
+ Status = VBoxErrorToNTStatus(vboxRC);
+ if (Status == STATUS_SUCCESS)
+ {
+ Log(("VBOXSF: VBoxMRxSetEndOfFile: vboxCallFSInfo new allocation size = %RX64\n", pObjInfo->cbAllocated));
+
+ /* Return new allocation size */
+ pNewAllocationSize->QuadPart = pObjInfo->cbAllocated;
+ }
+
+ if (pObjInfo)
+ vbsfFreeNonPagedMem((PVOID)pObjInfo);
+
+ Log(("VBOXSF: VBoxMRxSetEndOfFile: Returned %d\n", Status));
+ return Status;
+}
+
+NTSTATUS VBoxMRxTruncateFile (IN OUT struct _RX_CONTEXT * RxContext)
+/*++
+
+ Routine Description:
+
+ This routine handles requests to truncate the file
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxTruncateFile not implemented!\n"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+ULONG VBoxMRxExtendFile (IN OUT struct _RX_CONTEXT * RxContext, IN OUT PLARGE_INTEGER pNewFileSize, OUT PLARGE_INTEGER pNewAllocationSize)
+/*++
+
+ Routine Description:
+
+ This routine handles requests to extend the file for cached IO.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxExtendFile new size = %RX64\n", pNewFileSize->QuadPart));
+ return VBoxMRxSetEndOfFile(RxContext, pNewFileSize, pNewAllocationSize);
+}
+
+NTSTATUS VBoxMRxExtendStub (IN OUT struct _RX_CONTEXT * RxContext, IN OUT PLARGE_INTEGER pNewFileSize, OUT PLARGE_INTEGER pNewAllocationSize)
+/*++
+
+Routine Description:
+
+ This routine handles MRxExtendForCache and MRxExtendForNonCache requests. Since the write
+ itself will extend the file, we can pretty much just get out quickly.
+
+Arguments:
+
+ RxContext - the RDBSS context
+
+Return Value:
+
+ RXSTATUS - The return status for the operation
+
+--*/
+{
+ /* Note: On Windows hosts VBoxMRxSetEndOfFile returns ACCESS_DENIED if the file has been
+ * opened in APPEND mode. Therefore it is better to not call host at all and implement
+ * this MrxExtend* request just like in mrxsmb DDK sample.
+ */
+ Log(("VBOXSF: VBoxMRxExtendStub new size = %RX64\n", pNewFileSize->QuadPart));
+
+ pNewAllocationSize->QuadPart = pNewFileSize->QuadPart;
+
+ return(STATUS_SUCCESS);
+}
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c
new file mode 100644
index 00000000000..03ce645315b
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/ea.c
@@ -0,0 +1,109 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ ea.c
+
+ Abstract:
+
+ This module implements 'extended attributes' on a file handle
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// The local debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_EA)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, VBoxMRxQueryEaInformation)
+#endif
+
+#ifdef VBOX
+/*
+ * We don't support extended attributes as the host OS might not know the concept at all
+ *
+ */
+#endif
+
+//
+// Extended Attributes (EA) functionality
+//
+
+NTSTATUS VBoxMRxQueryEaInformation (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine queries IFS for extended attributes like
+ scatter-gather list and filename for an IFS handle.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ Notes:
+
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ RxCaptureFcb;
+ RxCaptureFobx;
+ RxCaptureParamBlock;
+
+ PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
+ PFILE_FULL_EA_INFORMATION pEaInfo = (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
+ ULONG BufferLength = RxContext->Info.LengthRemaining;
+ ULONG UserEaListLength = RxContext->QueryEa.UserEaListLength;
+ PUCHAR UserEaList = RxContext->QueryEa.UserEaList;
+ PFILE_GET_EA_INFORMATION pGetEaInfo = (PFILE_GET_EA_INFORMATION)UserEaList;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxQueryEaInformation: Ea buffer len remaining is %d\n", RxContext->Info.LengthRemaining));
+
+ return (Status);
+}
+
+NTSTATUS VBoxMRxSetEaInformation (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine sets the EA information for this FCB
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ Notes:
+
+
+ --*/
+{
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(RxContext);
+
+ Log(("VBOXSF: VBoxMRxSetEaInformation: Not implemented!\n"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c
new file mode 100644
index 00000000000..cc8e8a7d125
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/fileinfo.c
@@ -0,0 +1,1684 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ fileinfo.c
+
+ Abstract:
+
+ This module implements the mini redirector call down routines pertaining to retrieval/
+ update of file/directory/volume information.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+/** 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)
+/*++
+
+ Routine Description:
+
+ This routine does a directory query. Only the NT-->NT path is implemented.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ FILE_INFORMATION_CLASS FileInformationClass;
+ PCHAR Buffer;
+ PLONG pLengthRemaining;
+ LONG CopySize;
+ RxCaptureFobx;
+ RxCaptureFcb;
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension);
+ PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+ PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
+ int vboxRC;
+ uint8_t *pHGCMBuffer;
+ uint32_t index, fSFFlags, cFiles, u32BufSize;
+ LONG cbHGCMBuffer, cbMaxSize;
+ PSHFLDIRINFO pDirEntry;
+ ULONG *pNextOffset = 0;
+ PSHFLSTRING ParsedPath = 0;
+
+ if (NULL == pVBoxFobx)
+ {
+ Log(("VBOXSF: QueryDirectory: pVBoxFobx is invalid!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ FileInformationClass = RxContext->Info.FileInformationClass;
+ Log(("VBOXSF: QueryDirectory: FileInformationClass %d\n", FileInformationClass));
+
+ Buffer = (PCHAR)RxContext->Info.Buffer;
+ cbMaxSize = RxContext->Info.Length;
+ pLengthRemaining = (PULONG) & RxContext->Info.LengthRemaining;
+
+ Log(("VBOXSF: QueryDirectory: vboxFobx = 0x%08x VBox file handle = 0x%08x\n", pVBoxFobx, pVBoxFobx->hFile));
+
+ if (NULL == DirectoryName)
+ return STATUS_INVALID_PARAMETER;
+
+ if (DirectoryName->Length == 0)
+ {
+ Log(("VBOXSF: QueryDirectory: DirectoryName = \\ (null string)\n"));
+ }
+ else Log(("VBOXSF: QueryDirectory: DirectoryName = %.*ls\n", DirectoryName->Length / sizeof(WCHAR), DirectoryName->Buffer));
+
+ if (NULL == Template)
+ return STATUS_INVALID_PARAMETER;
+
+ if (Template->Length == 0)
+ {
+ Log(("VBOXSF: QueryDirectory: Template = \\ (null string)\n"));
+ }
+ else Log(("VBOXSF: QueryDirectory: Template = %.*ls\n", Template->Length / sizeof(WCHAR), Template->Buffer));
+
+ cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE);
+ Log(("VBOXSF: QueryDirectory: Allocating HGCMBuffer = %d\n", cbHGCMBuffer));
+ pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+ if (pHGCMBuffer == NULL)
+ {
+ AssertFailed();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Assume start from the beginning. */
+ index = 0;
+ if (RxContext->QueryDirectory.IndexSpecified == TRUE)
+ {
+ Log(("VBOXSF: QueryDirectory: Index specified %d\n", index));
+ index = RxContext->QueryDirectory.FileIndex;
+ }
+ fSFFlags = SHFL_LIST_NONE;
+ if (RxContext->QueryDirectory.ReturnSingleEntry == TRUE)
+ {
+ Log(("VBOXSF: QueryDirectory: 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: QueryDirectory: ParsedPathSize = %d\n", ParsedPathSize));
+
+ ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+ if (!ParsedPath)
+ {
+ Status = STATUS_NO_MEMORY;
+ 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: QueryDirectory: ParsedPath = %.*ls\n", ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
+ }
+
+ cFiles = 0;
+ /* vboxCallDirInfo requires a pointer to uint32_t. */
+ u32BufSize = cbHGCMBuffer;
+
+ Log(("VBOXSF: QueryDirectory: CallDirInfo: File = 0x%08x, Flags = 0x%08x, Index = %d\n", pVBoxFobx->hFile, fSFFlags, index));
+ Log(("VBOXSF: QueryDirectory: u32BufSize before CallDirInfo = %d\n", u32BufSize));
+ vboxRC = vboxCallDirInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, ParsedPath, fSFFlags, index, &u32BufSize, (PSHFLDIRINFO)pHGCMBuffer, &cFiles);
+ Log(("VBOXSF: QueryDirectory: u32BufSize after CallDirInfo = %d\n", u32BufSize));
+ Log(("VBOXSF: QueryDirectory: CallDirInfo returned %Rrc\n", vboxRC));
+
+ switch (vboxRC)
+ {
+ case VINF_SUCCESS:
+ /* Nothing to do here. */
+ break;
+ case VERR_NO_TRANSLATION:
+ Log(("VBOXSF: QueryDirectory: 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: QueryDirectory: 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: QueryDirectory: no such file!\n"));
+ break;
+ default:
+ Status = VBoxErrorToNTStatus(vboxRC);
+ Log(("VBOXSF: QueryDirectory: 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: QueryDirectory: 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: QueryDirectory: 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: QueryDirectory: 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 pDirInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
+ CopySize = sizeof(FILE_DIRECTORY_INFORMATION);
+
+ /* Struct already contains one char for null terminator. */
+ CopySize += pDirEntry->name.u16Size;
+
+ Log(("VBOXSF: QueryDirectory: FileDirectoryInformation Buffer=%08x\n", Buffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory( pDirInfo, CopySize );
+
+ pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+ pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+ pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+ pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+ pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+ pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
+
+ pDirInfo->FileIndex = index;
+ pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+ INIT_FILE_NAME(pDirInfo, pDirEntry->name);
+
+ /* Align to 8 byte boundary */
+ CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG));
+ pDirInfo->NextEntryOffset = CopySize;
+ pNextOffset = &pDirInfo->NextEntryOffset;
+ }
+ else
+ {
+ pDirInfo->NextEntryOffset = 0; /* last item */
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ break;
+ }
+
+ case FileFullDirectoryInformation:
+ {
+ PFILE_FULL_DIR_INFORMATION pDirInfo = (PFILE_FULL_DIR_INFORMATION)Buffer;
+ CopySize = sizeof(FILE_FULL_DIR_INFORMATION);
+
+ /* Struct already contains one char for null terminator. */
+ CopySize += pDirEntry->name.u16Size;
+
+ Log(("VBOXSF: QueryDirectory: FileFullDirectoryInformation Buffer=%08x\n", Buffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory( pDirInfo, CopySize );
+
+ pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+ pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+ pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+ pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+ pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+ pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
+
+ pDirInfo->EaSize = 0;
+ pDirInfo->FileIndex = index;
+ pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+ INIT_FILE_NAME(pDirInfo, pDirEntry->name);
+
+ /* Align to 8 byte boundary */
+ CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG));
+ pDirInfo->NextEntryOffset = CopySize;
+ pNextOffset = &pDirInfo->NextEntryOffset;
+ }
+ else
+ {
+ pDirInfo->NextEntryOffset = 0; /* last item */
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ break;
+ }
+
+ case FileBothDirectoryInformation:
+ {
+ PFILE_BOTH_DIR_INFORMATION pDirInfo = (PFILE_BOTH_DIR_INFORMATION)Buffer;
+ CopySize = sizeof(FILE_BOTH_DIR_INFORMATION);
+ /* struct already contains one char for null terminator */
+ CopySize += pDirEntry->name.u16Size;
+
+ Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation Buffer=%08x\n", Buffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory( pDirInfo, CopySize );
+
+ pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+ pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+ pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+ pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+ pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+ pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
+
+ pDirInfo->EaSize = 0;
+ pDirInfo->ShortNameLength = 0; /* @todo ? */
+ pDirInfo->FileIndex = index;
+ pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+ INIT_FILE_NAME(pDirInfo, pDirEntry->name);
+
+ Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation cbAlloc = %x cbObject = %x\n", pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
+ Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation CopySize = %d, name size=%d name len=%d\n", CopySize, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
+ Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation File name %.*ls (DirInfo)\n", pDirInfo->FileNameLength / sizeof(WCHAR), pDirInfo->FileName));
+ Log(("VBOXSF: QueryDirectory: FileBothDirectoryInformation File name %.*ls (DirEntry)\n", pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
+
+ /* Align to 8 byte boundary. */
+ CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG));
+ pDirInfo->NextEntryOffset = CopySize;
+ pNextOffset = &pDirInfo->NextEntryOffset;
+ }
+ else
+ {
+ pDirInfo->NextEntryOffset = 0; /* Last item. */
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ break;
+ }
+
+ case FileIdBothDirectoryInformation:
+ {
+ PFILE_ID_BOTH_DIR_INFORMATION pDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)Buffer;
+ CopySize = sizeof(FILE_ID_BOTH_DIR_INFORMATION);
+ /* struct already contains one char for null terminator */
+ CopySize += pDirEntry->name.u16Size;
+
+ Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation Buffer=%08x\n", Buffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory( pDirInfo, CopySize );
+
+ pDirInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
+ pDirInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
+ pDirInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
+ pDirInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
+ pDirInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
+ pDirInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
+
+ pDirInfo->EaSize = 0;
+ pDirInfo->ShortNameLength = 0; /* @todo ? */
+ pDirInfo->EaSize = 0;
+ pDirInfo->FileId.QuadPart = 0;
+ pDirInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
+
+ INIT_FILE_NAME(pDirInfo, pDirEntry->name);
+
+ Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation cbAlloc = %x cbObject = %x\n", pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
+ Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation CopySize = %d, name size=%d name len=%d\n", CopySize, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
+ Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirInfo)\n", pDirInfo->FileNameLength / sizeof(WCHAR), pDirInfo->FileName));
+ Log(("VBOXSF: QueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirEntry)\n", pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
+
+ /* Align to 8 byte boundary. */
+ CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG));
+ pDirInfo->NextEntryOffset = CopySize;
+ pNextOffset = &pDirInfo->NextEntryOffset;
+ }
+ else
+ {
+ pDirInfo->NextEntryOffset = 0; /* Last item. */
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ break;
+ }
+
+ case FileNamesInformation:
+ {
+ PFILE_NAMES_INFORMATION pDirInfo = (PFILE_NAMES_INFORMATION)Buffer;
+ CopySize = sizeof(FILE_NAMES_INFORMATION);
+
+ /* Struct already contains one char for null terminator. */
+ CopySize += pDirEntry->name.u16Size;
+
+ Log(("VBOXSF: QueryDirectory: FileNamesInformation Buffer=%08x\n", Buffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory( pDirInfo, CopySize );
+
+ pDirInfo->FileIndex = index;
+
+ INIT_FILE_NAME(pDirInfo, pDirEntry->name);
+
+ Log(("VBOXSF: QueryDirectory: FileNamesInformation File name %.*ls\n", pDirInfo->FileNameLength / sizeof(WCHAR), pDirInfo->FileName));
+
+ /* Align to 8 byte boundary. */
+ CopySize = RT_ALIGN(CopySize, sizeof(LONGLONG));
+ pDirInfo->NextEntryOffset = CopySize;
+ pNextOffset = &pDirInfo->NextEntryOffset;
+ }
+ else
+ {
+ pDirInfo->NextEntryOffset = 0; /* Last item. */
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ break;
+ }
+
+ default:
+ Log(("VBOXSF: QueryDirectory: Invalid FS information class %d!\n", FileInformationClass));
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ cbHGCMBuffer -= cbEntry;
+ pDirEntry = (PSHFLDIRINFO)((uintptr_t)pDirEntry + cbEntry);
+ Log(("VBOXSF: QueryDirectory: %d bytes left in HGCM buffer\n", cbHGCMBuffer));
+
+ if (*pLengthRemaining >= CopySize)
+ {
+ Buffer += CopySize;
+ *pLengthRemaining -= CopySize;
+ }
+ else break;
+
+ if (RxContext->QueryDirectory.ReturnSingleEntry)
+ break;
+
+ /* More left? */
+ if (cbHGCMBuffer <= 0)
+ break;
+
+ index++; /* File Index. */
+
+ cFiles--;
+ }
+ if (pNextOffset)
+ *pNextOffset = 0; /* Last pDirInfo->NextEntryOffset should be set to zero! */
+
+ end: if (pHGCMBuffer)
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+
+ if (ParsedPath)
+ vbsfFreeNonPagedMem(ParsedPath);
+
+ Log(("VBOXSF: QueryDirectory: Returned 0x%x\n", Status));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxQueryVolumeInformationWithFullBuffer (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine queries the volume information
+
+ Arguments:
+
+ pRxContext - the RDBSS context
+
+ FsInformationClass - the kind of Fs information desired.
+
+ pBuffer - the buffer for copying the information
+
+ pBufferLength - the buffer length ( set to buffer length on input and set
+ to the remaining length on output)
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ ULONG OriginalLength = RxContext->Info.LengthRemaining;
+ FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
+ PVOID OriginalBuffer = RxContext->Info.Buffer;
+ ULONG BytesToCopy, cbMaxSize;
+
+ if (NULL != pVBoxFobx)
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: vboxFobx = %p, Handle = 0x%08x\n", pVBoxFobx, pVBoxFobx->hFile));
+
+ cbMaxSize = RxContext->Info.Length;
+
+ switch (FsInformationClass)
+ {
+ case FileFsVolumeInformation:
+ {
+ PFILE_FS_VOLUME_INFORMATION pVolInfo = (PFILE_FS_VOLUME_INFORMATION)OriginalBuffer;
+ PWCHAR pRootName;
+ ULONG RootNameLength;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+ PSHFLVOLINFO pSHFLVolInfo;
+ uint32_t cbHGCMBuffer;
+ uint8_t *pHGCMBuffer = NULL;
+ int vboxRC;
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining));
+ if (RxContext->Info.LengthRemaining < sizeof(FILE_FS_VOLUME_INFORMATION))
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: Insufficient buffer size (%d)\n", RxContext->Info.LengthRemaining));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ if (NULL == pVBoxFobx)
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: pVBoxFobx is invalid!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ RtlZeroMemory( pVolInfo, sizeof(FILE_FS_VOLUME_INFORMATION) );
+
+ RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
+ RootNameLength -= 2; /* remove leading backslash */
+
+ pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
+ pRootName++; /* remove leading backslash */
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: Root name = %.*ls\n", RootNameLength / sizeof(WCHAR), pRootName));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsVolumeInformation: Prefix %ls has %d elements\n", VBOX_VOLNAME_PREFIX, RT_ELEMENTS(VBOX_VOLNAME_PREFIX)));
+
+ /* Query serial number. */
+ cbHGCMBuffer = sizeof(SHFLVOLINFO);
+ pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+ if (pHGCMBuffer == 0)
+ {
+ AssertFailed();
+ Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
+ AssertRC(vboxRC);
+
+ if (vboxRC != VINF_SUCCESS)
+ {
+ Status = VBoxErrorToNTStatus(vboxRC);
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+ break;
+ }
+
+ pSHFLVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
+ pVolInfo->VolumeSerialNumber = pSHFLVolInfo->ulSerial;
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+
+ pVolInfo->VolumeCreationTime.QuadPart = 0;
+ pVolInfo->VolumeLabelLength = RootNameLength + VBOX_VOLNAME_PREFIX_SIZE;
+ pVolInfo->SupportsObjects = FALSE;
+
+ RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
+
+ if (RxContext->Info.LengthRemaining >= (LONG)pVolInfo->VolumeLabelLength)
+ {
+ BytesToCopy = pVolInfo->VolumeLabelLength;
+
+ /* Copy prefix */
+ RtlCopyMemory( &pVolInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE);
+
+ /* Copy share name (- 1 for zero terminator) */
+ RtlCopyMemory( &pVolInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, RootNameLength );
+ }
+ else
+ {
+ BytesToCopy = RxContext->Info.LengthRemaining;
+
+ /* Copy prefix */
+ RtlCopyMemory( &pVolInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, RT_MIN(BytesToCopy, VBOX_VOLNAME_PREFIX_SIZE) );
+
+ if (BytesToCopy > VBOX_VOLNAME_PREFIX_SIZE)
+ {
+ /* Copy share name (- 1 for zero terminator) */
+ RtlCopyMemory( &pVolInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, BytesToCopy - VBOX_VOLNAME_PREFIX_SIZE );
+ }
+ }
+
+ RxContext->Info.LengthRemaining -= BytesToCopy;
+ pVolInfo->VolumeLabelLength = BytesToCopy;
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case FileFsLabelInformation:
+ {
+ PFILE_FS_LABEL_INFORMATION pLabelInfo = (PFILE_FS_LABEL_INFORMATION)OriginalBuffer;
+ PWCHAR pRootName;
+ ULONG RootNameLength;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining));
+ if (RxContext->Info.LengthRemaining < sizeof(PFILE_FS_LABEL_INFORMATION))
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: Insufficient buffer size (%d)\n", RxContext->Info.LengthRemaining));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+ RtlZeroMemory( pLabelInfo, sizeof(FILE_FS_LABEL_INFORMATION) );
+
+ RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
+ RootNameLength -= 2; /* remove leading backslash */
+
+ pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
+ pRootName++; /* remove leading backslash */
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: Root name = %.*ls\n", RootNameLength / sizeof(WCHAR), pRootName));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsLabelInformation: Prefix %ls has %d elements\n", VBOX_VOLNAME_PREFIX, RT_ELEMENTS(VBOX_VOLNAME_PREFIX)));
+
+ pLabelInfo->VolumeLabelLength = RootNameLength + VBOX_VOLNAME_PREFIX_SIZE;
+ RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabel[0]);
+
+ if (RxContext->Info.LengthRemaining >= (LONG)pLabelInfo->VolumeLabelLength)
+ {
+ BytesToCopy = pLabelInfo->VolumeLabelLength;
+
+ /* Copy prefix */
+ RtlCopyMemory( &pLabelInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE);
+
+ /* Copy share name (- 1 for zero terminator) */
+ RtlCopyMemory( &pLabelInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, RootNameLength );
+ }
+ else
+ {
+ BytesToCopy = RxContext->Info.LengthRemaining;
+
+ /* Copy prefix */
+ RtlCopyMemory( &pLabelInfo->VolumeLabel[0], (PVOID)VBOX_VOLNAME_PREFIX, RT_MIN(BytesToCopy, VBOX_VOLNAME_PREFIX_SIZE) );
+
+ if (BytesToCopy > VBOX_VOLNAME_PREFIX_SIZE)
+ {
+ /* Copy share name (- 1 for zero terminator) */
+ RtlCopyMemory( &pLabelInfo->VolumeLabel[RT_ELEMENTS(VBOX_VOLNAME_PREFIX) - 1], (PVOID)pRootName, BytesToCopy - VBOX_VOLNAME_PREFIX_SIZE );
+ }
+ }
+ RxContext->Info.LengthRemaining -= BytesToCopy;
+ pLabelInfo->VolumeLabelLength = BytesToCopy;
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case FileFsFullSizeInformation:
+ case FileFsSizeInformation:
+ {
+ PFILE_FS_FULL_SIZE_INFORMATION pFullSizeInfo = (PFILE_FS_FULL_SIZE_INFORMATION)OriginalBuffer;
+ PFILE_FS_SIZE_INFORMATION pSizeInfo = (PFILE_FS_SIZE_INFORMATION)OriginalBuffer;
+ uint32_t cbHGCMBuffer;
+ uint8_t *pHGCMBuffer = NULL;
+ int vboxRC;
+ PSHFLVOLINFO pVolInfo;
+
+ if (FsInformationClass == FileFsFullSizeInformation)
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining));
+ BytesToCopy = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: OriginalBuffer = %p, LenRemaining = %d\n", OriginalBuffer, RxContext->Info.LengthRemaining));
+ BytesToCopy = sizeof(FILE_FS_SIZE_INFORMATION);
+ }
+
+ if (RxContext->Info.LengthRemaining < (LONG)BytesToCopy)
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation/FileFsSizeInformation: Insufficient buffer size (%d)!\n", RxContext->Info.LengthRemaining));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ if (NULL == pVBoxFobx)
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: pVBoxFobx is invalid!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ RtlZeroMemory( pSizeInfo, BytesToCopy );
+
+ cbHGCMBuffer = sizeof(SHFLVOLINFO);
+ pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+ if (pHGCMBuffer == 0)
+ {
+ AssertFailed();
+ Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
+ AssertRC(vboxRC);
+
+ if (vboxRC != VINF_SUCCESS)
+ {
+ Status = VBoxErrorToNTStatus(vboxRC);
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+ break;
+ }
+
+ pVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
+
+ if (FsInformationClass == FileFsFullSizeInformation)
+ {
+ pFullSizeInfo->SectorsPerAllocationUnit = pVolInfo->ulBytesPerAllocationUnit / pVolInfo->ulBytesPerSector;
+ pFullSizeInfo->BytesPerSector = pVolInfo->ulBytesPerSector;
+ pFullSizeInfo->ActualAvailableAllocationUnits.QuadPart = pVolInfo->ullAvailableAllocationBytes / pVolInfo->ulBytesPerAllocationUnit;
+ pFullSizeInfo->CallerAvailableAllocationUnits.QuadPart = pFullSizeInfo->ActualAvailableAllocationUnits.QuadPart;
+ pFullSizeInfo->TotalAllocationUnits.QuadPart = pVolInfo->ullTotalAllocationBytes / pVolInfo->ulBytesPerAllocationUnit;
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: SectorsPerAllocationUnit %08x\n", (ULONG)pFullSizeInfo->SectorsPerAllocationUnit));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: BytesPerSector %08x\n", (ULONG)pFullSizeInfo->BytesPerSector));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: ActualAvailableAllocationUnits %RX64\n", pFullSizeInfo->ActualAvailableAllocationUnits.QuadPart));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsFullSizeInformation: TotalAllocationUnits %RX64\n", pFullSizeInfo->TotalAllocationUnits.QuadPart));
+ }
+ else
+ {
+ pSizeInfo->SectorsPerAllocationUnit = pVolInfo->ulBytesPerAllocationUnit / pVolInfo->ulBytesPerSector;
+ pSizeInfo->BytesPerSector = pVolInfo->ulBytesPerSector;
+ pSizeInfo->AvailableAllocationUnits.QuadPart = pVolInfo->ullAvailableAllocationBytes / pVolInfo->ulBytesPerAllocationUnit;
+ pSizeInfo->TotalAllocationUnits.QuadPart = pVolInfo->ullTotalAllocationBytes / pVolInfo->ulBytesPerAllocationUnit;
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: SectorsPerAllocationUnit %08x\n", (ULONG)pSizeInfo->SectorsPerAllocationUnit));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: BytesPerSector %08x\n", (ULONG)pSizeInfo->BytesPerSector));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: AvailableAllocationUnits %RX64\n", pSizeInfo->AvailableAllocationUnits.QuadPart));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsSizeInformation: TotalAllocationUnits %RX64\n", pSizeInfo->TotalAllocationUnits.QuadPart));
+ }
+
+ if (pHGCMBuffer)
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+
+ RxContext->Info.LengthRemaining -= BytesToCopy;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case FileFsDeviceInformation:
+ {
+ PFILE_FS_DEVICE_INFORMATION pDevInfo = (PFILE_FS_DEVICE_INFORMATION)OriginalBuffer;
+ PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsDeviceInformation: Type = 0x%x\n", NetRoot->DeviceType));
+ Status = STATUS_SUCCESS;
+
+ BytesToCopy = sizeof(FILE_FS_DEVICE_INFORMATION);
+ if (RxContext->Info.LengthRemaining >= (LONG)BytesToCopy)
+ {
+ pDevInfo->DeviceType = NetRoot->DeviceType;
+ pDevInfo->Characteristics = FILE_REMOTE_DEVICE;
+
+ if (NetRoot->Type == NET_ROOT_PIPE)
+ {
+ NetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ RxContext->Info.LengthRemaining -= BytesToCopy;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsDeviceInformation: Buffer too small (%d vs %d)!\n", RxContext->Info.LengthRemaining, BytesToCopy));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileFsAttributeInformation:
+ {
+ PFILE_FS_ATTRIBUTE_INFORMATION pAttribInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)OriginalBuffer;
+
+ BytesToCopy = sizeof(MRX_VBOX_FILESYS_NAME_U) + FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0]);
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsAttributeInformation: BytesToCopy = %d\n", BytesToCopy));
+ if (RxContext->Info.LengthRemaining < (LONG)BytesToCopy)
+ {
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsAttributeInformation: Buffer too small (%d)!\n", RxContext->Info.LengthRemaining));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ /** @todo set unicode, case sensitive etc? */
+ pAttribInfo->FileSystemAttributes = 0;
+ 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, pAttribInfo->FileSystemNameLength);
+
+ RxContext->Info.LengthRemaining -= BytesToCopy;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case FileFsControlInformation:
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsControlInformation (skipping ...)\n"));
+ break;
+
+ case FileFsObjectIdInformation:
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsObjectIdInformation (skipping ...)\n"));
+ break;
+
+ case FileFsMaximumInformation:
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: FileFsMaximumInformation (skipping ...)\n"));
+ break;
+
+ default:
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: Invalid parameter!\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformationWithFullBuffer: Returned 0x%x\n", Status));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxQueryVolumeInformation (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine queries the volume information. Since the NT server does not
+ handle bufferoverflow gracefully on query-fs-info, we allocate a buffer here
+ that is big enough to hold anything passed back; then we call the "real"
+ queryvolinfo routine.
+
+ Arguments:
+
+ pRxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PVOID OriginalBuffer = RxContext->Info.Buffer;
+ ULONG OriginalLength = RxContext->Info.LengthRemaining;
+ ULONG ReturnedLength;
+
+ BOOLEAN UsingSideBuffer = FALSE;
+ uint32_t cbSideBuffer = 0;
+
+ typedef struct
+ {
+ union
+ {
+ FILE_FS_LABEL_INFORMATION labelinfo;
+ FILE_FS_VOLUME_INFORMATION volumeinfo;
+ FILE_FS_SIZE_INFORMATION sizeinfo;
+ FILE_FS_DEVICE_INFORMATION deviceinfo;
+ FILE_FS_ATTRIBUTE_INFORMATION attributeinfo;
+ } Info;
+ WCHAR VolumeName[MAXIMUM_FILENAME_LENGTH];
+ } SideBuffer;
+
+ SideBuffer *pSideBuffer = NULL;
+
+ PAGED_CODE();
+
+ Log(
+ ("VBOXSF: VBoxMRxQueryVolumeInformation: rxContextBufferAddr = 0x%x, rxContextBufferLengthRem = %d, (SideBufferSize = %d)\n", RxContext->Info.Buffer, RxContext->Info.LengthRemaining, sizeof(SideBuffer)));
+ if (RxContext->Info.LengthRemaining < sizeof(SideBuffer))
+ {
+ /* I replace the buffer and length in the context with my stuff. */
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformation: Using Sidebuffer ...\n"));
+ UsingSideBuffer = TRUE;
+ RxContext->Info.Buffer = vbsfAllocNonPagedMem(sizeof(SideBuffer));
+ pSideBuffer = (SideBuffer *)RxContext->Info.Buffer;
+ RxContext->Info.LengthRemaining = sizeof(SideBuffer);
+ }
+
+ Status = VBoxMRxQueryVolumeInformationWithFullBuffer(RxContext);
+ Assert(Status != STATUS_PENDING);
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformation: RxContext->Info.LengthRemaining = %d\n", RxContext->Info.LengthRemaining));
+
+ if (Status != STATUS_SUCCESS)
+ {
+ RxContext->Info.Buffer = OriginalBuffer;
+ RxContext->Info.LengthRemaining = OriginalLength;
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformation: VBoxMRxQueryVolumeInformationWithFullBuffer failed with 0x%x\n", Status));
+ goto FINALLY;
+ }
+
+ if (UsingSideBuffer == TRUE)
+ {
+ ReturnedLength = sizeof(SideBuffer) - RxContext->Info.LengthRemaining;
+ }
+ else
+ {
+ ReturnedLength = OriginalLength - RxContext->Info.LengthRemaining;
+ }
+
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformation: ReturnedLength = %d, OriginalLength = %d\n", ReturnedLength, OriginalLength));
+ if (ReturnedLength > OriginalLength)
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ ReturnedLength = OriginalLength;
+ }
+
+ if (UsingSideBuffer == TRUE)
+ {
+ RtlCopyMemory(OriginalBuffer, pSideBuffer, ReturnedLength);
+ }
+
+ RxContext->Info.Buffer = OriginalBuffer;
+ RxContext->Info.LengthRemaining = OriginalLength - ReturnedLength;
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformation: OriginalLength = %d, LengthRemaining = %d, Status = 0x%x\n", OriginalLength, RxContext->Info.LengthRemaining, Status));
+ Log(("VBOXSF: VBoxMRxQueryVolumeInformation: Final rxContextBufferAddr = 0x%x, rxContextBufferLengthRem = %d\n", RxContext->Info.Buffer, RxContext->Info.LengthRemaining));
+
+ FINALLY:
+
+ if (NULL != pSideBuffer)
+ vbsfFreeNonPagedMem(pSideBuffer);
+
+ return Status;
+}
+
+NTSTATUS VBoxMRxSetVolumeInformation (IN OUT PRX_CONTEXT pRxContext)
+/*++
+
+ Routine Description:
+
+ This routine sets the volume information
+
+ Arguments:
+
+ pRxContext - the RDBSS context
+
+ FsInformationClass - the kind of Fs information desired.
+
+ pBuffer - the buffer for copying the information
+
+ BufferLength - the buffer length
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+
+ Log(("VBOXSF: VBoxMRxSetVolumeInformation called.\n"));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxQueryFileInformation (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine does a query file info. Only the NT-->NT path is implemented.
+
+ The NT-->NT path works by just remoting the call basically without further ado.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG CopySize = 0;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ FILE_INFORMATION_CLASS FunctionalityRequested = RxContext->Info.FileInformationClass;
+
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+
+ uint8_t *pHGCMBuffer = 0;
+ int vboxRC = 0;
+ uint32_t cbHGCMBuffer, cbMaxSize = 0;
+ PRTFSOBJINFO pFileEntry = NULL;
+ PCHAR pInfoBuffer = NULL;
+ ULONG *pLengthRemaining = NULL;
+
+ pInfoBuffer = (PCHAR)RxContext->Info.Buffer;
+ cbMaxSize = RxContext->Info.Length;
+ pLengthRemaining = (PULONG) & RxContext->Info.LengthRemaining;
+
+ if (NULL == pLengthRemaining)
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Invalid length pointer detected!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: InfoBuffer = 0x%08x, Size = %d bytes, LenRemain = %d bytes\n", pInfoBuffer, cbMaxSize, *pLengthRemaining));
+
+ if (NULL == pVBoxFobx)
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: pVBoxFobx is invalid!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (NULL == pInfoBuffer)
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Invalid information buffer detected!\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (pVBoxFobx->FileStandardInfo.Directory == TRUE)
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Directory -> Copy info retrieved during the create call\n"));
+ Status = STATUS_SUCCESS;
+
+ switch (FunctionalityRequested)
+ {
+
+ case FileBasicInformation:
+ {
+ PFILE_BASIC_INFORMATION pFileInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer;
+ CopySize = sizeof(FILE_BASIC_INFORMATION);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer = 0x%08x\n", pFileInfo));
+ if (*pLengthRemaining >= CopySize)
+ {
+ *pFileInfo = pVBoxFobx->FileBasicInfo;
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: File attributes: 0x%x\n", pFileInfo->FileAttributes));
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileStandardInformation:
+ {
+ PFILE_STANDARD_INFORMATION pFileInfo = (PFILE_STANDARD_INFORMATION)pInfoBuffer;
+ CopySize = sizeof(FILE_STANDARD_INFORMATION);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer = 0x%08x\n", pFileInfo));
+ if (*pLengthRemaining >= CopySize)
+ {
+ *pFileInfo = pVBoxFobx->FileStandardInfo;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileNamesInformation:
+ {
+ PFILE_NAMES_INFORMATION pFileInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
+ CopySize = sizeof(FILE_NAMES_INFORMATION);
+
+ /* Struct already contains one char for null terminator. */
+ CopySize += (FileName->Length + 1) * sizeof(WCHAR);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer = %08x\n", pFileInfo));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory (pFileInfo, CopySize);
+
+ pFileInfo->FileIndex = 0;
+ pFileInfo->FileNameLength = FileName->Length * sizeof(WCHAR);
+ RtlCopyMemory(pFileInfo->FileName, FileName->Buffer, pFileInfo->FileNameLength);
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileInternalInformation:
+ {
+ PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pInfoBuffer;
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer = 0x%08x\n", pInfoBuffer));
+
+ /*
+ * Note: We use the address of the FCB to determine the
+ * index number of the file. If we have to maintain persistance between
+ * file opens for this request, then we might have to do something
+ * like checksuming the reserved fields on a FUNIQUE SMB response.
+ *
+
+ *
+ * NT64: the address of capFcb used to be stuffed into
+ * IndexNumber.LowPart, with HighPart being zeroed.
+ *
+ * Whoever is asking for this pointer value should be
+ * prepared to deal with the returned 64-bit value.
+ */
+
+ CopySize = sizeof(FILE_INTERNAL_INFORMATION);
+
+ if (*pLengthRemaining >= CopySize)
+ {
+ UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer overflow (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+ case FileEaInformation:
+ {
+ PFILE_EA_INFORMATION EaBuffer = (PFILE_EA_INFORMATION)pInfoBuffer;
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer = 0x%08x\n", pInfoBuffer));
+
+ CopySize = sizeof(FILE_EA_INFORMATION);
+ if (*pLengthRemaining >= CopySize)
+ {
+ EaBuffer->EaSize = 0;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer overflow (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileNetworkOpenInformation:
+ {
+ PFILE_NETWORK_OPEN_INFORMATION pFileInfo = (PFILE_NETWORK_OPEN_INFORMATION)pInfoBuffer;
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer = 0x%08x\n", pInfoBuffer));
+
+ CopySize = sizeof(FILE_NETWORK_OPEN_INFORMATION);
+ if (*pLengthRemaining >= CopySize)
+ {
+ pFileInfo->CreationTime = pVBoxFobx->FileBasicInfo.CreationTime;
+ pFileInfo->LastAccessTime = pVBoxFobx->FileBasicInfo.LastAccessTime;
+ pFileInfo->LastWriteTime = pVBoxFobx->FileBasicInfo.LastWriteTime;
+ pFileInfo->ChangeTime = pVBoxFobx->FileBasicInfo.ChangeTime;
+ pFileInfo->AllocationSize.QuadPart = 0; /* This is a directory, attribute not needed. */
+ pFileInfo->EndOfFile.QuadPart = 0; /* This is a directory, attribute not needed. */
+ pFileInfo->FileAttributes = pVBoxFobx->FileBasicInfo.FileAttributes;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ default:
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Invalid filesystem information class %d!\n", FunctionalityRequested));
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto end;
+ }
+ }
+ else /* Entry is a file. */
+ {
+ cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE);
+ pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbHGCMBuffer);
+
+ if (pHGCMBuffer == 0)
+ return STATUS_NO_MEMORY;
+
+ 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 = (PRTFSOBJINFO)pHGCMBuffer;
+ Status = STATUS_SUCCESS;
+
+ switch (FunctionalityRequested)
+ {
+
+ case FileBasicInformation:
+ {
+ PFILE_BASIC_INFORMATION pFileInfo = (PFILE_BASIC_INFORMATION)pInfoBuffer;
+ CopySize = sizeof(FILE_BASIC_INFORMATION);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer = 0x%08x\n", pInfoBuffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ pFileInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->BirthTime); /* Ridiculous name. */
+ pFileInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->AccessTime);
+ pFileInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ModificationTime);
+ pFileInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ChangeTime);
+
+ pFileInfo->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode);
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: File attributes = 0x%x\n", pFileInfo->FileAttributes));
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileBasicInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileStandardInformation:
+ {
+ PFILE_STANDARD_INFORMATION pFileInfo = (PFILE_STANDARD_INFORMATION)pInfoBuffer;
+ CopySize = sizeof(FILE_STANDARD_INFORMATION);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer = 0x%08x\n", pInfoBuffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ pFileInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated;
+ pFileInfo->EndOfFile.QuadPart = pFileEntry->cbObject;
+
+ pFileInfo->NumberOfLinks = 1; /* @todo 0? */
+ pFileInfo->DeletePending = FALSE;
+
+ if (pFileEntry->Attr.fMode & RTFS_DOS_DIRECTORY)
+ pFileInfo->Directory = TRUE;
+ else pFileInfo->Directory = FALSE;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileStandardInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileNamesInformation:
+ {
+ PFILE_NAMES_INFORMATION pFileInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
+
+ CopySize = sizeof(FILE_NAMES_INFORMATION);
+
+ /* Struct already contains one char for null terminator */
+ CopySize += (FileName->Length + 1) * sizeof(WCHAR);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer = 0x%08x\n", pInfoBuffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ RtlZeroMemory (pFileInfo, CopySize);
+
+ pFileInfo->FileIndex = 0;
+ pFileInfo->FileNameLength = FileName->Length * sizeof(WCHAR);
+ RtlCopyMemory(pFileInfo->FileName, FileName->Buffer, pFileInfo->FileNameLength);
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNamesInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileInternalInformation:
+ {
+ PFILE_INTERNAL_INFORMATION UsersBuffer = (PFILE_INTERNAL_INFORMATION)pInfoBuffer;
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer = 0x%08x\n", pInfoBuffer));
+
+ /* Note: We use the address of the FCB to determine the
+ index number of the file. If we have to maintain persistance between
+ file opens for this request, then we might have to do something
+ like checksuming the reserved fields on a FUNIQUE SMB response.
+
+ NT64: the address of capFcb used to be stuffed into
+ IndexNumber.LowPart, with HighPart being zeroed.
+
+ Whoever is asking for this pointer value should be
+ prepared to deal with the returned 64-bit value. */
+ CopySize = sizeof(FILE_INTERNAL_INFORMATION);
+
+ if (*pLengthRemaining >= CopySize)
+ {
+ UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileInternalInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileEaInformation:
+ {
+ PFILE_EA_INFORMATION EaBuffer = (PFILE_EA_INFORMATION)pInfoBuffer;
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer = 0x%08x\n", pInfoBuffer));
+ CopySize = sizeof(FILE_EA_INFORMATION);
+
+ if (*pLengthRemaining >= CopySize)
+ {
+ EaBuffer->EaSize = 0;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEaInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileAttributeTagInformation:
+ {
+ PFILE_ATTRIBUTE_TAG_INFORMATION pAttrTag = (PFILE_ATTRIBUTE_TAG_INFORMATION)pInfoBuffer;
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAttributeTagInformation: Buffer = 0x%08x\n", pInfoBuffer));
+ CopySize = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
+ if (*pLengthRemaining >= CopySize)
+ {
+ pAttrTag->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode);
+ pAttrTag->ReparseTag = 0;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAttributeTagInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileEndOfFileInformation:
+ {
+ PFILE_END_OF_FILE_INFORMATION pEndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)pInfoBuffer;
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEndOfFileInformation: Buffer = %08x\n", pInfoBuffer));
+
+ CopySize = sizeof(FILE_END_OF_FILE_INFORMATION);
+ if (*pLengthRemaining >= CopySize)
+ {
+ pEndOfFileInfo->EndOfFile.QuadPart = pFileEntry->cbObject;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileEndOfFileInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileAllocationInformation:
+ {
+ PFILE_ALLOCATION_INFORMATION pAllocInfo = (PFILE_ALLOCATION_INFORMATION)pInfoBuffer;
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAllocationInformation: Buffer = 0x%08x\n", pInfoBuffer));
+
+ CopySize = sizeof(FILE_ALLOCATION_INFORMATION);
+ if (*pLengthRemaining >= CopySize)
+ {
+ pAllocInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileAllocationInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ case FileNetworkOpenInformation:
+ {
+ PFILE_NETWORK_OPEN_INFORMATION pFileInfo = (PFILE_NETWORK_OPEN_INFORMATION)pInfoBuffer;
+ CopySize = sizeof(FILE_NETWORK_OPEN_INFORMATION);
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer = 0x%08x\n", pInfoBuffer));
+ if (*pLengthRemaining >= CopySize)
+ {
+ pFileInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->BirthTime); /* Ridiculous name. */
+ pFileInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->AccessTime);
+ pFileInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ModificationTime);
+ pFileInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pFileEntry->ChangeTime);
+ pFileInfo->AllocationSize.QuadPart = pFileEntry->cbAllocated;
+ pFileInfo->EndOfFile.QuadPart = pFileEntry->cbObject;
+ pFileInfo->FileAttributes = VBoxToNTFileAttributes(pFileEntry->Attr.fMode);
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: FileNetworkOpenInformation: Buffer too small (%d vs %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+ default:
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Unknown functionality requested (0x%x)!\n", FunctionalityRequested));
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto end;
+ }
+ }
+
+ if (Status == STATUS_SUCCESS)
+ {
+ if (*pLengthRemaining < CopySize)
+ {
+ /* This situation must be already taken into account by the above code. */
+ AssertMsgFailed(("VBOXSF: VBoxMRxQueryFileInformation: Length remaing is below 0! (%d - %d)!\n", *pLengthRemaining, CopySize));
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ pInfoBuffer += CopySize;
+ *pLengthRemaining -= CopySize;
+ }
+ }
+
+ end: if (Status == STATUS_BUFFER_TOO_SMALL)
+ RxContext->InformationToReturn = CopySize;
+
+ if (pHGCMBuffer)
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+
+ if (Status == STATUS_SUCCESS)
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Success! Remaining length = %d\n", *pLengthRemaining));
+
+ Log(("VBOXSF: VBoxMRxQueryFileInformation: Returned 0x%x\n", Status));
+ return Status;
+}
+
+NTSTATUS VBoxMRxSetFileInformation (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine does a set file info. Only the NT-->NT path is implemented.
+
+ The NT-->NT path works by just remoting the call basically without further ado.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot, pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ FILE_INFORMATION_CLASS FunctionalityRequested = RxContext->Info.FileInformationClass;
+ PVOID pBuffer = (PVOID)RxContext->Info.Buffer;
+ uint8_t *pHGCMBuffer = 0;
+ uint32_t cbBuffer = 0;
+ int vboxRC;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation called.\n"));
+
+ switch (FunctionalityRequested)
+ {
+ case FileBasicInformation:
+ {
+ PFILE_BASIC_INFORMATION pFileInfo = (PFILE_BASIC_INFORMATION)pBuffer;
+ PRTFSOBJINFO pSHFLFileInfo;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: CreationTime %RX64\n", pFileInfo->CreationTime.QuadPart));
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: LastAccessTime %RX64\n", pFileInfo->LastAccessTime.QuadPart));
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: LastWriteTime %RX64\n", pFileInfo->LastWriteTime.QuadPart));
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: ChangeTime %RX64\n", pFileInfo->ChangeTime.QuadPart));
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileBasicInformation: FileAttributes %RX32\n", pFileInfo->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 (pFileInfo->CreationTime.QuadPart == -1)
+ {
+ pVBoxFobx->fKeepCreationTime = TRUE;
+ }
+ if (pFileInfo->LastAccessTime.QuadPart == -1)
+ {
+ pVBoxFobx->fKeepLastAccessTime = TRUE;
+ }
+ if (pFileInfo->LastWriteTime.QuadPart == -1)
+ {
+ pVBoxFobx->fKeepLastWriteTime = TRUE;
+ }
+ if (pFileInfo->ChangeTime.QuadPart == -1)
+ {
+ pVBoxFobx->fKeepChangeTime = TRUE;
+ }
+
+ cbBuffer = sizeof(RTFSOBJINFO);
+ pHGCMBuffer = (uint8_t *)vbsfAllocNonPagedMem(cbBuffer);
+ if (pHGCMBuffer == 0)
+ {
+ AssertFailed();
+ return STATUS_NO_MEMORY;
+ }
+ RtlZeroMemory(pHGCMBuffer, cbBuffer);
+ pSHFLFileInfo = (PRTFSOBJINFO)pHGCMBuffer;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: 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 (pFileInfo->CreationTime.QuadPart && !pVBoxFobx->fKeepCreationTime)
+ RTTimeSpecSetNtTime(&pSHFLFileInfo->BirthTime, pFileInfo->CreationTime.QuadPart);
+ if (pFileInfo->LastAccessTime.QuadPart && !pVBoxFobx->fKeepLastAccessTime)
+ RTTimeSpecSetNtTime(&pSHFLFileInfo->AccessTime, pFileInfo->LastAccessTime.QuadPart);
+ if (pFileInfo->LastWriteTime.QuadPart && !pVBoxFobx->fKeepLastWriteTime)
+ RTTimeSpecSetNtTime(&pSHFLFileInfo->ModificationTime, pFileInfo->LastWriteTime.QuadPart);
+ if (pFileInfo->ChangeTime.QuadPart && !pVBoxFobx->fKeepChangeTime)
+ RTTimeSpecSetNtTime(&pSHFLFileInfo->ChangeTime, pFileInfo->ChangeTime.QuadPart);
+ if (pFileInfo->FileAttributes)
+ pSHFLFileInfo->Attr.fMode = NTToVBoxFileAttributes(pFileInfo->FileAttributes);
+
+ Assert(pVBoxFobx && pNetRootExtension && pDeviceExtension);
+ vboxRC = vboxCallFSInfo(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer, (PSHFLDIRINFO)pSHFLFileInfo);
+ AssertRC(vboxRC);
+
+ if (vboxRC != VINF_SUCCESS)
+ {
+ Status = VBoxErrorToNTStatus(vboxRC);
+ goto end;
+ }
+ else
+ {
+ /* Update our internal copy */
+ pVBoxFobx->FileBasicInfo = *pFileInfo;
+ }
+
+ break;
+ }
+
+ case FileDispositionInformation:
+ {
+ PFILE_DISPOSITION_INFORMATION pDispInfo = (PFILE_DISPOSITION_INFORMATION)pBuffer;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileDispositionInformation: Delete = %d\n", pDispInfo->DeleteFile));
+ if (pDispInfo->DeleteFile && capFcb->OpenCount == 1)
+ Status = VBoxMRxRemove(RxContext);
+ else Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case FilePositionInformation:
+ {
+ PFILE_POSITION_INFORMATION pPosInfo = (PFILE_POSITION_INFORMATION)pBuffer;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FilePositionInformation: CurrentByteOffset = %RX64\n", pPosInfo->CurrentByteOffset.QuadPart));
+
+ /* Unsupported */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ case FileAllocationInformation:
+ {
+ PFILE_ALLOCATION_INFORMATION pAllocInfo = (PFILE_ALLOCATION_INFORMATION)pBuffer;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileAllocationInformation: AllocSize = %RX64\n", pAllocInfo->AllocationSize.QuadPart));
+
+ /* Pretend success */
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case FileEndOfFileInformation:
+ {
+ PFILE_END_OF_FILE_INFORMATION pEndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)pBuffer;
+ LARGE_INTEGER NewAllocationSize;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileEndOfFileInformation: FileSize = %RX64\n", capFcb->Header.AllocationSize.QuadPart));
+ if (pEndOfFileInfo->EndOfFile.QuadPart > capFcb->Header.AllocationSize.QuadPart)
+ {
+ Status = VBoxMRxExtendFile(RxContext, &pEndOfFileInfo->EndOfFile, &NewAllocationSize);
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: FileEndOfFileInformation: AllocSize = %d AllocSizeHigh = %d\n", NewAllocationSize.LowPart, NewAllocationSize.HighPart));
+
+ //
+ // Change the file allocation
+ //
+ capFcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
+ }
+ else
+ {
+ Status = VBoxMRxSetEndOfFile(RxContext, &pEndOfFileInfo->EndOfFile, &NewAllocationSize);
+ }
+ /** @todo is this really necessary? */
+ RxContext->Info.LengthRemaining -= sizeof(FILE_END_OF_FILE_INFORMATION);
+ break;
+ }
+
+ case FileLinkInformation:
+ {
+ PFILE_RENAME_INFORMATION pRenameInfo = (PFILE_RENAME_INFORMATION)pBuffer;
+
+ Log(
+ ("VBOXSF: VBoxMRxSetFileInformation: FileLinkInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = %.*ls\n", pRenameInfo->ReplaceIfExists, pRenameInfo->RootDirectory, pRenameInfo->FileNameLength
+ / sizeof(WCHAR), pRenameInfo->FileName));
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ case FileRenameInformation:
+ {
+ PFILE_RENAME_INFORMATION pRenameInfo = (PFILE_RENAME_INFORMATION)pBuffer;
+
+ Log(
+ ("VBOXSF: VBoxMRxSetFileInformation: FileRenameInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = %.*ls\n", pRenameInfo->ReplaceIfExists, pRenameInfo->RootDirectory, pRenameInfo->FileNameLength
+ / sizeof(WCHAR), pRenameInfo->FileName));
+ Status = VBoxMRxRename(RxContext, FileRenameInformation, pBuffer, RxContext->Info.Length);
+ break;
+ }
+
+ default:
+ Log(("VBOXSF: VBoxMRxSetFileInformation: Unknown functionality requested (0x%x)!\n", FunctionalityRequested));
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ end:
+
+ if (pHGCMBuffer)
+ vbsfFreeNonPagedMem(pHGCMBuffer);
+
+ Log(("VBOXSF: VBoxMRxSetFileInformation: Returned 0x%x\n", Status));
+ return Status;
+}
+
+NTSTATUS VBoxMRxSetFileInformationAtCleanup (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine sets the file information on cleanup. the old rdr just swallows this operation (i.e.
+ it doesn't generate it). we are doing the same..........
+
+ Arguments:
+
+ pRxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+
+ Log(("VBOXSF: VBoxMRxSetFileInformationAtCleanup\n"));
+ return (Status);
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c
new file mode 100644
index 00000000000..01f5188b724
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/init.c
@@ -0,0 +1,1771 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ Init.c
+
+ Abstract:
+
+ This module implements the DRIVER_INITIALIZATION routine for
+ the null mini rdr.
+
+ --*/
+
+#include "precomp.h"
+#include "rdbss_vbox.h"
+#pragma hdrstop
+
+#include "ntverp.h"
+#include "nulmrx.h"
+
+#ifdef VBOX
+#include "VBoxGuestR0LibSharedFolders.h"
+
+#if defined(DEBUG) || defined (LOG_ENABLED)
+static PCHAR MajorFunctionString(UCHAR MajorFunction, LONG MinorFunction);
+#endif
+#endif
+
+//
+// Global data declarations.
+//
+
+MRX_VBOX_STATE VBoxMRxState = MRX_VBOX_STARTABLE;
+
+//
+// Mini Redirector global variables.
+//
+
+//
+// LogRate
+//
+ULONG LogRate = 0;
+
+//
+// This is the minirdr dispatch table. It is initialized by
+// VBoxMRxInitializeTables. This table will be used by the wrapper to call
+// into this minirdr
+//
+
+struct _MINIRDR_DISPATCH VBoxMRxDispatch;
+
+//
+// Pointer to the device Object for this minirdr. Since the device object is
+// created by the wrapper when this minirdr registers, this pointer is
+// initialized in the DriverEntry routine below (see RxRegisterMinirdr)
+//
+
+PRDBSS_DEVICE_OBJECT VBoxMRxDeviceObject;
+
+#define VBOX_SF_STATIC_LIB
+
+//
+// declare the shadow debugtrace controlpoints
+//
+
+RXDT_DefineCategory (CREATE);
+RXDT_DefineCategory (CLEANUP);
+RXDT_DefineCategory (CLOSE);
+RXDT_DefineCategory (READ);
+RXDT_DefineCategory (WRITE);
+RXDT_DefineCategory (LOCKCTRL);
+RXDT_DefineCategory (FLUSH);
+RXDT_DefineCategory (PREFIX);
+RXDT_DefineCategory (FCBSTRUCTS);
+RXDT_DefineCategory (DISPATCH);
+RXDT_DefineCategory (EA);
+RXDT_DefineCategory (DEVFCB);
+RXDT_DefineCategory (INIT);
+
+//
+// The following enumerated values signify the current state of the minirdr
+// initialization. With the aid of this state information, it is possible
+// to determine which resources to deallocate, whether deallocation comes
+// as a result of a normal stop/unload, or as the result of an exception
+//
+
+typedef enum _MRX_VBOX_INIT_STATES
+{
+ MRX_VBOXINIT_UNINT, MRX_VBOXINIT_ALL_INITIALIZATION_COMPLETED, MRX_VBOXINIT_MINIRDR_REGISTERED, MRX_VBOXINIT_START
+} MRX_VBOX_INIT_STATES;
+
+//
+// function prototypes
+//
+
+NTSTATUS VBoxMRxInitializeTables (void);
+
+VOID VBoxMRxUnload (IN PDRIVER_OBJECT DriverObject);
+
+VOID VBoxMRxInitUnwind (IN PDRIVER_OBJECT DriverObject, IN MRX_VBOX_INIT_STATES VBoxMRxInitState);
+
+NTSTATUS VBoxMRxFsdDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+
+VOID VBoxMRxReadRegistryParameters ();
+
+#ifdef VBOX
+static int
+vboxCtlGuestFilterMask (uint32_t u32OrMask, uint32_t u32NotMask)
+{
+ int rc;
+ VMMDevCtlGuestFilterMask *req;
+
+ rc = VbglGRAlloc ((VMMDevRequestHeader**) &req, sizeof (*req),
+ VMMDevReq_CtlGuestFilterMask);
+
+ if (RT_FAILURE (rc))
+ {
+ Log (("VBOXSF: vboxCtlGuestFilterMask: "
+ "VbglGRAlloc (CtlGuestFilterMask) failed rc=%Rrc\n", rc));
+ return -1;
+ }
+
+ req->u32OrMask = u32OrMask;
+ req->u32NotMask = u32NotMask;
+
+ rc = VbglGRPerform (&req->header);
+ VbglGRFree (&req->header);
+ if (RT_FAILURE (rc))
+ {
+ Log (("VBOXSF: vboxCtlGuestFilterMask: "
+ "VbglGRPerform (CtlGuestFilterMask) failed rc=%Rrc\n", rc));
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+static PFAST_IO_DISPATCH pfnRDBSSTable = NULL;
+
+BOOLEAN VBoxMrxFastIoRead (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+#ifdef VBOX_FAIL_FASTIO
+ Log(("VBOXSF: VBoxMrxFastIoRead\n"));
+ IoStatus->Information = 0;
+ IoStatus->Status = STATUS_NOT_IMPLEMENTED;
+ return FALSE;
+#else
+ BOOLEAN ret = FALSE;
+
+ Log(("VBOXSF: VBoxMrxFastIoRead: FileObject = 0x%x, QuadPart = %RX64, Len = %d, Buffer = 0x%x\n", FileObject, FileOffset->QuadPart, Length, Buffer));
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoRead)
+ {
+ /* Necessary to satisfy the driver verifier. APCs must be turned off when ExAcquireResourceExclusiveLite is called */
+ FsRtlEnterFileSystem();
+ ret = pfnRDBSSTable->FastIoRead(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
+ FsRtlExitFileSystem();
+ }
+
+ Log(("VBOXSF: VBoxMrxFastIoRead: Returned 0x%x\n", ret));
+ return ret;
+#endif /* !VBOX_FAIL_FASTIO */
+}
+
+BOOLEAN VBoxMrxFastIoWrite (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+#ifdef VBOX_FAIL_FASTIO
+ Log(("VBOXSF: VBoxMrxFastIoWrite\n"));
+ IoStatus->Information = 0;
+ IoStatus->Status = STATUS_NOT_IMPLEMENTED;
+ return FALSE;
+#else
+ BOOLEAN ret = FALSE;
+
+ Log(("VBOXSF: VBoxMrxFastIoWrite: FileObject = 0x%x, QuadPart = %RX64, Len = %d, Buffer = 0x%x\n", FileObject, FileOffset->QuadPart, Length, Buffer));
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoWrite)
+ {
+ /* Necessary to satisfy the driver verifier. APCs must be turned off when ExAcquireResourceExclusiveLite is called */
+ FsRtlEnterFileSystem();
+ ret = pfnRDBSSTable->FastIoWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
+ FsRtlExitFileSystem();
+ }
+
+ Log(("VBOXSF: VBoxMrxFastIoWrite: Returned 0x%x\n", ret));
+ return ret;
+#endif /* !VBOX_FAIL_FASTIO */
+}
+
+BOOLEAN VBoxMrxFastIoCheckIfPossible (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN BOOLEAN CheckForReadOperation,
+ OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoCheckIfPossible)
+ {
+ ret = pfnRDBSSTable->FastIoCheckIfPossible(FileObject, FileOffset, Length, Wait, LockKey, CheckForReadOperation, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoCheckIfPossible: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoQueryBasicInfo (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, OUT PFILE_BASIC_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryBasicInfo)
+ {
+ ret = pfnRDBSSTable->FastIoQueryBasicInfo(FileObject, Wait, Buffer, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoQueryBasicInfo: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoQueryStandardInfo (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, OUT PFILE_STANDARD_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryStandardInfo)
+ {
+ ret = pfnRDBSSTable->FastIoQueryStandardInfo(FileObject, Wait, Buffer, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoQueryStandardInfo: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoLock (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock,
+ OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoLock)
+ {
+ ret = pfnRDBSSTable->FastIoLock(FileObject, FileOffset, Length, ProcessId, Key, FailImmediately, ExclusiveLock, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoLock: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoUnlockSingle (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoUnlockSingle)
+ {
+ ret = pfnRDBSSTable->FastIoUnlockSingle(FileObject, FileOffset, Length, ProcessId, Key, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoUnlockSingle: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoUnlockAll (IN struct _FILE_OBJECT *FileObject, PEPROCESS ProcessId, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoUnlockAll)
+ {
+ ret = pfnRDBSSTable->FastIoUnlockAll(FileObject, ProcessId, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoUnlockAll: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoUnlockAllByKey (IN struct _FILE_OBJECT *FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoUnlockAllByKey)
+ {
+ ret = pfnRDBSSTable->FastIoUnlockAllByKey(FileObject, ProcessId, Key, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoUnlockAllByKey: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoDeviceControl (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength,
+ IN ULONG IoControlCode, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoDeviceControl)
+ {
+ ret = pfnRDBSSTable->FastIoDeviceControl(FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, IoControlCode, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoDeviceControl: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+VOID VBoxMrxAcquireFileForNtCreateSection (IN struct _FILE_OBJECT *FileObject)
+{
+ if (pfnRDBSSTable && pfnRDBSSTable->AcquireFileForNtCreateSection)
+ {
+ pfnRDBSSTable->AcquireFileForNtCreateSection(FileObject);
+ Log(("VBOXSF: VBoxMrxAcquireFileForNtCreateSection: Called.\n"));
+ }
+}
+
+VOID VBoxMrxReleaseFileForNtCreateSection (IN struct _FILE_OBJECT *FileObject)
+{
+ if (pfnRDBSSTable && pfnRDBSSTable->ReleaseFileForNtCreateSection)
+ {
+ pfnRDBSSTable->ReleaseFileForNtCreateSection(FileObject);
+ Log(("VBOXSF: VBoxMrxReleaseFileForNtCreateSection: Called.\n"));
+ }
+}
+
+VOID VBoxMrxFastIoDetachDevice (IN struct _DEVICE_OBJECT *SourceDevice, IN struct _DEVICE_OBJECT *TargetDevice)
+{
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoDetachDevice)
+ {
+ pfnRDBSSTable->FastIoDetachDevice(SourceDevice, TargetDevice);
+ Log(("VBOXSF: VBoxMrxFastIoDetachDevice: Called.\n"));
+ }
+}
+
+BOOLEAN VBoxMrxFastIoQueryNetworkOpenInfo (IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer, OUT struct _IO_STATUS_BLOCK *IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryNetworkOpenInfo)
+ {
+ ret = pfnRDBSSTable->FastIoQueryNetworkOpenInfo(FileObject, Wait, Buffer, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoQueryNetworkOpenInfo: Called.\n"));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxMdlRead (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->MdlRead)
+ {
+ ret = pfnRDBSSTable->MdlRead(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxMdlRead: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxMdlReadComplete (IN struct _FILE_OBJECT *FileObject, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->MdlReadComplete)
+ {
+ ret = pfnRDBSSTable->MdlReadComplete(FileObject, MdlChain, DeviceObject);
+ Log(("VBOXSF: VBoxMrxMdlReadComplete: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxPrepareMdlWrite (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->PrepareMdlWrite)
+ {
+ ret = pfnRDBSSTable->PrepareMdlWrite(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
+ Log(("VBOXSF: VBoxMrxPrepareMdlWrite: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxMdlWriteComplete (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->MdlWriteComplete)
+ {
+ ret = pfnRDBSSTable->MdlWriteComplete(FileObject, FileOffset, MdlChain, DeviceObject);
+ Log(("VBOXSF: VBoxMrxMdlWriteComplete: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+NTSTATUS VBoxMrxAcquireForModWrite (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER EndingOffset, OUT struct _ERESOURCE **ResourceToRelease, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->AcquireForModWrite)
+ {
+ ret = pfnRDBSSTable->AcquireForModWrite(FileObject, EndingOffset, ResourceToRelease, DeviceObject);
+ Log(("VBOXSF: VBoxMrxAcquireForModWrite: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+NTSTATUS VBoxMrxReleaseForModWrite (IN struct _FILE_OBJECT *FileObject, IN struct _ERESOURCE *ResourceToRelease, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->ReleaseForModWrite)
+ {
+ ret = pfnRDBSSTable->ReleaseForModWrite(FileObject, ResourceToRelease, DeviceObject);
+ Log(("VBOXSF: VBoxMrxReleaseForModWrite: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+NTSTATUS VBoxMrxAcquireForCcFlush (IN struct _FILE_OBJECT *FileObject, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->AcquireForCcFlush)
+ {
+ ret = pfnRDBSSTable->AcquireForCcFlush(FileObject, DeviceObject);
+ Log(("VBOXSF: VBoxMrxAcquireForCcFlush: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+NTSTATUS VBoxMrxReleaseForCcFlush (IN struct _FILE_OBJECT *FileObject, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->ReleaseForCcFlush)
+ {
+ ret = pfnRDBSSTable->ReleaseForCcFlush(FileObject, DeviceObject);
+ Log(("VBOXSF: VBoxMrxReleaseForCcFlush: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoReadCompressed (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PVOID Buffer, OUT PMDL *MdlChain,
+ OUT PIO_STATUS_BLOCK IoStatus, OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo, IN ULONG CompressedDataInfoLength, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoReadCompressed)
+ {
+ ret = pfnRDBSSTable->FastIoReadCompressed(FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus, CompressedDataInfo, CompressedDataInfoLength, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoReadCompressed: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoWriteCompressed (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, IN PVOID Buffer, OUT PMDL *MdlChain,
+ OUT PIO_STATUS_BLOCK IoStatus, IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo, IN ULONG CompressedDataInfoLength, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoWriteCompressed)
+ {
+ ret = pfnRDBSSTable->FastIoWriteCompressed(FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus, CompressedDataInfo, CompressedDataInfoLength, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoWriteCompressed: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxMdlReadCompleteCompressed (IN struct _FILE_OBJECT *FileObject, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->MdlReadCompleteCompressed)
+ {
+ ret = pfnRDBSSTable->MdlReadCompleteCompressed(FileObject, MdlChain, DeviceObject);
+ Log(("VBOXSF: VBoxMrxMdlReadCompleteCompressed: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxMdlWriteCompleteCompressed (IN struct _FILE_OBJECT *FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->MdlWriteCompleteCompressed)
+ {
+ ret = pfnRDBSSTable->MdlWriteCompleteCompressed(FileObject, FileOffset, MdlChain, DeviceObject);
+ Log(("VBOXSF: VBoxMrxMdlWriteCompleteCompressed: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+BOOLEAN VBoxMrxFastIoQueryOpen (IN struct _IRP *Irp, OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, IN struct _DEVICE_OBJECT *DeviceObject)
+{
+ BOOLEAN ret = FALSE;
+
+ if (pfnRDBSSTable && pfnRDBSSTable->FastIoQueryOpen)
+ {
+ ret = pfnRDBSSTable->FastIoQueryOpen(Irp, NetworkInformation, DeviceObject);
+ Log(("VBOXSF: VBoxMrxFastIoQueryOpen: Returned 0x%x\n", ret));
+ }
+ return ret;
+}
+
+
+static FAST_IO_DISPATCH dispatchTable =
+{
+ sizeof(FAST_IO_DISPATCH),
+ VBoxMrxFastIoCheckIfPossible,
+ VBoxMrxFastIoRead,
+ VBoxMrxFastIoWrite,
+ VBoxMrxFastIoQueryBasicInfo,
+ VBoxMrxFastIoQueryStandardInfo,
+ VBoxMrxFastIoLock,
+ VBoxMrxFastIoUnlockSingle,
+ VBoxMrxFastIoUnlockAll,
+ VBoxMrxFastIoUnlockAllByKey,
+ VBoxMrxFastIoDeviceControl,
+ VBoxMrxAcquireFileForNtCreateSection,
+ VBoxMrxReleaseFileForNtCreateSection,
+ VBoxMrxFastIoDetachDevice,
+ VBoxMrxFastIoQueryNetworkOpenInfo,
+ VBoxMrxAcquireForModWrite,
+ VBoxMrxMdlRead,
+ VBoxMrxMdlReadComplete,
+ VBoxMrxPrepareMdlWrite,
+ VBoxMrxMdlWriteComplete,
+ VBoxMrxFastIoReadCompressed,
+ VBoxMrxFastIoWriteCompressed,
+ VBoxMrxMdlReadCompleteCompressed,
+ VBoxMrxMdlWriteCompleteCompressed,
+ VBoxMrxFastIoQueryOpen,
+ VBoxMrxReleaseForModWrite,
+ VBoxMrxAcquireForCcFlush,
+ VBoxMrxReleaseForCcFlush
+};
+
+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;
+}
+
+#if 0
+static BOOL vboxIsPathToIntercept (const WCHAR *FilePathName, ULONG PathNameLength)
+{
+ BOOL PathToIntercept = FALSE;
+
+ /* Detect '\vboxsrv' */
+ if (PathNameLength == 8 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv' unicode string. */
+ {
+ PathToIntercept = TRUE;
+ }
+
+ if (!PathToIntercept)
+ {
+ /* Detect '\vboxsrv\ipc$' */
+ if (PathNameLength >= 13 * sizeof (WCHAR)) /* Number of bytes in '\vboxsrv\ipc$' unicode string. */
+ {
+ const WCHAR *FilePathNameSuffix = &FilePathName[8];
+
+ PathToIntercept = (FilePathNameSuffix[0] == L'\\');
+ PathToIntercept &= (FilePathNameSuffix[1] == L'I') || (FilePathNameSuffix[1] == L'i');
+ PathToIntercept &= (FilePathNameSuffix[2] == L'P') || (FilePathNameSuffix[2] == L'p');
+ PathToIntercept &= (FilePathNameSuffix[3] == L'C') || (FilePathNameSuffix[3] == L'c');
+ PathToIntercept &= (FilePathNameSuffix[4] == L'$') || (FilePathNameSuffix[4] == L'$');
+ if (PathNameLength > 13 * sizeof (WCHAR))
+ {
+ /* There is something after '\vboxsrv\IPC$'. */
+ PathToIntercept &= (FilePathNameSuffix[5] == L'\\') || (FilePathNameSuffix[5] == 0);
+ }
+ }
+ }
+
+ return PathToIntercept;
+}
+#endif
+
+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::VBoxMRXDeviceControl: 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: VBoxMRxDevFcbXXXControlFile: 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: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH: Called (pid %x).\n", IoGetCurrentProcess()));
+
+ if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST))
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: 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: VBoxMRxDevFcbXXXControlFile: PathNameLength = %d.\n", pReq->PathNameLength));
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: SecurityContext = %p.\n", pReq->SecurityContext));
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: FilePathName = %.*ls.\n", pReq->PathNameLength / sizeof (WCHAR), pReq->FilePathName));
+
+ FilePathName = pReq->FilePathName;
+ PathNameLength = pReq->PathNameLength;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: IOCTL_REDIR_QUERY_PATH_EX: Called.\n"));
+
+ if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST_EX))
+ {
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: 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: VBoxMRxDevFcbXXXControlFile: pSecurityContext = %p.\n", pReqEx->pSecurityContext));
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: EaLength = %d.\n", pReqEx->EaLength));
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: pEaBuffer = %p.\n", pReqEx->pEaBuffer));
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: PathNameLength = %d.\n", pReqEx->PathName.Length));
+ Log(("VBOXSF: VBoxMRxDevFcbXXXControlFile: 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::VBoxMRXDeviceControl 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::VBoxMRXDeviceControl: returned STATUS_BAD_NETWORK_NAME\n"));
+ return Status;
+ }
+
+ Log(("VBoxSF::VBoxMRXDeviceControl 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::VBoxMRXDeviceControl: 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::VBoxMRXDeviceControl: returned STATUS_INVALID_PARAMETER\n"));
+ return Status;
+ }
+
+ default:
+ break;
+ }
+
+ /* Pass the IOCTL to RDBSS. */
+ if (pDeviceExtension && pDeviceExtension->pfnRDBSSDeviceControl)
+ {
+ Log(("VBoxSF::VBoxMRXDeviceControl calling RDBSS %p\n", pDeviceExtension->pfnRDBSSDeviceControl));
+ Status = pDeviceExtension->pfnRDBSSDeviceControl (pDevObj, pIrp);
+ Log(("VBoxSF::VBoxMRXDeviceControl RDBSS status %x\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::VBoxMRXDeviceControl: returned STATUS_NOT_IMPLEMENTED\n"));
+ }
+
+ return Status;
+}
+
+
+NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+/*++
+
+ Routine Description:
+
+ This is the initialization routine for the mini redirector
+
+ Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ Return Value:
+
+ RXSTATUS - The function value is the final status from the initialization
+ operation.
+
+ --*/
+{
+ NTSTATUS Status;
+ ULONG Controls = 0;
+ MRX_VBOX_INIT_STATES VBoxMRxInitState = MRX_VBOXINIT_UNINT;
+ UNICODE_STRING VBoxMRxName;
+ UNICODE_STRING UserModeDeviceName;
+ PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension;
+ ULONG i;
+#ifdef VBOX
+ int vboxRC;
+ VBSFCLIENT hgcmClient =
+ { 0};
+#endif
+
+ Log(("VBOXSF: DriverEntry: Driver object 0x%08lx loaded!\n", DriverObject));
+
+#ifdef VBOX
+ /* Initialize VBox subsystem. */
+ vboxRC = vboxInit();
+ if (RT_FAILURE(vboxRC))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ Log(("VBOXSF: DriverEntry: ERROR while initializing Vbox subsystem (%Rrc)!\n", vboxRC));
+ return Status;
+ }
+
+ /* Set filter mask */
+ if (vboxCtlGuestFilterMask (VMMDEV_EVENT_HGCM, 0)) /** @todo r=bird: Why are we doing this? And more importantely, why are we clearing it further down. We're not the only HGCM user, are we? */
+ {
+ Log (("VBOXSF: DriverEntry: ERROR while setting guest event filter mask!\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Connect the HGCM client */
+ vboxRC = vboxConnect(&hgcmClient);
+ if (RT_FAILURE (vboxRC))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ Log(("VBOXSF: DriverEntry: ERROR while connecting to host (%Rrc)!\n", vboxRC));
+ vboxCtlGuestFilterMask (0, VMMDEV_EVENT_HGCM);
+ vboxUninit();
+ return Status;
+ }
+#endif
+
+ if (DriverObject == NULL)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ Log(("VBOXSF: DriverEntry: Invalid driver object detected!\n"));
+ vboxCtlGuestFilterMask(0, VMMDEV_EVENT_HGCM);
+ vboxUninit();
+ return Status;
+ }
+
+ //
+ // Setup Unload Routine
+ //
+
+ DriverObject->DriverUnload = VBoxMRxUnload;
+ DriverObject->FastIoDispatch = NULL;
+ DriverObject->DriverStartIo = NULL;
+
+ //
+ //setup the driver dispatch for people who come in here directly....like the browser
+ //
+
+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)VBoxMRxFsdDispatch;
+ }
+
+#ifdef VBOX_SF_STATIC_LIB
+ Status = RxDriverEntry(DriverObject, RegistryPath);
+ if (Status != STATUS_SUCCESS)
+ {
+ Log(("VBOXSF: DriverEntry: Wrapper failed to initialize. Status = 0x%08lx\n", Status));
+ goto failure;
+ }
+#endif
+
+ try
+ {
+ VBoxMRxInitState = MRX_VBOXINIT_START;
+
+ //
+ // Register this minirdr with the connection engine. Registration makes the connection
+ // engine aware of the device name, driver object, and other characteristics.
+ // If registration is successful, a new device object is returned
+ //
+ //
+
+
+ RtlInitUnicodeString(&VBoxMRxName, DD_MRX_VBOX_FS_DEVICE_NAME_U);
+ /* don't set RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS or else UNC mappings don't work (including Windows explorer browsing) */
+
+ /** @todo set RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER and the system will crash on boot */
+ SetFlag(Controls,RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
+
+ Status = VBoxRxRegisterMinirdr(
+ &VBoxMRxDeviceObject, // where the new device object goes
+ DriverObject, // the Driver Object to register
+ &VBoxMRxDispatch, // the dispatch table for this driver
+ Controls, // dont register with unc and for mailslots
+ &VBoxMRxName, // the device name for this minirdr
+ sizeof(MRX_VBOX_DEVICE_EXTENSION), // IN ULONG DeviceExtensionSize,
+ FILE_DEVICE_NETWORK_FILE_SYSTEM, // IN ULONG DeviceType - disk ?
+ FILE_REMOTE_DEVICE // IN ULONG DeviceCharacteristics
+ );
+
+ if (Status!=STATUS_SUCCESS)
+ {
+ Log(("VBOXSF: DriverEntry: Registering mini reader failed: 0x%08lx!\n", Status ));
+ try_return(Status);
+ }
+
+ //
+ // Init the device extension data
+ // 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;
+
+ // initialize local connection list
+ for (i = 0; i < RTL_NUMBER_OF(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: VBoxMRxDriverEntry: Failed calling IoCreateSymbolicLink: 0x%08lx\n", Status ));
+ try_return(Status);
+ }
+ Log(("VBOXSF: DriverEntry: Symbolic link created.\n"));
+
+ VBoxMRxInitState = MRX_VBOXINIT_MINIRDR_REGISTERED;
+
+ //
+ // Build the dispatch tables for the minirdr
+ //
+
+ Status = VBoxMRxInitializeTables();
+
+ if (!NT_SUCCESS( Status ))
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: VBoxMRxInitializeTables failed: 0x%08lx\n", Status ));
+ try_return(Status);
+ }
+
+ //
+ // Get information from the registry
+ //
+ VBoxMRxReadRegistryParameters();
+
+ Log(("VBOXSF: VBoxMRxDriverEntry: First phase done!\n"));
+
+ try_exit:
+ NOTHING;
+ }
+ finally
+ {
+ if (Status != STATUS_SUCCESS)
+ {
+ VBoxMRxInitUnwind(DriverObject,VBoxMRxInitState);
+ }
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+
+ Log(("VBOXSF: VBoxMRxDriverEntry: VBoxSF.sys failed to start with Status = 0x%08lx, VBoxMRxInitState = 0x%08lx\n", Status, VBoxMRxInitState));
+ goto failure;
+ }
+
+#ifdef VBOX
+ pDeviceExtension->pDriverObject = DriverObject;
+ pDeviceExtension->hgcmClient = hgcmClient;
+#endif
+
+ Log(("VBOXSF: VBoxMRxDriverEntry: FastIoDispatch address = 0x%x, DriverStartIo address = 0x%x\n", DriverObject->FastIoDispatch, DriverObject->DriverStartIo));
+
+ /* Wrap the fast io path */
+ if (DriverObject->FastIoDispatch)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: SizeOfFastIoDispatch = 0x%x (expected = 0x%x)\n", DriverObject->FastIoDispatch->SizeOfFastIoDispatch, sizeof(dispatchTable)));
+ pfnRDBSSTable = DriverObject->FastIoDispatch;
+ DriverObject->FastIoDispatch = &dispatchTable;
+
+ if (pfnRDBSSTable->FastIoCheckIfPossible == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoCheckIfPossible == NULL\n"));
+ dispatchTable.FastIoCheckIfPossible = NULL;
+ }
+ if (pfnRDBSSTable->FastIoRead == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoRead == NULL\n"));
+ dispatchTable.FastIoRead = NULL;
+ }
+ if (pfnRDBSSTable->FastIoWrite == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoWrite == NULL\n"));
+ dispatchTable.FastIoWrite = NULL;
+ }
+ if (pfnRDBSSTable->FastIoQueryBasicInfo == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryBasicInfo == NULL\n"));
+ dispatchTable.FastIoQueryBasicInfo = NULL;
+ }
+ if (pfnRDBSSTable->FastIoQueryStandardInfo == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryStandardInfo == NULL\n"));
+ dispatchTable.FastIoQueryStandardInfo = NULL;
+ }
+ if (pfnRDBSSTable->FastIoLock == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoLock == NULL\n"));
+ dispatchTable.FastIoLock = NULL;
+ }
+ if (pfnRDBSSTable->FastIoUnlockSingle == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoUnlockSingle == NULL\n"));
+ dispatchTable.FastIoUnlockSingle = NULL;
+ }
+ if (pfnRDBSSTable->FastIoUnlockAll == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoUnlockAll == NULL\n"));
+ dispatchTable.FastIoUnlockAll = NULL;
+ }
+ if (pfnRDBSSTable->FastIoUnlockAllByKey == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoUnlockAllByKey == NULL\n"));
+ dispatchTable.FastIoUnlockAllByKey = NULL;
+ }
+ if (pfnRDBSSTable->FastIoDeviceControl == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoDeviceControl == NULL\n"));
+ dispatchTable.FastIoDeviceControl = NULL;
+ }
+ if (pfnRDBSSTable->AcquireFileForNtCreateSection == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: AcquireFileForNtCreateSection == NULL\n"));
+ dispatchTable.AcquireFileForNtCreateSection = NULL;
+ }
+ if (pfnRDBSSTable->ReleaseFileForNtCreateSection == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: ReleaseFileForNtCreateSection == NULL\n"));
+ dispatchTable.ReleaseFileForNtCreateSection = NULL;
+ }
+ if (pfnRDBSSTable->FastIoDetachDevice == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoDetachDevice == NULL\n"));
+ dispatchTable.FastIoDetachDevice = NULL;
+ }
+ if (pfnRDBSSTable->FastIoQueryNetworkOpenInfo == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryNetworkOpenInfo == NULL\n"));
+ dispatchTable.FastIoQueryNetworkOpenInfo = NULL;
+ }
+ if (pfnRDBSSTable->AcquireForModWrite == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: AcquireForModWrite == NULL\n"));
+ dispatchTable.AcquireForModWrite = NULL;
+ }
+ if (pfnRDBSSTable->MdlRead == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlRead == NULL\n"));
+ dispatchTable.MdlRead = NULL;
+ }
+ if (pfnRDBSSTable->MdlReadComplete == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlReadComplete == NULL\n"));
+ dispatchTable.MdlReadComplete = NULL;
+ }
+ if (pfnRDBSSTable->PrepareMdlWrite == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: PrepareMdlWrite == NULL\n"));
+ dispatchTable.PrepareMdlWrite = NULL;
+ }
+ if (pfnRDBSSTable->MdlWriteComplete == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlWriteComplete == NULL\n"));
+ dispatchTable.MdlWriteComplete = NULL;
+ }
+ if (pfnRDBSSTable->FastIoReadCompressed == NULL)
+ {
+ Log(("VVBOXSF: VBoxMRxDriverEntry: Function Table: FastIoReadCompressed == NULL\n"));
+ dispatchTable.FastIoReadCompressed = NULL;
+ }
+ if (pfnRDBSSTable->FastIoWriteCompressed == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoWriteCompressed == NULL\n"));
+ dispatchTable.FastIoWriteCompressed = NULL;
+ }
+ if (pfnRDBSSTable->MdlReadCompleteCompressed == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlReadCompleteCompressed == NULL\n"));
+ dispatchTable.MdlReadCompleteCompressed = NULL;
+ }
+ if (pfnRDBSSTable->MdlWriteCompleteCompressed == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: MdlWriteCompleteCompressed == NULL\n"));
+ dispatchTable.MdlWriteCompleteCompressed = NULL;
+ }
+ if (pfnRDBSSTable->FastIoQueryOpen == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: FastIoQueryOpen == NULL\n"));
+ dispatchTable.FastIoQueryOpen = NULL;
+ }
+ if (pfnRDBSSTable->ReleaseForModWrite == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: ReleaseForModWrite == NULL\n"));
+ dispatchTable.ReleaseForModWrite = NULL;
+ }
+ if (pfnRDBSSTable->AcquireForCcFlush == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: AcquireForCcFlush == NULL\n"));
+ dispatchTable.AcquireForCcFlush = NULL;
+ }
+ if (pfnRDBSSTable->ReleaseForCcFlush == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxDriverEntry: Function Table: ReleaseForCcFlush == NULL\n"));
+ dispatchTable.ReleaseForCcFlush = NULL;
+ }
+ }
+
+ /* The redirector driver must intercept the IOCTL to avoid VBOXSVR name resolution
+ * by other redirectors. These additional name resolutions cause long delays.
+ */
+ Log(("VBOXSF: VBoxMRxDriverEntry: 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;
+
+ Log(("VBOXSF: VBoxMRxDriverEntry: Init successful!\n"));
+ return STATUS_SUCCESS;
+
+ failure:
+
+#ifdef VBOX
+ Log(("VBOXSF: VBoxMRxDriverEntry: Failure! Status = 0x%08X\n", Status));
+
+ vboxDisconnect (&hgcmClient);
+ vboxCtlGuestFilterMask (0, VMMDEV_EVENT_HGCM);
+ vboxUninit();
+#endif
+ VBoxMRxInitUnwind(DriverObject, VBoxMRxInitState);
+
+ return Status;
+}
+
+VOID VBoxMRxInitUnwind (IN PDRIVER_OBJECT DriverObject, IN MRX_VBOX_INIT_STATES VBoxMRxInitState)
+/*++
+
+ Routine Description:
+
+ This routine does the common uninit work for unwinding from a bad driver entry or for unloading.
+
+ Arguments:
+
+ VBoxMRxInitState - tells how far we got into the intialization
+
+ Return Value:
+
+ None
+
+ --*/
+
+{
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxInitUnwind: VBoxMRxInitState = 0x%x\n", VBoxMRxInitState));
+ switch (VBoxMRxInitState)
+ {
+ case MRX_VBOXINIT_ALL_INITIALIZATION_COMPLETED:
+
+ //Nothing extra to do...this is just so that the constant in RxUnload doesn't change.......
+ //lack of break intentional
+
+ case MRX_VBOXINIT_MINIRDR_REGISTERED:
+ VBoxRxUnregisterMinirdr(VBoxMRxDeviceObject);
+
+ //lack of break intentional
+
+ case MRX_VBOXINIT_START:
+ break;
+ }
+
+}
+
+VOID VBoxMRxUnload (IN PDRIVER_OBJECT DriverObject)
+/*++
+
+ Routine Description:
+
+ This is the unload routine for the Exchange mini redirector.
+
+ Arguments:
+
+ DriverObject - pointer to the driver object for the VBoxMRx
+
+ Return Value:
+
+ None
+
+ --*/
+
+{
+ PRX_CONTEXT RxContext;
+ NTSTATUS Status;
+ UNICODE_STRING UserModeDeviceName;
+ PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension;
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxUnload: Called.\n"));
+#ifdef VBOX
+ pDeviceExtension = (PMRX_VBOX_DEVICE_EXTENSION)
+ ((PBYTE)(VBoxMRxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT));
+
+ vboxDisconnect (&pDeviceExtension->hgcmClient);
+ vboxUninit ();
+ vboxCtlGuestFilterMask (0, VMMDEV_EVENT_HGCM);
+#endif
+
+ VBoxMRxInitUnwind(DriverObject, MRX_VBOXINIT_ALL_INITIALIZATION_COMPLETED);
+ RxContext = VBoxRxCreateRxContext(NULL, VBoxMRxDeviceObject, RX_CONTEXT_FLAG_IN_FSP);
+
+ if (RxContext != NULL)
+ {
+ Status = VBoxRxStopMinirdr(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;
+ }
+ }
+
+ VBoxRxDereferenceAndDeleteRxContext(RxContext);
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlInitUnicodeString(&UserModeDeviceName, DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U);
+ Status = IoDeleteSymbolicLink(&UserModeDeviceName);
+ if (Status != STATUS_SUCCESS)
+ {
+ Log(("VBOXSF: VBoxMRxUnload: Could not delete symbolic link!\n"));
+ }
+
+#ifdef VBOX_SF_STATIC_LIB
+ RxUnload(DriverObject);
+#endif
+ Log(("VBOXSF: VBoxMRxUnload: VBoxSF.sys driver object 0x%08lx unoaded\n", DriverObject));
+}
+
+NTSTATUS VBoxMRxInitializeTables (void)
+/*++
+
+ Routine Description:
+
+ This routine sets up the mini redirector dispatch vector and also calls
+ to initialize any other tables needed.
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxInitializeTables: Called.\n"));
+
+ //
+ // Ensure that the Exchange mini redirector context satisfies the size constraints
+ //
+ //ASSERT(sizeof(MRX_VBOX_RX_CONTEXT) <= MRX_CONTEXT_SIZE);
+
+ //
+ // Build the local minirdr dispatch table and initialize
+ //
+
+ ZeroAndInitializeNodeType(&VBoxMRxDispatch, RDBSS_NTC_MINIRDR_DISPATCH, sizeof(MINIRDR_DISPATCH));
+
+ //
+ // null mini redirector extension sizes and allocation policies.
+ //
+
+
+ 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);
+
+ // Mini redirector cancel routine ..
+
+ VBoxMRxDispatch.MRxCancel = NULL;
+
+ //
+ // Mini redirector Start/Stop. Each mini-rdr can be started or stopped
+ // while the others continue to operate.
+ //
+
+ VBoxMRxDispatch.MRxStart = VBoxMRxStart;
+ VBoxMRxDispatch.MRxStop = VBoxMRxStop;
+ VBoxMRxDispatch.MRxDevFcbXXXControlFile = VBoxMRxDevFcbXXXControlFile;
+
+ //
+ // Mini redirector name resolution.
+ //
+
+ VBoxMRxDispatch.MRxCreateSrvCall = VBoxMRxCreateSrvCall;
+ VBoxMRxDispatch.MRxSrvCallWinnerNotify = VBoxMRxSrvCallWinnerNotify;
+ VBoxMRxDispatch.MRxCreateVNetRoot = VBoxMRxCreateVNetRoot;
+ VBoxMRxDispatch.MRxUpdateNetRootState = VBoxMRxUpdateNetRootState;
+ VBoxMRxDispatch.MRxExtractNetRootName = VBoxMRxExtractNetRootName;
+ VBoxMRxDispatch.MRxFinalizeSrvCall = VBoxMRxFinalizeSrvCall;
+ VBoxMRxDispatch.MRxFinalizeNetRoot = VBoxMRxFinalizeNetRoot;
+ VBoxMRxDispatch.MRxFinalizeVNetRoot = VBoxMRxFinalizeVNetRoot;
+
+ //
+ // File System Object Creation/Deletion.
+ //
+
+ VBoxMRxDispatch.MRxCreate = VBoxMRxCreate;
+ VBoxMRxDispatch.MRxCollapseOpen = VBoxMRxCollapseOpen;
+ VBoxMRxDispatch.MRxShouldTryToCollapseThisOpen = VBoxMRxShouldTryToCollapseThisOpen;
+ VBoxMRxDispatch.MRxExtendForCache = VBoxMRxExtendStub;
+ VBoxMRxDispatch.MRxExtendForNonCache = VBoxMRxExtendStub;
+ VBoxMRxDispatch.MRxTruncate = VBoxMRxTruncate;
+ VBoxMRxDispatch.MRxCleanupFobx = VBoxMRxCleanupFobx;
+ VBoxMRxDispatch.MRxCloseSrvOpen = VBoxMRxCloseSrvOpen;
+ VBoxMRxDispatch.MRxFlush = VBoxMRxFlush;
+ VBoxMRxDispatch.MRxForceClosed = VBoxMRxForcedClose;
+ VBoxMRxDispatch.MRxDeallocateForFcb = VBoxMRxDeallocateForFcb;
+ VBoxMRxDispatch.MRxDeallocateForFobx = VBoxMRxDeallocateForFobx;
+
+ //
+ // File System Objects query/Set
+ //
+
+ VBoxMRxDispatch.MRxQueryDirectory = VBoxMRxQueryDirectory;
+ VBoxMRxDispatch.MRxQueryVolumeInfo = VBoxMRxQueryVolumeInformation;
+ VBoxMRxDispatch.MRxQueryEaInfo = VBoxMRxQueryEaInformation;
+ VBoxMRxDispatch.MRxSetEaInfo = VBoxMRxSetEaInformation;
+ VBoxMRxDispatch.MRxQuerySdInfo = VBoxMRxQuerySecurityInformation;
+ VBoxMRxDispatch.MRxSetSdInfo = VBoxMRxSetSecurityInformation;
+ VBoxMRxDispatch.MRxQueryFileInfo = VBoxMRxQueryFileInformation;
+ VBoxMRxDispatch.MRxSetFileInfo = VBoxMRxSetFileInformation;
+ VBoxMRxDispatch.MRxSetFileInfoAtCleanup = VBoxMRxSetFileInformationAtCleanup;
+
+ //
+ // Buffering state change
+ //
+
+ VBoxMRxDispatch.MRxComputeNewBufferingState = VBoxMRxComputeNewBufferingState;
+
+ //
+ // File System Object I/O
+ //
+
+ 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;
+
+ //
+ // Miscellanous
+ //
+
+ VBoxMRxDispatch.MRxCompleteBufferingStateChangeRequest = VBoxMRxCompleteBufferingStateChangeRequest;
+
+ Log(("VBOXSF: VBoxMRxInitializeTables: Success.\n"));
+ return (STATUS_SUCCESS);
+}
+
+NTSTATUS VBoxMRxStart (PRX_CONTEXT RxContext, IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject)
+/*++
+
+ Routine Description:
+
+ This routine completes the initialization of the mini redirector fromn the
+ RDBSS perspective. Note that this is different from the initialization done
+ in DriverEntry. Any initialization that depends on RDBSS should be done as
+ part of this routine while the initialization that is independent of RDBSS
+ should be done in the DriverEntry routine.
+
+ Arguments:
+
+ RxContext - Supplies the Irp that was used to startup the rdbss
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ MRX_VBOX_STATE CurrentState;
+
+ Log(("VBOXSF: VBoxMRxStart: Called.\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: VBoxMRxStart: Start in progress -> started\n"));
+ Status = STATUS_SUCCESS;
+ }
+ else if (VBoxMRxState == MRX_VBOX_STARTED)
+ {
+ Log(("VBOXSF: VBoxMRxStart: Already started!\n"));
+ Status = STATUS_REDIRECTOR_STARTED;
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxStart: Bad state! VBoxMRxState = %d\n", VBoxMRxState));
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ return Status;
+}
+
+NTSTATUS VBoxMRxStop (PRX_CONTEXT RxContext, IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject)
+/*++
+
+ Routine Description:
+
+ This routine is used to activate the mini redirector from the RDBSS perspective
+
+ Arguments:
+
+ RxContext - the context that was used to start the mini redirector
+
+ pContext - the null mini rdr context passed in at registration time.
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxStop: Called.\n"));
+ return (STATUS_SUCCESS);
+}
+
+NTSTATUS VBoxMRxInitializeSecurity (VOID)
+/*++
+
+ Routine Description:
+
+ This routine initializes the null miniredirector security .
+
+ Arguments:
+
+ None.
+
+ Return Value:
+
+ None.
+
+ Note:
+
+ This API can only be called from a FS process.
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBOXSF: VBoxMRxInitializeSecurity: Called.\n"));
+ return Status;
+}
+
+NTSTATUS VBoxMRxUninitializeSecurity (VOID)
+/*++
+
+ Routine Description:
+
+ Arguments:
+
+ None.
+
+ Return Value:
+
+ None.
+
+ Note:
+
+ This API can only be called from a FS process.
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxUninitializeSecurity: Called.\n"));
+ return Status;
+}
+
+NTSTATUS VBoxMRxFsdDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+
+/*++
+
+ Routine Description:
+
+ This routine implements the FSD dispatch for the mini DRIVER object.
+
+ Arguments:
+
+ DeviceObject - Supplies the device object for the packet being processed.
+
+ Irp - Supplies the Irp being processed
+
+ Return Value:
+
+ RXSTATUS - The Fsd status for the Irp
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ UCHAR MajorFunctionCode = IrpSp->MajorFunction;
+ ULONG MinorFunctionCode = IrpSp->MinorFunction;
+
+ Log(("VBOXSF: VBoxMRxFsdDispatch: Called.\n"));
+
+ Assert(DeviceObject == (PDEVICE_OBJECT)VBoxMRxDeviceObject);
+ if (DeviceObject != (PDEVICE_OBJECT)VBoxMRxDeviceObject)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ Log(("VBOXSF: VBoxMRxFsdDispatch: Invalid device request detected, this in no error!\n"));
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ Log(("%s\n", MajorFunctionString(MajorFunctionCode, MinorFunctionCode)));
+
+ Status = VBoxRxFsdDispatch((PRDBSS_DEVICE_OBJECT)VBoxMRxDeviceObject, Irp);
+ Log(("VBOXSF: VBoxMRxFsdDispatch: Returned 0x%x\n", Status));
+ return Status;
+}
+
+NTSTATUS VBoxMRxGetUlongRegistryParameter (HANDLE ParametersHandle, PWCHAR ParameterName, PULONG ParamUlong, BOOLEAN LogFailure)
+/*++
+
+ Routine Description:
+
+ This routine is called to read a ULONG param from t he registry.
+
+ Arguments:
+
+ ParametersHandle - the handle of the containing registry "folder"
+ ParameterName - name of the parameter to be read
+ ParamUlong - where to store the value, if successful
+ LogFailure - if TRUE and the registry stuff fails, log an error
+
+ Return Value:
+
+ RXSTATUS - STATUS_SUCCESS
+
+ --*/
+{
+ ULONG Storage[16];
+ PKEY_VALUE_PARTIAL_INFORMATION Value;
+ ULONG ValueSize;
+ UNICODE_STRING UnicodeString;
+ NTSTATUS Status;
+ ULONG BytesRead;
+
+ PAGED_CODE(); //INIT
+
+ Log(("VBOXSF: VBoxMRxGetUlongRegistryParameter: Called.\n"));
+
+ Value = (PKEY_VALUE_PARTIAL_INFORMATION)Storage;
+ ValueSize = sizeof(Storage);
+
+ RtlInitUnicodeString(&UnicodeString, ParameterName);
+
+ Status = ZwQueryValueKey(ParametersHandle, &UnicodeString, KeyValuePartialInformation, Value, ValueSize, &BytesRead);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (Value->Type == REG_DWORD)
+ {
+ PULONG ConfigValue = (PULONG) & Value->Data[0];
+ *ParamUlong = *((PULONG)ConfigValue);
+ Log(("BOXSF: VBoxMRxGetUlongRegistryParameter: Read registry value %.*ls = 0x%08lx\n", UnicodeString.Length / sizeof(WCHAR), UnicodeString.Buffer, *ParamUlong));
+ return (STATUS_SUCCESS);
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (LogFailure)
+ Log(("VBOXSF: VBoxMRxGetUlongRegistryParameter: Failure!\n"));
+
+ return Status;
+}
+
+VOID VBoxMRxReadRegistryParameters ()
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING ParametersRegistryKeyName;
+ HANDLE ParametersHandle;
+ ULONG Temp;
+
+ Log(("VBOXSF: VBoxMRxReadRegistryParameters: Called.\n"));
+ RtlInitUnicodeString(&ParametersRegistryKeyName, NULL_MINIRDR_PARAMETERS);
+ InitializeObjectAttributes(&ObjectAttributes, &ParametersRegistryKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL
+ );
+
+ Status = ZwOpenKey(&ParametersHandle, KEY_READ, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ Status = VBoxMRxGetUlongRegistryParameter(ParametersHandle,L"LogRate" ,
+ (PULONG)&Temp,
+ FALSE
+ );
+ }
+ if (NT_SUCCESS(Status)) LogRate = Temp;
+
+ ZwClose(ParametersHandle);
+}
+
+#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";
+ }
+}
+
+static 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
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c
new file mode 100644
index 00000000000..e6374bfbb1e
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/locks.c
@@ -0,0 +1,173 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ locks.c
+
+ Abstract:
+
+ This module implements the mini redirector call down routines pertaining to locks
+ of file system objects.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, VBoxMRxLocks)
+#pragma alloc_text(PAGE, VBoxMRxCompleteBufferingStateChangeRequest)
+#pragma alloc_text(PAGE, VBoxMRxFlush)
+#endif
+
+NTSTATUS VBoxMRxLocks (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine handles network requests for filelocks
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+#ifndef VBOX
+ PDEVICE_OBJECT deviceObject;
+#endif
+
+ PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context;
+ uint32_t fLock = 0;
+
+ int vboxRC;
+
+ Log(("VBOXSF: VBoxMRxLocks: Called.\n"));
+
+ switch (LowIoContext->Operation)
+ {
+ default:
+ AssertMsgFailed(("VBOXSF: VBoxMRxLocks: 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: VBoxMRxLocks: Unsupported lock/unlock type %d detected!\n", LowIoContext->Operation));
+ return STATUS_NOT_IMPLEMENTED;
+
+ /* Reading is allowed, writing isn't */
+ case LOWIO_OP_SHAREDLOCK:
+ fLock = SHFL_LOCK_SHARED | SHFL_LOCK_PARTIAL;
+ break;
+
+ /* Reading and writing not allowed */
+ case LOWIO_OP_EXCLUSIVELOCK:
+ fLock = SHFL_LOCK_EXCLUSIVE | SHFL_LOCK_PARTIAL;
+ break;
+
+ case LOWIO_OP_UNLOCK:
+ fLock = SHFL_LOCK_CANCEL | SHFL_LOCK_PARTIAL;
+ break;
+ }
+
+ if (LowIoContext->ParamsFor.Locks.Flags & LOWIO_LOCKSFLAG_FAIL_IMMEDIATELY)
+ {
+ fLock |= SHFL_LOCK_NOWAIT;
+ }
+ else
+ {
+ fLock |= SHFL_LOCK_WAIT;
+ }
+
+ /* Do the actual flushing of file buffers */
+ vboxRC = vboxCallLock(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, LowIoContext->ParamsFor.Locks.ByteOffset, LowIoContext->ParamsFor.Locks.Length, fLock);
+ AssertRC(vboxRC);
+ Status = VBoxErrorToNTStatus(vboxRC);
+
+ Log(("VBOXSF: VBoxMRxLocks: Returned 0x%x\n", Status));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxCompleteBufferingStateChangeRequest (IN OUT PRX_CONTEXT RxContext, IN OUT PMRX_SRV_OPEN SrvOpen, IN PVOID pContext)
+/*++
+
+ Routine Description:
+
+ This routine is called to assert the locks that the wrapper has buffered. currently, it is synchronous!
+
+
+ Arguments:
+
+ RxContext - the open instance
+ SrvOpen - tells which fcb is to be used.
+ LockEnumerator - the routine to call to get the locks
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+
+ Log(("VBOXSF: VBoxMRxCompleteBufferingStateChangeRequest: Called.\n"));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxFlush (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine handles network requests for file flush
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+#ifndef VBOX
+ PDEVICE_OBJECT deviceObject;
+#endif
+
+ PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context;
+
+ int vboxRC;
+
+ Log(("VBOXSF: VBoxMRxFlush: Called.\n"));
+
+ /* Do the actual flushing of file buffers */
+ vboxRC = vboxCallFlush(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+ AssertRC(vboxRC);
+
+ Status = VBoxErrorToNTStatus(vboxRC);
+
+ return (Status);
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h
new file mode 100644
index 00000000000..57a39afbda5
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/minip.h
@@ -0,0 +1,76 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ minip.h
+
+ Abstract:
+
+ Macros and definitions private to the null mini driver.
+
+ Notes:
+
+ This module has been built and tested only in UNICODE environment
+
+ --*/
+
+#ifndef _NULLMINIP_H_
+#define _NULLMINIP_H_
+
+NTHALAPI
+VOID
+KeStallExecutionProcessor (
+ IN ULONG MicroSeconds
+);
+
+#ifndef min
+#define min(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+#define RX_VERIFY( f ) if( (f) ) ; else ASSERT( 1==0 )
+
+//
+// Set or Validate equal
+//
+#define SetOrValidate(x,y,f) \
+ if( f ) (x) = (y); else ASSERT( (x) == (y) )
+
+//
+// RXCONTEXT data - mini-rdr context stored for async completions
+// NOTE: sizeof this struct should be == MRX_CONTEXT_SIZE !!
+//
+
+typedef struct _MRX_VBOX_COMPLETION_CONTEXT
+{
+ //
+ // IoStatus.Information
+ //
+ ULONG Information;
+
+ //
+ // IoStatus.Status
+ //
+ NTSTATUS Status;
+
+ //
+ // Outstanding I/Os
+ //
+ ULONG OutstandingIOs;
+
+ //
+ // I/O type
+ //
+ ULONG IoType;
+
+} MRX_VBOX_COMPLETION_CONTEXT, *PMRX_VBOX_COMPLETION_CONTEXT;
+
+#define IO_TYPE_SYNCHRONOUS 0x00000001
+#define IO_TYPE_ASYNC 0x00000010
+
+#define VBoxMRxGetMinirdrContext(pRxContext) \
+ ((PMRX_VBOX_COMPLETION_CONTEXT)(&(pRxContext)->MRxContext[0]))
+
+#endif // _NULLMINIP_H_
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h
new file mode 100644
index 00000000000..e30e01520c5
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxglobs.h
@@ -0,0 +1,463 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ mrxglobs.h
+
+ Abstract:
+
+ The global include file for MRX_VBOX mini-redirector
+
+ --*/
+
+#ifndef _MRXGLOBS_H_
+#define _MRXGLOBS_H_
+
+#ifdef VBOX
+#include "VBoxGuestR0LibSharedFolders.h"
+#endif
+
+extern PRDBSS_DEVICE_OBJECT VBoxMRxDeviceObject;
+#define RxNetNameTable (*(*___MINIRDR_IMPORTS_NAME).pRxNetNameTable)
+
+// The following enum type defines the various states associated with the null
+// mini redirector. This is used during initialization
+
+typedef enum _MRX_VBOX_STATE_
+{
+ MRX_VBOX_STARTABLE, MRX_VBOX_START_IN_PROGRESS, MRX_VBOX_STARTED
+} MRX_VBOX_STATE, *PMRX_VBOX_STATE;
+
+extern MRX_VBOX_STATE VBoxMRxState;
+extern ULONG LogRate;
+extern ULONG VBoxMRxVersion;
+
+//
+// Reg keys
+//
+#define NULL_MINIRDR_PARAMETERS \
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\VBoxMRx\\Parameters"
+
+/*
+ * Maximum drive letters (A - Z).
+ */
+#define _MRX_MAX_DRIVE_LETTERS 26
+
+//
+// typedef our device extension - stores state global to the driver
+//
+typedef struct _MRX_VBOX_DEVICE_EXTENSION
+{
+ //
+ // Back-pointer to owning device object
+ //
+ PRDBSS_DEVICE_OBJECT pDeviceObject;
+
+ //
+ // Count of active nodes
+ // Driver can be unloaded if ActiveNodes == 0
+ //
+ ULONG ulActiveNodes;
+
+ /*
+ * 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;
+
+#ifdef VBOX
+ /* The HGCM client information. */
+ VBSFCLIENT hgcmClient;
+ /* Poller thread flags */
+ ULONG ulPollerThreadFlags;
+
+ /* Poller thread handle */
+ PKTHREAD pPollerThread;
+
+ /* Redirector driver object pointer */
+ PDRIVER_OBJECT pDriverObject;
+#endif
+
+ NTSTATUS (* pfnRDBSSDeviceControl) (PDEVICE_OBJECT pDevObj, PIRP pIrp);
+
+} MRX_VBOX_DEVICE_EXTENSION, *PMRX_VBOX_DEVICE_EXTENSION;
+
+//
+// NET_ROOT extension - stores state global to a root
+//
+typedef struct _MRX_VBOX_NETROOT_EXTENSION
+{
+ /* The HGCM client information. */
+ VBSFCLIENT *phgcmClient;
+ VBSFMAP map;
+
+} MRX_VBOX_NETROOT_EXTENSION, *PMRX_VBOX_NETROOT_EXTENSION;
+
+// A pointer to an instance of MRX_VBOX_FOBX is stored in the context field
+// of MRX_FOBXs handled by the SMB mini rdr. Depending upon the file type
+// i.e., file or directory the appropriate context information is stored.
+
+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;
+
+//
+// Macros to get & validate extensions
+//
+
+#define VBoxMRxGetDeviceExtension(RxContext,pExt) \
+ PMRX_VBOX_DEVICE_EXTENSION pExt = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
+
+#define VBoxMRxGetNetRootExtension(pNetRoot,pExt) \
+ PMRX_VBOX_NETROOT_EXTENSION pExt = (((pNetRoot) == NULL) ? NULL : (PMRX_VBOX_NETROOT_EXTENSION)((pNetRoot)->Context))
+
+#define VBoxMRxGetFcbExtension(pFcb,pExt) \
+ PMRX_VBOX_FCB_EXTENSION pExt = (((pFcb) == NULL) ? NULL : (PMRX_VBOX_FCB_EXTENSION)((pFcb)->Context))
+
+#define VBoxMRxGetSrvOpenExtension(pSrvOpen) \
+ (((pSrvOpen) == NULL) ? NULL : (PMRX_VBOX_SRV_OPEN)((pSrvOpen)->Context))
+
+#define VBoxMRxGetFileObjectExtension(pFobx) \
+ (((pFobx) == NULL) ? NULL : (PMRX_VBOX_FOBX)((pFobx)->Context))
+
+//
+// forward declarations for all dispatch vector methods.
+//
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern NTSTATUS
+VBoxMRxStart (
+ IN OUT struct _RX_CONTEXT * RxContext,
+ IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
+);
+
+extern NTSTATUS
+VBoxMRxStop (
+ IN OUT struct _RX_CONTEXT * RxContext,
+ IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
+);
+
+extern NTSTATUS
+VBoxMRxMinirdrControl (
+ IN OUT PRX_CONTEXT RxContext,
+ IN OUT PVOID pContext,
+ IN OUT PUCHAR SharedBuffer,
+ IN ULONG InputBufferLength,
+ IN ULONG OutputBufferLength,
+ OUT PULONG CopyBackLength
+);
+
+extern NTSTATUS
+VBoxMRxDevFcb (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxDevFcbXXXControlFile (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCreate (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCollapseOpen (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxShouldTryToCollapseThisOpen (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxRead (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxWrite (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxLocks(
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxFlush(
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxFsCtl(
+ IN OUT PRX_CONTEXT RxContext
+);
+
+NTSTATUS
+VBoxMRxIoCtl(
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxNotifyChangeDirectory(
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxComputeNewBufferingState(
+ IN OUT PMRX_SRV_OPEN pSrvOpen,
+ IN PVOID pMRxContext,
+ OUT ULONG *pNewBufferingState);
+
+extern NTSTATUS
+VBoxMRxFlush (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCloseWithDelete (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxZeroExtend (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxSetEndOfFile(
+ IN OUT struct _RX_CONTEXT * RxContext,
+ IN OUT PLARGE_INTEGER pNewFileSize,
+ OUT PLARGE_INTEGER pNewAllocationSize
+);
+
+extern NTSTATUS
+VBoxMRxTruncate (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCleanupFobx (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCloseSrvOpen (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxClosedSrvOpenTimeOut (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxQueryDirectory (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxQueryEaInformation (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxSetEaInformation (
+ IN OUT struct _RX_CONTEXT * RxContext
+);
+
+extern NTSTATUS
+VBoxMRxQuerySecurityInformation (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxSetSecurityInformation (
+ IN OUT struct _RX_CONTEXT * RxContext
+);
+
+extern NTSTATUS
+VBoxMRxQueryVolumeInformation (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxSetVolumeInformation (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxLowIOSubmit (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCreateVNetRoot(
+ IN OUT PMRX_CREATENETROOT_CONTEXT pContext
+);
+
+extern NTSTATUS
+VBoxMRxFinalizeVNetRoot(
+ IN OUT PMRX_V_NET_ROOT pVirtualNetRoot,
+ IN PBOOLEAN ForceDisconnect);
+
+extern NTSTATUS
+VBoxMRxFinalizeNetRoot(
+ IN OUT PMRX_NET_ROOT pNetRoot,
+ IN PBOOLEAN ForceDisconnect);
+
+extern 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
+);
+
+extern NTSTATUS
+VBoxMRxCreateSrvCall(
+ PMRX_SRV_CALL pSrvCall,
+ PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext);
+
+extern NTSTATUS
+VBoxMRxFinalizeSrvCall(
+ PMRX_SRV_CALL pSrvCall,
+ BOOLEAN Force);
+
+extern NTSTATUS
+VBoxMRxSrvCallWinnerNotify(
+ IN OUT PMRX_SRV_CALL pSrvCall,
+ IN BOOLEAN ThisMinirdrIsTheWinner,
+ IN OUT PVOID pSrvCallContext);
+
+extern NTSTATUS
+VBoxMRxQueryFileInformation (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxQueryNamedPipeInformation (
+ IN OUT PRX_CONTEXT RxContext,
+ IN FILE_INFORMATION_CLASS FileInformationClass,
+ IN OUT PVOID Buffer,
+ IN OUT PULONG pLengthRemaining
+);
+
+extern NTSTATUS
+VBoxMRxSetFileInformation (
+ IN OUT PRX_CONTEXT RxContext
+);
+
+extern NTSTATUS
+VBoxMRxSetNamedPipeInformation (
+ IN OUT PRX_CONTEXT RxContext,
+ IN FILE_INFORMATION_CLASS FileInformationClass,
+ IN PVOID pBuffer,
+ IN ULONG BufferLength
+);
+
+NTSTATUS
+VBoxMRxSetFileInformationAtCleanup(
+ IN OUT PRX_CONTEXT RxContext
+);
+
+NTSTATUS
+VBoxMRxDeallocateForFcb (
+ IN OUT PMRX_FCB pFcb
+);
+
+NTSTATUS
+VBoxMRxDeallocateForFobx (
+ IN OUT PMRX_FOBX pFobx
+);
+
+extern NTSTATUS
+VBoxMRxForcedClose (
+ IN OUT PMRX_SRV_OPEN SrvOpen
+);
+
+extern ULONG
+VBoxMRxExtendFile (
+ IN OUT struct _RX_CONTEXT * RxContext,
+ IN OUT PLARGE_INTEGER pNewFileSize,
+ OUT PLARGE_INTEGER pNewAllocationSize
+);
+
+extern NTSTATUS
+VBoxMRxExtendStub (
+ IN OUT struct _RX_CONTEXT * RxContext,
+ IN OUT PLARGE_INTEGER pNewFileSize,
+ OUT PLARGE_INTEGER pNewAllocationSize
+);
+
+extern NTSTATUS
+VBoxMRxTruncateFile(
+ IN OUT struct _RX_CONTEXT * RxContext
+);
+
+extern NTSTATUS
+VBoxMRxCompleteBufferingStateChangeRequest (
+ IN OUT PRX_CONTEXT RxContext,
+ IN OUT PMRX_SRV_OPEN SrvOpen,
+ IN PVOID pContext
+);
+
+extern NTSTATUS
+VBoxMRxExtendForCache (
+ IN OUT PRX_CONTEXT RxContext,
+ IN OUT PFCB Fcb,
+ OUT PLONGLONG pNewFileSize
+);
+
+extern
+NTSTATUS
+VBoxMRxInitializeSecurity (VOID);
+
+extern
+NTSTATUS
+VBoxMRxUninitializeSecurity (VOID);
+
+extern
+NTSTATUS
+VBoxMRxInitializeTransport(VOID);
+
+extern
+NTSTATUS
+VBoxMRxUninitializeTransport(VOID);
+
+#ifdef __cplusplus
+}
+;
+#endif
+
+#define VBoxMRxMakeSrvOpenKey(Tid,Fid) \
+ (PVOID)(((ULONG)(Tid) << 16) | (ULONG)(Fid))
+
+#include "mrxprocs.h" // crossreferenced routines
+#endif _MRXGLOBS_H_
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h
new file mode 100644
index 00000000000..d79547606b4
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/mrxprocs.h
@@ -0,0 +1,50 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ mrxprocs.h
+
+ Abstract:
+
+ The module contains the prototype definitions for all cross referenced
+ routines.
+
+ --*/
+
+#ifndef _MRXPROCS_H_
+#define _MRXPROCS_H_
+
+//cross-referenced internal routines
+
+//from rename.c
+NTSTATUS VBoxMRxRename(
+ IN PRX_CONTEXT RxContext,
+ IN FILE_INFORMATION_CLASS FileInformationClass,
+ IN PVOID pBuffer,
+ IN ULONG BufferLength);
+
+NTSTATUS VBoxMRxRemove(IN PRX_CONTEXT RxContext);
+
+// from usrcnnct.c
+NTSTATUS
+VBoxMRxDeleteConnection (
+IN PRX_CONTEXT RxContext,
+OUT PBOOLEAN PostToFsp
+);
+
+NTSTATUS
+VBoxMRxCreateConnection (
+IN PRX_CONTEXT RxContext,
+OUT PBOOLEAN PostToFsp
+);
+
+NTSTATUS
+VBoxMRxDoConnection(
+IN PRX_CONTEXT RxContext,
+ULONG CreateDisposition
+);
+
+#endif // _MRXPROCS_H_
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c
new file mode 100644
index 00000000000..8bd2e523c72
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/netroot.c
@@ -0,0 +1,456 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ netroot.c
+
+ Abstract:
+
+ This module implements the routines for creating the net root.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Forward declarations ...
+//
+
+NTSTATUS VBoxMRxUpdateNetRootState (IN OUT PMRX_NET_ROOT pNetRoot)
+/*++
+
+ Routine Description:
+
+ This routine updates the mini redirector state associated with a net root.
+
+ Arguments:
+
+ pNetRoot - the net root instance.
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ Notes:
+
+ By diffrentiating the mini redirector state from the net root condition it is possible
+ to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
+ a net root to be good while the underlying mini redirector might mark it as invalid
+ and reconnect on the fly.
+
+ --*/
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+
+ Log(("VBOXSF: VBoxMRxUpdateNetRootState: Called.\n"));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxInitializeNetRootEntry (IN PMRX_NET_ROOT pNetRoot)
+/*++
+
+ Routine Description:
+
+ This routine initializes a new net root.
+ It also validates rootnames. Eg: attempts to create a
+ file in a root that has not been created will fail.
+
+ Arguments:
+
+ pNetRoot - the net root
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ Notes:
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+ PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context;
+
+ Log(("VBOXSF: VBoxMRxInitializeNetRootEntry: Called.\n"));
+ return Status;
+}
+
+NTSTATUS VBoxUpdateNetRoot (PMRX_NET_ROOT pNetRoot)
+/*++
+
+ Routine Description:
+
+ This routine initializes the wrapper data structure corresponding to a
+ given net root entry.
+
+ Arguments:
+
+ pNetRootEntry - the server entry
+
+ Return Value:
+
+ STATUS_SUCCESS if successful
+
+ --*/
+{
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxUpdateNetRoot: 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: VBoxUpdateNetRoot: Invalid net root type! Type = 0x%x\n", pNetRoot->Type));
+ break;
+ }
+
+ Log(("VBOXSF: VBoxUpdateNetRoot: leaving pNetRoot->DeviceType = 0x%x\n", pNetRoot->DeviceType));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxCreateVNetRoot (IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
+/*++
+
+ Routine Description:
+
+ This routine patches the RDBSS created net root instance with the information required
+ by the mini redirector.
+
+ Arguments:
+
+ pVNetRoot - the virtual net root instance.
+
+ pCreateNetRootContext - the net root context for calling back
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ Notes:
+
+ --*/
+{
+ NTSTATUS Status;
+ PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext;
+ PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
+ VBoxMRxGetDeviceExtension(pRxContext, pDeviceExtension);
+ VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension);
+
+ PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
+ PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
+
+ BOOLEAN fTreeConnectOpen = TRUE; // RxContext->Create.ThisIsATreeConnectOpen;
+ BOOLEAN fInitializeNetRoot;
+
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: pNetRoot = %p, fTreeConnectOpen = %d\n", pNetRoot, pRxContext->Create.ThisIsATreeConnectOpen));
+
+ /* 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_MAILSLOT || pNetRoot->Type == NET_ROOT_PIPE)
+ {
+ /* DDK sample returns this status code. And our driver does get such NetRoots. */
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: Mailslot or Pipe open (%d) not supported!\n", pNetRoot->Type));
+ pVNetRoot->Context = NULL;
+
+ Status = STATUS_NOT_SUPPORTED;
+ goto l_Exit;
+ }
+
+ // The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as
+ // follows
+ // 1) the V_NET_ROOT and the associated NET_ROOT are being newly created.
+ // 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created.
+ //
+ // These two cases can be distinguished by checking if the context associated with
+ // NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized
+ // by the wrapper this is a safe check.
+ // ( The wrapper cannot have more then one thread tryingto initialize the same
+ // NET_ROOT).
+ //
+ // The above is not really true in our case. Since we have asked the wrapper,
+ // to manage our netroot extension, the netroot context will always be non-NULL.
+ // We will distinguish the cases by checking our root state in the context...
+ //
+
+ if (pNetRoot->Context == NULL)
+ {
+ fInitializeNetRoot = TRUE;
+ }
+ else
+ {
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+ /* Detect an already initialized NetRoot.
+ * pNetRootExtension is actually the pNetRoot->Context and it is not null.
+ */
+ fInitializeNetRoot = pNetRootExtension->phgcmClient == NULL;
+ }
+
+ Assert((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) && (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
+
+ Status = STATUS_SUCCESS;
+
+ // update the net root state to be good.
+
+ if (fInitializeNetRoot)
+ {
+ PWCHAR pRootName;
+ ULONG RootNameLength;
+ int vboxRC;
+ PSHFLSTRING ParsedPath = 0;
+ ULONG ParsedPathSize;
+
+ pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
+
+ // validate the fixed netroot name
+
+ RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
+ if (!RootNameLength)
+ {
+ /* Refuse a netroot path with an empty shared folder name */
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: Invalid shared folder name! (length=0)\n"));
+ pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
+
+ Status = STATUS_BAD_NETWORK_NAME;
+ goto l_Exit;
+ }
+
+ RootNameLength -= 2; /* remove leading backslash */
+
+ pRootName = (PWCHAR)(pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
+ pRootName++; /* remove leading backslash */
+
+ if (pNetRootExtension->phgcmClient == NULL)
+ {
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: 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: VBoxMRxCreateVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
+ Status = STATUS_BAD_NETWORK_NAME;
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ pNetRootExtension->phgcmClient = &pDeviceExtension->hgcmClient;
+ }
+ }
+ }
+ else Log(("VBOXSF: VBoxMRxCreateVNetRoot: Creating V_NET_ROOT on existing NET_ROOT!\n"));
+
+ if ((Status == STATUS_SUCCESS) && fInitializeNetRoot)
+ {
+ //
+ // A new NET_ROOT and associated V_NET_ROOT are being created !
+ //
+ Status = VBoxMRxInitializeNetRootEntry(pNetRoot);
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: NulMRXInitializeNetRootEntry called, Status = 0x%lx\n", Status));
+ }
+
+ VBoxUpdateNetRoot(pNetRoot);
+
+l_Exit:
+ if (Status != STATUS_PENDING)
+ {
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returning 0x%lx\n", Status));
+ pCreateNetRootContext->VirtualNetRootStatus = Status;
+ if (fInitializeNetRoot)
+ pCreateNetRootContext->NetRootStatus = Status;
+ else pCreateNetRootContext->NetRootStatus = Status;
+
+ // Callback the RDBSS for resumption.
+ pCreateNetRootContext->Callback(pCreateNetRootContext);
+
+ // Map the error code to STATUS_PENDING since this triggers
+ // the synchronization mechanism in the RDBSS.
+ Status = STATUS_PENDING;
+ }
+
+ Log(("VBOXSF: VBoxMRxCreateVNetRoot: Returned STATUS_PENDING\n"));
+ return Status;
+}
+
+NTSTATUS VBoxMRxFinalizeVNetRoot (IN PMRX_V_NET_ROOT pVNetRoot, IN PBOOLEAN ForceDisconnect)
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+ pVNetRoot - the virtual net root
+
+ ForceDisconnect - disconnect is forced
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
+ VBoxMRxGetNetRootExtension(pVNetRoot->pNetRoot, pNetRootExtension);
+ int vboxRC;
+
+ Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: Address = 0x%lx\n", pVNetRoot));
+
+ if (pNetRootExtension->phgcmClient)
+ {
+ vboxRC = vboxCallUnmapFolder(pNetRootExtension->phgcmClient, &pNetRootExtension->map);
+ if (vboxRC != VINF_SUCCESS)
+ {
+ Log(("VBOXSF: VBoxMRxFinalizeVNetRoot: vboxCallMapFolder failed with %d\n", vboxRC));
+ }
+ pNetRootExtension->phgcmClient = NULL;
+ }
+
+ //
+ // This is called when all outstanding handles on this
+ // root have been cleaned up ! We can now zap the netroot
+ // extension...
+ //
+
+ return Status;
+}
+
+NTSTATUS VBoxMRxFinalizeNetRoot (IN PMRX_NET_ROOT pNetRoot, IN PBOOLEAN ForceDisconnect)
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+ pVirtualNetRoot - the virtual net root
+
+ ForceDisconnect - disconnect is forced
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBOXSF: VBoxMRxFinalizeNetRoot: Called.\n"));
+ //
+ // This is called when all outstanding handles on this
+ // root have been cleaned up ! We can now zap the netroot
+ // extension...
+ //
+ return (Status);
+}
+
+VOID VBoxMRxExtractNetRootName (IN PUNICODE_STRING FilePathName, IN PMRX_SRV_CALL SrvCall, OUT PUNICODE_STRING NetRootName, OUT PUNICODE_STRING RestOfName OPTIONAL
+ )
+/*++
+
+ Routine Description:
+
+ This routine parses the input name into srv, netroot, and the
+ rest.
+
+ Arguments:
+
+
+ --*/
+{
+ UNICODE_STRING xRestOfName;
+
+ ULONG length = FilePathName->Length;
+ PWCH w = FilePathName->Buffer;
+ PWCH wlimit = (PWCH)(((PCHAR)w) + length);
+ PWCH wlow;
+
+ Log(("VBOXSF: VBoxMRxExtractNetRootName: Called.\n"));
+
+ w += (SrvCall->pSrvCallName->Length / sizeof(WCHAR));
+ NetRootName->Buffer = wlow = w;
+ for (;;)
+ {
+ if (w >= wlimit)
+ break;
+ if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow))
+ {
+ break;
+ }
+ w++;
+ }
+
+ NetRootName->Length = NetRootName->MaximumLength = (USHORT)((PCHAR)w - (PCHAR)wlow);
+
+ //w = FilePathName->Buffer;
+ //NetRootName->Buffer = w++;
+
+ if (!RestOfName)
+ RestOfName = &xRestOfName;
+ RestOfName->Buffer = w;
+ RestOfName->Length = (USHORT)RestOfName->MaximumLength = (USHORT)((PCHAR)wlimit - (PCHAR)w);
+
+ Log(("VBOXSF: VBoxMRxExtractNetRootName: FilePath = %.*ls\n", FilePathName->Length / sizeof(WCHAR), FilePathName->Buffer));
+ Log(("VBOXSF: VBoxMRxExtractNetRootName: Srv = %.*ls, Root = %.*ls, Rest = %.*ls\n", SrvCall->pSrvCallName->Length / sizeof(WCHAR), SrvCall->pSrvCallName->Buffer, NetRootName->Length
+ / sizeof(WCHAR), NetRootName->Buffer, RestOfName->Length / sizeof(WCHAR), RestOfName->Buffer));
+
+ return;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c
new file mode 100644
index 00000000000..71370019607
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/notimpl.c
@@ -0,0 +1,110 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ notimpl.c
+
+ Abstract:
+
+ This module includes prototypes of the functionality that has not been
+ implemented in the null mini rdr.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// File System Control funcitonality
+//
+
+
+NTSTATUS VBoxMRxFsCtl (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine performs an FSCTL operation (remote) on a file across the network
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+
+ --*/
+{
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ Log(("VBOXSF: VBoxMRxFsCtl: Returned 0x%08lx\n", Status));
+ return Status;
+}
+
+NTSTATUS VBoxMRxNotifyChangeDirectoryCancellation (PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine is invoked when a directory change notification operation is cancelled.
+ This example doesn't support it.
+
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+
+ UNREFERENCED_PARAMETER(RxContext);
+
+ Log(("VBoxMRxNotifyChangeDirectoryCancellation\n"));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxNotifyChangeDirectory (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine performs a directory change notification operation.
+ This example doesn't support it.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation [not implemented]
+
+ --*/
+{
+
+ UNREFERENCED_PARAMETER(RxContext);
+
+ Log(("VBoxMRxNotifyChangeDirectory\n"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxQuerySecurityInformation (IN OUT PRX_CONTEXT RxContext)
+{
+ Log(("VBoxMRxQuerySecurityInformation \n"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxSetSecurityInformation (IN OUT struct _RX_CONTEXT * RxContext)
+{
+ Log(("VBoxMRxSetSecurityInformation \n"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h
new file mode 100644
index 00000000000..2c5708fea93
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/nulmrx.h
@@ -0,0 +1,119 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ nulmrx.h
+
+ Abstract:
+
+ This header exports all symbols and definitions shared between
+ user-mode clients of nulmrx and the driver itself.
+
+ Notes:
+
+ This module has been built and tested only in UNICODE environment
+
+ --*/
+
+#ifndef _MRX_VBOX_H_
+#define _MRX_VBOX_H_
+
+/** ULONG tags used by the FSD. */
+#define TAG_PP 'PfsV'
+#define TAG_FCB 'FfsV'
+#define TAG_CCB 'CfsV'
+#define TAG_IRPCTX 'IfsV'
+
+// Device name for this driver
+#define MRX_VBOX_DEVICE_NAME_A "VBoxMiniRdr"
+#define MRX_VBOX_DEVICE_NAME_U L"VBoxMiniRdr"
+
+// Provider name for this driver
+#define MRX_VBOX_PROVIDER_NAME_A "VirtualBox Shared Folders"
+#define MRX_VBOX_PROVIDER_NAME_U L"VirtualBox Shared Folders"
+
+// File system name
+#define MRX_VBOX_FILESYS_NAME_A "VBoxSharedFolderFS"
+#define MRX_VBOX_FILESYS_NAME_U L"VBoxSharedFolderFS"
+
+// The following constant defines the length of the above name.
+#define MRX_VBOX_DEVICE_NAME_A_LENGTH (15)
+
+// The following constant defines the path in the ob namespace
+#define DD_MRX_VBOX_FS_DEVICE_NAME_U L"\\Device\\VBoxMiniRdr"
+
+/* File system volume name prefix */
+#define VBOX_VOLNAME_PREFIX L"VBOX_"
+#define VBOX_VOLNAME_PREFIX_SIZE (sizeof(VBOX_VOLNAME_PREFIX) - sizeof(VBOX_VOLNAME_PREFIX[0]))
+
+#ifndef MRX_VBOX_DEVICE_NAME
+#define MRX_VBOX_DEVICE_NAME
+
+//
+// The Devicename string required to access the nullmini device
+// from User-Mode. Clients should use DD_MRX_VBOX_USERMODE_DEV_NAME_U.
+//
+// WARNING The next two strings must be kept in sync. Change one and you must
+// change the other. These strings have been chosen such that they are
+// unlikely to coincide with names of other drivers.
+//
+#define DD_MRX_VBOX_USERMODE_SHADOW_DEV_NAME_U L"\\??\\VBoxMiniRdrDN"
+#define DD_MRX_VBOX_USERMODE_DEV_NAME_U L"\\\\.\\VBoxMiniRdrDN"
+
+//
+// Prefix needed for disk filesystems
+//
+#define DD_MRX_VBOX_MINIRDR_PREFIX L"\\;E:"
+
+#endif // MRX_VBOX_DEVICE_NAME
+//
+// BEGIN WARNING WARNING WARNING WARNING
+// The following are from the ddk include files and cannot be changed
+
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 // from ddk\inc\ntddk.h
+#define METHOD_BUFFERED 0
+#define FILE_ANY_ACCESS 0
+
+// END WARNING WARNING WARNING WARNING
+
+#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)
+
+//
+// IOCTL codes supported by NullMini Device.
+//
+
+#define IOCTL_CODE_ADDCONN 100
+#define IOCTL_CODE_GETCONN 101
+#define IOCTL_CODE_DELCONN 102
+#define IOCTL_CODE_GETLIST 103
+#define IOCTL_CODE_GETGLOBALLIST 104
+#define IOCTL_CODE_GETGLOBALCONN 105
+#define IOCTL_CODE_START 106
+#define IOCTL_CODE_STOP 107
+
+//
+// Following is the IOCTL definition and associated structs.
+// for IOCTL_CODE_SAMPLE1
+//
+#define IOCTL_MRX_VBOX_ADDCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_ADDCONN, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_MRX_VBOX_GETCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETCONN, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_MRX_VBOX_DELCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_DELCONN, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_MRX_VBOX_GETLIST _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETLIST, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_MRX_VBOX_GETGLOBALLIST _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETGLOBALLIST, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_MRX_VBOX_GETGLOBALCONN _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_GETGLOBALCONN, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_MRX_VBOX_START _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_START, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MRX_VBOX_STOP _MRX_VBOX_CONTROL_CODE(IOCTL_CODE_STOP, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif // _MRX_VBOX_H_
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c
new file mode 100644
index 00000000000..153e06bedd2
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/openclos.c
@@ -0,0 +1,1526 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ openclos.c
+
+ Abstract:
+
+ This module implements the mini redirector call down routines pertaining to opening/
+ closing of file/directories.
+
+ --*/
+
+#include "precomp.h"
+#include "rdbss_vbox.h"
+#pragma hdrstop
+
+static UNICODE_STRING UnicodeBackslash = { 2, 4,L"\\" };
+
+//
+// forwards & pragmas
+//
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+NTSTATUS VBoxMRxProcessCreate (IN PRX_CONTEXT RxContext, IN PUNICODE_STRING RemainingName, IN FILE_BASIC_INFORMATION *pFileBasicInfo, IN FILE_STANDARD_INFORMATION *pFileStandardInfo,
+ IN PVOID EaBuffer, IN ULONG EaLength, OUT ULONG *pulCreateAction, OUT SHFLHANDLE *pHandle);
+
+NTSTATUS VBoxMRxCreateFileSuccessTail (PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, RX_FILE_TYPE StorageType, ULONG CreateAction, FILE_BASIC_INFORMATION* pFileBasicInfo,
+ FILE_STANDARD_INFORMATION* pFileStandardInfo, SHFLHANDLE Handle);
+
+VOID VBoxMRxSetSrvOpenFlags (PRX_CONTEXT RxContext, RX_FILE_TYPE StorageType, PMRX_SRV_OPEN SrvOpen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, VBoxMRxCreate)
+#pragma alloc_text(PAGE, VBoxMRxShouldTryToCollapseThisOpen)
+#pragma alloc_text(PAGE, VBoxMRxProcessCreate)
+#pragma alloc_text(PAGE, VBoxMRxCreateFileSuccessTail)
+#pragma alloc_text(PAGE, VBoxMRxSetSrvOpenFlags)
+#endif
+
+NTSTATUS VBoxMRxShouldTryToCollapseThisOpen (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine determines if the mini knows of a good reason not
+ to try collapsing on this open. Presently, the only reason would
+ be if this were a copychunk open.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+ SUCCESS --> okay to try collapse
+ other (MORE_PROCESSING_REQUIRED) --> dont collapse
+
+ --*/
+{
+#ifdef VBOX_SHFL_WITH_COLLAPSE
+ NTSTATUS Status = STATUS_SUCCESS;
+#else
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+#endif
+
+ Log(("VBoxMRxShouldTryToCollapseThisOpen returned %x\n", Status));
+
+ PAGED_CODE();
+
+ return Status;
+}
+
+BOOLEAN VBoxMRxIsStreamFile (PUNICODE_STRING FileName, PUNICODE_STRING AdjustFileName)
+/*++
+
+ Routine Description:
+
+ This routine checks if it is a stream file and return the root file name if true.
+
+ Arguments:
+
+ FileName - the file name needs to be parsed
+ AdjustFileName - the file name contains only root name of the stream
+
+ Return Value:
+
+ BOOLEAN - stream file
+
+ --*/
+{
+ USHORT i;
+ BOOLEAN IsStream = FALSE;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBoxMRxIsStreamFile %.*ls\n", FileName->Length / sizeof(WCHAR), FileName->Buffer));
+
+ for (i = 0; i < FileName->Length / sizeof(WCHAR); i++)
+ {
+ if (FileName->Buffer[i] == L':')
+ {
+ IsStream = TRUE;
+ break;
+ }
+ }
+
+ if (AdjustFileName != NULL)
+ {
+ if (IsStream)
+ {
+ AdjustFileName->Length = AdjustFileName->MaximumLength = i * sizeof(WCHAR);
+ AdjustFileName->Buffer = FileName->Buffer;
+ }
+ else
+ {
+ AdjustFileName->Length = AdjustFileName->MaximumLength = 0;
+ AdjustFileName->Buffer = NULL;
+ }
+ }
+
+ return IsStream;
+}
+
+#define NulMRxGetFcbExtension(pFcb,pExt) \
+ PNULMRX_FCB_EXTENSION pExt = (((pFcb) == NULL) ? NULL : (PNULMRX_FCB_EXTENSION)((pFcb)->Context))
+
+#define NulMRxGetNetRootExtension(pNetRoot,pExt) \
+ PNULMRX_NETROOT_EXTENSION pExt = (((pNetRoot) == NULL) ? NULL : (PNULMRX_NETROOT_EXTENSION)((pNetRoot)->Context))
+
+typedef struct _NULMRX_FCB_EXTENSION_
+{
+ //
+ // Node type code and size
+ //
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+} NULMRX_FCB_EXTENSION, *PNULMRX_FCB_EXTENSION;
+
+//
+// NET_ROOT extension - stores state global to a root
+//
+typedef struct _NULMRX_NETROOT_EXTENSION
+{
+ //
+ // Node type code and size
+ //
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+} NULMRX_NETROOT_EXTENSION, *PNULMRX_NETROOT_EXTENSION;
+
+NTSTATUS NulMRxProcessCreate (IN PNULMRX_FCB_EXTENSION pFcbExtension, IN PVOID EaBuffer, IN ULONG EaLength, OUT PLONGLONG pEndOfFile, OUT PLONGLONG pAllocationSize)
+/*++
+
+ Routine Description:
+
+ This routine processes a create calldown.
+
+ Arguments:
+
+ pFcbExtension - ptr to the FCB extension
+ EaBuffer - ptr to the EA param buffer
+ EaLength - len of EaBuffer
+ pEndOfFile - return end of file value
+ pAllocationSize - return allocation size (which maybe > EOF)
+
+ Notes:
+
+ It is possible to create a file with no EAs
+
+ Return Value:
+
+ None
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxDbgTrace(0, Dbg, ("NulMRxInitializeFcbExtension\n"));
+
+ *pAllocationSize = *pEndOfFile = 0;
+ return Status;
+}
+
+VOID NulMRxSetSrvOpenFlags (PRX_CONTEXT RxContext, RX_FILE_TYPE StorageType, PMRX_SRV_OPEN SrvOpen)
+{
+ PMRX_SRV_CALL SrvCall = (PMRX_SRV_CALL)RxContext->Create.pSrvCall;
+
+ //
+ // set this only if cache manager will be used for mini-rdr handles !
+ //
+ SrvOpen->BufferingFlags |= (FCB_STATE_FILESIZECACHEING_ENABLED | FCB_STATE_FILETIMECACHEING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED | FCB_STATE_LOCK_BUFFERING_ENABLED
+ | FCB_STATE_READBUFFERING_ENABLED |
+#if (NTDDI_VERSION >= NTDDI_VISTA) /* Correct spelling for Vista 6001 SDK. */
+ FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_READCACHING_ENABLED);
+#else
+ FCB_STATE_WRITECACHEING_ENABLED |
+ FCB_STATE_READCACHEING_ENABLED);
+#endif
+}
+
+NTSTATUS NulMRxCreateFileSuccessTail (PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, RX_FILE_TYPE StorageType, ULONG CreateAction, FILE_BASIC_INFORMATION* pFileBasicInfo,
+ FILE_STANDARD_INFORMATION* pFileStandardInfo)
+/*++
+
+ Routine Description:
+
+ This routine finishes the initialization of the fcb and srvopen for a
+ successful open.
+
+ Arguments:
+
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
+
+ FCB_INIT_PACKET InitPacket;
+
+ RxDbgTrace(0, Dbg, ("MRxExCreateFileSuccessTail\n"));
+ PAGED_CODE();
+
+ ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
+ ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
+
+ if (*MustRegainExclusiveResource)
+ { //this is required because of oplock breaks
+ RxAcquireExclusiveFcb(RxContext, capFcb);
+ *MustRegainExclusiveResource = FALSE;
+ }
+
+ // This Fobx should be cleaned up by the wrapper
+ RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
+ if (RxContext->pFobx == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ASSERT(RxIsFcbAcquiredExclusive(capFcb));
+ RxDbgTrace(0, Dbg, ("Storagetype %08lx/Action %08lx\n", StorageType, CreateAction));
+
+ RxContext->Create.ReturnedCreateInformation = CreateAction;
+
+ RxFormInitPacket(InitPacket, &pFileBasicInfo->FileAttributes, &pFileStandardInfo->NumberOfLinks, &pFileBasicInfo->CreationTime, &pFileBasicInfo->LastAccessTime, &pFileBasicInfo->LastWriteTime,
+ &pFileBasicInfo->ChangeTime, &pFileStandardInfo->AllocationSize, &pFileStandardInfo->EndOfFile, &pFileStandardInfo->EndOfFile);
+
+ if (capFcb->OpenCount == 0)
+ {
+ RxFinishFcbInitialization(capFcb, RDBSS_STORAGE_NTC(StorageType), &InitPacket);
+ }
+ else
+ {
+
+ ASSERT(StorageType == 0 || NodeType(capFcb) == RDBSS_STORAGE_NTC(StorageType));
+
+ }
+
+ NulMRxSetSrvOpenFlags(RxContext, StorageType, SrvOpen);
+
+ RxContext->pFobx->OffsetOfNextEaToReturn = 1;
+ //transition happens later
+
+ return Status;
+}
+
+NTSTATUS VBoxMRxCreate (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine opens a file across the network
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOLEAN fMustRegainExclusiveResource = FALSE;
+ RX_FILE_TYPE StorageType = FileTypeFile;
+ ULONG CreateAction = FILE_CREATED;
+ FILE_BASIC_INFORMATION FileBasicInfo;
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
+ PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
+ PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
+ PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+ PVOID EaBuffer = RxContext->Create.EaBuffer;
+ ULONG EaLength = RxContext->Create.EaLength;
+ VBoxMRxGetNetRootExtension(NetRoot,pNetRootExtension);
+ SHFLHANDLE Handle = SHFL_HANDLE_NIL;
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxCreate: %x length=%d\n", RemainingName, RemainingName->Length));
+
+ if (RemainingName->Length)
+ {
+#ifdef VBOX_GUEST
+ Log(("VBOXSF: VBoxMRxCreate: Attempt to open %.*ls Len is %d\n", RemainingName->Length/sizeof(WCHAR), RemainingName->Buffer, RemainingName->Length ));
+#else
+ Log(("VBOXSF: VBoxMRxCreate: Attempt to open %wZ Len is %d\n", RemainingName, RemainingName->Length));
+#endif
+ }
+ else
+ {
+ if (FlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
+ {
+ Log(("VBOXSF: VBoxMRxCreate: Empty name -> Only backslash used\n"));
+ RemainingName = &UnicodeBackslash;
+ }
+ }
+
+ switch (NetRoot->Type)
+ {
+ case NET_ROOT_MAILSLOT:
+ case NET_ROOT_PIPE:
+ case NET_ROOT_PRINT:
+ default:
+ Log(("VBOXSF: VBoxMRxCreate: Type %d not supported or invalid open\n", NetRoot->Type));
+ Status = STATUS_NOT_SUPPORTED;
+ goto Exit;
+
+ case NET_ROOT_WILD: /** @todo what's this?? */
+ case NET_ROOT_DISK:
+ break;
+ }
+
+ FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ //
+ // Squirrel away the scatter list in the FCB extension.
+ // This is done only for data files.
+ //
+ Status = VBoxMRxProcessCreate(RxContext, RemainingName, &FileBasicInfo, &FileStandardInfo, EaBuffer, EaLength, &CreateAction, &Handle);
+ if (Status != STATUS_SUCCESS)
+ {
+ //
+ // error..
+ //
+ Log(("VBOXSF: VBoxMRxCreate: Failed to initialize scatter list!\n"));
+ goto Exit;
+ }
+
+ //
+ // Complete CreateFile contract
+ //
+ Log(("VBOXSF: VBoxMRxCreate: EOF is %d AllocSize is %d\n", (ULONG)FileStandardInfo.EndOfFile.QuadPart, (ULONG)FileStandardInfo.AllocationSize.QuadPart));
+
+ Status = VBoxMRxCreateFileSuccessTail(RxContext, &fMustRegainExclusiveResource, StorageType, CreateAction, &FileBasicInfo, &FileStandardInfo, Handle);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ //
+ // alloc error..
+ //
+ Log(("VBOXSF: VBoxMRxCreate: Failed to allocate Fobx!\n"));
+ goto Exit;
+ }
+
+ if (!RxIsFcbAcquiredExclusive(capFcb))
+ {
+ Assert(!RxIsFcbAcquiredShared(capFcb));
+ VboxRxAcquireExclusiveFcbResourceInMRx(capFcb);
+ }
+
+ Assert(Status != (STATUS_PENDING));
+ Assert(RxIsFcbAcquiredExclusive(capFcb));
+
+ Log(("VBOXSF: VBoxMRxCreate: NetRoot is 0x%x, Fcb is 0x%x, SrvOpen is 0x%x, Fobx is 0x%x\n", NetRoot, capFcb, SrvOpen, RxContext->pFobx));
+ Log(("VBOXSF: VBoxMRxCreate: Exit with status=%08lx\n", Status));
+
+ Exit: return (Status);
+}
+
+NTSTATUS VBoxMRxProcessCreate (IN PRX_CONTEXT RxContext, IN PUNICODE_STRING RemainingName, IN FILE_BASIC_INFORMATION *pFileBasicInfo, IN FILE_STANDARD_INFORMATION *pFileStandardInfo,
+ IN PVOID EaBuffer, IN ULONG EaLength, OUT ULONG *pulCreateAction, OUT SHFLHANDLE *pHandle)
+/*++
+
+ Routine Description:
+
+ This routine processes a create calldown.
+
+ Arguments:
+
+ pFcbExtension - ptr to the FCB extension
+ EaBuffer - ptr to the EA param buffer
+ EaLength - len of EaBuffer
+ pEndOfFile - return end of file value
+ pAllocationSize - return allocation size (which maybe > EOF)
+
+ Notes:
+
+ It is possible to create a file with no EAs
+
+ Return Value:
+
+ None
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot,pNetRootExtension);
+
+ int vboxRC = VINF_SUCCESS;
+
+ /* Various boolean flags. */
+ struct
+ {
+ ULONG CreateDirectory :1;
+ ULONG SequentialOnly :1;
+ ULONG NoIntermediateBuffering :1;
+ ULONG OpenDirectory :1;
+ ULONG IsPagingFile :1;
+ ULONG OpenTargetDirectory :1;
+ ULONG DirectoryFile :1;
+ ULONG NonDirectoryFile :1;
+ ULONG NoEaKnowledge :1;
+ ULONG DeleteOnClose :1;
+ ULONG TemporaryFile :1;
+ ULONG FileNameOpenedDos :1;
+ ULONG PostIrp :1;
+ ULONG OplockPostIrp :1;
+ ULONG TrailingBackslash :1;
+ ULONG FirstLoop :1;
+ ULONG SeparatorEncountered :1;
+ ULONG DriveAcquired :1;
+ } bf;
+
+ ACCESS_MASK DesiredAccess;
+ ULONG Options;
+ UCHAR FileAttributes;
+ ULONG ShareAccess;
+ ULONG CreateDisposition;
+ SHFLCREATEPARMS *pCreateParms = 0;
+
+ Log(("VBOXSF: VBoxMRxProcessCreate\n"));
+ Log(("VBOXSF: VBoxMRxProcessCreate: FileAttributes = %08x\n", RxContext->Create.NtCreateParameters.FileAttributes));
+ Log(("VBOXSF: VBoxMRxProcessCreate: CreateOptions = %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;
+
+ /* Extended attributes are not supported! */
+ if (EaLength)
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: Unsupported: extended attributes!\n"));
+ Status = STATUS_NOT_SUPPORTED;
+ goto failure;
+ }
+
+ /* We do not support opens by file ids yet. */
+ if (FlagOn(Options, FILE_OPEN_BY_FILE_ID))
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: 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.SequentialOnly = BooleanFlagOn(Options, FILE_SEQUENTIAL_ONLY);
+ bf.NoIntermediateBuffering = BooleanFlagOn(Options, FILE_NO_INTERMEDIATE_BUFFERING);
+ bf.NoEaKnowledge = BooleanFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
+ bf.DeleteOnClose = BooleanFlagOn(Options, FILE_DELETE_ON_CLOSE);
+ if (bf.DeleteOnClose)
+ Log(("VBOXSF: VBoxMRxProcessCreate: Delete on close!\n"));
+
+ CreateDisposition = RxContext->Create.NtCreateParameters.Disposition;
+
+ bf.IsPagingFile = BooleanFlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE);
+ if (bf.IsPagingFile)
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: Unsupported: paging file!\n"));
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto failure;
+ }
+
+ 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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: Not allowed: Temporary directories!\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto failure;
+ }
+
+ if (bf.DirectoryFile && bf.NonDirectoryFile)
+ {
+ AssertMsgFailed(("VBOXSF: VBoxMRxProcessCreate: 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.OpenTargetDirectory)
+ {
+ pCreateParms->CreateFlags |= SHFL_CF_OPEN_TARGET_DIRECTORY;
+ }
+
+ if (bf.DirectoryFile)
+ {
+ if (CreateDisposition != FILE_CREATE && CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF)
+ {
+ AssertMsgFailed(("VBOXSF: VBoxMRxProcessCreate: Invalid disposition %x for directory!\n", CreateDisposition));
+ Status = STATUS_INVALID_PARAMETER;
+ goto failure;
+ }
+
+ pCreateParms->CreateFlags |= SHFL_CF_DIRECTORY;
+ }
+
+ Log(("VBOXSF: VBoxMRxProcessCreate: CreateDisposition = %08x\n", CreateDisposition));
+
+ switch (CreateDisposition)
+ {
+ case FILE_SUPERSEDE:
+ pCreateParms->CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
+ Log(("VBOXSF: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
+ break;
+
+ default:
+ AssertMsgFailed(("VBOXSF: VBoxMRxProcessCreate: Unexpected create disposition: 0x%08X\n", CreateDisposition));
+ Status = STATUS_INVALID_PARAMETER;
+ goto failure;
+ }
+
+ Log(("VBOXSF: VBoxMRxProcessCreate: DesiredAccess = 0x%08x\n", DesiredAccess));
+ Log(("VBOXSF: VBoxMRxProcessCreate: ShareAccess = 0x%08x\n", ShareAccess));
+
+ if (DesiredAccess & FILE_READ_DATA)
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: FILE_READ_DATA\n"));
+ pCreateParms->CreateFlags |= SHFL_CF_ACCESS_READ;
+ }
+
+ if (DesiredAccess & FILE_WRITE_DATA)
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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);
+
+#ifdef VBOX_FAKE_IO_CREATE
+ {
+ LARGE_INTEGER liSystemTime;
+ pFileBasicInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ KeQuerySystemTime(&liSystemTime);
+ pFileBasicInfo->CreationTime = liSystemTime;
+ pFileBasicInfo->LastAccessTime = liSystemTime;
+ pFileBasicInfo->LastWriteTime = liSystemTime;
+ pFileBasicInfo->ChangeTime = liSystemTime;
+ pFileStandardInfo->AllocationSize.QuadPart = 0;
+ pFileStandardInfo->EndOfFile.QuadPart = 0;
+ pFileStandardInfo->NumberOfLinks = 0;
+
+ *pulCreateAction = FILE_CREATED;
+
+ *pHandle = (SHFLHANDLE)0xABCDEF00;
+ }
+#else
+ {
+ PSHFLSTRING ParsedPath = 0;
+ ULONG ParsedPathSize;
+
+ /* Calculate length required for parsed path.
+ */
+ ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR));
+
+ Log(("VBOXSF: VBoxMRxProcessCreate: ParsedPathSize = %d\n", ParsedPathSize));
+
+ ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+ if (NULL == ParsedPath)
+ {
+ 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(("ParsedPath: %.*ls\n", ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
+
+ /* Call host. */
+ Log(("VBOXSF: VBoxMRxProcessCreate: vboxCallCreate called.\n"));
+ vboxRC = vboxCallCreate(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, pCreateParms);
+ vbsfFreeNonPagedMem(ParsedPath);
+ }
+
+ Log(("VBOXSF: VBoxMRxProcessCreate: vboxCallCreate returns vboxRC = %Rrc, Result = %x\n", vboxRC, pCreateParms->Result));
+ if (RT_FAILURE(vboxRC))
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: vboxCallCreate failed with %Rrc\n", 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 in the next switch below. */
+ 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: VBoxMRxProcessCreate: Path not found\n"));
+ *pulCreateAction = FILE_DOES_NOT_EXIST;
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ goto failure;
+ }
+
+ case SHFL_FILE_NOT_FOUND:
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: File not found\n"));
+ *pulCreateAction = FILE_DOES_NOT_EXIST;
+ if (pCreateParms->Handle == SHFL_HANDLE_NIL)
+ {
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto failure;
+ }
+
+ /* Here we can only have the OpenTargetDirectory mode. */
+ if (!bf.OpenTargetDirectory)
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: File not found but have a handle!\n"));
+ Status = STATUS_UNSUCCESSFUL;
+ goto failure;
+ }
+ /* File components does not exist but target directory was opened. */
+ break;
+ }
+
+ case SHFL_FILE_EXISTS:
+ {
+ Log(("VBOXSF: VBoxMRxProcessCreate: File exists, Handle = %08x\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: VBoxMRxProcessCreate: Existing file was not opened!\n"));
+ Status = STATUS_ACCESS_DENIED;
+ goto failure;
+ }
+
+ if (bf.OpenTargetDirectory)
+ {
+ *pulCreateAction = FILE_EXISTS;
+ }
+ else
+ {
+ *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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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: VBoxMRxProcessCreate: 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))
+ {
+ Assert(!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: VBoxMRxProcessCreate: AllocationSize = %RX64, EndOfFile = %RX64\n", pCreateParms->Info.cbAllocated, pCreateParms->Info.cbObject));
+ }
+ else
+ {
+ Assert(FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY));
+ pFileStandardInfo->AllocationSize.QuadPart = 0;
+ pFileStandardInfo->EndOfFile.QuadPart = 0;
+ pFileStandardInfo->Directory = TRUE;
+ }
+ pFileStandardInfo->NumberOfLinks = 0;
+ pFileStandardInfo->DeletePending = FALSE;
+#endif
+
+ vbsfFreeNonPagedMem(pCreateParms);
+ return Status;
+
+ failure:
+
+ Log(("VBOXSF: VBoxMRxProcessCreate: Returned with status = 0x%08lx\n", Status));
+ if (pCreateParms && pCreateParms->Handle != SHFL_HANDLE_NIL)
+ {
+#ifndef VBOX_FAKE_IO_CREATE
+ vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pCreateParms->Handle);
+#endif
+ *pHandle = SHFL_HANDLE_NIL;
+ }
+
+ if (pCreateParms)
+ vbsfFreeNonPagedMem(pCreateParms);
+
+ return Status;
+}
+
+VOID VBoxMRxSetSrvOpenFlags (PRX_CONTEXT RxContext, RX_FILE_TYPE StorageType, PMRX_SRV_OPEN SrvOpen)
+{
+ PMRX_SRV_CALL SrvCall = (PMRX_SRV_CALL)RxContext->Create.pSrvCall;
+
+ //
+ // set this only if cache manager will be used for mini-rdr handles !
+ //
+ Log(("VBoxMRxSetSrvOpenFlags %x\n", SrvOpen->BufferingFlags));
+#if 0
+ /* This seems to be the root cause of the strange bug checks when enabling
+ * the driver verifier.
+ */
+ SrvOpen->BufferingFlags |= (FCB_STATE_WRITECACHEING_ENABLED |
+ FCB_STATE_FILESIZECACHEING_ENABLED |
+ FCB_STATE_FILETIMECACHEING_ENABLED |
+ FCB_STATE_WRITEBUFFERING_ENABLED |
+ FCB_STATE_LOCK_BUFFERING_ENABLED |
+ FCB_STATE_READBUFFERING_ENABLED |
+ FCB_STATE_READCACHEING_ENABLED);
+#endif
+}
+
+NTSTATUS VBoxMRxCreateFileSuccessTail (PRX_CONTEXT RxContext, PBOOLEAN MustRegainExclusiveResource, RX_FILE_TYPE StorageType, ULONG CreateAction, FILE_BASIC_INFORMATION* pFileBasicInfo,
+ FILE_STANDARD_INFORMATION* pFileStandardInfo, SHFLHANDLE Handle)
+/*++
+
+ Routine Description:
+
+ This routine finishes the initialization of the fcb and srvopen for a
+ successful open.
+
+ Arguments:
+
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
+ PMRX_VBOX_FOBX pVBoxFobx;
+
+ FCB_INIT_PACKET InitPacket;
+
+ Log(("VBOXSF: VBoxMRxCreateFileSuccessTail\n"));
+ PAGED_CODE();
+
+ Assert(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
+ Assert(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
+
+ if (*MustRegainExclusiveResource)
+ { //this is required because of oplock breaks
+ VboxRxAcquireExclusiveFcbResourceInMRx(capFcb);
+ *MustRegainExclusiveResource = FALSE;
+ }
+
+ // This Fobx should be cleaned up by the wrapper
+ RxContext->pFobx = VboxRxCreateNetFobx(RxContext, SrvOpen);
+ if (RxContext->pFobx == NULL)
+ {
+ AssertFailed();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Assert(VBoxRxIsFcbAcquiredExclusive(capFcb));
+ Log(("VBOXSF: VBoxMRxCreateFileSuccessTail: StorageType = 0x%08lx, Action = 0x%08lx\n", StorageType, CreateAction));
+
+ RxContext->Create.ReturnedCreateInformation = CreateAction;
+
+ RxFormInitPacket(InitPacket, &pFileBasicInfo->FileAttributes, &pFileStandardInfo->NumberOfLinks, &pFileBasicInfo->CreationTime, &pFileBasicInfo->LastAccessTime, &pFileBasicInfo->LastWriteTime,
+ &pFileBasicInfo->ChangeTime, &pFileStandardInfo->AllocationSize, &pFileStandardInfo->EndOfFile, &pFileStandardInfo->EndOfFile);
+
+ if (capFcb->OpenCount == 0)
+ {
+ VboxRxFinishFcbInitialization(capFcb, RDBSS_STORAGE_NTC(StorageType), &InitPacket);
+ }
+ else
+ {
+ Assert(StorageType == 0 || NodeType(capFcb) == RDBSS_STORAGE_NTC(StorageType));
+ }
+
+ VBoxMRxSetSrvOpenFlags(RxContext, StorageType, SrvOpen);
+
+ RxContext->pFobx->OffsetOfNextEaToReturn = 1;
+ //transition happens later
+
+ pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+ Assert(pVBoxFobx);
+ if (pVBoxFobx)
+ {
+ Log(("VBOXSF: VBoxMRxCreateFileSuccessTail: VBoxFobx = %p\n", pVBoxFobx));
+ pVBoxFobx->hFile = Handle;
+ pVBoxFobx->pSrvCall = RxContext->Create.pSrvCall;
+ pVBoxFobx->FileStandardInfo = *pFileStandardInfo;
+ pVBoxFobx->FileBasicInfo = *pFileBasicInfo;
+ pVBoxFobx->fKeepCreationTime = FALSE;
+ pVBoxFobx->fKeepLastAccessTime = FALSE;
+ pVBoxFobx->fKeepLastWriteTime = FALSE;
+ pVBoxFobx->fKeepChangeTime = FALSE;
+ }
+ else return STATUS_INSUFFICIENT_RESOURCES;
+
+ return Status;
+}
+
+NTSTATUS VBoxMRxCollapseOpen (IN OUT PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine collapses a open locally
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+#ifdef VBOX_SHFL_WITH_COLLAPSE
+ NTSTATUS Status;
+
+ RxCaptureFcb;
+ RxCaptureRequestPacket;
+
+ PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
+ PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
+ PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+
+ Log(("VBOXSF: VBoxMRxCollapseOpen: Old Fobx = %p, old VBoxFobx = %p\n", RxContext->pFobx, pVBoxFobx));
+
+ RxContext->pFobx = (PMRX_FOBX)RxCreateNetFobx( RxContext, SrvOpen);
+ pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+
+ Log(("VBOXSF: VBoxMRxCollapseOpen: New Fobx = %p, new VBoxFobx = %p\n", RxContext->pFobx, pVBoxFobx));
+
+ if (RxContext->pFobx != NULL)
+ {
+ SHFLCREATEPARMS CreateParms;
+ PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+ int vboxRC;
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ VBoxMRxGetNetRootExtension(capFcb->pNetRoot,pNetRootExtension);
+ FILE_BASIC_INFORMATION * pFileBasicInfo;
+ FILE_STANDARD_INFORMATION* pFileStandardInfo;
+
+ Assert(RxIsFcbAcquiredExclusive(capFcb));
+
+ RxContext->pFobx->OffsetOfNextEaToReturn = 1;
+ capReqPacket->IoStatus.Information = FILE_OPENED;
+ Status = STATUS_SUCCESS;
+
+ /* Initialize create parameters. */
+ RtlZeroMemory (&CreateParms, sizeof (SHFLCREATEPARMS));
+
+ CreateParms.Handle = SHFL_HANDLE_NIL;
+ CreateParms.Result = SHFL_NO_RESULT;
+
+ /* Assume it's a directory; open existing, read-only access, deny-none sharing */
+ --> incorrect
+ CreateParms.CreateFlags = SHFL_CF_OPEN_TARGET_DIRECTORY
+ | SHFL_CF_DIRECTORY
+ | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW
+ | SHFL_CF_ACCESS_READ
+ | SHFL_CF_ACCESS_DENYNONE;
+ {
+ PSHFLSTRING ParsedPath = 0;
+ ULONG ParsedPathSize;
+
+ /* Calculate length required for parsed path.
+ */
+ ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR));
+
+ Log(("ParsedPathSize %d\n", ParsedPathSize));
+
+ ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+ if (NULL == ParsedPath)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ 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);
+
+ /* Call host. */
+ vboxRC = vboxCallCreate (&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, &CreateParms);
+
+ if (ParsedPath)
+ vbsfFreeNonPagedMem (ParsedPath);
+ }
+
+ Log(("VBoxMRxCollapseOpen result %Rrc Result=%x\n", vboxRC, CreateParms.Result));
+ if (RT_FAILURE(vboxRC))
+ {
+ /* A host/guest communication error occurred while processing the request. */
+ AssertMsgFailed(("VBOXSF: vboxCallCreate failed with %Rrc\n", vboxRC));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /*
+ * The request succeeded. Analyze host response,
+ */
+ switch (CreateParms.Result)
+ {
+ case SHFL_PATH_NOT_FOUND:
+ {
+ /* Path to object does not exist. */
+ Log(("VBOXSF: Path not found\n"));
+ return STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ case SHFL_FILE_NOT_FOUND:
+ {
+ Log(("VBOXSF: File not found\n"));
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ case SHFL_FILE_EXISTS:
+ {
+ Log(("VBOXSF: Object exists.\n"));
+ break; /* existing dir opened */
+ }
+
+ default:
+ {
+ Log(("VBOXSF: VBoxSF: invalid CreateResult from host %08X\n", CreateParms.Result));
+ return STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ }
+
+ pFileBasicInfo = &pVBoxFobx->FileBasicInfo;
+ pFileStandardInfo = &pVBoxFobx->FileStandardInfo;
+
+ /* Translate attributes */
+ pFileBasicInfo->FileAttributes = VBoxToNTFileAttributes(CreateParms.Info.Attr.fMode);
+
+ /* Translate file times */
+ pFileBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.BirthTime); /* ridiculous name */
+ pFileBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.AccessTime);
+ pFileBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.ModificationTime);
+ pFileBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&CreateParms.Info.ChangeTime);
+
+ Assert(FlagOn(CreateParms.Info.Attr.fMode, RTFS_DOS_DIRECTORY));
+ pFileStandardInfo->AllocationSize.QuadPart = 0;
+ pFileStandardInfo->EndOfFile.QuadPart = 0;
+ pFileStandardInfo->Directory = TRUE;
+ pFileStandardInfo->NumberOfLinks = 0;
+ pFileStandardInfo->DeletePending = FALSE;
+
+ Log(("VBOXSF: VBoxMRxCollapseOpen VBoxFobx=%p\n", pVBoxFobx));
+ pVBoxFobx->hFile = CreateParms.Handle;
+ pVBoxFobx->pSrvCall = RxContext->Create.pSrvCall;
+ pVBoxFobx->FileStandardInfo = *pFileStandardInfo;
+ pVBoxFobx->FileBasicInfo = *pFileBasicInfo;
+ }
+ else
+ {
+ Status = (STATUS_INSUFFICIENT_RESOURCES);
+ AssertFailed();
+ }
+
+ return Status;
+#else
+
+#ifdef DEBUG
+ RxCaptureFcb;
+ RxCaptureRequestPacket;
+
+ PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
+ PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
+ PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+
+ Log(("VBOXSF: VBoxMRxCollapseOpen: Old Fobx = %p, old VBoxFobx = %p -> Not implemented!\n", RxContext->pFobx, pVBoxFobx));
+#endif
+ return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+NTSTATUS VBoxMRxComputeNewBufferingState (IN OUT PMRX_SRV_OPEN pMRxSrvOpen, IN PVOID pMRxContext, OUT PULONG pNewBufferingState)
+/*++
+
+ Routine Description:
+
+ This routine maps specific oplock levels into the appropriate RDBSS
+ buffering state flags
+
+ Arguments:
+
+ pMRxSrvOpen - the MRX SRV_OPEN extension
+
+ pMRxContext - the context passed to RDBSS at Oplock indication time
+
+ pNewBufferingState - the place holder for the new buffering state
+
+ Return Value:
+
+
+ Notes:
+
+ --*/
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+
+ Log(("VBOXSF: VBoxMRxComputeNewBufferingState \n"));
+ return (Status);
+}
+
+NTSTATUS VBoxMRxDeallocateForFcb (IN OUT PMRX_FCB pFcb)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBOXSF: VBoxMRxDeallocateForFcb\n"));
+
+ return (Status);
+}
+
+NTSTATUS VBoxMRxTruncate (IN PRX_CONTEXT pRxContext)
+/*++
+
+ Routine Description:
+
+ This routine truncates the contents of a file system object
+
+ Arguments:
+
+ pRxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ Log(("VBoxMRxTruncate\n"));
+ AssertMsgFailed(("Found a truncate"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxCleanupFobx (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine cleansup a file system object...normally a noop. unless it's a pipe in which case
+ we do the close at cleanup time and mark the file as being not open.
+
+ Arguments:
+
+ pRxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ RxCaptureFcb;
+ RxCaptureFobx;
+
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
+ NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
+ PMRX_SRV_OPEN pSrvOpen = NULL;
+ BOOLEAN SearchHandleOpen = FALSE;
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxCleanupFobx: capFcb = %p, capFobx = %p\n", capFcb, capFobx));
+ Assert(capFcb);
+ Assert(capFobx);
+
+ pSrvOpen = capFobx->pSrvOpen;
+ Assert(pSrvOpen);
+
+ Assert(NodeType(pSrvOpen) == RDBSS_NTC_SRVOPEN);
+ Assert(NodeTypeIsFcb(capFcb));
+
+ if (NULL == pVBoxFobx)
+ return STATUS_INVALID_PARAMETER;
+
+ Log(("VBOXSF: VBoxMRxCleanupFobx: vboxFobx = %p, Handle = 0x%08x\n", pVBoxFobx, pVBoxFobx->hFile));
+
+ /* Close file */
+ if (!((capFcb->pNetRoot->Type != NET_ROOT_PIPE) && !SearchHandleOpen))
+ {
+ if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
+ {
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+
+#ifndef VBOX_FAKE_IO_CREATE
+ int vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+ AssertRC(vboxRC);
+#endif
+
+ pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+ }
+ }
+
+ if (FlagOn(capFcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ Log(("VBOXSF: VBoxMRxCleanupFobx: File orphaned\n"));
+ return (STATUS_SUCCESS);
+ }
+
+ if ((capFcb->pNetRoot->Type != NET_ROOT_PIPE) && !SearchHandleOpen)
+ {
+ Log(("VBOXSF: VBoxMRxCleanupFobx: File not for closing at cleanup\n"));
+ return (STATUS_SUCCESS);
+ }
+
+ Log(("VBOXSF: VBoxMRxCleanupFobx: Returned with status = 0x%08lx\n", Status));
+ return Status;
+}
+
+NTSTATUS VBoxMRxForcedClose (IN PMRX_SRV_OPEN pSrvOpen)
+/*++
+
+ Routine Description:
+
+ This routine closes a file system object
+
+ Arguments:
+
+ pSrvOpen - the instance to be closed
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ Notes:
+
+
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxForcedClose\n"));
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS VBoxMRxCloseSrvOpen (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine closes a file across the network
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ RxCaptureFcb;
+ RxCaptureFobx;
+
+ int vboxRC = 0;
+ PMRX_SRV_OPEN pSrvOpen = NULL;
+ PUNICODE_STRING RemainingName = NULL;
+ NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+ PAGED_CODE();
+
+ Log(("VBOXSF: VBoxMRxCloseSrvOpen: capFcb = %p, capFobx = %p\n", capFcb, capFobx));
+ Log(("VBOXSF: VBoxMRxCloseSrvOpen: pVBoxFobx = 0x%08x\n", pVBoxFobx));
+
+ Assert(capFcb);
+ Assert(capFobx);
+
+ pSrvOpen = capFobx->pSrvOpen;
+ Assert(pSrvOpen);
+
+ RemainingName = pSrvOpen->pAlreadyPrefixedName;
+ Log(("VBOXSF: VBoxMRxCloseSrvOpen: Remaining name = %.*ls, Len = %d\n", RemainingName->Length / sizeof(WCHAR), RemainingName->Buffer, RemainingName->Length));
+
+ if (NULL == pVBoxFobx)
+ return STATUS_INVALID_PARAMETER;
+
+ /* If we renamed or delete the file/dir, then it's already closed */
+ if (FlagOn(pSrvOpen->Flags, (SRVOPEN_FLAG_FILE_RENAMED | SRVOPEN_FLAG_FILE_DELETED)))
+ {
+ Assert(pVBoxFobx->hFile == SHFL_HANDLE_NIL);
+
+ Log(("VBOXSF: VBoxMRxCloseSrvOpen: File was renamed; ignore close!\n"));
+ return STATUS_SUCCESS;
+ }
+
+ /* Close file */
+ if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
+ {
+#ifndef VBOX_FAKE_IO_CREATE
+ vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+ AssertRC(vboxRC);
+#endif
+ pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+ }
+
+ if (capFcb->FcbState & FCB_STATE_DELETE_ON_CLOSE)
+ Log(("VBOXSF: VBoxMRxCloseSrvOpen: Delete on close. Open count = %d\n", capFcb->OpenCount));
+
+ /* Remove file or directory if delete action is pending. */
+ if ((capFcb->FcbState & FCB_STATE_DELETE_ON_CLOSE) && capFcb->OpenCount == 0)
+ {
+ Status = VBoxMRxRemove(RxContext);
+ }
+
+ return (Status);
+}
+
+NTSTATUS VBoxMRxDeallocateForFobx (IN OUT PMRX_FOBX pFobx)
+{
+ Log(("VBOXSF: VBoxMRxDeallocateForFobx\n"));
+
+ return (STATUS_SUCCESS);
+}
+
+NTSTATUS VBoxMRxRemove (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine removes a file or directory
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
+ int vboxRC;
+ PSHFLSTRING ParsedPath = 0;
+ ULONG ParsedPathSize;
+ PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBOXSF: VBoxMRxRemove 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)
+ {
+#ifndef VBOX_FAKE_IO_CREATE
+ vboxRC = vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile);
+ AssertRC(vboxRC);
+#endif
+ pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+ }
+
+ /* Calculate length required for parsed path.
+ */
+ ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR));
+
+ Log(("ParsedPathSize %d\n", ParsedPathSize));
+
+ ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+ if (!ParsedPath)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+ Log(("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. */
+#ifdef VBOX_FAKE_IO_DELETE
+ vboxRC = VINF_SUCCESS;
+#else
+ vboxRC = vboxCallRemove(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, (pVBoxFobx->FileStandardInfo.Directory) ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE);
+#endif
+
+ if (ParsedPath)
+ vbsfFreeNonPagedMem(ParsedPath);
+
+ Status = VBoxErrorToNTStatus(vboxRC);
+ if (vboxRC != VINF_SUCCESS)
+ Log(("vboxCallRemove failed with %d (status=%d)\n", vboxRC, Status));
+
+ if (vboxRC == VINF_SUCCESS)
+ SetFlag(pSrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED);
+
+ return Status;
+}
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h
new file mode 100644
index 00000000000..7cd8691cf9b
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/precomp.h
@@ -0,0 +1,39 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+
+ --*/
+
+#define MINIRDR__NAME NulMRx
+#define ___MINIRDR_IMPORTS_NAME (NulMRxDeviceObject->RdbssExports)
+
+#include <ntifs.h>
+
+#include "rx.h"
+
+#include "nodetype.h"
+#include "netevent.h"
+
+#include <windef.h>
+
+#include "nulmrx.h"
+#include "minip.h"
+#include <lmcons.h> // from the Win32 SDK
+#include "mrxglobs.h"
+
+#ifdef VBOX
+#define try __try
+#define leave __leave
+#define finally __finally
+#define except __except
+/* bird: Added this to kill warnings about using unprototyped functions.
+ * I hope it doesn't break anything... */
+#include "vbsfhlp.h"
+
+////#define VBOX_FAKE_IO
+////#define VBOX_FAKE_IO_READ_WRITE
+////#define VBOX_FAKE_IO_CREATE
+////#define VBOX_FAKE_IO_DELETE
+
+#endif
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm
new file mode 100644
index 00000000000..cf0c6a2bfe5
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss.asm
@@ -0,0 +1,92 @@
+;
+; Export definitions
+;
+; Copyright (C) 2006-2007 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "VBox/asmdefs.mac"
+
+extern __imp__RxAcquireExclusiveFcbResourceInMRx
+extern __imp__RxCreateNetFobx
+extern __imp__RxCreateRxContext
+extern __imp__RxDereferenceAndDeleteRxContext_Real
+extern __imp__RxDispatchToWorkerThread
+extern __imp__RxFinalizeConnection
+extern __imp__RxFinishFcbInitialization
+extern __imp__RxFsdDispatch
+extern __imp__RxGetFileSizeWithLock
+extern __imp__RxGetFileSizeWithLock
+extern __imp__RxLowIoGetBufferAddress
+extern __imp__RxRegisterMinirdr
+extern __imp__RxStartMinirdr
+extern __imp__RxStopMinirdr
+extern __imp__RxpUnregisterMinirdr
+extern __imp__RxGetRDBSSProcess
+
+
+BEGINPROC RxAcquireExclusiveFcbResourceInMRx@4
+ jmp dword [__imp__RxAcquireExclusiveFcbResourceInMRx]
+ENDPROC RxAcquireExclusiveFcbResourceInMRx@4
+
+BEGINPROC RxCreateNetFobx@8
+ jmp dword [__imp__RxCreateNetFobx]
+ENDPROC RxCreateNetFobx@8
+
+BEGINPROC RxCreateRxContext@12
+ jmp dword [__imp__RxCreateRxContext]
+ENDPROC RxCreateRxContext@12
+
+BEGINPROC RxDereferenceAndDeleteRxContext_Real@4
+ jmp dword [__imp__RxDereferenceAndDeleteRxContext_Real]
+ENDPROC RxDereferenceAndDeleteRxContext_Real@4
+
+BEGINPROC RxDispatchToWorkerThread@16
+ jmp dword [__imp__RxDispatchToWorkerThread]
+ENDPROC RxDispatchToWorkerThread@16
+
+BEGINPROC RxFinalizeConnection@12
+ jmp dword [__imp__RxFinalizeConnection]
+ENDPROC RxFinalizeConnection@12
+
+BEGINPROC RxFinishFcbInitialization@12
+ jmp dword [__imp__RxFinishFcbInitialization]
+ENDPROC RxFinishFcbInitialization@12
+
+BEGINPROC RxFsdDispatch@8
+ jmp dword [__imp__RxFsdDispatch]
+ENDPROC RxFsdDispatch@8
+
+BEGINPROC RxGetFileSizeWithLock@8
+ jmp dword [__imp__RxGetFileSizeWithLock]
+ENDPROC RxGetFileSizeWithLock@8
+
+BEGINPROC RxGetRDBSSProcess@0
+ jmp dword [__imp__RxGetRDBSSProcess]
+ENDPROC RxGetRDBSSProcess@0
+
+BEGINPROC RxLowIoGetBufferAddress@4
+ jmp dword [__imp__RxLowIoGetBufferAddress]
+ENDPROC RxLowIoGetBufferAddress@4
+
+BEGINPROC RxRegisterMinirdr@32
+ jmp dword [__imp__RxRegisterMinirdr]
+ENDPROC RxRegisterMinirdr@32
+
+BEGINPROC RxStartMinirdr@8
+ jmp dword [__imp__RxStartMinirdr]
+ENDPROC RxStartMinirdr@8
+
+BEGINPROC RxStopMinirdr@8
+ jmp dword [__imp__RxStopMinirdr]
+ENDPROC RxStopMinirdr@8
+
+BEGINPROC RxpUnregisterMinirdr@4
+ jmp dword [__imp__RxpUnregisterMinirdr]
+ENDPROC RxpUnregisterMinirdr@4
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/Makefile.kup
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def
new file mode 100644
index 00000000000..d849dfac17f
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss/rdbss.def
@@ -0,0 +1,134 @@
+;
+; Export definitions
+;
+; Copyright (C) 2006-2007 Oracle Corporation
+;
+; Oracle Corporation confidential
+; All rights reserved
+;
+
+LIBRARY RDBSS.SYS
+
+EXPORTS
+ RxAcquireExclusiveFcbResourceInMRx
+ RxAcquireSharedFcbResourceInMRx
+ RxAcquireSharedFcbResourceInMRxEx
+ RxAssert
+ RxAssociateContextWithMid
+ RxCancelTimerRequest
+ RxCeAllocateIrpWithMDL
+ RxCeBuildAddress
+ RxCeBuildConnection
+ RxCeBuildConnectionOverMultipleTransports
+ RxCeBuildTransport
+ RxCeBuildVC
+ RxCeCancelConnectRequest
+ RxCeFreeIrp
+ RxCeInitiateVCDisconnect
+ RxCeQueryAdapterStatus
+ RxCeQueryInformation
+ RxCeQueryTransportInformation
+ RxCeSend
+ RxCeSendDatagram
+ RxCeTearDownAddress
+ RxCeTearDownConnection
+ RxCeTearDownTransport
+ RxCeTearDownVC
+ RxChangeBufferingState
+ RxCompleteRequest
+ RxCompleteRequest_Real
+ RxCreateMidAtlas
+ RxCreateNetFcb
+ RxCreateNetFobx
+ RxCreateNetRoot
+ RxCreateRxContext
+ RxCreateSrvCall
+ RxCreateSrvOpen
+ RxCreateVNetRoot
+ RxDbgBreakPoint
+ RxDereference
+ RxDereferenceAndDeleteRxContext_Real
+ RxDestroyMidAtlas
+ RxDispatchToWorkerThread
+ RxFinalizeConnection
+ RxFinalizeNetFcb
+ RxFinalizeNetFobx
+ RxFinalizeNetRoot
+ RxFinalizeSrvCall
+ RxFinalizeSrvOpen
+ RxFinalizeVNetRoot
+ RxFinishFcbInitialization
+ RxForceFinalizeAllVNetRoots
+ RxFsdDispatch
+ RxFsdPostRequest
+ RxGetFileSizeWithLock
+ RxGetRDBSSProcess
+ RxIndicateChangeOfBufferingState
+ RxIndicateChangeOfBufferingStateForSrvOpen
+ RxInferFileType
+ RxInitializeContext
+ RxLockEnumerator
+ RxLogEventDirect
+ RxLogEventWithAnnotation
+ RxLogEventWithBufferDirect
+ RxLowIoCompletion
+ RxLowIoGetBufferAddress
+ RxMakeLateDeviceAvailable
+ RxMapAndDissociateMidFromContext
+ RxMapMidToContext
+ RxMapSystemBuffer
+ RxNameCacheActivateEntry
+ RxNameCacheAddNameCacheControlToGlobalList
+ RxNameCacheCheckEntry
+ RxNameCacheCreateEntry
+ RxNameCacheExpireAndFinalizeEx
+ RxNameCacheExpireEntry
+ RxNameCacheExpireEntryWithShortName
+ RxNameCacheFetchEntry
+ RxNameCacheFinalize
+ RxNameCacheFinalizeEx
+ RxNameCacheFreeActiveListEntries
+ RxNameCacheFreeEntry
+ RxNameCacheFreeNotifiedFreeList
+ RxNameCacheInitialize
+ RxNameCacheInitializeEx
+ RxNameCacheNotifyFreeListEntries
+ RxNameCacheRemoveNameCacheCtlFromGlobalList
+ RxNameCacheScavengeNameCaches
+ RxNewMapUserBuffer
+ RxPostOneShotTimerRequest
+ RxPostRecurrentTimerRequest
+ RxPostToWorkerThread
+ RxPrefixTableLookupName
+ RxPrepareContextForReuse
+ RxPrepareToReparseSymbolicLink
+ RxPurgeAllFobxs
+ RxPurgeRelatedFobxs
+ RxReassociateMid
+ RxReference
+ RxRegisterMinirdr
+ RxReleaseFcbResourceForThreadInMRx
+ RxReleaseFcbResourceInMRx
+ RxResumeBlockedOperations_Serially
+ RxScavengeAllFobxs
+ RxScavengeFobxsForNetRoot
+ RxSetDomainForMailslotBroadcast
+ RxSetMinirdrCancelRoutine
+ RxSetSrvCallDomainName
+ RxSpinDownMRxDispatcher
+ RxStartMinirdr = _RxStartMinirdr@8
+ RxStopMinirdr
+ RxpAcquirePrefixTableLockExclusive
+ RxpAcquirePrefixTableLockShared
+ RxpDereferenceAndFinalizeNetFcb
+ RxpDereferenceNetFcb
+ RxpReferenceNetFcb
+ RxpReleasePrefixTableLock
+ RxpTrackDereference
+ RxpTrackReference
+ RxpUnregisterMinirdr
+ _RxAllocatePoolWithTag
+ _RxCheckMemoryBlock
+ _RxFreePool
+ __RxFillAndInstallFastIoDispatch
+ __RxSynchronizeBlockingOperationsMaybeDroppingFcbLock
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c
new file mode 100644
index 00000000000..a742098cc14
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.c
@@ -0,0 +1,99 @@
+#include "rdbss_vbox.h"
+#pragma hdrstop
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* KeXXXXXXX or ExXXXXXXXXX */
+
+NTSTATUS VBoxRxRegisterMinirdr (PRDBSS_DEVICE_OBJECT *DeviceObject, PDRIVER_OBJECT DriverObject, PMINIRDR_DISPATCH MrdrDispatch, ULONG Controls, PUNICODE_STRING DeviceName, ULONG DeviceExtensionSize,
+ DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics)
+{
+ return RxRegisterMinirdr(DeviceObject, DriverObject, MrdrDispatch, Controls, DeviceName, DeviceExtensionSize, DeviceType, DeviceCharacteristics);
+ return STATUS_SUCCESS;
+}
+
+VOID VBoxRxUnregisterMinirdr (PRDBSS_DEVICE_OBJECT RxDeviceObject)
+{
+ RxUnregisterMinirdr(RxDeviceObject);
+}
+
+NTSTATUS VBoxRxStartMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp)
+{
+ return RxStartMinirdr(RxContext, PostToFsp);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxRxStopMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp)
+{
+ return RxStopMinirdr(RxContext, PostToFsp);
+ return STATUS_SUCCESS;
+}
+
+PRX_CONTEXT VBoxRxCreateRxContext (PIRP Irp, PRDBSS_DEVICE_OBJECT RxDeviceObject, ULONG InitialContextFlags)
+{
+ return RxCreateRxContext(Irp, RxDeviceObject, InitialContextFlags);
+}
+
+VOID VBoxRxDereferenceAndDeleteRxContext (PRX_CONTEXT RxContext)
+{
+ RxDereferenceAndDeleteRxContext(RxContext);
+}
+
+NTSTATUS VBoxRxFinalizeConnection (OUT PNET_ROOT NetRoot, OUT PV_NET_ROOT VNetRoot, LOGICAL Level)
+{
+ return RxFinalizeConnection(NetRoot, VNetRoot, Level);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxRxFsdDispatch (PRDBSS_DEVICE_OBJECT RxDeviceObject, PIRP Irp)
+{
+ return RxFsdDispatch(RxDeviceObject, Irp);
+ return STATUS_SUCCESS;
+}
+
+VOID VBoxRxGetFileSizeWithLock (PFCB Fcb, OUT PLONGLONG FileSize)
+{
+ RxGetFileSizeWithLock(Fcb, FileSize);
+}
+
+PVOID VBoxRxLowIoGetBufferAddress (IN PRX_CONTEXT RxContext)
+{
+ return RxLowIoGetBufferAddress(RxContext);
+}
+
+NTSTATUS VBoxRxDispatchToWorkerThread (OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject, WORK_QUEUE_TYPE WorkQueueType, PRX_WORKERTHREAD_ROUTINE Routine, PVOID pContext)
+{
+ return RxDispatchToWorkerThread(pMRxDeviceObject, WorkQueueType, Routine, pContext);
+ return STATUS_SUCCESS;
+}
+
+/* FCB stuff */
+
+VOID VboxRxFinishFcbInitialization (PMRX_FCB MrxFcb, RDBSS_STORAGE_TYPE_CODES RdbssStorageType, PFCB_INIT_PACKET InitPacket)
+{
+ RxFinishFcbInitialization(MrxFcb, RdbssStorageType, InitPacket);
+}
+
+NTSTATUS VboxRxAcquireExclusiveFcbResourceInMRx (PMRX_FCB pFcb)
+{
+ return RxAcquireExclusiveFcbResourceInMRx(pFcb);
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN VBoxRxIsFcbAcquiredExclusive (PMRX_FCB pFcb)
+{
+ // ExIsResourceAcquiredExclusive is obsolete since W2K and XP!
+ return ExIsResourceAcquiredExclusiveLite(RX_GET_MRX_FCB(pFcb)->Header.Resource);
+}
+
+/* FOBX stuff */
+
+PMRX_FOBX VboxRxCreateNetFobx (OUT PRX_CONTEXT RxContext, IN PMRX_SRV_OPEN MrxSrvOpen)
+{
+ return RxCreateNetFobx(RxContext, MrxSrvOpen);
+ return NULL;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h
new file mode 100644
index 00000000000..5bb0b98badb
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rdbss_vbox.h
@@ -0,0 +1,32 @@
+#include "precomp.h"
+
+NTSTATUS VBoxRxRegisterMinirdr (PRDBSS_DEVICE_OBJECT *DeviceObject, PDRIVER_OBJECT DriverObject, PMINIRDR_DISPATCH MrdrDispatch, ULONG Controls, PUNICODE_STRING DeviceName, ULONG DeviceExtensionSize,
+ DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics);
+
+VOID VBoxRxUnregisterMinirdr (PRDBSS_DEVICE_OBJECT RxDeviceObject);
+
+NTSTATUS VBoxRxStartMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp);
+
+NTSTATUS VBoxRxStopMinirdr (PRX_CONTEXT RxContext, PBOOLEAN PostToFsp);
+
+PRX_CONTEXT VBoxRxCreateRxContext (PIRP Irp, PRDBSS_DEVICE_OBJECT RxDeviceObject, ULONG InitialContextFlags);
+
+VOID VBoxRxDereferenceAndDeleteRxContext_Real (PRX_CONTEXT RxContext);
+
+NTSTATUS VBoxRxFinalizeConnection (OUT PNET_ROOT NetRoot, OUT PV_NET_ROOT VNetRoot, LOGICAL Level);
+
+NTSTATUS VBoxRxFsdDispatch (PRDBSS_DEVICE_OBJECT RxDeviceObject, PIRP Irp);
+
+VOID VBoxRxGetFileSizeWithLock (PFCB Fcb, OUT PLONGLONG FileSize);
+
+PVOID VBoxRxLowIoGetBufferAddress (IN PRX_CONTEXT RxContext);
+
+NTSTATUS VBoxRxDispatchToWorkerThread (OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject, WORK_QUEUE_TYPE WorkQueueType, PRX_WORKERTHREAD_ROUTINE Routine, PVOID pContext);
+
+VOID VboxRxFinishFcbInitialization (PMRX_FCB MrxFcb, RDBSS_STORAGE_TYPE_CODES RdbssStorageType, PFCB_INIT_PACKET InitPacket);
+
+NTSTATUS VboxRxAcquireExclusiveFcbResourceInMRx (PMRX_FCB pFcb);
+
+BOOLEAN VBoxRxIsFcbAcquiredExclusive (PMRX_FCB pFcb);
+
+PMRX_FOBX VboxRxCreateNetFobx (OUT PRX_CONTEXT RxContext, IN PMRX_SRV_OPEN MrxSrvOpen);
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c
new file mode 100644
index 00000000000..d2868526bc2
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/read.c
@@ -0,0 +1,189 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ read.c
+
+ Abstract:
+
+ This module implements the mini redirector call down routines pertaining to read
+ of file system objects.
+
+ --*/
+
+#include "precomp.h"
+#include <VBox/log.h>
+#include "rdbss_vbox.h"
+
+#pragma hdrstop
+
+static NTSTATUS VBoxMRxReadInternal (IN PRX_CONTEXT RxContext)
+/*++
+
+ Routine Description:
+
+ This routine handles network read requests.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ RxCaptureFobx;
+
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
+
+ PVOID pbUserBuffer = VBoxRxLowIoGetBufferAddress(RxContext);
+ uint32_t ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
+ RXVBO ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
+ LONGLONG FileSize = 0;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = (PMRX_VBOX_NETROOT_EXTENSION)pNetRoot->Context;
+ BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+#ifndef VBOX
+ PDEVICE_OBJECT deviceObject;
+#endif
+
+ PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+ Log(("VBOXSF: VBoxMRxRead: SynchronousIo = %d\n", SynchronousIo));
+ Log(("VBOXSF: VBoxMRxRead: NetRoot is 0x%x, Fcb is 0x%x\n", pNetRoot, capFcb));
+
+ VBoxRxGetFileSizeWithLock((PFCB)capFcb, &FileSize);
+
+ //
+ // NB: This should be done by the wrapper ! It does this
+ // only if READCACHING is enabled on the FCB !!
+ //
+#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 the read starts beyond End of File, return EOF.
+ //
+
+ if (ByteOffset >= FileSize)
+ {
+ Log(("VBOXSF: VBoxMRxRead: End of File\n", 0 ));
+ Status = STATUS_END_OF_FILE;
+ goto Exit;
+ }
+
+ //
+ // If the read extends beyond EOF, truncate the read
+ //
+
+ if (ByteCount > FileSize - ByteOffset)
+ {
+ ByteCount = (ULONG)(FileSize - ByteOffset);
+ }
+ }
+
+ Log(("VBOXSF: VBoxMRxRead: UserBuffer is 0x%x\n", pbUserBuffer));
+ Log(("VBOXSF: VBoxMRxRead: ByteCount is %d, ByteOffset is %x\n", ByteCount, ByteOffset));
+
+ Assert((OriginalDataMdl != NULL && (RxMdlIsLocked(OriginalDataMdl) || RxMdlSourceIsNonPaged(OriginalDataMdl))) || (OriginalDataMdl == NULL && LowIoContext->ParamsFor.ReadWrite.ByteCount == 0));
+
+ if (OriginalDataMdl == NULL || LowIoContext->ParamsFor.ReadWrite.ByteCount == 0)
+ {
+ AssertFailed();
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* @todo async io !!!! */
+ SynchronousIo = TRUE;
+
+ if (SynchronousIo)
+ {
+ int vboxRC;
+
+ /* Do the actual reading */
+#ifdef VBOX_FAKE_IO_READ_WRITE
+ Status = STATUS_SUCCESS;
+ memset(pbUserBuffer, 0, ByteCount);
+#else
+ vboxRC = vboxCallRead(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */);
+ AssertRC(vboxRC);
+
+ Status = VBoxErrorToNTStatus(vboxRC);
+#endif
+ if (Status != STATUS_SUCCESS)
+ ByteCount = 0; /* Nothing read */
+
+ Log(("VBOXSF: VBoxMRxRead: This I/O is sync!\n"));
+
+ RxContext->InformationToReturn = ByteCount;
+
+ /* Never call RxLowIoCompletion here!! */
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxRead: This I/O is async!\n"));
+ }
+
+ Log(("VBOXSF: VBoxMRxRead: Status = %x Info = %x\n",RxContext->IoStatusBlock.Status,RxContext->IoStatusBlock.Information));
+
+ Exit:
+
+ return (Status);
+}
+
+
+static VOID VBoxMRxReadWorker (VOID *pv)
+{
+ PRX_CONTEXT RxContext = (PRX_CONTEXT)pv;
+
+ Log(("VBOXSF: VBoxMRxReadWorker: calling the worker\n"));
+
+ RxContext->IoStatusBlock.Status = VBoxMRxReadInternal (RxContext);
+
+ Log(("VBOXSF: VBoxMRxReadWorker: Status %x\n", RxContext->IoStatusBlock.Status));
+
+ RxLowIoCompletion (RxContext);
+}
+
+
+#ifdef VBOX_ASYNC_RW
+NTSTATUS
+VBoxMRxRead (
+ IN PRX_CONTEXT RxContext)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue,
+ VBoxMRxReadWorker,
+ RxContext);
+
+ Log(("VBOXSF: VBoxMRxRead: RxDispatchToWorkerThread: Status %x\n", Status));
+
+ if (Status == STATUS_SUCCESS)
+ {
+ Status = STATUS_PENDING;
+ }
+
+ return Status;
+}
+#else
+NTSTATUS
+VBoxMRxRead (
+ IN PRX_CONTEXT RxContext)
+{
+ RxContext->IoStatusBlock.Status = VBoxMRxReadInternal (RxContext);
+ return RxContext->IoStatusBlock.Status;
+}
+#endif /* !VBOX_ASYNC_RW */
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c
new file mode 100644
index 00000000000..320c88f8b7e
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/rename.c
@@ -0,0 +1,129 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ rename.c
+
+ Abstract:
+
+ This module implements rename in the null minirdr.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef VBOX
+NTSTATUS
+#endif
+VBoxMRxRename (IN PRX_CONTEXT RxContext, IN FILE_INFORMATION_CLASS FileInformationClass, IN PVOID pBuffer, IN ULONG BufferLength)
+/*++
+
+ Routine Description:
+
+ This routine does a rename. since the real NT-->NT path is not implemented at the server end,
+ we implement just the downlevel path.
+
+ Arguments:
+
+ RxContext - the RDBSS context
+ FILE_INFO_CLASS - must be rename....shouldn't really pass this
+ pBuffer - pointer to the new name
+ bufferlength - and the size
+
+ Return Value:
+
+ NTSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+
+ RxCaptureFcb;
+ RxCaptureFobx;
+ PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
+ PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen, capFcb);
+ PFILE_RENAME_INFORMATION RenameInformation = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ int vboxRC;
+ PSHFLSTRING SrcPath = 0, DestPath = 0;
+ ULONG ParsedPathSize, flags;
+
+ Assert(FileInformationClass == FileRenameInformation);
+
+ Log(("VBOXSF: VBoxMRxRename: 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);
+ AssertRC(vboxRC);
+ pVBoxFobx->hFile = SHFL_HANDLE_NIL;
+ }
+
+ /* Mark it as renamed, so we do nothing during close */
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED);
+
+ /* Calculate length required for destination path.
+ */
+ ParsedPathSize = sizeof(*DestPath) + (RenameInformation->FileNameLength + sizeof(WCHAR));
+
+ Log(("VBOXSF: VBoxMRxRename: 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: VBoxMRxRename: 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: VBoxMRxRename: 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: VBoxMRxRename: ParsedPathSize = %d\n", ParsedPathSize));
+
+ SrcPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize);
+
+ if (NULL == SrcPath)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlZeroMemory(SrcPath, ParsedPathSize);
+ ShflStringInitBuffer(SrcPath, ParsedPathSize - sizeof(SHFLSTRING));
+
+ Log(("VBOXSF: VBoxMRxRename: 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: VBoxMRxRename: 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: VBoxMRxRename: Calling vboxCallRename ...\n", SrcPath->u16Length / sizeof(WCHAR), &SrcPath->String.ucs2[0]));
+ vboxRC = vboxCallRename(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, SrcPath, DestPath, flags);
+
+ vbsfFreeNonPagedMem(SrcPath);
+ vbsfFreeNonPagedMem(DestPath);
+
+ Status = VBoxErrorToNTStatus(vboxRC);
+ if (vboxRC != VINF_SUCCESS)
+ Log(("VBOXSF: VBoxMRxRename: vboxCallRename failed with %d (Status = %x)!\n", vboxRC, Status));
+
+ Log(("VBOXSF: VBoxMRxRename: Returned 0x%lx\n", Status));
+ return (Status);
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c
new file mode 100644
index 00000000000..83a52effd68
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/srvcall.c
@@ -0,0 +1,243 @@
+/*
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ srvcall.c
+
+ Abstract:
+
+ This module implements the routines for handling the creation/manipulation of
+ server entries in the connection engine database. It also contains the routines
+ for parsing the negotiate response from the server.
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+VOID ExecuteCreateSrvCall (PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
+/*++
+
+ Routine Description:
+
+ This routine patches the RDBSS created srv call instance with the
+ information required by the mini redirector.
+
+ Arguments:
+
+ CallBackContext - the call back context in RDBSS for continuation.
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ 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;
+
+ Assert(pSrvCall);
+ Assert(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);
+
+ /* Validate the server name with the test name of 'vboxsvr'. */
+ Log(("VBOXSF: ExecuteCreateSrvCall: 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: ExecuteCreateSrvCall: Principal name = %.*ls\n", pSrvCall->pPrincipalName->Length / sizeof(WCHAR), pSrvCall->pPrincipalName->Buffer));
+
+ if (pSrvCall->pDomainName && pSrvCall->pDomainName->Length)
+ Log(("VBOXSF: ExecuteCreateSrvCall: 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: ExecuteCreateSrvCall: Verifier succeeded!\n"));
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ Log(("VBOXSF: ExecuteCreateSrvCall: 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)
+/*++
+
+ Routine Description:
+
+ This routine patches the RDBSS created srv call instance with the information required
+ by the mini redirector.
+
+ Arguments:
+
+ RxContext - Supplies the context of the original create/ioctl
+
+ CallBackContext - the call back context in RDBSS for continuation.
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status;
+
+ PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
+
+ Assert(pSrvCall);
+ Assert(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);
+
+ Log(("VBOXSF: VBoxMRxCreateSrvCall: Called %p.\n", pSrvCall));
+
+ //
+ // If this request was made on behalf of the RDBSS, do ExecuteCreatSrvCall
+ // immediately. If the request was made from somewhere else, create a work item
+ // and place it on a queue for a worker thread to process later. This distinction
+ // is made to simplify transport handle management.
+ //
+ if (IoGetCurrentProcess() == RxGetRDBSSProcess())
+ {
+ Log(("VBOXSF: VBoxMRxCreateSrvCall: Called in context of RDBSS process\n"));
+
+ //
+ // Peform the processing immediately because RDBSS is the initiator of this
+ // request
+ //
+
+ ExecuteCreateSrvCall(pCallbackContext);
+ }
+ else
+ {
+ Log(("VBOXSF: VBoxMRxCreateSrvCall: Dispatching to worker thread\n"));
+
+ //
+ // Dispatch the request to a worker thread because the redirected drive
+ // buffering sub-system (RDBSS) was not the initiator
+ //
+
+ Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue, (PWORKER_THREAD_ROUTINE)ExecuteCreateSrvCall, /* explicit cast for first parameter type */
+ pCallbackContext);
+
+ if (Status == STATUS_SUCCESS)
+ {
+ Log(("VBOXSF: VBoxMRxCreateSrvCall: queued!\n"));
+ }
+ else
+ {
+ pCallbackContext->Status = Status;
+ SrvCalldownStructure->CallBack(pCallbackContext);
+ }
+ }
+
+ //
+ // The wrapper expects PENDING.
+ //
+ return STATUS_PENDING;
+}
+
+NTSTATUS VBoxMRxFinalizeSrvCall (PMRX_SRV_CALL pSrvCall, BOOLEAN Force)
+/*++
+
+ Routine Description:
+
+ This routine destroys a given server call instance
+
+ Arguments:
+
+ pSrvCall - the server call instance to be disconnected.
+
+ Force - TRUE if a disconnection is to be enforced immediately.
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBOXSF: VBoxMRxFinalizeSrvCall called %p, ctx = %p.\n", pSrvCall, pSrvCall->Context));
+ pSrvCall->Context = NULL;
+
+ return (Status);
+}
+
+NTSTATUS VBoxMRxSrvCallWinnerNotify (IN PMRX_SRV_CALL pSrvCall, IN BOOLEAN ThisMinirdrIsTheWinner, IN OUT PVOID pSrvCallContext)
+/*++
+
+ Routine Description:
+
+ This routine finalizes the mini rdr context associated with an RDBSS Server call instance
+
+ Arguments:
+
+ pSrvCall - the Server Call
+
+ ThisMinirdrIsTheWinner - TRUE if this mini rdr is the choosen one.
+
+ pSrvCallContext - the server call context created by the mini redirector.
+
+ Return Value:
+
+ RXSTATUS - The return status for the operation
+
+ Notes:
+
+ The two phase construction protocol for Server calls is required because of parallel
+ initiation of a number of mini redirectors. The RDBSS finalizes the particular mini
+ redirector to be used in communicating with a given server based on quality of
+ service criterion.
+
+ --*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Log(("VBOXSF: VBoxMRxSrvCallWinnerNotify called %p.\n", pSrvCall));
+ if (ThisMinirdrIsTheWinner)
+ {
+ Log(("VBOXSF: VBoxMRxSrvCallWinnerNotify: VboxSF.sys is the winner!\n"));
+ }
+
+ pSrvCall->Context = (PVOID)0xDEADBEEF;
+
+ return (Status);
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c
new file mode 100644
index 00000000000..f2313d84d03
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/transprt.c
@@ -0,0 +1,51 @@
+/*++
+
+ Copyright (c) 1989 - 1999 Microsoft Corporation
+
+ Module Name:
+
+ transport.c
+
+ Abstract:
+
+ This module implements all transport related functions in the SMB connection engine
+
+ --*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+NTSTATUS VBoxMRxInitializeTransport ()
+/*++
+
+ Routine Description:
+
+ This routine initializes the transport related data structures
+
+ Returns:
+
+ STATUS_SUCCESS if the transport data structures was successfully initialized
+
+ Notes:
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxInitializeTransport: Called.\n"));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VBoxMRxUninitializeTransport ()
+/*++
+
+ Routine Description:
+
+ This routine uninitializes the transport related data structures
+
+ Notes:
+
+ --*/
+{
+ Log(("VBOXSF: VBoxMRxUninitializeTransport: Called.\n"));
+ return STATUS_SUCCESS;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini
new file mode 100644
index 00000000000..15db40d1ffe
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vboxsf.ini
@@ -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
+
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h
new file mode 100644
index 00000000000..a889ca9be15
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhdrs.h
@@ -0,0 +1,70 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver main header
+ *
+ * Copyright (C) 2006-2010 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#ifndef __VBOXHDRS__H
+#define __VBOXHDRS__H
+
+#include "VBoxGuestR0LibSharedFolders.h"
+
+/*
+ * UNICODE name of the virtual drive device and FSD device.
+ */
+#define VBOXSF_DEVICE_NAME_U L"VBoxSharedFolders"
+
+/*
+ * The path in the ob namespace for a virtual drive device.
+ * ? is replaced with a drive letter.
+ */
+#define VBOXSF_DEVICE_NAME_TEMPLATE_U L"\\Device\\" VBOXSF_DEVICE_NAME_U L"?"
+
+#if 0 /** @todo r=bird: defined in two .c files but with different parameter lists. dunno who uses them.
+ * Vitali / Sander, please fix when you got time. */
+NTSTATUS vbsfFsdStartPollerThread (void);
+void vbsfFsdStopPollerThread (void);
+#endif
+
+NTSTATUS
+FatMountVolume (
+ IN struct _VOLUME_DEVICE_OBJECT *pVdo
+);
+
+typedef struct _VBSFDIRENT
+{
+ ULONG64 FileSize;
+ ULONG64 AllocationSize;
+
+ ULONG64 LastAccessTime;
+ ULONG64 CreationTime;
+ ULONG64 LastWriteTime;
+
+ UCHAR Attributes;
+
+#if 0
+ FAT8DOT3 FileName; // offset = 0
+ UCHAR Attributes; // offset = 11
+ UCHAR NtByte; // offset = 12
+ UCHAR CreationMSec; // offset = 13
+ FAT_TIME_STAMP CreationTime; // offset = 14
+ FAT_DATE LastAccessDate; // offset = 18
+ union
+ {
+ USHORT ExtendedAttributes; // offset = 20
+ USHORT FirstClusterOfFileHi; // offset = 20
+ };
+ FAT_TIME_STAMP LastWriteTime; // offset = 22
+ USHORT FirstClusterOfFile; // offset = 26
+ ULONG32 FileSize; // offset = 28
+#endif
+} VBSFDIRENT; // sizeof = 32
+typedef VBSFDIRENT *PVBSFDIRENT;
+
+#endif /* __VBOXHDRS__H */
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c
new file mode 100644
index 00000000000..f91d56650c5
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.c
@@ -0,0 +1,343 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver system helpers
+ *
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#include <ntifs.h>
+#include <ntdddisk.h>
+
+#include "vbsfhdrs.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;
+ AssertMsgFailed(("Unexpected vbox error %d\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
+
+ Assert(ulSize > sizeof(void *));
+
+ /* 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;
+}
+
+winVersion_t vboxQueryWinVersion ()
+{
+ static winVersion_t winVersion = UNKNOWN_WINVERSION;
+ ULONG majorVersion;
+ ULONG minorVersion;
+ ULONG buildNumber;
+
+ if (winVersion != UNKNOWN_WINVERSION)
+ return winVersion;
+
+ PsGetVersion(&majorVersion, &minorVersion, &buildNumber, NULL);
+
+ Log(("VBoxVideo::vboxQueryWinVersion: running on Windows NT version %d.%d, build %d\n", majorVersion, minorVersion, buildNumber));
+
+ if (majorVersion >= 5)
+ {
+ if (minorVersion >= 1)
+ {
+ winVersion = WINXP;
+ }
+ else
+ {
+ winVersion = WIN2K;
+ }
+ }
+ else if (majorVersion == 4)
+ {
+ winVersion = WINNT4;
+ }
+ else
+ {
+ Log(("VBoxVideo::vboxQueryWinVersion: NT4 required!\n"));
+ }
+ return winVersion;
+}
+
+#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
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h
new file mode 100644
index 00000000000..ee87ff49195
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/vbsfhlp.h
@@ -0,0 +1,61 @@
+/** @file
+ *
+ * VirtualBox Windows Guest Shared Folders
+ *
+ * File System Driver system helpers
+ *
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#ifndef __VBSFHLP__H
+#define __VBSFHLP__H
+
+#include <ntifs.h>
+#include <ntverp.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);
+
+winVersion_t vboxQueryWinVersion ();
+
+#endif /* __VBSFHLP__H */
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c
new file mode 100644
index 00000000000..26424c5caa3
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.c
@@ -0,0 +1,138 @@
+/*++
+
+Copyright (c) 1996-1998 Microsoft Corporation
+
+Module Name:
+
+ cldskwmi.c
+
+Abstract:
+
+ km wmi tracing code.
+
+ Will be shared between our drivers.
+
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+
+
+Comments:
+
+ This code is a quick hack to enable WMI tracing in cluster drivers.
+ It should eventually go away.
+
+ WmlTinySystemControl will be replaced with WmilibSystemControl from wmilib.sys .
+
+ WmlTrace or equivalent will be added to the kernel in addition to IoWMIWriteEvent(&TraceBuffer);
+
+--*/
+#include "precomp.h"
+#pragma hdrstop
+
+//#include <ntos.h>
+//#include <ntrtl.h>
+//#include <nturtl.h>
+
+
+// #include <wmistr.h>
+// #include <evntrace.h>
+
+// #include "wmlkm.h"
+
+BOOLEAN
+WmlpFindGuid(
+ __in PVOID GuidList,
+ __in ULONG GuidCount,
+ __in LPVOID Guid,
+ __out PULONG GuidIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine will search the list of guids registered and return
+ the index for the one that was registered.
+
+Arguments:
+
+ GuidList is the list of guids to search
+
+ GuidCount is the count of guids in the list
+
+ Guid is the guid being searched for
+
+ *GuidIndex returns the index to the guid
+
+Return Value:
+
+ TRUE if guid is found else FALSE
+
+--*/
+{
+
+ return(FALSE);
+}
+
+
+NTSTATUS
+WmlTinySystemControl(
+ __inout PVOID WmiLibInfo,
+ __in PVOID DeviceObject,
+ __in PVOID Irp
+ )
+/*++
+
+Routine Description:
+
+ Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process
+ all wmi requests received, forwarding them if they are not for this
+ driver or determining if the guid is valid and if so passing it to
+ the driver specific function for handing wmi requests.
+
+Arguments:
+
+ WmiLibInfo has the WMI information control block
+
+ DeviceObject - Supplies a pointer to the device object for this request.
+
+ Irp - Supplies the Irp making the request.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ return(STATUS_WMI_GUID_NOT_FOUND);
+}
+
+ULONG
+WmlTrace(
+ __in ULONG Type,
+ __in LPVOID TraceGuid,
+ __in ULONG64 LoggerHandle,
+ ... // Pairs: Address, Length
+ )
+{
+ return STATUS_SUCCESS;
+}
+
+
+ULONG
+WmlPrintf(
+ __in ULONG Type,
+ __in LPCGUID TraceGuid,
+ __in ULONG64 LoggerHandle,
+ __in PCWSTR FormatString,
+ ... // printf var args
+ )
+{
+ return STATUS_SUCCESS;
+}
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h
new file mode 100644
index 00000000000..2381e642fa1
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/wmlkm.h
@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 1999 Microsoft Corporation
+
+Module Name:
+
+ wmlkm.h
+
+Abstract:
+
+ Kernel mode definitions for an easy wmi tracing.
+
+
+Comments:
+
+ Needs to be moved to wmilib\inc when DCR is approved
+
+--*/
+#ifndef WMLKM_H
+#define WMLKM_H 1
+
+#pragma warning(disable: 4201) // error C4201: nonstandard extension used : nameless struct/union
+#include <wmistr.h>
+#include <evntrace.h>
+
+#include "wmlmacro.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_TRACE_GUIDS_PER_CONTROL 3
+
+typedef struct _WML_CONTROL_GUID_REG {
+ GUID Guid;
+ GUID TraceGuids[MAX_TRACE_GUIDS_PER_CONTROL];
+ ULONG EnableFlags;
+ ULONG EnableLevel;
+ TRACEHANDLE LoggerHandle;
+} WML_CONTROL_GUID_REG, *PWML_CONTROL_GUID_REG;
+
+typedef struct _WML_TINY_INFO {
+ PWML_CONTROL_GUID_REG ControlGuids;
+ ULONG GuidCount;
+ PDEVICE_OBJECT LowerDeviceObject;
+ PUNICODE_STRING DriverRegPath;
+} WML_TINY_INFO, *PWML_TINY_INFO;
+
+
+NTSTATUS
+WmlTinySystemControl(
+ IN OUT PWML_TINY_INFO WmiLibInfo,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+ULONG
+WmlTrace(
+ IN ULONG Type,
+ IN LPCGUID TraceGuid,
+ IN TRACEHANDLE LoggerHandle,
+ ... // Pairs: Address, Length
+ );
+
+ULONG
+WmlPrintf(
+ IN ULONG Type,
+ IN LPCGUID TraceGuid,
+ IN TRACEHANDLE LoggerHandle,
+ IN PCHAR FormatString,
+ ... // var args
+ );
+
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // WMLKM_H
+
diff --git a/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c
new file mode 100644
index 00000000000..9c79ceda85d
--- /dev/null
+++ b/src/VBox/Additions/WINNT/SharedFolders/redirector/sys/write.c
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) 1989 - 1999 Microsoft Corporation
+
+Module Name:
+
+ write.c
+
+Abstract:
+
+ This module implements the mini redirector call down routines pertaining
+ to write of file system objects.
+
+--*/
+
+#include "precomp.h"
+#include "rdbss_vbox.h"
+#pragma hdrstop
+
+
+static NTSTATUS
+VBoxMRxWriteInternal (
+ IN PRX_CONTEXT RxContext)
+
+/*++
+
+Routine Description:
+
+ This routine opens a file across the network.
+
+Arguments:
+
+ RxContext - the RDBSS context
+
+Return Value:
+
+ RXSTATUS - The return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ RxCaptureFcb;
+ RxCaptureFobx;
+
+ PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
+ PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
+
+ PVOID pbUserBuffer = VBoxRxLowIoGetBufferAddress(RxContext);
+ uint32_t ByteCount = (LowIoContext->ParamsFor).ReadWrite.ByteCount;
+ RXVBO ByteOffset = (LowIoContext->ParamsFor).ReadWrite.ByteOffset;
+ LONGLONG FileSize = 0;
+ PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
+ VBoxMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
+ BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
+#ifndef VBOX
+ PDEVICE_OBJECT deviceObject;
+#endif
+ VBoxMRxGetDeviceExtension(RxContext, pDeviceExtension);
+ PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
+
+ Log(("VBOXSF: VBoxMRxWrite: SynchronousIo = %d\n", SynchronousIo));
+ Log(("VBOXSF: VBoxMRxWrite: NetRoot is 0x%x Fcb is 0x%x\n", pNetRoot, capFcb));
+
+ Assert( ( OriginalDataMdl != NULL
+ &&
+ ( RxMdlIsLocked(OriginalDataMdl)
+ || RxMdlSourceIsNonPaged(OriginalDataMdl)
+ )
+ )
+ ||
+ (
+ OriginalDataMdl == NULL
+ &&
+ LowIoContext->ParamsFor.ReadWrite.ByteCount == 0
+ )
+ );
+
+ if ( OriginalDataMdl == NULL
+ || LowIoContext->ParamsFor.ReadWrite.ByteCount == 0)
+ {
+ AssertFailed();
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Lengths that are not sector aligned will be rounded up to
+ // the next sector boundary. The rounded up length should be
+ // < AllocationSize.
+ //
+ VBoxRxGetFileSizeWithLock((PFCB)capFcb,&FileSize);
+
+ Log(("VBOXSF: VBoxMRxWrite: UserBuffer is 0x%x\n", pbUserBuffer ));
+ Log(("VBOXSF: VBoxMRxWrite: ByteCount is %d, ByteOffset is %d\n", ByteCount, ByteOffset ));
+
+ /* @todo async io !!!! */
+ SynchronousIo = TRUE;
+
+ if( SynchronousIo )
+ {
+ int vboxRC;
+ PMDL pMdlBuf = NULL;
+
+#ifdef VBOX_FAKE_IO_READ_WRITE
+ Status = STATUS_SUCCESS;
+#else
+ vboxRC = vboxCallWrite(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pVBoxFobx->hFile, ByteOffset, &ByteCount, (uint8_t *)pbUserBuffer, true /* locked */);
+ AssertRC(vboxRC);
+
+ Status = VBoxErrorToNTStatus(vboxRC);
+#endif
+ if (Status != STATUS_SUCCESS)
+ ByteCount = 0; /* Nothing written */
+
+ Log(("VBOXSF: VBoxMRxWrite: This I/O is sync!\n"));
+
+ RxContext->InformationToReturn = ByteCount;
+
+ /* Never call RxLowIoCompletion here!! */
+ }
+ else {
+ Log(("VBOXSF: VBoxMRxWrite: This I/O is async!\n"));
+ }
+
+ Log(("VBOXSF: VBoxMRxWrite: Status = %x, Info = %x\n",RxContext->IoStatusBlock.Status,RxContext->IoStatusBlock.Information));
+
+#ifndef VBOX
+Exit:
+#endif
+ return(Status);
+}
+
+static VOID VBoxMRxWriteWorker (VOID *pv)
+{
+ PRX_CONTEXT RxContext = (PRX_CONTEXT)pv;
+
+ Log(("VBOXSF: VBoxMRxWriteWorker: calling the worker\n"));
+
+ RxContext->IoStatusBlock.Status = VBoxMRxWriteInternal (RxContext);
+
+ Log(("VBOXSF: VBoxMRxWriteWorker: Status %x\n", RxContext->IoStatusBlock.Status));
+
+ RxLowIoCompletion (RxContext);
+}
+
+
+#ifdef VBOX_ASYNC_RW
+NTSTATUS
+VBoxMRxWrite (
+ IN PRX_CONTEXT RxContext)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Status = RxDispatchToWorkerThread(VBoxMRxDeviceObject, DelayedWorkQueue,
+ VBoxMRxWriteWorker,
+ RxContext);
+
+ Log(("VBOXSF: VBoxMRxWrite: RxDispatchToWorkerThread: Status %x\n", Status));
+
+ if (Status == STATUS_SUCCESS)
+ {
+ Status = STATUS_PENDING;
+ }
+
+ return Status;
+}
+#else
+NTSTATUS
+VBoxMRxWrite (
+ IN PRX_CONTEXT RxContext)
+{
+ RxContext->IoStatusBlock.Status = VBoxMRxWriteInternal (RxContext);
+ return RxContext->IoStatusBlock.Status;
+}
+#endif /* !VBOX_ASYNC_RW */