1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/windows/TestNtPathToDosPath.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,222 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "TestHarness.h" 1.11 + 1.12 +#include <windows.h> 1.13 +#include <winnetwk.h> 1.14 + 1.15 +#include "mozilla/FileUtilsWin.h" 1.16 +#include "mozilla/DebugOnly.h" 1.17 +#include "nsCRTGlue.h" 1.18 + 1.19 +class DriveMapping 1.20 +{ 1.21 +public: 1.22 + DriveMapping(const nsAString& aRemoteUNCPath); 1.23 + ~DriveMapping(); 1.24 + 1.25 + bool 1.26 + Init(); 1.27 + bool 1.28 + ChangeDriveLetter(); 1.29 + wchar_t 1.30 + GetDriveLetter() { return mDriveLetter; } 1.31 + 1.32 +private: 1.33 + bool 1.34 + DoMapping(); 1.35 + void 1.36 + Disconnect(wchar_t aDriveLetter); 1.37 + 1.38 + wchar_t mDriveLetter; 1.39 + nsString mRemoteUNCPath; 1.40 +}; 1.41 + 1.42 +DriveMapping::DriveMapping(const nsAString& aRemoteUNCPath) 1.43 + : mDriveLetter(0) 1.44 + , mRemoteUNCPath(aRemoteUNCPath) 1.45 +{ 1.46 +} 1.47 + 1.48 +bool 1.49 +DriveMapping::Init() 1.50 +{ 1.51 + if (mDriveLetter) { 1.52 + return false; 1.53 + } 1.54 + return DoMapping(); 1.55 +} 1.56 + 1.57 +bool 1.58 +DriveMapping::DoMapping() 1.59 +{ 1.60 + wchar_t drvTemplate[] = L" :"; 1.61 + NETRESOURCEW netRes = {0}; 1.62 + netRes.dwType = RESOURCETYPE_DISK; 1.63 + netRes.lpLocalName = drvTemplate; 1.64 + netRes.lpRemoteName = reinterpret_cast<wchar_t*>(mRemoteUNCPath.BeginWriting()); 1.65 + wchar_t driveLetter = L'D'; 1.66 + DWORD result = NO_ERROR; 1.67 + do { 1.68 + drvTemplate[0] = driveLetter; 1.69 + result = WNetAddConnection2W(&netRes, nullptr, nullptr, CONNECT_TEMPORARY); 1.70 + } while (result == ERROR_ALREADY_ASSIGNED && ++driveLetter <= L'Z'); 1.71 + if (result != NO_ERROR) { 1.72 + return false; 1.73 + } 1.74 + mDriveLetter = driveLetter; 1.75 + return true; 1.76 +} 1.77 + 1.78 +bool 1.79 +DriveMapping::ChangeDriveLetter() 1.80 +{ 1.81 + wchar_t prevDriveLetter = mDriveLetter; 1.82 + bool result = DoMapping(); 1.83 + MOZ_ASSERT(mDriveLetter != prevDriveLetter); 1.84 + if (result && prevDriveLetter) { 1.85 + Disconnect(prevDriveLetter); 1.86 + } 1.87 + return result; 1.88 +} 1.89 + 1.90 +void 1.91 +DriveMapping::Disconnect(wchar_t aDriveLetter) 1.92 +{ 1.93 + wchar_t drvTemplate[] = {aDriveLetter, L':', L'\0'}; 1.94 + mozilla::DebugOnly<DWORD> result = WNetCancelConnection2W(drvTemplate, 0, TRUE); 1.95 + MOZ_ASSERT(result == NO_ERROR); 1.96 +} 1.97 + 1.98 +DriveMapping::~DriveMapping() 1.99 +{ 1.100 + if (mDriveLetter) { 1.101 + Disconnect(mDriveLetter); 1.102 + } 1.103 +} 1.104 + 1.105 +bool 1.106 +DriveToNtPath(const wchar_t aDriveLetter, nsAString& aNtPath) 1.107 +{ 1.108 + const wchar_t drvTpl[] = {aDriveLetter, L':', L'\0'}; 1.109 + aNtPath.SetLength(MAX_PATH); 1.110 + DWORD pathLen; 1.111 + while (true) { 1.112 + pathLen = QueryDosDeviceW(drvTpl, reinterpret_cast<wchar_t*>(aNtPath.BeginWriting()), aNtPath.Length()); 1.113 + if (pathLen || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 1.114 + break; 1.115 + } 1.116 + aNtPath.SetLength(aNtPath.Length() * 2); 1.117 + } 1.118 + if (!pathLen) { 1.119 + return false; 1.120 + } 1.121 + // aNtPath contains embedded NULLs, so we need to figure out the real length 1.122 + // via wcslen. 1.123 + aNtPath.SetLength(NS_strlen(aNtPath.BeginReading())); 1.124 + return true; 1.125 +} 1.126 + 1.127 +bool 1.128 +TestNtPathToDosPath(const wchar_t* aNtPath, 1.129 + const wchar_t* aExpectedDosPath) 1.130 +{ 1.131 + nsAutoString output; 1.132 + bool result = mozilla::NtPathToDosPath(nsDependentString(aNtPath), output); 1.133 + return result && output == aExpectedDosPath; 1.134 +} 1.135 + 1.136 +int main(int argc, char* argv[]) 1.137 +{ 1.138 + ScopedXPCOM xpcom("NtPathToDosPath"); 1.139 + if (xpcom.failed()) { 1.140 + fail("XPCOM Startup"); 1.141 + return 1; 1.142 + } 1.143 + nsAutoString cDrive; 1.144 + if (!DriveToNtPath(L'C', cDrive)) { 1.145 + fail("Querying for this machine's C:"); 1.146 + return 1; 1.147 + } 1.148 + 1.149 + int result = 0; 1.150 + 1.151 + // empty string 1.152 + if (!TestNtPathToDosPath(L"", L"")) { 1.153 + fail("Empty string"); 1.154 + result = 1; 1.155 + } 1.156 + // non-existent device, must fail 1.157 + if (TestNtPathToDosPath(L"\\Device\\ThisDeviceDoesNotExist\\Foo", nullptr)) { 1.158 + fail("Non-existent device"); 1.159 + result = 1; 1.160 + } 1.161 + // base case 1.162 + nsAutoString testPath(cDrive); 1.163 + testPath.Append(L"\\Foo"); 1.164 + if (!TestNtPathToDosPath(testPath.get(), L"C:\\Foo")) { 1.165 + fail("Base case"); 1.166 + result = 1; 1.167 + } 1.168 + // drive letters as symbolic links (NtCreateFile uses these) 1.169 + if (!TestNtPathToDosPath(L"\\??\\C:\\Foo", L"C:\\Foo")) { 1.170 + fail("Path specified as symbolic link"); 1.171 + result = 1; 1.172 + } 1.173 + // other symbolic links (should fail) 1.174 + if (TestNtPathToDosPath(L"\\??\\MountPointManager", nullptr)) { 1.175 + fail("Other symbolic link"); 1.176 + result = 1; 1.177 + } 1.178 + // socket (should fail) 1.179 + if (TestNtPathToDosPath(L"\\Device\\Afd\\Endpoint", nullptr)) { 1.180 + fail("Socket"); 1.181 + result = 1; 1.182 + } 1.183 + // currently UNC paths that are not mapped to drive letters are unsupported, 1.184 + // so this should fail 1.185 + if (TestNtPathToDosPath(L"\\Device\\Mup\\127.0.0.1\\C$", nullptr)) { 1.186 + fail("Unmapped UNC path"); 1.187 + result = 1; 1.188 + } 1.189 + DriveMapping drvMapping(NS_LITERAL_STRING("\\\\127.0.0.1\\C$")); 1.190 + // Only run these tests if we were able to map; some machines don't have perms 1.191 + if (drvMapping.Init()) { 1.192 + wchar_t expected[] = L" :\\"; 1.193 + expected[0] = drvMapping.GetDriveLetter(); 1.194 + nsAutoString networkPath; 1.195 + if (!DriveToNtPath(drvMapping.GetDriveLetter(), networkPath)) { 1.196 + fail("Querying network drive"); 1.197 + return 1; 1.198 + } 1.199 + networkPath += MOZ_UTF16("\\"); 1.200 + if (!TestNtPathToDosPath(networkPath.get(), expected)) { 1.201 + fail("Mapped UNC path"); 1.202 + result = 1; 1.203 + } 1.204 + // NtPathToDosPath must correctly handle paths whose drive letter mapping has 1.205 + // changed. We need to test this because the APIs called by NtPathToDosPath 1.206 + // return different info if this has happened. 1.207 + if (!drvMapping.ChangeDriveLetter()) { 1.208 + fail("Change drive letter"); 1.209 + return 1; 1.210 + } 1.211 + expected[0] = drvMapping.GetDriveLetter(); 1.212 + if (!DriveToNtPath(drvMapping.GetDriveLetter(), networkPath)) { 1.213 + fail("Querying second network drive"); 1.214 + return 1; 1.215 + } 1.216 + networkPath += MOZ_UTF16("\\"); 1.217 + if (!TestNtPathToDosPath(networkPath.get(), expected)) { 1.218 + fail("Re-mapped UNC path"); 1.219 + result = 1; 1.220 + } 1.221 + } 1.222 + 1.223 + return result; 1.224 +} 1.225 +