diff options
author | Zachary Turner <zturner@google.com> | 2017-02-21 20:55:47 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2017-02-21 20:55:47 +0000 |
commit | 392ed9d342229b95d77a5ec6310e10093f73e75c (patch) | |
tree | 2b223846e02b9c38cebf8b5b61092040cc73bf3a /llvm/lib/Support | |
parent | ccee0e0c055327d202e48b5dfeb06cb3716e49d0 (diff) | |
download | bcm5719-llvm-392ed9d342229b95d77a5ec6310e10093f73e75c.tar.gz bcm5719-llvm-392ed9d342229b95d77a5ec6310e10093f73e75c.zip |
[Support] Add a function to check if a file resides locally.
Differential Revision: https://reviews.llvm.org/D30010
llvm-svn: 295768
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r-- | llvm/lib/Support/MemoryBuffer.cpp | 34 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Path.inc | 66 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Path.inc | 74 |
3 files changed, 153 insertions, 21 deletions
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp index a3a18c9283c..227e792d83d 100644 --- a/llvm/lib/Support/MemoryBuffer.cpp +++ b/llvm/lib/Support/MemoryBuffer.cpp @@ -103,7 +103,7 @@ public: static ErrorOr<std::unique_ptr<MemoryBuffer>> getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, - uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize); + uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile); std::unique_ptr<MemoryBuffer> MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, @@ -178,8 +178,8 @@ MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize, ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, - uint64_t Offset) { - return getFileAux(FilePath, -1, MapSize, Offset, false, false); + uint64_t Offset, bool IsVolatile) { + return getFileAux(FilePath, -1, MapSize, Offset, false, IsVolatile); } @@ -254,19 +254,19 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) { ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, - bool RequiresNullTerminator, bool IsVolatileSize) { + bool RequiresNullTerminator, bool IsVolatile) { return getFileAux(Filename, FileSize, FileSize, 0, - RequiresNullTerminator, IsVolatileSize); + RequiresNullTerminator, IsVolatile); } static ErrorOr<std::unique_ptr<MemoryBuffer>> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, - bool IsVolatileSize); + bool IsVolatile); static ErrorOr<std::unique_ptr<MemoryBuffer>> getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, - uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize) { + uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { int FD; std::error_code EC = sys::fs::openFileForRead(Filename, FD); if (EC) @@ -274,7 +274,7 @@ getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset, - RequiresNullTerminator, IsVolatileSize); + RequiresNullTerminator, IsVolatile); close(FD); return Ret; } @@ -285,11 +285,11 @@ static bool shouldUseMmap(int FD, off_t Offset, bool RequiresNullTerminator, int PageSize, - bool IsVolatileSize) { + bool IsVolatile) { // mmap may leave the buffer without null terminator if the file size changed // by the time the last page is mapped in, so avoid it if the file size is // likely to change. - if (IsVolatileSize) + if (IsVolatile) return false; // We don't use mmap for small files because this can severely fragment our @@ -300,7 +300,6 @@ static bool shouldUseMmap(int FD, if (!RequiresNullTerminator) return true; - // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. // FIXME: this chunk of code is duplicated, but it avoids a fstat when @@ -338,7 +337,7 @@ static bool shouldUseMmap(int FD, static ErrorOr<std::unique_ptr<MemoryBuffer>> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, - bool IsVolatileSize) { + bool IsVolatile) { static int PageSize = sys::Process::getPageSize(); // Default is to map the full file. @@ -365,7 +364,7 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, } if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, - PageSize, IsVolatileSize)) { + PageSize, IsVolatile)) { std::error_code EC; std::unique_ptr<MemoryBuffer> Result( new (NamedBufferAlloc(Filename)) @@ -415,17 +414,16 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, - bool RequiresNullTerminator, bool IsVolatileSize) { + bool RequiresNullTerminator, bool IsVolatile) { return getOpenFileImpl(FD, Filename, FileSize, FileSize, 0, - RequiresNullTerminator, IsVolatileSize); + RequiresNullTerminator, IsVolatile); } ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize, - int64_t Offset) { + int64_t Offset, bool IsVolatile) { assert(MapSize != uint64_t(-1)); - return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, - /*IsVolatileSize*/ false); + return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, IsVolatile); } ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index 10e21af5371..94cb6817e40 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -65,23 +65,32 @@ #endif #include <sys/types.h> -#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) +#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \ + !defined(__linux__) #include <sys/statvfs.h> #define STATVFS statvfs +#define FSTATVFS fstatvfs #define STATVFS_F_FRSIZE(vfs) vfs.f_frsize #else -#ifdef __OpenBSD__ +#if defined(__OpenBSD__) || defined(__FreeBSD__) #include <sys/param.h> #include <sys/mount.h> -#elif defined(__ANDROID__) +#elif defined(__linux__) +#include <linux/magic.h> #include <sys/vfs.h> #else #include <sys/mount.h> #endif #define STATVFS statfs +#define FSTATVFS fstatfs #define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize) #endif +#if defined(__NetBSD__) +#define STATVFS_F_FLAG(vfs) (vfs).f_flag +#else +#define STATVFS_F_FLAG(vfs) (vfs).f_flags +#endif using namespace llvm; @@ -335,6 +344,40 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { return std::error_code(); } +static bool is_local_impl(struct STATVFS &Vfs) { +#if defined(__linux__) + constexpr uint32_t CIFS_MAGIC_NUMBER = 0xFF534D42; + switch ((uint32_t)Vfs.f_type) { + case NFS_SUPER_MAGIC: + case SMB_SUPER_MAGIC: + case CIFS_MAGIC_NUMBER: + return false; + default: + return true; + } +#else + return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL); +#endif +} + +std::error_code is_local(const Twine &Path, bool &Result) { + struct STATVFS Vfs; + if (::STATVFS(Path.str().c_str(), &Vfs)) + return std::error_code(errno, std::generic_category()); + + Result = is_local_impl(Vfs); + return std::error_code(); +} + +std::error_code is_local(int FD, bool &Result) { + struct STATVFS Vfs; + if (::FSTATVFS(FD, &Vfs)) + return std::error_code(errno, std::generic_category()); + + Result = is_local_impl(Vfs); + return std::error_code(); +} + std::error_code rename(const Twine &from, const Twine &to) { // Get arguments. SmallString<128> from_storage; @@ -491,6 +534,23 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); +#if defined(__APPLE__) +//---------------------------------------------------------------------- +// Newer versions of MacOSX have a flag that will allow us to read from +// binaries whose code signature is invalid without crashing by using +// the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media +// is mapped we can avoid crashing and return zeroes to any pages we try +// to read if the media becomes unavailable by using the +// MAP_RESILIENT_MEDIA flag. +//---------------------------------------------------------------------- +#if defined(MAP_RESILIENT_CODESIGN) + flags |= MAP_RESILIENT_CODESIGN; +#endif +#if defined(MAP_RESILIENT_MEDIA) + flags |= MAP_RESILIENT_MEDIA; +#endif +#endif // #if defined (__APPLE__) + Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset); if (Mapping == MAP_FAILED) return std::error_code(errno, std::generic_category()); diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index 3597b551098..d9e1ff4ffe4 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -277,6 +277,80 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { return std::error_code(); } +static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, + bool &Result) { + SmallVector<wchar_t, 128> VolumePath; + size_t Len = 128; + while (true) { + VolumePath.resize(Len); + BOOL Success = + ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); + + if (Success) + break; + + DWORD Err = ::GetLastError(); + if (Err != ERROR_INSUFFICIENT_BUFFER) + return mapWindowsError(Err); + + Len *= 2; + } + // If the output buffer has exactly enough space for the path name, but not + // the null terminator, it will leave the output unterminated. Push a null + // terminator onto the end to ensure that this never happens. + VolumePath.push_back(L'\0'); + VolumePath.set_size(wcslen(VolumePath.data())); + const wchar_t *P = VolumePath.data(); + + UINT Type = ::GetDriveTypeW(P); + switch (Type) { + case DRIVE_FIXED: + Result = true; + return std::error_code(); + case DRIVE_REMOTE: + case DRIVE_CDROM: + case DRIVE_RAMDISK: + case DRIVE_REMOVABLE: + Result = false; + return std::error_code(); + default: + return make_error_code(errc::no_such_file_or_directory); + } + llvm_unreachable("Unreachable!"); +} + +std::error_code is_local(const Twine &path, bool &result) { + if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) + return make_error_code(errc::no_such_file_or_directory); + + SmallString<128> Storage; + StringRef P = path.toStringRef(Storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> WidePath; + if (std::error_code ec = widenPath(P, WidePath)) + return ec; + return is_local_internal(WidePath, result); +} + +std::error_code is_local(int FD, bool &Result) { + SmallVector<wchar_t, 128> FinalPath; + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + + size_t Len = 128; + do { + FinalPath.reserve(Len); + Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(), + FinalPath.capacity() - 1, VOLUME_NAME_NT); + if (Len == 0) + return mapWindowsError(::GetLastError()); + } while (Len > FinalPath.capacity()); + + FinalPath.set_size(Len); + + return is_local_internal(FinalPath, Result); +} + std::error_code rename(const Twine &from, const Twine &to) { // Convert to utf-16. SmallVector<wchar_t, 128> wide_from; |