aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Support/Unix/Path.inc
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Support/Unix/Path.inc')
-rw-r--r--contrib/llvm/lib/Support/Unix/Path.inc219
1 files changed, 189 insertions, 30 deletions
diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc
index d7cc0d627d09..e80880c6b3cb 100644
--- a/contrib/llvm/lib/Support/Unix/Path.inc
+++ b/contrib/llvm/lib/Support/Unix/Path.inc
@@ -1,9 +1,8 @@
//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -38,6 +37,7 @@
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <sys/attr.h>
+#include <copyfile.h>
#elif defined(__DragonFly__)
#include <sys/mount.h>
#endif
@@ -56,7 +56,7 @@
#include <sys/types.h>
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \
- !defined(__linux__) && !defined(__FreeBSD_kernel__)
+ !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX)
#include <sys/statvfs.h>
#define STATVFS statvfs
#define FSTATVFS fstatvfs
@@ -77,6 +77,14 @@
#endif
#endif
#include <sys/vfs.h>
+#elif defined(_AIX)
+#include <sys/statfs.h>
+
+// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to
+// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide
+// the typedef prior to including <sys/vmount.h> to work around this issue.
+typedef uint_t uint;
+#include <sys/vmount.h>
#else
#include <sys/mount.h>
#endif
@@ -108,7 +116,11 @@ test_dir(char ret[PATH_MAX], const char *dir, const char *bin)
struct stat sb;
char fullpath[PATH_MAX];
- snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin);
+ int chars = snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin);
+ // We cannot write PATH_MAX characters because the string will be terminated
+ // with a null character. Fail if truncation happened.
+ if (chars >= PATH_MAX)
+ return 1;
if (!realpath(fullpath, ret))
return 1;
if (stat(fullpath, &sb) != 0)
@@ -120,8 +132,6 @@ test_dir(char ret[PATH_MAX], const char *dir, const char *bin)
static char *
getprogpath(char ret[PATH_MAX], const char *bin)
{
- char *pv, *s, *t;
-
/* First approach: absolute path. */
if (bin[0] == '/') {
if (test_dir(ret, "/", bin) == 0)
@@ -140,18 +150,21 @@ getprogpath(char ret[PATH_MAX], const char *bin)
}
/* Third approach: $PATH */
+ char *pv;
if ((pv = getenv("PATH")) == nullptr)
return nullptr;
- s = pv = strdup(pv);
- if (!pv)
+ char *s = strdup(pv);
+ if (!s)
return nullptr;
- while ((t = strsep(&s, ":")) != nullptr) {
+ char *state;
+ for (char *t = strtok_r(s, ":", &state); t != nullptr;
+ t = strtok_r(nullptr, ":", &state)) {
if (test_dir(ret, t, bin) == 0) {
- free(pv);
+ free(s);
return ret;
}
}
- free(pv);
+ free(s);
return nullptr;
}
#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
@@ -173,8 +186,21 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__minix) || defined(__DragonFly__) || \
defined(__FreeBSD_kernel__) || defined(_AIX)
+ StringRef curproc("/proc/curproc/file");
char exe_path[PATH_MAX];
-
+ // /proc is not mounted by default under FreeBSD, but gives more accurate
+ // information than argv[0] when it is.
+ if (sys::fs::exists(curproc)) {
+ ssize_t len = readlink(curproc.str().c_str(), exe_path, sizeof(exe_path));
+ if (len > 0) {
+ // Null terminate the string for realpath. readlink never null
+ // terminates its output.
+ len = std::min(len, ssize_t(sizeof(exe_path) - 1));
+ exe_path[len] = '\0';
+ return exe_path;
+ }
+ }
+ // If we don't have procfs mounted, fall back to argv[0]
if (getprogpath(exe_path, argv0) != NULL)
return exe_path;
#elif defined(__linux__) || defined(__CYGWIN__)
@@ -196,20 +222,20 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// the program, and not the eventual binary file. Therefore, call realpath
// so this behaves the same on all platforms.
#if _POSIX_VERSION >= 200112 || defined(__GLIBC__)
- char *real_path = realpath(exe_path, NULL);
- std::string ret = std::string(real_path);
- free(real_path);
- return ret;
+ if (char *real_path = realpath(exe_path, NULL)) {
+ std::string ret = std::string(real_path);
+ free(real_path);
+ return ret;
+ }
#else
char real_path[MAXPATHLEN];
- realpath(exe_path, real_path);
- return std::string(real_path);
+ if (realpath(exe_path, real_path))
+ return std::string(real_path);
#endif
- } else {
- // Fall back to the classical detection.
- if (getprogpath(exe_path, argv0))
- return exe_path;
}
+ // Fall back to the classical detection.
+ if (getprogpath(exe_path, argv0))
+ return exe_path;
#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
// Use dladdr to get executable path if available.
Dl_info DLInfo;
@@ -246,7 +272,7 @@ uint32_t file_status::getLinkCount() const {
ErrorOr<space_info> disk_space(const Twine &Path) {
struct STATVFS Vfs;
- if (::STATVFS(Path.str().c_str(), &Vfs))
+ if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
return std::error_code(errno, std::generic_category());
auto FrSize = STATVFS_F_FRSIZE(Vfs);
space_info SpaceInfo;
@@ -398,6 +424,9 @@ static bool is_local_impl(struct STATVFS &Vfs) {
#elif defined(__Fuchsia__)
// Fuchsia doesn't yet support remote filesystem mounts.
return true;
+#elif defined(__EMSCRIPTEN__)
+ // Emscripten doesn't currently support remote filesystem mounts.
+ return true;
#elif defined(__HAIKU__)
// Haiku doesn't expose this information.
return false;
@@ -406,6 +435,40 @@ static bool is_local_impl(struct STATVFS &Vfs) {
StringRef fstype(Vfs.f_basetype);
// NFS is the only non-local fstype??
return !fstype.equals("nfs");
+#elif defined(_AIX)
+ // Call mntctl; try more than twice in case of timing issues with a concurrent
+ // mount.
+ int Ret;
+ size_t BufSize = 2048u;
+ std::unique_ptr<char[]> Buf;
+ int Tries = 3;
+ while (Tries--) {
+ Buf = llvm::make_unique<char[]>(BufSize);
+ Ret = mntctl(MCTL_QUERY, BufSize, Buf.get());
+ if (Ret != 0)
+ break;
+ BufSize = *reinterpret_cast<unsigned int *>(Buf.get());
+ Buf.reset();
+ }
+
+ if (Ret == -1)
+ // There was an error; "remote" is the conservative answer.
+ return false;
+
+ // Look for the correct vmount entry.
+ char *CurObjPtr = Buf.get();
+ while (Ret--) {
+ struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr);
+ static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid),
+ "fsid length mismatch");
+ if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0)
+ return (Vp->vmt_flags & MNT_REMOTE) == 0;
+
+ CurObjPtr += Vp->vmt_length;
+ }
+
+ // vmount entry not found; "remote" is the conservative answer.
+ return false;
#else
return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
#endif
@@ -413,7 +476,7 @@ static bool is_local_impl(struct STATVFS &Vfs) {
std::error_code is_local(const Twine &Path, bool &Result) {
struct STATVFS Vfs;
- if (::STATVFS(Path.str().c_str(), &Vfs))
+ if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs))
return std::error_code(errno, std::generic_category());
Result = is_local_impl(Vfs);
@@ -447,7 +510,12 @@ std::error_code resize_file(int FD, uint64_t Size) {
// If we have posix_fallocate use it. Unlike ftruncate it always allocates
// space, so we get an error if the disk is full.
if (int Err = ::posix_fallocate(FD, 0, Size)) {
- if (Err != EINVAL && Err != EOPNOTSUPP)
+#ifdef _AIX
+ constexpr int NotSupportedError = ENOTSUP;
+#else
+ constexpr int NotSupportedError = EOPNOTSUPP;
+#endif
+ if (Err != EINVAL && Err != NotSupportedError)
return std::error_code(Err, std::generic_category());
}
#endif
@@ -626,6 +694,14 @@ std::error_code status(int FD, file_status &Result) {
return fillStatus(StatRet, Status, Result);
}
+unsigned getUmask() {
+ // Chose arbitary new mask and reset the umask to the old mask.
+ // umask(2) never fails so ignore the return of the second call.
+ unsigned Mask = ::umask(0);
+ (void) ::umask(Mask);
+ return Mask;
+}
+
std::error_code setPermissions(const Twine &Path, perms Permissions) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
@@ -635,6 +711,12 @@ std::error_code setPermissions(const Twine &Path, perms Permissions) {
return std::error_code();
}
+std::error_code setPermissions(int FD, perms Permissions) {
+ if (::fchmod(FD, Permissions))
+ return std::error_code(errno, std::generic_category());
+ return std::error_code();
+}
+
std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
TimePoint<> ModificationTime) {
#if defined(HAVE_FUTIMENS)
@@ -722,7 +804,7 @@ const char *mapped_file_region::const_data() const {
}
int mapped_file_region::alignment() {
- return Process::getPageSize();
+ return Process::getPageSizeEstimate();
}
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
@@ -910,9 +992,54 @@ Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
return ResultFD;
}
-void closeFile(file_t &F) {
- ::close(F);
+file_t getStdinHandle() { return 0; }
+file_t getStdoutHandle() { return 1; }
+file_t getStderrHandle() { return 2; }
+
+std::error_code readNativeFile(file_t FD, MutableArrayRef<char> Buf,
+ size_t *BytesRead) {
+ *BytesRead = sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size());
+ if (ssize_t(*BytesRead) == -1)
+ return std::error_code(errno, std::generic_category());
+ return std::error_code();
+}
+
+std::error_code readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf,
+ size_t Offset) {
+ char *BufPtr = Buf.data();
+ size_t BytesLeft = Buf.size();
+
+#ifndef HAVE_PREAD
+ // If we don't have pread, seek to Offset.
+ if (lseek(FD, Offset, SEEK_SET) == -1)
+ return std::error_code(errno, std::generic_category());
+#endif
+
+ while (BytesLeft) {
+#ifdef HAVE_PREAD
+ ssize_t NumRead = sys::RetryAfterSignal(-1, ::pread, FD, BufPtr, BytesLeft,
+ Buf.size() - BytesLeft + Offset);
+#else
+ ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, BufPtr, BytesLeft);
+#endif
+ if (NumRead == -1) {
+ // Error while reading.
+ return std::error_code(errno, std::generic_category());
+ }
+ if (NumRead == 0) {
+ memset(BufPtr, 0, BytesLeft); // zero-initialize rest of the buffer.
+ break;
+ }
+ BytesLeft -= NumRead;
+ BufPtr += NumRead;
+ }
+ return std::error_code();
+}
+
+std::error_code closeFile(file_t &F) {
+ file_t TmpF = F;
F = kInvalidFile;
+ return Process::SafelyCloseFileDescriptor(TmpF);
}
template <typename T>
@@ -1063,5 +1190,37 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
} // end namespace path
+namespace fs {
+
+#ifdef __APPLE__
+/// This implementation tries to perform an APFS CoW clone of the file,
+/// which can be much faster and uses less space.
+/// Unfortunately fcopyfile(3) does not support COPYFILE_CLONE, so the
+/// file descriptor variant of this function still uses the default
+/// implementation.
+std::error_code copy_file(const Twine &From, const Twine &To) {
+ uint32_t Flag = COPYFILE_DATA;
+#if __has_builtin(__builtin_available)
+ if (__builtin_available(macos 10.12, *)) {
+ bool IsSymlink;
+ if (std::error_code Error = is_symlink_file(From, IsSymlink))
+ return Error;
+ // COPYFILE_CLONE clones the symlink instead of following it
+ // and returns EEXISTS if the target file already exists.
+ if (!IsSymlink && !exists(To))
+ Flag = COPYFILE_CLONE;
+ }
+#endif
+ int Status =
+ copyfile(From.str().c_str(), To.str().c_str(), /* State */ NULL, Flag);
+
+ if (Status == 0)
+ return std::error_code();
+ return std::error_code(errno, std::generic_category());
+}
+#endif // __APPLE__
+
+} // end namespace fs
+
} // end namespace sys
} // end namespace llvm