Skip to content

Commit

Permalink
Windows, protoc: create io_win32.{h,cc}
Browse files Browse the repository at this point in the history
Create dedicated files for the long-path-aware
Windows implementations of open/access/mkdir.

This commit updates many BUT NOT ALL usages of
<io.h> functions in protobuf's code base. Reason
being is that there are no Bazel build rules for
the unittest files that include <io.h>, so I
decided to leave those alone.

Thanks to this commit I can now build Bazel with
MSVC without needing a short --output_user_base.

Fixes #2634
See #2107
See protocolbuffers/protobuf#2891

Change-Id: I374726452300854a36e4628bb22cb7bbb12f3bad
  • Loading branch information
laszlocsomor committed Mar 21, 2017
1 parent ea90356 commit 184f3c8
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 102 deletions.
2 changes: 2 additions & 0 deletions third_party/protobuf/3.0.0/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ cc_library(
"src/google/protobuf/extension_set.cc",
"src/google/protobuf/generated_message_util.cc",
"src/google/protobuf/io/coded_stream.cc",
"src/google/protobuf/io/io_win32.cc",
"src/google/protobuf/io/zero_copy_stream.cc",
"src/google/protobuf/io/zero_copy_stream_impl_lite.cc",
"src/google/protobuf/message_lite.cc",
Expand Down Expand Up @@ -161,6 +162,7 @@ cc_library(
"src/google/protobuf/field_mask.pb.cc",
"src/google/protobuf/generated_message_reflection.cc",
"src/google/protobuf/io/gzip_stream.cc",
"src/google/protobuf/io/io_win32.cc",
"src/google/protobuf/io/printer.cc",
"src/google/protobuf/io/strtod.cc",
"src/google/protobuf/io/tokenizer.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/stubs/platform_macros.h>

#ifdef _MSC_VER
#include <Windows.h>
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
Expand All @@ -56,7 +52,6 @@

#include <limits.h> //For PATH_MAX

#include <string>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
Expand All @@ -79,6 +74,7 @@
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/io_win32.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
Expand All @@ -90,88 +86,6 @@ namespace google {
namespace protobuf {
namespace compiler {

#if defined(_WIN32)

static bool is_path_absolute(const std::string& path) {
return ((path.size() > 2 && path[1] == ':') ||
(path.size() > 4 && path[0] == '\\' && path[1] == '\\' &&
path[2] == '?' && path[3] == '\\'));
}

static std::wstring as_windows_path(const std::string& path) {
// Convert `path` to WCHAR string.
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;

// Replace all '/' with '\'.
for (WCHAR* p = wbuf.get(); *p != L'\0'; ++p) {
if (*p == L'/') {
*p = L'\\';
}
}

// Create a wstring of the WCHAR buffer.
std::wstring wpath(wbuf.get());

// Make the path absolute.
if (!is_path_absolute(path)) {
// Get the current working directory.
DWORD result = ::GetCurrentDirectoryW(0, NULL);
std::unique_ptr<WCHAR[]> cwd(new WCHAR[result]);
::GetCurrentDirectoryW(result, cwd.get());
cwd.get()[result - 1] = 0;
std::wstring wcwd(cwd.get());
// Make the path absolute by appending it to the cwd.
wpath = wcwd.back() == L'\\' ? (wcwd + wpath) : (wcwd + L'\\' + wpath);
}

// Prepend UNC prefix if necessary.
if (wpath.size() >= MAX_PATH) {
wpath = std::wstring(L"\\\\?\\") + wpath;
}

return wpath;
}

#ifdef open
#undef open
#endif
static int open(const char* path, int flags, int mode) {
return _wopen(as_windows_path(path).c_str(), flags, mode);
}

#ifdef mkdir
#undef mkdir
#endif
static int mkdir(const char* name, int _mode) {
return _wmkdir(as_windows_path(name).c_str());
}

#ifdef access
#undef access
#endif
static int access(const char* pathname, int mode) {
return _waccess(as_windows_path(pathname).c_str(), mode);
}

#ifndef W_OK
#define W_OK 02 // not defined by MSVC for whatever reason
#endif
#ifndef F_OK
#define F_OK 00 // not defined by MSVC for whatever reason
#endif
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#endif // defined(_WIN32)

#ifndef O_BINARY
#ifdef _O_BINARY
#define O_BINARY _O_BINARY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.

#ifdef _MSC_VER
#include <io.h>
#else
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <sys/types.h>
Expand All @@ -51,6 +49,7 @@
#include <google/protobuf/compiler/importer.h>

#include <google/protobuf/compiler/parser.h>
#include <google/protobuf/io/io_win32.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/strutil.h>
Expand All @@ -60,9 +59,6 @@ namespace protobuf {
namespace compiler {

#ifdef _WIN32
#ifndef F_OK
#define F_OK 00 // not defined by MSVC for whatever reason
#endif
#include <ctype.h>
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifdef _MSC_VER
#include <io.h>
#else
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <climits>
Expand All @@ -46,6 +44,7 @@
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/io_win32.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#else
#include <unistd.h>
#endif
Expand All @@ -53,6 +47,7 @@
#include <google/protobuf/compiler/plugin.pb.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/io_win32.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>


Expand Down
159 changes: 159 additions & 0 deletions third_party/protobuf/3.0.0/src/google/protobuf/io/io_win32.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: laszlocsomor@google.com (Laszlo Csomor)
//
// Implementation for long-path-aware open/mkdir/access 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 is longer than
// MAX_PATH (260 chars).
//
// This file is only used on Windows, it's empty on other platforms.

#if defined(_WIN32)

#include <Windows.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <io.h>

#include <string>
#include <memory>

#include <google/protobuf/io/io_win32.h>

namespace google {
namespace protobuf {
namespace io {
namespace win32 {

template <typename char_type>
static bool has_unc_prefix(const std::basic_string<char_type>& path) {
return path.size() > 4 && path[0] == '\\' && path[1] == '\\' &&
path[2] == '?' && path[3] == '\\';
}

template <typename char_type>
static bool is_path_absolute(const std::basic_string<char_type>& path) {
return (path.size() > 2 && path[1] == ':') || has_unc_prefix(path);
}

template <typename char_type>
static bool is_separator(char_type c) {
return c == '/' || c == '\\';
}

static void replace_directory_separators(WCHAR* p) {
for (; *p != L'\0'; ++p) {
if (*p == L'/') {
*p = L'\\';
}
}
}

static std::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(std::wstring(cwd.get()));
}

static std::wstring join_paths(const std::wstring& path1,
const std::wstring& path2) {
if (path1.empty() || is_path_absolute(path2)) {
return path2;
}
if (path2.empty()) {
return path1;
}

if (is_separator(path1.back())) {
return is_separator(path2.front())
? (path1 + path2.substr(1))
: (path1 + path2);
} else {
return is_separator(path2.front())
? (path1 + path2)
: (path1 + L'\\' + path2);
}
}

static std::wstring as_wchar_path(const std::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;
replace_directory_separators(wbuf.get());
return std::move(std::wstring(wbuf.get()));
}

static std::wstring as_windows_path(const std::string& path,
size_t max_path) {
std::wstring wpath(as_wchar_path(path));
if (!is_path_absolute(path)) {
wpath = join_paths(get_cwd(), wpath);
}
if (wpath.size() >= max_path && !has_unc_prefix(wpath)) {
wpath = std::wstring(L"\\\\?\\") + wpath;
}
return wpath;
}

int open(const char* path, int flags, int mode) {
return ::_wopen(as_windows_path(path, MAX_PATH).c_str(), flags, mode);
}

int mkdir(const char* name, 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.
return ::_wmkdir(as_windows_path(name, 248).c_str());
}

int access(const char* pathname, int mode) {
return ::_waccess(as_windows_path(pathname, MAX_PATH).c_str(), mode);
}

} // namespace win32
} // namespace io
} // namespace protobuf
} // namespace google

#endif // defined(_WIN32)
Loading

0 comments on commit 184f3c8

Please sign in to comment.