diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-12-01 19:32:01 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-12-01 19:32:01 +0000 |
commit | bee0c38f595f52d424161dc1db9c0bfe61421957 (patch) | |
tree | 7960210198d9c6a272adaba4a42cbe3cb7e6db4c /lib/Support/Unix | |
parent | 5a7df60619d88a2c804b0dbdf68b0b502941bba3 (diff) |
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
Diffstat (limited to 'lib/Support/Unix')
-rw-r--r-- | lib/Support/Unix/PathV2.inc | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc index bcd93f046d..d12cd1647e 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 <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 |