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 
  89 // Test which tries to find out if the os::stat, os::open and os::dir_is_empty methods
  90 // can handle long path names correctly.
  91 enum ModsFilter {
  92   Allow_None = 0,
  93   Allow_Sep_Mods = 1,
  94   Allow_Dot_Path = 2,
  95   Allow_Dot_Dot_Path = 4,
  96   Allow_All = Allow_Sep_Mods | Allow_Dot_Path | Allow_Dot_Dot_Path
  97 };
  98 
  99 enum Mode {
 100   TEST,
 101   EXAMPLES,
 102   BENCH
 103 };
 104 
 105 static ModsFilter mods_filter = Allow_All;
 106 static int mods_per_path = 50;
 107 static Mode mode = TEST;
 108 
 109 static void get_current_dir_w(wchar_t* path, size_t size) {
 110   DWORD count = GetCurrentDirectoryW((DWORD) size, path);
 111   EXPECT_GT((int) count, 0) << "Failed to get current directory: " << GetLastError();
 112   EXPECT_LT((size_t) count, size) << "Buffer too small for current directory: " << size;
 113 }
 114 
 115 #define WITH_ABS_PATH(path) \
 116   wchar_t abs_path[JVM_MAXPATHLEN]; \
 117   wchar_t cwd[JVM_MAXPATHLEN]; \
 118   get_current_dir_w(cwd, JVM_MAXPATHLEN); \
 119   wsprintfW(abs_path, L"\\\\?\\%ls\\%ls", cwd, (path))
 120 
 121 static bool file_exists_w(const wchar_t* path) {
 122   WIN32_FILE_ATTRIBUTE_DATA file_data;
 123   return ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data);
 124 }
 125 
 126 static void create_rel_directory_w(const wchar_t* path) {
 127   WITH_ABS_PATH(path);
 128   EXPECT_FALSE(file_exists_w(abs_path)) <<  "Can't create directory: \"" << path << "\" already exists";
 129   BOOL result = CreateDirectoryW(abs_path, NULL);
 130   EXPECT_TRUE(result) << "Failed to create directory \"" << path << "\" " << GetLastError();
 131 }
 132 
 133 static void delete_empty_rel_directory_w(const wchar_t* path) {
 134   WITH_ABS_PATH(path);
 135   EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete directory: \"" << path << "\" does not exists";
 136   BOOL result = RemoveDirectoryW(abs_path);
 137   EXPECT_TRUE(result) << "Failed to delete directory \"" << path << "\": " << GetLastError();
 138 }
 139 
 140 static void create_rel_file_w(const wchar_t* path) {
 141   WITH_ABS_PATH(path);
 142   EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create file: \"" << path << "\" already exists";
 143   HANDLE h = CreateFileW(abs_path, 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
 144   EXPECT_NE(h, INVALID_HANDLE_VALUE) << "Failed to create file \"" << path << "\": " << GetLastError();
 145   CloseHandle(h);
 146 }
 147 
 148 static void delete_rel_file_w(const wchar_t* path) {
 149   WITH_ABS_PATH(path);
 150   EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete file: \"" << path << "\" does not exists";
 151   BOOL result = DeleteFileW(abs_path);
 152   EXPECT_TRUE(result) << "Failed to delete file \"" << path << "\": " << GetLastError();
 153 }
 154 
 155 static bool convert_to_cstring(char* c_str, size_t size, wchar_t* w_str) {
 156   size_t converted;
 157   errno_t err = wcstombs_s(&converted, c_str, size, w_str, size - 1);
 158   EXPECT_EQ(err, ERROR_SUCCESS) << "Could not convert \"" << w_str << "\" to c-string";
 159 
 160   return err == ERROR_SUCCESS;
 161 }
 162 
 163 static const wchar_t* sep_replacements[] = {
 164   L"\\", L"\\/", L"/", L"//", L"\\\\/\\", L"//\\/"
 165 };
 166 
 167 static wchar_t* my_wcscpy_s(wchar_t* dest, size_t size, wchar_t* start, const wchar_t* to_copy) {
 168   size_t already_used = dest - start;
 169   size_t len = wcslen(to_copy);
 170 
 171   if (already_used + len < size) {
 172     wcscpy_s(dest, size - already_used, to_copy);
 173   }
 174 
 175   return dest + wcslen(to_copy);
 176 }
 177 
 178 static bool unnormalize_path(wchar_t* result, size_t size, bool is_dir, const wchar_t* path) {
 179   wchar_t* dest = result;
 180   const wchar_t* src = path;
 181   const wchar_t* path_start;
 182 
 183   if (wcsncmp(src, L"\\\\?\\UNC\\", 8) == 0) {
 184     path_start = src + 8;
 185   } else if (wcsncmp(src, L"\\\\?\\", 4) == 0) {
 186     if (src[5] == L':') {
 187       path_start = src + 6;
 188     } else {
 189       path_start = wcschr(src + 4, L'\\');
 190     }
 191   } else if (wcsncmp(src, L"\\\\", 2) == 0) {
 192     path_start = wcschr(src + 2, L'?');
 193 
 194     if (path_start == NULL) {
 195       path_start = wcschr(src + 2, L'\\');
 196     } else {
 197       path_start = wcschr(path_start, L'\\');
 198     }
 199   } else {
 200     path_start = wcschr(src + 1, L'\\');
 201   }
 202 
 203   bool allow_sep_change = (mods_filter & Allow_Sep_Mods) && (os::random() & 1) == 0;
 204   bool allow_dot_change = (mods_filter & Allow_Dot_Path) && (os::random() & 1) == 0;
 205   bool allow_dotdot_change = (mods_filter & Allow_Dot_Dot_Path) && (os::random() & 1) == 0;
 206 
 207   while ((*src != L'\0') && (result + size > dest)) {
 208     wchar_t c = *src;
 209     *dest = c;
 210     ++src;
 211     ++dest;
 212 
 213     if (c == L'\\') {
 214       if (allow_sep_change && (os::random() & 3) == 3) {
 215         int i = os::random() % (sizeof(sep_replacements) / sizeof(sep_replacements[0]));
 216 
 217         if (i >= 0) {
 218           const wchar_t* replacement = sep_replacements[i];
 219           dest = my_wcscpy_s(dest - 1, size,  result, replacement);
 220         }
 221       } else if (path_start != NULL) {
 222         if (allow_dotdot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) {
 223           wchar_t const* last_sep = src - 2;
 224 
 225           while (last_sep[0] != L'\\') {
 226             --last_sep;
 227           }
 228 
 229           if (last_sep > path_start) {
 230             dest = my_wcscpy_s(dest, size, result, L"../");
 231             src = last_sep + 1;
 232           }
 233         } else if (allow_dot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) {
 234           dest = my_wcscpy_s(dest, size, result, L"./");
 235         }
 236       }
 237     }
 238   }
 239 
 240   while (is_dir && ((os::random() & 15) == 1)) {
 241     dest = my_wcscpy_s(dest, size, result, L"/");
 242   }
 243 
 244   if (result + size > dest) {
 245     *dest = L'\0';
 246   }
 247 
 248   // Use this modification only if not too close to the max size.
 249   return result + size - 10 > dest;
 250 }
 251 
 252 static void check_dir_impl(wchar_t* path, bool should_be_empty) {
 253   char buf[JVM_MAXPATHLEN];
 254 
 255   if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
 256     struct stat st;
 257     EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\"";
 258     EXPECT_EQ(st.st_mode & S_IFMT, S_IFDIR) << "\"" << path << "\" is not a directory according to os::stat";
 259     errno = ERROR_SUCCESS;
 260     bool is_empty = os::dir_is_empty(buf);
 261     errno_t err = errno;
 262     EXPECT_EQ(is_empty, should_be_empty) << "os::dir_is_empty assumed \"" << path << "\" is "
 263                                          << (should_be_empty ?  "not ": "") << "empty";
 264     EXPECT_EQ(err, ERROR_SUCCESS) << "os::dir_is_empty failed for \"" << path << "\"with errno " << err;
 265   }
 266 }
 267 
 268 static void check_file_impl(wchar_t* path) {
 269   char buf[JVM_MAXPATHLEN];
 270 
 271   if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
 272     struct stat st;
 273     EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\"";
 274     EXPECT_EQ(st.st_mode & S_IFMT, S_IFREG) << "\"" << path << "\" is not a regular file according to os::stat";
 275     int fd = os::open(buf, O_RDONLY, 0);
 276     EXPECT_NE(fd, -1) << "os::open failed for \"" << path << "\" with errno " << errno;
 277     if (fd >= 0) {
 278       ::close(fd);
 279     }
 280   }
 281 }
 282 
 283 static void check_file_not_present_impl(wchar_t* path) {
 284   char buf[JVM_MAXPATHLEN];
 285 
 286   if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
 287     struct stat st;
 288     int stat_ret;
 289     EXPECT_EQ(stat_ret = os::stat(buf, &st), -1) << "os::stat did not fail for \"" << path << "\"";
 290     if (stat_ret != -1) {
 291       // Only check open if stat not already failed.
 292       int fd = os::open(buf, O_RDONLY, 0);
 293       EXPECT_EQ(fd, -1) << "os::open did not fail for \"" << path << "\"";
 294       if (fd >= 0) {
 295         ::close(fd);
 296       }
 297     }
 298   }
 299 }
 300 
 301 static void check_dir(wchar_t* path, bool should_be_empty) {
 302   check_dir_impl(path, should_be_empty);
 303 
 304   for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) {
 305     wchar_t tmp[JVM_MAXPATHLEN];
 306     if (unnormalize_path(tmp, JVM_MAXPATHLEN, true, path)) {
 307       check_dir_impl(tmp, should_be_empty);
 308     }
 309   }
 310 }
 311 
 312 static void check_file(wchar_t* path) {
 313   check_file_impl(path);
 314 
 315   for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) {
 316     wchar_t tmp[JVM_MAXPATHLEN];
 317     if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) {
 318       check_file_impl(tmp);
 319     }
 320   }
 321 }
 322 
 323 static void check_file_not_present(wchar_t* path) {
 324   check_file_not_present_impl(path);
 325 
 326   for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) {
 327     wchar_t tmp[JVM_MAXPATHLEN];
 328     if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) {
 329       check_file_not_present_impl(tmp);
 330     }
 331   }
 332 }
 333 
 334 static void record_path(char const* name, char const* len_name, wchar_t* path) {
 335   char buf[JVM_MAXPATHLEN];
 336 
 337   if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
 338     ::testing::Test::RecordProperty(name, buf);
 339     snprintf(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path));
 340     ::testing::Test::RecordProperty(len_name, buf);
 341   }
 342 }
 343 
 344 static void bench_path(wchar_t* path) {
 345   char buf[JVM_MAXPATHLEN];
 346   int reps = 100000;
 347 
 348   if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
 349     jlong wtime[2];
 350 
 351     for (int t = 0; t < 2; ++t) {
 352       wtime[t] = os::javaTimeNanos();
 353 
 354       for (int i = 0; i < reps; ++i) {
 355         bool succ = false;
 356         size_t buf_len = strlen(buf);
 357         wchar_t* w_path = (wchar_t*) os::malloc(sizeof(wchar_t) * (buf_len + 1), mtInternal);
 358 
 359         if (w_path != NULL) {
 360           size_t converted_chars;
 361           if (::mbstowcs_s(&converted_chars, w_path, buf_len + 1, buf, buf_len) == ERROR_SUCCESS) {
 362             if (t == 1) {
 363               wchar_t* tmp = (wchar_t*) os::malloc(sizeof(wchar_t) * JVM_MAXPATHLEN, mtInternal);
 364 
 365               if (tmp) {
 366                 if (_wfullpath(tmp, w_path, JVM_MAXPATHLEN)) {
 367                   succ = true;
 368                 }
 369 
 370                 os::free(tmp);
 371               }
 372               if (!succ) {
 373                 printf("Failed fullpathing \"%s\"\n", buf);
 374                 return;
 375               }
 376               succ = false;
 377             }
 378             HANDLE h = ::CreateFileW(w_path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 379 
 380             if (h != INVALID_HANDLE_VALUE) {
 381               ::CloseHandle(h);
 382               succ = true;
 383             }
 384           }
 385         }
 386 
 387         os::free(w_path);
 388         if (!succ) {
 389           printf("Failed getting W*attr. \"%s\"\n", buf);
 390           return;
 391         }
 392       }
 393 
 394       wtime[t] = os::javaTimeNanos() - wtime[t];
 395     }
 396 
 397     jlong ctime = os::javaTimeNanos();
 398 
 399     for (int i = 0; i < reps; ++i) {
 400       HANDLE h = ::CreateFileA(buf, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 401 
 402       if (h == INVALID_HANDLE_VALUE) {
 403         return;
 404       }
 405 
 406       ::CloseHandle(h);
 407     }
 408 
 409     ctime = os::javaTimeNanos() - ctime;
 410 
 411     printf("\"%s\" %f us for *A, %f us for *W, %f us for *W with fullpath\n", buf,
 412       0.001 * ctime / reps, 0.001 * wtime[0] / reps, 0.001 * wtime[1] / reps);
 413   }
 414 }
 415 
 416 static void print_attr_result_for_path(wchar_t* path) {
 417   WIN32_FILE_ATTRIBUTE_DATA file_data;
 418   struct stat st;
 419   char buf[JVM_MAXPATHLEN];
 420   wchar_t abs[JVM_MAXPATHLEN];
 421 
 422   _wfullpath(abs, path, JVM_MAXPATHLEN);
 423   printf("Checking \"%ls\" (%d chars):\n", path, (int) wcslen(path));
 424   printf("_wfullpath             %ls (%d chars)\n", abs, (int) wcslen(abs));
 425   BOOL bret = ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data);
 426   printf("GetFileAttributesExW() %s\n", bret ? "success" : "failed");
 427 
 428   if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) {
 429     bret = ::GetFileAttributesExA(buf, GetFileExInfoStandard, &file_data);
 430     printf("GetFileAttributesExA() %s\n", bret ? "success" : "failed");
 431 
 432     bool succ = os::stat(buf, &st) != -1;
 433     printf("os::stat()             %s\n", succ ? "success" : "failed");
 434   }
 435 }
 436 
 437 static void print_attr_result(wchar_t* format, ...) {
 438   va_list argptr;
 439   wchar_t buf[JVM_MAXPATHLEN];
 440 
 441   va_start(argptr, format);
 442   wvsprintfW(buf, format, argptr);
 443   print_attr_result_for_path(buf);
 444   va_end(argptr);
 445 }
 446 
 447 #define RECORD_PATH(name) record_path(#name, #name "Len", name)
 448 #define NAME_PART_50 L"01234567890123456789012345678901234567890123456789"
 449 #define NAME_PART_250 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50
 450 
 451 TEST_VM(os_windows, handle_long_paths) {
 452   static wchar_t cwd[JVM_MAXPATHLEN];
 453   static wchar_t nearly_long_rel_path[JVM_MAXPATHLEN];
 454   static wchar_t long_rel_path[JVM_MAXPATHLEN];
 455   static wchar_t empty_dir_rel_path[JVM_MAXPATHLEN];
 456   static wchar_t not_empty_dir_rel_path[JVM_MAXPATHLEN];
 457   static wchar_t file_rel_path[JVM_MAXPATHLEN];
 458   static wchar_t nearly_long_file_rel_path[JVM_MAXPATHLEN];
 459   static wchar_t nearly_long_path[JVM_MAXPATHLEN];
 460   static wchar_t empty_dir_path[JVM_MAXPATHLEN];
 461   static wchar_t not_empty_dir_path[JVM_MAXPATHLEN];
 462   static wchar_t nearly_long_file_path[JVM_MAXPATHLEN];
 463   static wchar_t file_path[JVM_MAXPATHLEN];
 464   static wchar_t nearly_long_unc_path[JVM_MAXPATHLEN];
 465   static wchar_t empty_dir_unc_path[JVM_MAXPATHLEN];
 466   static wchar_t not_empty_dir_unc_path[JVM_MAXPATHLEN];
 467   static wchar_t nearly_long_file_unc_path[JVM_MAXPATHLEN];
 468   static wchar_t file_unc_path[JVM_MAXPATHLEN];
 469   static wchar_t root_dir_path[JVM_MAXPATHLEN];
 470   static wchar_t root_rel_dir_path[JVM_MAXPATHLEN];
 471 
 472   wchar_t* dir_prefix = L"os_windows_long_paths_dir_";
 473   wchar_t* empty_dir_name = L"empty_directory_with_long_path";
 474   wchar_t* not_empty_dir_name = L"not_empty_directory_with_long_path";
 475   wchar_t* file_name = L"file";
 476   wchar_t dir_letter;
 477   WIN32_FILE_ATTRIBUTE_DATA file_data;
 478   bool can_test_unc = false;
 479 
 480   get_current_dir_w(cwd, sizeof(cwd) / sizeof(wchar_t));
 481   dir_letter = (cwd[1] == L':' ? cwd[0] : L'\0');
 482   int cwd_len = (int) wcslen(cwd);
 483   int dir_prefix_len = (int) wcslen(dir_prefix);
 484   int rel_path_len = MAX2(dir_prefix_len, 235 - cwd_len);
 485 
 486   memcpy(nearly_long_rel_path, dir_prefix, sizeof(wchar_t) * dir_prefix_len);
 487 
 488   for (int i = dir_prefix_len; i < rel_path_len; ++i) {
 489     nearly_long_rel_path[i] = L'L';
 490   }
 491 
 492   nearly_long_rel_path[rel_path_len] = L'\0';
 493 
 494   wsprintfW(long_rel_path, L"%ls\\%ls", nearly_long_rel_path, NAME_PART_250);
 495   wsprintfW(empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, empty_dir_name);
 496   wsprintfW(not_empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, not_empty_dir_name);
 497   wsprintfW(nearly_long_file_rel_path, L"%ls\\%ls", nearly_long_rel_path, file_name);
 498   wsprintfW(file_rel_path, L"%ls\\%ls\\%ls", nearly_long_rel_path, not_empty_dir_name, file_name);
 499   wsprintfW(nearly_long_path, L"\\\\?\\%ls\\%ls", cwd, nearly_long_rel_path);
 500   wsprintfW(empty_dir_path, L"%ls\\%ls", nearly_long_path, empty_dir_name);
 501   wsprintfW(not_empty_dir_path, L"%ls\\%ls", nearly_long_path, not_empty_dir_name);
 502   wsprintfW(nearly_long_file_path, L"%ls\\%ls", nearly_long_path, file_name);
 503   wsprintfW(file_path, L"%ls\\%ls\\%ls", nearly_long_path, not_empty_dir_name, file_name);
 504   wsprintfW(nearly_long_unc_path, L"\\\\localhost\\%lc$\\%s", dir_letter, nearly_long_path + 7);
 505   wsprintfW(empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, empty_dir_name);
 506   wsprintfW(not_empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, not_empty_dir_name);
 507   wsprintfW(nearly_long_file_unc_path, L"%ls\\%ls", nearly_long_unc_path, file_name);
 508   wsprintfW(file_unc_path, L"%s\\%s\\%s", nearly_long_unc_path, not_empty_dir_name, file_name);
 509   wsprintfW(root_dir_path, L"%lc:\\", dir_letter);
 510   wsprintfW(root_rel_dir_path, L"%lc:", dir_letter);
 511 
 512   RECORD_PATH(long_rel_path);
 513   RECORD_PATH(nearly_long_rel_path);
 514   RECORD_PATH(nearly_long_path);
 515   RECORD_PATH(nearly_long_unc_path);
 516   RECORD_PATH(empty_dir_rel_path);
 517   RECORD_PATH(empty_dir_path);
 518   RECORD_PATH(empty_dir_unc_path);
 519   RECORD_PATH(not_empty_dir_rel_path);
 520   RECORD_PATH(not_empty_dir_path);
 521   RECORD_PATH(not_empty_dir_unc_path);
 522   RECORD_PATH(nearly_long_file_rel_path);
 523   RECORD_PATH(nearly_long_file_path);
 524   RECORD_PATH(nearly_long_file_unc_path);
 525   RECORD_PATH(file_rel_path);
 526   RECORD_PATH(file_path);
 527   RECORD_PATH(file_unc_path);
 528 
 529   create_rel_directory_w(nearly_long_rel_path);
 530   create_rel_directory_w(long_rel_path);
 531   create_rel_directory_w(empty_dir_rel_path);
 532   create_rel_directory_w(not_empty_dir_rel_path);
 533   create_rel_file_w(nearly_long_file_rel_path);
 534   create_rel_file_w(file_rel_path);
 535 
 536   // For UNC path test we assume that the current DRIVE has a share
 537   // called "<DRIVELETTER>$" (so for D: we expect \\localhost\D$ to be
 538   // the same). Since this is only an assumption, we have to skip
 539   // the UNC tests if the share is missing.
 540   if (dir_letter && !::GetFileAttributesExW(nearly_long_unc_path, GetFileExInfoStandard, &file_data)) {
 541     printf("Disabled UNC path test, since %lc: is not mapped as share %lc$.\n", dir_letter, dir_letter);
 542   } else {
 543     can_test_unc = true;
 544   }
 545 
 546   if (mode == BENCH) {
 547     bench_path(nearly_long_path + 4);
 548     bench_path(nearly_long_rel_path);
 549     bench_path(nearly_long_file_path + 4);
 550     bench_path(nearly_long_file_rel_path);
 551   } else if (mode == EXAMPLES) {
 552     printf("Working directory: %ls", cwd);
 553 
 554     if (dir_letter) {
 555       static wchar_t top_buf[JVM_MAXPATHLEN];
 556       wchar_t* top_path = wcschr(cwd + 3, L'\\');
 557 
 558       if (top_path) {
 559         size_t top_len = (top_path - cwd) - 3;
 560 
 561         memcpy(top_buf, cwd + 3, top_len * 2);
 562         top_buf[top_len] = L'\0';
 563         top_path = top_buf;
 564       }
 565 
 566       print_attr_result(L"%lc:\\", dir_letter);
 567       print_attr_result(L"%lc:\\.\\", dir_letter);
 568 
 569       if (top_path) {
 570         print_attr_result(L"%lc:\\%ls\\..\\%ls\\", dir_letter, top_path, top_path);
 571       }
 572 
 573       print_attr_result(L"%lc:", dir_letter);
 574       print_attr_result(L"%lc:.", dir_letter);
 575       print_attr_result(L"%lc:\\COM1", dir_letter);
 576       print_attr_result(L"%lc:\\PRN", dir_letter);
 577       print_attr_result(L"%lc:\\PRN\\COM1", dir_letter);
 578       print_attr_result(L"\\\\?\\UNC\\localhost\\%lc$\\", dir_letter);
 579       print_attr_result(L"\\\\?\\UNC\\\\localhost\\%lc$\\", dir_letter);
 580       print_attr_result(nearly_long_unc_path);
 581       print_attr_result(L"%ls\\.\\", nearly_long_unc_path);
 582       print_attr_result(L"%ls\\..\\%ls", nearly_long_unc_path, nearly_long_rel_path);
 583       print_attr_result(L"\\\\?\\UNC\\%ls", nearly_long_unc_path + 2);
 584       print_attr_result(file_unc_path);
 585       print_attr_result(L"%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path, not_empty_dir_name, not_empty_dir_name, file_name);
 586       print_attr_result(L"%ls\\%ls\\.\\%ls", nearly_long_unc_path, not_empty_dir_name, file_name);
 587       print_attr_result(L"\\\\?\\UNC\\%ls", file_unc_path + 2);
 588       print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\.\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, file_name);
 589       print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, not_empty_dir_name, file_name);
 590     }
 591 
 592     print_attr_result(nearly_long_rel_path);
 593     print_attr_result(L"%ls\\.\\", nearly_long_rel_path);
 594     print_attr_result(L"%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path);
 595     print_attr_result(L"%\\\\?\\%ls", nearly_long_rel_path);
 596     print_attr_result(L"\\\\?\\%ls\\.\\", nearly_long_rel_path);
 597     print_attr_result(L"\\\\?\\%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path);
 598 
 599     print_attr_result(nearly_long_path + 4);
 600     print_attr_result(L"%ls\\.\\", nearly_long_path + 4);
 601     print_attr_result(L"%ls\\..\\%ls", nearly_long_path + 4, nearly_long_rel_path);
 602     print_attr_result(nearly_long_path);
 603     print_attr_result(L"%ls\\.\\", nearly_long_path);
 604     print_attr_result(L"%ls\\..\\%ls", nearly_long_path, nearly_long_rel_path);
 605   } else {
 606     // Check relative paths
 607     check_dir(nearly_long_rel_path, false);
 608     check_dir(long_rel_path, true);
 609     check_dir(empty_dir_rel_path, true);
 610     check_dir(not_empty_dir_rel_path, false);
 611     check_file(nearly_long_file_rel_path);
 612     check_file(file_rel_path);
 613 
 614     // Check absolute paths
 615     if (dir_letter) {
 616       check_dir(root_dir_path, false);
 617       check_dir(root_rel_dir_path, false);
 618     }
 619 
 620     check_dir(cwd, false);
 621     check_dir(nearly_long_path + 4, false);
 622     check_dir(empty_dir_path + 4, true);
 623     check_dir(not_empty_dir_path + 4, false);
 624     check_file(nearly_long_file_path + 4);
 625     check_file(file_path + 4);
 626 
 627     // Check UNC paths
 628     if (can_test_unc) {
 629       check_dir(nearly_long_unc_path, false);
 630       check_dir(empty_dir_unc_path, true);
 631       check_dir(not_empty_dir_unc_path, false);
 632       check_file(nearly_long_file_unc_path);
 633       check_file(file_unc_path);
 634     }
 635 
 636     // Check handling of <DRIVE>:/../<OTHER_DRIVE>:/path/...
 637     // The other drive letter should not overwrite the original one.
 638     if (dir_letter) {
 639       static wchar_t tmp[JVM_MAXPATHLEN];
 640       wchar_t* other_letter = dir_letter == L'D' ? L"C" : L"D";
 641       wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", nearly_long_file_path, other_letter, nearly_long_file_path + 2);
 642       check_file_not_present(tmp);
 643       wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", file_path, other_letter, file_path + 2);
 644       check_file_not_present(tmp);
 645     }
 646   }
 647 
 648   delete_rel_file_w(file_rel_path);
 649   delete_rel_file_w(nearly_long_file_rel_path);
 650   delete_empty_rel_directory_w(not_empty_dir_rel_path);
 651   delete_empty_rel_directory_w(empty_dir_rel_path);
 652   delete_empty_rel_directory_w(long_rel_path);
 653   delete_empty_rel_directory_w(nearly_long_rel_path);
 654 }
 655 
 656 #endif