diff options
Diffstat (limited to 'third_party/protobuf/3.2.0/src/google/protobuf/stubs/io_win32.cc')
-rw-r--r-- | third_party/protobuf/3.2.0/src/google/protobuf/stubs/io_win32.cc | 181 |
1 files changed, 130 insertions, 51 deletions
diff --git a/third_party/protobuf/3.2.0/src/google/protobuf/stubs/io_win32.cc b/third_party/protobuf/3.2.0/src/google/protobuf/stubs/io_win32.cc index bffa450a26..310cb1b0c4 100644 --- a/third_party/protobuf/3.2.0/src/google/protobuf/stubs/io_win32.cc +++ b/third_party/protobuf/3.2.0/src/google/protobuf/stubs/io_win32.cc @@ -30,21 +30,31 @@ // Author: laszlocsomor@google.com (Laszlo Csomor) // -// Implementation for long-path-aware open/mkdir/access on Windows. +// Implementation for long-path-aware open/mkdir/etc. on Windows. // // These functions convert the input path to an absolute Windows path -// with UNC prefix if necessary, then pass that to -// _wopen/_wmkdir/_waccess (declared in <io.h>) respectively. This -// allows working with files/directories whose paths are longer than -// MAX_PATH (260 chars). +// with "\\?\" prefix if necessary, then pass that to _wopen/_wmkdir/etc. +// (declared in <io.h>) respectively. This allows working with files/directories +// whose paths are longer than MAX_PATH (260 chars). // // This file is only used on Windows, it's empty on other platforms. #if defined(_WIN32) +// Comment this out to fall back to using the ANSI versions (open, mkdir, ...) +// instead of the Unicode ones (_wopen, _wmkdir, ...). Doing so can be useful to +// debug failing tests if that's caused by the long path support. +#define SUPPORT_LONGPATHS + #include <ctype.h> +#include <direct.h> #include <errno.h> +#include <fcntl.h> +#include <io.h> +#include <sys/stat.h> +#include <sys/types.h> #include <wctype.h> +#include <windows.h> #include <google/protobuf/stubs/io_win32.h> @@ -84,14 +94,14 @@ bool has_drive_letter(const char_type* ch) { } template <typename char_type> -bool has_unc_prefix(const std::basic_string<char_type>& path) { +bool has_longpath_prefix(const std::basic_string<char_type>& path) { return path.size() > 4 && path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\'; } template <typename char_type> bool is_path_absolute(const std::basic_string<char_type>& path) { - return (path.size() > 2 && path[1] == ':') || has_unc_prefix(path); + return (path.size() > 2 && path[1] == ':') || has_longpath_prefix(path); } template <typename char_type> @@ -104,24 +114,16 @@ bool is_drive_relative(const string& s) { (s.size() == 2 || !is_separator(s[2])); } -void replace_directory_separators(WCHAR* p) { - for (; *p != L'\0'; ++p) { - if (*p == L'/') { - *p = L'\\'; +template <typename char_type> +void replace_directory_separators(char_type* p) { + for (; *p; ++p) { + if (*p == '/') { + *p = '\\'; } } } -wstring get_cwd() { - DWORD result = ::GetCurrentDirectoryW(0, NULL); - std::unique_ptr<WCHAR[]> cwd(new WCHAR[result]); - ::GetCurrentDirectoryW(result, cwd.get()); - cwd.get()[result - 1] = 0; - replace_directory_separators(cwd.get()); - return std::move(wstring(cwd.get())); -} - -wstring join_paths(const wstring& path1, const wstring& path2) { +string join_paths(const string& path1, const string& path2) { if (path1.empty() || is_path_absolute(path2)) { return path2; } @@ -134,12 +136,12 @@ wstring join_paths(const wstring& path1, const wstring& path2) { : (path1 + path2); } else { return is_separator(path2.front()) ? (path1 + path2) - : (path1 + L'\\' + path2); + : (path1 + '\\' + path2); } } string normalize(string path) { - if (has_unc_prefix(path)) { + if (has_longpath_prefix(path)) { path = path.substr(4); } @@ -162,10 +164,11 @@ string normalize(string path) { string segment(path, segment_start, i - segment_start); segment_start = -1; if (segment == dotdot) { - if (!segments.empty() && !has_drive_letter(segments[0].c_str())) { + if (!segments.empty() && + (!has_drive_letter(segments[0].c_str()) || segments.size() > 1)) { segments.pop_back(); } - } else if (segment != dot) { + } else if (segment != dot && !segment.empty()) { segments.push_back(segment); } } @@ -191,22 +194,28 @@ string normalize(string path) { first = false; result << s; } + // Preserve trailing separator if the input contained it. + if (is_separator(path.back())) { + result << '\\'; + } return result.str(); } +std::unique_ptr<WCHAR[]> as_wstring(const string& s) { + int len = ::MultiByteToWideChar(CP_UTF8, 0, s.c_str(), s.size(), NULL, 0); + std::unique_ptr<WCHAR[]> result(new WCHAR[len + 1]); + ::MultiByteToWideChar(CP_UTF8, 0, s.c_str(), s.size(), result.get(), len + 1); + result.get()[len] = 0; + return std::move(result); +} + wstring as_wchar_path(const string& path) { - int len = - ::MultiByteToWideChar(CP_UTF8, 0, path.c_str(), path.size(), NULL, 0); - std::unique_ptr<WCHAR[]> wbuf(new WCHAR[len + 1]); - ::MultiByteToWideChar(CP_UTF8, 0, path.c_str(), path.size(), wbuf.get(), - len + 1); - wbuf.get()[len] = 0; + std::unique_ptr<WCHAR[]> wbuf(as_wstring(path)); replace_directory_separators(wbuf.get()); - return std::move(wstring(wbuf.get())); + return wstring(wbuf.get()); } -bool as_windows_path(const string& path, size_t max_path, - wstring* result) { +bool as_windows_path(const string& path, wstring* result) { if (path.empty()) { result->clear(); return true; @@ -215,11 +224,18 @@ bool as_windows_path(const string& path, size_t max_path, return false; } - *result = as_wchar_path(normalize(path)); - if (!is_path_absolute(path)) { - *result = join_paths(get_cwd(), *result); + string mutable_path = path; + if (!is_path_absolute(mutable_path)) { + char cwd[MAX_PATH]; + ::GetCurrentDirectoryA(MAX_PATH, cwd); + mutable_path = join_paths(cwd, mutable_path); } - if (result->size() >= max_path && !has_unc_prefix(*result)) { + *result = as_wchar_path(normalize(mutable_path)); + if (!has_longpath_prefix(*result)) { + // Add the "\\?\" prefix unconditionally. This way we prevent the Win32 API + // from processing the path and "helpfully" removing trailing dots from the + // path for example. + // See https://github.com/bazelbuild/bazel/issues/2935 *result = wstring(L"\\\\?\\") + *result; } return true; @@ -227,41 +243,104 @@ bool as_windows_path(const string& path, size_t max_path, } // namespace -int win32_open(const char* path, int flags, int mode) { +int open(const char* path, int flags, int mode) { +#ifdef SUPPORT_LONGPATHS wstring wpath; - if (!as_windows_path(path, MAX_PATH, &wpath)) { + if (!as_windows_path(path, &wpath)) { errno = ENOENT; return -1; } return ::_wopen(wpath.c_str(), flags, mode); +#else + return ::_open(path, flags, mode); +#endif } -int win32_mkdir(const char* path, int _mode) { - // CreateDirectoryA's limit is 248 chars, see MSDN. - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx - // This limit presumably includes the null-terminator, because other - // functions that have the MAX_PATH limit, such as CreateFileA, - // actually include it. +int mkdir(const char* path, int _mode) { +#ifdef SUPPORT_LONGPATHS wstring wpath; - if (!as_windows_path(path, 248, &wpath)) { + if (!as_windows_path(path, &wpath)) { errno = ENOENT; return -1; } return ::_wmkdir(wpath.c_str()); +#else // not SUPPORT_LONGPATHS + return ::_mkdir(path); +#endif // not SUPPORT_LONGPATHS } -int win32_access(const char* path, int mode) { +int access(const char* path, int mode) { +#ifdef SUPPORT_LONGPATHS wstring wpath; - if (!as_windows_path(path, MAX_PATH, &wpath)) { + if (!as_windows_path(path, &wpath)) { errno = ENOENT; return -1; } return ::_waccess(wpath.c_str(), mode); +#else + return ::_access(path, mode); +#endif +} + +int chdir(const char* path) { +#ifdef SUPPORT_LONGPATHS + wstring wpath; + if (!as_windows_path(path, &wpath)) { + errno = ENOENT; + return -1; + } + return ::_wchdir(wpath.c_str()); +#else + return ::_chdir(path); +#endif +} + +int stat(const char* path, struct _stat* buffer) { +#ifdef SUPPORT_LONGPATHS + wstring wpath; + if (!as_windows_path(path, &wpath)) { + errno = ENOENT; + return -1; + } + return ::_wstat(wpath.c_str(), buffer); +#else // not SUPPORT_LONGPATHS + return ::_stat(path, buffer); +#endif // not SUPPORT_LONGPATHS +} + +FILE* fopen(const char* path, const char* mode) { +#ifdef SUPPORT_LONGPATHS + wstring wpath; + if (!as_windows_path(path, &wpath)) { + errno = ENOENT; + return NULL; + } + std::unique_ptr<WCHAR[]> wmode(as_wstring(mode)); + return ::_wfopen(wpath.c_str(), wmode.get()); +#else + return ::fopen(path, mode); +#endif +} + +int close(int fd) { return ::close(fd); } + +int dup(int fd) { return ::_dup(fd); } + +int dup2(int fd1, int fd2) { return ::_dup2(fd1, fd2); } + +int read(int fd, void* buffer, size_t size) { + return ::_read(fd, buffer, size); +} + +int setmode(int fd, int mode) { return ::_setmode(fd, mode); } + +int write(int fd, const void* buffer, size_t size) { + return ::_write(fd, buffer, size); } -wstring testonly_path_to_winpath(const string& path, size_t max_path) { +wstring testonly_path_to_winpath(const string& path) { wstring wpath; - as_windows_path(path, max_path, &wpath); + as_windows_path(path, &wpath); return wpath; } |