You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by jo...@apache.org on 2016/01/16 22:10:02 UTC

[1/3] mesos git commit: Moved filesystems tests to their own file.

Repository: mesos
Updated Branches:
  refs/heads/master 1b56d99bf -> a465c45cd


Moved filesystems tests to their own file.

Review: https://reviews.apache.org/r/39805/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a465c45c
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a465c45c
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a465c45c

Branch: refs/heads/master
Commit: a465c45cd12d1d0b1e9aaba1d7702e773ff23fc0
Parents: a4aa314
Author: Alex Clemmer <cl...@gmail.com>
Authored: Sat Jan 16 15:44:37 2016 -0500
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Sat Jan 16 16:09:51 2016 -0500

----------------------------------------------------------------------
 3rdparty/libprocess/3rdparty/stout/Makefile.am  |   1 +
 .../stout/include/stout/tests/utils.hpp         |   6 +-
 .../3rdparty/stout/tests/CMakeLists.txt         |   1 +
 .../stout/tests/os/filesystem_tests.cpp         | 142 +++++++++++++++++++
 .../3rdparty/stout/tests/path_tests.cpp         |   3 +
 5 files changed, 152 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a465c45c/3rdparty/libprocess/3rdparty/stout/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/Makefile.am b/3rdparty/libprocess/3rdparty/stout/Makefile.am
index 206489c..0bddd00 100644
--- a/3rdparty/libprocess/3rdparty/stout/Makefile.am
+++ b/3rdparty/libprocess/3rdparty/stout/Makefile.am
@@ -44,6 +44,7 @@ EXTRA_DIST =					\
   tests/numify_tests.cpp			\
   tests/option_tests.cpp			\
   tests/os_tests.cpp				\
+  tests/os/filesystem_tests.cpp			\
   tests/os/sendfile_tests.cpp			\
   tests/os/signals_tests.cpp			\
   tests/os/strerror_tests.cpp			\

http://git-wip-us.apache.org/repos/asf/mesos/blob/a465c45c/3rdparty/libprocess/3rdparty/stout/include/stout/tests/utils.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/tests/utils.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/tests/utils.hpp
index 3cff837..4e5359c 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/tests/utils.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/tests/utils.hpp
@@ -18,9 +18,13 @@
 #include <gtest/gtest.h>
 
 #include <stout/gtest.hpp>
-#include <stout/os.hpp>
 #include <stout/try.hpp>
 
+#include <stout/os/chdir.hpp>
+#include <stout/os/getcwd.hpp>
+#include <stout/os/mkdtemp.hpp>
+#include <stout/os/rmdir.hpp>
+
 class TemporaryDirectoryTest : public ::testing::Test
 {
 protected:

http://git-wip-us.apache.org/repos/asf/mesos/blob/a465c45c/3rdparty/libprocess/3rdparty/stout/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/CMakeLists.txt b/3rdparty/libprocess/3rdparty/stout/tests/CMakeLists.txt
index ebf9795..3c65d04 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/CMakeLists.txt
+++ b/3rdparty/libprocess/3rdparty/stout/tests/CMakeLists.txt
@@ -36,6 +36,7 @@ set(STOUT_TESTS_SRC
   none_tests.cpp
   numify_tests.cpp
   option_tests.cpp
+  os/filesystem_tests.cpp
   protobuf_tests.pb.h
   protobuf_tests.proto
   result_tests.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/a465c45c/3rdparty/libprocess/3rdparty/stout/tests/os/filesystem_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/os/filesystem_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/os/filesystem_tests.cpp
new file mode 100644
index 0000000..c5ffd01
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/tests/os/filesystem_tests.cpp
@@ -0,0 +1,142 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+
+#include <stout/foreach.hpp>
+#include <stout/hashset.hpp>
+#include <stout/path.hpp>
+#include <stout/try.hpp>
+#include <stout/uuid.hpp>
+
+#include <stout/os/find.hpp>
+#include <stout/os/getcwd.hpp>
+#include <stout/os/ls.hpp>
+#include <stout/os/mkdir.hpp>
+#include <stout/os/read.hpp>
+#include <stout/os/touch.hpp>
+#include <stout/os/write.hpp>
+
+#include <stout/tests/utils.hpp>
+
+using std::list;
+using std::set;
+using std::string;
+
+
+static hashset<string> listfiles(const string& directory)
+{
+  hashset<string> fileset;
+  Try<std::list<std::string>> entries = os::ls(directory);
+  if (entries.isSome()) {
+    foreach (const string& entry, entries.get()) {
+      fileset.insert(entry);
+    }
+  }
+  return fileset;
+}
+
+
+class FsTest : public TemporaryDirectoryTest {};
+
+
+TEST_F(FsTest, Find)
+{
+  const string testdir = path::join(os::getcwd(), UUID::random().toString());
+  const string subdir = testdir + "/test1";
+  ASSERT_SOME(os::mkdir(subdir)); // Create the directories.
+
+  // Now write some files.
+  const string file1 = testdir + "/file1.txt";
+  const string file2 = subdir + "/file2.txt";
+  const string file3 = subdir + "/file3.jpg";
+
+  ASSERT_SOME(os::touch(file1));
+  ASSERT_SOME(os::touch(file2));
+  ASSERT_SOME(os::touch(file3));
+
+  // Find "*.txt" files.
+  Try<std::list<string>> result = os::find(testdir, ".txt");
+  ASSERT_SOME(result);
+
+  hashset<string> files;
+  foreach (const string& file, result.get()) {
+    files.insert(file);
+  }
+
+  ASSERT_EQ(2u, files.size());
+  ASSERT_TRUE(files.contains(file1));
+  ASSERT_TRUE(files.contains(file2));
+}
+
+
+TEST_F(FsTest, ReadWriteString)
+{
+  const string testfile  = path::join(os::getcwd(), UUID::random().toString());
+  const string teststr = "line1\nline2";
+
+  ASSERT_SOME(os::write(testfile, teststr));
+
+  Try<string> readstr = os::read(testfile);
+
+  EXPECT_SOME_EQ(teststr, readstr);
+}
+
+
+TEST_F(FsTest, Rmdir)
+{
+  const hashset<string> EMPTY;
+  const string tmpdir = os::getcwd();
+
+  hashset<string> expectedListing = EMPTY;
+  EXPECT_EQ(expectedListing, listfiles(tmpdir));
+
+  os::mkdir(tmpdir + "/a/b/c");
+  os::mkdir(tmpdir + "/a/b/d");
+  os::mkdir(tmpdir + "/e/f");
+
+  expectedListing = EMPTY;
+  expectedListing.insert("a");
+  expectedListing.insert("e");
+  EXPECT_EQ(expectedListing, listfiles(tmpdir));
+
+  expectedListing = EMPTY;
+  expectedListing.insert("b");
+  EXPECT_EQ(expectedListing, listfiles(tmpdir + "/a"));
+
+  expectedListing = EMPTY;
+  expectedListing.insert("c");
+  expectedListing.insert("d");
+  EXPECT_EQ(expectedListing, listfiles(tmpdir + "/a/b"));
+
+  expectedListing = EMPTY;
+  EXPECT_EQ(expectedListing, listfiles(tmpdir + "/a/b/c"));
+  EXPECT_EQ(expectedListing, listfiles(tmpdir + "/a/b/d"));
+
+  expectedListing.insert("f");
+  EXPECT_EQ(expectedListing, listfiles(tmpdir + "/e"));
+
+  expectedListing = EMPTY;
+  EXPECT_EQ(expectedListing, listfiles(tmpdir + "/e/f"));
+}
+
+
+TEST_F(FsTest, Touch)
+{
+  const string testfile  = path::join(os::getcwd(), UUID::random().toString());
+
+  ASSERT_SOME(os::touch(testfile));
+  ASSERT_TRUE(os::exists(testfile));
+}

http://git-wip-us.apache.org/repos/asf/mesos/blob/a465c45c/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
index 79cda84..4568d20 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
@@ -17,6 +17,9 @@
 
 #include <stout/path.hpp>
 
+#include <stout/os/rm.hpp>
+#include <stout/os/touch.hpp>
+
 #include <stout/tests/utils.hpp>
 
 using std::string;


[2/3] mesos git commit: Windows: Implemented `os::rmdir.hpp`.

Posted by jo...@apache.org.
Windows: Implemented `os::rmdir.hpp`.

Review: https://reviews.apache.org/r/39584/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a4aa3145
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a4aa3145
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a4aa3145

Branch: refs/heads/master
Commit: a4aa31451e8db580db768ca7ca20b58ac2c1bdf9
Parents: e6db388
Author: Alex Clemmer <cl...@gmail.com>
Authored: Sat Jan 16 15:29:49 2016 -0500
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Sat Jan 16 16:09:51 2016 -0500

----------------------------------------------------------------------
 .../3rdparty/stout/include/Makefile.am          |   3 +
 .../3rdparty/stout/include/stout/os.hpp         |   1 +
 .../stout/include/stout/os/posix/rmdir.hpp      |  86 ++++++++++++
 .../3rdparty/stout/include/stout/os/rmdir.hpp   |  26 ++++
 .../stout/include/stout/os/windows/rmdir.hpp    | 137 +++++++++++++++++++
 .../3rdparty/stout/include/stout/posix/os.hpp   |  57 --------
 .../3rdparty/stout/include/stout/windows/os.hpp |   9 --
 7 files changed, 253 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/Makefile.am b/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
index 06aa662..0459cb8 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
+++ b/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
@@ -84,6 +84,7 @@ nobase_include_HEADERS =		\
   stout/os/realpath.hpp			\
   stout/os/rename.hpp			\
   stout/os/rm.hpp			\
+  stout/os/rmdir.hpp			\
   stout/os/sendfile.hpp			\
   stout/os/shell.hpp			\
   stout/os/signals.hpp			\
@@ -102,6 +103,7 @@ nobase_include_HEADERS =		\
   stout/os/posix/killtree.hpp		\
   stout/os/posix/mkdtemp.hpp		\
   stout/os/posix/pstree.hpp		\
+  stout/os/posix/rmdir.hpp		\
   stout/os/posix/sendfile.hpp		\
   stout/os/posix/shell.hpp		\
   stout/os/posix/signals.hpp		\
@@ -116,6 +118,7 @@ nobase_include_HEADERS =		\
   stout/os/windows/killtree.hpp		\
   stout/os/windows/mkdtemp.hpp		\
   stout/os/windows/pstree.hpp		\
+  stout/os/windows/rmdir.hpp		\
   stout/os/windows/sendfile.hpp		\
   stout/os/windows/shell.hpp		\
   stout/os/windows/signals.hpp		\

http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/stout/os.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os.hpp
index 486a632..ed3bb2c 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/os.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os.hpp
@@ -90,6 +90,7 @@
 #include <stout/os/realpath.hpp>
 #include <stout/os/rename.hpp>
 #include <stout/os/rm.hpp>
+#include <stout/os/rmdir.hpp>
 #include <stout/os/sendfile.hpp>
 #include <stout/os/shell.hpp>
 #include <stout/os/signals.hpp>

http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/rmdir.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/rmdir.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/rmdir.hpp
new file mode 100644
index 0000000..bc420c9
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/rmdir.hpp
@@ -0,0 +1,86 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_RMDIR_HPP__
+#define __STOUT_OS_POSIX_RMDIR_HPP__
+
+#include <fts.h>
+#include <unistd.h>
+#include <string>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+
+namespace os {
+
+// By default, recursively deletes a directory akin to: 'rm -r'. If the
+// programmer sets recursive to false, it deletes a directory akin to: 'rmdir'.
+// Note that this function expects an absolute path.
+#ifndef __sun // FTS is not available on Solaris.
+inline Try<Nothing> rmdir(const std::string& directory, bool recursive = true)
+{
+  if (!recursive) {
+    if (::rmdir(directory.c_str()) < 0) {
+      return ErrnoError();
+    }
+  } else {
+    char* paths[] = {const_cast<char*>(directory.c_str()), NULL};
+
+    FTS* tree = fts_open(paths, FTS_NOCHDIR, NULL);
+    if (tree == NULL) {
+      return ErrnoError();
+    }
+
+    FTSENT* node;
+    while ((node = fts_read(tree)) != NULL) {
+      switch (node->fts_info) {
+        case FTS_DP:
+          if (::rmdir(node->fts_path) < 0 && errno != ENOENT) {
+            Error error = ErrnoError();
+            fts_close(tree);
+            return error;
+          }
+          break;
+        case FTS_F:
+        case FTS_SL:
+          if (::unlink(node->fts_path) < 0 && errno != ENOENT) {
+            Error error = ErrnoError();
+            fts_close(tree);
+            return error;
+          }
+          break;
+        default:
+          break;
+      }
+    }
+
+    if (errno != 0) {
+      Error error = ErrnoError();
+      fts_close(tree);
+      return error;
+    }
+
+    if (fts_close(tree) < 0) {
+      return ErrnoError();
+    }
+  }
+
+  return Nothing();
+}
+#endif // __sun
+
+} // namespace os {
+
+
+#endif // __STOUT_OS_POSIX_RMDIR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/stout/os/rmdir.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/rmdir.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/rmdir.hpp
new file mode 100644
index 0000000..9f662fc
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/rmdir.hpp
@@ -0,0 +1,26 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_RMDIR_HPP__
+#define __STOUT_OS_RMDIR_HPP__
+
+
+// For readability, we minimize the number of #ifdef blocks in the code by
+// splitting platform specifc system calls into separate directories.
+#ifdef __WINDOWS__
+#include <stout/os/windows/rmdir.hpp>
+#else
+#include <stout/os/posix/rmdir.hpp>
+#endif // __WINDOWS__
+
+
+#endif // __STOUT_OS_RMDIR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/rmdir.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/rmdir.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/rmdir.hpp
new file mode 100644
index 0000000..6decdc5
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/rmdir.hpp
@@ -0,0 +1,137 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_WINDOWS_RMDIR_HPP__
+#define __STOUT_OS_WINDOWS_RMDIR_HPP__
+
+#include <stout/nothing.hpp>
+#include <stout/strings.hpp>
+#include <stout/try.hpp>
+#include <stout/windows.hpp>
+
+#include <stout/os/realpath.hpp>
+#include <stout/os/stat.hpp>
+
+#include <stout/windows/error.hpp>
+
+
+namespace os {
+namespace internal {
+
+// Recursive version of `RemoveDirectory`. NOTE: unlike `rmdir`, this requires
+// Windows-formatted paths, and therefore should be in the `internal` namespace.
+Try<Nothing> recursive_remove_directory(const std::string& path)
+{
+  // Appending a slash here if the path doesn't already have one simplifies
+  // path join logic later, because (unlike Unix) Windows doesn't like double
+  // slashes in paths.
+  std::string current_path;
+
+  if (!strings::endsWith(path, "\\")) {
+    current_path = path + "\\";
+  } else {
+    current_path = path;
+  }
+
+  // Get first file matching pattern `X:\path\to\wherever\*`.
+  WIN32_FIND_DATA found;
+  const std::string search_pattern = current_path + "*";
+  const SharedHandle search_handle(
+      FindFirstFile(search_pattern.c_str(), &found),
+      FindClose);
+
+  if (search_handle.get() == INVALID_HANDLE_VALUE) {
+    return WindowsError(
+        "`os::internal::recursive_remove_directory` failed when searching "
+        "for files with pattern '" + search_pattern + "'");
+  }
+
+  do {
+    // NOTE: do-while is appropriate here because folder is guaranteed to have
+    // at least a file called `.` (and probably also one called `..`).
+    const std::string current_file(found.cFileName);
+
+    const bool is_current_directory = current_file.compare(".") == 0;
+    const bool is_parent_directory = current_file.compare("..") == 0;
+
+    // Don't try to delete `.` and `..` files in directory.
+    if (is_current_directory || is_parent_directory) {
+      continue;
+    }
+
+    // Path to remove.
+    const std::string current_absolute_path = current_path + current_file;
+
+    const bool is_directory = os::stat::isdir(current_absolute_path);
+
+    // Delete current path, whether it's a directory, file, or symlink.
+    if (is_directory) {
+      Try<Nothing> removed = recursive_remove_directory(current_absolute_path);
+
+      if (removed.isError()) {
+        return Error(removed.error());
+      }
+    } else {
+      // NOTE: this also handles symbolic links.
+      if (::remove(current_absolute_path.c_str()) != 0) {
+        return WindowsError(
+            "`os::internal::recursive_remove_directory` attempted to delete "
+            "file '" + current_absolute_path + "', but failed");
+      }
+    }
+  } while (FindNextFile(search_handle.get(), &found));
+
+  // Finally, remove current directory.
+  if (::_rmdir(current_path.c_str()) == -1) {
+    return ErrnoError(
+        "`os::internal::recursive_remove_directory` attempted to delete file " +
+        "'" + current_path + "', but failed");
+  }
+
+  return Nothing();
+}
+
+} // namespace internal {
+
+
+// By default, recursively deletes a directory akin to: 'rm -r'. If the
+// programmer sets recursive to false, it deletes a directory akin to: 'rmdir'.
+// Note that this function expects an absolute path.
+inline Try<Nothing> rmdir(const std::string& directory, bool recursive = true)
+{
+  // Canonicalize the path to Windows style for the call to
+  // `recursive_remove_directory`.
+  Result<std::string> root = os::realpath(directory);
+
+  if (root.isError()) {
+    return Error(root.error());
+  } else if (root.isNone()) {
+    return Error(
+        "Argument to `os::rmdir` is not a valid directory or file: '" +
+        directory + "'");
+  }
+
+  if (!recursive) {
+    if (::_rmdir(directory.c_str()) < 0) {
+      return ErrnoError();
+    } else {
+      return Nothing();
+    }
+  } else {
+    return os::internal::recursive_remove_directory(root.get());
+  }
+}
+
+} // namespace os {
+
+
+#endif // __STOUT_OS_WINDOWS_RMDIR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/stout/posix/os.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/posix/os.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/posix/os.hpp
index 4cf693f..c2b9e3d 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/posix/os.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/posix/os.hpp
@@ -109,63 +109,6 @@ inline void unsetenv(const std::string& key)
 }
 
 
-// By default, recursively deletes a directory akin to: 'rm -r'. If the
-// programmer sets recursive to false, it deletes a directory akin to: 'rmdir'.
-// Note that this function expects an absolute path.
-#ifndef __sun // FTS is not available on Solaris.
-inline Try<Nothing> rmdir(const std::string& directory, bool recursive = true)
-{
-  if (!recursive) {
-    if (::rmdir(directory.c_str()) < 0) {
-      return ErrnoError();
-    }
-  } else {
-    char* paths[] = {const_cast<char*>(directory.c_str()), NULL};
-
-    FTS* tree = fts_open(paths, FTS_NOCHDIR, NULL);
-    if (tree == NULL) {
-      return ErrnoError();
-    }
-
-    FTSENT* node;
-    while ((node = fts_read(tree)) != NULL) {
-      switch (node->fts_info) {
-        case FTS_DP:
-          if (::rmdir(node->fts_path) < 0 && errno != ENOENT) {
-            Error error = ErrnoError();
-            fts_close(tree);
-            return error;
-          }
-          break;
-        case FTS_F:
-        case FTS_SL:
-          if (::unlink(node->fts_path) < 0 && errno != ENOENT) {
-            Error error = ErrnoError();
-            fts_close(tree);
-            return error;
-          }
-          break;
-        default:
-          break;
-      }
-    }
-
-    if (errno != 0) {
-      Error error = ErrnoError();
-      fts_close(tree);
-      return error;
-    }
-
-    if (fts_close(tree) < 0) {
-      return ErrnoError();
-    }
-  }
-
-  return Nothing();
-}
-#endif // __sun
-
-
 // Executes a command by calling "/bin/sh -c <command>", and returns
 // after the command has been completed. Returns 0 if succeeds, and
 // return -1 on error (e.g., fork/exec/waitpid failed). This function

http://git-wip-us.apache.org/repos/asf/mesos/blob/a4aa3145/3rdparty/libprocess/3rdparty/stout/include/stout/windows/os.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/windows/os.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/windows/os.hpp
index e738cdb..c224e9e 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/windows/os.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/windows/os.hpp
@@ -55,15 +55,6 @@ inline void unsetenv(const std::string& key)
 }
 
 
-// By default, recursively deletes a directory akin to: 'rm -r'. If the
-// programmer sets recursive to false, it deletes a directory akin to: 'rmdir'.
-// Note that this function expects an absolute path.
-inline Try<Nothing> rmdir(const std::string& directory, bool recursive = true)
-{
-  UNIMPLEMENTED;
-}
-
-
 // Executes a command by calling "/bin/sh -c <command>", and returns
 // after the command has been completed. Returns 0 if succeeds, and
 // return -1 on error (e.g., fork/exec/waitpid failed). This function


[3/3] mesos git commit: Windows: Implemented stout/os/stat.hpp`.

Posted by jo...@apache.org.
Windows: Implemented stout/os/stat.hpp`.

Review: https://reviews.apache.org/r/39803/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e6db3880
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e6db3880
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e6db3880

Branch: refs/heads/master
Commit: e6db3880b6ddf6b2cae6786eb206fcc0cf8ac7c6
Parents: 1b56d99
Author: Alex Clemmer <cl...@gmail.com>
Authored: Sat Jan 16 15:13:32 2016 -0500
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Sat Jan 16 16:09:51 2016 -0500

----------------------------------------------------------------------
 .../3rdparty/stout/include/Makefile.am          |   2 +
 .../stout/internal/windows/reparsepoint.hpp     | 250 +++++++++++++++++++
 .../include/stout/internal/windows/symlink.hpp  |  87 +++++++
 .../stout/include/stout/os/posix/stat.hpp       |  12 +-
 .../stout/include/stout/os/windows/stat.hpp     | 103 +++++++-
 .../3rdparty/stout/include/stout/windows.hpp    |  77 +++++-
 6 files changed, 507 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/e6db3880/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/Makefile.am b/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
index e6d5b42..06aa662 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
+++ b/3rdparty/libprocess/3rdparty/stout/include/Makefile.am
@@ -39,6 +39,8 @@ nobase_include_HEADERS =		\
   stout/internal/windows/dirent.hpp	\
   stout/internal/windows/grp.hpp	\
   stout/internal/windows/pwd.hpp	\
+  stout/internal/windows/symlink.hpp	\
+  stout/internal/windows/reparsepoint.hpp	\
   stout/interval.hpp			\
   stout/ip.hpp				\
   stout/json.hpp			\

http://git-wip-us.apache.org/repos/asf/mesos/blob/e6db3880/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
new file mode 100644
index 0000000..36b0068
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
@@ -0,0 +1,250 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_INTERNAL_WINDOWS_REPARSEPOINT_HPP__
+#define __STOUT_INTERNAL_WINDOWS_REPARSEPOINT_HPP__
+
+#include <string>
+
+#include <stout/try.hpp>
+#include <stout/windows.hpp>
+
+
+namespace internal {
+namespace windows {
+
+// We pass this struct to `DeviceIoControl` to get information about a reparse
+// point (including things like whether it's a symlink). It is normally part of
+// the Device Driver Kit (DDK), specifically `nitfs.h`, but rather than taking
+// a dependency on the DDK, we choose to simply copy the struct here. This is a
+// well-worn path used by Boost FS[1], among others. See documentation
+// here[2].
+//
+// [1] http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/src/operations.cpp
+// [2] https://msdn.microsoft.com/en-us/library/cc232007.aspx
+typedef struct _REPARSE_DATA_BUFFER
+{
+  // Describes, among other things, which type of reparse point this is (e.g.,
+  // a symlink).
+  ULONG  ReparseTag;
+  // Size in bytes of common portion of the `REPARSE_DATA_BUFFER`.
+  USHORT  ReparseDataLength;
+  // Unused. Ignore.
+  USHORT  Reserved;
+  union
+  {
+    // Holds symlink data.
+    struct
+    {
+      // Byte offset in `PathBuffer` where the substitute name begins.
+      // Calculated as an offset from 0.
+      USHORT SubstituteNameOffset;
+      // Length in bytes of the substitute name.
+      USHORT SubstituteNameLength;
+      // Byte offset in `PathBuffer` where the print name begins. Calculated as
+      // an offset from 0.
+      USHORT PrintNameOffset;
+      // Length in bytes of the print name.
+      USHORT PrintNameLength;
+      // Indicates whether symlink is absolute or relative. If flags containing
+      // `SYMLINK_FLAG_RELATIVE`, then the substitute name is a relative
+      // symlink.
+      ULONG Flags;
+      // The first byte of the path string -- according to the documentation[1],
+      // this is followed in memory by the rest of the path string. The "path
+      // string" itself is a unicode char array containing both substitute name
+      // and print name. They can occur in any order. Use the offset and length
+      // of each in this struct to calculate where each starts and ends.
+      //
+      // [1] https://msdn.microsoft.com/en-us/library/windows/hardware/ff552012(v=vs.85).aspx
+      WCHAR PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+
+    // Unused: holds mount point data.
+    struct
+    {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      WCHAR PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct
+    {
+      UCHAR DataBuffer[1];
+    } GenericReparseBuffer;
+  };
+} REPARSE_DATA_BUFFER;
+
+#define REPARSE_MOUNTPOINT_HEADER_SIZE 8
+
+
+// Convenience struct for holding symlink data, meant purely for internal use.
+// We pass this around instead of the extremely inelegant `REPARSE_DATA_BUFFER`
+// struct, simply because this struct is easier to deal with and reason about.
+struct SymbolicLink
+{
+  std::wstring substitute_name;
+  std::wstring print_name;
+  ULONG flags;
+};
+
+
+// Checks file/folder attributes for a path to see if the reparse point
+// attribute is set; this indicates whether the path points at a reparse point,
+// rather than a "normal" file or folder.
+inline Try<bool> reparse_point_attribute_set(const std::string& absolute_path)
+{
+  const DWORD attributes = GetFileAttributes(absolute_path.c_str());
+  if (attributes == INVALID_FILE_ATTRIBUTES) {
+    return WindowsError(
+        "Failed to get attributes for file '" + absolute_path + "'");
+  }
+
+  return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+}
+
+
+// Attempts to extract symlink data out of a `REPARSE_DATA_BUFFER` (which could
+// hold other things, e.g., mount point data).
+inline Try<SymbolicLink> build_symbolic_link(const REPARSE_DATA_BUFFER& data)
+{
+  const bool is_symLink = (data.ReparseTag & IO_REPARSE_TAG_SYMLINK) != 0;
+  if (!is_symLink) {
+    return Error("Data buffer is not a symlink");
+  }
+
+  // NOTE: This buffer is not null terminated.
+  const WCHAR* substitute_name =
+    data.SymbolicLinkReparseBuffer.PathBuffer +
+    data.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
+  const size_t substitute_name_length =
+    data.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+
+  // NOTE: This buffer is not null terminated.
+  const WCHAR* print_name =
+    data.SymbolicLinkReparseBuffer.PathBuffer +
+    data.SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR);
+  const size_t print_name_length =
+    data.SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR);
+
+  return SymbolicLink{
+      std::wstring(substitute_name, substitute_name_length),
+      std::wstring(print_name, print_name_length),
+      data.SymbolicLinkReparseBuffer.Flags};
+}
+
+
+// Attempts to get a file or folder handle for an absolute path, and does not
+// follow symlinks. That is, if the path points at a symlink, the handle will
+// refer to the symlink rather than the file or folder the symlink points at.
+inline Try<SharedHandle> get_handle_no_follow(const std::string& absolute_path)
+{
+  struct _stat s;
+  bool resolved_path_is_directory = false;
+  if (::_stat(absolute_path.c_str(), &s) >= 0) {
+    resolved_path_is_directory = S_ISDIR(s.st_mode);
+  }
+
+  // NOTE: The `CreateFile` documentation[1] tells us which flags we need to
+  // invoke to open a handle that will point at the symlink instead of the
+  // folder or file it points at. The short answer is that you need to be sure
+  // to pass in `OPEN_EXISTING` and `FILE_FLAG_OPEN_REPARSE_POINT` to get a
+  // handle for the symlink and not the file the symlink points to.
+  //
+  // Note also that `CreateFile` will appropriately generate a handle for
+  // either a folder or a file (they are different!), as long as you
+  // appropriately set a magic flag, `FILE_FLAG_BACKUP_SEMANTICS`. It is not
+  // clear why, or what this flag means, the documentation[1] only says it's
+  // necessary.
+  //
+  // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
+  const DWORD access_flags = resolved_path_is_directory
+    ? (FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)
+    : FILE_FLAG_OPEN_REPARSE_POINT;
+
+  const HANDLE handle = CreateFile(
+    absolute_path.c_str(),
+    0,              // Ignored.
+    0,              // Ignored.
+    NULL,           // Ignored.
+    OPEN_EXISTING,  // Open existing symlink.
+    access_flags,   // Open symlink, not the file it points to.
+    NULL);          // Ignored.
+
+  if (handle == INVALID_HANDLE_VALUE) {
+    return WindowsError(
+        "Could not open handle for symlink at path '" + absolute_path + "'");
+  }
+
+  return SharedHandle(handle, CloseHandle);
+}
+
+
+// Attempts to get the symlink data for a file or folder handle.
+inline Try<SymbolicLink> get_symbolic_link_data(const HANDLE handle)
+{
+  // To get the symlink data, we call `DeviceIoControl`. This function is part
+  // of the Device Driver Kit (DDK), and buried away in a corner of the
+  // DDK documentation[1] is an incomplete explanation of how to twist API to
+  // get it to emit information about reparse points (and, thus, symlinks,
+  // since symlinks are implemented with reparse points). This technique is a
+  // hack, but it is used pretty much everywhere, including the Boost FS code,
+  // though it's worth noting that they seem to use it incorrectly[2].
+  //
+  // Summarized, the documentation tells us that we need to pass in the magic
+  // flag `FSCTL_GET_REPARSE_POINT` to get the function to populate a
+  // `REPARSE_DATA_BUFFER` struct with data about a reparse point. What it
+  // doesn't tell you is that this struct is in a header in the DDK, so in
+  // order to get information about the reparse point, you must either take a
+  // dependency on the DDK, or copy the struct from the header into your code.
+  // We take a cue from Boost FS, and copy the struct into this header (see
+  // above).
+  //
+  // Finally, for context, it may be worth looking at the (sparse)
+  // documentation for `DeviceIoControl` itself.
+  //
+  // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx
+  // [2] https://svn.boost.org/trac/boost/ticket/4663
+  // [3] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx
+
+  const size_t reparse_point_data_size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+  BYTE buffer[reparse_point_data_size];
+  REPARSE_DATA_BUFFER* reparse_point_data =
+    reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
+
+  DWORD ignored = 0;
+
+  // The semantics of this function are: get the reparse data associated with
+  // the `handle` of some open directory or file, and that data in
+  // `reparse_point_data`.
+  const BOOL reparse_data_obtained = DeviceIoControl(
+    handle,                  // handle to file or directory
+    FSCTL_GET_REPARSE_POINT, // Gets reparse point data for file/folder handle.
+    NULL,                    // Ignored.
+    0,                       // Ignored.
+    reparse_point_data,
+    reparse_point_data_size,
+    &ignored,                // Ignored.
+    NULL);                   // Ignored.
+
+  if (!reparse_data_obtained) {
+    return WindowsError("Failed to obtain reparse point data for handle");
+  }
+
+  return build_symbolic_link(*reparse_point_data);
+}
+
+} // namespace windows {
+} // namespace internal {
+
+#endif // __STOUT_INTERNAL_WINDOWS_REPARSEPOINT_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/e6db3880/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/symlink.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/symlink.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/symlink.hpp
new file mode 100644
index 0000000..5dc022b
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/internal/windows/symlink.hpp
@@ -0,0 +1,87 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_INTERNAL_WINDOWS_SYMLINK_HPP__
+#define __STOUT_INTERNAL_WINDOWS_SYMLINK_HPP__
+
+#include <string>
+
+#include <stout/try.hpp>
+#include <stout/windows.hpp>
+
+#include <stout/internal/windows/reparsepoint.hpp>
+
+#include <stout/os/realpath.hpp>
+
+
+namespace internal {
+namespace windows {
+
+// Gets symlink data for a given path, if it exists.
+//
+// This turns out to be a very complicated task on Windows. The gist of it is
+// that we know that symlinks on Windows are implemented with the Reparse Point
+// API, and so the process is a matter of:
+//
+//   1. Checking whether the attributes for the file/folder specified by the
+//      path have the reparse point bit set; all symlinks are implemented with
+//      reparse points, so this bit should be on all symlinks.
+//   2. Opening a file/folder handle for that path, instructing it specifically
+//      to open a handle for the symlink (if the path points at a symlink) and
+//      *not* the file the symlink points at (as is the default). Note that
+//      file and folder handles are different, so we have a function that
+//      chooses appropriately.
+//   3. Using `DeviceIoControl` to obtain information about the handle for this
+//      reparse point, which we can then query to figure out if it's a reparse
+//      point that is owned by the symlink filesystem filter driver.
+//   4. If it is, then we report that this path does point at a symlink.
+//
+// NOTE: it may be helpful to consult the documentation for each of these
+// functions, as they give you sources that justify the arguments to the
+// obscure APIs we call to get this all working.
+inline Try<SymbolicLink> query_symbolic_link_data(const std::string& path)
+{
+  // Convert to absolute path because Windows APIs expect it.
+  const Result<std::string> absolute_path = os::realpath(path);
+  if (!absolute_path.isSome()) {
+    return Error(absolute_path.error());
+  }
+
+  // Windows has no built-in way to tell whether a path points at a symbolic
+  // link; but, we know that symbolic links are implemented with reparse
+  // points, so we begin by checking that.
+  Try<bool> is_reparse_point =
+    reparse_point_attribute_set(absolute_path.get());
+
+  if (is_reparse_point.isError()) {
+    return Error(is_reparse_point.error());
+  } else if (!is_reparse_point.get()) {
+    return Error(
+        "Reparse point attribute is not set for path '" + absolute_path.get() +
+        "', and therefore it is not a symbolic link");
+  }
+
+  const Try<SharedHandle> symlink_handle =
+    get_handle_no_follow(absolute_path.get());
+
+  if (symlink_handle.isError()) {
+    return Error(symlink_handle.error());
+  }
+
+  // Finally, retrieve symlink data for the handle, if any.
+  return get_symbolic_link_data(symlink_handle.get().get_handle());
+}
+
+} // namespace windows {
+} // namespace internal {
+
+#endif // __STOUT_INTERNAL_WINDOWS_SYMLINK_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/e6db3880/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/stat.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/stat.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/stat.hpp
index ffe0748..32fa426 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/stat.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/posix/stat.hpp
@@ -34,6 +34,7 @@ inline bool isdir(const std::string& path)
   if (::stat(path.c_str(), &s) < 0) {
     return false;
   }
+
   return S_ISDIR(s.st_mode);
 }
 
@@ -45,6 +46,7 @@ inline bool isfile(const std::string& path)
   if (::stat(path.c_str(), &s) < 0) {
     return false;
   }
+
   return S_ISREG(s.st_mode);
 }
 
@@ -56,6 +58,7 @@ inline bool islink(const std::string& path)
   if (::lstat(path.c_str(), &s) < 0) {
     return false;
   }
+
   return S_ISLNK(s.st_mode);
 }
 
@@ -83,21 +86,22 @@ inline Try<Bytes> size(
     case DO_NOT_FOLLOW_SYMLINK: {
       if (::lstat(path.c_str(), &s) < 0) {
         return ErrnoError("Error invoking lstat for '" + path + "'");
+      } else {
+        return Bytes(s.st_size);
       }
       break;
     }
     case FOLLOW_SYMLINK: {
       if (::stat(path.c_str(), &s) < 0) {
         return ErrnoError("Error invoking stat for '" + path + "'");
+      } else {
+        return Bytes(s.st_size);
       }
       break;
     }
-    default: {
-      UNREACHABLE();
-    }
   }
 
-  return Bytes(s.st_size);
+  UNREACHABLE();
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/e6db3880/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/stat.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/stat.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/stat.hpp
index 5b38b9a..a2a5d0b 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/stat.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/windows/stat.hpp
@@ -15,29 +15,52 @@
 
 #include <string>
 
+#include <stout/bytes.hpp>
 #include <stout/try.hpp>
+#include <stout/unreachable.hpp>
+#include <stout/windows.hpp>
 
+#include <stout/internal/windows/reparsepoint.hpp>
+#include <stout/internal/windows/symlink.hpp>
+
+#ifdef _USE_32BIT_TIME_T
+#error "Implementation of `os::stat::mtime` assumes 64-bit `time_t`."
+#endif // _USE_32BIT_TIME_T
 
-namespace os {
 
+namespace os {
 namespace stat {
 
 inline bool isdir(const std::string& path)
 {
-  UNIMPLEMENTED;
+  struct _stat s;
+
+  if (::_stat(path.c_str(), &s) < 0) {
+    return false;
+  }
+
+  return S_ISDIR(s.st_mode);
 }
 
 
 inline bool isfile(const std::string& path)
 {
-  UNIMPLEMENTED;
-}
+  struct _stat s;
+
+  if (::_stat(path.c_str(), &s) < 0) {
+    return false;
+  }
 
+  return S_ISREG(s.st_mode);
+}
 
 
 inline bool islink(const std::string& path)
 {
-  UNIMPLEMENTED;
+  Try<internal::windows::SymbolicLink> symlink =
+    internal::windows::query_symbolic_link_data(path);
+
+  return symlink.isSome();
 }
 
 
@@ -58,35 +81,91 @@ inline Try<Bytes> size(
     const std::string& path,
     const FollowSymlink follow = FOLLOW_SYMLINK)
 {
-  UNIMPLEMENTED;
+  switch (follow) {
+    case DO_NOT_FOLLOW_SYMLINK: {
+      Try<internal::windows::SymbolicLink> symlink =
+        internal::windows::query_symbolic_link_data(path);
+
+      if (symlink.isError()) {
+        return Error(symlink.error());
+      } else {
+        return Bytes(symlink.get().substitute_name.length());
+      }
+      break;
+    }
+    case FOLLOW_SYMLINK: {
+      struct _stat s;
+
+      if (::_stat(path.c_str(), &s) < 0) {
+        return ErrnoError("Error invoking stat for '" + path + "'");
+      } else {
+        return Bytes(s.st_size);
+      }
+      break;
+    }
+  }
+
+  UNREACHABLE();
 }
 
 
 inline Try<long> mtime(const std::string& path)
 {
-  UNIMPLEMENTED;
+  Try<internal::windows::SymbolicLink> symlink =
+    internal::windows::query_symbolic_link_data(path);
+
+  if (symlink.isSome()) {
+    return Error(
+        "Requested mtime for '" + path +
+        "', but symbolic links don't have an mtime on Windows");
+  }
+
+  struct _stat s;
+
+  if (::_stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_mtime;
 }
 
 
 inline Try<mode_t> mode(const std::string& path)
 {
-  UNIMPLEMENTED;
+  struct _stat s;
+
+  if (::_stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_mode;
 }
 
 
-inline Try<dev_t> rdev(const std::string& path)
+inline Try<dev_t> dev(const std::string& path)
 {
-  UNIMPLEMENTED;
+  struct _stat s;
+
+  if (::_stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_dev;
 }
 
 
 inline Try<ino_t> inode(const std::string& path)
 {
-  UNIMPLEMENTED;
+  struct _stat s;
+
+  if (::_stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_ino;
 }
 
 } // namespace stat {
-
 } // namespace os {
 
 #endif // __STOUT_OS_WINDOWS_STAT_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/e6db3880/3rdparty/libprocess/3rdparty/stout/include/stout/windows.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/windows.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/windows.hpp
index 27edf1b..061bb4a 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/windows.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/windows.hpp
@@ -27,6 +27,37 @@
 #include <Winsock2.h>
 #include <Windows.h>
 
+#include <memory>
+
+
+#ifdef _UNICODE
+// Much of the core Windows API is available both in `string` and `wstring`
+// varieties. To avoid polluting the namespace with two versions of every
+// function, a common pattern in the Windows headers is to offer a single macro
+// that expands to the `string` or `wstring` version, depending on whether the
+// `_UNICODE` preprocessor symbol is set. For example, `GetMessage` will expand
+// to either `GetMessageA` (the `string` version) or `GetMessageW` (the
+// `wstring` version) depending on whether this symbol is defined.
+//
+// The downside of this is that it makes POSIX interop really hard. Hence, we
+// refuse to compile if such a symbol is passed in during compilation.
+#error "Mesos doesn't currently support the `_UNICODE` Windows header constant"
+#endif // _UNICODE
+
+// An RAII `HANDLE`.
+class SharedHandle : public std::shared_ptr<void>
+{
+  static_assert(std::is_same<HANDLE, void*>::value,
+                "Expected `HANDLE` to be of type `void*`.");
+
+public:
+  template <typename Deleter>
+  SharedHandle(HANDLE handle, Deleter deleter)
+      : std::shared_ptr<void>(handle, deleter) {}
+
+  HANDLE get_handle() const { return this->get(); }
+};
+
 
 // Definitions and constants used for Windows compat.
 //
@@ -137,14 +168,44 @@ typedef SSIZE_T ssize_t;
 // have to change any socket code.
 constexpr int SHUT_RD = SD_RECEIVE;
 
-// Macros that test whether a `stat` struct represents a directory or a file.
-#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)  // Directory.
-#define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)  // File.
-#define S_ISCHR(mode)  (((mode) & S_IFMT) == S_IFCHR)  // Character device.
-#define S_ISFIFO(mode) (((mode) & S_IFMT) == _S_IFIFO) // Pipe.
-#define S_ISBLK(mode)  0                               // Block special device.
-#define S_ISSOCK(mode) 0                               // Socket.
-#define S_ISLNK(mode)  0                               // Symbolic link.
+// The following functions are usually macros on POSIX; we provide them here as
+// functions to avoid having global macros lying around. Note that these
+// operate on the `_stat` struct (a Windows version of the standard POSIX
+// `stat` struct), of which the `st_mode` field is known to be an `int`.
+inline bool S_ISDIR(const int mode)
+{
+  return (mode & S_IFMT) == S_IFDIR; // Directory.
+}
+
+inline bool S_ISREG(const int mode)
+{
+  return (mode & S_IFMT) == S_IFREG;  // File.
+}
+
+inline bool S_ISCHR(const int mode)
+{
+  return (mode & S_IFMT) == S_IFCHR;  // Character device.
+}
+
+inline bool S_ISFIFO(const int mode)
+{
+  return (mode & S_IFMT) == _S_IFIFO; // Pipe.
+}
+
+inline bool S_ISBLK(const int mode)
+{
+  return false;                       // Block special device.
+}
+
+inline bool S_ISSOCK(const int mode)
+{
+  return false;                       // Socket.
+}
+
+inline bool S_ISLNK(const int mode)
+{
+  return false;                       // Symbolic link.
+}
 
 // Permissions API. (cf. MESOS-3176 to track ongoing permissions work.)
 //