test/hotspot/gtest/runtime/test_os_windows.cpp
changeset 58426 ed5e399d967d
parent 54983 81becad91321
child 58474 74094a60d018
equal deleted inserted replaced
58425:f4a4804ab3e6 58426:ed5e399d967d
     1 /*
     1 /*
     2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
     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.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    83 
    83 
    84   EXPECT_EQ(expected_location, actual_location)
    84   EXPECT_EQ(expected_location, actual_location)
    85         << "Failed to allocate memory at requested location " << expected_location << " of size " << expected_allocation_size;
    85         << "Failed to allocate memory at requested location " << expected_location << " of size " << expected_allocation_size;
    86 }
    86 }
    87 
    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     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 
    88 #endif
   679 #endif