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";
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'\\');
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) {
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);
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];
|
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";
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'\\');
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) {
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);
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 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];
|