LCOV - code coverage report
Current view: top level - lib/Support/Unix - Path.inc (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 294 382 77.0 %
Date: 2017-09-14 15:23:50 Functions: 44 49 89.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <limits.h>
      21             : #include <stdio.h>
      22             : #if HAVE_SYS_STAT_H
      23             : #include <sys/stat.h>
      24             : #endif
      25             : #if HAVE_FCNTL_H
      26             : #include <fcntl.h>
      27             : #endif
      28             : #ifdef HAVE_UNISTD_H
      29             : #include <unistd.h>
      30             : #endif
      31             : #ifdef HAVE_SYS_MMAN_H
      32             : #include <sys/mman.h>
      33             : #endif
      34             : #if HAVE_DIRENT_H
      35             : # include <dirent.h>
      36             : # define NAMLEN(dirent) strlen((dirent)->d_name)
      37             : #else
      38             : # define dirent direct
      39             : # define NAMLEN(dirent) (dirent)->d_namlen
      40             : # if HAVE_SYS_NDIR_H
      41             : #  include <sys/ndir.h>
      42             : # endif
      43             : # if HAVE_SYS_DIR_H
      44             : #  include <sys/dir.h>
      45             : # endif
      46             : # if HAVE_NDIR_H
      47             : #  include <ndir.h>
      48             : # endif
      49             : #endif
      50             : 
      51             : #include <pwd.h>
      52             : 
      53             : #ifdef __APPLE__
      54             : #include <mach-o/dyld.h>
      55             : #include <sys/attr.h>
      56             : #endif
      57             : 
      58             : // Both stdio.h and cstdio are included via different paths and
      59             : // stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros
      60             : // either.
      61             : #undef ferror
      62             : #undef feof
      63             : 
      64             : // For GNU Hurd
      65             : #if defined(__GNU__) && !defined(PATH_MAX)
      66             : # define PATH_MAX 4096
      67             : # define MAXPATHLEN 4096
      68             : #endif
      69             : 
      70             : #include <sys/types.h>
      71             : #if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) &&   \
      72             :     !defined(__linux__)
      73             : #include <sys/statvfs.h>
      74             : #define STATVFS statvfs
      75             : #define FSTATVFS fstatvfs
      76             : #define STATVFS_F_FRSIZE(vfs) vfs.f_frsize
      77             : #else
      78             : #if defined(__OpenBSD__) || defined(__FreeBSD__)
      79             : #include <sys/mount.h>
      80             : #include <sys/param.h>
      81             : #elif defined(__linux__)
      82             : #if defined(HAVE_LINUX_MAGIC_H)
      83             : #include <linux/magic.h>
      84             : #else
      85             : #if defined(HAVE_LINUX_NFS_FS_H)
      86             : #include <linux/nfs_fs.h>
      87             : #endif
      88             : #if defined(HAVE_LINUX_SMB_H)
      89             : #include <linux/smb.h>
      90             : #endif
      91             : #endif
      92             : #include <sys/vfs.h>
      93             : #else
      94             : #include <sys/mount.h>
      95             : #endif
      96             : #define STATVFS statfs
      97             : #define FSTATVFS fstatfs
      98             : #define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize)
      99             : #endif
     100             : 
     101             : #if defined(__NetBSD__)
     102             : #define STATVFS_F_FLAG(vfs) (vfs).f_flag
     103             : #else
     104             : #define STATVFS_F_FLAG(vfs) (vfs).f_flags
     105             : #endif
     106             : 
     107             : using namespace llvm;
     108             : 
     109             : namespace llvm {
     110             : namespace sys  {
     111             : namespace fs {
     112             : #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
     113             :     defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) ||   \
     114             :     defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX)
     115             : static int
     116           0 : test_dir(char ret[PATH_MAX], const char *dir, const char *bin)
     117             : {
     118             :   struct stat sb;
     119             :   char fullpath[PATH_MAX];
     120             : 
     121           0 :   snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin);
     122           0 :   if (!realpath(fullpath, ret))
     123             :     return 1;
     124           0 :   if (stat(fullpath, &sb) != 0)
     125             :     return 1;
     126             : 
     127           0 :   return 0;
     128             : }
     129             : 
     130             : static char *
     131           0 : getprogpath(char ret[PATH_MAX], const char *bin)
     132             : {
     133             :   char *pv, *s, *t;
     134             : 
     135             :   /* First approach: absolute path. */
     136           0 :   if (bin[0] == '/') {
     137           0 :     if (test_dir(ret, "/", bin) == 0)
     138             :       return ret;
     139           0 :     return nullptr;
     140             :   }
     141             : 
     142             :   /* Second approach: relative path. */
     143           0 :   if (strchr(bin, '/')) {
     144             :     char cwd[PATH_MAX];
     145           0 :     if (!getcwd(cwd, PATH_MAX))
     146             :       return nullptr;
     147           0 :     if (test_dir(ret, cwd, bin) == 0)
     148             :       return ret;
     149           0 :     return nullptr;
     150             :   }
     151             : 
     152             :   /* Third approach: $PATH */
     153           0 :   if ((pv = getenv("PATH")) == nullptr)
     154             :     return nullptr;
     155           0 :   s = pv = strdup(pv);
     156           0 :   if (!pv)
     157             :     return nullptr;
     158           0 :   while ((t = strsep(&s, ":")) != nullptr) {
     159           0 :     if (test_dir(ret, t, bin) == 0) {
     160           0 :       free(pv);
     161           0 :       return ret;
     162             :     }
     163             :   }
     164           0 :   free(pv);
     165           0 :   return nullptr;
     166             : }
     167             : #endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
     168             : 
     169             : /// GetMainExecutable - Return the path to the main executable, given the
     170             : /// value of argv[0] from program startup.
     171       20803 : std::string getMainExecutable(const char *argv0, void *MainAddr) {
     172             : #if defined(__APPLE__)
     173             :   // On OS X the executable path is saved to the stack by dyld. Reading it
     174             :   // from there is much faster than calling dladdr, especially for large
     175             :   // binaries with symbols.
     176             :   char exe_path[MAXPATHLEN];
     177             :   uint32_t size = sizeof(exe_path);
     178             :   if (_NSGetExecutablePath(exe_path, &size) == 0) {
     179             :     char link_path[MAXPATHLEN];
     180             :     if (realpath(exe_path, link_path))
     181             :       return link_path;
     182             :   }
     183             : #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||   \
     184             :     defined(__minix) || defined(__DragonFly__) ||                              \
     185             :     defined(__FreeBSD_kernel__) || defined(_AIX)
     186             :   char exe_path[PATH_MAX];
     187             : 
     188             :   if (getprogpath(exe_path, argv0) != NULL)
     189             :     return exe_path;
     190             : #elif defined(__linux__) || defined(__CYGWIN__)
     191             :   char exe_path[MAXPATHLEN];
     192       20803 :   StringRef aPath("/proc/self/exe");
     193       41606 :   if (sys::fs::exists(aPath)) {
     194             :       // /proc is not always mounted under Linux (chroot for example).
     195       62409 :       ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
     196       20803 :       if (len >= 0)
     197       62409 :           return std::string(exe_path, len);
     198             :   } else {
     199             :       // Fall back to the classical detection.
     200           0 :       if (getprogpath(exe_path, argv0))
     201           0 :         return exe_path;
     202             :   }
     203             : #elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
     204             :   // Use dladdr to get executable path if available.
     205             :   Dl_info DLInfo;
     206             :   int err = dladdr(MainAddr, &DLInfo);
     207             :   if (err == 0)
     208             :     return "";
     209             : 
     210             :   // If the filename is a symlink, we need to resolve and return the location of
     211             :   // the actual executable.
     212             :   char link_path[MAXPATHLEN];
     213             :   if (realpath(DLInfo.dli_fname, link_path))
     214             :     return link_path;
     215             : #else
     216             : #error GetMainExecutable is not implemented on this host yet.
     217             : #endif
     218           0 :   return "";
     219             : }
     220             : 
     221          21 : TimePoint<> file_status::getLastAccessedTime() const {
     222          63 :   return toTimePoint(fs_st_atime);
     223             : }
     224             : 
     225      450111 : TimePoint<> file_status::getLastModificationTime() const {
     226     1350333 :   return toTimePoint(fs_st_mtime);
     227             : }
     228             : 
     229      509458 : UniqueID file_status::getUniqueID() const {
     230      509458 :   return UniqueID(fs_st_dev, fs_st_ino);
     231             : }
     232             : 
     233           0 : uint32_t file_status::getLinkCount() const {
     234           0 :   return fs_st_nlinks;
     235             : }
     236             : 
     237          10 : ErrorOr<space_info> disk_space(const Twine &Path) {
     238             :   struct STATVFS Vfs;
     239          30 :   if (::STATVFS(Path.str().c_str(), &Vfs))
     240           0 :     return std::error_code(errno, std::generic_category());
     241          10 :   auto FrSize = STATVFS_F_FRSIZE(Vfs);
     242             :   space_info SpaceInfo;
     243          10 :   SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize;
     244          10 :   SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize;
     245          10 :   SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize;
     246             :   return SpaceInfo;
     247             : }
     248             : 
     249       35207 : std::error_code current_path(SmallVectorImpl<char> &result) {
     250       35207 :   result.clear();
     251             : 
     252       35207 :   const char *pwd = ::getenv("PWD");
     253       35207 :   llvm::sys::fs::file_status PWDStatus, DotStatus;
     254       92826 :   if (pwd && llvm::sys::path::is_absolute(pwd) &&
     255       92827 :       !llvm::sys::fs::status(pwd, PWDStatus) &&
     256       99223 :       !llvm::sys::fs::status(".", DotStatus) &&
     257       64017 :       PWDStatus.getUniqueID() == DotStatus.getUniqueID()) {
     258       23862 :     result.append(pwd, pwd + strlen(pwd));
     259       23862 :     return std::error_code();
     260             :   }
     261             : 
     262             : #ifdef MAXPATHLEN
     263             :   result.reserve(MAXPATHLEN);
     264             : #else
     265             : // For GNU Hurd
     266             :   result.reserve(1024);
     267             : #endif
     268             : 
     269             :   while (true) {
     270       34038 :     if (::getcwd(result.data(), result.capacity()) == nullptr) {
     271             :       // See if there was a real error.
     272           0 :       if (errno != ENOMEM)
     273           0 :         return std::error_code(errno, std::generic_category());
     274             :       // Otherwise there just wasn't enough space.
     275           0 :       result.reserve(result.capacity() * 2);
     276             :     } else
     277             :       break;
     278             :   }
     279             : 
     280       34038 :   result.set_size(strlen(result.data()));
     281       11346 :   return std::error_code();
     282             : }
     283             : 
     284        8411 : std::error_code set_current_path(const Twine &path) {
     285       16822 :   SmallString<128> path_storage;
     286        8411 :   StringRef p = path.toNullTerminatedStringRef(path_storage);
     287             : 
     288        8411 :   if (::chdir(p.begin()) == -1)
     289           0 :     return std::error_code(errno, std::generic_category());
     290             : 
     291        8411 :   return std::error_code();
     292             : }
     293             : 
     294        2544 : std::error_code create_directory(const Twine &path, bool IgnoreExisting,
     295             :                                  perms Perms) {
     296        5088 :   SmallString<128> path_storage;
     297        2544 :   StringRef p = path.toNullTerminatedStringRef(path_storage);
     298             : 
     299        2544 :   if (::mkdir(p.begin(), Perms) == -1) {
     300        1390 :     if (errno != EEXIST || !IgnoreExisting)
     301         450 :       return std::error_code(errno, std::generic_category());
     302             :   }
     303             : 
     304        2094 :   return std::error_code();
     305             : }
     306             : 
     307             : // Note that we are using symbolic link because hard links are not supported by
     308             : // all filesystems (SMB doesn't).
     309        1624 : std::error_code create_link(const Twine &to, const Twine &from) {
     310             :   // Get arguments.
     311        3248 :   SmallString<128> from_storage;
     312        3248 :   SmallString<128> to_storage;
     313        1624 :   StringRef f = from.toNullTerminatedStringRef(from_storage);
     314        1624 :   StringRef t = to.toNullTerminatedStringRef(to_storage);
     315             : 
     316        1624 :   if (::symlink(t.begin(), f.begin()) == -1)
     317           0 :     return std::error_code(errno, std::generic_category());
     318             : 
     319        1624 :   return std::error_code();
     320             : }
     321             : 
     322           4 : std::error_code create_hard_link(const Twine &to, const Twine &from) {
     323             :   // Get arguments.
     324           8 :   SmallString<128> from_storage;
     325           8 :   SmallString<128> to_storage;
     326           4 :   StringRef f = from.toNullTerminatedStringRef(from_storage);
     327           4 :   StringRef t = to.toNullTerminatedStringRef(to_storage);
     328             : 
     329           4 :   if (::link(t.begin(), f.begin()) == -1)
     330           0 :     return std::error_code(errno, std::generic_category());
     331             : 
     332           4 :   return std::error_code();
     333             : }
     334             : 
     335       15124 : std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
     336       30248 :   SmallString<128> path_storage;
     337       15124 :   StringRef p = path.toNullTerminatedStringRef(path_storage);
     338             : 
     339             :   struct stat buf;
     340       30248 :   if (lstat(p.begin(), &buf) != 0) {
     341        7362 :     if (errno != ENOENT || !IgnoreNonExisting)
     342           1 :       return std::error_code(errno, std::generic_category());
     343        7361 :     return std::error_code();
     344             :   }
     345             : 
     346             :   // Note: this check catches strange situations. In all cases, LLVM should
     347             :   // only be involved in the creation and deletion of regular files.  This
     348             :   // check ensures that what we're trying to erase is a regular file. It
     349             :   // effectively prevents LLVM from erasing things like /dev/null, any block
     350             :   // special file, or other things that aren't "regular" files.
     351        7762 :   if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode))
     352             :     return make_error_code(errc::operation_not_permitted);
     353             : 
     354        7497 :   if (::remove(p.begin()) == -1) {
     355           2 :     if (errno != ENOENT || !IgnoreNonExisting)
     356           2 :       return std::error_code(errno, std::generic_category());
     357             :   }
     358             : 
     359        7495 :   return std::error_code();
     360             : }
     361             : 
     362             : static bool is_local_impl(struct STATVFS &Vfs) {
     363             : #if defined(__linux__)
     364             : #ifndef NFS_SUPER_MAGIC
     365             : #define NFS_SUPER_MAGIC 0x6969
     366             : #endif
     367             : #ifndef SMB_SUPER_MAGIC
     368             : #define SMB_SUPER_MAGIC 0x517B
     369             : #endif
     370             : #ifndef CIFS_MAGIC_NUMBER
     371             : #define CIFS_MAGIC_NUMBER 0xFF534D42
     372             : #endif
     373        8656 :   switch ((uint32_t)Vfs.f_type) {
     374             :   case NFS_SUPER_MAGIC:
     375             :   case SMB_SUPER_MAGIC:
     376             :   case CIFS_MAGIC_NUMBER:
     377             :     return false;
     378        8655 :   default:
     379             :     return true;
     380             :   }
     381             : #elif defined(__CYGWIN__)
     382             :   // Cygwin doesn't expose this information; would need to use Win32 API.
     383             :   return false;
     384             : #elif defined(__sun)
     385             :   // statvfs::f_basetype contains a null-terminated FSType name of the mounted target
     386             :   StringRef fstype(Vfs.f_basetype);
     387             :   // NFS is the only non-local fstype??
     388             :   return !fstype.equals("nfs");
     389             : #else
     390             :   return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
     391             : #endif
     392             : }
     393             : 
     394       15323 : std::error_code is_local(const Twine &Path, bool &Result) {
     395             :   struct STATVFS Vfs;
     396       45970 :   if (::STATVFS(Path.str().c_str(), &Vfs))
     397        6667 :     return std::error_code(errno, std::generic_category());
     398             : 
     399       17312 :   Result = is_local_impl(Vfs);
     400        8656 :   return std::error_code();
     401             : }
     402             : 
     403           0 : std::error_code is_local(int FD, bool &Result) {
     404             :   struct STATVFS Vfs;
     405           0 :   if (::FSTATVFS(FD, &Vfs))
     406           0 :     return std::error_code(errno, std::generic_category());
     407             : 
     408           0 :   Result = is_local_impl(Vfs);
     409           0 :   return std::error_code();
     410             : }
     411             : 
     412        5919 : std::error_code rename(const Twine &from, const Twine &to) {
     413             :   // Get arguments.
     414       11838 :   SmallString<128> from_storage;
     415       11838 :   SmallString<128> to_storage;
     416        5919 :   StringRef f = from.toNullTerminatedStringRef(from_storage);
     417        5919 :   StringRef t = to.toNullTerminatedStringRef(to_storage);
     418             : 
     419        5919 :   if (::rename(f.begin(), t.begin()) == -1)
     420           0 :     return std::error_code(errno, std::generic_category());
     421             : 
     422        5919 :   return std::error_code();
     423             : }
     424             : 
     425        3629 : std::error_code resize_file(int FD, uint64_t Size) {
     426             : #if defined(HAVE_POSIX_FALLOCATE)
     427             :   // If we have posix_fallocate use it. Unlike ftruncate it always allocates
     428             :   // space, so we get an error if the disk is full.
     429        3629 :   if (int Err = ::posix_fallocate(FD, 0, Size)) {
     430           0 :     if (Err != EOPNOTSUPP)
     431           0 :       return std::error_code(Err, std::generic_category());
     432             :   }
     433             : #endif
     434             :   // Use ftruncate as a fallback. It may or may not allocate space. At least on
     435             :   // OS X with HFS+ it does.
     436        3629 :   if (::ftruncate(FD, Size) == -1)
     437           0 :     return std::error_code(errno, std::generic_category());
     438             : 
     439        3629 :   return std::error_code();
     440             : }
     441             : 
     442             : static int convertAccessMode(AccessMode Mode) {
     443      180449 :   switch (Mode) {
     444             :   case AccessMode::Exist:
     445             :     return F_OK;
     446         841 :   case AccessMode::Write:
     447             :     return W_OK;
     448       52179 :   case AccessMode::Execute:
     449             :     return R_OK | X_OK; // scripts also need R_OK.
     450             :   }
     451           0 :   llvm_unreachable("invalid enum");
     452             : }
     453             : 
     454      180450 : std::error_code access(const Twine &Path, AccessMode Mode) {
     455      360901 :   SmallString<128> PathStorage;
     456      180450 :   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
     457             : 
     458      180449 :   if (::access(P.begin(), convertAccessMode(Mode)) == -1)
     459      116920 :     return std::error_code(errno, std::generic_category());
     460             : 
     461       63531 :   if (Mode == AccessMode::Execute) {
     462             :     // Don't say that directories are executable.
     463             :     struct stat buf;
     464        6402 :     if (0 != stat(P.begin(), &buf))
     465           0 :       return errc::permission_denied;
     466        3201 :     if (!S_ISREG(buf.st_mode))
     467           1 :       return errc::permission_denied;
     468             :   }
     469             : 
     470       63530 :   return std::error_code();
     471             : }
     472             : 
     473       52179 : bool can_execute(const Twine &Path) {
     474       52179 :   return !access(Path, AccessMode::Execute);
     475             : }
     476             : 
     477          70 : bool equivalent(file_status A, file_status B) {
     478             :   assert(status_known(A) && status_known(B));
     479         140 :   return A.fs_st_dev == B.fs_st_dev &&
     480         140 :          A.fs_st_ino == B.fs_st_ino;
     481             : }
     482             : 
     483         140 : std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
     484         140 :   file_status fsA, fsB;
     485         140 :   if (std::error_code ec = status(A, fsA))
     486          67 :     return ec;
     487          73 :   if (std::error_code ec = status(B, fsB))
     488           5 :     return ec;
     489          68 :   result = equivalent(fsA, fsB);
     490          68 :   return std::error_code();
     491             : }
     492             : 
     493           0 : static void expandTildeExpr(SmallVectorImpl<char> &Path) {
     494           0 :   StringRef PathStr(Path.begin(), Path.size());
     495           0 :   if (PathStr.empty() || !PathStr.startswith("~"))
     496           0 :     return;
     497             : 
     498           0 :   PathStr = PathStr.drop_front();
     499             :   StringRef Expr =
     500           0 :       PathStr.take_until([](char c) { return path::is_separator(c); });
     501           0 :   StringRef Remainder = PathStr.substr(Expr.size() + 1);
     502           0 :   SmallString<128> Storage;
     503           0 :   if (Expr.empty()) {
     504             :     // This is just ~/..., resolve it to the current user's home dir.
     505           0 :     if (!path::home_directory(Storage)) {
     506             :       // For some reason we couldn't get the home directory.  Just exit.
     507             :       return;
     508             :     }
     509             : 
     510             :     // Overwrite the first character and insert the rest.
     511           0 :     Path[0] = Storage[0];
     512           0 :     Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end());
     513           0 :     return;
     514             :   }
     515             : 
     516             :   // This is a string of the form ~username/, look up this user's entry in the
     517             :   // password database.
     518           0 :   struct passwd *Entry = nullptr;
     519           0 :   std::string User = Expr.str();
     520           0 :   Entry = ::getpwnam(User.c_str());
     521             : 
     522           0 :   if (!Entry) {
     523             :     // Unable to look up the entry, just return back the original path.
     524             :     return;
     525             :   }
     526             : 
     527           0 :   Storage = Remainder;
     528           0 :   Path.clear();
     529           0 :   Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir));
     530           0 :   llvm::sys::path::append(Path, Storage);
     531             : }
     532             : 
     533      842327 : static std::error_code fillStatus(int StatRet, const struct stat &Status,
     534             :                              file_status &Result) {
     535      842327 :   if (StatRet != 0) {
     536      460128 :     std::error_code ec(errno, std::generic_category());
     537      460128 :     if (ec == errc::no_such_file_or_directory)
     538      229993 :       Result = file_status(file_type::file_not_found);
     539             :     else
     540          71 :       Result = file_status(file_type::status_error);
     541      230064 :     return ec;
     542             :   }
     543             : 
     544      612263 :   file_type Type = file_type::type_unknown;
     545             : 
     546      612263 :   if (S_ISDIR(Status.st_mode))
     547             :     Type = file_type::directory_file;
     548      251086 :   else if (S_ISREG(Status.st_mode))
     549             :     Type = file_type::regular_file;
     550         330 :   else if (S_ISBLK(Status.st_mode))
     551             :     Type = file_type::block_file;
     552         330 :   else if (S_ISCHR(Status.st_mode))
     553             :     Type = file_type::character_file;
     554          23 :   else if (S_ISFIFO(Status.st_mode))
     555             :     Type = file_type::fifo_file;
     556          20 :   else if (S_ISSOCK(Status.st_mode))
     557             :     Type = file_type::socket_file;
     558          20 :   else if (S_ISLNK(Status.st_mode))
     559          20 :     Type = file_type::symlink_file;
     560             : 
     561     1224526 :   perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
     562      612263 :   Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
     563      612263 :                        Status.st_ino, Status.st_atime, Status.st_mtime,
     564      612263 :                        Status.st_uid, Status.st_gid, Status.st_size);
     565             : 
     566      612263 :   return std::error_code();
     567             : }
     568             : 
     569      710469 : std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
     570     1420939 :   SmallString<128> PathStorage;
     571      710469 :   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
     572             : 
     573             :   struct stat Status;
     574      710470 :   int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
     575     1420940 :   return fillStatus(StatRet, Status, Result);
     576             : }
     577             : 
     578      131856 : std::error_code status(int FD, file_status &Result) {
     579             :   struct stat Status;
     580      131856 :   int StatRet = ::fstat(FD, &Status);
     581      131856 :   return fillStatus(StatRet, Status, Result);
     582             : }
     583             : 
     584          25 : std::error_code setPermissions(const Twine &Path, perms Permissions) {
     585          50 :   SmallString<128> PathStorage;
     586          25 :   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
     587             : 
     588          25 :   if (::chmod(P.begin(), Permissions))
     589           0 :     return std::error_code(errno, std::generic_category());
     590          25 :   return std::error_code();
     591             : }
     592             : 
     593           1 : std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
     594             : #if defined(HAVE_FUTIMENS)
     595             :   timespec Times[2];
     596           1 :   Times[0] = Times[1] = sys::toTimeSpec(Time);
     597           1 :   if (::futimens(FD, Times))
     598           0 :     return std::error_code(errno, std::generic_category());
     599           1 :   return std::error_code();
     600             : #elif defined(HAVE_FUTIMES)
     601             :   timeval Times[2];
     602             :   Times[0] = Times[1] = sys::toTimeVal(
     603             :       std::chrono::time_point_cast<std::chrono::microseconds>(Time));
     604             :   if (::futimes(FD, Times))
     605             :     return std::error_code(errno, std::generic_category());
     606             :   return std::error_code();
     607             : #else
     608             : #warning Missing futimes() and futimens()
     609             :   return make_error_code(errc::function_not_supported);
     610             : #endif
     611             : }
     612             : 
     613       26838 : std::error_code mapped_file_region::init(int FD, uint64_t Offset,
     614             :                                          mapmode Mode) {
     615             :   assert(Size != 0);
     616             : 
     617       26838 :   int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
     618       26838 :   int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
     619             : #if defined(__APPLE__)
     620             :   //----------------------------------------------------------------------
     621             :   // Newer versions of MacOSX have a flag that will allow us to read from
     622             :   // binaries whose code signature is invalid without crashing by using
     623             :   // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
     624             :   // is mapped we can avoid crashing and return zeroes to any pages we try
     625             :   // to read if the media becomes unavailable by using the
     626             :   // MAP_RESILIENT_MEDIA flag.  These flags are only usable when mapping
     627             :   // with PROT_READ, so take care not to specify them otherwise.
     628             :   //----------------------------------------------------------------------
     629             :   if (Mode == readonly) {
     630             : #if defined(MAP_RESILIENT_CODESIGN)
     631             :     flags |= MAP_RESILIENT_CODESIGN;
     632             : #endif
     633             : #if defined(MAP_RESILIENT_MEDIA)
     634             :     flags |= MAP_RESILIENT_MEDIA;
     635             : #endif
     636             :   }
     637             : #endif // #if defined (__APPLE__)
     638             : 
     639       26838 :   Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
     640       26838 :   if (Mapping == MAP_FAILED)
     641           0 :     return std::error_code(errno, std::generic_category());
     642       26838 :   return std::error_code();
     643             : }
     644             : 
     645       26838 : mapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length,
     646       26838 :                                        uint64_t offset, std::error_code &ec)
     647       26838 :     : Size(length), Mapping() {
     648             :   // Make sure that the requested size fits within SIZE_T.
     649             :   if (length > std::numeric_limits<size_t>::max()) {
     650             :     ec = make_error_code(errc::invalid_argument);
     651             :     return;
     652             :   }
     653             : 
     654       26838 :   ec = init(fd, offset, mode);
     655       26838 :   if (ec)
     656           0 :     Mapping = nullptr;
     657             : }
     658             : 
     659       45420 : mapped_file_region::~mapped_file_region() {
     660       22710 :   if (Mapping)
     661       22710 :     ::munmap(Mapping, Size);
     662       22710 : }
     663             : 
     664         159 : uint64_t mapped_file_region::size() const {
     665             :   assert(Mapping && "Mapping failed but used anyway!");
     666         159 :   return Size;
     667             : }
     668             : 
     669        5370 : char *mapped_file_region::data() const {
     670             :   assert(Mapping && "Mapping failed but used anyway!");
     671        5370 :   return reinterpret_cast<char*>(Mapping);
     672             : }
     673             : 
     674       23112 : const char *mapped_file_region::const_data() const {
     675             :   assert(Mapping && "Mapping failed but used anyway!");
     676       23112 :   return reinterpret_cast<const char*>(Mapping);
     677             : }
     678             : 
     679       69333 : int mapped_file_region::alignment() {
     680       69333 :   return Process::getPageSize();
     681             : }
     682             : 
     683     1193011 : std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
     684             :                                                      StringRef path,
     685             :                                                      bool follow_symlinks) {
     686     2386022 :   SmallString<128> path_null(path);
     687     1193011 :   DIR *directory = ::opendir(path_null.c_str());
     688     1193011 :   if (!directory)
     689     1182160 :     return std::error_code(errno, std::generic_category());
     690             : 
     691       10851 :   it.IterationHandle = reinterpret_cast<intptr_t>(directory);
     692             :   // Add something for replace_filename to replace.
     693       43404 :   path::append(path_null, ".");
     694       65106 :   it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
     695       10851 :   return directory_iterator_increment(it);
     696             : }
     697             : 
     698     1203846 : std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
     699     1203846 :   if (it.IterationHandle)
     700       10851 :     ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
     701     1203846 :   it.IterationHandle = 0;
     702     4815384 :   it.CurrentEntry = directory_entry();
     703     1203846 :   return std::error_code();
     704             : }
     705             : 
     706      145223 : std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
     707      145223 :   errno = 0;
     708      145223 :   dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
     709      145223 :   if (cur_dir == nullptr && errno != 0) {
     710           0 :     return std::error_code(errno, std::generic_category());
     711      145223 :   } else if (cur_dir != nullptr) {
     712      268776 :     StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
     713      295215 :     if ((name.size() == 1 && name[0] == '.') ||
     714      156128 :         (name.size() == 2 && name[0] == '.' && name[1] == '.'))
     715       21670 :       return directory_iterator_increment(it);
     716      338154 :     it.CurrentEntry.replace_filename(name);
     717             :   } else
     718       10835 :     return directory_iterator_destruct(it);
     719             : 
     720      112718 :   return std::error_code();
     721             : }
     722             : 
     723             : #if !defined(F_GETPATH)
     724       61228 : static bool hasProcSelfFD() {
     725             :   // If we have a /proc filesystem mounted, we can quickly establish the
     726             :   // real name of the file with readlink
     727       61228 :   static const bool Result = (::access("/proc/self/fd", R_OK) == 0);
     728       61228 :   return Result;
     729             : }
     730             : #endif
     731             : 
     732      414057 : std::error_code openFileForRead(const Twine &Name, int &ResultFD,
     733             :                                 SmallVectorImpl<char> *RealPath) {
     734      828116 :   SmallString<128> Storage;
     735      414057 :   StringRef P = Name.toNullTerminatedStringRef(Storage);
     736             :   int OpenFlags = O_RDONLY;
     737             : #ifdef O_CLOEXEC
     738      414059 :   OpenFlags |= O_CLOEXEC;
     739             : #endif
     740      414059 :   if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0)
     741      197140 :     return std::error_code(errno, std::generic_category());
     742             : #ifndef O_CLOEXEC
     743             :   int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
     744             :   (void)r;
     745             :   assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
     746             : #endif
     747             :   // Attempt to get the real name of the file, if the user asked
     748      216919 :   if(!RealPath)
     749      155691 :     return std::error_code();
     750       61228 :   RealPath->clear();
     751             : #if defined(F_GETPATH)
     752             :   // When F_GETPATH is availble, it is the quickest way to get
     753             :   // the real path name.
     754             :   char Buffer[MAXPATHLEN];
     755             :   if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1)
     756             :     RealPath->append(Buffer, Buffer + strlen(Buffer));
     757             : #else
     758             :   char Buffer[PATH_MAX];
     759       61228 :   if (hasProcSelfFD()) {
     760             :     char ProcPath[64];
     761       61228 :     snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD);
     762       61228 :     ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer));
     763       61228 :     if (CharCount > 0)
     764       61228 :       RealPath->append(Buffer, Buffer + CharCount);
     765             :   } else {
     766             :     // Use ::realpath to get the real path name
     767           0 :     if (::realpath(P.begin(), Buffer) != nullptr)
     768           0 :       RealPath->append(Buffer, Buffer + strlen(Buffer));
     769             :   }
     770             : #endif
     771       61228 :   return std::error_code();
     772             : }
     773             : 
     774       17570 : std::error_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_CREAT;
     781             : 
     782             : #ifdef O_CLOEXEC
     783       17570 :   OpenFlags |= O_CLOEXEC;
     784             : #endif
     785             : 
     786       17570 :   if (Flags & F_RW)
     787        9727 :     OpenFlags |= O_RDWR;
     788             :   else
     789        7843 :     OpenFlags |= O_WRONLY;
     790             : 
     791       17570 :   if (Flags & F_Append)
     792           5 :     OpenFlags |= O_APPEND;
     793             :   else
     794       17565 :     OpenFlags |= O_TRUNC;
     795             : 
     796       17570 :   if (Flags & F_Excl)
     797        9697 :     OpenFlags |= O_EXCL;
     798             : 
     799       35140 :   SmallString<128> Storage;
     800       17570 :   StringRef P = Name.toNullTerminatedStringRef(Storage);
     801       17570 :   if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0)
     802         381 :     return std::error_code(errno, std::generic_category());
     803             : #ifndef O_CLOEXEC
     804             :   int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
     805             :   (void)r;
     806             :   assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
     807             : #endif
     808       17189 :   return std::error_code();
     809             : }
     810             : 
     811             : template <typename T>
     812          20 : static std::error_code remove_directories_impl(const T &Entry,
     813             :                                                bool IgnoreErrors) {
     814          20 :   std::error_code EC;
     815          40 :   directory_iterator Begin(Entry, EC, false);
     816          40 :   directory_iterator End;
     817          74 :   while (Begin != End) {
     818          27 :     auto &Item = *Begin;
     819          27 :     file_status st;
     820          27 :     EC = Item.status(st);
     821          27 :     if (EC && !IgnoreErrors)
     822           0 :       return EC;
     823             : 
     824          27 :     if (is_directory(st)) {
     825          11 :       EC = remove_directories_impl(Item, IgnoreErrors);
     826          11 :       if (EC && !IgnoreErrors)
     827           0 :         return EC;
     828             :     }
     829             : 
     830          54 :     EC = fs::remove(Item.path(), true);
     831          27 :     if (EC && !IgnoreErrors)
     832           0 :       return EC;
     833             : 
     834          27 :     Begin.increment(EC);
     835          27 :     if (EC && !IgnoreErrors)
     836           0 :       return EC;
     837             :   }
     838          20 :   return std::error_code();
     839             : }
     840             : 
     841           9 : std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
     842           9 :   auto EC = remove_directories_impl(path, IgnoreErrors);
     843           9 :   if (EC && !IgnoreErrors)
     844           0 :     return EC;
     845           9 :   EC = fs::remove(path, true);
     846           9 :   if (EC && !IgnoreErrors)
     847           0 :     return EC;
     848           9 :   return std::error_code();
     849             : }
     850             : 
     851           2 : std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
     852             :                           bool expand_tilde) {
     853           2 :   dest.clear();
     854           2 :   if (path.isTriviallyEmpty())
     855           0 :     return std::error_code();
     856             : 
     857           2 :   if (expand_tilde) {
     858           0 :     SmallString<128> Storage;
     859           0 :     path.toVector(Storage);
     860           0 :     expandTildeExpr(Storage);
     861           0 :     return real_path(Storage, dest, false);
     862             :   }
     863             : 
     864             :   int fd;
     865           2 :   std::error_code EC = openFileForRead(path, fd, &dest);
     866             : 
     867           2 :   if (EC)
     868           0 :     return EC;
     869           2 :   ::close(fd);
     870           2 :   return std::error_code();
     871             : }
     872             : 
     873             : } // end namespace fs
     874             : 
     875             : namespace path {
     876             : 
     877        3354 : bool home_directory(SmallVectorImpl<char> &result) {
     878        3354 :   char *RequestedDir = getenv("HOME");
     879        3354 :   if (!RequestedDir) {
     880           6 :     struct passwd *pw = getpwuid(getuid());
     881           6 :     if (pw && pw->pw_dir)
     882           6 :       RequestedDir = pw->pw_dir;
     883             :   }
     884        3354 :   if (!RequestedDir)
     885             :     return false;
     886             : 
     887        3354 :   result.clear();
     888        3354 :   result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
     889        3354 :   return true;
     890             : }
     891             : 
     892             : static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
     893             :   #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR)
     894             :   // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR.
     895             :   // macros defined in <unistd.h> on darwin >= 9
     896             :   int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR
     897             :                          : _CS_DARWIN_USER_CACHE_DIR;
     898             :   size_t ConfLen = confstr(ConfName, nullptr, 0);
     899             :   if (ConfLen > 0) {
     900             :     do {
     901             :       Result.resize(ConfLen);
     902             :       ConfLen = confstr(ConfName, Result.data(), Result.size());
     903             :     } while (ConfLen > 0 && ConfLen != Result.size());
     904             : 
     905             :     if (ConfLen > 0) {
     906             :       assert(Result.back() == 0);
     907             :       Result.pop_back();
     908             :       return true;
     909             :     }
     910             : 
     911             :     Result.clear();
     912             :   }
     913             :   #endif
     914             :   return false;
     915             : }
     916             : 
     917           4 : static bool getUserCacheDir(SmallVectorImpl<char> &Result) {
     918             :   // First try using XDG_CACHE_HOME env variable,
     919             :   // as specified in XDG Base Directory Specification at
     920             :   // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
     921           4 :   if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) {
     922           0 :     Result.clear();
     923           0 :     Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir));
     924           0 :     return true;
     925             :   }
     926             : 
     927             :   // Try Darwin configuration query
     928           4 :   if (getDarwinConfDir(false, Result))
     929             :     return true;
     930             : 
     931             :   // Use "$HOME/.cache" if $HOME is available
     932           4 :   if (home_directory(Result)) {
     933          16 :     append(Result, ".cache");
     934           4 :     return true;
     935             :   }
     936             : 
     937             :   return false;
     938             : }
     939             : 
     940        4679 : static const char *getEnvTempDir() {
     941             :   // Check whether the temporary directory is specified by an environment
     942             :   // variable.
     943        4679 :   const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
     944        4707 :   for (const char *Env : EnvironmentVariables) {
     945        4700 :     if (const char *Dir = std::getenv(Env))
     946             :       return Dir;
     947             :   }
     948             : 
     949             :   return nullptr;
     950             : }
     951             : 
     952             : static const char *getDefaultTempDir(bool ErasedOnReboot) {
     953             : #ifdef P_tmpdir
     954             :   if ((bool)P_tmpdir)
     955             :     return P_tmpdir;
     956             : #endif
     957             : 
     958             :   if (ErasedOnReboot)
     959             :     return "/tmp";
     960             :   return "/var/tmp";
     961             : }
     962             : 
     963        4694 : void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
     964        4694 :   Result.clear();
     965             : 
     966        4694 :   if (ErasedOnReboot) {
     967             :     // There is no env variable for the cache directory.
     968        4679 :     if (const char *RequestedDir = getEnvTempDir()) {
     969        4672 :       Result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
     970        4672 :       return;
     971             :     }
     972             :   }
     973             : 
     974          22 :   if (getDarwinConfDir(ErasedOnReboot, Result))
     975             :     return;
     976             : 
     977          22 :   const char *RequestedDir = getDefaultTempDir(ErasedOnReboot);
     978          22 :   Result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
     979             : }
     980             : 
     981             : } // end namespace path
     982             : 
     983             : } // end namespace sys
     984             : } // end namespace llvm

Generated by: LCOV version 1.13