blob: 4ca482dfce1d50d1ae25e0160583e7d2ffccdf4c [file] [log] [blame]
Michael J. Spencerdffde992010-11-29 22:28:51 +00001//===- 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"
Michael J. Spencerbee0c382010-12-01 19:32:01 +000020#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_FCNTL_H
24#include <fcntl.h>
25#endif
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +000026#if HAVE_STDIO_H
27#include <stdio.h>
Michael J. Spencerbee0c382010-12-01 19:32:01 +000028#endif
29
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +000030using namespace llvm;
31
Michael J. Spencerbee0c382010-12-01 19:32:01 +000032namespace {
Michael J. Spencerad8a14f2010-12-07 01:23:08 +000033 /// This class automatically closes the given file descriptor when it goes out
34 /// of scope. You can take back explicit ownership of the file descriptor by
35 /// calling take(). The destructor does not verify that close was successful.
36 /// Therefore, never allow this class to call close on a file descriptor that
37 /// has been read from or written to.
Michael J. Spencerbee0c382010-12-01 19:32:01 +000038 struct AutoFD {
39 int FileDescriptor;
40
41 AutoFD(int fd) : FileDescriptor(fd) {}
42 ~AutoFD() {
43 if (FileDescriptor >= 0)
44 ::close(FileDescriptor);
45 }
46
47 int take() {
48 int ret = FileDescriptor;
49 FileDescriptor = -1;
50 return ret;
51 }
52
53 operator int() const {return FileDescriptor;}
54 };
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +000055
56 error_code TempDir(SmallVectorImpl<char> &result) {
57 // FIXME: Don't use TMPDIR if program is SUID or SGID enabled.
58 const char *dir = 0;
59 (dir = std::getenv("TMPDIR" )) ||
60 (dir = std::getenv("TMP" )) ||
61 (dir = std::getenv("TEMP" )) ||
62 (dir = std::getenv("TEMPDIR")) ||
63#ifdef P_tmpdir
64 (dir = P_tmpdir) ||
65#endif
66 (dir = "/tmp");
67
68 result.set_size(0);
69 StringRef d(dir);
70 result.append(d.begin(), d.end());
Michael J. Spencer9d425e72010-12-04 18:45:32 +000071 return success;
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +000072 }
Michael J. Spencerbee0c382010-12-01 19:32:01 +000073}
Michael J. Spencerdffde992010-11-29 22:28:51 +000074
75namespace llvm {
76namespace sys {
Michael J. Spencer1522fce2010-12-07 01:22:31 +000077namespace fs {
Michael J. Spencerdffde992010-11-29 22:28:51 +000078
79error_code current_path(SmallVectorImpl<char> &result) {
Michael J. Spencer1522fce2010-12-07 01:22:31 +000080 result.reserve(MAXPATHLEN);
Michael J. Spencerdffde992010-11-29 22:28:51 +000081
Michael J. Spencer1522fce2010-12-07 01:22:31 +000082 while (true) {
83 if (::getcwd(result.data(), result.capacity()) == 0) {
84 // See if there was a real error.
85 if (errno != errc::not_enough_memory)
86 return error_code(errno, system_category());
87 // Otherwise there just wasn't enough space.
88 result.reserve(result.capacity() * 2);
89 } else
90 break;
91 }
Michael J. Spencerdffde992010-11-29 22:28:51 +000092
93 result.set_size(strlen(result.data()));
Michael J. Spencer9d425e72010-12-04 18:45:32 +000094 return success;
Michael J. Spencerdffde992010-11-29 22:28:51 +000095}
96
Michael J. Spencerbee0c382010-12-01 19:32:01 +000097error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
98 // Get arguments.
99 SmallString<128> from_storage;
100 SmallString<128> to_storage;
Michael J. Spencer871498e2010-12-01 20:37:42 +0000101 StringRef f = from.toNullTerminatedStringRef(from_storage);
102 StringRef t = to.toNullTerminatedStringRef(to_storage);
Michael J. Spencerbee0c382010-12-01 19:32:01 +0000103
104 const size_t buf_sz = 32768;
105 char buffer[buf_sz];
106 int from_file = -1, to_file = -1;
107
108 // Open from.
109 if ((from_file = ::open(f.begin(), O_RDONLY)) < 0)
110 return error_code(errno, system_category());
111 AutoFD from_fd(from_file);
112
113 // Stat from.
114 struct stat from_stat;
115 if (::stat(f.begin(), &from_stat) != 0)
116 return error_code(errno, system_category());
117
118 // Setup to flags.
119 int to_flags = O_CREAT | O_WRONLY;
120 if (copt == copy_option::fail_if_exists)
121 to_flags |= O_EXCL;
122
123 // Open to.
124 if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0)
125 return error_code(errno, system_category());
126 AutoFD to_fd(to_file);
127
128 // Copy!
129 ssize_t sz, sz_read = 1, sz_write;
130 while (sz_read > 0 &&
131 (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) {
132 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
133 // Marc Rochkind, Addison-Wesley, 2004, page 94
134 sz_write = 0;
135 do {
136 if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) {
137 sz_read = sz; // cause read loop termination.
138 break; // error.
139 }
140 sz_write += sz;
141 } while (sz_write < sz_read);
142 }
143
144 // After all the file operations above the return value of close actually
145 // matters.
146 if (::close(from_fd.take()) < 0) sz_read = -1;
147 if (::close(to_fd.take()) < 0) sz_read = -1;
148
149 // Check for errors.
150 if (sz_read < 0)
151 return error_code(errno, system_category());
152
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000153 return success;
Michael J. Spencerbee0c382010-12-01 19:32:01 +0000154}
155
Michael J. Spencerb83769f2010-12-03 05:42:11 +0000156error_code create_directory(const Twine &path, bool &existed) {
157 SmallString<128> path_storage;
158 StringRef p = path.toNullTerminatedStringRef(path_storage);
159
160 if (::mkdir(p.begin(), 0700) == -1) {
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000161 if (errno != errc::file_exists)
Michael J. Spencerb83769f2010-12-03 05:42:11 +0000162 return error_code(errno, system_category());
163 existed = true;
164 } else
165 existed = false;
166
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000167 return success;
Michael J. Spencerb83769f2010-12-03 05:42:11 +0000168}
169
Michael J. Spencerd7b305f2010-12-03 05:58:41 +0000170error_code create_hard_link(const Twine &to, const Twine &from) {
171 // Get arguments.
172 SmallString<128> from_storage;
173 SmallString<128> to_storage;
174 StringRef f = from.toNullTerminatedStringRef(from_storage);
175 StringRef t = to.toNullTerminatedStringRef(to_storage);
176
177 if (::link(t.begin(), f.begin()) == -1)
178 return error_code(errno, system_category());
179
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000180 return success;
Michael J. Spencerd7b305f2010-12-03 05:58:41 +0000181}
182
Michael J. Spencer9b391c52010-12-03 07:41:25 +0000183error_code create_symlink(const Twine &to, const Twine &from) {
184 // Get arguments.
185 SmallString<128> from_storage;
186 SmallString<128> to_storage;
187 StringRef f = from.toNullTerminatedStringRef(from_storage);
188 StringRef t = to.toNullTerminatedStringRef(to_storage);
189
190 if (::symlink(t.begin(), f.begin()) == -1)
191 return error_code(errno, system_category());
192
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000193 return success;
Michael J. Spencer9b391c52010-12-03 07:41:25 +0000194}
195
Michael J. Spencer106aa732010-12-03 17:53:43 +0000196error_code remove(const Twine &path, bool &existed) {
197 SmallString<128> path_storage;
198 StringRef p = path.toNullTerminatedStringRef(path_storage);
199
200 if (::remove(p.begin()) == -1) {
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000201 if (errno != errc::no_such_file_or_directory)
Michael J. Spencer106aa732010-12-03 17:53:43 +0000202 return error_code(errno, system_category());
203 existed = false;
204 } else
205 existed = true;
206
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000207 return success;
Michael J. Spencer106aa732010-12-03 17:53:43 +0000208}
209
Michael J. Spencera50b98c2010-12-03 17:53:55 +0000210error_code rename(const Twine &from, const Twine &to) {
211 // Get arguments.
212 SmallString<128> from_storage;
213 SmallString<128> to_storage;
214 StringRef f = from.toNullTerminatedStringRef(from_storage);
215 StringRef t = to.toNullTerminatedStringRef(to_storage);
216
217 if (::rename(f.begin(), t.begin()) == -1)
218 return error_code(errno, system_category());
219
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000220 return success;
Michael J. Spencera50b98c2010-12-03 17:53:55 +0000221}
222
Michael J. Spencer3920d3b2010-12-03 17:54:07 +0000223error_code resize_file(const Twine &path, uint64_t size) {
224 SmallString<128> path_storage;
225 StringRef p = path.toNullTerminatedStringRef(path_storage);
226
227 if (::truncate(p.begin(), size) == -1)
228 return error_code(errno, system_category());
229
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000230 return success;
Michael J. Spencer3920d3b2010-12-03 17:54:07 +0000231}
232
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000233error_code exists(const Twine &path, bool &result) {
234 SmallString<128> path_storage;
235 StringRef p = path.toNullTerminatedStringRef(path_storage);
236
237 struct stat status;
238 if (::stat(p.begin(), &status) == -1) {
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000239 if (errno != errc::no_such_file_or_directory)
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000240 return error_code(errno, system_category());
241 result = false;
242 } else
243 result = true;
244
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000245 return success;
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000246}
247
Michael J. Spencerb531f452010-12-03 18:49:13 +0000248error_code equivalent(const Twine &A, const Twine &B, bool &result) {
249 // Get arguments.
250 SmallString<128> a_storage;
251 SmallString<128> b_storage;
252 StringRef a = A.toNullTerminatedStringRef(a_storage);
253 StringRef b = B.toNullTerminatedStringRef(b_storage);
254
255 struct stat stat_a, stat_b;
256 int error_b = ::stat(b.begin(), &stat_b);
257 int error_a = ::stat(a.begin(), &stat_a);
258
259 // If both are invalid, it's an error. If only one is, the result is false.
260 if (error_a != 0 || error_b != 0) {
261 if (error_a == error_b)
262 return error_code(errno, system_category());
263 result = false;
264 } else {
265 result =
266 stat_a.st_dev == stat_b.st_dev &&
267 stat_a.st_ino == stat_b.st_ino;
268 }
269
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000270 return success;
Michael J. Spencerb531f452010-12-03 18:49:13 +0000271}
272
Michael J. Spencer01a87c42010-12-04 00:31:48 +0000273error_code file_size(const Twine &path, uint64_t &result) {
274 SmallString<128> path_storage;
275 StringRef p = path.toNullTerminatedStringRef(path_storage);
276
277 struct stat status;
278 if (::stat(p.begin(), &status) == -1)
279 return error_code(errno, system_category());
280 if (!S_ISREG(status.st_mode))
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000281 return make_error_code(errc::operation_not_permitted);
Michael J. Spencer01a87c42010-12-04 00:31:48 +0000282
283 result = status.st_size;
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000284 return success;
Michael J. Spencer01a87c42010-12-04 00:31:48 +0000285}
286
Michael J. Spencer470ae132010-12-04 00:32:40 +0000287error_code status(const Twine &path, file_status &result) {
288 SmallString<128> path_storage;
289 StringRef p = path.toNullTerminatedStringRef(path_storage);
290
291 struct stat status;
292 if (::stat(p.begin(), &status) != 0) {
293 error_code ec(errno, system_category());
294 if (ec == errc::no_such_file_or_directory)
295 result = file_status(file_type::file_not_found);
296 else
297 result = file_status(file_type::status_error);
298 return ec;
299 }
300
301 if (S_ISDIR(status.st_mode))
302 result = file_status(file_type::directory_file);
303 else if (S_ISREG(status.st_mode))
304 result = file_status(file_type::regular_file);
305 else if (S_ISBLK(status.st_mode))
306 result = file_status(file_type::block_file);
307 else if (S_ISCHR(status.st_mode))
308 result = file_status(file_type::character_file);
309 else if (S_ISFIFO(status.st_mode))
310 result = file_status(file_type::fifo_file);
311 else if (S_ISSOCK(status.st_mode))
312 result = file_status(file_type::socket_file);
313 else
314 result = file_status(file_type::type_unknown);
315
316 return success;
317}
318
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000319error_code unique_file(const Twine &model, int &result_fd,
320 SmallVectorImpl<char> &result_path) {
321 SmallString<128> Model;
322 model.toVector(Model);
323 // Null terminate.
324 Model.c_str();
325
326 // Make model absolute by prepending a temp directory if it's not already.
327 bool absolute;
328 if (error_code ec = path::is_absolute(Twine(Model), absolute)) return ec;
329 if (!absolute) {
330 SmallString<128> TDir;
331 if (error_code ec = TempDir(TDir)) return ec;
332 if (error_code ec = path::append(TDir, Twine(Model))) return ec;
333 Model.swap(TDir);
334 }
335
336 // Replace '%' with random chars. From here on, DO NOT modify model. It may be
337 // needed if the randomly chosen path already exists.
338 SmallString<128> RandomPath;
339 RandomPath.reserve(Model.size() + 1);
340 ::srand(::time(NULL));
341
342retry_random_path:
343 // This is opened here instead of above to make it easier to track when to
344 // close it. Collisions should be rare enough for the possible extra syscalls
345 // not to matter.
346 FILE *RandomSource = ::fopen("/dev/urandom", "r");
347 RandomPath.set_size(0);
348 for (SmallVectorImpl<char>::const_iterator i = Model.begin(),
349 e = Model.end(); i != e; ++i) {
350 if (*i == '%') {
351 char val = 0;
352 if (RandomSource)
353 val = fgetc(RandomSource);
354 else
355 val = ::rand();
356 RandomPath.push_back("0123456789abcdef"[val & 15]);
357 } else
358 RandomPath.push_back(*i);
359 }
360
361 if (RandomSource)
362 ::fclose(RandomSource);
363
364 // Try to open + create the file.
365rety_open_create:
366 int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
367 if (RandomFD == -1) {
368 // If the file existed, try again, otherwise, error.
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000369 if (errno == errc::file_exists)
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000370 goto retry_random_path;
371 // The path prefix doesn't exist.
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000372 if (errno == errc::no_such_file_or_directory) {
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000373 StringRef p(RandomPath.begin(), RandomPath.size());
374 SmallString<64> dir_to_create;
375 for (path::const_iterator i = path::begin(p),
376 e = --path::end(p); i != e; ++i) {
377 if (error_code ec = path::append(dir_to_create, *i)) return ec;
378 bool Exists;
379 if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
380 if (!Exists) {
381 // Don't try to create network paths.
382 if (i->size() > 2 && (*i)[0] == '/' &&
383 (*i)[1] == '/' &&
384 (*i)[2] != '/')
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000385 return make_error_code(errc::no_such_file_or_directory);
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000386 if (::mkdir(dir_to_create.c_str(), 0700) == -1)
387 return error_code(errno, system_category());
388 }
389 }
390 goto rety_open_create;
391 }
392 return error_code(errno, system_category());
393 }
394
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000395 // Make the path absolute.
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000396 char real_path_buff[PATH_MAX + 1];
397 if (realpath(RandomPath.c_str(), real_path_buff) == NULL) {
398 ::close(RandomFD);
399 ::unlink(RandomPath.c_str());
400 return error_code(errno, system_category());
401 }
402
403 result_path.set_size(0);
404 StringRef d(real_path_buff);
405 result_path.append(d.begin(), d.end());
406
407 result_fd = RandomFD;
Michael J. Spencer9d425e72010-12-04 18:45:32 +0000408 return success;
Michael J. Spencer3cb84ef2010-12-03 01:21:28 +0000409}
410
Michael J. Spencerbee0c382010-12-01 19:32:01 +0000411} // end namespace fs
Michael J. Spencerdffde992010-11-29 22:28:51 +0000412} // end namespace sys
413} // end namespace llvm