1 /* 2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include "precompiled.hpp" 25 26 #ifdef _WINDOWS 27 28 #include "runtime/os.hpp" 29 #include "runtime/flags/flagSetting.hpp" 30 #include "runtime/globals_extension.hpp" 31 #include "unittest.hpp" 32 33 namespace { 34 class MemoryReleaser { 35 char* const _ptr; 36 const size_t _size; 37 public: 38 MemoryReleaser(char* ptr, size_t size) : _ptr(ptr), _size(size) { } 39 ~MemoryReleaser() { 40 os::release_memory_special(_ptr, _size); 41 } 42 }; 43 } 44 45 // test tries to allocate memory in a single contiguous memory block at a particular address. 46 // The test first tries to find a good approximate address to allocate at by using the same 47 // method to allocate some memory at any address. The test then tries to allocate memory in 48 // the vicinity (not directly after it to avoid possible by-chance use of that location) 49 // This is of course only some dodgy assumption, there is no guarantee that the vicinity of 50 // the previously allocated memory is available for allocation. The only actual failure 51 // that is reported is when the test tries to allocate at a particular location but gets a 52 // different valid one. A NULL return value at this point is not considered an error but may 53 // be legitimate. 54 TEST_VM(os_windows, reserve_memory_special) { 55 if (!UseLargePages) { 56 return; 57 } 58 59 // set globals to make sure we hit the correct code path 60 FLAG_GUARD(UseLargePagesIndividualAllocation); 61 FLAG_GUARD(UseNUMAInterleaving); 62 FLAG_SET_CMDLINE(UseLargePagesIndividualAllocation, false); 63 FLAG_SET_CMDLINE(UseNUMAInterleaving, false); 64 65 const size_t large_allocation_size = os::large_page_size() * 4; 66 char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), NULL, false); 67 if (result != NULL) { 68 // failed to allocate memory, skipping the test 69 return; 70 } 71 MemoryReleaser mr(result, large_allocation_size); 72 73 // allocate another page within the recently allocated memory area which seems to be a good location. At least 74 // we managed to get it once. 75 const size_t expected_allocation_size = os::large_page_size(); 76 char* expected_location = result + os::large_page_size(); 77 char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), expected_location, false); 78 if (actual_location != NULL) { 79 // failed to allocate memory, skipping the test 80 return; 81 } 82 MemoryReleaser mr2(actual_location, expected_allocation_size); 83 84 EXPECT_EQ(expected_location, actual_location) 85 << "Failed to allocate memory at requested location " << expected_location << " of size " << expected_allocation_size; 86 } 87 88 // The types of path modifications we randomly apply to a path. They should not change the file designated by the path. 89 enum ModsFilter { 90 Allow_None = 0, // No modifications 91 Allow_Sep_Mods = 1, // Replace '\\' by any sequence of '/' or '\\' or at least length 1. 92 Allow_Dot_Path = 2, // Add /. segments at random positions 93 Allow_Dot_Dot_Path = 4, // Add /../<correct-dir> segments at random positions. 94 Allow_All = Allow_Sep_Mods | Allow_Dot_Path | Allow_Dot_Dot_Path 95 }; 96 97 // The mode in which to run. 98 enum Mode { 99 TEST, // Runs the test. This is the normal modus. 100 EXAMPLES, // Runs example which document the behaviour of the Windows system calls. 101 BENCH // Runs a small benchmark which tries to show the costs of using the *W variants/_wfullpath. 102 }; 103 104 // Parameters of the test. 105 static ModsFilter mods_filter = Allow_All; 106 static int mods_per_path = 50; // The number of variants of a path we try. 107 static Mode mode = TEST; 108 109 110 // Utility methods 111 static void get_current_dir_w(wchar_t* path, size_t size) { 112 DWORD count = GetCurrentDirectoryW((DWORD) size, path); 113 EXPECT_GT((int) count, 0) << "Failed to get current directory: " << GetLastError(); 114 EXPECT_LT((size_t) count, size) << "Buffer too small for current directory: " << size; 115 } 116 117 #define WITH_ABS_PATH(path) \ 118 wchar_t abs_path[JVM_MAXPATHLEN]; \ 119 wchar_t cwd[JVM_MAXPATHLEN]; \ 120 get_current_dir_w(cwd, JVM_MAXPATHLEN); \ 121 wsprintfW(abs_path, L"\\\\?\\%ls\\%ls", cwd, (path)) 122 123 static bool file_exists_w(const wchar_t* path) { 124 WIN32_FILE_ATTRIBUTE_DATA file_data; 125 return ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data); 126 } 127 128 static void create_rel_directory_w(const wchar_t* path) { 129 WITH_ABS_PATH(path); 130 EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create directory: \"" << path << "\" already exists"; 131 BOOL result = CreateDirectoryW(abs_path, NULL); 132 EXPECT_TRUE(result) << "Failed to create directory \"" << path << "\" " << GetLastError(); 133 } 134 135 static void delete_empty_rel_directory_w(const wchar_t* path) { 136 WITH_ABS_PATH(path); 137 EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete directory: \"" << path << "\" does not exists"; 138 BOOL result = RemoveDirectoryW(abs_path); 139 EXPECT_TRUE(result) << "Failed to delete directory \"" << path << "\": " << GetLastError(); 140 } 141 142 static void create_rel_file_w(const wchar_t* path) { 143 WITH_ABS_PATH(path); 144 EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create file: \"" << path << "\" already exists"; 145 HANDLE h = CreateFileW(abs_path, 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 146 EXPECT_NE(h, INVALID_HANDLE_VALUE) << "Failed to create file \"" << path << "\": " << GetLastError(); 147 CloseHandle(h); 148 } 149 150 static void delete_rel_file_w(const wchar_t* path) { 151 WITH_ABS_PATH(path); 152 EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete file: \"" << path << "\" does not exists"; 153 BOOL result = DeleteFileW(abs_path); 154 EXPECT_TRUE(result) << "Failed to delete file \"" << path << "\": " << GetLastError(); 155 } 156 157 static bool convert_to_cstring(char* c_str, size_t size, wchar_t* w_str) { 158 size_t converted; 159 errno_t err = wcstombs_s(&converted, c_str, size, w_str, size - 1); 160 EXPECT_EQ(err, ERROR_SUCCESS) << "Could not convert \"" << w_str << "\" to c-string"; 161 162 return err == ERROR_SUCCESS; 163 } 164 165 static wchar_t* my_wcscpy_s(wchar_t* dest, size_t size, wchar_t* start, const wchar_t* to_copy) { 166 size_t already_used = dest - start; 167 size_t len = wcslen(to_copy); 168 169 if (already_used + len < size) { 170 wcscpy_s(dest, size - already_used, to_copy); 171 } 172 173 return dest + wcslen(to_copy); 174 } 175 176 // The currently finite list of seperator sequences we might use instead of '\\'. 177 static const wchar_t* sep_replacements[] = { 178 L"\\", L"\\/", L"/", L"//", L"\\\\/\\", L"//\\/" 179 }; 180 181 // Takes a path and modifies it in a way that it should still designate the same file. 182 static bool unnormalize_path(wchar_t* result, size_t size, bool is_dir, const wchar_t* path) { 183 wchar_t* dest = result; 184 const wchar_t* src = path; 185 const wchar_t* path_start; 186 187 if (wcsncmp(src, L"\\\\?\\UNC\\", 8) == 0) { 188 path_start = src + 8; 189 } else if (wcsncmp(src, L"\\\\?\\", 4) == 0) { 190 if (src[5] == L':') { 191 path_start = src + 6; 192 } else { 193 path_start = wcschr(src + 4, L'\\'); 194 } 195 } else if (wcsncmp(src, L"\\\\", 2) == 0) { 196 path_start = wcschr(src + 2, L'?'); 197 198 if (path_start == NULL) { 199 path_start = wcschr(src + 2, L'\\'); 200 } else { 201 path_start = wcschr(path_start, L'\\'); 202 } 203 } else { 204 path_start = wcschr(src + 1, L'\\'); 205 } 206 207 bool allow_sep_change = (mods_filter & Allow_Sep_Mods) && (os::random() & 1) == 0; 208 bool allow_dot_change = (mods_filter & Allow_Dot_Path) && (os::random() & 1) == 0; 209 bool allow_dotdot_change = (mods_filter & Allow_Dot_Dot_Path) && (os::random() & 1) == 0; 210 211 while ((*src != L'\0') && (result + size > dest)) { 212 wchar_t c = *src; 213 *dest = c; 214 ++src; 215 ++dest; 216 217 if (c == L'\\') { 218 if (allow_sep_change && (os::random() & 3) == 3) { 219 int i = os::random() % (sizeof(sep_replacements) / sizeof(sep_replacements[0])); 220 221 if (i >= 0) { 222 const wchar_t* replacement = sep_replacements[i]; 223 dest = my_wcscpy_s(dest - 1, size, result, replacement); 224 } 225 } else if (path_start != NULL) { 226 if (allow_dotdot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) { 227 wchar_t const* last_sep = src - 2; 228 229 while (last_sep[0] != L'\\') { 230 --last_sep; 231 } 232 233 if (last_sep > path_start) { 234 dest = my_wcscpy_s(dest, size, result, L"../"); 235 src = last_sep + 1; 236 } 237 } else if (allow_dot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) { 238 dest = my_wcscpy_s(dest, size, result, L"./"); 239 } 240 } 241 } 242 } 243 244 while (is_dir && ((os::random() & 15) == 1)) { 245 dest = my_wcscpy_s(dest, size, result, L"/"); 246 } 247 248 if (result + size > dest) { 249 *dest = L'\0'; 250 } 251 252 // Use this modification only if not too close to the max size. 253 return result + size - 10 > dest; 254 } 255 256 static void check_dir_impl(wchar_t* path, bool should_be_empty) { 257 char buf[JVM_MAXPATHLEN]; 258 259 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 260 struct stat st; 261 EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\""; 262 EXPECT_EQ(st.st_mode & S_IFMT, S_IFDIR) << "\"" << path << "\" is not a directory according to os::stat"; 263 errno = ERROR_SUCCESS; 264 bool is_empty = os::dir_is_empty(buf); 265 errno_t err = errno; 266 EXPECT_EQ(is_empty, should_be_empty) << "os::dir_is_empty assumed \"" << path << "\" is " 267 << (should_be_empty ? "not ": "") << "empty"; 268 EXPECT_EQ(err, ERROR_SUCCESS) << "os::dir_is_empty failed for \"" << path << "\"with errno " << err; 269 } 270 } 271 272 static void check_file_impl(wchar_t* path) { 273 char buf[JVM_MAXPATHLEN]; 274 275 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 276 struct stat st; 277 EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\""; 278 EXPECT_EQ(st.st_mode & S_IFMT, S_IFREG) << "\"" << path << "\" is not a regular file according to os::stat"; 279 int fd = os::open(buf, O_RDONLY, 0); 280 EXPECT_NE(fd, -1) << "os::open failed for \"" << path << "\" with errno " << errno; 281 if (fd >= 0) { 282 ::close(fd); 283 } 284 } 285 } 286 287 static void check_file_not_present_impl(wchar_t* path) { 288 char buf[JVM_MAXPATHLEN]; 289 290 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 291 struct stat st; 292 int stat_ret; 293 EXPECT_EQ(stat_ret = os::stat(buf, &st), -1) << "os::stat did not fail for \"" << path << "\""; 294 if (stat_ret != -1) { 295 // Only check open if stat not already failed. 296 int fd = os::open(buf, O_RDONLY, 0); 297 EXPECT_EQ(fd, -1) << "os::open did not fail for \"" << path << "\""; 298 if (fd >= 0) { 299 ::close(fd); 300 } 301 } 302 } 303 } 304 305 static void check_dir(wchar_t* path, bool should_be_empty) { 306 check_dir_impl(path, should_be_empty); 307 308 for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { 309 wchar_t tmp[JVM_MAXPATHLEN]; 310 if (unnormalize_path(tmp, JVM_MAXPATHLEN, true, path)) { 311 check_dir_impl(tmp, should_be_empty); 312 } 313 } 314 } 315 316 static void check_file(wchar_t* path) { 317 check_file_impl(path); 318 319 // Check os::same_files at least somewhat. 320 char buf[JVM_MAXPATHLEN]; 321 322 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 323 wchar_t mod[JVM_MAXPATHLEN]; 324 325 if (unnormalize_path(mod, JVM_MAXPATHLEN, false, path)) { 326 char mod_c[JVM_MAXPATHLEN]; 327 if (convert_to_cstring(mod_c, JVM_MAXPATHLEN, mod)) { 328 EXPECT_EQ(os::same_files(buf, mod_c), true) << "os::same files failed for \\" << path << "\" and \"" << mod_c << "\""; 329 } 330 } 331 } 332 333 for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { 334 wchar_t tmp[JVM_MAXPATHLEN]; 335 if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) { 336 check_file_impl(tmp); 337 } 338 } 339 } 340 341 static void check_file_not_present(wchar_t* path) { 342 check_file_not_present_impl(path); 343 344 for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { 345 wchar_t tmp[JVM_MAXPATHLEN]; 346 if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) { 347 check_file_not_present_impl(tmp); 348 } 349 } 350 } 351 352 static void record_path(char const* name, char const* len_name, wchar_t* path) { 353 char buf[JVM_MAXPATHLEN]; 354 355 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 356 ::testing::Test::RecordProperty(name, buf); 357 os::snprintf(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path)); 358 ::testing::Test::RecordProperty(len_name, buf); 359 } 360 } 361 362 static void bench_path(wchar_t* path) { 363 char buf[JVM_MAXPATHLEN]; 364 int reps = 100000; 365 366 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 367 jlong wtime[2]; 368 369 for (int t = 0; t < 2; ++t) { 370 wtime[t] = os::javaTimeNanos(); 371 372 for (int i = 0; i < reps; ++i) { 373 bool succ = false; 374 size_t buf_len = strlen(buf); 375 wchar_t* w_path = (wchar_t*) os::malloc(sizeof(wchar_t) * (buf_len + 1), mtInternal); 376 377 if (w_path != NULL) { 378 size_t converted_chars; 379 if (::mbstowcs_s(&converted_chars, w_path, buf_len + 1, buf, buf_len) == ERROR_SUCCESS) { 380 if (t == 1) { 381 wchar_t* tmp = (wchar_t*) os::malloc(sizeof(wchar_t) * JVM_MAXPATHLEN, mtInternal); 382 383 if (tmp) { 384 if (_wfullpath(tmp, w_path, JVM_MAXPATHLEN)) { 385 succ = true; 386 } 387 388 // Note that we really don't use the full path name, but just add the cost of running _wfullpath. 389 os::free(tmp); 390 } 391 if (!succ) { 392 printf("Failed fullpathing \"%s\"\n", buf); 393 return; 394 } 395 succ = false; 396 } 397 HANDLE h = ::CreateFileW(w_path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 398 399 if (h != INVALID_HANDLE_VALUE) { 400 ::CloseHandle(h); 401 succ = true; 402 } 403 } 404 } 405 406 os::free(w_path); 407 if (!succ) { 408 printf("Failed getting W*attr. \"%s\"\n", buf); 409 return; 410 } 411 } 412 413 wtime[t] = os::javaTimeNanos() - wtime[t]; 414 } 415 416 jlong ctime = os::javaTimeNanos(); 417 418 for (int i = 0; i < reps; ++i) { 419 HANDLE h = ::CreateFileA(buf, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 420 421 if (h == INVALID_HANDLE_VALUE) { 422 return; 423 } 424 425 ::CloseHandle(h); 426 } 427 428 ctime = os::javaTimeNanos() - ctime; 429 430 printf("\"%s\" %f us for *A, %f us for *W, %f us for *W with fullpath\n", buf, 431 0.001 * ctime / reps, 0.001 * wtime[0] / reps, 0.001 * wtime[1] / reps); 432 } 433 } 434 435 static void print_attr_result_for_path(wchar_t* path) { 436 WIN32_FILE_ATTRIBUTE_DATA file_data; 437 struct stat st; 438 char buf[JVM_MAXPATHLEN]; 439 wchar_t abs[JVM_MAXPATHLEN]; 440 441 _wfullpath(abs, path, JVM_MAXPATHLEN); 442 printf("Checking \"%ls\" (%d chars):\n", path, (int) wcslen(path)); 443 printf("_wfullpath %ls (%d chars)\n", abs, (int) wcslen(abs)); 444 BOOL bret = ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data); 445 printf("GetFileAttributesExW() %s\n", bret ? "success" : "failed"); 446 447 if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { 448 bret = ::GetFileAttributesExA(buf, GetFileExInfoStandard, &file_data); 449 printf("GetFileAttributesExA() %s\n", bret ? "success" : "failed"); 450 451 bool succ = os::stat(buf, &st) != -1; 452 printf("os::stat() %s\n", succ ? "success" : "failed"); 453 } 454 } 455 456 static void print_attr_result(wchar_t* format, ...) { 457 va_list argptr; 458 wchar_t buf[JVM_MAXPATHLEN]; 459 460 va_start(argptr, format); 461 wvsprintfW(buf, format, argptr); 462 print_attr_result_for_path(buf); 463 va_end(argptr); 464 } 465 466 #define RECORD_PATH(name) record_path(#name, #name "Len", name) 467 #define NAME_PART_50 L"01234567890123456789012345678901234567890123456789" 468 #define NAME_PART_250 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50 469 470 // Test which tries to find out if the os::stat, os::open, os::same_files and os::dir_is_empty methods 471 // can handle long path names correctly. 472 TEST_VM(os_windows, handle_long_paths) { 473 static wchar_t cwd[JVM_MAXPATHLEN]; 474 static wchar_t nearly_long_rel_path[JVM_MAXPATHLEN]; 475 static wchar_t long_rel_path[JVM_MAXPATHLEN]; 476 static wchar_t empty_dir_rel_path[JVM_MAXPATHLEN]; 477 static wchar_t not_empty_dir_rel_path[JVM_MAXPATHLEN]; 478 static wchar_t file_rel_path[JVM_MAXPATHLEN]; 479 static wchar_t nearly_long_file_rel_path[JVM_MAXPATHLEN]; 480 static wchar_t nearly_long_path[JVM_MAXPATHLEN]; 481 static wchar_t empty_dir_path[JVM_MAXPATHLEN]; 482 static wchar_t not_empty_dir_path[JVM_MAXPATHLEN]; 483 static wchar_t nearly_long_file_path[JVM_MAXPATHLEN]; 484 static wchar_t file_path[JVM_MAXPATHLEN]; 485 static wchar_t nearly_long_unc_path[JVM_MAXPATHLEN]; 486 static wchar_t empty_dir_unc_path[JVM_MAXPATHLEN]; 487 static wchar_t not_empty_dir_unc_path[JVM_MAXPATHLEN]; 488 static wchar_t nearly_long_file_unc_path[JVM_MAXPATHLEN]; 489 static wchar_t file_unc_path[JVM_MAXPATHLEN]; 490 static wchar_t root_dir_path[JVM_MAXPATHLEN]; 491 static wchar_t root_rel_dir_path[JVM_MAXPATHLEN]; 492 493 wchar_t* dir_prefix = L"os_windows_long_paths_dir_"; 494 wchar_t* empty_dir_name = L"empty_directory_with_long_path"; 495 wchar_t* not_empty_dir_name = L"not_empty_directory_with_long_path"; 496 wchar_t* file_name = L"file"; 497 wchar_t dir_letter; 498 WIN32_FILE_ATTRIBUTE_DATA file_data; 499 bool can_test_unc = false; 500 501 get_current_dir_w(cwd, sizeof(cwd) / sizeof(wchar_t)); 502 dir_letter = (cwd[1] == L':' ? cwd[0] : L'\0'); 503 int cwd_len = (int) wcslen(cwd); 504 int dir_prefix_len = (int) wcslen(dir_prefix); 505 int rel_path_len = MAX2(dir_prefix_len, 235 - cwd_len); 506 507 memcpy(nearly_long_rel_path, dir_prefix, sizeof(wchar_t) * dir_prefix_len); 508 509 for (int i = dir_prefix_len; i < rel_path_len; ++i) { 510 nearly_long_rel_path[i] = L'L'; 511 } 512 513 nearly_long_rel_path[rel_path_len] = L'\0'; 514 515 wsprintfW(long_rel_path, L"%ls\\%ls", nearly_long_rel_path, NAME_PART_250); 516 wsprintfW(empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, empty_dir_name); 517 wsprintfW(not_empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, not_empty_dir_name); 518 wsprintfW(nearly_long_file_rel_path, L"%ls\\%ls", nearly_long_rel_path, file_name); 519 wsprintfW(file_rel_path, L"%ls\\%ls\\%ls", nearly_long_rel_path, not_empty_dir_name, file_name); 520 wsprintfW(nearly_long_path, L"\\\\?\\%ls\\%ls", cwd, nearly_long_rel_path); 521 wsprintfW(empty_dir_path, L"%ls\\%ls", nearly_long_path, empty_dir_name); 522 wsprintfW(not_empty_dir_path, L"%ls\\%ls", nearly_long_path, not_empty_dir_name); 523 wsprintfW(nearly_long_file_path, L"%ls\\%ls", nearly_long_path, file_name); 524 wsprintfW(file_path, L"%ls\\%ls\\%ls", nearly_long_path, not_empty_dir_name, file_name); 525 wsprintfW(nearly_long_unc_path, L"\\\\localhost\\%lc$\\%s", dir_letter, nearly_long_path + 7); 526 wsprintfW(empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, empty_dir_name); 527 wsprintfW(not_empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, not_empty_dir_name); 528 wsprintfW(nearly_long_file_unc_path, L"%ls\\%ls", nearly_long_unc_path, file_name); 529 wsprintfW(file_unc_path, L"%s\\%s\\%s", nearly_long_unc_path, not_empty_dir_name, file_name); 530 wsprintfW(root_dir_path, L"%lc:\\", dir_letter); 531 wsprintfW(root_rel_dir_path, L"%lc:", dir_letter); 532 533 RECORD_PATH(long_rel_path); 534 RECORD_PATH(nearly_long_rel_path); 535 RECORD_PATH(nearly_long_path); 536 RECORD_PATH(nearly_long_unc_path); 537 RECORD_PATH(empty_dir_rel_path); 538 RECORD_PATH(empty_dir_path); 539 RECORD_PATH(empty_dir_unc_path); 540 RECORD_PATH(not_empty_dir_rel_path); 541 RECORD_PATH(not_empty_dir_path); 542 RECORD_PATH(not_empty_dir_unc_path); 543 RECORD_PATH(nearly_long_file_rel_path); 544 RECORD_PATH(nearly_long_file_path); 545 RECORD_PATH(nearly_long_file_unc_path); 546 RECORD_PATH(file_rel_path); 547 RECORD_PATH(file_path); 548 RECORD_PATH(file_unc_path); 549 550 create_rel_directory_w(nearly_long_rel_path); 551 create_rel_directory_w(long_rel_path); 552 create_rel_directory_w(empty_dir_rel_path); 553 create_rel_directory_w(not_empty_dir_rel_path); 554 create_rel_file_w(nearly_long_file_rel_path); 555 create_rel_file_w(file_rel_path); 556 557 // For UNC path test we assume that the current DRIVE has a share 558 // called "<DRIVELETTER>$" (so for D: we expect \\localhost\D$ to be 559 // the same). Since this is only an assumption, we have to skip 560 // the UNC tests if the share is missing. 561 if (dir_letter && !::GetFileAttributesExW(nearly_long_unc_path, GetFileExInfoStandard, &file_data)) { 562 printf("Disabled UNC path test, since %lc: is not mapped as share %lc$.\n", dir_letter, dir_letter); 563 } else { 564 can_test_unc = true; 565 } 566 567 if (mode == BENCH) { 568 bench_path(nearly_long_path + 4); 569 bench_path(nearly_long_rel_path); 570 bench_path(nearly_long_file_path + 4); 571 bench_path(nearly_long_file_rel_path); 572 } else if (mode == EXAMPLES) { 573 printf("Working directory: %ls", cwd); 574 575 if (dir_letter) { 576 static wchar_t top_buf[JVM_MAXPATHLEN]; 577 wchar_t* top_path = wcschr(cwd + 3, L'\\'); 578 579 if (top_path) { 580 size_t top_len = (top_path - cwd) - 3; 581 582 memcpy(top_buf, cwd + 3, top_len * 2); 583 top_buf[top_len] = L'\0'; 584 top_path = top_buf; 585 } 586 587 print_attr_result(L"%lc:\\", dir_letter); 588 print_attr_result(L"%lc:\\.\\", dir_letter); 589 590 if (top_path) { 591 print_attr_result(L"%lc:\\%ls\\..\\%ls\\", dir_letter, top_path, top_path); 592 } 593 594 print_attr_result(L"%lc:", dir_letter); 595 print_attr_result(L"%lc:.", dir_letter); 596 print_attr_result(L"%lc:\\COM1", dir_letter); 597 print_attr_result(L"%lc:\\PRN", dir_letter); 598 print_attr_result(L"%lc:\\PRN\\COM1", dir_letter); 599 print_attr_result(L"\\\\?\\UNC\\localhost\\%lc$\\", dir_letter); 600 print_attr_result(L"\\\\?\\UNC\\\\localhost\\%lc$\\", dir_letter); 601 print_attr_result(nearly_long_unc_path); 602 print_attr_result(L"%ls\\.\\", nearly_long_unc_path); 603 print_attr_result(L"%ls\\..\\%ls", nearly_long_unc_path, nearly_long_rel_path); 604 print_attr_result(L"\\\\?\\UNC\\%ls", nearly_long_unc_path + 2); 605 print_attr_result(file_unc_path); 606 print_attr_result(L"%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path, not_empty_dir_name, not_empty_dir_name, file_name); 607 print_attr_result(L"%ls\\%ls\\.\\%ls", nearly_long_unc_path, not_empty_dir_name, file_name); 608 print_attr_result(L"\\\\?\\UNC\\%ls", file_unc_path + 2); 609 print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\.\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, file_name); 610 print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, not_empty_dir_name, file_name); 611 } 612 613 print_attr_result(nearly_long_rel_path); 614 print_attr_result(L"%ls\\.\\", nearly_long_rel_path); 615 print_attr_result(L"%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path); 616 print_attr_result(L"%\\\\?\\%ls", nearly_long_rel_path); 617 print_attr_result(L"\\\\?\\%ls\\.\\", nearly_long_rel_path); 618 print_attr_result(L"\\\\?\\%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path); 619 620 print_attr_result(nearly_long_path + 4); 621 print_attr_result(L"%ls\\.\\", nearly_long_path + 4); 622 print_attr_result(L"%ls\\..\\%ls", nearly_long_path + 4, nearly_long_rel_path); 623 print_attr_result(nearly_long_path); 624 print_attr_result(L"%ls\\.\\", nearly_long_path); 625 print_attr_result(L"%ls\\..\\%ls", nearly_long_path, nearly_long_rel_path); 626 } else { 627 check_file_not_present(L""); 628 629 // Check relative paths 630 check_dir(nearly_long_rel_path, false); 631 check_dir(long_rel_path, true); 632 check_dir(empty_dir_rel_path, true); 633 check_dir(not_empty_dir_rel_path, false); 634 check_file(nearly_long_file_rel_path); 635 check_file(file_rel_path); 636 637 // Check absolute paths 638 if (dir_letter) { 639 check_dir(root_dir_path, false); 640 check_dir(root_rel_dir_path, false); 641 } 642 643 check_dir(cwd, false); 644 check_dir(nearly_long_path + 4, false); 645 check_dir(empty_dir_path + 4, true); 646 check_dir(not_empty_dir_path + 4, false); 647 check_file(nearly_long_file_path + 4); 648 check_file(file_path + 4); 649 650 // Check UNC paths 651 if (can_test_unc) { 652 check_dir(nearly_long_unc_path, false); 653 check_dir(empty_dir_unc_path, true); 654 check_dir(not_empty_dir_unc_path, false); 655 check_file(nearly_long_file_unc_path); 656 check_file(file_unc_path); 657 } 658 659 // Check handling of <DRIVE>:/../<OTHER_DRIVE>:/path/... 660 // The other drive letter should not overwrite the original one. 661 if (dir_letter) { 662 static wchar_t tmp[JVM_MAXPATHLEN]; 663 wchar_t* other_letter = dir_letter == L'D' ? L"C" : L"D"; 664 wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", nearly_long_file_path, other_letter, nearly_long_file_path + 2); 665 check_file_not_present(tmp); 666 wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", file_path, other_letter, file_path + 2); 667 check_file_not_present(tmp); 668 } 669 } 670 671 delete_rel_file_w(file_rel_path); 672 delete_rel_file_w(nearly_long_file_rel_path); 673 delete_empty_rel_directory_w(not_empty_dir_rel_path); 674 delete_empty_rel_directory_w(empty_dir_rel_path); 675 delete_empty_rel_directory_w(long_rel_path); 676 delete_empty_rel_directory_w(nearly_long_rel_path); 677 } 678 679 #endif