1 /* 2 * Copyright 2017 Katayama Hirofumi MZ 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <apitest.h> 20 #include <shlwapi.h> 21 #include <assert.h> 22 23 #include <pseh/pseh2.h> 24 25 #define EF_FULLPATH 1 26 #define EF_TESTDATA 2 27 #define EF_WIN_DIR 4 28 #define EF_SYS_DIR 8 29 #define EF_TYPE_MASK 0xF 30 31 #define EF_NAME_ONLY 16 32 33 typedef struct ENTRY 34 { 35 INT EntryNumber; /* # */ 36 INT Ret; 37 DWORD Error; 38 UINT EF_; 39 LPCWSTR NameBefore; 40 LPCWSTR NameExpected; 41 LPCWSTR PathExpected; 42 LPWSTR * Dirs; 43 } ENTRY; 44 45 #define BEEF 0xBEEF /* Error Code 48879 */ 46 #define DEAD 0xDEAD /* Error Code 57005 */ 47 #define IGNORE_ERR 0x7F7F7F7F /* Ignore Error Code */ 48 #define RAISED 9999 /* exception raised */ 49 50 static WCHAR s_TestDataPath[MAX_PATH]; 51 static LPWSTR s_Dirs[2]; 52 static WCHAR s_WinDir[MAX_PATH]; 53 static WCHAR s_SysDir[MAX_PATH]; 54 static WCHAR s_FontsDir[MAX_PATH]; 55 static WCHAR s_NotepadPath[MAX_PATH]; 56 57 static const ENTRY s_Entries[] = 58 { 59 /* NULL or empty path */ 60 { 0, 0, BEEF, EF_FULLPATH, NULL, NULL }, 61 { 1, 1, BEEF, EF_FULLPATH, L"", s_SysDir }, 62 /* path without dirs in Windows */ 63 { 2, 0, BEEF, EF_WIN_DIR, L"", L"" }, 64 { 3, 0, BEEF, EF_WIN_DIR, L"Fonts", L"Fonts" }, 65 { 4, 0, BEEF, EF_WIN_DIR, L"notepad", L"notepad" }, 66 { 5, 0, BEEF, EF_WIN_DIR, L"notepad.exe", L"notepad.exe" }, 67 { 6, 0, BEEF, EF_WIN_DIR, L"system32", L"system32" }, 68 { 7, 0, BEEF, EF_WIN_DIR, L"invalid name", L"invalid name" }, 69 /* path with dirs in Windows */ 70 { 8, 0, BEEF, EF_WIN_DIR, L"", L"", NULL, s_Dirs }, 71 { 9, 0, BEEF, EF_WIN_DIR, L"Fonts", L"Fonts", NULL, s_Dirs }, 72 { 10, 0, BEEF, EF_WIN_DIR, L"notepad", L"notepad", NULL, s_Dirs }, 73 { 11, 0, BEEF, EF_WIN_DIR, L"notepad.exe", L"notepad.exe", NULL, s_Dirs }, 74 { 12, 0, BEEF, EF_WIN_DIR, L"system32", L"system32", NULL, s_Dirs }, 75 { 13, 0, BEEF, EF_WIN_DIR, L"invalid name", L"invalid name", NULL, s_Dirs }, 76 /* name only without dirs in Windows */ 77 { 14, 1, BEEF, EF_WIN_DIR | EF_NAME_ONLY, L"", L"system32" }, 78 { 15, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"Fonts", L"Fonts" }, 79 { 16, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"notepad" }, 80 { 17, 1, BEEF, EF_WIN_DIR | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath }, 81 { 18, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"system32" }, 82 { 19, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name" }, 83 /* name only with dirs in Windows */ 84 { 20, 1, BEEF, EF_WIN_DIR | EF_NAME_ONLY, L"", NULL, s_TestDataPath, s_Dirs }, 85 { 21, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"Fonts", L"Fonts", NULL, s_Dirs }, 86 { 22, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"notepad", NULL, L"notepad", s_Dirs }, 87 { 23, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath, s_Dirs }, 88 { 24, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"system32", L"system32", NULL, s_Dirs }, 89 { 25, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name", s_Dirs }, 90 /* path without dirs in system32 */ 91 { 26, 0, BEEF, EF_SYS_DIR, L"", L"" }, 92 { 27, 0, BEEF, EF_SYS_DIR, L"Fonts", L"Fonts" }, 93 { 28, 0, BEEF, EF_SYS_DIR, L"notepad", L"notepad" }, 94 { 29, 0, BEEF, EF_SYS_DIR, L"notepad.exe", L"notepad.exe" }, 95 { 30, 0, BEEF, EF_SYS_DIR, L"system32", L"system32" }, 96 { 31, 0, BEEF, EF_SYS_DIR, L"invalid name", L"invalid name" }, 97 /* path with dirs in system32 */ 98 { 32, 0, BEEF, EF_SYS_DIR, L"", L"", NULL, s_Dirs }, 99 { 33, 0, BEEF, EF_SYS_DIR, L"Fonts", L"Fonts", NULL, s_Dirs }, 100 { 34, 0, BEEF, EF_SYS_DIR, L"notepad", L"notepad", NULL, s_Dirs }, 101 { 35, 0, BEEF, EF_SYS_DIR, L"notepad.exe", L"notepad.exe", NULL, s_Dirs }, 102 { 36, 0, BEEF, EF_SYS_DIR, L"system32", L"system32", NULL, s_Dirs }, 103 { 37, 0, BEEF, EF_SYS_DIR, L"invalid name", L"invalid name", NULL, s_Dirs }, 104 /* name only without dirs in system32 */ 105 { 38, 1, BEEF, EF_SYS_DIR | EF_NAME_ONLY, L"", NULL, s_SysDir }, 106 { 39, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir }, 107 { 40, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"notepad", NULL, L"notepad" }, 108 { 41, 1, BEEF, EF_SYS_DIR | EF_NAME_ONLY, L"notepad.exe", L"notepad.exe" }, 109 { 42, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"system32", NULL, s_SysDir }, 110 { 43, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name" }, 111 /* name only with dirs in system32 */ 112 { 44, 1, BEEF, EF_SYS_DIR | EF_NAME_ONLY, L"", NULL, s_TestDataPath, s_Dirs }, 113 { 45, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir, s_Dirs }, 114 { 46, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"notepad", NULL, L"notepad", s_Dirs }, 115 { 47, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"notepad.exe", L"notepad.exe", NULL, s_Dirs }, 116 { 48, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"system32", NULL, s_SysDir, s_Dirs }, 117 { 49, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name", s_Dirs }, 118 /* path without dirs in testdata dir */ 119 { 50, 0, BEEF, EF_TESTDATA, L"", L"" }, 120 { 51, 0, BEEF, EF_TESTDATA, L"Fonts", L"Fonts" }, 121 { 52, 0, BEEF, EF_TESTDATA, L"notepad", L"notepad" }, 122 { 53, 0, BEEF, EF_TESTDATA, L"notepad.exe", L"notepad.exe" }, 123 { 54, 0, BEEF, EF_TESTDATA, L"system32", L"system32" }, 124 { 55, 0, BEEF, EF_TESTDATA, L"invalid name", L"invalid name" }, 125 { 56, 0, BEEF, EF_TESTDATA, L"README.txt", L"README.txt" }, 126 { 57, 0, BEEF, EF_TESTDATA, L"CmdLineUtils", L"CmdLineUtils" }, 127 { 58, 0, BEEF, EF_TESTDATA, L"CmdLineUtils.exe", L"CmdLineUtils.exe" }, 128 /* path with dirs in testdata dir */ 129 { 59, 0, BEEF, EF_TESTDATA, L"", L"", NULL, s_Dirs }, 130 { 60, 0, BEEF, EF_TESTDATA, L"Fonts", L"Fonts", NULL, s_Dirs }, 131 { 61, 0, BEEF, EF_TESTDATA, L"notepad", L"notepad", NULL, s_Dirs }, 132 { 62, 0, BEEF, EF_TESTDATA, L"notepad.exe", L"notepad.exe", NULL, s_Dirs }, 133 { 63, 0, BEEF, EF_TESTDATA, L"system32", L"system32", NULL, s_Dirs }, 134 { 64, 0, BEEF, EF_TESTDATA, L"invalid name", L"invalid name", NULL, s_Dirs }, 135 { 65, 0, BEEF, EF_TESTDATA, L"README.txt", L"README.txt", NULL, s_Dirs }, 136 { 66, 0, BEEF, EF_TESTDATA, L"CmdLineUtils", L"CmdLineUtils", NULL, s_Dirs }, 137 { 67, 0, BEEF, EF_TESTDATA, L"CmdLineUtils.exe", L"CmdLineUtils.exe", NULL, s_Dirs }, 138 /* name only without dirs in testdata dir */ 139 { 68, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"", NULL, s_SysDir }, 140 { 69, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir }, 141 { 70, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"notepad", NULL, L"notepad" }, 142 { 71, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath }, 143 { 72, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"system32", NULL, s_SysDir }, 144 { 73, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name" }, 145 { 74, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"README.txt", L"README.txt", NULL, s_Dirs }, 146 { 75, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils", NULL, L"CmdLineUtils", s_Dirs }, 147 { 76, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils.exe", NULL, L"CmdLineUtils.exe", s_Dirs }, 148 /* name only with dirs in testdata dir */ 149 { 77, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"", NULL, s_TestDataPath, s_Dirs }, 150 { 78, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir, s_Dirs }, 151 { 79, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"notepad", NULL, L"notepad", s_Dirs }, 152 { 80, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath, s_Dirs }, 153 { 81, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"system32", NULL, s_SysDir, s_Dirs }, 154 { 82, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name", s_Dirs }, 155 { 83, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"README.txt", L"README.txt", NULL, s_Dirs }, 156 { 84, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils", NULL, L"CmdLineUtils", s_Dirs }, 157 { 85, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils.exe", NULL, L"CmdLineUtils.exe", s_Dirs }, 158 }; 159 160 static void DoEntry(INT EntryNumber, const ENTRY *pEntry, const WCHAR *PathVar) 161 { 162 WCHAR Path[MAX_PATH], PathExpected[MAX_PATH], OldPathVar[256]; 163 INT Ret; 164 DWORD Error; 165 166 if (pEntry->NameBefore == NULL) 167 { 168 assert(pEntry->NameExpected == NULL); 169 assert(pEntry->PathExpected == NULL); 170 } 171 172 switch (pEntry->EF_ & EF_TYPE_MASK) 173 { 174 case EF_FULLPATH: 175 if (pEntry->NameBefore) 176 { 177 lstrcpyW(Path, pEntry->NameBefore); 178 } 179 if (pEntry->NameExpected) 180 { 181 lstrcpyW(PathExpected, pEntry->NameExpected); 182 } 183 break; 184 185 case EF_TESTDATA: 186 if (pEntry->EF_ & EF_NAME_ONLY) 187 { 188 lstrcpyW(Path, pEntry->NameBefore); 189 } 190 else 191 { 192 lstrcpyW(Path, s_TestDataPath); 193 lstrcatW(Path, L"\\"); 194 lstrcatW(Path, pEntry->NameBefore); 195 } 196 197 if (pEntry->NameExpected) 198 { 199 lstrcpyW(PathExpected, s_TestDataPath); 200 lstrcatW(PathExpected, L"\\"); 201 lstrcatW(PathExpected, pEntry->NameExpected); 202 } 203 break; 204 205 case EF_WIN_DIR: 206 if (pEntry->EF_ & EF_NAME_ONLY) 207 { 208 lstrcpyW(Path, pEntry->NameBefore); 209 } 210 else 211 { 212 GetWindowsDirectoryW(Path, _countof(Path)); 213 lstrcatW(Path, L"\\"); 214 lstrcatW(Path, pEntry->NameBefore); 215 } 216 217 if (pEntry->NameExpected) 218 { 219 GetWindowsDirectoryW(PathExpected, _countof(PathExpected)); 220 lstrcatW(PathExpected, L"\\"); 221 lstrcatW(PathExpected, pEntry->NameExpected); 222 } 223 break; 224 225 case EF_SYS_DIR: 226 if (pEntry->EF_ & EF_NAME_ONLY) 227 { 228 lstrcpyW(Path, pEntry->NameBefore); 229 } 230 else 231 { 232 GetSystemDirectoryW(Path, _countof(Path)); 233 lstrcatW(Path, L"\\"); 234 lstrcatW(Path, pEntry->NameBefore); 235 } 236 237 if (pEntry->NameExpected) 238 { 239 GetSystemDirectoryW(PathExpected, _countof(PathExpected)); 240 lstrcatW(PathExpected, L"\\"); 241 lstrcatW(PathExpected, pEntry->NameExpected); 242 } 243 break; 244 } 245 246 if (PathVar) 247 { 248 if (!GetEnvironmentVariableW(L"PATH", OldPathVar, _countof(OldPathVar))) 249 { 250 skip("#%d: GetEnvironmentVariableW failed\n", EntryNumber); 251 return; 252 } 253 if (!SetEnvironmentVariableW(L"PATH", PathVar)) 254 { 255 skip("#%d: SetEnvironmentVariableW failed\n", EntryNumber); 256 return; 257 } 258 } 259 260 _SEH2_TRY 261 { 262 SetLastError(BEEF); 263 if (pEntry->NameBefore) 264 { 265 Ret = PathFindOnPathW(Path, (LPCWSTR *)pEntry->Dirs); 266 } 267 else 268 { 269 Ret = PathFindOnPathW(NULL, (LPCWSTR *)pEntry->Dirs); 270 } 271 Error = GetLastError(); 272 } 273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 274 { 275 Ret = RAISED; 276 Error = DEAD; 277 } 278 _SEH2_END; 279 280 if (PathVar) 281 { 282 ok(SetEnvironmentVariableW(L"PATH", OldPathVar), 283 "#%d: SetEnvironmentVariableW failed\n", EntryNumber); 284 } 285 286 ok(Ret == pEntry->Ret, "#%d: Ret expected %d, was %d.\n", 287 EntryNumber, pEntry->Ret, Ret); 288 289 if (pEntry->Error != IGNORE_ERR) 290 { 291 ok(Error == pEntry->Error, "#%d: last error expected %ld, was %ld.\n", 292 EntryNumber, pEntry->Error, Error); 293 } 294 295 if (pEntry->PathExpected) 296 { 297 ok(lstrcmpiW(Path, pEntry->PathExpected) == 0, "#%d: Path expected %s, was %s.\n", 298 EntryNumber, wine_dbgstr_w(pEntry->PathExpected), wine_dbgstr_w(Path)); 299 } 300 else if (pEntry->NameExpected) 301 { 302 ok(lstrcmpiW(Path, PathExpected) == 0, "#%d: Path expected %s, was %s.\n", 303 EntryNumber, wine_dbgstr_w(PathExpected), wine_dbgstr_w(Path)); 304 } 305 } 306 307 static void Test_PathFindOnPathW(void) 308 { 309 UINT i; 310 311 for (i = 0; i < _countof(s_Entries); ++i) 312 { 313 DoEntry(s_Entries[i].EntryNumber, &s_Entries[i], NULL); 314 } 315 } 316 317 START_TEST(PathFindOnPath) 318 { 319 LPWSTR pch; 320 321 GetWindowsDirectoryW(s_WinDir, _countof(s_WinDir)); 322 GetSystemDirectoryW(s_SysDir, _countof(s_SysDir)); 323 324 lstrcpyW(s_FontsDir, s_WinDir); 325 lstrcatW(s_FontsDir, L"\\Fonts"); 326 327 lstrcpyW(s_NotepadPath, s_SysDir); 328 lstrcatW(s_NotepadPath, L"\\notepad.exe"); 329 330 GetModuleFileNameW(NULL, s_TestDataPath, _countof(s_TestDataPath)); 331 pch = wcsrchr(s_TestDataPath, L'\\'); 332 if (pch == NULL) 333 pch = wcsrchr(s_TestDataPath, L'/'); 334 if (pch == NULL) 335 { 336 skip("GetModuleFileName and/or wcsrchr are insane.\n"); 337 return; 338 } 339 lstrcpyW(pch, L"\\testdata"); 340 if (GetFileAttributesW(s_TestDataPath) == INVALID_FILE_ATTRIBUTES) 341 { 342 skip("testdata is not found.\n"); 343 return; 344 } 345 346 s_Dirs[0] = s_TestDataPath; 347 s_Dirs[1] = NULL; 348 349 Test_PathFindOnPathW(); 350 } 351