0fa4b87cff2e2fc75e1c13ede489239c7787b98c
[oota-llvm.git] / lib / Support / Unix / PathV2.inc
1 //===- llvm/Support/Unix/PathV2.cpp - Unix Path Implementation --*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Unix specific implementation of the PathV2 API.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include "Unix.h"
20 #if HAVE_SYS_STAT_H
21 #include <sys/stat.h>
22 #endif
23 #if HAVE_FCNTL_H
24 #include <fcntl.h>
25 #endif
26 #if HAVE_SYS_TYPES_H
27 #include <sys/types.h>
28 #endif
29
30 namespace {
31   struct AutoFD {
32     int FileDescriptor;
33
34     AutoFD(int fd) : FileDescriptor(fd) {}
35     ~AutoFD() {
36       if (FileDescriptor >= 0)
37         ::close(FileDescriptor);
38     }
39
40     int take() {
41       int ret = FileDescriptor;
42       FileDescriptor = -1;
43       return ret;
44     }
45
46     operator int() const {return FileDescriptor;}
47   };
48 }
49
50 namespace llvm {
51 namespace sys  {
52 namespace path {
53
54 error_code current_path(SmallVectorImpl<char> &result) {
55   long size = ::pathconf(".", _PC_PATH_MAX);
56   result.reserve(size + 1);
57   result.set_size(size + 1);
58
59   if (::getcwd(result.data(), result.size()) == 0)
60     return error_code(errno, system_category());
61
62   result.set_size(strlen(result.data()));
63   return make_error_code(errc::success);
64 }
65
66 } // end namespace path
67
68 namespace fs{
69
70 error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
71  // Get arguments.
72   SmallString<128> from_storage;
73   SmallString<128> to_storage;
74   StringRef f = from.toNullTerminatedStringRef(from_storage);
75   StringRef t = to.toNullTerminatedStringRef(to_storage);
76
77   const size_t buf_sz = 32768;
78   char buffer[buf_sz];
79   int from_file = -1, to_file = -1;
80
81   // Open from.
82   if ((from_file = ::open(f.begin(), O_RDONLY)) < 0)
83     return error_code(errno, system_category());
84   AutoFD from_fd(from_file);
85
86   // Stat from.
87   struct stat from_stat;
88   if (::stat(f.begin(), &from_stat) != 0)
89     return error_code(errno, system_category());
90
91   // Setup to flags.
92   int to_flags = O_CREAT | O_WRONLY;
93   if (copt == copy_option::fail_if_exists)
94     to_flags |= O_EXCL;
95
96   // Open to.
97   if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0)
98     return error_code(errno, system_category());
99   AutoFD to_fd(to_file);
100
101   // Copy!
102   ssize_t sz, sz_read = 1, sz_write;
103   while (sz_read > 0 &&
104          (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) {
105     // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
106     // Marc Rochkind, Addison-Wesley, 2004, page 94
107     sz_write = 0;
108     do {
109       if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) {
110         sz_read = sz;  // cause read loop termination.
111         break;         // error.
112       }
113       sz_write += sz;
114     } while (sz_write < sz_read);
115   }
116
117   // After all the file operations above the return value of close actually
118   // matters.
119   if (::close(from_fd.take()) < 0) sz_read = -1;
120   if (::close(to_fd.take()) < 0) sz_read = -1;
121
122   // Check for errors.
123   if (sz_read < 0)
124     return error_code(errno, system_category());
125
126   return make_error_code(errc::success);
127 }
128
129 } // end namespace fs
130 } // end namespace sys
131 } // end namespace llvm