summaryrefslogtreecommitdiffstats
path: root/xpcom/tests/windows
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/tests/windows')
-rw-r--r--xpcom/tests/windows/TestCOM.cpp158
-rw-r--r--xpcom/tests/windows/TestHelloXPLoop.cpp144
-rw-r--r--xpcom/tests/windows/TestNTFSPermissions.cpp286
-rw-r--r--xpcom/tests/windows/TestNtPathToDosPath.cpp193
-rw-r--r--xpcom/tests/windows/TestWinFileAttribs.cpp173
-rw-r--r--xpcom/tests/windows/moz.build16
6 files changed, 970 insertions, 0 deletions
diff --git a/xpcom/tests/windows/TestCOM.cpp b/xpcom/tests/windows/TestCOM.cpp
new file mode 100644
index 000000000..9f0b9854c
--- /dev/null
+++ b/xpcom/tests/windows/TestCOM.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <windows.h>
+#include <unknwn.h>
+#include <stdio.h>
+#include "nsISupports.h"
+#include "nsIFactory.h"
+
+// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
+#include <unknwn.h>
+
+#include "gtest/gtest.h"
+
+// {5846BA30-B856-11d1-A98A-00805F8A7AC4}
+#define NS_ITEST_COM_IID \
+{ 0x5846ba30, 0xb856, 0x11d1, \
+ { 0xa9, 0x8a, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } }
+
+class nsITestCom: public nsISupports
+{
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITEST_COM_IID)
+ NS_IMETHOD Test() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsITestCom, NS_ITEST_COM_IID)
+
+/*
+ * nsTestCom
+ */
+
+class nsTestCom final : public nsITestCom {
+ NS_DECL_ISUPPORTS
+
+public:
+ nsTestCom() {
+ }
+
+ NS_IMETHOD Test() {
+ return NS_OK;
+ }
+
+ static int sDestructions;
+
+private:
+ ~nsTestCom() {
+ sDestructions++;
+ }
+};
+
+int nsTestCom::sDestructions;
+
+NS_IMPL_QUERY_INTERFACE(nsTestCom, nsITestCom)
+
+MozExternalRefCountType nsTestCom::AddRef()
+{
+ nsrefcnt res = ++mRefCnt;
+ NS_LOG_ADDREF(this, mRefCnt, "nsTestCom", sizeof(*this));
+ return res;
+}
+
+MozExternalRefCountType nsTestCom::Release()
+{
+ nsrefcnt res = --mRefCnt;
+ NS_LOG_RELEASE(this, mRefCnt, "nsTestCom");
+ if (res == 0) {
+ delete this;
+ }
+ return res;
+}
+
+class nsTestComFactory final : public nsIFactory {
+ ~nsTestComFactory() { sDestructions++; }
+ NS_DECL_ISUPPORTS
+public:
+ nsTestComFactory() {
+ }
+
+ NS_IMETHOD CreateInstance(nsISupports *aOuter,
+ const nsIID &aIID,
+ void **aResult);
+
+ NS_IMETHOD LockFactory(bool aLock) {
+ return NS_OK;
+ }
+
+ static int sDestructions;
+};
+
+int nsTestComFactory::sDestructions;
+
+NS_IMPL_ISUPPORTS(nsTestComFactory, nsIFactory)
+
+nsresult nsTestComFactory::CreateInstance(nsISupports *aOuter,
+ const nsIID &aIID,
+ void **aResult)
+{
+ if (aOuter != nullptr) {
+ return NS_ERROR_NO_AGGREGATION;
+ }
+
+ nsTestCom *t = new nsTestCom();
+
+ if (t == nullptr) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ NS_ADDREF(t);
+ nsresult res = t->QueryInterface(aIID, aResult);
+ NS_RELEASE(t);
+
+ return res;
+}
+
+TEST(TestCOM, WindowsInterop)
+{
+ nsTestComFactory *inst = new nsTestComFactory();
+
+ // Test we can QI nsIFactory to an IClassFactory.
+ IClassFactory *iFactory = nullptr;
+ nsresult rv = inst->QueryInterface(NS_GET_IID(nsIFactory),
+ (void **) &iFactory);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+ ASSERT_TRUE(iFactory);
+
+ // Test we can CreateInstance with an IUnknown.
+ IUnknown *iUnknown = nullptr;
+
+ HRESULT hr = iFactory->LockServer(TRUE);
+ ASSERT_TRUE(SUCCEEDED(hr));
+ hr = iFactory->CreateInstance(nullptr, IID_IUnknown, (void **) &iUnknown);
+ ASSERT_TRUE(SUCCEEDED(hr));
+ ASSERT_TRUE(iUnknown);
+ hr = iFactory->LockServer(FALSE);
+ ASSERT_TRUE(SUCCEEDED(hr));
+
+ // Test we can QI an IUnknown to nsITestCom.
+ nsITestCom *iTestCom = nullptr;
+ GUID testGUID = NS_ITEST_COM_IID;
+ hr = iUnknown->QueryInterface(testGUID,
+ (void **) &iTestCom);
+ ASSERT_TRUE(SUCCEEDED(hr));
+ ASSERT_TRUE(iTestCom);
+
+ // Make sure we can call our test function (and the pointer is valid).
+ rv = iTestCom->Test();
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ iUnknown->Release();
+ iTestCom->Release();
+ iFactory->Release();
+
+ ASSERT_EQ(nsTestComFactory::sDestructions, 1);
+ ASSERT_EQ(nsTestCom::sDestructions, 1);
+}
diff --git a/xpcom/tests/windows/TestHelloXPLoop.cpp b/xpcom/tests/windows/TestHelloXPLoop.cpp
new file mode 100644
index 000000000..ffb4442e0
--- /dev/null
+++ b/xpcom/tests/windows/TestHelloXPLoop.cpp
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIServiceManager.h"
+#include "nsCOMPtr.h"
+#include "nsCNativeApp.h"
+#include "nsIEventLoop.h"
+#include <windows.h>
+
+static NS_DEFINE_CID(kNativeAppCID, NS_NATIVE_APP_CID);
+
+LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void ErrorBox(LPSTR text)
+{
+ MessageBox(nullptr, text, "XP Event Loop", MB_OK | MB_ICONSTOP);
+}
+
+void InfoBox(LPSTR text)
+{
+ MessageBox(nullptr, text, "XP Event Loop", MB_OK | MB_ICONINFORMATION);
+}
+
+int WINAPI WinMain(HINSTANCE inst,
+ HINSTANCE prevInstance,
+ LPSTR lpszCmdLine,
+ int nShowCmd)
+{
+ char* lpszAppName = "HelloWorld";
+ HWND wnd;
+ WNDCLASSEX wndclass;
+ int retCode;
+
+ { // Needed to scope all nsCOMPtr within XPCOM Init and Shutdown
+ nsresult rv;
+ nsCOMPtr<nsIServiceManager> servMan;
+ rv = NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr);
+ if(NS_FAILED(rv))
+ {
+ ErrorBox("Failed to initialize xpcom.");
+ return -1;
+ }
+
+ nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
+ NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
+ registrar->AutoRegister(nullptr);
+
+ nsCOMPtr<nsINativeApp> nativeAppService(do_GetService(kNativeAppCID, &rv));
+
+ if(NS_FAILED(rv))
+ {
+ ErrorBox("Failed to get nativeAppService");
+ return -1;
+ }
+ wndclass.cbSize = sizeof(wndclass);
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = inst;
+ wndclass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+ wndclass.lpszMenuName = nullptr;
+ wndclass.lpszClassName = lpszAppName;
+ wndclass.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
+
+ RegisterClassEx(&wndclass) ;
+
+ wnd = CreateWindow(lpszAppName, "The Hello World",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ nullptr, nullptr, inst, nullptr);
+
+ ShowWindow(wnd, nShowCmd);
+ UpdateWindow(wnd);
+
+ nsCOMPtr<nsIEventLoop> eventLoop;
+
+ if(NS_FAILED(nativeAppService->CreateEventLoop(L"_MainLoop",
+ nsEventLoopTypes::MainAppLoop, getter_AddRefs(eventLoop))))
+ {
+ ErrorBox("Failed to create event Loop");
+ return 0;
+ }
+
+ eventLoop->Run(nullptr, nullptr, nullptr, &retCode);
+ eventLoop = nullptr; // Clear out before Shutting down XPCOM
+
+ InfoBox("Hello World app is out of loop");
+ }
+ NS_ShutdownXPCOM(nullptr);
+ InfoBox("Hello World app is exiting");
+ return retCode;
+}
+
+LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ RECT rect;
+
+ switch(msg)
+ {
+ case WM_PAINT:
+ hdc = BeginPaint(wnd, &ps);
+
+ GetClientRect(wnd, &rect);
+
+ DrawText(hdc, "Hello, XP Event Loop!", -1, &rect,
+ DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+
+ EndPaint(wnd, &ps);
+ return 0;
+
+ case WM_DESTROY:
+ {
+ nsresult rv;
+ nsCOMPtr<nsINativeApp> nativeAppService =
+ do_GetService(kNativeAppCID, &rv);
+ if(NS_FAILED(rv))
+ {
+ ErrorBox("Could not get NativeAppService");
+ return 0;
+ }
+ nsCOMPtr<nsIEventLoop> eventLoop;
+
+ if(NS_FAILED(nativeAppService->FindEventLoop(L"_MainLoop",
+ getter_AddRefs(eventLoop))))
+ {
+ ErrorBox("Failed to find event Loop");
+ return 0;
+ }
+ eventLoop->Exit(0);
+ }
+ return 0;
+ }
+
+ return DefWindowProc(wnd, msg, wParam, lParam);
+}
diff --git a/xpcom/tests/windows/TestNTFSPermissions.cpp b/xpcom/tests/windows/TestNTFSPermissions.cpp
new file mode 100644
index 000000000..062a9e650
--- /dev/null
+++ b/xpcom/tests/windows/TestNTFSPermissions.cpp
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test for NTFS File Permissions being correctly changed to match the new
+ * directory upon moving a file. (Bug 224692.)
+ */
+
+#include "../TestHarness.h"
+#include "nsEmbedString.h"
+#include "nsIFile.h"
+#include <windows.h>
+#include <aclapi.h>
+
+#define BUFFSIZE 512
+
+
+
+nsresult TestPermissions()
+{
+
+ nsresult rv; // Return value
+
+ // File variables
+ HANDLE tempFileHandle;
+ nsCOMPtr<nsIFile> tempFile;
+ nsCOMPtr<nsIFile> tempDirectory1;
+ nsCOMPtr<nsIFile> tempDirectory2;
+ WCHAR filePath[MAX_PATH];
+ WCHAR dir1Path[MAX_PATH];
+ WCHAR dir2Path[MAX_PATH];
+
+ // Security variables
+ DWORD result;
+ PSID everyoneSID = nullptr, adminSID = nullptr;
+ PACL dirACL = nullptr, fileACL = nullptr;
+ PSECURITY_DESCRIPTOR dirSD = nullptr, fileSD = nullptr;
+ EXPLICIT_ACCESS ea[2];
+ SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
+ SECURITY_WORLD_SID_AUTHORITY;
+ SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
+ SECURITY_ATTRIBUTES sa;
+ TRUSTEE everyoneTrustee;
+ ACCESS_MASK everyoneRights;
+
+ // Create a well-known SID for the Everyone group.
+ if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &everyoneSID))
+ {
+ fail("NTFS Permissions: AllocateAndInitializeSid Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Create a SID for the Administrators group.
+ if(! AllocateAndInitializeSid(&SIDAuthNT, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &adminSID))
+ {
+ fail("NTFS Permissions: AllocateAndInitializeSid Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Initialize an EXPLICIT_ACCESS structure for an ACE.
+ // The ACE will allow Everyone read access to the directory.
+ ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
+ ea[0].grfAccessPermissions = GENERIC_READ;
+ ea[0].grfAccessMode = SET_ACCESS;
+ ea[0].grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+ ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+ ea[0].Trustee.ptstrName = (LPTSTR) everyoneSID;
+
+ // Initialize an EXPLICIT_ACCESS structure for an ACE.
+ // The ACE will allow the Administrators group full access
+ ea[1].grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
+ ea[1].grfAccessMode = SET_ACCESS;
+ ea[1].grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+ ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+ ea[1].Trustee.ptstrName = (LPTSTR) adminSID;
+
+ // Create a new ACL that contains the new ACEs.
+ result = SetEntriesInAcl(2, ea, nullptr, &dirACL);
+ if (ERROR_SUCCESS != result)
+ {
+ fail("NTFS Permissions: SetEntriesInAcl Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Initialize a security descriptor.
+ dirSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
+ SECURITY_DESCRIPTOR_MIN_LENGTH);
+ if (nullptr == dirSD)
+ {
+ fail("NTFS Permissions: LocalAlloc Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (!InitializeSecurityDescriptor(dirSD,
+ SECURITY_DESCRIPTOR_REVISION))
+ {
+ fail("NTFS Permissions: InitializeSecurityDescriptor Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Add the ACL to the security descriptor.
+ if (!SetSecurityDescriptorDacl(dirSD, true, dirACL, false))
+ {
+ fail("NTFS Permissions: SetSecurityDescriptorDacl Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Initialize a security attributes structure.
+ sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = dirSD;
+ sa.bInheritHandle = false;
+
+ // Create and open first temporary directory
+ if(!CreateDirectoryW(L".\\NTFSPERMTEMP1", &sa))
+ {
+ fail("NTFS Permissions: Creating Temporary Directory");
+ return NS_ERROR_FAILURE;
+ }
+
+ GetFullPathNameW((LPCWSTR)L".\\NTFSPERMTEMP1", MAX_PATH, dir1Path,
+ nullptr);
+
+ rv = NS_NewLocalFile(nsEmbedString(dir1Path), false,
+ getter_AddRefs(tempDirectory1));
+ if (NS_FAILED(rv))
+ {
+ fail("NTFS Permissions: Opening Temporary Directory 1");
+ return rv;
+ }
+
+
+ // Create and open temporary file
+ tempFileHandle = CreateFileW(L".\\NTFSPERMTEMP1\\NTFSPerm.tmp",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ nullptr, //default security
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ nullptr);
+
+ if(tempFileHandle == INVALID_HANDLE_VALUE)
+ {
+ fail("NTFS Permissions: Creating Temporary File");
+ return NS_ERROR_FAILURE;
+ }
+
+ CloseHandle(tempFileHandle);
+
+ GetFullPathNameW((LPCWSTR)L".\\NTFSPERMTEMP1\\NTFSPerm.tmp",
+ MAX_PATH, filePath, nullptr);
+
+ rv = NS_NewLocalFile(nsEmbedString(filePath), false,
+ getter_AddRefs(tempFile));
+ if (NS_FAILED(rv))
+ {
+ fail("NTFS Permissions: Opening Temporary File");
+ return rv;
+ }
+
+ // Update Everyone Explict_Acess to full access.
+ ea[0].grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
+
+ // Update the ACL to contain the new ACEs.
+ result = SetEntriesInAcl(2, ea, nullptr, &dirACL);
+ if (ERROR_SUCCESS != result)
+ {
+ fail("NTFS Permissions: SetEntriesInAcl 2 Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Add the new ACL to the security descriptor.
+ if (!SetSecurityDescriptorDacl(dirSD, true, dirACL, false))
+ {
+ fail("NTFS Permissions: SetSecurityDescriptorDacl 2 Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Create and open second temporary directory
+ if(!CreateDirectoryW(L".\\NTFSPERMTEMP2", &sa))
+ {
+ fail("NTFS Permissions: Creating Temporary Directory 2");
+ return NS_ERROR_FAILURE;
+ }
+
+ GetFullPathNameW((LPCWSTR)L".\\NTFSPERMTEMP2", MAX_PATH, dir2Path,
+ nullptr);
+
+ rv = NS_NewLocalFile(nsEmbedString(dir2Path), false,
+ getter_AddRefs(tempDirectory2));
+ if (NS_FAILED(rv))
+ {
+ fail("NTFS Permissions: Opening Temporary Directory 2");
+ return rv;
+ }
+
+ // Move the file.
+ rv = tempFile->MoveTo(tempDirectory2, EmptyString());
+
+ if (NS_FAILED(rv))
+ {
+ fail("NTFS Permissions: Moving");
+ return rv;
+ }
+
+ // Access the ACL of the file
+ result = GetNamedSecurityInfoW(L".\\NTFSPERMTEMP2\\NTFSPerm.tmp",
+ SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION |
+ UNPROTECTED_DACL_SECURITY_INFORMATION,
+ nullptr, nullptr, &fileACL, nullptr,
+ &fileSD);
+ if (ERROR_SUCCESS != result)
+ {
+ fail("NTFS Permissions: GetNamedSecurityDescriptor Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Build a trustee representing "Everyone"
+ BuildTrusteeWithSid(&everyoneTrustee, everyoneSID);
+
+ // Get Everyone's effective rights.
+ result = GetEffectiveRightsFromAcl(fileACL, &everyoneTrustee,
+ &everyoneRights);
+ if (ERROR_SUCCESS != result)
+ {
+ fail("NTFS Permissions: GetEffectiveRightsFromAcl Error");
+ return NS_ERROR_FAILURE;
+ }
+
+ // Check for delete access, which we won't have unless permissions have
+ // updated
+ if((everyoneRights & DELETE) == (DELETE))
+ {
+ passed("NTFS Permissions Test");
+ rv = NS_OK;
+ }
+ else
+ {
+ fail("NTFS Permissions: Access check.");
+ rv = NS_ERROR_FAILURE;
+ }
+
+ // Cleanup
+ if (everyoneSID)
+ FreeSid(everyoneSID);
+ if (adminSID)
+ FreeSid(adminSID);
+ if (dirACL)
+ LocalFree(dirACL);
+ if (dirSD)
+ LocalFree(dirSD);
+ if(fileACL)
+ LocalFree(fileACL);
+
+ tempDirectory1->Remove(true);
+ tempDirectory2->Remove(true);
+
+ return rv;
+}
+
+int main(int argc, char** argv)
+{
+ ScopedXPCOM xpcom("NTFSPermissionsTests"); // name for tests being run
+ if (xpcom.failed())
+ return 1;
+
+ int rv = 0;
+
+ if(NS_FAILED(TestPermissions()))
+ rv = 1;
+
+ return rv;
+
+}
+
diff --git a/xpcom/tests/windows/TestNtPathToDosPath.cpp b/xpcom/tests/windows/TestNtPathToDosPath.cpp
new file mode 100644
index 000000000..b826d4f20
--- /dev/null
+++ b/xpcom/tests/windows/TestNtPathToDosPath.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <windows.h>
+#include <winnetwk.h>
+
+#include "mozilla/FileUtilsWin.h"
+#include "mozilla/DebugOnly.h"
+#include "nsCRTGlue.h"
+
+#include "gtest/gtest.h"
+
+class DriveMapping
+{
+public:
+ DriveMapping(const nsAString& aRemoteUNCPath);
+ ~DriveMapping();
+
+ bool
+ Init();
+ bool
+ ChangeDriveLetter();
+ wchar_t
+ GetDriveLetter() { return mDriveLetter; }
+
+private:
+ bool
+ DoMapping();
+ void
+ Disconnect(wchar_t aDriveLetter);
+
+ wchar_t mDriveLetter;
+ nsString mRemoteUNCPath;
+};
+
+DriveMapping::DriveMapping(const nsAString& aRemoteUNCPath)
+ : mDriveLetter(0)
+ , mRemoteUNCPath(aRemoteUNCPath)
+{
+}
+
+bool
+DriveMapping::Init()
+{
+ if (mDriveLetter) {
+ return false;
+ }
+ return DoMapping();
+}
+
+bool
+DriveMapping::DoMapping()
+{
+ wchar_t drvTemplate[] = L" :";
+ NETRESOURCEW netRes = {0};
+ netRes.dwType = RESOURCETYPE_DISK;
+ netRes.lpLocalName = drvTemplate;
+ netRes.lpRemoteName = reinterpret_cast<wchar_t*>(mRemoteUNCPath.BeginWriting());
+ wchar_t driveLetter = L'D';
+ DWORD result = NO_ERROR;
+ do {
+ drvTemplate[0] = driveLetter;
+ result = WNetAddConnection2W(&netRes, nullptr, nullptr, CONNECT_TEMPORARY);
+ } while (result == ERROR_ALREADY_ASSIGNED && ++driveLetter <= L'Z');
+ if (result != NO_ERROR) {
+ return false;
+ }
+ mDriveLetter = driveLetter;
+ return true;
+}
+
+bool
+DriveMapping::ChangeDriveLetter()
+{
+ wchar_t prevDriveLetter = mDriveLetter;
+ bool result = DoMapping();
+ MOZ_RELEASE_ASSERT(mDriveLetter != prevDriveLetter);
+ if (result && prevDriveLetter) {
+ Disconnect(prevDriveLetter);
+ }
+ return result;
+}
+
+void
+DriveMapping::Disconnect(wchar_t aDriveLetter)
+{
+ wchar_t drvTemplate[] = {aDriveLetter, L':', L'\0'};
+ DWORD result = WNetCancelConnection2W(drvTemplate, 0, TRUE);
+ MOZ_RELEASE_ASSERT(result == NO_ERROR);
+}
+
+DriveMapping::~DriveMapping()
+{
+ if (mDriveLetter) {
+ Disconnect(mDriveLetter);
+ }
+}
+
+bool
+DriveToNtPath(const wchar_t aDriveLetter, nsAString& aNtPath)
+{
+ const wchar_t drvTpl[] = {aDriveLetter, L':', L'\0'};
+ aNtPath.SetLength(MAX_PATH);
+ DWORD pathLen;
+ while (true) {
+ pathLen = QueryDosDeviceW(drvTpl, reinterpret_cast<wchar_t*>(aNtPath.BeginWriting()), aNtPath.Length());
+ if (pathLen || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ break;
+ }
+ aNtPath.SetLength(aNtPath.Length() * 2);
+ }
+ if (!pathLen) {
+ return false;
+ }
+ // aNtPath contains embedded NULLs, so we need to figure out the real length
+ // via wcslen.
+ aNtPath.SetLength(NS_strlen(aNtPath.BeginReading()));
+ return true;
+}
+
+bool
+TestNtPathToDosPath(const wchar_t* aNtPath,
+ const wchar_t* aExpectedDosPath)
+{
+ nsAutoString output;
+ bool result = mozilla::NtPathToDosPath(nsDependentString(aNtPath), output);
+ return result && output == reinterpret_cast<const nsAString::char_type *>(aExpectedDosPath);
+}
+
+TEST(NtPathToDosPath, Tests)
+{
+ nsAutoString cDrive;
+ ASSERT_TRUE(DriveToNtPath(L'C', cDrive));
+
+ // empty string
+ EXPECT_TRUE(TestNtPathToDosPath(L"", L""));
+
+ // non-existent device, must fail
+ EXPECT_FALSE(TestNtPathToDosPath(L"\\Device\\ThisDeviceDoesNotExist\\Foo", nullptr));
+
+ // base case
+ nsAutoString testPath(cDrive);
+ testPath.Append(L"\\Program Files");
+ EXPECT_TRUE(TestNtPathToDosPath(testPath.get(), L"C:\\Program Files"));
+
+ // short filename
+ nsAutoString ntShortName(cDrive);
+ ntShortName.Append(L"\\progra~1");
+ EXPECT_TRUE(TestNtPathToDosPath(ntShortName.get(), L"C:\\Program Files"));
+
+ // drive letters as symbolic links (NtCreateFile uses these)
+ EXPECT_TRUE(TestNtPathToDosPath(L"\\??\\C:\\Foo", L"C:\\Foo"));
+
+ // other symbolic links (should fail)
+ EXPECT_FALSE(TestNtPathToDosPath(L"\\??\\MountPointManager", nullptr));
+
+ // socket (should fail)
+ EXPECT_FALSE(TestNtPathToDosPath(L"\\Device\\Afd\\Endpoint", nullptr));
+
+ // UNC path (using MUP)
+ EXPECT_TRUE(TestNtPathToDosPath(L"\\Device\\Mup\\127.0.0.1\\C$",
+ L"\\\\127.0.0.1\\C$"));
+
+ // UNC path (using LanmanRedirector)
+ EXPECT_TRUE(TestNtPathToDosPath(L"\\Device\\LanmanRedirector\\127.0.0.1\\C$",
+ L"\\\\127.0.0.1\\C$"));
+
+ DriveMapping drvMapping(NS_LITERAL_STRING("\\\\127.0.0.1\\C$"));
+ // Only run these tests if we were able to map; some machines don't have perms
+ if (drvMapping.Init()) {
+ wchar_t expected[] = L" :\\";
+ expected[0] = drvMapping.GetDriveLetter();
+ nsAutoString networkPath;
+ ASSERT_TRUE(DriveToNtPath(drvMapping.GetDriveLetter(), networkPath));
+
+ networkPath += u"\\";
+ EXPECT_TRUE(TestNtPathToDosPath(networkPath.get(), expected));
+
+ // NtPathToDosPath must correctly handle paths whose drive letter mapping has
+ // changed. We need to test this because the APIs called by NtPathToDosPath
+ // return different info if this has happened.
+ ASSERT_TRUE(drvMapping.ChangeDriveLetter());
+
+ expected[0] = drvMapping.GetDriveLetter();
+ ASSERT_TRUE(DriveToNtPath(drvMapping.GetDriveLetter(), networkPath));
+
+ networkPath += u"\\";
+ EXPECT_TRUE(TestNtPathToDosPath(networkPath.get(), expected));
+ }
+}
diff --git a/xpcom/tests/windows/TestWinFileAttribs.cpp b/xpcom/tests/windows/TestWinFileAttribs.cpp
new file mode 100644
index 000000000..56fbcbdea
--- /dev/null
+++ b/xpcom/tests/windows/TestWinFileAttribs.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test:
+ */
+
+#include "../TestHarness.h"
+#include "nsEmbedString.h"
+#include "nsILocalFileWin.h"
+#include <windows.h>
+
+#define BUFFSIZE 512
+
+nsresult TestWinAttribs()
+{
+
+ nsresult rv;
+
+ // File variables
+ HANDLE hIndexed;
+ nsCOMPtr<nsIFile> localFile;
+ WCHAR filePath[MAX_PATH];
+
+ // Create and open temporary file
+ hIndexed = CreateFileW(L".\\indexbit.txt",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ nullptr,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, //FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, not supported by cf
+ nullptr);
+
+ if(hIndexed == INVALID_HANDLE_VALUE)
+ {
+ fail("Test Win Attribs: Creating Test File");
+ return NS_ERROR_FAILURE;
+ }
+
+ CloseHandle(hIndexed);
+
+ GetFullPathNameW((LPCWSTR)L".\\indexbit.txt",
+ MAX_PATH, filePath, nullptr);
+
+ //wprintf(filePath);
+ //wprintf(L"\n");
+
+ rv = NS_NewLocalFile(nsEmbedString(filePath), false,
+ getter_AddRefs(localFile));
+ if (NS_FAILED(rv))
+ {
+ fail("Test Win Attribs: Opening Test File");
+ DeleteFileW(filePath);
+ return rv;
+ }
+
+ nsCOMPtr<nsILocalFileWin> localFileWin(do_QueryInterface(localFile));
+
+ DWORD dwAttrs = GetFileAttributesW(filePath);
+ if (dwAttrs == INVALID_FILE_ATTRIBUTES)
+ {
+ fail("Test Win Attribs: GetFileAttributesW - couldn't find our temp file.");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ dwAttrs |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+ SetFileAttributesW(filePath, dwAttrs);
+
+ uint32_t attribs = 0;
+ rv = localFileWin->GetFileAttributesWin(&attribs);
+
+ if (NS_FAILED(rv))
+ {
+ fail("Test Win Attribs: GetFileAttributesWin failed to GET attributes. (1)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (attribs & nsILocalFileWin::WFA_SEARCH_INDEXED)
+ {
+ fail("Test Win Attribs: GetFileAttributesWin attributed did not match. (2)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ dwAttrs &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+ SetFileAttributesW(filePath, dwAttrs);
+
+ rv = localFileWin->GetFileAttributesWin(&attribs);
+
+ if (NS_FAILED(rv))
+ {
+ fail("Test Win Attribs: GetFileAttributesWin failed to GET attributes. (3)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (!(attribs & nsILocalFileWin::WFA_SEARCH_INDEXED))
+ {
+ fail("Test Win Attribs: GetFileAttributesWin attributed did not match. (4)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ dwAttrs &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+ SetFileAttributesW(filePath, dwAttrs);
+
+ attribs = nsILocalFileWin::WFA_SEARCH_INDEXED;
+ rv = localFileWin->SetFileAttributesWin(attribs);
+
+ dwAttrs = GetFileAttributesW(filePath);
+
+ if (NS_FAILED(rv))
+ {
+ fail("Test Win Attribs: GetFileAttributesWin failed to SET attributes. (5)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (dwAttrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+ {
+ fail("Test Win Attribs: SetFileAttributesWin attributed did not match. (6)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ dwAttrs |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+ SetFileAttributesW(filePath, dwAttrs);
+
+ attribs = 0;
+ rv = localFileWin->SetFileAttributesWin(attribs);
+
+ dwAttrs = GetFileAttributesW(filePath);
+
+ if (NS_FAILED(rv))
+ {
+ fail("Test Win Attribs: GetFileAttributesWin failed to SET attributes. (7)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (!(dwAttrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
+ {
+ fail("Test Win Attribs: SetFileAttributesWin attributed did not match. (8)");
+ DeleteFileW(filePath);
+ return NS_ERROR_FAILURE;
+ }
+
+ DeleteFileW(filePath);
+
+ passed("Test Win Attribs: passed tests.");
+
+ return NS_OK;
+}
+
+int main(int argc, char** argv)
+{
+ ScopedXPCOM xpcom("WinFileAttributes");
+ if (xpcom.failed())
+ return 1;
+
+ int rv = 0;
+
+ if(NS_FAILED(TestWinAttribs()))
+ rv = 1;
+
+ return rv;
+
+}
+
diff --git a/xpcom/tests/windows/moz.build b/xpcom/tests/windows/moz.build
new file mode 100644
index 000000000..21b5eb2f7
--- /dev/null
+++ b/xpcom/tests/windows/moz.build
@@ -0,0 +1,16 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ 'TestCOM.cpp',
+ 'TestNtPathToDosPath.cpp',
+]
+
+OS_LIBS += [
+ 'mpr',
+]
+
+FINAL_LIBRARY = 'xul-gtest'