blob: 57f02be109471631219bc672f6bf23cdca88b334 [file] [log] [blame]
Charles Davis54c9eb62010-11-29 19:44:50 +00001//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
Mikhail Glushenkova5398362009-02-15 03:20:03 +00002//
Reid Spencer814ba572004-08-25 06:20:07 +00003// The LLVM Compiler Infrastructure
4//
Chris Lattnerf3ebc3f2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Mikhail Glushenkova5398362009-02-15 03:20:03 +00007//
Reid Spencer814ba572004-08-25 06:20:07 +00008//===----------------------------------------------------------------------===//
9//
10// This file implements the Unix specific portion of the Path class.
11//
12//===----------------------------------------------------------------------===//
13
14//===----------------------------------------------------------------------===//
15//=== WARNING: Implementation here must contain only generic UNIX code that
Reid Spencer6df221d2004-08-29 05:24:01 +000016//=== is guaranteed to work on *all* UNIX variants.
Reid Spencer814ba572004-08-25 06:20:07 +000017//===----------------------------------------------------------------------===//
18
19#include "Unix.h"
Reid Spencerd103e082004-12-27 06:17:15 +000020#if HAVE_SYS_STAT_H
Reid Spencer814ba572004-08-25 06:20:07 +000021#include <sys/stat.h>
Reid Spencerd103e082004-12-27 06:17:15 +000022#endif
23#if HAVE_FCNTL_H
Reid Spencer814ba572004-08-25 06:20:07 +000024#include <fcntl.h>
Reid Spencerd103e082004-12-27 06:17:15 +000025#endif
Chris Lattnerba98fca2008-04-01 06:25:23 +000026#ifdef HAVE_SYS_MMAN_H
27#include <sys/mman.h>
28#endif
29#ifdef HAVE_SYS_STAT_H
30#include <sys/stat.h>
31#endif
Reid Spencerd103e082004-12-27 06:17:15 +000032#if HAVE_UTIME_H
Reid Spencerc1d474f2004-11-14 22:08:36 +000033#include <utime.h>
Reid Spencerd103e082004-12-27 06:17:15 +000034#endif
35#if HAVE_TIME_H
Reid Spencer20540312004-12-24 06:29:42 +000036#include <time.h>
Reid Spencerd103e082004-12-27 06:17:15 +000037#endif
38#if HAVE_DIRENT_H
39# include <dirent.h>
40# define NAMLEN(dirent) strlen((dirent)->d_name)
41#else
42# define dirent direct
43# define NAMLEN(dirent) (dirent)->d_namlen
44# if HAVE_SYS_NDIR_H
45# include <sys/ndir.h>
46# endif
47# if HAVE_SYS_DIR_H
48# include <sys/dir.h>
49# endif
50# if HAVE_NDIR_H
51# include <ndir.h>
52# endif
53#endif
54
Chris Lattnere209be42008-03-03 02:55:43 +000055#if HAVE_DLFCN_H
56#include <dlfcn.h>
57#endif
58
Benjamin Kramer2a1131a2009-09-09 12:09:08 +000059#ifdef __APPLE__
60#include <mach-o/dyld.h>
61#endif
62
Sylvestre Ledru14ada942012-04-11 15:35:36 +000063// For GNU Hurd
64#if defined(__GNU__) && !defined(MAXPATHLEN)
65# define MAXPATHLEN 4096
66#endif
67
Reid Spencerd1ef1df2005-06-02 05:38:20 +000068// Put in a hack for Cygwin which falsely reports that the mkdtemp function
69// is available when it is not.
70#ifdef __CYGWIN__
71# undef HAVE_MKDTEMP
72#endif
Reid Spencer814ba572004-08-25 06:20:07 +000073
Reid Spencer29f83e02005-07-28 16:25:57 +000074namespace {
75inline bool lastIsSlash(const std::string& path) {
76 return !path.empty() && path[path.length() - 1] == '/';
77}
78
79}
80
Reid Spencer6df221d2004-08-29 05:24:01 +000081namespace llvm {
82using namespace sys;
Reid Spencer814ba572004-08-25 06:20:07 +000083
Daniel Dunbar5ea62002009-12-09 03:26:33 +000084const char sys::PathSeparator = ':';
Chris Lattner6fca9382008-02-27 06:17:10 +000085
Mikhail Glushenkovfcfaf512010-11-02 20:32:26 +000086StringRef Path::GetEXESuffix() {
Dan Gohmanbba85852010-11-02 20:52:47 +000087 return StringRef();
Mikhail Glushenkovfcfaf512010-11-02 20:32:26 +000088}
89
Jeffrey Yasskin5908f1e2009-12-17 21:02:39 +000090Path::Path(StringRef p)
Nick Lewyckyc38c1712008-05-11 17:37:40 +000091 : path(p) {}
92
93Path::Path(const char *StrStart, unsigned StrLen)
94 : path(StrStart, StrLen) {}
95
Chris Lattnerb56e07e2008-08-11 23:39:47 +000096Path&
Jeffrey Yasskin5908f1e2009-12-17 21:02:39 +000097Path::operator=(StringRef that) {
98 path.assign(that.data(), that.size());
Chris Lattnerb56e07e2008-08-11 23:39:47 +000099 return *this;
100}
101
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000102bool
Reid Spencer20540312004-12-24 06:29:42 +0000103Path::isValid() const {
Dan Gohmanc0a8bee2010-11-02 23:19:55 +0000104 // Empty paths are considered invalid here.
105 // This code doesn't check MAXPATHLEN because there's no need. Nothing in
106 // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't
107 // handle names longer than some limit, it'll report this on demand using
108 // ENAMETOLONG.
109 return !path.empty();
Reid Spencer20540312004-12-24 06:29:42 +0000110}
111
Reid Spencer6df221d2004-08-29 05:24:01 +0000112Path
Chris Lattner3c50fdf2009-02-19 05:34:35 +0000113Path::GetTemporaryDirectory(std::string *ErrMsg) {
Reid Spencer20540312004-12-24 06:29:42 +0000114#if defined(HAVE_MKDTEMP)
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000115 // The best way is with mkdtemp but that's not available on many systems,
Reid Spencer20540312004-12-24 06:29:42 +0000116 // Linux and FreeBSD have it. Others probably won't.
Dan Gohman32d51fa2010-11-02 22:50:10 +0000117 char pathname[] = "/tmp/llvm_XXXXXX";
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000118 if (0 == mkdtemp(pathname)) {
Dan Gohman6e05d6c2010-11-02 22:56:51 +0000119 MakeErrMsg(ErrMsg,
120 std::string(pathname) + ": can't create temporary directory");
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000121 return Path();
122 }
Dan Gohmanecc4d732010-11-03 00:01:23 +0000123 return Path(pathname);
Reid Spencer20540312004-12-24 06:29:42 +0000124#elif defined(HAVE_MKSTEMP)
125 // If no mkdtemp is available, mkstemp can be used to create a temporary file
126 // which is then removed and created as a directory. We prefer this over
127 // mktemp because of mktemp's inherent security and threading risks. We still
128 // have a slight race condition from the time the temporary file is created to
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000129 // the time it is re-created as a directoy.
Dan Gohman32d51fa2010-11-02 22:50:10 +0000130 char pathname[] = "/tmp/llvm_XXXXXX";
Reid Spencer20540312004-12-24 06:29:42 +0000131 int fd = 0;
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000132 if (-1 == (fd = mkstemp(pathname))) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000133 MakeErrMsg(ErrMsg,
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000134 std::string(pathname) + ": can't create temporary directory");
135 return Path();
136 }
Reid Spencer20540312004-12-24 06:29:42 +0000137 ::close(fd);
138 ::unlink(pathname); // start race condition, ignore errors
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000139 if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000140 MakeErrMsg(ErrMsg,
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000141 std::string(pathname) + ": can't create temporary directory");
142 return Path();
143 }
Dan Gohmanecc4d732010-11-03 00:01:23 +0000144 return Path(pathname);
Reid Spencer20540312004-12-24 06:29:42 +0000145#elif defined(HAVE_MKTEMP)
146 // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have
147 // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable
148 // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing
149 // the XXXXXX with the pid of the process and a letter. That leads to only
150 // twenty six temporary files that can be generated.
Dan Gohman32d51fa2010-11-02 22:50:10 +0000151 char pathname[] = "/tmp/llvm_XXXXXX";
Reid Spencer20540312004-12-24 06:29:42 +0000152 char *TmpName = ::mktemp(pathname);
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000153 if (TmpName == 0) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000154 MakeErrMsg(ErrMsg,
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000155 std::string(TmpName) + ": can't create unique directory name");
156 return Path();
157 }
158 if (-1 == ::mkdir(TmpName, S_IRWXU)) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000159 MakeErrMsg(ErrMsg,
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000160 std::string(TmpName) + ": can't create temporary directory");
161 return Path();
162 }
Dan Gohmanecc4d732010-11-03 00:01:23 +0000163 return Path(TmpName);
Reid Spencer20540312004-12-24 06:29:42 +0000164#else
165 // This is the worst case implementation. tempnam(3) leaks memory unless its
166 // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread
167 // issues. The mktemp(3) function doesn't have enough variability in the
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000168 // temporary name generated. So, we provide our own implementation that
Reid Spencer20540312004-12-24 06:29:42 +0000169 // increments an integer from a random number seeded by the current time. This
170 // should be sufficiently unique that we don't have many collisions between
171 // processes. Generally LLVM processes don't run very long and don't use very
172 // many temporary files so this shouldn't be a big issue for LLVM.
173 static time_t num = ::time(0);
174 char pathname[MAXPATHLEN];
175 do {
176 num++;
177 sprintf(pathname, "/tmp/llvm_%010u", unsigned(num));
178 } while ( 0 == access(pathname, F_OK ) );
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000179 if (-1 == ::mkdir(pathname, S_IRWXU)) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000180 MakeErrMsg(ErrMsg,
Reid Spencer6ba87bb2006-08-22 19:01:30 +0000181 std::string(pathname) + ": can't create temporary directory");
182 return Path();
Reid Spencere4ca7222006-08-23 20:34:57 +0000183 }
Dan Gohmanecc4d732010-11-03 00:01:23 +0000184 return Path(pathname);
Reid Spencer20540312004-12-24 06:29:42 +0000185#endif
186}
187
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000188Path
Ted Kremenek14020702007-12-18 22:07:33 +0000189Path::GetCurrentDirectory() {
190 char pathname[MAXPATHLEN];
Nick Lewycky38b9b562011-07-29 04:42:39 +0000191 if (!getcwd(pathname, MAXPATHLEN)) {
192 assert(false && "Could not query current working directory.");
Dan Gohman5cae1032010-08-04 01:39:08 +0000193 return Path();
Ted Kremenek14020702007-12-18 22:07:33 +0000194 }
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000195
Ted Kremenek14020702007-12-18 22:07:33 +0000196 return Path(pathname);
197}
Reid Spenceraf48d862005-07-08 03:08:58 +0000198
Eric Christopher22738d02012-08-06 20:52:18 +0000199#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
Sylvestre Ledru12c44e52012-09-26 08:30:35 +0000200 defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \
201 defined(__linux__) || defined(__CYGWIN__)
Chris Lattnerbab44172009-03-02 22:17:15 +0000202static int
203test_dir(char buf[PATH_MAX], char ret[PATH_MAX],
204 const char *dir, const char *bin)
205{
Bill Wendling09f17a82009-05-30 01:09:53 +0000206 struct stat sb;
Chris Lattnerbab44172009-03-02 22:17:15 +0000207
Dan Gohman9e857442010-09-02 18:24:46 +0000208 snprintf(buf, PATH_MAX, "%s/%s", dir, bin);
Bill Wendling09f17a82009-05-30 01:09:53 +0000209 if (realpath(buf, ret) == NULL)
210 return (1);
211 if (stat(buf, &sb) != 0)
212 return (1);
213
214 return (0);
Chris Lattnerbab44172009-03-02 22:17:15 +0000215}
216
217static char *
218getprogpath(char ret[PATH_MAX], const char *bin)
219{
Bill Wendling09f17a82009-05-30 01:09:53 +0000220 char *pv, *s, *t, buf[PATH_MAX];
Chris Lattnerbab44172009-03-02 22:17:15 +0000221
Bill Wendling09f17a82009-05-30 01:09:53 +0000222 /* First approach: absolute path. */
223 if (bin[0] == '/') {
224 if (test_dir(buf, ret, "/", bin) == 0)
225 return (ret);
226 return (NULL);
227 }
Chris Lattnerbab44172009-03-02 22:17:15 +0000228
Bill Wendling09f17a82009-05-30 01:09:53 +0000229 /* Second approach: relative path. */
230 if (strchr(bin, '/') != NULL) {
231 if (getcwd(buf, PATH_MAX) == NULL)
232 return (NULL);
233 if (test_dir(buf, ret, buf, bin) == 0)
234 return (ret);
235 return (NULL);
236 }
Chris Lattnerbab44172009-03-02 22:17:15 +0000237
Bill Wendling09f17a82009-05-30 01:09:53 +0000238 /* Third approach: $PATH */
239 if ((pv = getenv("PATH")) == NULL)
240 return (NULL);
241 s = pv = strdup(pv);
242 if (pv == NULL)
243 return (NULL);
244 while ((t = strsep(&s, ":")) != NULL) {
245 if (test_dir(buf, ret, t, bin) == 0) {
246 free(pv);
247 return (ret);
248 }
249 }
250 free(pv);
251 return (NULL);
Chris Lattnerbab44172009-03-02 22:17:15 +0000252}
Anton Korobeynikov45470772012-03-26 12:05:51 +0000253#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
Chris Lattnerbab44172009-03-02 22:17:15 +0000254
Chris Lattnere209be42008-03-03 02:55:43 +0000255/// GetMainExecutable - Return the path to the main executable, given the
256/// value of argv[0] from program startup.
257Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
Benjamin Kramer2a1131a2009-09-09 12:09:08 +0000258#if defined(__APPLE__)
259 // On OS X the executable path is saved to the stack by dyld. Reading it
260 // from there is much faster than calling dladdr, especially for large
261 // binaries with symbols.
262 char exe_path[MAXPATHLEN];
263 uint32_t size = sizeof(exe_path);
264 if (_NSGetExecutablePath(exe_path, &size) == 0) {
265 char link_path[MAXPATHLEN];
Kovarththanan Rajaratnam4b9f0b62009-11-29 17:19:48 +0000266 if (realpath(exe_path, link_path))
Dan Gohman44e24e52010-11-02 22:07:47 +0000267 return Path(link_path);
Benjamin Kramer2a1131a2009-09-09 12:09:08 +0000268 }
Eric Christopher22738d02012-08-06 20:52:18 +0000269#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
Anton Korobeynikov45470772012-03-26 12:05:51 +0000270 defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__)
Chris Lattnerbab44172009-03-02 22:17:15 +0000271 char exe_path[PATH_MAX];
272
273 if (getprogpath(exe_path, argv0) != NULL)
Dan Gohman44e24e52010-11-02 22:07:47 +0000274 return Path(exe_path);
Chris Lattnerbab44172009-03-02 22:17:15 +0000275#elif defined(__linux__) || defined(__CYGWIN__)
Chris Lattner02e727f2008-03-13 05:22:05 +0000276 char exe_path[MAXPATHLEN];
Sylvestre Ledru12c44e52012-09-26 08:30:35 +0000277 StringRef aPath("/proc/self/exe");
278 if (sys::fs::exists(aPath)) {
279 // /proc is not always mounted under Linux (chroot for example).
280 ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
281 if (len >= 0)
282 return Path(StringRef(exe_path, len));
283 } else {
284 // Fall back to the classical detection.
285 if (getprogpath(exe_path, argv0) != NULL)
286 return Path(exe_path);
287 }
Chris Lattner02e727f2008-03-13 05:22:05 +0000288#elif defined(HAVE_DLFCN_H)
Chris Lattnere209be42008-03-03 02:55:43 +0000289 // Use dladdr to get executable path if available.
Chris Lattnere209be42008-03-03 02:55:43 +0000290 Dl_info DLInfo;
291 int err = dladdr(MainAddr, &DLInfo);
Chris Lattner3c50fdf2009-02-19 05:34:35 +0000292 if (err == 0)
293 return Path();
Bill Wendling09f17a82009-05-30 01:09:53 +0000294
Chris Lattner3c50fdf2009-02-19 05:34:35 +0000295 // If the filename is a symlink, we need to resolve and return the location of
296 // the actual executable.
297 char link_path[MAXPATHLEN];
Kovarththanan Rajaratnam4b9f0b62009-11-29 17:19:48 +0000298 if (realpath(DLInfo.dli_fname, link_path))
Dan Gohman44e24e52010-11-02 22:07:47 +0000299 return Path(link_path);
Dan Gohmand51b4312010-09-07 18:26:49 +0000300#else
301#error GetMainExecutable is not implemented on this host yet.
Chris Lattnere209be42008-03-03 02:55:43 +0000302#endif
303 return Path();
304}
305
Reid Spencerae9bbda2004-09-11 04:55:08 +0000306bool
Reid Spencer6df221d2004-08-29 05:24:01 +0000307Path::exists() const {
308 return 0 == access(path.c_str(), F_OK );
309}
310
311bool
Ted Kremenek74db0422007-12-18 19:46:22 +0000312Path::isDirectory() const {
313 struct stat buf;
314 if (0 != stat(path.c_str(), &buf))
315 return false;
Evan Cheng139edad2010-10-07 22:05:57 +0000316 return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false;
Ted Kremenek74db0422007-12-18 19:46:22 +0000317}
318
319bool
Rafael Espindola559b8fb2010-11-07 04:36:50 +0000320Path::isSymLink() const {
321 struct stat buf;
322 if (0 != lstat(path.c_str(), &buf))
323 return false;
324 return S_ISLNK(buf.st_mode);
325}
326
327
328bool
Reid Spencer5b891e92005-07-07 18:21:42 +0000329Path::canRead() const {
Dan Gohman36700652009-07-28 23:22:01 +0000330 return 0 == access(path.c_str(), R_OK);
Reid Spencer6df221d2004-08-29 05:24:01 +0000331}
332
333bool
Reid Spencer5b891e92005-07-07 18:21:42 +0000334Path::canWrite() const {
Dan Gohman36700652009-07-28 23:22:01 +0000335 return 0 == access(path.c_str(), W_OK);
Reid Spencer6df221d2004-08-29 05:24:01 +0000336}
337
338bool
Edward O'Callaghan746782d2009-11-25 06:32:19 +0000339Path::isRegularFile() const {
Dan Gohman39027c42010-03-30 20:04:57 +0000340 // Get the status so we can determine if it's a file or directory
Edward O'Callaghandddf1342009-11-24 15:19:10 +0000341 struct stat buf;
Edward O'Callaghandddf1342009-11-24 15:19:10 +0000342
Daniel Dunbar7402c472009-11-24 19:03:33 +0000343 if (0 != stat(path.c_str(), &buf))
Edward O'Callaghandddf1342009-11-24 15:19:10 +0000344 return false;
Edward O'Callaghandddf1342009-11-24 15:19:10 +0000345
Edward O'Callaghan746782d2009-11-25 06:32:19 +0000346 if (S_ISREG(buf.st_mode))
347 return true;
348
349 return false;
Edward O'Callaghandddf1342009-11-24 15:19:10 +0000350}
351
352bool
Reid Spencer5b891e92005-07-07 18:21:42 +0000353Path::canExecute() const {
Reid Spencer2d85f562005-07-08 17:46:10 +0000354 if (0 != access(path.c_str(), R_OK | X_OK ))
355 return false;
Reid Spencerceeb9182007-04-07 18:52:17 +0000356 struct stat buf;
357 if (0 != stat(path.c_str(), &buf))
358 return false;
359 if (!S_ISREG(buf.st_mode))
Misha Brukmana9a8c1b2005-04-20 15:33:22 +0000360 return false;
Reid Spencer2d85f562005-07-08 17:46:10 +0000361 return true;
Reid Spencer6df221d2004-08-29 05:24:01 +0000362}
363
Reid Spencerceeb9182007-04-07 18:52:17 +0000364const FileStatus *
365PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
366 if (!fsIsValid || update) {
Reid Spencer0f92f0e2007-03-29 16:43:20 +0000367 struct stat buf;
Reid Spencer200c6f92007-03-29 19:05:44 +0000368 if (0 != stat(path.c_str(), &buf)) {
369 MakeErrMsg(ErrStr, path + ": can't get status of file");
370 return 0;
371 }
Reid Spencerceeb9182007-04-07 18:52:17 +0000372 status.fileSize = buf.st_size;
373 status.modTime.fromEpochTime(buf.st_mtime);
374 status.mode = buf.st_mode;
375 status.user = buf.st_uid;
376 status.group = buf.st_gid;
377 status.uniqueID = uint64_t(buf.st_ino);
378 status.isDir = S_ISDIR(buf.st_mode);
379 status.isFile = S_ISREG(buf.st_mode);
380 fsIsValid = true;
Reid Spencer0f92f0e2007-03-29 16:43:20 +0000381 }
Reid Spencerceeb9182007-04-07 18:52:17 +0000382 return &status;
Reid Spencerc1d474f2004-11-14 22:08:36 +0000383}
384
Chris Lattner48572532006-07-28 22:03:44 +0000385static bool AddPermissionBits(const Path &File, int bits) {
Reid Spencer94bf2262004-12-13 19:59:50 +0000386 // Get the umask value from the operating system. We want to use it
387 // when changing the file's permissions. Since calling umask() sets
388 // the umask and returns its old value, we must call it a second
389 // time to reset it to the user's preference.
390 int mask = umask(0777); // The arg. to umask is arbitrary.
391 umask(mask); // Restore the umask.
392
393 // Get the file's current mode.
Reid Spencerceeb9182007-04-07 18:52:17 +0000394 struct stat buf;
Chris Lattnerc521f542009-08-23 22:45:37 +0000395 if (0 != stat(File.c_str(), &buf))
Reid Spencer94bf2262004-12-13 19:59:50 +0000396 return false;
Reid Spencerceeb9182007-04-07 18:52:17 +0000397 // Change the file to have whichever permissions bits from 'bits'
398 // that the umask would not disable.
399 if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1)
400 return false;
Reid Spencer94bf2262004-12-13 19:59:50 +0000401 return true;
402}
403
Reid Spencer9d2f19c2006-08-22 23:27:23 +0000404bool Path::makeReadableOnDisk(std::string* ErrMsg) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000405 if (!AddPermissionBits(*this, 0444))
Reid Spencer879ed5a2006-08-23 07:30:48 +0000406 return MakeErrMsg(ErrMsg, path + ": can't make file readable");
Reid Spencer9d2f19c2006-08-22 23:27:23 +0000407 return false;
Reid Spencer94bf2262004-12-13 19:59:50 +0000408}
409
Reid Spencer9d2f19c2006-08-22 23:27:23 +0000410bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
Reid Spencer879ed5a2006-08-23 07:30:48 +0000411 if (!AddPermissionBits(*this, 0222))
412 return MakeErrMsg(ErrMsg, path + ": can't make file writable");
Reid Spencer9d2f19c2006-08-22 23:27:23 +0000413 return false;
Reid Spencer94bf2262004-12-13 19:59:50 +0000414}
415
Reid Spencerc1d474f2004-11-14 22:08:36 +0000416bool
Reid Spencer51edba12006-08-23 06:56:27 +0000417Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
Reid Spencerc1d474f2004-11-14 22:08:36 +0000418 DIR* direntries = ::opendir(path.c_str());
Reid Spencer879ed5a2006-08-23 07:30:48 +0000419 if (direntries == 0)
420 return MakeErrMsg(ErrMsg, path + ": can't open directory");
Reid Spencerc1d474f2004-11-14 22:08:36 +0000421
Reid Spencer29f83e02005-07-28 16:25:57 +0000422 std::string dirPath = path;
423 if (!lastIsSlash(dirPath))
424 dirPath += '/';
425
Reid Spencerc1d474f2004-11-14 22:08:36 +0000426 result.clear();
427 struct dirent* de = ::readdir(direntries);
Misha Brukman1001aea2005-04-20 04:04:07 +0000428 for ( ; de != 0; de = ::readdir(direntries)) {
Reid Spencerc1d474f2004-11-14 22:08:36 +0000429 if (de->d_name[0] != '.') {
Reid Spencer29f83e02005-07-28 16:25:57 +0000430 Path aPath(dirPath + (const char*)de->d_name);
Chris Lattner0b2890e2006-07-07 21:21:06 +0000431 struct stat st;
432 if (0 != lstat(aPath.path.c_str(), &st)) {
433 if (S_ISLNK(st.st_mode))
Misha Brukman1001aea2005-04-20 04:04:07 +0000434 continue; // dangling symlink -- ignore
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000435 return MakeErrMsg(ErrMsg,
Reid Spencer879ed5a2006-08-23 07:30:48 +0000436 aPath.path + ": can't determine file object type");
Misha Brukman1001aea2005-04-20 04:04:07 +0000437 }
Reid Spencer91f505e2004-11-16 06:15:19 +0000438 result.insert(aPath);
Reid Spencerc1d474f2004-11-14 22:08:36 +0000439 }
Reid Spencerc1d474f2004-11-14 22:08:36 +0000440 }
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000441
Reid Spencerc1d474f2004-11-14 22:08:36 +0000442 closedir(direntries);
Reid Spencer51edba12006-08-23 06:56:27 +0000443 return false;
Reid Spencerfb1f7352004-11-09 20:26:31 +0000444}
445
Reid Spencer6df221d2004-08-29 05:24:01 +0000446bool
Jeffrey Yasskin5908f1e2009-12-17 21:02:39 +0000447Path::set(StringRef a_path) {
Reid Spencerc9c04732005-07-07 23:21:43 +0000448 if (a_path.empty())
Reid Spencer6df221d2004-08-29 05:24:01 +0000449 return false;
Reid Spencer6df221d2004-08-29 05:24:01 +0000450 path = a_path;
Reid Spencer6df221d2004-08-29 05:24:01 +0000451 return true;
452}
453
454bool
Jeffrey Yasskin5908f1e2009-12-17 21:02:39 +0000455Path::appendComponent(StringRef name) {
Reid Spencerc9c04732005-07-07 23:21:43 +0000456 if (name.empty())
Reid Spencer6df221d2004-08-29 05:24:01 +0000457 return false;
Reid Spencer29f83e02005-07-28 16:25:57 +0000458 if (!lastIsSlash(path))
459 path += '/';
Reid Spencerc9c04732005-07-07 23:21:43 +0000460 path += name;
Reid Spencer6df221d2004-08-29 05:24:01 +0000461 return true;
462}
463
464bool
Reid Spencerc9c04732005-07-07 23:21:43 +0000465Path::eraseComponent() {
Reid Spencer6df221d2004-08-29 05:24:01 +0000466 size_t slashpos = path.rfind('/',path.size());
Reid Spencerc9c04732005-07-07 23:21:43 +0000467 if (slashpos == 0 || slashpos == std::string::npos) {
468 path.erase();
469 return true;
470 }
Reid Spencer6df221d2004-08-29 05:24:01 +0000471 if (slashpos == path.size() - 1)
472 slashpos = path.rfind('/',slashpos-1);
Reid Spencerc9c04732005-07-07 23:21:43 +0000473 if (slashpos == std::string::npos) {
474 path.erase();
475 return true;
476 }
Reid Spencer6df221d2004-08-29 05:24:01 +0000477 path.erase(slashpos);
478 return true;
479}
480
481bool
Reid Spencerc9c04732005-07-07 23:21:43 +0000482Path::eraseSuffix() {
Reid Spencer6df221d2004-08-29 05:24:01 +0000483 size_t dotpos = path.rfind('.',path.size());
484 size_t slashpos = path.rfind('/',path.size());
Jeff Cohen4c241442005-07-08 04:49:16 +0000485 if (dotpos != std::string::npos) {
Jeff Cohen5b106d02005-07-09 18:42:02 +0000486 if (slashpos == std::string::npos || dotpos > slashpos+1) {
Jeff Cohen4c241442005-07-08 04:49:16 +0000487 path.erase(dotpos, path.size()-dotpos);
Jeff Cohenf5067762005-07-08 05:02:13 +0000488 return true;
Jeff Cohen4c241442005-07-08 04:49:16 +0000489 }
Reid Spencer6df221d2004-08-29 05:24:01 +0000490 }
Jeff Cohen4c241442005-07-08 04:49:16 +0000491 return false;
Reid Spencer6df221d2004-08-29 05:24:01 +0000492}
493
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000494static bool createDirectoryHelper(char* beg, char* end, bool create_parents) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000495
Dan Gohman4723c102009-07-29 00:02:58 +0000496 if (access(beg, R_OK | W_OK) == 0)
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000497 return false;
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000498
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000499 if (create_parents) {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000500
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000501 char* c = end;
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000502
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000503 for (; c != beg; --c)
504 if (*c == '/') {
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000505
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000506 // Recurse to handling the parent directory.
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000507 *c = '\0';
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000508 bool x = createDirectoryHelper(beg, c, create_parents);
509 *c = '/';
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000510
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000511 // Return if we encountered an error.
512 if (x)
513 return true;
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000514
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000515 break;
516 }
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000517 }
518
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000519 return mkdir(beg, S_IRWXU | S_IRWXG) != 0;
520}
521
Reid Spencer6df221d2004-08-29 05:24:01 +0000522bool
Reid Spencer8db84422006-08-23 00:39:35 +0000523Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) {
Reid Spencer6df221d2004-08-29 05:24:01 +0000524 // Get a writeable copy of the path name
Dan Gohmana47bfef2010-11-02 22:55:34 +0000525 std::string pathname(path);
Reid Spencer6df221d2004-08-29 05:24:01 +0000526
527 // Null-terminate the last component
Evan Cheng86cb3182008-05-05 18:30:58 +0000528 size_t lastchar = path.length() - 1 ;
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000529
Ted Kremenek1d0436c2008-04-03 16:11:31 +0000530 if (pathname[lastchar] != '/')
531 ++lastchar;
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000532
Dan Gohmanf6e13ce2010-11-02 22:41:19 +0000533 pathname[lastchar] = '\0';
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000534
Dan Gohmana47bfef2010-11-02 22:55:34 +0000535 if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents))
Dan Gohmana8b63152010-11-02 23:16:26 +0000536 return MakeErrMsg(ErrMsg, pathname + ": can't create directory");
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000537
Reid Spencer8db84422006-08-23 00:39:35 +0000538 return false;
Reid Spencer6df221d2004-08-29 05:24:01 +0000539}
540
541bool
Reid Spencer8db84422006-08-23 00:39:35 +0000542Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
Reid Spencerf66d9322004-12-15 01:50:13 +0000543 // Make this into a unique file name
Reid Spencere4ca7222006-08-23 20:34:57 +0000544 if (makeUnique( reuse_current, ErrMsg ))
545 return true;
Reid Spencerf66d9322004-12-15 01:50:13 +0000546
547 // create the file
Reid Spencer8db84422006-08-23 00:39:35 +0000548 int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000549 if (fd < 0)
Reid Spencer879ed5a2006-08-23 07:30:48 +0000550 return MakeErrMsg(ErrMsg, path + ": can't create temporary file");
Reid Spencer8db84422006-08-23 00:39:35 +0000551 ::close(fd);
Reid Spencerf66d9322004-12-15 01:50:13 +0000552 return false;
Reid Spencerfb1f7352004-11-09 20:26:31 +0000553}
554
555bool
Chris Lattner3cec1092006-07-28 22:29:50 +0000556Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
Dan Gohman39027c42010-03-30 20:04:57 +0000557 // Get the status so we can determine if it's a file or directory.
Reid Spencerceeb9182007-04-07 18:52:17 +0000558 struct stat buf;
559 if (0 != stat(path.c_str(), &buf)) {
560 MakeErrMsg(ErrStr, path + ": can't get status of file");
Chris Lattner3cec1092006-07-28 22:29:50 +0000561 return true;
Reid Spencerceeb9182007-04-07 18:52:17 +0000562 }
563
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000564 // Note: this check catches strange situations. In all cases, LLVM should
565 // only be involved in the creation and deletion of regular files. This
566 // check ensures that what we're trying to erase is a regular file. It
567 // effectively prevents LLVM from erasing things like /dev/null, any block
568 // special file, or other things that aren't "regular" files.
Reid Spencerceeb9182007-04-07 18:52:17 +0000569 if (S_ISREG(buf.st_mode)) {
570 if (unlink(path.c_str()) != 0)
571 return MakeErrMsg(ErrStr, path + ": can't destroy file");
572 return false;
573 }
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000574
Reid Spencerceeb9182007-04-07 18:52:17 +0000575 if (!S_ISDIR(buf.st_mode)) {
576 if (ErrStr) *ErrStr = "not a file or directory";
577 return true;
578 }
Reid Spencer200c6f92007-03-29 19:05:44 +0000579
Chris Lattner3cec1092006-07-28 22:29:50 +0000580 if (remove_contents) {
581 // Recursively descend the directory to remove its contents.
582 std::string cmd = "/bin/rm -rf " + path;
Mikhail Glushenkov58a1a8e2009-02-15 03:20:32 +0000583 if (system(cmd.c_str()) != 0) {
584 MakeErrMsg(ErrStr, path + ": failed to recursively remove directory.");
585 return true;
586 }
Chris Lattner3cec1092006-07-28 22:29:50 +0000587 return false;
588 }
589
590 // Otherwise, try to just remove the one directory.
Dan Gohmana47bfef2010-11-02 22:55:34 +0000591 std::string pathname(path);
Evan Cheng86cb3182008-05-05 18:30:58 +0000592 size_t lastchar = path.length() - 1;
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000593 if (pathname[lastchar] == '/')
Dan Gohmanf6e13ce2010-11-02 22:41:19 +0000594 pathname[lastchar] = '\0';
Chris Lattner3cec1092006-07-28 22:29:50 +0000595 else
Dan Gohmanf6e13ce2010-11-02 22:41:19 +0000596 pathname[lastchar+1] = '\0';
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000597
Dan Gohmana47bfef2010-11-02 22:55:34 +0000598 if (rmdir(pathname.c_str()) != 0)
599 return MakeErrMsg(ErrStr, pathname + ": can't erase directory");
Chris Lattner3cec1092006-07-28 22:29:50 +0000600 return false;
Reid Spencer6df221d2004-08-29 05:24:01 +0000601}
602
603bool
Reid Spencer879ed5a2006-08-23 07:30:48 +0000604Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
Reid Spencerc9c04732005-07-07 23:21:43 +0000605 if (0 != ::rename(path.c_str(), newName.c_str()))
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000606 return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" +
Chris Lattnerc521f542009-08-23 22:45:37 +0000607 newName.str() + "'");
Reid Spencer879ed5a2006-08-23 07:30:48 +0000608 return false;
Reid Spencerc1d474f2004-11-14 22:08:36 +0000609}
610
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000611bool
Chris Lattner60c50642006-07-28 22:36:17 +0000612Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
Reid Spencerc1d474f2004-11-14 22:08:36 +0000613 struct utimbuf utb;
614 utb.actime = si.modTime.toPosixTime();
615 utb.modtime = utb.actime;
616 if (0 != ::utime(path.c_str(),&utb))
Reid Spencere4ca7222006-08-23 20:34:57 +0000617 return MakeErrMsg(ErrStr, path + ": can't set file modification time");
Reid Spencerc1d474f2004-11-14 22:08:36 +0000618 if (0 != ::chmod(path.c_str(),si.mode))
Reid Spencere4ca7222006-08-23 20:34:57 +0000619 return MakeErrMsg(ErrStr, path + ": can't set mode");
Chris Lattner60c50642006-07-28 22:36:17 +0000620 return false;
Reid Spencer6df221d2004-08-29 05:24:01 +0000621}
622
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000623bool
Reid Spencere4ca7222006-08-23 20:34:57 +0000624Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
Michael J. Spencer58df2e02011-01-10 02:34:23 +0000625 bool Exists;
626 if (reuse_current && (fs::exists(path, Exists) || !Exists))
Reid Spencere4ca7222006-08-23 20:34:57 +0000627 return false; // File doesn't exist already, just use it!
Reid Spencerf66d9322004-12-15 01:50:13 +0000628
Mikhail Glushenkova5398362009-02-15 03:20:03 +0000629 // Append an XXXXXX pattern to the end of the file for use with mkstemp,
Reid Spencerf66d9322004-12-15 01:50:13 +0000630 // mktemp or our own implementation.
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000631 // This uses std::vector instead of SmallVector to avoid a dependence on
632 // libSupport. And performance isn't critical here.
633 std::vector<char> Buf;
634 Buf.resize(path.size()+8);
Dan Gohman34570612010-04-19 16:33:28 +0000635 char *FNBuffer = &Buf[0];
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000636 path.copy(FNBuffer,path.size());
Michael J. Spencer0d771ed2011-01-11 01:21:55 +0000637 bool isdir;
638 if (!fs::is_directory(path, isdir) && isdir)
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000639 strcpy(FNBuffer+path.size(), "/XXXXXX");
Devang Patelcbfc1a42008-07-24 00:35:38 +0000640 else
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000641 strcpy(FNBuffer+path.size(), "-XXXXXX");
Reid Spencerf66d9322004-12-15 01:50:13 +0000642
643#if defined(HAVE_MKSTEMP)
644 int TempFD;
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000645 if ((TempFD = mkstemp(FNBuffer)) == -1)
Reid Spencere4ca7222006-08-23 20:34:57 +0000646 return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
Reid Spencerf66d9322004-12-15 01:50:13 +0000647
648 // We don't need to hold the temp file descriptor... we will trust that no one
649 // will overwrite/delete the file before we can open it again.
650 close(TempFD);
651
652 // Save the name
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000653 path = FNBuffer;
Chad Rosier30c34632011-07-05 18:55:31 +0000654
655 // By default mkstemp sets the mode to 0600, so update mode bits now.
656 AddPermissionBits (*this, 0666);
Reid Spencerf66d9322004-12-15 01:50:13 +0000657#elif defined(HAVE_MKTEMP)
658 // If we don't have mkstemp, use the old and obsolete mktemp function.
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000659 if (mktemp(FNBuffer) == 0)
Reid Spencere4ca7222006-08-23 20:34:57 +0000660 return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
Reid Spencerf66d9322004-12-15 01:50:13 +0000661
662 // Save the name
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000663 path = FNBuffer;
Reid Spencerf66d9322004-12-15 01:50:13 +0000664#else
665 // Okay, looks like we have to do it all by our lonesome.
666 static unsigned FCounter = 0;
Chris Lattnercda39c42010-07-12 00:09:55 +0000667 // Try to initialize with unique value.
668 if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8;
669 char* pos = strstr(FNBuffer, "XXXXXX");
670 do {
671 if (++FCounter > 0xFFFFFF) {
672 return MakeErrMsg(ErrMsg,
673 path + ": can't make unique filename: too many files");
674 }
675 sprintf(pos, "%06X", FCounter);
Dan Gohmana84dc0c2010-04-19 15:54:44 +0000676 path = FNBuffer;
Chris Lattnercda39c42010-07-12 00:09:55 +0000677 } while (exists());
678 // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit
679 // LLVM.
Reid Spencerf66d9322004-12-15 01:50:13 +0000680#endif
Reid Spencere4ca7222006-08-23 20:34:57 +0000681 return false;
682}
Reid Spencere4ca7222006-08-23 20:34:57 +0000683} // end llvm namespace