1//===- llvm/Support/Unix/Path.inc - 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 Path 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#include "llvm/Support/Process.h"
21#include <limits.h>
22#include <stdio.h>
23#if HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#if HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_SYS_MMAN_H
30#include <sys/mman.h>
31#endif
32#if HAVE_DIRENT_H
33# include <dirent.h>
34# define NAMLEN(dirent) strlen((dirent)->d_name)
35#else
36# define dirent direct
37# define NAMLEN(dirent) (dirent)->d_namlen
38# if HAVE_SYS_NDIR_H
39#  include <sys/ndir.h>
40# endif
41# if HAVE_SYS_DIR_H
42#  include <sys/dir.h>
43# endif
44# if HAVE_NDIR_H
45#  include <ndir.h>
46# endif
47#endif
48
49#ifdef __APPLE__
50#include <mach-o/dyld.h>
51#endif
52
53// Both stdio.h and cstdio are included via different pathes and
54// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros
55// either.
56#undef ferror
57#undef feof
58
59// For GNU Hurd
60#if defined(__GNU__) && !defined(PATH_MAX)
61# define PATH_MAX 4096
62#endif
63
64using namespace llvm;
65
66namespace {
67  /// This class automatically closes the given file descriptor when it goes out
68  /// of scope. You can take back explicit ownership of the file descriptor by
69  /// calling take(). The destructor does not verify that close was successful.
70  /// Therefore, never allow this class to call close on a file descriptor that
71  /// has been read from or written to.
72  struct AutoFD {
73    int FileDescriptor;
74
75    AutoFD(int fd) : FileDescriptor(fd) {}
76    ~AutoFD() {
77      if (FileDescriptor >= 0)
78        ::close(FileDescriptor);
79    }
80
81    int take() {
82      int ret = FileDescriptor;
83      FileDescriptor = -1;
84      return ret;
85    }
86
87    operator int() const {return FileDescriptor;}
88  };
89
90  error_code TempDir(SmallVectorImpl<char> &result) {
91    // FIXME: Don't use TMPDIR if program is SUID or SGID enabled.
92    const char *dir = 0;
93    (dir = std::getenv("TMPDIR" )) ||
94    (dir = std::getenv("TMP"    )) ||
95    (dir = std::getenv("TEMP"   )) ||
96    (dir = std::getenv("TEMPDIR")) ||
97#ifdef P_tmpdir
98    (dir = P_tmpdir) ||
99#endif
100    (dir = "/tmp");
101
102    result.clear();
103    StringRef d(dir);
104    result.append(d.begin(), d.end());
105    return error_code::success();
106  }
107}
108
109static error_code createUniqueEntity(const Twine &Model, int &ResultFD,
110                                     SmallVectorImpl<char> &ResultPath,
111                                     bool MakeAbsolute, unsigned Mode,
112                                     FSEntity Type) {
113  SmallString<128> ModelStorage;
114  Model.toVector(ModelStorage);
115
116  if (MakeAbsolute) {
117    // Make model absolute by prepending a temp directory if it's not already.
118    bool absolute = sys::path::is_absolute(Twine(ModelStorage));
119    if (!absolute) {
120      SmallString<128> TDir;
121      if (error_code ec = TempDir(TDir)) return ec;
122      sys::path::append(TDir, Twine(ModelStorage));
123      ModelStorage.swap(TDir);
124    }
125  }
126
127  // From here on, DO NOT modify model. It may be needed if the randomly chosen
128  // path already exists.
129  ResultPath = ModelStorage;
130  // Null terminate.
131  ResultPath.push_back(0);
132  ResultPath.pop_back();
133
134retry_random_path:
135  // Replace '%' with random chars.
136  for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
137    if (ModelStorage[i] == '%')
138      ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
139  }
140
141  // Try to open + create the file.
142  switch (Type) {
143  case FS_File: {
144    int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode);
145    if (RandomFD == -1) {
146      int SavedErrno = errno;
147      // If the file existed, try again, otherwise, error.
148      if (SavedErrno == errc::file_exists)
149        goto retry_random_path;
150      return error_code(SavedErrno, system_category());
151    }
152
153    ResultFD = RandomFD;
154    return error_code::success();
155  }
156
157  case FS_Name: {
158    bool Exists;
159    error_code EC = sys::fs::exists(ResultPath.begin(), Exists);
160    if (EC)
161      return EC;
162    if (Exists)
163      goto retry_random_path;
164    return error_code::success();
165  }
166
167  case FS_Dir: {
168    bool Existed;
169    error_code EC = sys::fs::create_directory(ResultPath.begin(), Existed);
170    if (EC)
171      return EC;
172    if (Existed)
173      goto retry_random_path;
174    return error_code::success();
175  }
176  }
177  llvm_unreachable("Invalid Type");
178}
179
180namespace llvm {
181namespace sys  {
182namespace fs {
183#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
184    defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \
185    defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__)
186static int
187test_dir(char ret[PATH_MAX], const char *dir, const char *bin)
188{
189  struct stat sb;
190  char fullpath[PATH_MAX];
191
192  snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin);
193  if (realpath(fullpath, ret) == NULL)
194    return (1);
195  if (stat(fullpath, &sb) != 0)
196    return (1);
197
198  return (0);
199}
200
201static char *
202getprogpath(char ret[PATH_MAX], const char *bin)
203{
204  char *pv, *s, *t;
205
206  /* First approach: absolute path. */
207  if (bin[0] == '/') {
208    if (test_dir(ret, "/", bin) == 0)
209      return (ret);
210    return (NULL);
211  }
212
213  /* Second approach: relative path. */
214  if (strchr(bin, '/') != NULL) {
215    char cwd[PATH_MAX];
216    if (getcwd(cwd, PATH_MAX) == NULL)
217      return (NULL);
218    if (test_dir(ret, cwd, bin) == 0)
219      return (ret);
220    return (NULL);
221  }
222
223  /* Third approach: $PATH */
224  if ((pv = getenv("PATH")) == NULL)
225    return (NULL);
226  s = pv = strdup(pv);
227  if (pv == NULL)
228    return (NULL);
229  while ((t = strsep(&s, ":")) != NULL) {
230    if (test_dir(ret, t, bin) == 0) {
231      free(pv);
232      return (ret);
233    }
234  }
235  free(pv);
236  return (NULL);
237}
238#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
239
240/// GetMainExecutable - Return the path to the main executable, given the
241/// value of argv[0] from program startup.
242std::string getMainExecutable(const char *argv0, void *MainAddr) {
243#if defined(__APPLE__)
244  // On OS X the executable path is saved to the stack by dyld. Reading it
245  // from there is much faster than calling dladdr, especially for large
246  // binaries with symbols.
247  char exe_path[MAXPATHLEN];
248  uint32_t size = sizeof(exe_path);
249  if (_NSGetExecutablePath(exe_path, &size) == 0) {
250    char link_path[MAXPATHLEN];
251    if (realpath(exe_path, link_path))
252      return link_path;
253  }
254#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
255      defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \
256      defined(__FreeBSD_kernel__)
257  char exe_path[PATH_MAX];
258
259  if (getprogpath(exe_path, argv0) != NULL)
260    return exe_path;
261#elif defined(__linux__) || defined(__CYGWIN__)
262  char exe_path[MAXPATHLEN];
263  StringRef aPath("/proc/self/exe");
264  if (sys::fs::exists(aPath)) {
265      // /proc is not always mounted under Linux (chroot for example).
266      ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
267      if (len >= 0)
268          return StringRef(exe_path, len);
269  } else {
270      // Fall back to the classical detection.
271      if (getprogpath(exe_path, argv0) != NULL)
272          return exe_path;
273  }
274#elif defined(HAVE_DLFCN_H)
275  // Use dladdr to get executable path if available.
276  Dl_info DLInfo;
277  int err = dladdr(MainAddr, &DLInfo);
278  if (err == 0)
279    return "";
280
281  // If the filename is a symlink, we need to resolve and return the location of
282  // the actual executable.
283  char link_path[MAXPATHLEN];
284  if (realpath(DLInfo.dli_fname, link_path))
285    return link_path;
286#else
287#error GetMainExecutable is not implemented on this host yet.
288#endif
289  return "";
290}
291
292TimeValue file_status::getLastModificationTime() const {
293  TimeValue Ret;
294  Ret.fromEpochTime(fs_st_mtime);
295  return Ret;
296}
297
298UniqueID file_status::getUniqueID() const {
299  return UniqueID(fs_st_dev, fs_st_ino);
300}
301
302error_code current_path(SmallVectorImpl<char> &result) {
303  result.clear();
304
305  const char *pwd = ::getenv("PWD");
306  llvm::sys::fs::file_status PWDStatus, DotStatus;
307  if (pwd && llvm::sys::path::is_absolute(pwd) &&
308      !llvm::sys::fs::status(pwd, PWDStatus) &&
309      !llvm::sys::fs::status(".", DotStatus) &&
310      PWDStatus.getUniqueID() == DotStatus.getUniqueID()) {
311    result.append(pwd, pwd + strlen(pwd));
312    return error_code::success();
313  }
314
315#ifdef MAXPATHLEN
316  result.reserve(MAXPATHLEN);
317#else
318// For GNU Hurd
319  result.reserve(1024);
320#endif
321
322  while (true) {
323    if (::getcwd(result.data(), result.capacity()) == 0) {
324      // See if there was a real error.
325      if (errno != errc::not_enough_memory)
326        return error_code(errno, system_category());
327      // Otherwise there just wasn't enough space.
328      result.reserve(result.capacity() * 2);
329    } else
330      break;
331  }
332
333  result.set_size(strlen(result.data()));
334  return error_code::success();
335}
336
337error_code create_directory(const Twine &path, bool &existed) {
338  SmallString<128> path_storage;
339  StringRef p = path.toNullTerminatedStringRef(path_storage);
340
341  if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) {
342    if (errno != errc::file_exists)
343      return error_code(errno, system_category());
344    existed = true;
345  } else
346    existed = false;
347
348  return error_code::success();
349}
350
351error_code create_hard_link(const Twine &to, const Twine &from) {
352  // Get arguments.
353  SmallString<128> from_storage;
354  SmallString<128> to_storage;
355  StringRef f = from.toNullTerminatedStringRef(from_storage);
356  StringRef t = to.toNullTerminatedStringRef(to_storage);
357
358  if (::link(t.begin(), f.begin()) == -1)
359    return error_code(errno, system_category());
360
361  return error_code::success();
362}
363
364error_code create_symlink(const Twine &to, const Twine &from) {
365  // Get arguments.
366  SmallString<128> from_storage;
367  SmallString<128> to_storage;
368  StringRef f = from.toNullTerminatedStringRef(from_storage);
369  StringRef t = to.toNullTerminatedStringRef(to_storage);
370
371  if (::symlink(t.begin(), f.begin()) == -1)
372    return error_code(errno, system_category());
373
374  return error_code::success();
375}
376
377error_code remove(const Twine &path, bool &existed) {
378  SmallString<128> path_storage;
379  StringRef p = path.toNullTerminatedStringRef(path_storage);
380
381  struct stat buf;
382  if (stat(p.begin(), &buf) != 0) {
383    if (errno != errc::no_such_file_or_directory)
384      return error_code(errno, system_category());
385    existed = false;
386    return error_code::success();
387  }
388
389  // Note: this check catches strange situations. In all cases, LLVM should
390  // only be involved in the creation and deletion of regular files.  This
391  // check ensures that what we're trying to erase is a regular file. It
392  // effectively prevents LLVM from erasing things like /dev/null, any block
393  // special file, or other things that aren't "regular" files.
394  if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode))
395    return make_error_code(errc::operation_not_permitted);
396
397  if (::remove(p.begin()) == -1) {
398    if (errno != errc::no_such_file_or_directory)
399      return error_code(errno, system_category());
400    existed = false;
401  } else
402    existed = true;
403
404  return error_code::success();
405}
406
407error_code rename(const Twine &from, const Twine &to) {
408  // Get arguments.
409  SmallString<128> from_storage;
410  SmallString<128> to_storage;
411  StringRef f = from.toNullTerminatedStringRef(from_storage);
412  StringRef t = to.toNullTerminatedStringRef(to_storage);
413
414  if (::rename(f.begin(), t.begin()) == -1)
415    return error_code(errno, system_category());
416
417  return error_code::success();
418}
419
420error_code resize_file(const Twine &path, uint64_t size) {
421  SmallString<128> path_storage;
422  StringRef p = path.toNullTerminatedStringRef(path_storage);
423
424  if (::truncate(p.begin(), size) == -1)
425    return error_code(errno, system_category());
426
427  return error_code::success();
428}
429
430error_code exists(const Twine &path, bool &result) {
431  SmallString<128> path_storage;
432  StringRef p = path.toNullTerminatedStringRef(path_storage);
433
434  if (::access(p.begin(), F_OK) == -1) {
435    if (errno != errc::no_such_file_or_directory)
436      return error_code(errno, system_category());
437    result = false;
438  } else
439    result = true;
440
441  return error_code::success();
442}
443
444bool can_write(const Twine &Path) {
445  SmallString<128> PathStorage;
446  StringRef P = Path.toNullTerminatedStringRef(PathStorage);
447  return 0 == access(P.begin(), W_OK);
448}
449
450bool can_execute(const Twine &Path) {
451  SmallString<128> PathStorage;
452  StringRef P = Path.toNullTerminatedStringRef(PathStorage);
453
454  if (0 != access(P.begin(), R_OK | X_OK))
455    return false;
456  struct stat buf;
457  if (0 != stat(P.begin(), &buf))
458    return false;
459  if (!S_ISREG(buf.st_mode))
460    return false;
461  return true;
462}
463
464bool equivalent(file_status A, file_status B) {
465  assert(status_known(A) && status_known(B));
466  return A.fs_st_dev == B.fs_st_dev &&
467         A.fs_st_ino == B.fs_st_ino;
468}
469
470error_code equivalent(const Twine &A, const Twine &B, bool &result) {
471  file_status fsA, fsB;
472  if (error_code ec = status(A, fsA)) return ec;
473  if (error_code ec = status(B, fsB)) return ec;
474  result = equivalent(fsA, fsB);
475  return error_code::success();
476}
477
478static error_code fillStatus(int StatRet, const struct stat &Status,
479                             file_status &Result) {
480  if (StatRet != 0) {
481    error_code ec(errno, system_category());
482    if (ec == errc::no_such_file_or_directory)
483      Result = file_status(file_type::file_not_found);
484    else
485      Result = file_status(file_type::status_error);
486    return ec;
487  }
488
489  file_type Type = file_type::type_unknown;
490
491  if (S_ISDIR(Status.st_mode))
492    Type = file_type::directory_file;
493  else if (S_ISREG(Status.st_mode))
494    Type = file_type::regular_file;
495  else if (S_ISBLK(Status.st_mode))
496    Type = file_type::block_file;
497  else if (S_ISCHR(Status.st_mode))
498    Type = file_type::character_file;
499  else if (S_ISFIFO(Status.st_mode))
500    Type = file_type::fifo_file;
501  else if (S_ISSOCK(Status.st_mode))
502    Type = file_type::socket_file;
503
504  perms Perms = static_cast<perms>(Status.st_mode);
505  Result =
506      file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime,
507                  Status.st_uid, Status.st_gid, Status.st_size);
508
509  return error_code::success();
510}
511
512error_code status(const Twine &Path, file_status &Result) {
513  SmallString<128> PathStorage;
514  StringRef P = Path.toNullTerminatedStringRef(PathStorage);
515
516  struct stat Status;
517  int StatRet = ::stat(P.begin(), &Status);
518  return fillStatus(StatRet, Status, Result);
519}
520
521error_code status(int FD, file_status &Result) {
522  struct stat Status;
523  int StatRet = ::fstat(FD, &Status);
524  return fillStatus(StatRet, Status, Result);
525}
526
527error_code setLastModificationAndAccessTime(int FD, TimeValue Time) {
528#if defined(HAVE_FUTIMENS)
529  timespec Times[2];
530  Times[0].tv_sec = Time.toPosixTime();
531  Times[0].tv_nsec = 0;
532  Times[1] = Times[0];
533  if (::futimens(FD, Times))
534    return error_code(errno, system_category());
535  return error_code::success();
536#elif defined(HAVE_FUTIMES)
537  timeval Times[2];
538  Times[0].tv_sec = Time.toPosixTime();
539  Times[0].tv_usec = 0;
540  Times[1] = Times[0];
541  if (::futimes(FD, Times))
542    return error_code(errno, system_category());
543  return error_code::success();
544#else
545#warning Missing futimes() and futimens()
546  return make_error_code(errc::not_supported);
547#endif
548}
549
550error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
551  AutoFD ScopedFD(FD);
552  if (!CloseFD)
553    ScopedFD.take();
554
555  // Figure out how large the file is.
556  struct stat FileInfo;
557  if (fstat(FD, &FileInfo) == -1)
558    return error_code(errno, system_category());
559  uint64_t FileSize = FileInfo.st_size;
560
561  if (Size == 0)
562    Size = FileSize;
563  else if (FileSize < Size) {
564    // We need to grow the file.
565    if (ftruncate(FD, Size) == -1)
566      return error_code(errno, system_category());
567  }
568
569  int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
570  int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
571#ifdef MAP_FILE
572  flags |= MAP_FILE;
573#endif
574  Mapping = ::mmap(0, Size, prot, flags, FD, Offset);
575  if (Mapping == MAP_FAILED)
576    return error_code(errno, system_category());
577  return error_code::success();
578}
579
580mapped_file_region::mapped_file_region(const Twine &path,
581                                       mapmode mode,
582                                       uint64_t length,
583                                       uint64_t offset,
584                                       error_code &ec)
585  : Mode(mode)
586  , Size(length)
587  , Mapping() {
588  // Make sure that the requested size fits within SIZE_T.
589  if (length > std::numeric_limits<size_t>::max()) {
590    ec = make_error_code(errc::invalid_argument);
591    return;
592  }
593
594  SmallString<128> path_storage;
595  StringRef name = path.toNullTerminatedStringRef(path_storage);
596  int oflags = (mode == readonly) ? O_RDONLY : O_RDWR;
597  int ofd = ::open(name.begin(), oflags);
598  if (ofd == -1) {
599    ec = error_code(errno, system_category());
600    return;
601  }
602
603  ec = init(ofd, true, offset);
604  if (ec)
605    Mapping = 0;
606}
607
608mapped_file_region::mapped_file_region(int fd,
609                                       bool closefd,
610                                       mapmode mode,
611                                       uint64_t length,
612                                       uint64_t offset,
613                                       error_code &ec)
614  : Mode(mode)
615  , Size(length)
616  , Mapping() {
617  // Make sure that the requested size fits within SIZE_T.
618  if (length > std::numeric_limits<size_t>::max()) {
619    ec = make_error_code(errc::invalid_argument);
620    return;
621  }
622
623  ec = init(fd, closefd, offset);
624  if (ec)
625    Mapping = 0;
626}
627
628mapped_file_region::~mapped_file_region() {
629  if (Mapping)
630    ::munmap(Mapping, Size);
631}
632
633#if LLVM_HAS_RVALUE_REFERENCES
634mapped_file_region::mapped_file_region(mapped_file_region &&other)
635  : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) {
636  other.Mapping = 0;
637}
638#endif
639
640mapped_file_region::mapmode mapped_file_region::flags() const {
641  assert(Mapping && "Mapping failed but used anyway!");
642  return Mode;
643}
644
645uint64_t mapped_file_region::size() const {
646  assert(Mapping && "Mapping failed but used anyway!");
647  return Size;
648}
649
650char *mapped_file_region::data() const {
651  assert(Mapping && "Mapping failed but used anyway!");
652  assert(Mode != readonly && "Cannot get non-const data for readonly mapping!");
653  return reinterpret_cast<char*>(Mapping);
654}
655
656const char *mapped_file_region::const_data() const {
657  assert(Mapping && "Mapping failed but used anyway!");
658  return reinterpret_cast<const char*>(Mapping);
659}
660
661int mapped_file_region::alignment() {
662  return process::get_self()->page_size();
663}
664
665error_code detail::directory_iterator_construct(detail::DirIterState &it,
666                                                StringRef path){
667  SmallString<128> path_null(path);
668  DIR *directory = ::opendir(path_null.c_str());
669  if (directory == 0)
670    return error_code(errno, system_category());
671
672  it.IterationHandle = reinterpret_cast<intptr_t>(directory);
673  // Add something for replace_filename to replace.
674  path::append(path_null, ".");
675  it.CurrentEntry = directory_entry(path_null.str());
676  return directory_iterator_increment(it);
677}
678
679error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
680  if (it.IterationHandle)
681    ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
682  it.IterationHandle = 0;
683  it.CurrentEntry = directory_entry();
684  return error_code::success();
685}
686
687error_code detail::directory_iterator_increment(detail::DirIterState &it) {
688  errno = 0;
689  dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
690  if (cur_dir == 0 && errno != 0) {
691    return error_code(errno, system_category());
692  } else if (cur_dir != 0) {
693    StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
694    if ((name.size() == 1 && name[0] == '.') ||
695        (name.size() == 2 && name[0] == '.' && name[1] == '.'))
696      return directory_iterator_increment(it);
697    it.CurrentEntry.replace_filename(name);
698  } else
699    return directory_iterator_destruct(it);
700
701  return error_code::success();
702}
703
704error_code get_magic(const Twine &path, uint32_t len,
705                     SmallVectorImpl<char> &result) {
706  SmallString<128> PathStorage;
707  StringRef Path = path.toNullTerminatedStringRef(PathStorage);
708  result.set_size(0);
709
710  // Open path.
711  std::FILE *file = std::fopen(Path.data(), "rb");
712  if (file == 0)
713    return error_code(errno, system_category());
714
715  // Reserve storage.
716  result.reserve(len);
717
718  // Read magic!
719  size_t size = std::fread(result.data(), 1, len, file);
720  if (std::ferror(file) != 0) {
721    std::fclose(file);
722    return error_code(errno, system_category());
723  } else if (size != len) {
724    if (std::feof(file) != 0) {
725      std::fclose(file);
726      result.set_size(size);
727      return make_error_code(errc::value_too_large);
728    }
729  }
730  std::fclose(file);
731  result.set_size(size);
732  return error_code::success();
733}
734
735error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
736                                            bool map_writable, void *&result) {
737  SmallString<128> path_storage;
738  StringRef name = path.toNullTerminatedStringRef(path_storage);
739  int oflags = map_writable ? O_RDWR : O_RDONLY;
740  int ofd = ::open(name.begin(), oflags);
741  if ( ofd == -1 )
742    return error_code(errno, system_category());
743  AutoFD fd(ofd);
744  int flags = map_writable ? MAP_SHARED : MAP_PRIVATE;
745  int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ;
746#ifdef MAP_FILE
747  flags |= MAP_FILE;
748#endif
749  result = ::mmap(0, size, prot, flags, fd, file_offset);
750  if (result == MAP_FAILED) {
751    return error_code(errno, system_category());
752  }
753
754  return error_code::success();
755}
756
757error_code unmap_file_pages(void *base, size_t size) {
758  if ( ::munmap(base, size) == -1 )
759    return error_code(errno, system_category());
760
761  return error_code::success();
762}
763
764error_code openFileForRead(const Twine &Name, int &ResultFD) {
765  SmallString<128> Storage;
766  StringRef P = Name.toNullTerminatedStringRef(Storage);
767  while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
768    if (errno != EINTR)
769      return error_code(errno, system_category());
770  }
771  return error_code::success();
772}
773
774error_code openFileForWrite(const Twine &Name, int &ResultFD,
775                            sys::fs::OpenFlags Flags, unsigned Mode) {
776  // Verify that we don't have both "append" and "excl".
777  assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
778         "Cannot specify both 'excl' and 'append' file creation flags!");
779
780  int OpenFlags = O_WRONLY | O_CREAT;
781
782  if (Flags & F_Append)
783    OpenFlags |= O_APPEND;
784  else
785    OpenFlags |= O_TRUNC;
786
787  if (Flags & F_Excl)
788    OpenFlags |= O_EXCL;
789
790  SmallString<128> Storage;
791  StringRef P = Name.toNullTerminatedStringRef(Storage);
792  while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) {
793    if (errno != EINTR)
794      return error_code(errno, system_category());
795  }
796  return error_code::success();
797}
798
799} // end namespace fs
800} // end namespace sys
801} // end namespace llvm
802