4144 return value; 4145 } 4146 4147 // Transfers data from WIN32_FILE_ATTRIBUTE_DATA structure to struct stat 4148 static void file_attribute_data_to_stat(struct stat* sbuf, WIN32_FILE_ATTRIBUTE_DATA file_data) { 4149 ::memset((void*)sbuf, 0, sizeof(struct stat)); 4150 sbuf->st_size = (_off_t)make_double_word(file_data.nFileSizeHigh, file_data.nFileSizeLow); 4151 sbuf->st_mtime = make_double_word(file_data.ftLastWriteTime.dwHighDateTime, 4152 file_data.ftLastWriteTime.dwLowDateTime); 4153 sbuf->st_ctime = make_double_word(file_data.ftCreationTime.dwHighDateTime, 4154 file_data.ftCreationTime.dwLowDateTime); 4155 sbuf->st_atime = make_double_word(file_data.ftLastAccessTime.dwHighDateTime, 4156 file_data.ftLastAccessTime.dwLowDateTime); 4157 if ((file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { 4158 sbuf->st_mode |= S_IFDIR; 4159 } else { 4160 sbuf->st_mode |= S_IFREG; 4161 } 4162 } 4163 4164 // Returns the given path as an absolute wide path in unc format. The returned path is NULL 4165 // on error (with err being set accordingly) and should be freed via os::free() otherwise. 4166 // additional_space is the number of additionally allocated wchars after the terminating L'\0'. 4167 // This is based on pathToNTPath() in io_util_md.cpp, but omits the optimizations for 4168 // short paths. 4169 static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additional_space = 0) { 4170 if ((path == NULL) || (path[0] == '\0')) { 4171 err = ENOENT; 4172 return NULL; 4173 } 4174 4175 size_t path_len = strlen(path); 4176 // Need to allocate at least room for 3 characters, since os::native_path transforms C: to C:. 4177 char* buf = (char*) os::malloc(1 + MAX2((size_t) 3, path_len), mtInternal); 4178 wchar_t* result = NULL; 4179 4180 if (buf == NULL) { 4181 err = ENOMEM; 4182 } else { 4183 memcpy(buf, path, path_len + 1); 4184 os::native_path(buf); 4185 4186 wchar_t* prefix; 4187 int prefix_off = 0; 4188 bool is_abs = true; 4189 bool needs_fullpath = true; 4190 4191 if (::isalpha(buf[0]) && !::IsDBCSLeadByte(buf[0]) && buf[1] == ':' && buf[2] == '\\') { 4192 prefix = L"\\\\?\\"; 4193 } else if (buf[0] == '\\' && buf[1] == '\\') { 4194 if (buf[2] == '?' && buf[3] == '\\') { 4195 prefix = L""; 4196 needs_fullpath = false; 4197 } else { 4198 prefix = L"\\\\?\\UNC"; 4199 prefix_off = 1; // Overwrite the first char with the prefix, so \\share\path becomes \\?\UNC\share\path 4200 } 4201 } else { 4202 is_abs = false; 4203 prefix = L"\\\\?\\"; 4204 } 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) { 4213 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 } 4245 } 4246 } 4247 4248 os::free(buf); 4249 4250 if (err != ERROR_SUCCESS) { 4251 os::free(result); 4252 result = NULL; 4253 } 4254 4255 return result; 4256 } 4257 4258 int os::stat(const char *path, struct stat *sbuf) { 4259 errno_t err; 4260 wchar_t* wide_path = wide_abs_unc_path(path, err); 4261 4262 if (wide_path == NULL) { 4263 errno = err; 4264 return -1; 4265 } 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; 4274 } 4275 | 4144 return value; 4145 } 4146 4147 // Transfers data from WIN32_FILE_ATTRIBUTE_DATA structure to struct stat 4148 static void file_attribute_data_to_stat(struct stat* sbuf, WIN32_FILE_ATTRIBUTE_DATA file_data) { 4149 ::memset((void*)sbuf, 0, sizeof(struct stat)); 4150 sbuf->st_size = (_off_t)make_double_word(file_data.nFileSizeHigh, file_data.nFileSizeLow); 4151 sbuf->st_mtime = make_double_word(file_data.ftLastWriteTime.dwHighDateTime, 4152 file_data.ftLastWriteTime.dwLowDateTime); 4153 sbuf->st_ctime = make_double_word(file_data.ftCreationTime.dwHighDateTime, 4154 file_data.ftCreationTime.dwLowDateTime); 4155 sbuf->st_atime = make_double_word(file_data.ftLastAccessTime.dwHighDateTime, 4156 file_data.ftLastAccessTime.dwLowDateTime); 4157 if ((file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { 4158 sbuf->st_mode |= S_IFDIR; 4159 } else { 4160 sbuf->st_mode |= S_IFREG; 4161 } 4162 } 4163 4164 static errno_t convert_to_unicode(char const* char_path, LPWSTR& unicode_path) { 4165 // Get required buffer size to convert to Unicode 4166 int unicode_path_len = MultiByteToWideChar(CP_THREAD_ACP, 4167 MB_ERR_INVALID_CHARS, 4168 char_path, -1, 4169 NULL, 0); 4170 if (unicode_path_len == 0) { 4171 return EINVAL; 4172 } 4173 4174 size_t unicode_path_size = sizeof(WCHAR) * unicode_path_len; 4175 unicode_path = reinterpret_cast<LPWSTR>(os::malloc(unicode_path_size, mtInternal)); 4176 if (unicode_path == NULL) { 4177 vm_exit_out_of_memory(unicode_path_size, OOM_MALLOC_ERROR, "convert_to_unicode"); 4178 } 4179 4180 int result = MultiByteToWideChar(CP_THREAD_ACP, 4181 MB_ERR_INVALID_CHARS, 4182 char_path, -1, 4183 unicode_path, unicode_path_len); 4184 assert(result == unicode_path_len, "length already checked above"); 4185 4186 return ERROR_SUCCESS; 4187 } 4188 4189 static errno_t get_full_path(LPCWSTR unicode_path, LPWSTR& full_path) { 4190 // Get required buffer size to convert to full path 4191 DWORD full_path_len = GetFullPathNameW(unicode_path, 0, NULL, NULL); 4192 if (full_path_len == 0) { 4193 return EINVAL; 4194 } 4195 4196 size_t full_path_size = sizeof(WCHAR) * full_path_len; 4197 full_path = reinterpret_cast<LPWSTR>(os::malloc(full_path_size, mtInternal)); 4198 if (full_path == NULL) { 4199 vm_exit_out_of_memory(full_path_size, OOM_MALLOC_ERROR, "get_full_path"); 4200 } 4201 4202 DWORD result = GetFullPathNameW(unicode_path, full_path_len, full_path, NULL); 4203 assert(result == (full_path_len - 1), "length already checked above"); 4204 4205 return ERROR_SUCCESS; 4206 } 4207 4208 static void set_path_prefix(char* buf, LPWSTR& prefix, int& prefix_off, bool& needs_fullpath) { 4209 prefix_off = 0; 4210 needs_fullpath = true; 4211 4212 if (::isalpha(buf[0]) && !::IsDBCSLeadByte(buf[0]) && buf[1] == ':' && buf[2] == '\\') { 4213 prefix = L"\\\\?\\"; 4214 } else if (buf[0] == '\\' && buf[1] == '\\') { 4215 if (buf[2] == '?' && buf[3] == '\\') { 4216 prefix = L""; 4217 needs_fullpath = false; 4218 } else { 4219 prefix = L"\\\\?\\UNC"; 4220 prefix_off = 1; // Overwrite the first char with the prefix, so \\share\path becomes \\?\UNC\share\path 4221 } 4222 } else { 4223 prefix = L"\\\\?\\"; 4224 } 4225 } 4226 4227 // Returns the given path as an absolute wide path in unc format. The returned path is NULL 4228 // on error (with err being set accordingly) and should be freed via os::free() otherwise. 4229 // additional_space is the number of additionally allocated wchars after the terminating L'\0'. 4230 // This is based on pathToNTPath() in io_util_md.cpp, but omits the optimizations for 4231 // short paths. 4232 static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additional_space = 0) { 4233 if ((path == NULL) || (path[0] == '\0')) { 4234 err = ENOENT; 4235 return NULL; 4236 } 4237 4238 // Need to allocate at least room for 3 characters, since os::native_path transforms C: to C:. 4239 size_t buf_size = 1 + MAX2((size_t)3, strlen(path)); 4240 char* buf = reinterpret_cast<char*>(os::malloc(buf_size, mtInternal)); 4241 if (buf == NULL) { 4242 vm_exit_out_of_memory(buf_size, OOM_MALLOC_ERROR, "wide_abs_unc_path"); 4243 } 4244 memcpy(buf, path, buf_size); 4245 os::native_path(buf); 4246 4247 LPWSTR prefix; 4248 int prefix_off = 0; 4249 bool needs_fullpath = true; 4250 set_path_prefix(buf, prefix, prefix_off, needs_fullpath); 4251 4252 LPWSTR unicode_path; 4253 err = convert_to_unicode(buf, unicode_path); 4254 os::free(buf); 4255 if (err != ERROR_SUCCESS) { 4256 return NULL; 4257 } 4258 4259 LPWSTR converted_path = NULL; 4260 if (needs_fullpath) { 4261 err = get_full_path(unicode_path, converted_path); 4262 } else { 4263 converted_path = unicode_path; 4264 } 4265 4266 LPWSTR result = NULL; 4267 if (converted_path != NULL) { 4268 size_t prefix_len = wcslen(prefix); 4269 size_t result_len = prefix_len - prefix_off + wcslen(converted_path) + additional_space + 1; 4270 result = reinterpret_cast<LPWSTR>(os::malloc(sizeof(WCHAR) * result_len, mtInternal)); 4271 if (result == NULL) { 4272 vm_exit_out_of_memory(buf_size, OOM_MALLOC_ERROR, "wide_abs_unc_path"); 4273 } 4274 _snwprintf(result, result_len, L"%s%s", prefix, &converted_path[prefix_off]); 4275 4276 // Remove trailing pathsep (not for \\?\<DRIVE>:\, since it would make it relative) 4277 result_len = wcslen(result); 4278 if ((result[result_len - 1] == L'\\') && 4279 !(::iswalpha(result[4]) && result[5] == L':' && result_len == 7)) { 4280 result[result_len - 1] = L'\0'; 4281 } 4282 } 4283 4284 if (converted_path != unicode_path) { 4285 os::free(converted_path); 4286 } 4287 os::free(unicode_path); 4288 4289 return (wchar_t*)result; // LPWSTR and wchat_t* are the same type on Windows. 4290 } 4291 4292 int os::stat(const char *path, struct stat *sbuf) { 4293 errno_t err; 4294 wchar_t* wide_path = wide_abs_unc_path(path, err); 4295 4296 if (wide_path == NULL) { 4297 errno = err; 4298 return -1; 4299 } 4300 4301 WIN32_FILE_ATTRIBUTE_DATA file_data;; 4302 BOOL bret = ::GetFileAttributesExW(wide_path, GetFileExInfoStandard, &file_data); 4303 os::free(wide_path); 4304 4305 if (!bret) { 4306 errno = ::GetLastError(); 4307 return -1; 4308 } 4309 |