Merge pull request #125 from ddunbar/directory-permissions

[Basic] Introduce a FS method for creating directories.
diff --git a/include/llbuild/Basic/FileSystem.h b/include/llbuild/Basic/FileSystem.h
index 3cf86aa..497f15d 100644
--- a/include/llbuild/Basic/FileSystem.h
+++ b/include/llbuild/Basic/FileSystem.h
@@ -42,6 +42,12 @@
   FileSystem() {}
   virtual ~FileSystem();
 
+  /// Create the given directory if it does not exist.
+  ///
+  /// \returns True on success (the directory was created, or already exists).
+  virtual bool
+  createDirectory(const std::string& path) = 0;
+
   /// Get a memory buffer for a given file on the file system.
   ///
   /// \returns The file contents, on success, or null on error.
diff --git a/lib/Basic/FileSystem.cpp b/lib/Basic/FileSystem.cpp
index 85ab4f8..b941d51 100644
--- a/lib/Basic/FileSystem.cpp
+++ b/lib/Basic/FileSystem.cpp
@@ -30,6 +30,16 @@
 public:
   LocalFileSystem() {}
 
+  virtual bool
+  createDirectory(const std::string& path) override {
+    if (::mkdir(path.c_str(), S_IRWXU | S_IRWXG |  S_IRWXO) == -1) {
+      if (errno != EEXIST) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   virtual std::unique_ptr<llvm::MemoryBuffer>
   getFileContents(const std::string& path) override {
     auto result = llvm::MemoryBuffer::getFile(path);
diff --git a/lib/BuildSystem/BuildSystem.cpp b/lib/BuildSystem/BuildSystem.cpp
index 6239b9c..62be1e3 100644
--- a/lib/BuildSystem/BuildSystem.cpp
+++ b/lib/BuildSystem/BuildSystem.cpp
@@ -1871,7 +1871,8 @@
                                                Task* task,
                                                QueueJobContext* context) override {
     auto output = getOutputs()[0];
-    if (llvm::sys::fs::create_directories(output->getName())) {
+    if (!bsci.getDelegate().getFileSystem().createDirectory(
+            output->getName())) {
       getBuildSystem(bsci.getBuildEngine()).error(
           "", "unable to create directory '" + output->getName() + "'");
       return CommandResult::Failed;
@@ -2079,7 +2080,7 @@
       {
         auto parent = llvm::sys::path::parent_path(output->getName());
         if (!parent.empty()) {
-          (void) llvm::sys::fs::create_directories(parent);
+          (void) bsci.getDelegate().getFileSystem().createDirectory(parent);
         }
       }
 
diff --git a/products/libllbuild/BuildSystem-C-API.cpp b/products/libllbuild/BuildSystem-C-API.cpp
index e864263..7824c7d 100644
--- a/products/libllbuild/BuildSystem-C-API.cpp
+++ b/products/libllbuild/BuildSystem-C-API.cpp
@@ -46,6 +46,15 @@
       : cAPIDelegate(delegate),
         localFileSystem(basic::createLocalFileSystem()) { }
 
+  virtual bool
+  createDirectory(const std::string& path) override {
+    if (!cAPIDelegate.fs_create_directory) {
+      return localFileSystem->createDirectory(path);
+    }
+
+    return cAPIDelegate.fs_create_directory(cAPIDelegate.context, path.c_str());
+  }
+  
   virtual std::unique_ptr<llvm::MemoryBuffer>
   getFileContents(const std::string& path) override {
     if (!cAPIDelegate.fs_get_file_contents) {
diff --git a/products/libllbuild/public-api/llbuild/buildsystem.h b/products/libllbuild/public-api/llbuild/buildsystem.h
index a8083b7..c70d266 100644
--- a/products/libllbuild/public-api/llbuild/buildsystem.h
+++ b/products/libllbuild/public-api/llbuild/buildsystem.h
@@ -158,6 +158,11 @@
   ///
   /// @{
 
+  /// Create the given directory if it does not exist.
+  ///
+  /// \\returns True on success (the directory was created, or already exists).
+  bool (*fs_create_directory)(void* context, const char* path);
+  
   /// Get the file contents for the given path.
   ///
   /// The contents *MUST* be returned in a new buffer allocated with \see
diff --git a/tests/BuildSystem/Build/Inputs/get-file-permissions b/tests/BuildSystem/Build/Inputs/get-file-permissions
new file mode 100755
index 0000000..cea8af3
--- /dev/null
+++ b/tests/BuildSystem/Build/Inputs/get-file-permissions
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+import os
+import stat
+import sys
+
+print(oct(stat.S_IMODE(os.stat(sys.argv[1]).st_mode)))
diff --git a/tests/BuildSystem/Build/mkdir.llbuild b/tests/BuildSystem/Build/mkdir.llbuild
index a327159..387824d 100644
--- a/tests/BuildSystem/Build/mkdir.llbuild
+++ b/tests/BuildSystem/Build/mkdir.llbuild
@@ -5,11 +5,14 @@
 # RUN: cp %s %t.build/build.llbuild
 # RUN: %{llbuild} buildsystem build --serial --chdir %t.build > %t.out
 # RUN: %{FileCheck} --input-file=%t.out %s
+# RUN: %S/Inputs/get-file-permissions %t.build/subdir/subdir2 > %t.permissions
+# RUN: %{FileCheck} --input-file=%t.permissions --check-prefix=CHECK-PERMISSIONS %s
 #
 # CHECK: ECHO
 # CHECK: MKDIR
 # CHECK: MUTATE
 # CHECK: TRIGGERED
+# CHECK-PERMISSIONS: 0755
 
 
 # Check that a null build does nothing.