1218885Sdim//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file implements the Unix specific portion of the Path class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim//===----------------------------------------------------------------------===//
15218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that
16218885Sdim//===          is guaranteed to work on *all* UNIX variants.
17218885Sdim//===----------------------------------------------------------------------===//
18218885Sdim
19218885Sdim#include "Unix.h"
20218885Sdim#if HAVE_SYS_STAT_H
21218885Sdim#include <sys/stat.h>
22218885Sdim#endif
23218885Sdim#if HAVE_FCNTL_H
24218885Sdim#include <fcntl.h>
25218885Sdim#endif
26218885Sdim#ifdef HAVE_SYS_MMAN_H
27218885Sdim#include <sys/mman.h>
28218885Sdim#endif
29218885Sdim#ifdef HAVE_SYS_STAT_H
30218885Sdim#include <sys/stat.h>
31218885Sdim#endif
32218885Sdim#if HAVE_UTIME_H
33218885Sdim#include <utime.h>
34218885Sdim#endif
35218885Sdim#if HAVE_TIME_H
36218885Sdim#include <time.h>
37218885Sdim#endif
38218885Sdim#if HAVE_DIRENT_H
39218885Sdim# include <dirent.h>
40218885Sdim# define NAMLEN(dirent) strlen((dirent)->d_name)
41218885Sdim#else
42218885Sdim# define dirent direct
43218885Sdim# define NAMLEN(dirent) (dirent)->d_namlen
44218885Sdim# if HAVE_SYS_NDIR_H
45218885Sdim#  include <sys/ndir.h>
46218885Sdim# endif
47218885Sdim# if HAVE_SYS_DIR_H
48218885Sdim#  include <sys/dir.h>
49218885Sdim# endif
50218885Sdim# if HAVE_NDIR_H
51218885Sdim#  include <ndir.h>
52218885Sdim# endif
53218885Sdim#endif
54218885Sdim
55218885Sdim#if HAVE_DLFCN_H
56218885Sdim#include <dlfcn.h>
57218885Sdim#endif
58218885Sdim
59218885Sdim#ifdef __APPLE__
60218885Sdim#include <mach-o/dyld.h>
61218885Sdim#endif
62218885Sdim
63234353Sdim// For GNU Hurd
64234353Sdim#if defined(__GNU__) && !defined(MAXPATHLEN)
65234353Sdim# define MAXPATHLEN 4096
66234353Sdim#endif
67234353Sdim
68218885Sdim// Put in a hack for Cygwin which falsely reports that the mkdtemp function
69218885Sdim// is available when it is not.
70218885Sdim#ifdef __CYGWIN__
71218885Sdim# undef HAVE_MKDTEMP
72218885Sdim#endif
73218885Sdim
74218885Sdimnamespace {
75218885Sdiminline bool lastIsSlash(const std::string& path) {
76218885Sdim  return !path.empty() && path[path.length() - 1] == '/';
77218885Sdim}
78218885Sdim
79218885Sdim}
80218885Sdim
81218885Sdimnamespace llvm {
82218885Sdimusing namespace sys;
83218885Sdim
84218885Sdimconst char sys::PathSeparator = ':';
85218885Sdim
86218885SdimStringRef Path::GetEXESuffix() {
87218885Sdim  return StringRef();
88218885Sdim}
89218885Sdim
90218885SdimPath::Path(StringRef p)
91218885Sdim  : path(p) {}
92218885Sdim
93218885SdimPath::Path(const char *StrStart, unsigned StrLen)
94218885Sdim  : path(StrStart, StrLen) {}
95218885Sdim
96218885SdimPath&
97218885SdimPath::operator=(StringRef that) {
98218885Sdim  path.assign(that.data(), that.size());
99218885Sdim  return *this;
100218885Sdim}
101218885Sdim
102218885Sdimbool
103218885SdimPath::isValid() const {
104218885Sdim  // Empty paths are considered invalid here.
105218885Sdim  // This code doesn't check MAXPATHLEN because there's no need. Nothing in
106218885Sdim  // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't
107218885Sdim  // handle names longer than some limit, it'll report this on demand using
108218885Sdim  // ENAMETOLONG.
109218885Sdim  return !path.empty();
110218885Sdim}
111218885Sdim
112218885Sdimbool
113218885SdimPath::isAbsolute(const char *NameStart, unsigned NameLen) {
114218885Sdim  assert(NameStart);
115218885Sdim  if (NameLen == 0)
116218885Sdim    return false;
117218885Sdim  return NameStart[0] == '/';
118218885Sdim}
119218885Sdim
120218885Sdimbool
121218885SdimPath::isAbsolute() const {
122218885Sdim  if (path.empty())
123218885Sdim    return false;
124218885Sdim  return path[0] == '/';
125218885Sdim}
126218885Sdim
127218885SdimPath
128218885SdimPath::GetRootDirectory() {
129218885Sdim  Path result;
130218885Sdim  result.set("/");
131218885Sdim  return result;
132218885Sdim}
133218885Sdim
134218885SdimPath
135218885SdimPath::GetTemporaryDirectory(std::string *ErrMsg) {
136218885Sdim#if defined(HAVE_MKDTEMP)
137218885Sdim  // The best way is with mkdtemp but that's not available on many systems,
138218885Sdim  // Linux and FreeBSD have it. Others probably won't.
139218885Sdim  char pathname[] = "/tmp/llvm_XXXXXX";
140218885Sdim  if (0 == mkdtemp(pathname)) {
141218885Sdim    MakeErrMsg(ErrMsg,
142218885Sdim               std::string(pathname) + ": can't create temporary directory");
143218885Sdim    return Path();
144218885Sdim  }
145218885Sdim  return Path(pathname);
146218885Sdim#elif defined(HAVE_MKSTEMP)
147218885Sdim  // If no mkdtemp is available, mkstemp can be used to create a temporary file
148218885Sdim  // which is then removed and created as a directory. We prefer this over
149218885Sdim  // mktemp because of mktemp's inherent security and threading risks. We still
150218885Sdim  // have a slight race condition from the time the temporary file is created to
151218885Sdim  // the time it is re-created as a directoy.
152218885Sdim  char pathname[] = "/tmp/llvm_XXXXXX";
153218885Sdim  int fd = 0;
154218885Sdim  if (-1 == (fd = mkstemp(pathname))) {
155218885Sdim    MakeErrMsg(ErrMsg,
156218885Sdim      std::string(pathname) + ": can't create temporary directory");
157218885Sdim    return Path();
158218885Sdim  }
159218885Sdim  ::close(fd);
160218885Sdim  ::unlink(pathname); // start race condition, ignore errors
161218885Sdim  if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition
162218885Sdim    MakeErrMsg(ErrMsg,
163218885Sdim      std::string(pathname) + ": can't create temporary directory");
164218885Sdim    return Path();
165218885Sdim  }
166218885Sdim  return Path(pathname);
167218885Sdim#elif defined(HAVE_MKTEMP)
168218885Sdim  // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have
169218885Sdim  // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable
170218885Sdim  // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing
171218885Sdim  // the XXXXXX with the pid of the process and a letter. That leads to only
172218885Sdim  // twenty six temporary files that can be generated.
173218885Sdim  char pathname[] = "/tmp/llvm_XXXXXX";
174218885Sdim  char *TmpName = ::mktemp(pathname);
175218885Sdim  if (TmpName == 0) {
176218885Sdim    MakeErrMsg(ErrMsg,
177218885Sdim      std::string(TmpName) + ": can't create unique directory name");
178218885Sdim    return Path();
179218885Sdim  }
180218885Sdim  if (-1 == ::mkdir(TmpName, S_IRWXU)) {
181218885Sdim    MakeErrMsg(ErrMsg,
182218885Sdim        std::string(TmpName) + ": can't create temporary directory");
183218885Sdim    return Path();
184218885Sdim  }
185218885Sdim  return Path(TmpName);
186218885Sdim#else
187218885Sdim  // This is the worst case implementation. tempnam(3) leaks memory unless its
188218885Sdim  // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread
189218885Sdim  // issues. The mktemp(3) function doesn't have enough variability in the
190218885Sdim  // temporary name generated. So, we provide our own implementation that
191218885Sdim  // increments an integer from a random number seeded by the current time. This
192218885Sdim  // should be sufficiently unique that we don't have many collisions between
193218885Sdim  // processes. Generally LLVM processes don't run very long and don't use very
194218885Sdim  // many temporary files so this shouldn't be a big issue for LLVM.
195218885Sdim  static time_t num = ::time(0);
196218885Sdim  char pathname[MAXPATHLEN];
197218885Sdim  do {
198218885Sdim    num++;
199218885Sdim    sprintf(pathname, "/tmp/llvm_%010u", unsigned(num));
200218885Sdim  } while ( 0 == access(pathname, F_OK ) );
201218885Sdim  if (-1 == ::mkdir(pathname, S_IRWXU)) {
202218885Sdim    MakeErrMsg(ErrMsg,
203218885Sdim      std::string(pathname) + ": can't create temporary directory");
204218885Sdim    return Path();
205218885Sdim  }
206218885Sdim  return Path(pathname);
207218885Sdim#endif
208218885Sdim}
209218885Sdim
210218885Sdimvoid
211218885SdimPath::GetSystemLibraryPaths(std::vector& Paths) {
212218885Sdim#ifdef LTDL_SHLIBPATH_VAR
213218885Sdim  char* env_var = getenv(LTDL_SHLIBPATH_VAR);
214218885Sdim  if (env_var != 0) {
215218885Sdim    getPathList(env_var,Paths);
216218885Sdim  }
217218885Sdim#endif
218218885Sdim  // FIXME: Should this look at LD_LIBRARY_PATH too?
219218885Sdim  Paths.push_back(sys::Path("/usr/local/lib/"));
220218885Sdim  Paths.push_back(sys::Path("/usr/X11R6/lib/"));
221218885Sdim  Paths.push_back(sys::Path("/usr/lib/"));
222218885Sdim  Paths.push_back(sys::Path("/lib/"));
223218885Sdim}
224218885Sdim
225218885Sdimvoid
226218885SdimPath::GetBitcodeLibraryPaths(std::vector& Paths) {
227218885Sdim  char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
228218885Sdim  if (env_var != 0) {
229218885Sdim    getPathList(env_var,Paths);
230218885Sdim  }
231218885Sdim#ifdef LLVM_LIBDIR
232218885Sdim  {
233218885Sdim    Path tmpPath;
234218885Sdim    if (tmpPath.set(LLVM_LIBDIR))
235218885Sdim      if (tmpPath.canRead())
236218885Sdim        Paths.push_back(tmpPath);
237218885Sdim  }
238218885Sdim#endif
239218885Sdim  GetSystemLibraryPaths(Paths);
240218885Sdim}
241218885Sdim
242218885SdimPath
243218885SdimPath::GetUserHomeDirectory() {
244218885Sdim  const char* home = getenv("HOME");
245218885Sdim  Path result;
246218885Sdim  if (home && result.set(home))
247218885Sdim    return result;
248218885Sdim  result.set("/");
249218885Sdim  return result;
250218885Sdim}
251218885Sdim
252218885SdimPath
253218885SdimPath::GetCurrentDirectory() {
254218885Sdim  char pathname[MAXPATHLEN];
255226633Sdim  if (!getcwd(pathname, MAXPATHLEN)) {
256226633Sdim    assert(false && "Could not query current working directory.");
257218885Sdim    return Path();
258218885Sdim  }
259218885Sdim
260218885Sdim  return Path(pathname);
261218885Sdim}
262218885Sdim
263239462Sdim#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
264243830Sdim    defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \
265243830Sdim    defined(__linux__) || defined(__CYGWIN__)
266218885Sdimstatic int
267218885Sdimtest_dir(char buf[PATH_MAX], char ret[PATH_MAX],
268218885Sdim    const char *dir, const char *bin)
269218885Sdim{
270218885Sdim  struct stat sb;
271218885Sdim
272218885Sdim  snprintf(buf, PATH_MAX, "%s/%s", dir, bin);
273218885Sdim  if (realpath(buf, ret) == NULL)
274218885Sdim    return (1);
275218885Sdim  if (stat(buf, &sb) != 0)
276218885Sdim    return (1);
277218885Sdim
278218885Sdim  return (0);
279218885Sdim}
280218885Sdim
281218885Sdimstatic char *
282218885Sdimgetprogpath(char ret[PATH_MAX], const char *bin)
283218885Sdim{
284218885Sdim  char *pv, *s, *t, buf[PATH_MAX];
285218885Sdim
286218885Sdim  /* First approach: absolute path. */
287218885Sdim  if (bin[0] == '/') {
288218885Sdim    if (test_dir(buf, ret, "/", bin) == 0)
289218885Sdim      return (ret);
290218885Sdim    return (NULL);
291218885Sdim  }
292218885Sdim
293218885Sdim  /* Second approach: relative path. */
294218885Sdim  if (strchr(bin, '/') != NULL) {
295218885Sdim    if (getcwd(buf, PATH_MAX) == NULL)
296218885Sdim      return (NULL);
297218885Sdim    if (test_dir(buf, ret, buf, bin) == 0)
298218885Sdim      return (ret);
299218885Sdim    return (NULL);
300218885Sdim  }
301218885Sdim
302218885Sdim  /* Third approach: $PATH */
303218885Sdim  if ((pv = getenv("PATH")) == NULL)
304218885Sdim    return (NULL);
305218885Sdim  s = pv = strdup(pv);
306218885Sdim  if (pv == NULL)
307218885Sdim    return (NULL);
308218885Sdim  while ((t = strsep(&s, ":")) != NULL) {
309218885Sdim    if (test_dir(buf, ret, t, bin) == 0) {
310218885Sdim      free(pv);
311218885Sdim      return (ret);
312218885Sdim    }
313218885Sdim  }
314218885Sdim  free(pv);
315218885Sdim  return (NULL);
316218885Sdim}
317234353Sdim#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
318218885Sdim
319218885Sdim/// GetMainExecutable - Return the path to the main executable, given the
320218885Sdim/// value of argv[0] from program startup.
321218885SdimPath Path::GetMainExecutable(const char *argv0, void *MainAddr) {
322218885Sdim#if defined(__APPLE__)
323218885Sdim  // On OS X the executable path is saved to the stack by dyld. Reading it
324218885Sdim  // from there is much faster than calling dladdr, especially for large
325218885Sdim  // binaries with symbols.
326218885Sdim  char exe_path[MAXPATHLEN];
327218885Sdim  uint32_t size = sizeof(exe_path);
328218885Sdim  if (_NSGetExecutablePath(exe_path, &size) == 0) {
329218885Sdim    char link_path[MAXPATHLEN];
330218885Sdim    if (realpath(exe_path, link_path))
331218885Sdim      return Path(link_path);
332218885Sdim  }
333239462Sdim#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
334234353Sdim      defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__)
335218885Sdim  char exe_path[PATH_MAX];
336218885Sdim
337218885Sdim  if (getprogpath(exe_path, argv0) != NULL)
338218885Sdim    return Path(exe_path);
339218885Sdim#elif defined(__linux__) || defined(__CYGWIN__)
340218885Sdim  char exe_path[MAXPATHLEN];
341243830Sdim  StringRef aPath("/proc/self/exe");
342243830Sdim  if (sys::fs::exists(aPath)) {
343243830Sdim      // /proc is not always mounted under Linux (chroot for example).
344243830Sdim      ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
345243830Sdim      if (len >= 0)
346243830Sdim          return Path(StringRef(exe_path, len));
347243830Sdim  } else {
348243830Sdim      // Fall back to the classical detection.
349243830Sdim      if (getprogpath(exe_path, argv0) != NULL)
350243830Sdim          return Path(exe_path);
351243830Sdim  }
352218885Sdim#elif defined(HAVE_DLFCN_H)
353218885Sdim  // Use dladdr to get executable path if available.
354218885Sdim  Dl_info DLInfo;
355218885Sdim  int err = dladdr(MainAddr, &DLInfo);
356218885Sdim  if (err == 0)
357218885Sdim    return Path();
358218885Sdim
359218885Sdim  // If the filename is a symlink, we need to resolve and return the location of
360218885Sdim  // the actual executable.
361218885Sdim  char link_path[MAXPATHLEN];
362218885Sdim  if (realpath(DLInfo.dli_fname, link_path))
363218885Sdim    return Path(link_path);
364218885Sdim#else
365218885Sdim#error GetMainExecutable is not implemented on this host yet.
366218885Sdim#endif
367218885Sdim  return Path();
368218885Sdim}
369218885Sdim
370218885Sdim
371218885SdimStringRef Path::getDirname() const {
372218885Sdim  return getDirnameCharSep(path, "/");
373218885Sdim}
374218885Sdim
375218885SdimStringRef
376218885SdimPath::getBasename() const {
377218885Sdim  // Find the last slash
378218885Sdim  std::string::size_type slash = path.rfind('/');
379218885Sdim  if (slash == std::string::npos)
380218885Sdim    slash = 0;
381218885Sdim  else
382218885Sdim    slash++;
383218885Sdim
384218885Sdim  std::string::size_type dot = path.rfind('.');
385218885Sdim  if (dot == std::string::npos || dot < slash)
386218885Sdim    return StringRef(path).substr(slash);
387218885Sdim  else
388218885Sdim    return StringRef(path).substr(slash, dot - slash);
389218885Sdim}
390218885Sdim
391218885SdimStringRef
392218885SdimPath::getSuffix() const {
393218885Sdim  // Find the last slash
394218885Sdim  std::string::size_type slash = path.rfind('/');
395218885Sdim  if (slash == std::string::npos)
396218885Sdim    slash = 0;
397218885Sdim  else
398218885Sdim    slash++;
399218885Sdim
400218885Sdim  std::string::size_type dot = path.rfind('.');
401218885Sdim  if (dot == std::string::npos || dot < slash)
402218885Sdim    return StringRef();
403218885Sdim  else
404218885Sdim    return StringRef(path).substr(dot + 1);
405218885Sdim}
406218885Sdim
407218885Sdimbool Path::getMagicNumber(std::string &Magic, unsigned len) const {
408218885Sdim  assert(len < 1024 && "Request for magic string too long");
409218885Sdim  char Buf[1025];
410218885Sdim  int fd = ::open(path.c_str(), O_RDONLY);
411218885Sdim  if (fd < 0)
412218885Sdim    return false;
413218885Sdim  ssize_t bytes_read = ::read(fd, Buf, len);
414218885Sdim  ::close(fd);
415218885Sdim  if (ssize_t(len) != bytes_read)
416218885Sdim    return false;
417218885Sdim  Magic.assign(Buf, len);
418218885Sdim  return true;
419218885Sdim}
420218885Sdim
421218885Sdimbool
422218885SdimPath::exists() const {
423218885Sdim  return 0 == access(path.c_str(), F_OK );
424218885Sdim}
425218885Sdim
426218885Sdimbool
427218885SdimPath::isDirectory() const {
428218885Sdim  struct stat buf;
429218885Sdim  if (0 != stat(path.c_str(), &buf))
430218885Sdim    return false;
431218885Sdim  return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false;
432218885Sdim}
433218885Sdim
434218885Sdimbool
435218885SdimPath::isSymLink() const {
436218885Sdim  struct stat buf;
437218885Sdim  if (0 != lstat(path.c_str(), &buf))
438218885Sdim    return false;
439218885Sdim  return S_ISLNK(buf.st_mode);
440218885Sdim}
441218885Sdim
442218885Sdim
443218885Sdimbool
444218885SdimPath::canRead() const {
445218885Sdim  return 0 == access(path.c_str(), R_OK);
446218885Sdim}
447218885Sdim
448218885Sdimbool
449218885SdimPath::canWrite() const {
450218885Sdim  return 0 == access(path.c_str(), W_OK);
451218885Sdim}
452218885Sdim
453218885Sdimbool
454218885SdimPath::isRegularFile() const {
455218885Sdim  // Get the status so we can determine if it's a file or directory
456218885Sdim  struct stat buf;
457218885Sdim
458218885Sdim  if (0 != stat(path.c_str(), &buf))
459218885Sdim    return false;
460218885Sdim
461218885Sdim  if (S_ISREG(buf.st_mode))
462218885Sdim    return true;
463218885Sdim
464218885Sdim  return false;
465218885Sdim}
466218885Sdim
467218885Sdimbool
468218885SdimPath::canExecute() const {
469218885Sdim  if (0 != access(path.c_str(), R_OK | X_OK ))
470218885Sdim    return false;
471218885Sdim  struct stat buf;
472218885Sdim  if (0 != stat(path.c_str(), &buf))
473218885Sdim    return false;
474218885Sdim  if (!S_ISREG(buf.st_mode))
475218885Sdim    return false;
476218885Sdim  return true;
477218885Sdim}
478218885Sdim
479218885SdimStringRef
480218885SdimPath::getLast() const {
481218885Sdim  // Find the last slash
482218885Sdim  size_t pos = path.rfind('/');
483218885Sdim
484218885Sdim  // Handle the corner cases
485218885Sdim  if (pos == std::string::npos)
486218885Sdim    return path;
487218885Sdim
488218885Sdim  // If the last character is a slash
489218885Sdim  if (pos == path.length()-1) {
490218885Sdim    // Find the second to last slash
491218885Sdim    size_t pos2 = path.rfind('/', pos-1);
492218885Sdim    if (pos2 == std::string::npos)
493218885Sdim      return StringRef(path).substr(0,pos);
494218885Sdim    else
495218885Sdim      return StringRef(path).substr(pos2+1,pos-pos2-1);
496218885Sdim  }
497218885Sdim  // Return everything after the last slash
498218885Sdim  return StringRef(path).substr(pos+1);
499218885Sdim}
500218885Sdim
501218885Sdimconst FileStatus *
502218885SdimPathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
503218885Sdim  if (!fsIsValid || update) {
504218885Sdim    struct stat buf;
505218885Sdim    if (0 != stat(path.c_str(), &buf)) {
506218885Sdim      MakeErrMsg(ErrStr, path + ": can't get status of file");
507218885Sdim      return 0;
508218885Sdim    }
509218885Sdim    status.fileSize = buf.st_size;
510218885Sdim    status.modTime.fromEpochTime(buf.st_mtime);
511218885Sdim    status.mode = buf.st_mode;
512218885Sdim    status.user = buf.st_uid;
513218885Sdim    status.group = buf.st_gid;
514218885Sdim    status.uniqueID = uint64_t(buf.st_ino);
515218885Sdim    status.isDir  = S_ISDIR(buf.st_mode);
516218885Sdim    status.isFile = S_ISREG(buf.st_mode);
517218885Sdim    fsIsValid = true;
518218885Sdim  }
519218885Sdim  return &status;
520218885Sdim}
521218885Sdim
522218885Sdimstatic bool AddPermissionBits(const Path &File, int bits) {
523218885Sdim  // Get the umask value from the operating system.  We want to use it
524218885Sdim  // when changing the file's permissions. Since calling umask() sets
525218885Sdim  // the umask and returns its old value, we must call it a second
526218885Sdim  // time to reset it to the user's preference.
527218885Sdim  int mask = umask(0777); // The arg. to umask is arbitrary.
528218885Sdim  umask(mask);            // Restore the umask.
529218885Sdim
530218885Sdim  // Get the file's current mode.
531218885Sdim  struct stat buf;
532218885Sdim  if (0 != stat(File.c_str(), &buf))
533218885Sdim    return false;
534218885Sdim  // Change the file to have whichever permissions bits from 'bits'
535218885Sdim  // that the umask would not disable.
536218885Sdim  if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1)
537218885Sdim      return false;
538218885Sdim  return true;
539218885Sdim}
540218885Sdim
541218885Sdimbool Path::makeReadableOnDisk(std::string* ErrMsg) {
542218885Sdim  if (!AddPermissionBits(*this, 0444))
543218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't make file readable");
544218885Sdim  return false;
545218885Sdim}
546218885Sdim
547218885Sdimbool Path::makeWriteableOnDisk(std::string* ErrMsg) {
548218885Sdim  if (!AddPermissionBits(*this, 0222))
549218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't make file writable");
550218885Sdim  return false;
551218885Sdim}
552218885Sdim
553218885Sdimbool Path::makeExecutableOnDisk(std::string* ErrMsg) {
554218885Sdim  if (!AddPermissionBits(*this, 0111))
555218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't make file executable");
556218885Sdim  return false;
557218885Sdim}
558218885Sdim
559218885Sdimbool
560218885SdimPath::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
561218885Sdim  DIR* direntries = ::opendir(path.c_str());
562218885Sdim  if (direntries == 0)
563218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't open directory");
564218885Sdim
565218885Sdim  std::string dirPath = path;
566218885Sdim  if (!lastIsSlash(dirPath))
567218885Sdim    dirPath += '/';
568218885Sdim
569218885Sdim  result.clear();
570218885Sdim  struct dirent* de = ::readdir(direntries);
571218885Sdim  for ( ; de != 0; de = ::readdir(direntries)) {
572218885Sdim    if (de->d_name[0] != '.') {
573218885Sdim      Path aPath(dirPath + (const char*)de->d_name);
574218885Sdim      struct stat st;
575218885Sdim      if (0 != lstat(aPath.path.c_str(), &st)) {
576218885Sdim        if (S_ISLNK(st.st_mode))
577218885Sdim          continue; // dangling symlink -- ignore
578218885Sdim        return MakeErrMsg(ErrMsg,
579218885Sdim                          aPath.path +  ": can't determine file object type");
580218885Sdim      }
581218885Sdim      result.insert(aPath);
582218885Sdim    }
583218885Sdim  }
584218885Sdim
585218885Sdim  closedir(direntries);
586218885Sdim  return false;
587218885Sdim}
588218885Sdim
589218885Sdimbool
590218885SdimPath::set(StringRef a_path) {
591218885Sdim  if (a_path.empty())
592218885Sdim    return false;
593218885Sdim  path = a_path;
594218885Sdim  return true;
595218885Sdim}
596218885Sdim
597218885Sdimbool
598218885SdimPath::appendComponent(StringRef name) {
599218885Sdim  if (name.empty())
600218885Sdim    return false;
601218885Sdim  if (!lastIsSlash(path))
602218885Sdim    path += '/';
603218885Sdim  path += name;
604218885Sdim  return true;
605218885Sdim}
606218885Sdim
607218885Sdimbool
608218885SdimPath::eraseComponent() {
609218885Sdim  size_t slashpos = path.rfind('/',path.size());
610218885Sdim  if (slashpos == 0 || slashpos == std::string::npos) {
611218885Sdim    path.erase();
612218885Sdim    return true;
613218885Sdim  }
614218885Sdim  if (slashpos == path.size() - 1)
615218885Sdim    slashpos = path.rfind('/',slashpos-1);
616218885Sdim  if (slashpos == std::string::npos) {
617218885Sdim    path.erase();
618218885Sdim    return true;
619218885Sdim  }
620218885Sdim  path.erase(slashpos);
621218885Sdim  return true;
622218885Sdim}
623218885Sdim
624218885Sdimbool
625218885SdimPath::eraseSuffix() {
626218885Sdim  size_t dotpos = path.rfind('.',path.size());
627218885Sdim  size_t slashpos = path.rfind('/',path.size());
628218885Sdim  if (dotpos != std::string::npos) {
629218885Sdim    if (slashpos == std::string::npos || dotpos > slashpos+1) {
630218885Sdim      path.erase(dotpos, path.size()-dotpos);
631218885Sdim      return true;
632218885Sdim    }
633218885Sdim  }
634218885Sdim  return false;
635218885Sdim}
636218885Sdim
637218885Sdimstatic bool createDirectoryHelper(char* beg, char* end, bool create_parents) {
638218885Sdim
639218885Sdim  if (access(beg, R_OK | W_OK) == 0)
640218885Sdim    return false;
641218885Sdim
642218885Sdim  if (create_parents) {
643218885Sdim
644218885Sdim    char* c = end;
645218885Sdim
646218885Sdim    for (; c != beg; --c)
647218885Sdim      if (*c == '/') {
648218885Sdim
649218885Sdim        // Recurse to handling the parent directory.
650218885Sdim        *c = '\0';
651218885Sdim        bool x = createDirectoryHelper(beg, c, create_parents);
652218885Sdim        *c = '/';
653218885Sdim
654218885Sdim        // Return if we encountered an error.
655218885Sdim        if (x)
656218885Sdim          return true;
657218885Sdim
658218885Sdim        break;
659218885Sdim      }
660218885Sdim  }
661218885Sdim
662218885Sdim  return mkdir(beg, S_IRWXU | S_IRWXG) != 0;
663218885Sdim}
664218885Sdim
665218885Sdimbool
666218885SdimPath::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) {
667218885Sdim  // Get a writeable copy of the path name
668218885Sdim  std::string pathname(path);
669218885Sdim
670218885Sdim  // Null-terminate the last component
671218885Sdim  size_t lastchar = path.length() - 1 ;
672218885Sdim
673218885Sdim  if (pathname[lastchar] != '/')
674218885Sdim    ++lastchar;
675218885Sdim
676218885Sdim  pathname[lastchar] = '\0';
677218885Sdim
678218885Sdim  if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents))
679218885Sdim    return MakeErrMsg(ErrMsg, pathname + ": can't create directory");
680218885Sdim
681218885Sdim  return false;
682218885Sdim}
683218885Sdim
684218885Sdimbool
685218885SdimPath::createFileOnDisk(std::string* ErrMsg) {
686218885Sdim  // Create the file
687218885Sdim  int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR);
688218885Sdim  if (fd < 0)
689218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't create file");
690218885Sdim  ::close(fd);
691218885Sdim  return false;
692218885Sdim}
693218885Sdim
694218885Sdimbool
695218885SdimPath::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
696218885Sdim  // Make this into a unique file name
697218885Sdim  if (makeUnique( reuse_current, ErrMsg ))
698218885Sdim    return true;
699218885Sdim
700218885Sdim  // create the file
701218885Sdim  int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
702218885Sdim  if (fd < 0)
703218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't create temporary file");
704218885Sdim  ::close(fd);
705218885Sdim  return false;
706218885Sdim}
707218885Sdim
708218885Sdimbool
709218885SdimPath::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
710218885Sdim  // Get the status so we can determine if it's a file or directory.
711218885Sdim  struct stat buf;
712218885Sdim  if (0 != stat(path.c_str(), &buf)) {
713218885Sdim    MakeErrMsg(ErrStr, path + ": can't get status of file");
714218885Sdim    return true;
715218885Sdim  }
716218885Sdim
717218885Sdim  // Note: this check catches strange situations. In all cases, LLVM should
718218885Sdim  // only be involved in the creation and deletion of regular files.  This
719218885Sdim  // check ensures that what we're trying to erase is a regular file. It
720218885Sdim  // effectively prevents LLVM from erasing things like /dev/null, any block
721218885Sdim  // special file, or other things that aren't "regular" files.
722218885Sdim  if (S_ISREG(buf.st_mode)) {
723218885Sdim    if (unlink(path.c_str()) != 0)
724218885Sdim      return MakeErrMsg(ErrStr, path + ": can't destroy file");
725218885Sdim    return false;
726218885Sdim  }
727218885Sdim
728218885Sdim  if (!S_ISDIR(buf.st_mode)) {
729218885Sdim    if (ErrStr) *ErrStr = "not a file or directory";
730218885Sdim    return true;
731218885Sdim  }
732218885Sdim
733218885Sdim  if (remove_contents) {
734218885Sdim    // Recursively descend the directory to remove its contents.
735218885Sdim    std::string cmd = "/bin/rm -rf " + path;
736218885Sdim    if (system(cmd.c_str()) != 0) {
737218885Sdim      MakeErrMsg(ErrStr, path + ": failed to recursively remove directory.");
738218885Sdim      return true;
739218885Sdim    }
740218885Sdim    return false;
741218885Sdim  }
742218885Sdim
743218885Sdim  // Otherwise, try to just remove the one directory.
744218885Sdim  std::string pathname(path);
745218885Sdim  size_t lastchar = path.length() - 1;
746218885Sdim  if (pathname[lastchar] == '/')
747218885Sdim    pathname[lastchar] = '\0';
748218885Sdim  else
749218885Sdim    pathname[lastchar+1] = '\0';
750218885Sdim
751218885Sdim  if (rmdir(pathname.c_str()) != 0)
752218885Sdim    return MakeErrMsg(ErrStr, pathname + ": can't erase directory");
753218885Sdim  return false;
754218885Sdim}
755218885Sdim
756218885Sdimbool
757218885SdimPath::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
758218885Sdim  if (0 != ::rename(path.c_str(), newName.c_str()))
759218885Sdim    return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" +
760218885Sdim               newName.str() + "'");
761218885Sdim  return false;
762218885Sdim}
763218885Sdim
764218885Sdimbool
765218885SdimPath::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
766218885Sdim  struct utimbuf utb;
767218885Sdim  utb.actime = si.modTime.toPosixTime();
768218885Sdim  utb.modtime = utb.actime;
769218885Sdim  if (0 != ::utime(path.c_str(),&utb))
770218885Sdim    return MakeErrMsg(ErrStr, path + ": can't set file modification time");
771218885Sdim  if (0 != ::chmod(path.c_str(),si.mode))
772218885Sdim    return MakeErrMsg(ErrStr, path + ": can't set mode");
773218885Sdim  return false;
774218885Sdim}
775218885Sdim
776218885Sdimbool
777218885Sdimsys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){
778218885Sdim  int inFile = -1;
779218885Sdim  int outFile = -1;
780218885Sdim  inFile = ::open(Src.c_str(), O_RDONLY);
781218885Sdim  if (inFile == -1)
782218885Sdim    return MakeErrMsg(ErrMsg, Src.str() +
783218885Sdim      ": can't open source file to copy");
784218885Sdim
785218885Sdim  outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666);
786218885Sdim  if (outFile == -1) {
787218885Sdim    ::close(inFile);
788218885Sdim    return MakeErrMsg(ErrMsg, Dest.str() +
789218885Sdim      ": can't create destination file for copy");
790218885Sdim  }
791218885Sdim
792218885Sdim  char Buffer[16*1024];
793218885Sdim  while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) {
794218885Sdim    if (Amt == -1) {
795218885Sdim      if (errno != EINTR && errno != EAGAIN) {
796218885Sdim        ::close(inFile);
797218885Sdim        ::close(outFile);
798218885Sdim        return MakeErrMsg(ErrMsg, Src.str()+": can't read source file");
799218885Sdim      }
800218885Sdim    } else {
801218885Sdim      char *BufPtr = Buffer;
802218885Sdim      while (Amt) {
803218885Sdim        ssize_t AmtWritten = ::write(outFile, BufPtr, Amt);
804218885Sdim        if (AmtWritten == -1) {
805218885Sdim          if (errno != EINTR && errno != EAGAIN) {
806218885Sdim            ::close(inFile);
807218885Sdim            ::close(outFile);
808218885Sdim            return MakeErrMsg(ErrMsg, Dest.str() +
809218885Sdim              ": can't write destination file");
810218885Sdim          }
811218885Sdim        } else {
812218885Sdim          Amt -= AmtWritten;
813218885Sdim          BufPtr += AmtWritten;
814218885Sdim        }
815218885Sdim      }
816218885Sdim    }
817218885Sdim  }
818218885Sdim  ::close(inFile);
819218885Sdim  ::close(outFile);
820218885Sdim  return false;
821218885Sdim}
822218885Sdim
823218885Sdimbool
824218885SdimPath::makeUnique(bool reuse_current, std::string* ErrMsg) {
825218885Sdim  bool Exists;
826218885Sdim  if (reuse_current && (fs::exists(path, Exists) || !Exists))
827218885Sdim    return false; // File doesn't exist already, just use it!
828218885Sdim
829218885Sdim  // Append an XXXXXX pattern to the end of the file for use with mkstemp,
830218885Sdim  // mktemp or our own implementation.
831218885Sdim  // This uses std::vector instead of SmallVector to avoid a dependence on
832218885Sdim  // libSupport. And performance isn't critical here.
833218885Sdim  std::vector<char> Buf;
834218885Sdim  Buf.resize(path.size()+8);
835218885Sdim  char *FNBuffer = &Buf[0];
836218885Sdim    path.copy(FNBuffer,path.size());
837218885Sdim  bool isdir;
838218885Sdim  if (!fs::is_directory(path, isdir) && isdir)
839218885Sdim    strcpy(FNBuffer+path.size(), "/XXXXXX");
840218885Sdim  else
841218885Sdim    strcpy(FNBuffer+path.size(), "-XXXXXX");
842218885Sdim
843218885Sdim#if defined(HAVE_MKSTEMP)
844218885Sdim  int TempFD;
845218885Sdim  if ((TempFD = mkstemp(FNBuffer)) == -1)
846218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
847218885Sdim
848218885Sdim  // We don't need to hold the temp file descriptor... we will trust that no one
849218885Sdim  // will overwrite/delete the file before we can open it again.
850218885Sdim  close(TempFD);
851218885Sdim
852218885Sdim  // Save the name
853218885Sdim  path = FNBuffer;
854224145Sdim
855224145Sdim  // By default mkstemp sets the mode to 0600, so update mode bits now.
856224145Sdim  AddPermissionBits (*this, 0666);
857218885Sdim#elif defined(HAVE_MKTEMP)
858218885Sdim  // If we don't have mkstemp, use the old and obsolete mktemp function.
859218885Sdim  if (mktemp(FNBuffer) == 0)
860218885Sdim    return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
861218885Sdim
862218885Sdim  // Save the name
863218885Sdim  path = FNBuffer;
864218885Sdim#else
865218885Sdim  // Okay, looks like we have to do it all by our lonesome.
866218885Sdim  static unsigned FCounter = 0;
867218885Sdim  // Try to initialize with unique value.
868218885Sdim  if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8;
869218885Sdim  char* pos = strstr(FNBuffer, "XXXXXX");
870218885Sdim  do {
871218885Sdim    if (++FCounter > 0xFFFFFF) {
872218885Sdim      return MakeErrMsg(ErrMsg,
873218885Sdim        path + ": can't make unique filename: too many files");
874218885Sdim    }
875218885Sdim    sprintf(pos, "%06X", FCounter);
876218885Sdim    path = FNBuffer;
877218885Sdim  } while (exists());
878218885Sdim  // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit
879218885Sdim  // LLVM.
880218885Sdim#endif
881218885Sdim  return false;
882218885Sdim}
883218885Sdim
884221345Sdimconst char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) {
885218885Sdim  int Flags = MAP_PRIVATE;
886218885Sdim#ifdef MAP_FILE
887218885Sdim  Flags |= MAP_FILE;
888218885Sdim#endif
889221345Sdim  void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, Offset);
890218885Sdim  if (BasePtr == MAP_FAILED)
891218885Sdim    return 0;
892218885Sdim  return (const char*)BasePtr;
893218885Sdim}
894218885Sdim
895221345Sdimvoid Path::UnMapFilePages(const char *BasePtr, size_t FileSize) {
896239462Sdim  const void *Addr = static_cast<const void *>(BasePtr);
897239462Sdim  ::munmap(const_cast<void *>(Addr), FileSize);
898218885Sdim}
899218885Sdim
900218885Sdim} // end llvm namespace
901