1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "precompiled_desktop.hxx" 25 #include "sal/config.h" 26 27 #include <cstddef> 28 29 #define WIN32_LEAN_AND_MEAN 30 #if defined _MSC_VER 31 #pragma warning(push, 1) 32 #endif 33 #include <windows.h> 34 #include <shlwapi.h> 35 #if defined _MSC_VER 36 #pragma warning(pop) 37 #endif 38 39 #include "tools/pathutils.hxx" 40 41 #include "extendloaderenvironment.hxx" 42 43 namespace { 44 45 void fail() { 46 LPWSTR buf = NULL; 47 FormatMessageW( 48 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, 49 GetLastError(), 0, reinterpret_cast< LPWSTR >(&buf), 0, NULL); 50 MessageBoxW(NULL, buf, NULL, MB_OK | MB_ICONERROR); 51 LocalFree(buf); 52 TerminateProcess(GetCurrentProcess(), 255); 53 } 54 55 bool contains(WCHAR const * paths, WCHAR const * path, WCHAR const * pathEnd) { 56 WCHAR const * q = path; 57 for (WCHAR const * p = paths;; ++p) { 58 WCHAR c = *p; 59 switch (c) { 60 case L'\0': 61 return q == pathEnd; 62 case L';': 63 if (q == pathEnd) { 64 return true; 65 } 66 q = path; 67 break; 68 default: 69 if (q != NULL) { 70 if (q != pathEnd && *q == c) { 71 ++q; 72 } else { 73 q = NULL; 74 } 75 } 76 break; 77 } 78 } 79 } 80 81 } 82 83 namespace desktop_win32 { 84 85 void extendLoaderEnvironment(WCHAR * binPath, WCHAR * iniDirectory) { 86 if (!GetModuleFileNameW(NULL, iniDirectory, MAX_PATH)) { 87 fail(); 88 } 89 WCHAR * iniDirEnd = tools::filename(iniDirectory); 90 WCHAR name[MAX_PATH + MY_LENGTH(L".bin")]; 91 // hopefully std::size_t is large enough to not overflow 92 WCHAR * nameEnd = name; 93 for (WCHAR * p = iniDirEnd; *p != L'\0'; ++p) { 94 *nameEnd++ = *p; 95 } 96 if (!(nameEnd - name >= 4 && nameEnd[-4] == L'.' && 97 (nameEnd[-3] == L'E' || nameEnd[-3] == L'e') && 98 (nameEnd[-2] == L'X' || nameEnd[-2] == L'x') && 99 (nameEnd[-1] == L'E' || nameEnd[-1] == L'e'))) 100 { 101 *nameEnd = L'.'; 102 nameEnd += 4; 103 } 104 nameEnd[-3] = 'b'; 105 nameEnd[-2] = 'i'; 106 nameEnd[-1] = 'n'; 107 tools::buildPath(binPath, iniDirectory, iniDirEnd, name, nameEnd - name); 108 *iniDirEnd = L'\0'; 109 WCHAR path[MAX_PATH]; 110 WCHAR * pathEnd = tools::buildPath( 111 path, iniDirectory, iniDirEnd, MY_STRING(L"..\\basis-link")); 112 if (pathEnd == NULL) { 113 fail(); 114 } 115 std::size_t const maxEnv = 32767; 116 WCHAR pad[2 * MAX_PATH + maxEnv]; 117 // hopefully std::size_t is large enough to not overflow 118 WCHAR * padEnd = NULL; 119 WCHAR env[maxEnv]; 120 DWORD n = GetEnvironmentVariableW(L"PATH", env, maxEnv); 121 if (n >= maxEnv || n == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND) { 122 fail(); 123 } 124 env[n] = L'\0'; 125 bool exclude1; 126 pathEnd = tools::resolveLink(path); 127 if (pathEnd == NULL) { 128 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 129 fail(); 130 } 131 // This path is only taken by testtool.exe in basis program directory; 132 // its PATH needs to include the brand program directory: 133 pathEnd = tools::buildPath( 134 path, iniDirectory, iniDirEnd, MY_STRING(L"..")); 135 if (pathEnd == NULL) { 136 fail(); 137 } 138 padEnd = tools::buildPath( 139 pad, path, pathEnd, MY_STRING(L"\\..\\program")); 140 if (padEnd == NULL) { 141 fail(); 142 } 143 exclude1 = contains(env, pad, padEnd); 144 } else { 145 exclude1 = true; 146 } 147 WCHAR * pad2 = exclude1 ? pad : padEnd + 1; 148 pathEnd = tools::buildPath(path, path, pathEnd, MY_STRING(L"\\ure-link")); 149 if (pathEnd == NULL) { 150 fail(); 151 } 152 pathEnd = tools::resolveLink(path); 153 if (pathEnd == NULL) { 154 fail(); 155 } 156 padEnd = tools::buildPath(pad2, path, pathEnd, MY_STRING(L"\\bin")); 157 if (padEnd == NULL) { 158 fail(); 159 } 160 bool exclude2 = contains(env, pad2, padEnd); 161 if (!(exclude1 && exclude2)) { 162 if (!(exclude1 || exclude2)) { 163 pad2[-1] = L';'; 164 } 165 WCHAR * p = exclude2 ? pad2 - 1 : padEnd; 166 if (n != 0) { 167 *p++ = L';'; 168 } 169 for (DWORD i = 0; i <= n; ++i) { 170 *p++ = env[i]; 171 } 172 if (!SetEnvironmentVariableW(L"PATH", pad)) { 173 fail(); 174 } 175 } 176 } 177 178 } 179