LCOV - code coverage report
Current view: top level - lib/Support/Unix - Path.inc (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 280 343 81.6 %
Date: 2018-02-19 03:08:00 Functions: 46 50 92.0 %
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       34620 : 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             :   StringRef aPath("/proc/self/exe");
     193       34620 :   if (sys::fs::exists(aPath)) {
     194             :       // /proc is not always mounted under Linux (chroot for example).
     195       69240 :       ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
     196       34620 :       if (len >= 0)
     197       34620 :           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          38 : TimePoint<> basic_file_status::getLastAccessedTime() const {
     222          76 :   return toTimePoint(fs_st_atime);
     223             : }
     224             : 
     225     1535663 : TimePoint<> basic_file_status::getLastModificationTime() const {
     226     3071326 :   return toTimePoint(fs_st_mtime);
     227             : }
     228             : 
     229     1630621 : UniqueID file_status::getUniqueID() const {
     230     1630621 :   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          15 : ErrorOr<space_info> disk_space(const Twine &Path) {
     238             :   struct STATVFS Vfs;
     239          45 :   if (::STATVFS(Path.str().c_str(), &Vfs))
     240           0 :     return std::error_code(errno, std::generic_category());
     241          15 :   auto FrSize = STATVFS_F_FRSIZE(Vfs);
     242             :   space_info SpaceInfo;
     243          15 :   SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize;
     244          15 :   SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize;
     245          15 :   SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize;
     246             :   return SpaceInfo;
     247             : }
     248             : 
     249       53239 : std::error_code current_path(SmallVectorImpl<char> &result) {
     250             :   result.clear();
     251             : 
     252       53239 :   const char *pwd = ::getenv("PWD");
     253       53239 :   llvm::sys::fs::file_status PWDStatus, DotStatus;
     254      142867 :   if (pwd && llvm::sys::path::is_absolute(pwd) &&
     255      142867 :       !llvm::sys::fs::status(pwd, PWDStatus) &&
     256      151292 :       !llvm::sys::fs::status(".", DotStatus) &&
     257       98053 :       PWDStatus.getUniqueID() == DotStatus.getUniqueID()) {
     258       37543 :     result.append(pwd, pwd + strlen(pwd));
     259       37543 :     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       15696 :     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       15696 :   result.set_size(strlen(result.data()));
     281       15696 :   return std::error_code();
     282             : }
     283             : 
     284        9354 : std::error_code set_current_path(const Twine &path) {
     285             :   SmallString<128> path_storage;
     286        9354 :   StringRef p = path.toNullTerminatedStringRef(path_storage);
     287             : 
     288        9354 :   if (::chdir(p.begin()) == -1)
     289          41 :     return std::error_code(errno, std::generic_category());
     290             : 
     291        9313 :   return std::error_code();
     292             : }
     293             : 
     294        3068 : std::error_code create_directory(const Twine &path, bool IgnoreExisting,
     295             :                                  perms Perms) {
     296             :   SmallString<128> path_storage;
     297        3068 :   StringRef p = path.toNullTerminatedStringRef(path_storage);
     298             : 
     299        3068 :   if (::mkdir(p.begin(), Perms) == -1) {
     300        1621 :     if (errno != EEXIST || !IgnoreExisting)
     301         581 :       return std::error_code(errno, std::generic_category());
     302             :   }
     303             : 
     304        2487 :   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        1854 : std::error_code create_link(const Twine &to, const Twine &from) {
     310             :   // Get arguments.
     311             :   SmallString<128> from_storage;
     312             :   SmallString<128> to_storage;
     313        1854 :   StringRef f = from.toNullTerminatedStringRef(from_storage);
     314        1854 :   StringRef t = to.toNullTerminatedStringRef(to_storage);
     315             : 
     316        1854 :   if (::symlink(t.begin(), f.begin()) == -1)
     317           0 :     return std::error_code(errno, std::generic_category());
     318             : 
     319        1854 :   return std::error_code();
     320             : }
     321             : 
     322           4 : std::error_code create_hard_link(const Twine &to, const Twine &from) {
     323             :   // Get arguments.
     324             :   SmallString<128> from_storage;
     325             :   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       11143 : std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
     336             :   SmallString<128> path_storage;
     337       11143 :   StringRef p = path.toNullTerminatedStringRef(path_storage);
     338             : 
     339             :   struct stat buf;
     340       11143 :   if (lstat(p.begin(), &buf) != 0) {
     341        2538 :     if (errno != ENOENT || !IgnoreNonExisting)
     342           1 :       return std::error_code(errno, std::generic_category());
     343        2537 :     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        8605 :   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        8329 :   if (::remove(p.begin()) == -1) {
     355           2 :     if (errno != ENOENT || !IgnoreNonExisting)
     356           2 :       return std::error_code(errno, std::generic_category());
     357             :   }
     358             : 
     359        8327 :   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       11190 :   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       11190 :   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       23577 : std::error_code is_local(const Twine &Path, bool &Result) {
     395             :   struct STATVFS Vfs;
     396       70731 :   if (::STATVFS(Path.str().c_str(), &Vfs))
     397       12387 :     return std::error_code(errno, std::generic_category());
     398             : 
     399       22380 :   Result = is_local_impl(Vfs);
     400       11190 :   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       10079 : std::error_code rename(const Twine &from, const Twine &to) {
     413             :   // Get arguments.
     414             :   SmallString<128> from_storage;
     415             :   SmallString<128> to_storage;
     416       10079 :   StringRef f = from.toNullTerminatedStringRef(from_storage);
     417       10079 :   StringRef t = to.toNullTerminatedStringRef(to_storage);
     418             : 
     419       10079 :   if (::rename(f.begin(), t.begin()) == -1)
     420           0 :     return std::error_code(errno, std::generic_category());
     421             : 
     422       10079 :   return std::error_code();
     423             : }
     424             : 
     425        4384 : 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        4384 :   if (int Err = ::posix_fallocate(FD, 0, Size)) {
     430           0 :     if (Err != EINVAL && 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        4384 :   if (::ftruncate(FD, Size) == -1)
     437           0 :     return std::error_code(errno, std::generic_category());
     438             : 
     439        4384 :   return std::error_code();
     440             : }
     441             : 
     442             : static int convertAccessMode(AccessMode Mode) {
     443      425055 :   switch (Mode) {
     444             :   case AccessMode::Exist:
     445             :     return F_OK;
     446        2143 :   case AccessMode::Write:
     447             :     return W_OK;
     448      181132 :   case AccessMode::Execute:
     449             :     return R_OK | X_OK; // scripts also need R_OK.
     450             :   }
     451           0 :   llvm_unreachable("invalid enum");
     452             : }
     453             : 
     454      425055 : std::error_code access(const Twine &Path, AccessMode Mode) {
     455             :   SmallString<128> PathStorage;
     456      425055 :   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
     457             : 
     458      425055 :   if (::access(P.begin(), convertAccessMode(Mode)) == -1)
     459      305138 :     return std::error_code(errno, std::generic_category());
     460             : 
     461      119917 :   if (Mode == AccessMode::Execute) {
     462             :     // Don't say that directories are executable.
     463             :     struct stat buf;
     464        5664 :     if (0 != stat(P.begin(), &buf))
     465           0 :       return errc::permission_denied;
     466        5664 :     if (!S_ISREG(buf.st_mode))
     467           1 :       return errc::permission_denied;
     468             :   }
     469             : 
     470      119916 :   return std::error_code();
     471             : }
     472             : 
     473      181132 : bool can_execute(const Twine &Path) {
     474      181132 :   return !access(Path, AccessMode::Execute);
     475             : }
     476             : 
     477         243 : bool equivalent(file_status A, file_status B) {
     478             :   assert(status_known(A) && status_known(B));
     479         486 :   return A.fs_st_dev == B.fs_st_dev &&
     480         486 :          A.fs_st_ino == B.fs_st_ino;
     481             : }
     482             : 
     483        3403 : std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
     484        3403 :   file_status fsA, fsB;
     485        3403 :   if (std::error_code ec = status(A, fsA))
     486        3157 :     return ec;
     487         246 :   if (std::error_code ec = status(B, fsB))
     488           5 :     return ec;
     489         241 :   result = equivalent(fsA, fsB);
     490         241 :   return std::error_code();
     491             : }
     492             : 
     493          38 : static void expandTildeExpr(SmallVectorImpl<char> &Path) {
     494             :   StringRef PathStr(Path.begin(), Path.size());
     495          38 :   if (PathStr.empty() || !PathStr.startswith("~"))
     496          38 :     return;
     497             : 
     498          38 :   PathStr = PathStr.drop_front();
     499             :   StringRef Expr =
     500          38 :       PathStr.take_until([](char c) { return path::is_separator(c); });
     501          38 :   StringRef Remainder = PathStr.substr(Expr.size() + 1);
     502             :   SmallString<128> Storage;
     503          38 :   if (Expr.empty()) {
     504             :     // This is just ~/..., resolve it to the current user's home dir.
     505          38 :     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          38 :     Path[0] = Storage[0];
     512          76 :     Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end());
     513          38 :     return;
     514             :   }
     515             : 
     516             :   // This is a string of the form ~username/, look up this user's entry in the
     517             :   // password database.
     518             :   struct passwd *Entry = nullptr;
     519             :   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             :   Storage = Remainder;
     528             :   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     2755567 : static std::error_code fillStatus(int StatRet, const struct stat &Status,
     534             :                              file_status &Result) {
     535     2755567 :   if (StatRet != 0) {
     536      966101 :     std::error_code ec(errno, std::generic_category());
     537             :     if (ec == errc::no_such_file_or_directory)
     538      966030 :       Result = file_status(file_type::file_not_found);
     539             :     else
     540          71 :       Result = file_status(file_type::status_error);
     541      966101 :     return ec;
     542             :   }
     543             : 
     544             :   file_type Type = file_type::type_unknown;
     545             : 
     546     1789466 :   if (S_ISDIR(Status.st_mode))
     547             :     Type = file_type::directory_file;
     548      807512 :   else if (S_ISREG(Status.st_mode))
     549             :     Type = file_type::regular_file;
     550         367 :   else if (S_ISBLK(Status.st_mode))
     551             :     Type = file_type::block_file;
     552         367 :   else if (S_ISCHR(Status.st_mode))
     553             :     Type = file_type::character_file;
     554          27 :   else if (S_ISFIFO(Status.st_mode))
     555             :     Type = file_type::fifo_file;
     556          24 :   else if (S_ISSOCK(Status.st_mode))
     557             :     Type = file_type::socket_file;
     558          24 :   else if (S_ISLNK(Status.st_mode))
     559             :     Type = file_type::symlink_file;
     560             : 
     561             :   perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
     562     1789466 :   Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
     563     1789466 :                        Status.st_ino, Status.st_atime, Status.st_mtime,
     564     1789466 :                        Status.st_uid, Status.st_gid, Status.st_size);
     565             : 
     566     1789466 :   return std::error_code();
     567             : }
     568             : 
     569     2180445 : std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
     570             :   SmallString<128> PathStorage;
     571     2180445 :   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
     572             : 
     573             :   struct stat Status;
     574     2180440 :   int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
     575     4360870 :   return fillStatus(StatRet, Status, Result);
     576             : }
     577             : 
     578      575130 : std::error_code status(int FD, file_status &Result) {
     579             :   struct stat Status;
     580             :   int StatRet = ::fstat(FD, &Status);
     581      575130 :   return fillStatus(StatRet, Status, Result);
     582             : }
     583             : 
     584          27 : std::error_code setPermissions(const Twine &Path, perms Permissions) {
     585             :   SmallString<128> PathStorage;
     586          27 :   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
     587             : 
     588          27 :   if (::chmod(P.begin(), Permissions))
     589           0 :     return std::error_code(errno, std::generic_category());
     590          27 :   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       82543 : std::error_code mapped_file_region::init(int FD, uint64_t Offset,
     614             :                                          mapmode Mode) {
     615             :   assert(Size != 0);
     616             : 
     617       82543 :   int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
     618       82543 :   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       82543 :   Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
     640       82543 :   if (Mapping == MAP_FAILED)
     641           0 :     return std::error_code(errno, std::generic_category());
     642       82543 :   return std::error_code();
     643             : }
     644             : 
     645       82543 : mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
     646       82543 :                                        uint64_t offset, std::error_code &ec)
     647       82543 :     : Size(length), Mapping(), FD(fd), Mode(mode) {
     648             :   (void)FD;
     649             :   (void)Mode;
     650       82543 :   ec = init(fd, offset, mode);
     651       82543 :   if (ec)
     652           0 :     Mapping = nullptr;
     653       82543 : }
     654             : 
     655       64498 : mapped_file_region::~mapped_file_region() {
     656       32249 :   if (Mapping)
     657       32249 :     ::munmap(Mapping, Size);
     658       32249 : }
     659             : 
     660         181 : size_t mapped_file_region::size() const {
     661             :   assert(Mapping && "Mapping failed but used anyway!");
     662         181 :   return Size;
     663             : }
     664             : 
     665        7088 : char *mapped_file_region::data() const {
     666             :   assert(Mapping && "Mapping failed but used anyway!");
     667        7088 :   return reinterpret_cast<char*>(Mapping);
     668             : }
     669             : 
     670       78059 : const char *mapped_file_region::const_data() const {
     671             :   assert(Mapping && "Mapping failed but used anyway!");
     672       78059 :   return reinterpret_cast<const char*>(Mapping);
     673             : }
     674             : 
     675      234174 : int mapped_file_region::alignment() {
     676      234174 :   return Process::getPageSize();
     677             : }
     678             : 
     679     3070690 : std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
     680             :                                                      StringRef path,
     681             :                                                      bool follow_symlinks) {
     682             :   SmallString<128> path_null(path);
     683     3070689 :   DIR *directory = ::opendir(path_null.c_str());
     684     3070683 :   if (!directory)
     685     3041498 :     return std::error_code(errno, std::generic_category());
     686             : 
     687       29185 :   it.IterationHandle = reinterpret_cast<intptr_t>(directory);
     688             :   // Add something for replace_filename to replace.
     689       29185 :   path::append(path_null, ".");
     690       58370 :   it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
     691       29185 :   return directory_iterator_increment(it);
     692             : }
     693             : 
     694     3099873 : std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
     695     3099873 :   if (it.IterationHandle)
     696       29185 :     ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
     697     3099873 :   it.IterationHandle = 0;
     698     6199788 :   it.CurrentEntry = directory_entry();
     699     3099915 :   return std::error_code();
     700             : }
     701             : 
     702      473226 : std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
     703      473226 :   errno = 0;
     704      473226 :   dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
     705      473226 :   if (cur_dir == nullptr && errno != 0) {
     706           0 :     return std::error_code(errno, std::generic_category());
     707      473226 :   } else if (cur_dir != nullptr) {
     708      444057 :     StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
     709      581005 :     if ((name.size() == 1 && name[0] == '.') ||
     710       58373 :         (name.size() == 2 && name[0] == '.' && name[1] == '.'))
     711       58338 :       return directory_iterator_increment(it);
     712      771438 :     it.CurrentEntry.replace_filename(name);
     713             :   } else
     714       29169 :     return directory_iterator_destruct(it);
     715             : 
     716      385719 :   return std::error_code();
     717             : }
     718             : 
     719         365 : ErrorOr<basic_file_status> directory_entry::status() const {
     720         365 :   file_status s;
     721         730 :   if (auto EC = fs::status(Path, s, FollowSymlinks))
     722           5 :     return EC;
     723             :   return s;
     724             : }
     725             : 
     726             : #if !defined(F_GETPATH)
     727      491276 : static bool hasProcSelfFD() {
     728             :   // If we have a /proc filesystem mounted, we can quickly establish the
     729             :   // real name of the file with readlink
     730      491276 :   static const bool Result = (::access("/proc/self/fd", R_OK) == 0);
     731      491276 :   return Result;
     732             : }
     733             : #endif
     734             : 
     735     1776915 : std::error_code openFileForRead(const Twine &Name, int &ResultFD,
     736             :                                 SmallVectorImpl<char> *RealPath) {
     737             :   SmallString<128> Storage;
     738     1776915 :   StringRef P = Name.toNullTerminatedStringRef(Storage);
     739             :   int OpenFlags = O_RDONLY;
     740             : #ifdef O_CLOEXEC
     741     1776916 :   OpenFlags |= O_CLOEXEC;
     742             : #endif
     743     1776916 :   if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0)
     744     1090631 :     return std::error_code(errno, std::generic_category());
     745             : #ifndef O_CLOEXEC
     746             :   int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
     747             :   (void)r;
     748             :   assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
     749             : #endif
     750             :   // Attempt to get the real name of the file, if the user asked
     751      686285 :   if(!RealPath)
     752      195009 :     return std::error_code();
     753             :   RealPath->clear();
     754             : #if defined(F_GETPATH)
     755             :   // When F_GETPATH is availble, it is the quickest way to get
     756             :   // the real path name.
     757             :   char Buffer[MAXPATHLEN];
     758             :   if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1)
     759             :     RealPath->append(Buffer, Buffer + strlen(Buffer));
     760             : #else
     761             :   char Buffer[PATH_MAX];
     762      491276 :   if (hasProcSelfFD()) {
     763             :     char ProcPath[64];
     764      491275 :     snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD);
     765      491275 :     ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer));
     766      491276 :     if (CharCount > 0)
     767      491276 :       RealPath->append(Buffer, Buffer + CharCount);
     768             :   } else {
     769             :     // Use ::realpath to get the real path name
     770           0 :     if (::realpath(P.begin(), Buffer) != nullptr)
     771           0 :       RealPath->append(Buffer, Buffer + strlen(Buffer));
     772             :   }
     773             : #endif
     774      491276 :   return std::error_code();
     775             : }
     776             : 
     777       24232 : std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
     778             :                             sys::fs::OpenFlags Flags, unsigned Mode) {
     779             :   // Verify that we don't have both "append" and "excl".
     780             :   assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
     781             :          "Cannot specify both 'excl' and 'append' file creation flags!");
     782             : 
     783             :   int OpenFlags = O_CREAT;
     784             : 
     785             : #ifdef O_CLOEXEC
     786       24232 :   OpenFlags |= O_CLOEXEC;
     787             : #endif
     788             : 
     789       24232 :   if (Flags & F_RW)
     790       14624 :     OpenFlags |= O_RDWR;
     791             :   else
     792        9608 :     OpenFlags |= O_WRONLY;
     793             : 
     794       24232 :   if (Flags & F_Append)
     795           5 :     OpenFlags |= O_APPEND;
     796             :   else
     797       24227 :     OpenFlags |= O_TRUNC;
     798             : 
     799       24232 :   if (Flags & F_Excl)
     800       14490 :     OpenFlags |= O_EXCL;
     801             : 
     802             :   SmallString<128> Storage;
     803       24232 :   StringRef P = Name.toNullTerminatedStringRef(Storage);
     804       24232 :   if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0)
     805         930 :     return std::error_code(errno, std::generic_category());
     806             : #ifndef O_CLOEXEC
     807             :   int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
     808             :   (void)r;
     809             :   assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
     810             : #endif
     811       23302 :   return std::error_code();
     812             : }
     813             : 
     814             : template <typename T>
     815          21 : static std::error_code remove_directories_impl(const T &Entry,
     816             :                                                bool IgnoreErrors) {
     817             :   std::error_code EC;
     818          21 :   directory_iterator Begin(Entry, EC, false);
     819          21 :   directory_iterator End;
     820          51 :   while (Begin != End) {
     821             :     auto &Item = *Begin;
     822          30 :     ErrorOr<basic_file_status> st = Item.status();
     823          30 :     if (!st && !IgnoreErrors)
     824             :       return st.getError();
     825             : 
     826          30 :     if (is_directory(*st)) {
     827          11 :       EC = remove_directories_impl(Item, IgnoreErrors);
     828          11 :       if (EC && !IgnoreErrors)
     829           0 :         return EC;
     830             :     }
     831             : 
     832          30 :     EC = fs::remove(Item.path(), true);
     833          30 :     if (EC && !IgnoreErrors)
     834           0 :       return EC;
     835             : 
     836             :     Begin.increment(EC);
     837          30 :     if (EC && !IgnoreErrors)
     838           0 :       return EC;
     839             :   }
     840          21 :   return std::error_code();
     841             : }
     842             : 
     843          10 : std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
     844          10 :   auto EC = remove_directories_impl(path, IgnoreErrors);
     845          10 :   if (EC && !IgnoreErrors)
     846           0 :     return EC;
     847          10 :   EC = fs::remove(path, true);
     848          10 :   if (EC && !IgnoreErrors)
     849           0 :     return EC;
     850          10 :   return std::error_code();
     851             : }
     852             : 
     853          83 : std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
     854             :                           bool expand_tilde) {
     855             :   dest.clear();
     856             :   if (path.isTriviallyEmpty())
     857           0 :     return std::error_code();
     858             : 
     859          83 :   if (expand_tilde) {
     860             :     SmallString<128> Storage;
     861          38 :     path.toVector(Storage);
     862          38 :     expandTildeExpr(Storage);
     863          38 :     return real_path(Storage, dest, false);
     864             :   }
     865             : 
     866             :   SmallString<128> Storage;
     867          45 :   StringRef P = path.toNullTerminatedStringRef(Storage);
     868             :   char Buffer[PATH_MAX];
     869          45 :   if (::realpath(P.begin(), Buffer) == nullptr)
     870          38 :     return std::error_code(errno, std::generic_category());
     871           7 :   dest.append(Buffer, Buffer + strlen(Buffer));
     872           7 :   return std::error_code();
     873             : }
     874             : 
     875             : } // end namespace fs
     876             : 
     877             : namespace path {
     878             : 
     879        3287 : bool home_directory(SmallVectorImpl<char> &result) {
     880        3287 :   char *RequestedDir = getenv("HOME");
     881        3287 :   if (!RequestedDir) {
     882           6 :     struct passwd *pw = getpwuid(getuid());
     883           6 :     if (pw && pw->pw_dir)
     884             :       RequestedDir = pw->pw_dir;
     885             :   }
     886        3287 :   if (!RequestedDir)
     887             :     return false;
     888             : 
     889             :   result.clear();
     890        3287 :   result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
     891        3287 :   return true;
     892             : }
     893             : 
     894             : static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
     895             :   #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR)
     896             :   // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR.
     897             :   // macros defined in <unistd.h> on darwin >= 9
     898             :   int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR
     899             :                          : _CS_DARWIN_USER_CACHE_DIR;
     900             :   size_t ConfLen = confstr(ConfName, nullptr, 0);
     901             :   if (ConfLen > 0) {
     902             :     do {
     903             :       Result.resize(ConfLen);
     904             :       ConfLen = confstr(ConfName, Result.data(), Result.size());
     905             :     } while (ConfLen > 0 && ConfLen != Result.size());
     906             : 
     907             :     if (ConfLen > 0) {
     908             :       assert(Result.back() == 0);
     909             :       Result.pop_back();
     910             :       return true;
     911             :     }
     912             : 
     913             :     Result.clear();
     914             :   }
     915             :   #endif
     916             :   return false;
     917             : }
     918             : 
     919           4 : static bool getUserCacheDir(SmallVectorImpl<char> &Result) {
     920             :   // First try using XDG_CACHE_HOME env variable,
     921             :   // as specified in XDG Base Directory Specification at
     922             :   // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
     923           4 :   if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) {
     924             :     Result.clear();
     925           0 :     Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir));
     926           0 :     return true;
     927             :   }
     928             : 
     929             :   // Try Darwin configuration query
     930             :   if (getDarwinConfDir(false, Result))
     931             :     return true;
     932             : 
     933             :   // Use "$HOME/.cache" if $HOME is available
     934           4 :   if (home_directory(Result)) {
     935           4 :     append(Result, ".cache");
     936           4 :     return true;
     937             :   }
     938             : 
     939             :   return false;
     940             : }
     941             : 
     942        5202 : static const char *getEnvTempDir() {
     943             :   // Check whether the temporary directory is specified by an environment
     944             :   // variable.
     945        5202 :   const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
     946        5722 :   for (const char *Env : EnvironmentVariables) {
     947        5397 :     if (const char *Dir = std::getenv(Env))
     948             :       return Dir;
     949             :   }
     950             : 
     951             :   return nullptr;
     952             : }
     953             : 
     954             : static const char *getDefaultTempDir(bool ErasedOnReboot) {
     955             : #ifdef P_tmpdir
     956             :   if ((bool)P_tmpdir)
     957             :     return P_tmpdir;
     958             : #endif
     959             : 
     960             :   if (ErasedOnReboot)
     961             :     return "/tmp";
     962             :   return "/var/tmp";
     963             : }
     964             : 
     965        5219 : void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
     966             :   Result.clear();
     967             : 
     968        5219 :   if (ErasedOnReboot) {
     969             :     // There is no env variable for the cache directory.
     970        5202 :     if (const char *RequestedDir = getEnvTempDir()) {
     971        5137 :       Result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
     972        5137 :       return;
     973             :     }
     974             :   }
     975             : 
     976             :   if (getDarwinConfDir(ErasedOnReboot, Result))
     977             :     return;
     978             : 
     979             :   const char *RequestedDir = getDefaultTempDir(ErasedOnReboot);
     980          82 :   Result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
     981             : }
     982             : 
     983             : } // end namespace path
     984             : 
     985             : } // end namespace sys
     986             : } // end namespace llvm

Generated by: LCOV version 1.13