From bee0c38f595f52d424161dc1db9c0bfe61421957 Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Wed, 1 Dec 2010 19:32:01 +0000 Subject: [PATCH] Support/FileSystem: Add copy_file implementation. Not tests yet because the 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 | 11 ++-- lib/Support/Unix/PathV2.inc | 92 ++++++++++++++++++++++++++++++++++ lib/Support/Windows/PathV2.inc | 57 +++++++++++++++++++++ 3 files changed, 157 insertions(+), 3 deletions(-) diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp index a4a3f383411..dbfde54a73a 100644 --- a/lib/Support/PathV2.cpp +++ b/lib/Support/PathV2.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/PathV2.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/ErrorHandling.h" #include @@ -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) diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc index bcd93f046dd..d12cd1647ed 100644 --- a/lib/Support/Unix/PathV2.inc +++ b/lib/Support/Unix/PathV2.inc @@ -17,6 +17,35 @@ //===----------------------------------------------------------------------===// #include "Unix.h" +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#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 &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 diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc index 9c15e26b79d..cb80731c1c3 100644 --- a/lib/Support/Windows/PathV2.inc +++ b/lib/Support/Windows/PathV2.inc @@ -18,6 +18,36 @@ #include "Windows.h" +using namespace llvm; + +namespace { + error_code UTF8ToUTF16(const StringRef &utf8, + SmallVectorImpl &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 wide_from; + SmallVector 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