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;; | 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 LPWSTR 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 // Need to allocate at least room for 3 characters, since os::native_path transforms C: to C:. 4176 size_t buf_size = 1 + MAX2((size_t)3, strlen(path)); 4177 char* buf = static_cast<char*>(os::malloc(buf_size, mtInternal)); 4178 if (buf == NULL) { 4179 err = ENOMEM; 4180 return NULL; 4181 } 4182 memcpy(buf, path, buf_size); 4183 os::native_path(buf); 4184 4185 // Get required buffer size to convert to Unicode 4186 int unicode_path_len = MultiByteToWideChar(CP_THREAD_ACP, 4187 MB_ERR_INVALID_CHARS, 4188 buf, -1, 4189 NULL, 0); 4190 if (unicode_path_len == 0) { 4191 os::free(buf); 4192 err = EINVAL; 4193 return NULL; 4194 } 4195 4196 LPWSTR prefix; 4197 int prefix_off = 0; 4198 bool needs_fullpath = true; 4199 4200 if (::isalpha(buf[0]) && !::IsDBCSLeadByte(buf[0]) && buf[1] == ':' && buf[2] == '\\') { 4201 prefix = L"\\\\?\\"; 4202 } else if (buf[0] == '\\' && buf[1] == '\\') { 4203 if (buf[2] == '?' && buf[3] == '\\') { 4204 prefix = L""; 4205 needs_fullpath = false; 4206 } else { 4207 prefix = L"\\\\?\\UNC"; 4208 prefix_off = 1; // Overwrite the first char with the prefix, so \\share\path becomes \\?\UNC\share\path 4209 } 4210 } else { 4211 prefix = L"\\\\?\\"; 4212 } 4213 size_t prefix_len = wcslen(prefix); 4214 LPWSTR result = NULL; 4215 4216 LPWSTR unicode_path = static_cast<LPWSTR>(os::malloc(sizeof(WCHAR) * unicode_path_len, mtInternal)); 4217 if (unicode_path == NULL) { 4218 err = ENOMEM; 4219 } else { 4220 // This call would be success because it is checked in above 4221 err = ERROR_SUCCESS; 4222 MultiByteToWideChar(CP_THREAD_ACP, 4223 MB_ERR_INVALID_CHARS, 4224 buf, -1, 4225 unicode_path, unicode_path_len); 4226 4227 size_t result_len = prefix_len + prefix_off + additional_space; 4228 if (needs_fullpath) { 4229 // Get required buffer size to convert to full path 4230 DWORD full_path_len = GetFullPathNameW(unicode_path, 0, NULL, NULL); 4231 if (full_path_len == 0) { 4232 err = EINVAL; 4233 } else { 4234 size_t result_size = sizeof(WCHAR) * (result_len + full_path_len); 4235 result = static_cast<LPWSTR>(os::malloc(result_size, mtInternal)); 4236 if (result == NULL) { 4237 err = ENOMEM; 4238 } else { 4239 // Copy prefix 4240 memcpy(result, prefix, sizeof(WCHAR) * prefix_len); 4241 // This call would be success because it is checked in above 4242 GetFullPathNameW(unicode_path, full_path_len, result + prefix_len - prefix_off, NULL); 4243 } 4244 } 4245 } else { 4246 size_t result_size = sizeof(WCHAR) * (result_len + unicode_path_len); 4247 result = static_cast<LPWSTR>(os::malloc(result_size, mtInternal)); 4248 if (result == NULL) { 4249 err = ENOMEM; 4250 } else { 4251 // Copy prefix 4252 memcpy(result, prefix, sizeof(WCHAR) * prefix_len); 4253 // Copy unicode path 4254 memcpy(result + prefix_len - prefix_off, unicode_path, sizeof(WCHAR) * unicode_path_len); 4255 } 4256 } 4257 4258 // Remove trailing pathsep (not for \\?\<DRIVE>:\, since it would make it relative) 4259 result_len = wcslen(result); 4260 4261 if (result[result_len - 1] == L'\\') { 4262 if (!(::iswalpha(result[4]) && result[5] == L':' && result_len == 7)) { 4263 result[result_len - 1] = L'\0'; 4264 } 4265 } 4266 } 4267 4268 os::free(unicode_path); 4269 os::free(buf); 4270 4271 if (err != ERROR_SUCCESS) { 4272 os::free(result); 4273 result = NULL; 4274 } 4275 4276 return result; 4277 } 4278 4279 int os::stat(const char *path, struct stat *sbuf) { 4280 errno_t err; 4281 wchar_t* wide_path = wide_abs_unc_path(path, err); 4282 4283 if (wide_path == NULL) { 4284 errno = err; 4285 return -1; 4286 } 4287 4288 WIN32_FILE_ATTRIBUTE_DATA file_data;; |