10b57cec5SDimitry Andric//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// 20b57cec5SDimitry Andric// 30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric// 70b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric// 90b57cec5SDimitry Andric// This file implements the Unix specific implementation of the Path API. 100b57cec5SDimitry Andric// 110b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric//=== WARNING: Implementation here must contain only generic UNIX code that 150b57cec5SDimitry Andric//=== is guaranteed to work on *all* UNIX variants. 160b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric#include "Unix.h" 190b57cec5SDimitry Andric#include <limits.h> 200b57cec5SDimitry Andric#include <stdio.h> 210b57cec5SDimitry Andric#if HAVE_SYS_STAT_H 220b57cec5SDimitry Andric#include <sys/stat.h> 230b57cec5SDimitry Andric#endif 240b57cec5SDimitry Andric#if HAVE_FCNTL_H 250b57cec5SDimitry Andric#include <fcntl.h> 260b57cec5SDimitry Andric#endif 270b57cec5SDimitry Andric#ifdef HAVE_UNISTD_H 280b57cec5SDimitry Andric#include <unistd.h> 290b57cec5SDimitry Andric#endif 300b57cec5SDimitry Andric#ifdef HAVE_SYS_MMAN_H 310b57cec5SDimitry Andric#include <sys/mman.h> 320b57cec5SDimitry Andric#endif 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric#include <dirent.h> 350b57cec5SDimitry Andric#include <pwd.h> 36e8d8bef9SDimitry Andric#include <sys/file.h> 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric#ifdef __APPLE__ 39bdd1243dSDimitry Andric#include <copyfile.h> 400b57cec5SDimitry Andric#include <mach-o/dyld.h> 410b57cec5SDimitry Andric#include <sys/attr.h> 42349cc55cSDimitry Andric#if __has_include(<sys/clonefile.h>) 43349cc55cSDimitry Andric#include <sys/clonefile.h> 44349cc55cSDimitry Andric#endif 450b57cec5SDimitry Andric#elif defined(__FreeBSD__) 460b57cec5SDimitry Andric#include <osreldate.h> 470b57cec5SDimitry Andric#if __FreeBSD_version >= 1300057 480b57cec5SDimitry Andric#include <sys/auxv.h> 490b57cec5SDimitry Andric#else 500b57cec5SDimitry Andric#include <machine/elf.h> 510b57cec5SDimitry Andricextern char **environ; 520b57cec5SDimitry Andric#endif 530b57cec5SDimitry Andric#elif defined(__DragonFly__) 540b57cec5SDimitry Andric#include <sys/mount.h> 555ffd83dbSDimitry Andric#elif defined(__MVS__) 56fe6060f1SDimitry Andric#include "llvm/Support/AutoConvert.h" 575ffd83dbSDimitry Andric#include <sys/ps.h> 580b57cec5SDimitry Andric#endif 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric// Both stdio.h and cstdio are included via different paths and 610b57cec5SDimitry Andric// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros 620b57cec5SDimitry Andric// either. 630b57cec5SDimitry Andric#undef ferror 640b57cec5SDimitry Andric#undef feof 650b57cec5SDimitry Andric 665ffd83dbSDimitry Andric#if !defined(PATH_MAX) 670b57cec5SDimitry Andric// For GNU Hurd 685ffd83dbSDimitry Andric#if defined(__GNU__) 690b57cec5SDimitry Andric#define PATH_MAX 4096 705ffd83dbSDimitry Andric#elif defined(__MVS__) 715ffd83dbSDimitry Andric#define PATH_MAX _XOPEN_PATH_MAX 725ffd83dbSDimitry Andric#endif 730b57cec5SDimitry Andric#endif 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric#include <sys/types.h> 760b57cec5SDimitry Andric#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \ 770b57cec5SDimitry Andric !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX) 780b57cec5SDimitry Andric#include <sys/statvfs.h> 790b57cec5SDimitry Andric#define STATVFS statvfs 800b57cec5SDimitry Andric#define FSTATVFS fstatvfs 810b57cec5SDimitry Andric#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize 820b57cec5SDimitry Andric#else 830b57cec5SDimitry Andric#if defined(__OpenBSD__) || defined(__FreeBSD__) 840b57cec5SDimitry Andric#include <sys/mount.h> 850b57cec5SDimitry Andric#include <sys/param.h> 860b57cec5SDimitry Andric#elif defined(__linux__) 870b57cec5SDimitry Andric#if defined(HAVE_LINUX_MAGIC_H) 880b57cec5SDimitry Andric#include <linux/magic.h> 890b57cec5SDimitry Andric#else 900b57cec5SDimitry Andric#if defined(HAVE_LINUX_NFS_FS_H) 910b57cec5SDimitry Andric#include <linux/nfs_fs.h> 920b57cec5SDimitry Andric#endif 930b57cec5SDimitry Andric#if defined(HAVE_LINUX_SMB_H) 940b57cec5SDimitry Andric#include <linux/smb.h> 950b57cec5SDimitry Andric#endif 960b57cec5SDimitry Andric#endif 970b57cec5SDimitry Andric#include <sys/vfs.h> 980b57cec5SDimitry Andric#elif defined(_AIX) 990b57cec5SDimitry Andric#include <sys/statfs.h> 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to 1020b57cec5SDimitry Andric// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide 1030b57cec5SDimitry Andric// the typedef prior to including <sys/vmount.h> to work around this issue. 1040b57cec5SDimitry Andrictypedef uint_t uint; 1050b57cec5SDimitry Andric#include <sys/vmount.h> 1060b57cec5SDimitry Andric#else 1070b57cec5SDimitry Andric#include <sys/mount.h> 1080b57cec5SDimitry Andric#endif 1090b57cec5SDimitry Andric#define STATVFS statfs 1100b57cec5SDimitry Andric#define FSTATVFS fstatfs 1110b57cec5SDimitry Andric#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize) 1120b57cec5SDimitry Andric#endif 1130b57cec5SDimitry Andric 1145ffd83dbSDimitry Andric#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__) || \ 1155ffd83dbSDimitry Andric defined(__MVS__) 1160b57cec5SDimitry Andric#define STATVFS_F_FLAG(vfs) (vfs).f_flag 1170b57cec5SDimitry Andric#else 1180b57cec5SDimitry Andric#define STATVFS_F_FLAG(vfs) (vfs).f_flags 1190b57cec5SDimitry Andric#endif 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andricusing namespace llvm; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andricnamespace llvm { 1240b57cec5SDimitry Andricnamespace sys { 1250b57cec5SDimitry Andricnamespace fs { 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andricconst file_t kInvalidFile = -1; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ 1305f757f3fSDimitry Andric defined(__FreeBSD_kernel__) || defined(__linux__) || defined(__CYGWIN__) || \ 1315f757f3fSDimitry Andric defined(__DragonFly__) || defined(_AIX) || defined(__GNU__) || \ 1325f757f3fSDimitry Andric (defined(__sun__) && defined(__svr4__) || defined(__HAIKU__)) 133bdd1243dSDimitry Andricstatic int test_dir(char ret[PATH_MAX], const char *dir, const char *bin) { 1340b57cec5SDimitry Andric struct stat sb; 1350b57cec5SDimitry Andric char fullpath[PATH_MAX]; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric int chars = snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin); 1380b57cec5SDimitry Andric // We cannot write PATH_MAX characters because the string will be terminated 1390b57cec5SDimitry Andric // with a null character. Fail if truncation happened. 1400b57cec5SDimitry Andric if (chars >= PATH_MAX) 1410b57cec5SDimitry Andric return 1; 1420b57cec5SDimitry Andric if (!realpath(fullpath, ret)) 1430b57cec5SDimitry Andric return 1; 1440b57cec5SDimitry Andric if (stat(fullpath, &sb) != 0) 1450b57cec5SDimitry Andric return 1; 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric return 0; 1480b57cec5SDimitry Andric} 1490b57cec5SDimitry Andric 150bdd1243dSDimitry Andricstatic char *getprogpath(char ret[PATH_MAX], const char *bin) { 151e8d8bef9SDimitry Andric if (bin == nullptr) 152e8d8bef9SDimitry Andric return nullptr; 153e8d8bef9SDimitry Andric 1540b57cec5SDimitry Andric /* First approach: absolute path. */ 1550b57cec5SDimitry Andric if (bin[0] == '/') { 1560b57cec5SDimitry Andric if (test_dir(ret, "/", bin) == 0) 1570b57cec5SDimitry Andric return ret; 1580b57cec5SDimitry Andric return nullptr; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric /* Second approach: relative path. */ 1620b57cec5SDimitry Andric if (strchr(bin, '/')) { 1630b57cec5SDimitry Andric char cwd[PATH_MAX]; 1640b57cec5SDimitry Andric if (!getcwd(cwd, PATH_MAX)) 1650b57cec5SDimitry Andric return nullptr; 1660b57cec5SDimitry Andric if (test_dir(ret, cwd, bin) == 0) 1670b57cec5SDimitry Andric return ret; 1680b57cec5SDimitry Andric return nullptr; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /* Third approach: $PATH */ 1720b57cec5SDimitry Andric char *pv; 1730b57cec5SDimitry Andric if ((pv = getenv("PATH")) == nullptr) 1740b57cec5SDimitry Andric return nullptr; 1750b57cec5SDimitry Andric char *s = strdup(pv); 1760b57cec5SDimitry Andric if (!s) 1770b57cec5SDimitry Andric return nullptr; 1780b57cec5SDimitry Andric char *state; 1790b57cec5SDimitry Andric for (char *t = strtok_r(s, ":", &state); t != nullptr; 1800b57cec5SDimitry Andric t = strtok_r(nullptr, ":", &state)) { 1810b57cec5SDimitry Andric if (test_dir(ret, t, bin) == 0) { 1820b57cec5SDimitry Andric free(s); 1830b57cec5SDimitry Andric return ret; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric free(s); 1870b57cec5SDimitry Andric return nullptr; 1880b57cec5SDimitry Andric} 1890b57cec5SDimitry Andric#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric/// GetMainExecutable - Return the path to the main executable, given the 1920b57cec5SDimitry Andric/// value of argv[0] from program startup. 19306c3fb27SDimitry Andricstd::string getMainExecutable(const char *argv0, void *MainAddr) { 1940b57cec5SDimitry Andric#if defined(__APPLE__) 1950b57cec5SDimitry Andric // On OS X the executable path is saved to the stack by dyld. Reading it 1960b57cec5SDimitry Andric // from there is much faster than calling dladdr, especially for large 1970b57cec5SDimitry Andric // binaries with symbols. 1985ffd83dbSDimitry Andric char exe_path[PATH_MAX]; 1990b57cec5SDimitry Andric uint32_t size = sizeof(exe_path); 2000b57cec5SDimitry Andric if (_NSGetExecutablePath(exe_path, &size) == 0) { 2015ffd83dbSDimitry Andric char link_path[PATH_MAX]; 2020b57cec5SDimitry Andric if (realpath(exe_path, link_path)) 2030b57cec5SDimitry Andric return link_path; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric#elif defined(__FreeBSD__) 2060b57cec5SDimitry Andric // On FreeBSD if the exec path specified in ELF auxiliary vectors is 2070b57cec5SDimitry Andric // preferred, if available. /proc/curproc/file and the KERN_PROC_PATHNAME 2080b57cec5SDimitry Andric // sysctl may not return the desired path if there are multiple hardlinks 2090b57cec5SDimitry Andric // to the file. 2100b57cec5SDimitry Andric char exe_path[PATH_MAX]; 2110b57cec5SDimitry Andric#if __FreeBSD_version >= 1300057 212fe6060f1SDimitry Andric if (elf_aux_info(AT_EXECPATH, exe_path, sizeof(exe_path)) == 0) { 213fe6060f1SDimitry Andric char link_path[PATH_MAX]; 214fe6060f1SDimitry Andric if (realpath(exe_path, link_path)) 215fe6060f1SDimitry Andric return link_path; 216fe6060f1SDimitry Andric } 2170b57cec5SDimitry Andric#else 218480093f4SDimitry Andric // elf_aux_info(AT_EXECPATH, ... is not available in all supported versions, 219480093f4SDimitry Andric // fall back to finding the ELF auxiliary vectors after the process's 2200b57cec5SDimitry Andric // environment. 2210b57cec5SDimitry Andric char **p = ::environ; 2220b57cec5SDimitry Andric while (*p++ != 0) 2230b57cec5SDimitry Andric ; 2240b57cec5SDimitry Andric // Iterate through auxiliary vectors for AT_EXECPATH. 225fe6060f1SDimitry Andric for (Elf_Auxinfo *aux = (Elf_Auxinfo *)p; aux->a_type != AT_NULL; aux++) { 226fe6060f1SDimitry Andric if (aux->a_type == AT_EXECPATH) { 227fe6060f1SDimitry Andric char link_path[PATH_MAX]; 228fe6060f1SDimitry Andric if (realpath((char *)aux->a_un.a_ptr, link_path)) 229fe6060f1SDimitry Andric return link_path; 230fe6060f1SDimitry Andric } 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric#endif 2330b57cec5SDimitry Andric // Fall back to argv[0] if auxiliary vectors are not available. 2340b57cec5SDimitry Andric if (getprogpath(exe_path, argv0) != NULL) 2350b57cec5SDimitry Andric return exe_path; 2365f757f3fSDimitry Andric#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || \ 2375f757f3fSDimitry Andric defined(__NetBSD__) 2388bcb0991SDimitry Andric const char *curproc = "/proc/curproc/file"; 2390b57cec5SDimitry Andric char exe_path[PATH_MAX]; 2400b57cec5SDimitry Andric if (sys::fs::exists(curproc)) { 2418bcb0991SDimitry Andric ssize_t len = readlink(curproc, exe_path, sizeof(exe_path)); 2420b57cec5SDimitry Andric if (len > 0) { 2430b57cec5SDimitry Andric // Null terminate the string for realpath. readlink never null 2440b57cec5SDimitry Andric // terminates its output. 2450b57cec5SDimitry Andric len = std::min(len, ssize_t(sizeof(exe_path) - 1)); 2460b57cec5SDimitry Andric exe_path[len] = '\0'; 2470b57cec5SDimitry Andric return exe_path; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric // If we don't have procfs mounted, fall back to argv[0] 2510b57cec5SDimitry Andric if (getprogpath(exe_path, argv0) != NULL) 2520b57cec5SDimitry Andric return exe_path; 253480093f4SDimitry Andric#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__) 2545ffd83dbSDimitry Andric char exe_path[PATH_MAX]; 2558bcb0991SDimitry Andric const char *aPath = "/proc/self/exe"; 2560b57cec5SDimitry Andric if (sys::fs::exists(aPath)) { 2570b57cec5SDimitry Andric // /proc is not always mounted under Linux (chroot for example). 2588bcb0991SDimitry Andric ssize_t len = readlink(aPath, exe_path, sizeof(exe_path)); 2590b57cec5SDimitry Andric if (len < 0) 2600b57cec5SDimitry Andric return ""; 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // Null terminate the string for realpath. readlink never null 2630b57cec5SDimitry Andric // terminates its output. 2640b57cec5SDimitry Andric len = std::min(len, ssize_t(sizeof(exe_path) - 1)); 2650b57cec5SDimitry Andric exe_path[len] = '\0'; 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric // On Linux, /proc/self/exe always looks through symlinks. However, on 2680b57cec5SDimitry Andric // GNU/Hurd, /proc/self/exe is a symlink to the path that was used to start 2690b57cec5SDimitry Andric // the program, and not the eventual binary file. Therefore, call realpath 2700b57cec5SDimitry Andric // so this behaves the same on all platforms. 2710b57cec5SDimitry Andric#if _POSIX_VERSION >= 200112 || defined(__GLIBC__) 27204eeddc0SDimitry Andric if (char *real_path = realpath(exe_path, nullptr)) { 2730b57cec5SDimitry Andric std::string ret = std::string(real_path); 2740b57cec5SDimitry Andric free(real_path); 2750b57cec5SDimitry Andric return ret; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric#else 2785ffd83dbSDimitry Andric char real_path[PATH_MAX]; 2790b57cec5SDimitry Andric if (realpath(exe_path, real_path)) 2800b57cec5SDimitry Andric return std::string(real_path); 2810b57cec5SDimitry Andric#endif 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric // Fall back to the classical detection. 2840b57cec5SDimitry Andric if (getprogpath(exe_path, argv0)) 2850b57cec5SDimitry Andric return exe_path; 2865f757f3fSDimitry Andric#elif defined(__OpenBSD__) || defined(__HAIKU__) 2875f757f3fSDimitry Andric char exe_path[PATH_MAX]; 2885f757f3fSDimitry Andric // argv[0] only 2895f757f3fSDimitry Andric if (getprogpath(exe_path, argv0) != NULL) 2905f757f3fSDimitry Andric return exe_path; 291349cc55cSDimitry Andric#elif defined(__sun__) && defined(__svr4__) 292349cc55cSDimitry Andric char exe_path[PATH_MAX]; 293349cc55cSDimitry Andric const char *aPath = "/proc/self/execname"; 294349cc55cSDimitry Andric if (sys::fs::exists(aPath)) { 295349cc55cSDimitry Andric int fd = open(aPath, O_RDONLY); 296349cc55cSDimitry Andric if (fd == -1) 297349cc55cSDimitry Andric return ""; 298349cc55cSDimitry Andric if (read(fd, exe_path, sizeof(exe_path)) < 0) 299349cc55cSDimitry Andric return ""; 300349cc55cSDimitry Andric return exe_path; 301349cc55cSDimitry Andric } 302349cc55cSDimitry Andric // Fall back to the classical detection. 303349cc55cSDimitry Andric if (getprogpath(exe_path, argv0) != NULL) 304349cc55cSDimitry Andric return exe_path; 3055ffd83dbSDimitry Andric#elif defined(__MVS__) 3065ffd83dbSDimitry Andric int token = 0; 3075ffd83dbSDimitry Andric W_PSPROC buf; 3085ffd83dbSDimitry Andric char exe_path[PS_PATHBLEN]; 3095ffd83dbSDimitry Andric pid_t pid = getpid(); 3105ffd83dbSDimitry Andric 3115ffd83dbSDimitry Andric memset(&buf, 0, sizeof(buf)); 3125ffd83dbSDimitry Andric buf.ps_pathptr = exe_path; 3135ffd83dbSDimitry Andric buf.ps_pathlen = sizeof(exe_path); 3145ffd83dbSDimitry Andric 3155ffd83dbSDimitry Andric while (true) { 3165ffd83dbSDimitry Andric if ((token = w_getpsent(token, &buf, sizeof(buf))) <= 0) 3175ffd83dbSDimitry Andric break; 3185ffd83dbSDimitry Andric if (buf.ps_pid != pid) 3195ffd83dbSDimitry Andric continue; 3205ffd83dbSDimitry Andric char real_path[PATH_MAX]; 3215ffd83dbSDimitry Andric if (realpath(exe_path, real_path)) 3225ffd83dbSDimitry Andric return std::string(real_path); 3235ffd83dbSDimitry Andric break; // Found entry, but realpath failed. 3245ffd83dbSDimitry Andric } 3250b57cec5SDimitry Andric#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR) 3260b57cec5SDimitry Andric // Use dladdr to get executable path if available. 3270b57cec5SDimitry Andric Dl_info DLInfo; 3280b57cec5SDimitry Andric int err = dladdr(MainAddr, &DLInfo); 3290b57cec5SDimitry Andric if (err == 0) 3300b57cec5SDimitry Andric return ""; 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric // If the filename is a symlink, we need to resolve and return the location of 3330b57cec5SDimitry Andric // the actual executable. 3345ffd83dbSDimitry Andric char link_path[PATH_MAX]; 3350b57cec5SDimitry Andric if (realpath(DLInfo.dli_fname, link_path)) 3360b57cec5SDimitry Andric return link_path; 3370b57cec5SDimitry Andric#else 3380b57cec5SDimitry Andric#error GetMainExecutable is not implemented on this host yet. 3390b57cec5SDimitry Andric#endif 3400b57cec5SDimitry Andric return ""; 3410b57cec5SDimitry Andric} 3420b57cec5SDimitry Andric 3430b57cec5SDimitry AndricTimePoint<> basic_file_status::getLastAccessedTime() const { 3440b57cec5SDimitry Andric return toTimePoint(fs_st_atime, fs_st_atime_nsec); 3450b57cec5SDimitry Andric} 3460b57cec5SDimitry Andric 3470b57cec5SDimitry AndricTimePoint<> basic_file_status::getLastModificationTime() const { 3480b57cec5SDimitry Andric return toTimePoint(fs_st_mtime, fs_st_mtime_nsec); 3490b57cec5SDimitry Andric} 3500b57cec5SDimitry Andric 3510b57cec5SDimitry AndricUniqueID file_status::getUniqueID() const { 3520b57cec5SDimitry Andric return UniqueID(fs_st_dev, fs_st_ino); 3530b57cec5SDimitry Andric} 3540b57cec5SDimitry Andric 355bdd1243dSDimitry Andricuint32_t file_status::getLinkCount() const { return fs_st_nlinks; } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry AndricErrorOr<space_info> disk_space(const Twine &Path) { 3580b57cec5SDimitry Andric struct STATVFS Vfs; 3590b57cec5SDimitry Andric if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs)) 3600b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 3610b57cec5SDimitry Andric auto FrSize = STATVFS_F_FRSIZE(Vfs); 3620b57cec5SDimitry Andric space_info SpaceInfo; 3630b57cec5SDimitry Andric SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize; 3640b57cec5SDimitry Andric SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize; 3650b57cec5SDimitry Andric SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize; 3660b57cec5SDimitry Andric return SpaceInfo; 3670b57cec5SDimitry Andric} 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andricstd::error_code current_path(SmallVectorImpl<char> &result) { 3700b57cec5SDimitry Andric result.clear(); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric const char *pwd = ::getenv("PWD"); 3730b57cec5SDimitry Andric llvm::sys::fs::file_status PWDStatus, DotStatus; 3740b57cec5SDimitry Andric if (pwd && llvm::sys::path::is_absolute(pwd) && 3750b57cec5SDimitry Andric !llvm::sys::fs::status(pwd, PWDStatus) && 3760b57cec5SDimitry Andric !llvm::sys::fs::status(".", DotStatus) && 3770b57cec5SDimitry Andric PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { 3780b57cec5SDimitry Andric result.append(pwd, pwd + strlen(pwd)); 3790b57cec5SDimitry Andric return std::error_code(); 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 38204eeddc0SDimitry Andric result.resize_for_overwrite(PATH_MAX); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric while (true) { 38504eeddc0SDimitry Andric if (::getcwd(result.data(), result.size()) == nullptr) { 3860b57cec5SDimitry Andric // See if there was a real error. 38704eeddc0SDimitry Andric if (errno != ENOMEM) { 38804eeddc0SDimitry Andric result.clear(); 3890b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 39004eeddc0SDimitry Andric } 3910b57cec5SDimitry Andric // Otherwise there just wasn't enough space. 39204eeddc0SDimitry Andric result.resize_for_overwrite(result.capacity() * 2); 3930b57cec5SDimitry Andric } else 3940b57cec5SDimitry Andric break; 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 39704eeddc0SDimitry Andric result.truncate(strlen(result.data())); 3980b57cec5SDimitry Andric return std::error_code(); 3990b57cec5SDimitry Andric} 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andricstd::error_code set_current_path(const Twine &path) { 4020b57cec5SDimitry Andric SmallString<128> path_storage; 4030b57cec5SDimitry Andric StringRef p = path.toNullTerminatedStringRef(path_storage); 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric if (::chdir(p.begin()) == -1) 4060b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric return std::error_code(); 4090b57cec5SDimitry Andric} 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andricstd::error_code create_directory(const Twine &path, bool IgnoreExisting, 4120b57cec5SDimitry Andric perms Perms) { 4130b57cec5SDimitry Andric SmallString<128> path_storage; 4140b57cec5SDimitry Andric StringRef p = path.toNullTerminatedStringRef(path_storage); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric if (::mkdir(p.begin(), Perms) == -1) { 4170b57cec5SDimitry Andric if (errno != EEXIST || !IgnoreExisting) 4180b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric return std::error_code(); 4220b57cec5SDimitry Andric} 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric// Note that we are using symbolic link because hard links are not supported by 4250b57cec5SDimitry Andric// all filesystems (SMB doesn't). 4260b57cec5SDimitry Andricstd::error_code create_link(const Twine &to, const Twine &from) { 4270b57cec5SDimitry Andric // Get arguments. 4280b57cec5SDimitry Andric SmallString<128> from_storage; 4290b57cec5SDimitry Andric SmallString<128> to_storage; 4300b57cec5SDimitry Andric StringRef f = from.toNullTerminatedStringRef(from_storage); 4310b57cec5SDimitry Andric StringRef t = to.toNullTerminatedStringRef(to_storage); 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric if (::symlink(t.begin(), f.begin()) == -1) 4340b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric return std::error_code(); 4370b57cec5SDimitry Andric} 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andricstd::error_code create_hard_link(const Twine &to, const Twine &from) { 4400b57cec5SDimitry Andric // Get arguments. 4410b57cec5SDimitry Andric SmallString<128> from_storage; 4420b57cec5SDimitry Andric SmallString<128> to_storage; 4430b57cec5SDimitry Andric StringRef f = from.toNullTerminatedStringRef(from_storage); 4440b57cec5SDimitry Andric StringRef t = to.toNullTerminatedStringRef(to_storage); 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric if (::link(t.begin(), f.begin()) == -1) 4470b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric return std::error_code(); 4500b57cec5SDimitry Andric} 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andricstd::error_code remove(const Twine &path, bool IgnoreNonExisting) { 4530b57cec5SDimitry Andric SmallString<128> path_storage; 4540b57cec5SDimitry Andric StringRef p = path.toNullTerminatedStringRef(path_storage); 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric struct stat buf; 4570b57cec5SDimitry Andric if (lstat(p.begin(), &buf) != 0) { 4580b57cec5SDimitry Andric if (errno != ENOENT || !IgnoreNonExisting) 4590b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 4600b57cec5SDimitry Andric return std::error_code(); 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric // Note: this check catches strange situations. In all cases, LLVM should 4640b57cec5SDimitry Andric // only be involved in the creation and deletion of regular files. This 4650b57cec5SDimitry Andric // check ensures that what we're trying to erase is a regular file. It 4660b57cec5SDimitry Andric // effectively prevents LLVM from erasing things like /dev/null, any block 4670b57cec5SDimitry Andric // special file, or other things that aren't "regular" files. 4680b57cec5SDimitry Andric if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode)) 4690b57cec5SDimitry Andric return make_error_code(errc::operation_not_permitted); 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric if (::remove(p.begin()) == -1) { 4720b57cec5SDimitry Andric if (errno != ENOENT || !IgnoreNonExisting) 4730b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 4740b57cec5SDimitry Andric } 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric return std::error_code(); 4770b57cec5SDimitry Andric} 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andricstatic bool is_local_impl(struct STATVFS &Vfs) { 4800b57cec5SDimitry Andric#if defined(__linux__) || defined(__GNU__) 4810b57cec5SDimitry Andric#ifndef NFS_SUPER_MAGIC 4820b57cec5SDimitry Andric#define NFS_SUPER_MAGIC 0x6969 4830b57cec5SDimitry Andric#endif 4840b57cec5SDimitry Andric#ifndef SMB_SUPER_MAGIC 4850b57cec5SDimitry Andric#define SMB_SUPER_MAGIC 0x517B 4860b57cec5SDimitry Andric#endif 4870b57cec5SDimitry Andric#ifndef CIFS_MAGIC_NUMBER 4880b57cec5SDimitry Andric#define CIFS_MAGIC_NUMBER 0xFF534D42 4890b57cec5SDimitry Andric#endif 4900b57cec5SDimitry Andric#ifdef __GNU__ 4910b57cec5SDimitry Andric switch ((uint32_t)Vfs.__f_type) { 4920b57cec5SDimitry Andric#else 4930b57cec5SDimitry Andric switch ((uint32_t)Vfs.f_type) { 4940b57cec5SDimitry Andric#endif 4950b57cec5SDimitry Andric case NFS_SUPER_MAGIC: 4960b57cec5SDimitry Andric case SMB_SUPER_MAGIC: 4970b57cec5SDimitry Andric case CIFS_MAGIC_NUMBER: 4980b57cec5SDimitry Andric return false; 4990b57cec5SDimitry Andric default: 5000b57cec5SDimitry Andric return true; 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric#elif defined(__CYGWIN__) 5030b57cec5SDimitry Andric // Cygwin doesn't expose this information; would need to use Win32 API. 5040b57cec5SDimitry Andric return false; 5050b57cec5SDimitry Andric#elif defined(__Fuchsia__) 5060b57cec5SDimitry Andric // Fuchsia doesn't yet support remote filesystem mounts. 5070b57cec5SDimitry Andric return true; 5080b57cec5SDimitry Andric#elif defined(__EMSCRIPTEN__) 5090b57cec5SDimitry Andric // Emscripten doesn't currently support remote filesystem mounts. 5100b57cec5SDimitry Andric return true; 5110b57cec5SDimitry Andric#elif defined(__HAIKU__) 5120b57cec5SDimitry Andric // Haiku doesn't expose this information. 5130b57cec5SDimitry Andric return false; 5140b57cec5SDimitry Andric#elif defined(__sun) 515bdd1243dSDimitry Andric // statvfs::f_basetype contains a null-terminated FSType name of the mounted 516bdd1243dSDimitry Andric // target 5170b57cec5SDimitry Andric StringRef fstype(Vfs.f_basetype); 5180b57cec5SDimitry Andric // NFS is the only non-local fstype?? 5190b57cec5SDimitry Andric return !fstype.equals("nfs"); 5200b57cec5SDimitry Andric#elif defined(_AIX) 5210b57cec5SDimitry Andric // Call mntctl; try more than twice in case of timing issues with a concurrent 5220b57cec5SDimitry Andric // mount. 5230b57cec5SDimitry Andric int Ret; 5240b57cec5SDimitry Andric size_t BufSize = 2048u; 5250b57cec5SDimitry Andric std::unique_ptr<char[]> Buf; 5260b57cec5SDimitry Andric int Tries = 3; 5270b57cec5SDimitry Andric while (Tries--) { 5288bcb0991SDimitry Andric Buf = std::make_unique<char[]>(BufSize); 5290b57cec5SDimitry Andric Ret = mntctl(MCTL_QUERY, BufSize, Buf.get()); 5300b57cec5SDimitry Andric if (Ret != 0) 5310b57cec5SDimitry Andric break; 5320b57cec5SDimitry Andric BufSize = *reinterpret_cast<unsigned int *>(Buf.get()); 5330b57cec5SDimitry Andric Buf.reset(); 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric if (Ret == -1) 5370b57cec5SDimitry Andric // There was an error; "remote" is the conservative answer. 5380b57cec5SDimitry Andric return false; 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric // Look for the correct vmount entry. 5410b57cec5SDimitry Andric char *CurObjPtr = Buf.get(); 5420b57cec5SDimitry Andric while (Ret--) { 5430b57cec5SDimitry Andric struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr); 5440b57cec5SDimitry Andric static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid), 5450b57cec5SDimitry Andric "fsid length mismatch"); 5460b57cec5SDimitry Andric if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0) 5470b57cec5SDimitry Andric return (Vp->vmt_flags & MNT_REMOTE) == 0; 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric CurObjPtr += Vp->vmt_length; 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric // vmount entry not found; "remote" is the conservative answer. 5530b57cec5SDimitry Andric return false; 5545ffd83dbSDimitry Andric#elif defined(__MVS__) 5555ffd83dbSDimitry Andric // The file system can have an arbitrary structure on z/OS; must go with the 5565ffd83dbSDimitry Andric // conservative answer. 5575ffd83dbSDimitry Andric return false; 5580b57cec5SDimitry Andric#else 5590b57cec5SDimitry Andric return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL); 5600b57cec5SDimitry Andric#endif 5610b57cec5SDimitry Andric} 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andricstd::error_code is_local(const Twine &Path, bool &Result) { 5640b57cec5SDimitry Andric struct STATVFS Vfs; 5650b57cec5SDimitry Andric if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs)) 5660b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric Result = is_local_impl(Vfs); 5690b57cec5SDimitry Andric return std::error_code(); 5700b57cec5SDimitry Andric} 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andricstd::error_code is_local(int FD, bool &Result) { 5730b57cec5SDimitry Andric struct STATVFS Vfs; 5740b57cec5SDimitry Andric if (::FSTATVFS(FD, &Vfs)) 5750b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric Result = is_local_impl(Vfs); 5780b57cec5SDimitry Andric return std::error_code(); 5790b57cec5SDimitry Andric} 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andricstd::error_code rename(const Twine &from, const Twine &to) { 5820b57cec5SDimitry Andric // Get arguments. 5830b57cec5SDimitry Andric SmallString<128> from_storage; 5840b57cec5SDimitry Andric SmallString<128> to_storage; 5850b57cec5SDimitry Andric StringRef f = from.toNullTerminatedStringRef(from_storage); 5860b57cec5SDimitry Andric StringRef t = to.toNullTerminatedStringRef(to_storage); 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric if (::rename(f.begin(), t.begin()) == -1) 5890b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric return std::error_code(); 5920b57cec5SDimitry Andric} 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andricstd::error_code resize_file(int FD, uint64_t Size) { 5950b57cec5SDimitry Andric // Use ftruncate as a fallback. It may or may not allocate space. At least on 5960b57cec5SDimitry Andric // OS X with HFS+ it does. 5970b57cec5SDimitry Andric if (::ftruncate(FD, Size) == -1) 5980b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric return std::error_code(); 6010b57cec5SDimitry Andric} 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andricstatic int convertAccessMode(AccessMode Mode) { 6040b57cec5SDimitry Andric switch (Mode) { 6050b57cec5SDimitry Andric case AccessMode::Exist: 6060b57cec5SDimitry Andric return F_OK; 6070b57cec5SDimitry Andric case AccessMode::Write: 6080b57cec5SDimitry Andric return W_OK; 6090b57cec5SDimitry Andric case AccessMode::Execute: 6100b57cec5SDimitry Andric return R_OK | X_OK; // scripts also need R_OK. 6110b57cec5SDimitry Andric } 6120b57cec5SDimitry Andric llvm_unreachable("invalid enum"); 6130b57cec5SDimitry Andric} 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andricstd::error_code access(const Twine &Path, AccessMode Mode) { 6160b57cec5SDimitry Andric SmallString<128> PathStorage; 6170b57cec5SDimitry Andric StringRef P = Path.toNullTerminatedStringRef(PathStorage); 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric if (::access(P.begin(), convertAccessMode(Mode)) == -1) 6200b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric if (Mode == AccessMode::Execute) { 6230b57cec5SDimitry Andric // Don't say that directories are executable. 6240b57cec5SDimitry Andric struct stat buf; 6250b57cec5SDimitry Andric if (0 != stat(P.begin(), &buf)) 6260b57cec5SDimitry Andric return errc::permission_denied; 6270b57cec5SDimitry Andric if (!S_ISREG(buf.st_mode)) 6280b57cec5SDimitry Andric return errc::permission_denied; 6290b57cec5SDimitry Andric } 6300b57cec5SDimitry Andric 6310b57cec5SDimitry Andric return std::error_code(); 6320b57cec5SDimitry Andric} 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andricbool can_execute(const Twine &Path) { 6350b57cec5SDimitry Andric return !access(Path, AccessMode::Execute); 6360b57cec5SDimitry Andric} 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andricbool equivalent(file_status A, file_status B) { 6390b57cec5SDimitry Andric assert(status_known(A) && status_known(B)); 640bdd1243dSDimitry Andric return A.fs_st_dev == B.fs_st_dev && A.fs_st_ino == B.fs_st_ino; 6410b57cec5SDimitry Andric} 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andricstd::error_code equivalent(const Twine &A, const Twine &B, bool &result) { 6440b57cec5SDimitry Andric file_status fsA, fsB; 6450b57cec5SDimitry Andric if (std::error_code ec = status(A, fsA)) 6460b57cec5SDimitry Andric return ec; 6470b57cec5SDimitry Andric if (std::error_code ec = status(B, fsB)) 6480b57cec5SDimitry Andric return ec; 6490b57cec5SDimitry Andric result = equivalent(fsA, fsB); 6500b57cec5SDimitry Andric return std::error_code(); 6510b57cec5SDimitry Andric} 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andricstatic void expandTildeExpr(SmallVectorImpl<char> &Path) { 6540b57cec5SDimitry Andric StringRef PathStr(Path.begin(), Path.size()); 6555f757f3fSDimitry Andric if (PathStr.empty() || !PathStr.starts_with("~")) 6560b57cec5SDimitry Andric return; 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric PathStr = PathStr.drop_front(); 6590b57cec5SDimitry Andric StringRef Expr = 6600b57cec5SDimitry Andric PathStr.take_until([](char c) { return path::is_separator(c); }); 6610b57cec5SDimitry Andric StringRef Remainder = PathStr.substr(Expr.size() + 1); 6620b57cec5SDimitry Andric SmallString<128> Storage; 6630b57cec5SDimitry Andric if (Expr.empty()) { 6640b57cec5SDimitry Andric // This is just ~/..., resolve it to the current user's home dir. 6650b57cec5SDimitry Andric if (!path::home_directory(Storage)) { 6660b57cec5SDimitry Andric // For some reason we couldn't get the home directory. Just exit. 6670b57cec5SDimitry Andric return; 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric // Overwrite the first character and insert the rest. 6710b57cec5SDimitry Andric Path[0] = Storage[0]; 6720b57cec5SDimitry Andric Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end()); 6730b57cec5SDimitry Andric return; 6740b57cec5SDimitry Andric } 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric // This is a string of the form ~username/, look up this user's entry in the 6770b57cec5SDimitry Andric // password database. 678bdd1243dSDimitry Andric std::unique_ptr<char[]> Buf; 679bdd1243dSDimitry Andric long BufSize = sysconf(_SC_GETPW_R_SIZE_MAX); 680bdd1243dSDimitry Andric if (BufSize <= 0) 681bdd1243dSDimitry Andric BufSize = 16384; 682bdd1243dSDimitry Andric Buf = std::make_unique<char[]>(BufSize); 683bdd1243dSDimitry Andric struct passwd Pwd; 6840b57cec5SDimitry Andric std::string User = Expr.str(); 685bdd1243dSDimitry Andric struct passwd *Entry = nullptr; 686bdd1243dSDimitry Andric getpwnam_r(User.c_str(), &Pwd, Buf.get(), BufSize, &Entry); 6870b57cec5SDimitry Andric 688bdd1243dSDimitry Andric if (!Entry || !Entry->pw_dir) { 6890b57cec5SDimitry Andric // Unable to look up the entry, just return back the original path. 6900b57cec5SDimitry Andric return; 6910b57cec5SDimitry Andric } 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric Storage = Remainder; 6940b57cec5SDimitry Andric Path.clear(); 6950b57cec5SDimitry Andric Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir)); 6960b57cec5SDimitry Andric llvm::sys::path::append(Path, Storage); 6970b57cec5SDimitry Andric} 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andricvoid expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { 7000b57cec5SDimitry Andric dest.clear(); 7010b57cec5SDimitry Andric if (path.isTriviallyEmpty()) 7020b57cec5SDimitry Andric return; 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric path.toVector(dest); 7050b57cec5SDimitry Andric expandTildeExpr(dest); 7060b57cec5SDimitry Andric} 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andricstatic file_type typeForMode(mode_t Mode) { 7090b57cec5SDimitry Andric if (S_ISDIR(Mode)) 7100b57cec5SDimitry Andric return file_type::directory_file; 7110b57cec5SDimitry Andric else if (S_ISREG(Mode)) 7120b57cec5SDimitry Andric return file_type::regular_file; 7130b57cec5SDimitry Andric else if (S_ISBLK(Mode)) 7140b57cec5SDimitry Andric return file_type::block_file; 7150b57cec5SDimitry Andric else if (S_ISCHR(Mode)) 7160b57cec5SDimitry Andric return file_type::character_file; 7170b57cec5SDimitry Andric else if (S_ISFIFO(Mode)) 7180b57cec5SDimitry Andric return file_type::fifo_file; 7190b57cec5SDimitry Andric else if (S_ISSOCK(Mode)) 7200b57cec5SDimitry Andric return file_type::socket_file; 7210b57cec5SDimitry Andric else if (S_ISLNK(Mode)) 7220b57cec5SDimitry Andric return file_type::symlink_file; 7230b57cec5SDimitry Andric return file_type::type_unknown; 7240b57cec5SDimitry Andric} 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andricstatic std::error_code fillStatus(int StatRet, const struct stat &Status, 7270b57cec5SDimitry Andric file_status &Result) { 7280b57cec5SDimitry Andric if (StatRet != 0) { 7290b57cec5SDimitry Andric std::error_code EC(errno, std::generic_category()); 7300b57cec5SDimitry Andric if (EC == errc::no_such_file_or_directory) 7310b57cec5SDimitry Andric Result = file_status(file_type::file_not_found); 7320b57cec5SDimitry Andric else 7330b57cec5SDimitry Andric Result = file_status(file_type::status_error); 7340b57cec5SDimitry Andric return EC; 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric uint32_t atime_nsec, mtime_nsec; 7380b57cec5SDimitry Andric#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) 7390b57cec5SDimitry Andric atime_nsec = Status.st_atimespec.tv_nsec; 7400b57cec5SDimitry Andric mtime_nsec = Status.st_mtimespec.tv_nsec; 7410b57cec5SDimitry Andric#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) 7420b57cec5SDimitry Andric atime_nsec = Status.st_atim.tv_nsec; 7430b57cec5SDimitry Andric mtime_nsec = Status.st_mtim.tv_nsec; 7440b57cec5SDimitry Andric#else 7450b57cec5SDimitry Andric atime_nsec = mtime_nsec = 0; 7460b57cec5SDimitry Andric#endif 7470b57cec5SDimitry Andric 7480b57cec5SDimitry Andric perms Perms = static_cast<perms>(Status.st_mode) & all_perms; 7490b57cec5SDimitry Andric Result = file_status(typeForMode(Status.st_mode), Perms, Status.st_dev, 750bdd1243dSDimitry Andric Status.st_nlink, Status.st_ino, Status.st_atime, 751bdd1243dSDimitry Andric atime_nsec, Status.st_mtime, mtime_nsec, Status.st_uid, 752bdd1243dSDimitry Andric Status.st_gid, Status.st_size); 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric return std::error_code(); 7550b57cec5SDimitry Andric} 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andricstd::error_code status(const Twine &Path, file_status &Result, bool Follow) { 7580b57cec5SDimitry Andric SmallString<128> PathStorage; 7590b57cec5SDimitry Andric StringRef P = Path.toNullTerminatedStringRef(PathStorage); 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric struct stat Status; 7620b57cec5SDimitry Andric int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status); 7630b57cec5SDimitry Andric return fillStatus(StatRet, Status, Result); 7640b57cec5SDimitry Andric} 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andricstd::error_code status(int FD, file_status &Result) { 7670b57cec5SDimitry Andric struct stat Status; 7680b57cec5SDimitry Andric int StatRet = ::fstat(FD, &Status); 7690b57cec5SDimitry Andric return fillStatus(StatRet, Status, Result); 7700b57cec5SDimitry Andric} 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andricunsigned getUmask() { 7730b57cec5SDimitry Andric // Chose arbitary new mask and reset the umask to the old mask. 7740b57cec5SDimitry Andric // umask(2) never fails so ignore the return of the second call. 7750b57cec5SDimitry Andric unsigned Mask = ::umask(0); 7760b57cec5SDimitry Andric (void)::umask(Mask); 7770b57cec5SDimitry Andric return Mask; 7780b57cec5SDimitry Andric} 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andricstd::error_code setPermissions(const Twine &Path, perms Permissions) { 7810b57cec5SDimitry Andric SmallString<128> PathStorage; 7820b57cec5SDimitry Andric StringRef P = Path.toNullTerminatedStringRef(PathStorage); 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric if (::chmod(P.begin(), Permissions)) 7850b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 7860b57cec5SDimitry Andric return std::error_code(); 7870b57cec5SDimitry Andric} 7880b57cec5SDimitry Andric 7890b57cec5SDimitry Andricstd::error_code setPermissions(int FD, perms Permissions) { 7900b57cec5SDimitry Andric if (::fchmod(FD, Permissions)) 7910b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 7920b57cec5SDimitry Andric return std::error_code(); 7930b57cec5SDimitry Andric} 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andricstd::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, 7960b57cec5SDimitry Andric TimePoint<> ModificationTime) { 7970b57cec5SDimitry Andric#if defined(HAVE_FUTIMENS) 7980b57cec5SDimitry Andric timespec Times[2]; 7990b57cec5SDimitry Andric Times[0] = sys::toTimeSpec(AccessTime); 8000b57cec5SDimitry Andric Times[1] = sys::toTimeSpec(ModificationTime); 8010b57cec5SDimitry Andric if (::futimens(FD, Times)) 8020b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 8030b57cec5SDimitry Andric return std::error_code(); 8040b57cec5SDimitry Andric#elif defined(HAVE_FUTIMES) 8050b57cec5SDimitry Andric timeval Times[2]; 8060b57cec5SDimitry Andric Times[0] = sys::toTimeVal( 8070b57cec5SDimitry Andric std::chrono::time_point_cast<std::chrono::microseconds>(AccessTime)); 8080b57cec5SDimitry Andric Times[1] = 8090b57cec5SDimitry Andric sys::toTimeVal(std::chrono::time_point_cast<std::chrono::microseconds>( 8100b57cec5SDimitry Andric ModificationTime)); 8110b57cec5SDimitry Andric if (::futimes(FD, Times)) 8120b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 8130b57cec5SDimitry Andric return std::error_code(); 814e8d8bef9SDimitry Andric#elif defined(__MVS__) 815e8d8bef9SDimitry Andric attrib_t Attr; 816e8d8bef9SDimitry Andric memset(&Attr, 0, sizeof(Attr)); 817e8d8bef9SDimitry Andric Attr.att_atimechg = 1; 818e8d8bef9SDimitry Andric Attr.att_atime = sys::toTimeT(AccessTime); 819e8d8bef9SDimitry Andric Attr.att_mtimechg = 1; 820e8d8bef9SDimitry Andric Attr.att_mtime = sys::toTimeT(ModificationTime); 821e8d8bef9SDimitry Andric if (::__fchattr(FD, &Attr, sizeof(Attr)) != 0) 822e8d8bef9SDimitry Andric return std::error_code(errno, std::generic_category()); 823e8d8bef9SDimitry Andric return std::error_code(); 8240b57cec5SDimitry Andric#else 8250b57cec5SDimitry Andric#warning Missing futimes() and futimens() 8260b57cec5SDimitry Andric return make_error_code(errc::function_not_supported); 8270b57cec5SDimitry Andric#endif 8280b57cec5SDimitry Andric} 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andricstd::error_code mapped_file_region::init(int FD, uint64_t Offset, 8310b57cec5SDimitry Andric mapmode Mode) { 8320b57cec5SDimitry Andric assert(Size != 0); 8330b57cec5SDimitry Andric 8340b57cec5SDimitry Andric int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; 8350b57cec5SDimitry Andric int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); 836fe6060f1SDimitry Andric#if defined(MAP_NORESERVE) 837fe6060f1SDimitry Andric flags |= MAP_NORESERVE; 838fe6060f1SDimitry Andric#endif 8390b57cec5SDimitry Andric#if defined(__APPLE__) 8400b57cec5SDimitry Andric //---------------------------------------------------------------------- 8410b57cec5SDimitry Andric // Newer versions of MacOSX have a flag that will allow us to read from 8420b57cec5SDimitry Andric // binaries whose code signature is invalid without crashing by using 8430b57cec5SDimitry Andric // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media 8440b57cec5SDimitry Andric // is mapped we can avoid crashing and return zeroes to any pages we try 8450b57cec5SDimitry Andric // to read if the media becomes unavailable by using the 8460b57cec5SDimitry Andric // MAP_RESILIENT_MEDIA flag. These flags are only usable when mapping 8470b57cec5SDimitry Andric // with PROT_READ, so take care not to specify them otherwise. 8480b57cec5SDimitry Andric //---------------------------------------------------------------------- 8490b57cec5SDimitry Andric if (Mode == readonly) { 8500b57cec5SDimitry Andric#if defined(MAP_RESILIENT_CODESIGN) 8510b57cec5SDimitry Andric flags |= MAP_RESILIENT_CODESIGN; 8520b57cec5SDimitry Andric#endif 8530b57cec5SDimitry Andric#if defined(MAP_RESILIENT_MEDIA) 8540b57cec5SDimitry Andric flags |= MAP_RESILIENT_MEDIA; 8550b57cec5SDimitry Andric#endif 8560b57cec5SDimitry Andric } 8570b57cec5SDimitry Andric#endif // #if defined (__APPLE__) 8580b57cec5SDimitry Andric 8590b57cec5SDimitry Andric Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset); 8600b57cec5SDimitry Andric if (Mapping == MAP_FAILED) 8610b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 8620b57cec5SDimitry Andric return std::error_code(); 8630b57cec5SDimitry Andric} 8640b57cec5SDimitry Andric 8650b57cec5SDimitry Andricmapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, 8660b57cec5SDimitry Andric uint64_t offset, std::error_code &ec) 867fe6060f1SDimitry Andric : Size(length), Mode(mode) { 8680b57cec5SDimitry Andric (void)Mode; 8690b57cec5SDimitry Andric ec = init(fd, offset, mode); 8700b57cec5SDimitry Andric if (ec) 871fe6060f1SDimitry Andric copyFrom(mapped_file_region()); 8720b57cec5SDimitry Andric} 8730b57cec5SDimitry Andric 874fe6060f1SDimitry Andricvoid mapped_file_region::unmapImpl() { 8750b57cec5SDimitry Andric if (Mapping) 8760b57cec5SDimitry Andric ::munmap(Mapping, Size); 8770b57cec5SDimitry Andric} 8780b57cec5SDimitry Andric 87904eeddc0SDimitry Andricvoid mapped_file_region::dontNeedImpl() { 88004eeddc0SDimitry Andric assert(Mode == mapped_file_region::readonly); 88181ad6265SDimitry Andric if (!Mapping) 88281ad6265SDimitry Andric return; 88304eeddc0SDimitry Andric#if defined(__MVS__) || defined(_AIX) 88404eeddc0SDimitry Andric // If we don't have madvise, or it isn't beneficial, treat this as a no-op. 88581ad6265SDimitry Andric#elif defined(POSIX_MADV_DONTNEED) 88681ad6265SDimitry Andric ::posix_madvise(Mapping, Size, POSIX_MADV_DONTNEED); 88704eeddc0SDimitry Andric#else 88804eeddc0SDimitry Andric ::madvise(Mapping, Size, MADV_DONTNEED); 88904eeddc0SDimitry Andric#endif 89004eeddc0SDimitry Andric} 89104eeddc0SDimitry Andric 892bdd1243dSDimitry Andricint mapped_file_region::alignment() { return Process::getPageSizeEstimate(); } 8930b57cec5SDimitry Andric 8940b57cec5SDimitry Andricstd::error_code detail::directory_iterator_construct(detail::DirIterState &it, 8950b57cec5SDimitry Andric StringRef path, 8960b57cec5SDimitry Andric bool follow_symlinks) { 8970b57cec5SDimitry Andric SmallString<128> path_null(path); 8980b57cec5SDimitry Andric DIR *directory = ::opendir(path_null.c_str()); 8990b57cec5SDimitry Andric if (!directory) 9000b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 9010b57cec5SDimitry Andric 9020b57cec5SDimitry Andric it.IterationHandle = reinterpret_cast<intptr_t>(directory); 9030b57cec5SDimitry Andric // Add something for replace_filename to replace. 9040b57cec5SDimitry Andric path::append(path_null, "."); 9050b57cec5SDimitry Andric it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks); 9060b57cec5SDimitry Andric return directory_iterator_increment(it); 9070b57cec5SDimitry Andric} 9080b57cec5SDimitry Andric 9090b57cec5SDimitry Andricstd::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 9100b57cec5SDimitry Andric if (it.IterationHandle) 9110b57cec5SDimitry Andric ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); 9120b57cec5SDimitry Andric it.IterationHandle = 0; 9130b57cec5SDimitry Andric it.CurrentEntry = directory_entry(); 9140b57cec5SDimitry Andric return std::error_code(); 9150b57cec5SDimitry Andric} 9160b57cec5SDimitry Andric 9170b57cec5SDimitry Andricstatic file_type direntType(dirent *Entry) { 9180b57cec5SDimitry Andric // Most platforms provide the file type in the dirent: Linux/BSD/Mac. 9190b57cec5SDimitry Andric // The DTTOIF macro lets us reuse our status -> type conversion. 9208bcb0991SDimitry Andric // Note that while glibc provides a macro to see if this is supported, 9218bcb0991SDimitry Andric // _DIRENT_HAVE_D_TYPE, it's not defined on BSD/Mac, so we test for the 9228bcb0991SDimitry Andric // d_type-to-mode_t conversion macro instead. 9238bcb0991SDimitry Andric#if defined(DTTOIF) 9240b57cec5SDimitry Andric return typeForMode(DTTOIF(Entry->d_type)); 9250b57cec5SDimitry Andric#else 9260b57cec5SDimitry Andric // Other platforms such as Solaris require a stat() to get the type. 9270b57cec5SDimitry Andric return file_type::type_unknown; 9280b57cec5SDimitry Andric#endif 9290b57cec5SDimitry Andric} 9300b57cec5SDimitry Andric 9310b57cec5SDimitry Andricstd::error_code detail::directory_iterator_increment(detail::DirIterState &It) { 9320b57cec5SDimitry Andric errno = 0; 9330b57cec5SDimitry Andric dirent *CurDir = ::readdir(reinterpret_cast<DIR *>(It.IterationHandle)); 9340b57cec5SDimitry Andric if (CurDir == nullptr && errno != 0) { 9350b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 9360b57cec5SDimitry Andric } else if (CurDir != nullptr) { 9370b57cec5SDimitry Andric StringRef Name(CurDir->d_name); 9380b57cec5SDimitry Andric if ((Name.size() == 1 && Name[0] == '.') || 9390b57cec5SDimitry Andric (Name.size() == 2 && Name[0] == '.' && Name[1] == '.')) 9400b57cec5SDimitry Andric return directory_iterator_increment(It); 9410b57cec5SDimitry Andric It.CurrentEntry.replace_filename(Name, direntType(CurDir)); 9420b57cec5SDimitry Andric } else 9430b57cec5SDimitry Andric return directory_iterator_destruct(It); 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric return std::error_code(); 9460b57cec5SDimitry Andric} 9470b57cec5SDimitry Andric 9480b57cec5SDimitry AndricErrorOr<basic_file_status> directory_entry::status() const { 9490b57cec5SDimitry Andric file_status s; 9500b57cec5SDimitry Andric if (auto EC = fs::status(Path, s, FollowSymlinks)) 9510b57cec5SDimitry Andric return EC; 9520b57cec5SDimitry Andric return s; 9530b57cec5SDimitry Andric} 9540b57cec5SDimitry Andric 95530ed48b0SMateusz Guzik// 95630ed48b0SMateusz Guzik// FreeBSD optionally provides /proc/self/fd, but it is incompatible with 95730ed48b0SMateusz Guzik// Linux. The thing to use is realpath. 95830ed48b0SMateusz Guzik// 9595f757f3fSDimitry Andric#if !defined(__FreeBSD__) && !defined(__OpenBSD__) 96030ed48b0SMateusz Guzik#define TRY_PROC_SELF_FD 96130ed48b0SMateusz Guzik#endif 96230ed48b0SMateusz Guzik 96330ed48b0SMateusz Guzik#if !defined(F_GETPATH) && defined(TRY_PROC_SELF_FD) 9640b57cec5SDimitry Andricstatic bool hasProcSelfFD() { 9650b57cec5SDimitry Andric // If we have a /proc filesystem mounted, we can quickly establish the 9660b57cec5SDimitry Andric // real name of the file with readlink 9670b57cec5SDimitry Andric static const bool Result = (::access("/proc/self/fd", R_OK) == 0); 9680b57cec5SDimitry Andric return Result; 9690b57cec5SDimitry Andric} 9700b57cec5SDimitry Andric#endif 9710b57cec5SDimitry Andric 9720b57cec5SDimitry Andricstatic int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags, 9730b57cec5SDimitry Andric FileAccess Access) { 9740b57cec5SDimitry Andric int Result = 0; 9750b57cec5SDimitry Andric if (Access == FA_Read) 9760b57cec5SDimitry Andric Result |= O_RDONLY; 9770b57cec5SDimitry Andric else if (Access == FA_Write) 9780b57cec5SDimitry Andric Result |= O_WRONLY; 9790b57cec5SDimitry Andric else if (Access == (FA_Read | FA_Write)) 9800b57cec5SDimitry Andric Result |= O_RDWR; 9810b57cec5SDimitry Andric 9828bcb0991SDimitry Andric // This is for compatibility with old code that assumed OF_Append implied 9830b57cec5SDimitry Andric // would open an existing file. See Windows/Path.inc for a longer comment. 9848bcb0991SDimitry Andric if (Flags & OF_Append) 9850b57cec5SDimitry Andric Disp = CD_OpenAlways; 9860b57cec5SDimitry Andric 9870b57cec5SDimitry Andric if (Disp == CD_CreateNew) { 9880b57cec5SDimitry Andric Result |= O_CREAT; // Create if it doesn't exist. 9890b57cec5SDimitry Andric Result |= O_EXCL; // Fail if it does. 9900b57cec5SDimitry Andric } else if (Disp == CD_CreateAlways) { 9910b57cec5SDimitry Andric Result |= O_CREAT; // Create if it doesn't exist. 9920b57cec5SDimitry Andric Result |= O_TRUNC; // Truncate if it does. 9930b57cec5SDimitry Andric } else if (Disp == CD_OpenAlways) { 9940b57cec5SDimitry Andric Result |= O_CREAT; // Create if it doesn't exist. 9950b57cec5SDimitry Andric } else if (Disp == CD_OpenExisting) { 9960b57cec5SDimitry Andric // Nothing special, just don't add O_CREAT and we get these semantics. 9970b57cec5SDimitry Andric } 9980b57cec5SDimitry Andric 999fe6060f1SDimitry Andric// Using append mode with z/OS UTF-8 auto-conversion results in EINVAL when 1000fe6060f1SDimitry Andric// calling write(). Instead we need to use lseek() to set offset to EOF after 1001fe6060f1SDimitry Andric// open(). 1002fe6060f1SDimitry Andric#ifndef __MVS__ 10038bcb0991SDimitry Andric if (Flags & OF_Append) 10040b57cec5SDimitry Andric Result |= O_APPEND; 1005fe6060f1SDimitry Andric#endif 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric#ifdef O_CLOEXEC 10080b57cec5SDimitry Andric if (!(Flags & OF_ChildInherit)) 10090b57cec5SDimitry Andric Result |= O_CLOEXEC; 10100b57cec5SDimitry Andric#endif 10110b57cec5SDimitry Andric 10120b57cec5SDimitry Andric return Result; 10130b57cec5SDimitry Andric} 10140b57cec5SDimitry Andric 10150b57cec5SDimitry Andricstd::error_code openFile(const Twine &Name, int &ResultFD, 10160b57cec5SDimitry Andric CreationDisposition Disp, FileAccess Access, 10170b57cec5SDimitry Andric OpenFlags Flags, unsigned Mode) { 10180b57cec5SDimitry Andric int OpenFlags = nativeOpenFlags(Disp, Flags, Access); 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric SmallString<128> Storage; 10210b57cec5SDimitry Andric StringRef P = Name.toNullTerminatedStringRef(Storage); 10220b57cec5SDimitry Andric // Call ::open in a lambda to avoid overload resolution in RetryAfterSignal 10230b57cec5SDimitry Andric // when open is overloaded, such as in Bionic. 10240b57cec5SDimitry Andric auto Open = [&]() { return ::open(P.begin(), OpenFlags, Mode); }; 10250b57cec5SDimitry Andric if ((ResultFD = sys::RetryAfterSignal(-1, Open)) < 0) 10260b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 10270b57cec5SDimitry Andric#ifndef O_CLOEXEC 10280b57cec5SDimitry Andric if (!(Flags & OF_ChildInherit)) { 10290b57cec5SDimitry Andric int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); 10300b57cec5SDimitry Andric (void)r; 10310b57cec5SDimitry Andric assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); 10320b57cec5SDimitry Andric } 10330b57cec5SDimitry Andric#endif 1034fe6060f1SDimitry Andric 1035fe6060f1SDimitry Andric#ifdef __MVS__ 1036fe6060f1SDimitry Andric /* Reason about auto-conversion and file tags. Setting the file tag only 1037fe6060f1SDimitry Andric * applies if file is opened in write mode: 1038fe6060f1SDimitry Andric * 1039fe6060f1SDimitry Andric * Text file: 1040fe6060f1SDimitry Andric * File exists File created 1041fe6060f1SDimitry Andric * CD_CreateNew n/a conv: on 1042fe6060f1SDimitry Andric * tag: set 1047 1043fe6060f1SDimitry Andric * CD_CreateAlways conv: auto conv: on 1044fe6060f1SDimitry Andric * tag: auto 1047 tag: set 1047 1045fe6060f1SDimitry Andric * CD_OpenAlways conv: auto conv: on 1046fe6060f1SDimitry Andric * tag: auto 1047 tag: set 1047 1047fe6060f1SDimitry Andric * CD_OpenExisting conv: auto n/a 1048fe6060f1SDimitry Andric * tag: unchanged 1049fe6060f1SDimitry Andric * 1050fe6060f1SDimitry Andric * Binary file: 1051fe6060f1SDimitry Andric * File exists File created 1052fe6060f1SDimitry Andric * CD_CreateNew n/a conv: off 1053fe6060f1SDimitry Andric * tag: set binary 1054fe6060f1SDimitry Andric * CD_CreateAlways conv: off conv: off 1055fe6060f1SDimitry Andric * tag: auto binary tag: set binary 1056fe6060f1SDimitry Andric * CD_OpenAlways conv: off conv: off 1057fe6060f1SDimitry Andric * tag: auto binary tag: set binary 1058fe6060f1SDimitry Andric * CD_OpenExisting conv: off n/a 1059fe6060f1SDimitry Andric * tag: unchanged 1060fe6060f1SDimitry Andric * 1061fe6060f1SDimitry Andric * Actions: 1062fe6060f1SDimitry Andric * conv: off -> auto-conversion is turned off 1063fe6060f1SDimitry Andric * conv: on -> auto-conversion is turned on 1064fe6060f1SDimitry Andric * conv: auto -> auto-conversion is turned on if the file is untagged 1065fe6060f1SDimitry Andric * tag: set 1047 -> set the file tag to text encoded in 1047 1066fe6060f1SDimitry Andric * tag: set binary -> set the file tag to binary 1067fe6060f1SDimitry Andric * tag: auto 1047 -> set file tag to 1047 if not set 1068fe6060f1SDimitry Andric * tag: auto binary -> set file tag to binary if not set 1069fe6060f1SDimitry Andric * tag: unchanged -> do not care about the file tag 1070fe6060f1SDimitry Andric * 1071fe6060f1SDimitry Andric * It is not possible to distinguish between the cases "file exists" and 1072fe6060f1SDimitry Andric * "file created". In the latter case, the file tag is not set and the file 1073fe6060f1SDimitry Andric * size is zero. The decision table boils down to: 1074fe6060f1SDimitry Andric * 1075fe6060f1SDimitry Andric * the file tag is set if 1076fe6060f1SDimitry Andric * - the file is opened for writing 1077fe6060f1SDimitry Andric * - the create disposition is not equal to CD_OpenExisting 1078fe6060f1SDimitry Andric * - the file tag is not set 1079fe6060f1SDimitry Andric * - the file size is zero 1080fe6060f1SDimitry Andric * 1081fe6060f1SDimitry Andric * This only applies if the file is a regular file. E.g. enabling 1082fe6060f1SDimitry Andric * auto-conversion for reading from /dev/null results in error EINVAL when 1083fe6060f1SDimitry Andric * calling read(). 1084fe6060f1SDimitry Andric * 1085fe6060f1SDimitry Andric * Using append mode with z/OS UTF-8 auto-conversion results in EINVAL when 1086fe6060f1SDimitry Andric * calling write(). Instead we need to use lseek() to set offset to EOF after 1087fe6060f1SDimitry Andric * open(). 1088fe6060f1SDimitry Andric */ 1089fe6060f1SDimitry Andric if ((Flags & OF_Append) && lseek(ResultFD, 0, SEEK_END) == -1) 1090fe6060f1SDimitry Andric return std::error_code(errno, std::generic_category()); 1091fe6060f1SDimitry Andric struct stat Stat; 1092fe6060f1SDimitry Andric if (fstat(ResultFD, &Stat) == -1) 1093fe6060f1SDimitry Andric return std::error_code(errno, std::generic_category()); 1094fe6060f1SDimitry Andric if (S_ISREG(Stat.st_mode)) { 1095fe6060f1SDimitry Andric bool DoSetTag = (Access & FA_Write) && (Disp != CD_OpenExisting) && 1096fe6060f1SDimitry Andric !Stat.st_tag.ft_txtflag && !Stat.st_tag.ft_ccsid && 1097fe6060f1SDimitry Andric Stat.st_size == 0; 1098fe6060f1SDimitry Andric if (Flags & OF_Text) { 1099fe6060f1SDimitry Andric if (auto EC = llvm::enableAutoConversion(ResultFD)) 1100fe6060f1SDimitry Andric return EC; 1101fe6060f1SDimitry Andric if (DoSetTag) { 1102fe6060f1SDimitry Andric if (auto EC = llvm::setFileTag(ResultFD, CCSID_IBM_1047, true)) 1103fe6060f1SDimitry Andric return EC; 1104fe6060f1SDimitry Andric } 1105fe6060f1SDimitry Andric } else { 1106fe6060f1SDimitry Andric if (auto EC = llvm::disableAutoConversion(ResultFD)) 1107fe6060f1SDimitry Andric return EC; 1108fe6060f1SDimitry Andric if (DoSetTag) { 1109fe6060f1SDimitry Andric if (auto EC = llvm::setFileTag(ResultFD, FT_BINARY, false)) 1110fe6060f1SDimitry Andric return EC; 1111fe6060f1SDimitry Andric } 1112fe6060f1SDimitry Andric } 1113fe6060f1SDimitry Andric } 1114fe6060f1SDimitry Andric#endif 1115fe6060f1SDimitry Andric 11160b57cec5SDimitry Andric return std::error_code(); 11170b57cec5SDimitry Andric} 11180b57cec5SDimitry Andric 11190b57cec5SDimitry AndricExpected<int> openNativeFile(const Twine &Name, CreationDisposition Disp, 11200b57cec5SDimitry Andric FileAccess Access, OpenFlags Flags, 11210b57cec5SDimitry Andric unsigned Mode) { 11220b57cec5SDimitry Andric 11230b57cec5SDimitry Andric int FD; 11240b57cec5SDimitry Andric std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode); 11250b57cec5SDimitry Andric if (EC) 11260b57cec5SDimitry Andric return errorCodeToError(EC); 11270b57cec5SDimitry Andric return FD; 11280b57cec5SDimitry Andric} 11290b57cec5SDimitry Andric 11300b57cec5SDimitry Andricstd::error_code openFileForRead(const Twine &Name, int &ResultFD, 11310b57cec5SDimitry Andric OpenFlags Flags, 11320b57cec5SDimitry Andric SmallVectorImpl<char> *RealPath) { 11330b57cec5SDimitry Andric std::error_code EC = 11340b57cec5SDimitry Andric openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666); 11350b57cec5SDimitry Andric if (EC) 11360b57cec5SDimitry Andric return EC; 11370b57cec5SDimitry Andric 11380b57cec5SDimitry Andric // Attempt to get the real name of the file, if the user asked 11390b57cec5SDimitry Andric if (!RealPath) 11400b57cec5SDimitry Andric return std::error_code(); 11410b57cec5SDimitry Andric RealPath->clear(); 11420b57cec5SDimitry Andric#if defined(F_GETPATH) 11430b57cec5SDimitry Andric // When F_GETPATH is availble, it is the quickest way to get 11440b57cec5SDimitry Andric // the real path name. 11455ffd83dbSDimitry Andric char Buffer[PATH_MAX]; 11460b57cec5SDimitry Andric if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1) 11470b57cec5SDimitry Andric RealPath->append(Buffer, Buffer + strlen(Buffer)); 11480b57cec5SDimitry Andric#else 11490b57cec5SDimitry Andric char Buffer[PATH_MAX]; 115030ed48b0SMateusz Guzik#if defined(TRY_PROC_SELF_FD) 11510b57cec5SDimitry Andric if (hasProcSelfFD()) { 11520b57cec5SDimitry Andric char ProcPath[64]; 11530b57cec5SDimitry Andric snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD); 11540b57cec5SDimitry Andric ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer)); 11550b57cec5SDimitry Andric if (CharCount > 0) 11560b57cec5SDimitry Andric RealPath->append(Buffer, Buffer + CharCount); 11570b57cec5SDimitry Andric } else { 115830ed48b0SMateusz Guzik#endif 11590b57cec5SDimitry Andric SmallString<128> Storage; 11600b57cec5SDimitry Andric StringRef P = Name.toNullTerminatedStringRef(Storage); 11610b57cec5SDimitry Andric 11620b57cec5SDimitry Andric // Use ::realpath to get the real path name 11630b57cec5SDimitry Andric if (::realpath(P.begin(), Buffer) != nullptr) 11640b57cec5SDimitry Andric RealPath->append(Buffer, Buffer + strlen(Buffer)); 116530ed48b0SMateusz Guzik#if defined(TRY_PROC_SELF_FD) 11660b57cec5SDimitry Andric } 11670b57cec5SDimitry Andric#endif 116830ed48b0SMateusz Guzik#endif 11690b57cec5SDimitry Andric return std::error_code(); 11700b57cec5SDimitry Andric} 11710b57cec5SDimitry Andric 11720b57cec5SDimitry AndricExpected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, 11730b57cec5SDimitry Andric SmallVectorImpl<char> *RealPath) { 11740b57cec5SDimitry Andric file_t ResultFD; 11750b57cec5SDimitry Andric std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath); 11760b57cec5SDimitry Andric if (EC) 11770b57cec5SDimitry Andric return errorCodeToError(EC); 11780b57cec5SDimitry Andric return ResultFD; 11790b57cec5SDimitry Andric} 11800b57cec5SDimitry Andric 11810b57cec5SDimitry Andricfile_t getStdinHandle() { return 0; } 11820b57cec5SDimitry Andricfile_t getStdoutHandle() { return 1; } 11830b57cec5SDimitry Andricfile_t getStderrHandle() { return 2; } 11840b57cec5SDimitry Andric 11858bcb0991SDimitry AndricExpected<size_t> readNativeFile(file_t FD, MutableArrayRef<char> Buf) { 1186e8d8bef9SDimitry Andric#if defined(__APPLE__) 1187e8d8bef9SDimitry Andric size_t Size = std::min<size_t>(Buf.size(), INT32_MAX); 1188e8d8bef9SDimitry Andric#else 1189e8d8bef9SDimitry Andric size_t Size = Buf.size(); 1190e8d8bef9SDimitry Andric#endif 1191bdd1243dSDimitry Andric ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size); 11928bcb0991SDimitry Andric if (ssize_t(NumRead) == -1) 11938bcb0991SDimitry Andric return errorCodeToError(std::error_code(errno, std::generic_category())); 11948bcb0991SDimitry Andric return NumRead; 11950b57cec5SDimitry Andric} 11960b57cec5SDimitry Andric 11978bcb0991SDimitry AndricExpected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf, 11988bcb0991SDimitry Andric uint64_t Offset) { 1199e8d8bef9SDimitry Andric#if defined(__APPLE__) 1200e8d8bef9SDimitry Andric size_t Size = std::min<size_t>(Buf.size(), INT32_MAX); 1201e8d8bef9SDimitry Andric#else 1202e8d8bef9SDimitry Andric size_t Size = Buf.size(); 1203e8d8bef9SDimitry Andric#endif 12040b57cec5SDimitry Andric#ifdef HAVE_PREAD 12058bcb0991SDimitry Andric ssize_t NumRead = 1206e8d8bef9SDimitry Andric sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Size, Offset); 12070b57cec5SDimitry Andric#else 12088bcb0991SDimitry Andric if (lseek(FD, Offset, SEEK_SET) == -1) 12098bcb0991SDimitry Andric return errorCodeToError(std::error_code(errno, std::generic_category())); 1210bdd1243dSDimitry Andric ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size); 12110b57cec5SDimitry Andric#endif 12128bcb0991SDimitry Andric if (NumRead == -1) 12138bcb0991SDimitry Andric return errorCodeToError(std::error_code(errno, std::generic_category())); 12148bcb0991SDimitry Andric return NumRead; 12150b57cec5SDimitry Andric} 12160b57cec5SDimitry Andric 1217e8d8bef9SDimitry Andricstd::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { 1218e8d8bef9SDimitry Andric auto Start = std::chrono::steady_clock::now(); 1219e8d8bef9SDimitry Andric auto End = Start + Timeout; 1220e8d8bef9SDimitry Andric do { 1221e8d8bef9SDimitry Andric struct flock Lock; 1222e8d8bef9SDimitry Andric memset(&Lock, 0, sizeof(Lock)); 1223e8d8bef9SDimitry Andric Lock.l_type = F_WRLCK; 1224e8d8bef9SDimitry Andric Lock.l_whence = SEEK_SET; 1225e8d8bef9SDimitry Andric Lock.l_start = 0; 1226e8d8bef9SDimitry Andric Lock.l_len = 0; 1227e8d8bef9SDimitry Andric if (::fcntl(FD, F_SETLK, &Lock) != -1) 1228e8d8bef9SDimitry Andric return std::error_code(); 1229e8d8bef9SDimitry Andric int Error = errno; 1230e8d8bef9SDimitry Andric if (Error != EACCES && Error != EAGAIN) 1231e8d8bef9SDimitry Andric return std::error_code(Error, std::generic_category()); 1232e8d8bef9SDimitry Andric usleep(1000); 1233e8d8bef9SDimitry Andric } while (std::chrono::steady_clock::now() < End); 1234e8d8bef9SDimitry Andric return make_error_code(errc::no_lock_available); 1235e8d8bef9SDimitry Andric} 1236e8d8bef9SDimitry Andric 1237e8d8bef9SDimitry Andricstd::error_code lockFile(int FD) { 1238e8d8bef9SDimitry Andric struct flock Lock; 1239e8d8bef9SDimitry Andric memset(&Lock, 0, sizeof(Lock)); 1240e8d8bef9SDimitry Andric Lock.l_type = F_WRLCK; 1241e8d8bef9SDimitry Andric Lock.l_whence = SEEK_SET; 1242e8d8bef9SDimitry Andric Lock.l_start = 0; 1243e8d8bef9SDimitry Andric Lock.l_len = 0; 1244e8d8bef9SDimitry Andric if (::fcntl(FD, F_SETLKW, &Lock) != -1) 1245e8d8bef9SDimitry Andric return std::error_code(); 1246e8d8bef9SDimitry Andric int Error = errno; 1247e8d8bef9SDimitry Andric return std::error_code(Error, std::generic_category()); 1248e8d8bef9SDimitry Andric} 1249e8d8bef9SDimitry Andric 1250e8d8bef9SDimitry Andricstd::error_code unlockFile(int FD) { 1251e8d8bef9SDimitry Andric struct flock Lock; 1252e8d8bef9SDimitry Andric Lock.l_type = F_UNLCK; 1253e8d8bef9SDimitry Andric Lock.l_whence = SEEK_SET; 1254e8d8bef9SDimitry Andric Lock.l_start = 0; 1255e8d8bef9SDimitry Andric Lock.l_len = 0; 1256e8d8bef9SDimitry Andric if (::fcntl(FD, F_SETLK, &Lock) != -1) 1257e8d8bef9SDimitry Andric return std::error_code(); 1258e8d8bef9SDimitry Andric return std::error_code(errno, std::generic_category()); 1259e8d8bef9SDimitry Andric} 1260e8d8bef9SDimitry Andric 12610b57cec5SDimitry Andricstd::error_code closeFile(file_t &F) { 12620b57cec5SDimitry Andric file_t TmpF = F; 12630b57cec5SDimitry Andric F = kInvalidFile; 12640b57cec5SDimitry Andric return Process::SafelyCloseFileDescriptor(TmpF); 12650b57cec5SDimitry Andric} 12660b57cec5SDimitry Andric 12670b57cec5SDimitry Andrictemplate <typename T> 12680b57cec5SDimitry Andricstatic std::error_code remove_directories_impl(const T &Entry, 12690b57cec5SDimitry Andric bool IgnoreErrors) { 12700b57cec5SDimitry Andric std::error_code EC; 12710b57cec5SDimitry Andric directory_iterator Begin(Entry, EC, false); 12720b57cec5SDimitry Andric directory_iterator End; 12730b57cec5SDimitry Andric while (Begin != End) { 12740b57cec5SDimitry Andric auto &Item = *Begin; 12750b57cec5SDimitry Andric ErrorOr<basic_file_status> st = Item.status(); 1276bdd1243dSDimitry Andric if (st) { 12770b57cec5SDimitry Andric if (is_directory(*st)) { 12780b57cec5SDimitry Andric EC = remove_directories_impl(Item, IgnoreErrors); 12790b57cec5SDimitry Andric if (EC && !IgnoreErrors) 12800b57cec5SDimitry Andric return EC; 12810b57cec5SDimitry Andric } 12820b57cec5SDimitry Andric 12830b57cec5SDimitry Andric EC = fs::remove(Item.path(), true); 12840b57cec5SDimitry Andric if (EC && !IgnoreErrors) 12850b57cec5SDimitry Andric return EC; 1286bdd1243dSDimitry Andric } else if (!IgnoreErrors) { 1287bdd1243dSDimitry Andric return st.getError(); 1288bdd1243dSDimitry Andric } 12890b57cec5SDimitry Andric 12900b57cec5SDimitry Andric Begin.increment(EC); 12910b57cec5SDimitry Andric if (EC && !IgnoreErrors) 12920b57cec5SDimitry Andric return EC; 12930b57cec5SDimitry Andric } 12940b57cec5SDimitry Andric return std::error_code(); 12950b57cec5SDimitry Andric} 12960b57cec5SDimitry Andric 12970b57cec5SDimitry Andricstd::error_code remove_directories(const Twine &path, bool IgnoreErrors) { 12980b57cec5SDimitry Andric auto EC = remove_directories_impl(path, IgnoreErrors); 12990b57cec5SDimitry Andric if (EC && !IgnoreErrors) 13000b57cec5SDimitry Andric return EC; 13010b57cec5SDimitry Andric EC = fs::remove(path, true); 13020b57cec5SDimitry Andric if (EC && !IgnoreErrors) 13030b57cec5SDimitry Andric return EC; 13040b57cec5SDimitry Andric return std::error_code(); 13050b57cec5SDimitry Andric} 13060b57cec5SDimitry Andric 13070b57cec5SDimitry Andricstd::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, 13080b57cec5SDimitry Andric bool expand_tilde) { 13090b57cec5SDimitry Andric dest.clear(); 13100b57cec5SDimitry Andric if (path.isTriviallyEmpty()) 13110b57cec5SDimitry Andric return std::error_code(); 13120b57cec5SDimitry Andric 13130b57cec5SDimitry Andric if (expand_tilde) { 13140b57cec5SDimitry Andric SmallString<128> Storage; 13150b57cec5SDimitry Andric path.toVector(Storage); 13160b57cec5SDimitry Andric expandTildeExpr(Storage); 13170b57cec5SDimitry Andric return real_path(Storage, dest, false); 13180b57cec5SDimitry Andric } 13190b57cec5SDimitry Andric 13200b57cec5SDimitry Andric SmallString<128> Storage; 13210b57cec5SDimitry Andric StringRef P = path.toNullTerminatedStringRef(Storage); 13220b57cec5SDimitry Andric char Buffer[PATH_MAX]; 13230b57cec5SDimitry Andric if (::realpath(P.begin(), Buffer) == nullptr) 13240b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 13250b57cec5SDimitry Andric dest.append(Buffer, Buffer + strlen(Buffer)); 13260b57cec5SDimitry Andric return std::error_code(); 13270b57cec5SDimitry Andric} 13280b57cec5SDimitry Andric 1329fe6060f1SDimitry Andricstd::error_code changeFileOwnership(int FD, uint32_t Owner, uint32_t Group) { 1330fe6060f1SDimitry Andric auto FChown = [&]() { return ::fchown(FD, Owner, Group); }; 1331fe6060f1SDimitry Andric // Retry if fchown call fails due to interruption. 1332fe6060f1SDimitry Andric if ((sys::RetryAfterSignal(-1, FChown)) < 0) 1333fe6060f1SDimitry Andric return std::error_code(errno, std::generic_category()); 1334fe6060f1SDimitry Andric return std::error_code(); 1335fe6060f1SDimitry Andric} 1336fe6060f1SDimitry Andric 13370b57cec5SDimitry Andric} // end namespace fs 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andricnamespace path { 13400b57cec5SDimitry Andric 13410b57cec5SDimitry Andricbool home_directory(SmallVectorImpl<char> &result) { 1342bdd1243dSDimitry Andric std::unique_ptr<char[]> Buf; 13430b57cec5SDimitry Andric char *RequestedDir = getenv("HOME"); 13440b57cec5SDimitry Andric if (!RequestedDir) { 1345bdd1243dSDimitry Andric long BufSize = sysconf(_SC_GETPW_R_SIZE_MAX); 1346bdd1243dSDimitry Andric if (BufSize <= 0) 1347bdd1243dSDimitry Andric BufSize = 16384; 1348bdd1243dSDimitry Andric Buf = std::make_unique<char[]>(BufSize); 1349bdd1243dSDimitry Andric struct passwd Pwd; 1350bdd1243dSDimitry Andric struct passwd *pw = nullptr; 1351bdd1243dSDimitry Andric getpwuid_r(getuid(), &Pwd, Buf.get(), BufSize, &pw); 13520b57cec5SDimitry Andric if (pw && pw->pw_dir) 13530b57cec5SDimitry Andric RequestedDir = pw->pw_dir; 13540b57cec5SDimitry Andric } 13550b57cec5SDimitry Andric if (!RequestedDir) 13560b57cec5SDimitry Andric return false; 13570b57cec5SDimitry Andric 13580b57cec5SDimitry Andric result.clear(); 13590b57cec5SDimitry Andric result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); 13600b57cec5SDimitry Andric return true; 13610b57cec5SDimitry Andric} 13620b57cec5SDimitry Andric 13630b57cec5SDimitry Andricstatic bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) { 13640b57cec5SDimitry Andric#if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) 13650b57cec5SDimitry Andric // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. 13660b57cec5SDimitry Andric // macros defined in <unistd.h> on darwin >= 9 1367bdd1243dSDimitry Andric int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR : _CS_DARWIN_USER_CACHE_DIR; 13680b57cec5SDimitry Andric size_t ConfLen = confstr(ConfName, nullptr, 0); 13690b57cec5SDimitry Andric if (ConfLen > 0) { 13700b57cec5SDimitry Andric do { 13710b57cec5SDimitry Andric Result.resize(ConfLen); 13720b57cec5SDimitry Andric ConfLen = confstr(ConfName, Result.data(), Result.size()); 13730b57cec5SDimitry Andric } while (ConfLen > 0 && ConfLen != Result.size()); 13740b57cec5SDimitry Andric 13750b57cec5SDimitry Andric if (ConfLen > 0) { 13760b57cec5SDimitry Andric assert(Result.back() == 0); 13770b57cec5SDimitry Andric Result.pop_back(); 13780b57cec5SDimitry Andric return true; 13790b57cec5SDimitry Andric } 13800b57cec5SDimitry Andric 13810b57cec5SDimitry Andric Result.clear(); 13820b57cec5SDimitry Andric } 13830b57cec5SDimitry Andric#endif 13840b57cec5SDimitry Andric return false; 13850b57cec5SDimitry Andric} 13860b57cec5SDimitry Andric 13875ffd83dbSDimitry Andricbool user_config_directory(SmallVectorImpl<char> &result) { 13885ffd83dbSDimitry Andric#ifdef __APPLE__ 13895ffd83dbSDimitry Andric // Mac: ~/Library/Preferences/ 13905ffd83dbSDimitry Andric if (home_directory(result)) { 13915ffd83dbSDimitry Andric append(result, "Library", "Preferences"); 13925ffd83dbSDimitry Andric return true; 13935ffd83dbSDimitry Andric } 13945ffd83dbSDimitry Andric#else 13955ffd83dbSDimitry Andric // XDG_CONFIG_HOME as defined in the XDG Base Directory Specification: 13965ffd83dbSDimitry Andric // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 13975ffd83dbSDimitry Andric if (const char *RequestedDir = getenv("XDG_CONFIG_HOME")) { 13985ffd83dbSDimitry Andric result.clear(); 13995ffd83dbSDimitry Andric result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); 14005ffd83dbSDimitry Andric return true; 14015ffd83dbSDimitry Andric } 14025ffd83dbSDimitry Andric#endif 14035ffd83dbSDimitry Andric // Fallback: ~/.config 14045ffd83dbSDimitry Andric if (!home_directory(result)) { 14055ffd83dbSDimitry Andric return false; 14065ffd83dbSDimitry Andric } 14075ffd83dbSDimitry Andric append(result, ".config"); 14085ffd83dbSDimitry Andric return true; 14095ffd83dbSDimitry Andric} 14105ffd83dbSDimitry Andric 14115ffd83dbSDimitry Andricbool cache_directory(SmallVectorImpl<char> &result) { 14125ffd83dbSDimitry Andric#ifdef __APPLE__ 14135ffd83dbSDimitry Andric if (getDarwinConfDir(false /*tempDir*/, result)) { 14145ffd83dbSDimitry Andric return true; 14155ffd83dbSDimitry Andric } 14165ffd83dbSDimitry Andric#else 14175ffd83dbSDimitry Andric // XDG_CACHE_HOME as defined in the XDG Base Directory Specification: 14185ffd83dbSDimitry Andric // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 14195ffd83dbSDimitry Andric if (const char *RequestedDir = getenv("XDG_CACHE_HOME")) { 14205ffd83dbSDimitry Andric result.clear(); 14215ffd83dbSDimitry Andric result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); 14225ffd83dbSDimitry Andric return true; 14235ffd83dbSDimitry Andric } 14245ffd83dbSDimitry Andric#endif 14255ffd83dbSDimitry Andric if (!home_directory(result)) { 14265ffd83dbSDimitry Andric return false; 14275ffd83dbSDimitry Andric } 14285ffd83dbSDimitry Andric append(result, ".cache"); 14295ffd83dbSDimitry Andric return true; 14305ffd83dbSDimitry Andric} 14315ffd83dbSDimitry Andric 14320b57cec5SDimitry Andricstatic const char *getEnvTempDir() { 14330b57cec5SDimitry Andric // Check whether the temporary directory is specified by an environment 14340b57cec5SDimitry Andric // variable. 14350b57cec5SDimitry Andric const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; 14360b57cec5SDimitry Andric for (const char *Env : EnvironmentVariables) { 14370b57cec5SDimitry Andric if (const char *Dir = std::getenv(Env)) 14380b57cec5SDimitry Andric return Dir; 14390b57cec5SDimitry Andric } 14400b57cec5SDimitry Andric 14410b57cec5SDimitry Andric return nullptr; 14420b57cec5SDimitry Andric} 14430b57cec5SDimitry Andric 14440b57cec5SDimitry Andricstatic const char *getDefaultTempDir(bool ErasedOnReboot) { 14450b57cec5SDimitry Andric#ifdef P_tmpdir 14460b57cec5SDimitry Andric if ((bool)P_tmpdir) 14470b57cec5SDimitry Andric return P_tmpdir; 14480b57cec5SDimitry Andric#endif 14490b57cec5SDimitry Andric 14500b57cec5SDimitry Andric if (ErasedOnReboot) 14510b57cec5SDimitry Andric return "/tmp"; 14520b57cec5SDimitry Andric return "/var/tmp"; 14530b57cec5SDimitry Andric} 14540b57cec5SDimitry Andric 14550b57cec5SDimitry Andricvoid system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { 14560b57cec5SDimitry Andric Result.clear(); 14570b57cec5SDimitry Andric 14580b57cec5SDimitry Andric if (ErasedOnReboot) { 14590b57cec5SDimitry Andric // There is no env variable for the cache directory. 14600b57cec5SDimitry Andric if (const char *RequestedDir = getEnvTempDir()) { 14610b57cec5SDimitry Andric Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); 14620b57cec5SDimitry Andric return; 14630b57cec5SDimitry Andric } 14640b57cec5SDimitry Andric } 14650b57cec5SDimitry Andric 14660b57cec5SDimitry Andric if (getDarwinConfDir(ErasedOnReboot, Result)) 14670b57cec5SDimitry Andric return; 14680b57cec5SDimitry Andric 14690b57cec5SDimitry Andric const char *RequestedDir = getDefaultTempDir(ErasedOnReboot); 14700b57cec5SDimitry Andric Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); 14710b57cec5SDimitry Andric} 14720b57cec5SDimitry Andric 14730b57cec5SDimitry Andric} // end namespace path 14740b57cec5SDimitry Andric 14750b57cec5SDimitry Andricnamespace fs { 14760b57cec5SDimitry Andric 14770b57cec5SDimitry Andric#ifdef __APPLE__ 14780b57cec5SDimitry Andric/// This implementation tries to perform an APFS CoW clone of the file, 14790b57cec5SDimitry Andric/// which can be much faster and uses less space. 14800b57cec5SDimitry Andric/// Unfortunately fcopyfile(3) does not support COPYFILE_CLONE, so the 14810b57cec5SDimitry Andric/// file descriptor variant of this function still uses the default 14820b57cec5SDimitry Andric/// implementation. 14830b57cec5SDimitry Andricstd::error_code copy_file(const Twine &From, const Twine &To) { 1484349cc55cSDimitry Andric std::string FromS = From.str(); 1485349cc55cSDimitry Andric std::string ToS = To.str(); 1486349cc55cSDimitry Andric#if __has_builtin(__builtin_available) 14870b57cec5SDimitry Andric if (__builtin_available(macos 10.12, *)) { 1488349cc55cSDimitry Andric // Optimistically try to use clonefile() and handle errors, rather than 1489349cc55cSDimitry Andric // calling stat() to see if it'll work. 1490349cc55cSDimitry Andric // 1491349cc55cSDimitry Andric // Note: It's okay if From is a symlink. In contrast to the behaviour of 1492349cc55cSDimitry Andric // copyfile() with COPYFILE_CLONE, clonefile() clones targets (not the 1493349cc55cSDimitry Andric // symlink itself) unless the flag CLONE_NOFOLLOW is passed. 1494349cc55cSDimitry Andric if (!clonefile(FromS.c_str(), ToS.c_str(), 0)) 1495349cc55cSDimitry Andric return std::error_code(); 1496349cc55cSDimitry Andric 1497349cc55cSDimitry Andric auto Errno = errno; 1498349cc55cSDimitry Andric switch (Errno) { 1499349cc55cSDimitry Andric case EEXIST: // To already exists. 1500349cc55cSDimitry Andric case ENOTSUP: // Device does not support cloning. 1501349cc55cSDimitry Andric case EXDEV: // From and To are on different devices. 1502349cc55cSDimitry Andric break; 1503349cc55cSDimitry Andric default: 1504349cc55cSDimitry Andric // Anything else will also break copyfile(). 1505349cc55cSDimitry Andric return std::error_code(Errno, std::generic_category()); 1506349cc55cSDimitry Andric } 1507349cc55cSDimitry Andric 1508349cc55cSDimitry Andric // TODO: For EEXIST, profile calling fs::generateUniqueName() and 1509349cc55cSDimitry Andric // clonefile() in a retry loop (then rename() on success) before falling 1510349cc55cSDimitry Andric // back to copyfile(). Depending on the size of the file this could be 1511349cc55cSDimitry Andric // cheaper. 15120b57cec5SDimitry Andric } 15130b57cec5SDimitry Andric#endif 1514349cc55cSDimitry Andric if (!copyfile(FromS.c_str(), ToS.c_str(), /*State=*/NULL, COPYFILE_DATA)) 15150b57cec5SDimitry Andric return std::error_code(); 15160b57cec5SDimitry Andric return std::error_code(errno, std::generic_category()); 15170b57cec5SDimitry Andric} 15180b57cec5SDimitry Andric#endif // __APPLE__ 15190b57cec5SDimitry Andric 15200b57cec5SDimitry Andric} // end namespace fs 15210b57cec5SDimitry Andric 15220b57cec5SDimitry Andric} // end namespace sys 15230b57cec5SDimitry Andric} // end namespace llvm 1524