From f257130b7701c37585d8015f27e1d75131b37166 Mon Sep 17 00:00:00 2001 From: Laszlo Csomor Date: Thu, 12 Jan 2017 13:09:35 +0000 Subject: Bazel client, Windows: implement MakeDirectories See https://github.com/bazelbuild/bazel/issues/2107 See https://github.com/bazelbuild/bazel/issues/1744 -- PiperOrigin-RevId: 144313301 MOS_MIGRATED_REVID=144313301 --- src/main/cpp/util/file_posix.cc | 12 ++++----- src/main/cpp/util/file_windows.cc | 54 ++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 13 deletions(-) (limited to 'src/main/cpp/util') diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc index 02c0fa8055..55d62a2211 100644 --- a/src/main/cpp/util/file_posix.cc +++ b/src/main/cpp/util/file_posix.cc @@ -34,6 +34,11 @@ namespace blaze_util { using std::pair; using std::string; +// TODO(bazel-team): implement all functions in file_windows.cc, use them from +// MSYS, remove file_posix.cc from the `srcs` of +// //src/main/cpp/util:file when building for MSYS, and remove all +// #ifndef __CYGWIN__ directives. +#ifndef __CYGWIN__ // Runs "stat" on `path`. Returns -1 and sets errno if stat fails or // `path` isn't a directory. If check_perms is true, this will also // make sure that `path` is owned by the current user and has `mode` @@ -119,11 +124,6 @@ static bool MakeDirectories(const string &path, mode_t mode, bool childmost) { return stat_succeeded; } -// TODO(bazel-team): implement all functions in file_windows.cc, use them from -// MSYS, remove file_posix.cc from the `srcs` of -// //src/main/cpp/util:file when building for MSYS, and remove all -// #ifndef __CYGWIN__ directives. -#ifndef __CYGWIN__ class PosixPipe : public IPipe { public: PosixPipe(int recv_socket, int send_socket) @@ -295,6 +295,7 @@ bool SetMtimeMillisec(const string& path, time_t mtime) { return utime(path.c_str(), ×) == 0; } +#ifndef __CYGWIN__ // mkdir -p path. Returns true if the path was created or already exists and // could // be chmod-ed to exactly the given permissions. If final part of the path is a @@ -305,7 +306,6 @@ bool MakeDirectories(const string &path, unsigned int mode) { return MakeDirectories(path, mode, true); } -#ifndef __CYGWIN__ string GetCwd() { char cwdbuf[PATH_MAX]; if (getcwd(cwdbuf, sizeof cwdbuf) == NULL) { diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc index d213b64179..3b2553ad1b 100644 --- a/src/main/cpp/util/file_windows.cc +++ b/src/main/cpp/util/file_windows.cc @@ -28,6 +28,7 @@ namespace blaze_util { +using std::basic_string; using std::pair; using std::string; using std::unique_ptr; @@ -54,6 +55,10 @@ static bool UnlinkPathW(const wstring& path); // Like `AsWindowsPath` but the result is absolute and has UNC prefix if needed. static bool AsWindowsPathWithUncPrefix(const string& path, wstring* wpath); +static bool IsRootDirectoryW(const wstring& path); + +static bool MakeDirectoriesW(const wstring& path); + // Returns a normalized form of the input `path`. // // `path` must be a relative or absolute Windows path, it may use "/" instead of @@ -161,7 +166,9 @@ IPipe* CreatePipe() { // If `must_be_root` is true, then in addition to being absolute, the path must // also be just the root part, no other components, e.g. "c:\" is both absolute // and root, but "c:\foo" is just absolute. -static bool IsRootOrAbsolute(const string& path, bool must_be_root) { +template +static bool IsRootOrAbsolute(const basic_string& path, + bool must_be_root) { // An absolute path is one that starts with "/", "\", "c:/", "c:\", // "\\?\c:\", or rarely "\??\c:\" or "\\.\c:\". // @@ -693,14 +700,47 @@ bool SetMtimeMillisec(const string& path, time_t mtime) { #else // not COMPILER_MSVC #endif // COMPILER_MSVC -#ifdef COMPILER_MSVC +static bool IsRootDirectoryW(const wstring& path) { + return IsRootOrAbsolute(path, true); +} + +static bool MakeDirectoriesW(const wstring& path) { + if (path.empty()) { + return false; + } + if (IsRootDirectoryW(path) || IsDirectoryW(path)) { + return true; + } + int last_separator = path.rfind(L"\\"); + if (last_separator < 0) { + // Since `path` is not a root directory, there must be at least one + // directory above it. + pdie(255, "MakeDirectoriesW(%S), could not find dirname", path.c_str()); + } + wstring parent = path.substr(0, last_separator); + if (!MakeDirectoriesW(parent)) { + return false; + } + if (!::CreateDirectoryW(path.c_str(), nullptr)) { + PrintError("MakeDirectoriesW(%S), CreateDirectoryW failed, err=%d", + path.c_str(), GetLastError()); + return false; + } + return true; +} + bool MakeDirectories(const string& path, unsigned int mode) { - // TODO(bazel-team): implement this. - pdie(255, "blaze::MakeDirectories is not implemented on Windows"); - return false; + // TODO(laszlocsomor): respect `mode` to the extent that it's possible on + // Windows; it's currently ignored. + if (path.empty() || IsDevNull(path) || IsRootDirectory(path)) { + return false; + } + wstring wpath; + if (!AsWindowsPathWithUncPrefix(path, &wpath)) { + return false; + } + return MakeDirectoriesW(wpath); } -#else // not COMPILER_MSVC -#endif // COMPILER_MSVC static unique_ptr GetCwdW() { DWORD len = ::GetCurrentDirectoryW(0, nullptr); -- cgit v1.2.3