Support/FileSystem: Add copy_file implementation. Not tests yet because the
authorMichael J. Spencer <bigcheesegs@gmail.com>
Wed, 1 Dec 2010 19:32:01 +0000 (19:32 +0000)
committerMichael J. Spencer <bigcheesegs@gmail.com>
Wed, 1 Dec 2010 19:32:01 +0000 (19:32 +0000)
file creation APIs aren't implemented.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120593 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Support/PathV2.cpp
lib/Support/Unix/PathV2.inc
lib/Support/Windows/PathV2.inc

index a4a3f383411d90364f48bd5f049559f1a81622a0..dbfde54a73a7454cede8f34c2d7a949b290c248f 100644 (file)
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/PathV2.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <cctype>
 
@@ -666,9 +667,13 @@ error_code is_relative(const Twine &path, bool &result) {
   return ec;
 }
 
-}
-}
-}
+} // end namespace path
+
+namespace fs {
+
+} // end namespace fs
+} // end namespace sys
+} // end namespace llvm
 
 // Include the truly platform-specific parts.
 #if defined(LLVM_ON_UNIX)
index bcd93f046ddc179ccef25ef2838e99d67262042a..d12cd1647ede708ad787a8917c76e8f9f3efd3f1 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "Unix.h"
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+namespace {
+  struct AutoFD {
+    int FileDescriptor;
+
+    AutoFD(int fd) : FileDescriptor(fd) {}
+    ~AutoFD() {
+      if (FileDescriptor >= 0)
+        ::close(FileDescriptor);
+    }
+
+    int take() {
+      int ret = FileDescriptor;
+      FileDescriptor = -1;
+      return ret;
+    }
+
+    operator int() const {return FileDescriptor;}
+  };
+}
 
 namespace llvm {
 namespace sys  {
@@ -35,5 +64,68 @@ error_code current_path(SmallVectorImpl<char> &result) {
 }
 
 } // end namespace path
+
+namespace fs{
+
+error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
+ // Get arguments.
+  SmallString<128> from_storage;
+  SmallString<128> to_storage;
+  StringRef f = from.toStringRef(from_storage);
+  StringRef t = to.toStringRef(to_storage);
+
+  const size_t buf_sz = 32768;
+  char buffer[buf_sz];
+  int from_file = -1, to_file = -1;
+
+  // Open from.
+  if ((from_file = ::open(f.begin(), O_RDONLY)) < 0)
+    return error_code(errno, system_category());
+  AutoFD from_fd(from_file);
+
+  // Stat from.
+  struct stat from_stat;
+  if (::stat(f.begin(), &from_stat) != 0)
+    return error_code(errno, system_category());
+
+  // Setup to flags.
+  int to_flags = O_CREAT | O_WRONLY;
+  if (copt == copy_option::fail_if_exists)
+    to_flags |= O_EXCL;
+
+  // Open to.
+  if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0)
+    return error_code(errno, system_category());
+  AutoFD to_fd(to_file);
+
+  // Copy!
+  ssize_t sz, sz_read = 1, sz_write;
+  while (sz_read > 0 &&
+         (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) {
+    // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
+    // Marc Rochkind, Addison-Wesley, 2004, page 94
+    sz_write = 0;
+    do {
+      if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) {
+        sz_read = sz;  // cause read loop termination.
+        break;         // error.
+      }
+      sz_write += sz;
+    } while (sz_write < sz_read);
+  }
+
+  // After all the file operations above the return value of close actually
+  // matters.
+  if (::close(from_fd.take()) < 0) sz_read = -1;
+  if (::close(to_fd.take()) < 0) sz_read = -1;
+
+  // Check for errors.
+  if (sz_read < 0)
+    return error_code(errno, system_category());
+
+  return make_error_code(errc::success);
+}
+
+} // end namespace fs
 } // end namespace sys
 } // end namespace llvm
index 9c15e26b79d378563015ac69da7fe00411cc7d87..cb80731c1c3cd9afce6dea76d421ce2abbf73248 100644 (file)
 
 #include "Windows.h"
 
+using namespace llvm;
+
+namespace {
+  error_code UTF8ToUTF16(const StringRef &utf8,
+                               SmallVectorImpl<wchar_t> &utf16) {
+    int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                    utf8.begin(), utf8.size(),
+                                    utf16.begin(), 0);
+
+    if (len == 0)
+      return make_error_code(windows_error(::GetLastError()));
+
+    utf16.reserve(len + 1);
+    utf16.set_size(len);
+
+    len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                    utf8.begin(), utf8.size(),
+                                    utf16.begin(), utf16.size());
+
+    if (len == 0)
+      return make_error_code(windows_error(::GetLastError()));
+
+    // Make utf16 null terminated.
+    utf16.push_back(0);
+    utf16.pop_back();
+
+    return make_error_code(errc::success);
+  }
+}
+
 namespace llvm {
 namespace sys  {
 namespace path {
@@ -67,5 +97,32 @@ retry_cur_dir:
 }
 
 } // end namespace path
+
+namespace fs {
+
+error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
+  // Get arguments.
+  SmallString<128> from_storage;
+  SmallString<128> to_storage;
+  StringRef f = from.toStringRef(from_storage);
+  StringRef t = to.toStringRef(to_storage);
+
+  // Convert to utf-16.
+  SmallVector<wchar_t, 128> wide_from;
+  SmallVector<wchar_t, 128> wide_to;
+  if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+  if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
+
+  // Copy the file.
+  BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(),
+                         copt != copy_option::overwrite_if_exists);
+
+  if (res == 0)
+    return make_error_code(windows_error(::GetLastError()));
+
+  return make_error_code(errc::success);
+}
+
+} // end namespace fs
 } // end namespace sys
 } // end namespace llvm