Skip to content

Commit 98a2c05

Browse files
committed
8191521: handle long relative path specified in -Xbootclasspath/a on windows
Reviewed-by: ccheung, clanger
1 parent fd3a403 commit 98a2c05

File tree

3 files changed

+736
-173
lines changed

3 files changed

+736
-173
lines changed

src/hotspot/os/windows/os_windows.cpp

Lines changed: 139 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -4159,128 +4159,137 @@ static void file_attribute_data_to_stat(struct stat* sbuf, WIN32_FILE_ATTRIBUTE_
41594159
}
41604160
}
41614161

4162-
// The following function is adapted from java.base/windows/native/libjava/canonicalize_md.c
4163-
// Creates an UNC path from a single byte path. Return buffer is
4164-
// allocated in C heap and needs to be freed by the caller.
4165-
// Returns NULL on error.
4166-
static wchar_t* create_unc_path(const char* path, errno_t &err) {
4167-
wchar_t* wpath = NULL;
4168-
size_t converted_chars = 0;
4169-
size_t path_len = strlen(path) + 1; // includes the terminating NULL
4170-
if (path[0] == '\\' && path[1] == '\\') {
4171-
if (path[2] == '?' && path[3] == '\\'){
4172-
// if it already has a \\?\ don't do the prefix
4173-
wpath = (wchar_t*)os::malloc(path_len * sizeof(wchar_t), mtInternal);
4174-
if (wpath != NULL) {
4175-
err = ::mbstowcs_s(&converted_chars, wpath, path_len, path, path_len);
4162+
// Returns the given path as an absolute wide path in unc format. The returned path is NULL
4163+
// on error (with err being set accordingly) and should be freed via os::free() otherwise.
4164+
// additional_space is the number of additionally allocated wchars after the terminating L'\0'.
4165+
// This is based on pathToNTPath() in io_util_md.cpp, but omits the optimizations for
4166+
// short paths.
4167+
static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additional_space = 0) {
4168+
if ((path == NULL) || (path[0] == '\0')) {
4169+
err = ENOENT;
4170+
return NULL;
4171+
}
4172+
4173+
size_t path_len = strlen(path);
4174+
// Need to allocate at least room for 3 characters, since os::native_path transforms C: to C:.
4175+
char* buf = (char*) os::malloc(1 + MAX2((size_t) 3, path_len), mtInternal);
4176+
wchar_t* result = NULL;
4177+
4178+
if (buf == NULL) {
4179+
err = ENOMEM;
4180+
} else {
4181+
memcpy(buf, path, path_len + 1);
4182+
os::native_path(buf);
4183+
4184+
wchar_t* prefix;
4185+
int prefix_off = 0;
4186+
bool is_abs = true;
4187+
bool needs_fullpath = true;
4188+
4189+
if (::isalpha(buf[0]) && !::IsDBCSLeadByte(buf[0]) && buf[1] == ':' && buf[2] == '\\') {
4190+
prefix = L"\\\\?\\";
4191+
} else if (buf[0] == '\\' && buf[1] == '\\') {
4192+
assert(buf[2] != '\\');
4193+
4194+
if (buf[2] == '?' && buf[3] == '\\') {
4195+
prefix = L"";
4196+
needs_fullpath = false;
41764197
} else {
4177-
err = ENOMEM;
4198+
prefix = L"\\\\?\\UNC";
4199+
prefix_off = 1; // Overwrite the first char with the prefix, so \\share\path becomes \\?\UNC\share\path
41784200
}
41794201
} else {
4180-
// only UNC pathname includes double slashes here
4181-
wpath = (wchar_t*)os::malloc((path_len + 7) * sizeof(wchar_t), mtInternal);
4182-
if (wpath != NULL) {
4183-
::wcscpy(wpath, L"\\\\?\\UNC\0");
4184-
err = ::mbstowcs_s(&converted_chars, &wpath[7], path_len, path, path_len);
4185-
} else {
4186-
err = ENOMEM;
4187-
}
4202+
is_abs = false;
4203+
prefix = L"\\\\?\\";
41884204
}
4189-
} else {
4190-
wpath = (wchar_t*)os::malloc((path_len + 4) * sizeof(wchar_t), mtInternal);
4191-
if (wpath != NULL) {
4192-
::wcscpy(wpath, L"\\\\?\\\0");
4193-
err = ::mbstowcs_s(&converted_chars, &wpath[4], path_len, path, path_len);
4194-
} else {
4205+
4206+
size_t buf_len = strlen(buf);
4207+
size_t prefix_len = wcslen(prefix);
4208+
size_t full_path_size = is_abs ? 1 + buf_len : JVM_MAXPATHLEN;
4209+
size_t result_size = prefix_len + full_path_size - prefix_off;
4210+
result = (wchar_t*) os::malloc(sizeof(wchar_t) * (additional_space + result_size), mtInternal);
4211+
4212+
if (result == NULL) {
41954213
err = ENOMEM;
4214+
} else {
4215+
size_t converted_chars;
4216+
wchar_t* path_start = result + prefix_len - prefix_off;
4217+
err = ::mbstowcs_s(&converted_chars, path_start, buf_len + 1, buf, buf_len);
4218+
4219+
if ((err == ERROR_SUCCESS) && needs_fullpath) {
4220+
wchar_t* tmp = (wchar_t*) os::malloc(sizeof(wchar_t) * full_path_size, mtInternal);
4221+
4222+
if (tmp == NULL) {
4223+
err = ENOMEM;
4224+
} else {
4225+
if (!_wfullpath(tmp, path_start, full_path_size)) {
4226+
err = ENOENT;
4227+
} else {
4228+
::memcpy(path_start, tmp, (1 + wcslen(tmp)) * sizeof(wchar_t));
4229+
}
4230+
4231+
os::free(tmp);
4232+
}
4233+
}
4234+
4235+
memcpy(result, prefix, sizeof(wchar_t) * prefix_len);
4236+
4237+
// Remove trailing pathsep (not for \\?\<DRIVE>:\, since it would make it relative)
4238+
size_t result_len = wcslen(result);
4239+
4240+
if (result[result_len - 1] == L'\\') {
4241+
if (!(::iswalpha(result[4]) && result[5] == L':' && result_len == 7)) {
4242+
result[result_len - 1] = L'\0';
4243+
}
4244+
}
41964245
}
41974246
}
4198-
return wpath;
4199-
}
42004247

4201-
static void destroy_unc_path(wchar_t* wpath) {
4202-
os::free(wpath);
4248+
os::free(buf);
4249+
4250+
if (err != ERROR_SUCCESS) {
4251+
os::free(result);
4252+
result = NULL;
4253+
}
4254+
4255+
return result;
42034256
}
42044257

42054258
int os::stat(const char *path, struct stat *sbuf) {
4206-
char* pathbuf = (char*)os::strdup(path, mtInternal);
4207-
if (pathbuf == NULL) {
4208-
errno = ENOMEM;
4259+
errno_t err;
4260+
wchar_t* wide_path = wide_abs_unc_path(path, err);
4261+
4262+
if (wide_path == NULL) {
4263+
errno = err;
42094264
return -1;
42104265
}
4211-
os::native_path(pathbuf);
4212-
int ret;
4213-
WIN32_FILE_ATTRIBUTE_DATA file_data;
4214-
// Not using stat() to avoid the problem described in JDK-6539723
4215-
if (strlen(path) < MAX_PATH) {
4216-
BOOL bret = ::GetFileAttributesExA(pathbuf, GetFileExInfoStandard, &file_data);
4217-
if (!bret) {
4218-
errno = ::GetLastError();
4219-
ret = -1;
4220-
}
4221-
else {
4222-
file_attribute_data_to_stat(sbuf, file_data);
4223-
ret = 0;
4224-
}
4225-
} else {
4226-
errno_t err = ERROR_SUCCESS;
4227-
wchar_t* wpath = create_unc_path(pathbuf, err);
4228-
if (err != ERROR_SUCCESS) {
4229-
if (wpath != NULL) {
4230-
destroy_unc_path(wpath);
4231-
}
4232-
os::free(pathbuf);
4233-
errno = err;
4234-
return -1;
4235-
}
4236-
BOOL bret = ::GetFileAttributesExW(wpath, GetFileExInfoStandard, &file_data);
4237-
if (!bret) {
4238-
errno = ::GetLastError();
4239-
ret = -1;
4240-
} else {
4241-
file_attribute_data_to_stat(sbuf, file_data);
4242-
ret = 0;
4243-
}
4244-
destroy_unc_path(wpath);
4266+
4267+
WIN32_FILE_ATTRIBUTE_DATA file_data;;
4268+
BOOL bret = ::GetFileAttributesExW(wide_path, GetFileExInfoStandard, &file_data);
4269+
os::free(wide_path);
4270+
4271+
if (!bret) {
4272+
errno = ::GetLastError();
4273+
return -1;
42454274
}
4246-
os::free(pathbuf);
4247-
return ret;
4275+
4276+
file_attribute_data_to_stat(sbuf, file_data);
4277+
return 0;
42484278
}
42494279

42504280
static HANDLE create_read_only_file_handle(const char* file) {
4251-
if (file == NULL) {
4252-
return INVALID_HANDLE_VALUE;
4253-
}
4281+
errno_t err;
4282+
wchar_t* wide_path = wide_abs_unc_path(file, err);
42544283

4255-
char* nativepath = (char*)os::strdup(file, mtInternal);
4256-
if (nativepath == NULL) {
4257-
errno = ENOMEM;
4284+
if (wide_path == NULL) {
4285+
errno = err;
42584286
return INVALID_HANDLE_VALUE;
42594287
}
4260-
os::native_path(nativepath);
42614288

4262-
size_t len = strlen(nativepath);
4263-
HANDLE handle = INVALID_HANDLE_VALUE;
4289+
HANDLE handle = ::CreateFileW(wide_path, 0, FILE_SHARE_READ,
4290+
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4291+
os::free(wide_path);
42644292

4265-
if (len < MAX_PATH) {
4266-
handle = ::CreateFile(nativepath, 0, FILE_SHARE_READ,
4267-
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4268-
} else {
4269-
errno_t err = ERROR_SUCCESS;
4270-
wchar_t* wfile = create_unc_path(nativepath, err);
4271-
if (err != ERROR_SUCCESS) {
4272-
if (wfile != NULL) {
4273-
destroy_unc_path(wfile);
4274-
}
4275-
os::free(nativepath);
4276-
return INVALID_HANDLE_VALUE;
4277-
}
4278-
handle = ::CreateFileW(wfile, 0, FILE_SHARE_READ,
4279-
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4280-
destroy_unc_path(wfile);
4281-
}
4282-
4283-
os::free(nativepath);
42844293
return handle;
42854294
}
42864295

@@ -4329,7 +4338,6 @@ bool os::same_files(const char* file1, const char* file2) {
43294338
return result;
43304339
}
43314340

4332-
43334341
#define FT2INT64(ft) \
43344342
((jlong)((jlong)(ft).dwHighDateTime << 32 | (julong)(ft).dwLowDateTime))
43354343

@@ -4434,38 +4442,22 @@ bool os::dont_yield() {
44344442
return DontYieldALot;
44354443
}
44364444

4437-
// This method is a slightly reworked copy of JDK's sysOpen
4438-
// from src/windows/hpi/src/sys_api_md.c
4439-
44404445
int os::open(const char *path, int oflag, int mode) {
4441-
char* pathbuf = (char*)os::strdup(path, mtInternal);
4442-
if (pathbuf == NULL) {
4443-
errno = ENOMEM;
4446+
errno_t err;
4447+
wchar_t* wide_path = wide_abs_unc_path(path, err);
4448+
4449+
if (wide_path == NULL) {
4450+
errno = err;
44444451
return -1;
44454452
}
4446-
os::native_path(pathbuf);
4447-
int ret;
4448-
if (strlen(path) < MAX_PATH) {
4449-
ret = ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode);
4450-
} else {
4451-
errno_t err = ERROR_SUCCESS;
4452-
wchar_t* wpath = create_unc_path(pathbuf, err);
4453-
if (err != ERROR_SUCCESS) {
4454-
if (wpath != NULL) {
4455-
destroy_unc_path(wpath);
4456-
}
4457-
os::free(pathbuf);
4458-
errno = err;
4459-
return -1;
4460-
}
4461-
ret = ::_wopen(wpath, oflag | O_BINARY | O_NOINHERIT, mode);
4462-
if (ret == -1) {
4463-
errno = ::GetLastError();
4464-
}
4465-
destroy_unc_path(wpath);
4453+
int fd = ::_wopen(wide_path, oflag | O_BINARY | O_NOINHERIT, mode);
4454+
os::free(wide_path);
4455+
4456+
if (fd == -1) {
4457+
errno = ::GetLastError();
44664458
}
4467-
os::free(pathbuf);
4468-
return ret;
4459+
4460+
return fd;
44694461
}
44704462

44714463
FILE* os::open(int fd, const char* mode) {
@@ -4474,37 +4466,26 @@ FILE* os::open(int fd, const char* mode) {
44744466

44754467
// Is a (classpath) directory empty?
44764468
bool os::dir_is_empty(const char* path) {
4477-
char* search_path = (char*)os::malloc(strlen(path) + 3, mtInternal);
4478-
if (search_path == NULL) {
4479-
errno = ENOMEM;
4480-
return false;
4481-
}
4482-
strcpy(search_path, path);
4483-
os::native_path(search_path);
4484-
// Append "*", or possibly "\\*", to path
4485-
if (search_path[1] == ':' &&
4486-
(search_path[2] == '\0' ||
4487-
(search_path[2] == '\\' && search_path[3] == '\0'))) {
4488-
// No '\\' needed for cases like "Z:" or "Z:\"
4489-
strcat(search_path, "*");
4490-
}
4491-
else {
4492-
strcat(search_path, "\\*");
4493-
}
4494-
errno_t err = ERROR_SUCCESS;
4495-
wchar_t* wpath = create_unc_path(search_path, err);
4496-
if (err != ERROR_SUCCESS) {
4497-
if (wpath != NULL) {
4498-
destroy_unc_path(wpath);
4499-
}
4500-
os::free(search_path);
4469+
errno_t err;
4470+
wchar_t* wide_path = wide_abs_unc_path(path, err, 2);
4471+
4472+
if (wide_path == NULL) {
45014473
errno = err;
45024474
return false;
45034475
}
4476+
4477+
// Make sure we end with "\\*"
4478+
if (wide_path[wcslen(wide_path) - 1] == L'\\') {
4479+
wcscat(wide_path, L"*");
4480+
} else {
4481+
wcscat(wide_path, L"\\*");
4482+
}
4483+
45044484
WIN32_FIND_DATAW fd;
4505-
HANDLE f = ::FindFirstFileW(wpath, &fd);
4506-
destroy_unc_path(wpath);
4485+
HANDLE f = ::FindFirstFileW(wide_path, &fd);
4486+
os::free(wide_path);
45074487
bool is_empty = true;
4488+
45084489
if (f != INVALID_HANDLE_VALUE) {
45094490
while (is_empty && ::FindNextFileW(f, &fd)) {
45104491
// An empty directory contains only the current directory file
@@ -4515,8 +4496,10 @@ bool os::dir_is_empty(const char* path) {
45154496
}
45164497
}
45174498
FindClose(f);
4499+
} else {
4500+
errno = ::GetLastError();
45184501
}
4519-
os::free(search_path);
4502+
45204503
return is_empty;
45214504
}
45224505

0 commit comments

Comments
 (0)