diff --git a/lldb/include/lldb/Host/FileSystem.h b/lldb/include/lldb/Host/FileSystem.h index ffcb20b0247f..c3ed4f7d7152 100644 --- a/lldb/include/lldb/Host/FileSystem.h +++ b/lldb/include/lldb/Host/FileSystem.h @@ -26,15 +26,30 @@ public: static const char *DEV_NULL; static const char *PATH_CONVERSION_ERROR; + static FileSpec::PathSyntax GetNativePathSyntax(); + + static lldb::user_id_t GetFileSize(const FileSpec &file_spec); + static bool GetFileExists(const FileSpec &file_spec); + + static Error Hardlink(const FileSpec &src, const FileSpec &dst); + static int GetHardlinkCount(const FileSpec &file_spec); static Error Symlink(const FileSpec &src, const FileSpec &dst); static Error Readlink(const FileSpec &src, FileSpec &dst); + static Error Unlink(const FileSpec &file_spec); static Error ResolveSymbolicLink(const FileSpec &src, FileSpec &dst); + /// Return \b true if \a spec is on a locally mounted file system, \b false + /// otherwise. + static bool IsLocal(const FileSpec &spec); + /// Wraps ::fopen in a platform-independent way. Once opened, FILEs can be /// manipulated and closed with the normal ::fread, ::fclose, etc. functions. static FILE *Fopen(const char *path, const char *mode); + /// Wraps ::stat in a platform-independent way. + static int Stat(const char *path, struct stat *stats); + static llvm::sys::TimePoint<> GetModificationTime(const FileSpec &file_spec); }; } diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index 36a931126b46..d7bb8582df61 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -24,11 +24,11 @@ #endif #include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors() #include "lldb/Host/Config.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Error.h" #include "lldb/Utility/Log.h" @@ -249,12 +249,14 @@ Error File::Open(const char *path, uint32_t options, uint32_t permissions) { uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) { if (file_spec) { - error.Clear(); - auto Perms = llvm::sys::fs::getPermissions(file_spec.GetPath()); - if (Perms) - return *Perms; - error = Error(Perms.getError()); - return 0; + struct stat file_stats; + int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats); + if (stat_result == -1) + error.SetErrorToErrno(); + else { + error.Clear(); + return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } } else error.SetErrorString("empty file spec"); return 0; diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 649b2c96c2f2..5d254ec05611 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -51,6 +51,7 @@ #include "lldb/Core/ArchSpec.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostProcess.h" @@ -597,7 +598,8 @@ Error Host::RunShellCommand(const Args &args, const FileSpec &working_dir, } } - llvm::sys::fs::remove(output_file_spec.GetPath()); + if (FileSystem::GetFileExists(output_file_spec)) + FileSystem::Unlink(output_file_spec); return error; } diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm index bf39ae1adbf7..700bce93c6d5 100644 --- a/lldb/source/Host/macosx/Host.mm +++ b/lldb/source/Host/macosx/Host.mm @@ -62,6 +62,7 @@ #include "lldb/Core/StructuredData.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Target/Platform.h" @@ -529,7 +530,7 @@ LaunchInNewTerminalWithAppleScript(const char *exe_path, WaitForProcessToSIGSTOP(pid, 5); } - llvm::sys::fs::remove(unix_socket_name.GetPath()); + FileSystem::Unlink(FileSpec{unix_socket_name, false}); [applescript release]; if (pid != LLDB_INVALID_PROCESS_ID) launch_info.SetProcessID(pid); diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 538979df2b6b..cb0a1d057506 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -9,7 +9,7 @@ #include "lldb/Host/posix/DomainSocket.h" -#include "llvm/Support/FileSystem.h" +#include "lldb/Host/FileSystem.h" #include #include @@ -116,5 +116,5 @@ Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, size_t DomainSocket::GetNameOffset() const { return 0; } void DomainSocket::DeleteSocketFile(llvm::StringRef name) { - llvm::sys::fs::remove(name); + FileSystem::Unlink(FileSpec{name, true}); } diff --git a/lldb/source/Host/posix/FileSystem.cpp b/lldb/source/Host/posix/FileSystem.cpp index 22f337fcfec5..4c21fcd34a05 100644 --- a/lldb/source/Host/posix/FileSystem.cpp +++ b/lldb/source/Host/posix/FileSystem.cpp @@ -36,6 +36,33 @@ using namespace lldb_private; const char *FileSystem::DEV_NULL = "/dev/null"; +FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { + return FileSpec::ePathSyntaxPosix; +} + +lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) { + return file_spec.GetByteSize(); +} + +bool FileSystem::GetFileExists(const FileSpec &file_spec) { + return file_spec.Exists(); +} + +Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { + Error error; + if (::link(dst.GetCString(), src.GetCString()) == -1) + error.SetErrorToErrno(); + return error; +} + +int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { + struct stat file_stat; + if (::stat(file_spec.GetCString(), &file_stat) == 0) + return file_stat.st_nlink; + + return -1; +} + Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { Error error; if (::symlink(dst.GetCString(), src.GetCString()) == -1) @@ -43,6 +70,13 @@ Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { return error; } +Error FileSystem::Unlink(const FileSpec &file_spec) { + Error error; + if (::unlink(file_spec.GetCString()) == -1) + error.SetErrorToErrno(); + return error; +} + Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { Error error; char buf[PATH_MAX]; @@ -74,6 +108,50 @@ Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { return Error(); } +#if defined(__NetBSD__) +static bool IsLocal(const struct statvfs &info) { + return (info.f_flag & MNT_LOCAL) != 0; +} +#else +static bool IsLocal(const struct statfs &info) { +#ifdef __linux__ +#define CIFS_MAGIC_NUMBER 0xFF534D42 + switch ((uint32_t)info.f_type) { + case NFS_SUPER_MAGIC: + case SMB_SUPER_MAGIC: + case CIFS_MAGIC_NUMBER: + return false; + default: + return true; + } +#else + return (info.f_flags & MNT_LOCAL) != 0; +#endif +} +#endif + +#if defined(__NetBSD__) +bool FileSystem::IsLocal(const FileSpec &spec) { + struct statvfs statfs_info; + std::string path(spec.GetPath()); + if (statvfs(path.c_str(), &statfs_info) == 0) + return ::IsLocal(statfs_info); + return false; +} +#else +bool FileSystem::IsLocal(const FileSpec &spec) { + struct statfs statfs_info; + std::string path(spec.GetPath()); + if (statfs(path.c_str(), &statfs_info) == 0) + return ::IsLocal(statfs_info); + return false; +} +#endif + FILE *FileSystem::Fopen(const char *path, const char *mode) { return ::fopen(path, mode); } + +int FileSystem::Stat(const char *path, struct stat *stats) { + return ::stat(path, stats); +} diff --git a/lldb/source/Host/posix/PipePosix.cpp b/lldb/source/Host/posix/PipePosix.cpp index 3ac5d480de89..4e0810c1a9b3 100644 --- a/lldb/source/Host/posix/PipePosix.cpp +++ b/lldb/source/Host/posix/PipePosix.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/posix/PipePosix.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/SelectHelper.h" #include "llvm/ADT/SmallString.h" @@ -230,7 +231,7 @@ void PipePosix::Close() { } Error PipePosix::Delete(llvm::StringRef name) { - return llvm::sys::fs::remove(name); + return FileSystem::Unlink(FileSpec{name.data(), true}); } bool PipePosix::CanRead() const { diff --git a/lldb/source/Host/windows/FileSystem.cpp b/lldb/source/Host/windows/FileSystem.cpp index 907c0c9337a0..e834c85a28cb 100644 --- a/lldb/source/Host/windows/FileSystem.cpp +++ b/lldb/source/Host/windows/FileSystem.cpp @@ -26,6 +26,49 @@ const char *FileSystem::DEV_NULL = "nul"; const char *FileSystem::PATH_CONVERSION_ERROR = "Error converting path between UTF-8 and native encoding"; +FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { + return FileSpec::ePathSyntaxWindows; +} + +lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) { + return file_spec.GetByteSize(); +} + +bool FileSystem::GetFileExists(const FileSpec &file_spec) { + return file_spec.Exists(); +} + +Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { + Error error; + std::wstring wsrc, wdst; + if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || + !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) + error.SetErrorString(PATH_CONVERSION_ERROR); + else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr)) + error.SetError(::GetLastError(), lldb::eErrorTypeWin32); + return error; +} + +int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { + std::wstring path; + if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) + return -1; + + HANDLE file_handle = + ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, + nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + + if (file_handle == INVALID_HANDLE_VALUE) + return -1; + + AutoHandle auto_file_handle(file_handle); + BY_HANDLE_FILE_INFORMATION file_info; + if (::GetFileInformationByHandle(file_handle, &file_info)) + return file_info.nNumberOfLinks; + + return -1; +} + Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { Error error; std::wstring wsrc, wdst; @@ -47,6 +90,19 @@ Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { return error; } +Error FileSystem::Unlink(const FileSpec &file_spec) { + Error error; + std::wstring path; + if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) { + error.SetErrorString(PATH_CONVERSION_ERROR); + return error; + } + BOOL result = ::DeleteFileW(path.c_str()); + if (!result) + error.SetError(::GetLastError(), lldb::eErrorTypeWin32); + return error; +} + Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { Error error; std::wstring wsrc; @@ -84,6 +140,15 @@ Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { return Error("ResolveSymbolicLink() isn't implemented on Windows"); } +bool FileSystem::IsLocal(const FileSpec &spec) { + if (spec) { + // TODO: return true if the file is on a locally mounted file system + return true; + } + + return false; +} + FILE *FileSystem::Fopen(const char *path, const char *mode) { std::wstring wpath, wmode; if (!llvm::ConvertUTF8toWide(path, wpath)) @@ -95,3 +160,25 @@ FILE *FileSystem::Fopen(const char *path, const char *mode) { return nullptr; return file; } + +int FileSystem::Stat(const char *path, struct stat *stats) { + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(path, wpath)) { + errno = EINVAL; + return -EINVAL; + } + int stat_result; +#ifdef _USE_32BIT_TIME_T + struct _stat32 file_stats; + stat_result = ::_wstat32(wpath.c_str(), &file_stats); +#else + struct _stat64i32 file_stats; + stat_result = ::_wstat64i32(wpath.c_str(), &file_stats); +#endif + if (stat_result == 0) { + static_assert(sizeof(struct stat) == sizeof(file_stats), + "stat and _stat32/_stat64i32 must have the same layout"); + *stats = *reinterpret_cast(&file_stats); + } + return stat_result; +} diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index c6ce3efc8ccc..fe1b1056da11 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -435,12 +435,9 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, } lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) { - if (IsHost()) { - uint64_t Size; - if (llvm::sys::fs::file_size(file_spec.GetPath(), Size)) - return 0; - return Size; - } else if (m_remote_platform_sp) + if (IsHost()) + return FileSystem::GetFileSize(file_spec); + else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileSize(file_spec); else return Platform::GetFileSize(file_spec); @@ -466,7 +463,7 @@ bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) { Error PlatformPOSIX::Unlink(const FileSpec &file_spec) { if (IsHost()) - return llvm::sys::fs::remove(file_spec.GetPath()); + return FileSystem::Unlink(file_spec); else if (m_remote_platform_sp) return m_remote_platform_sp->Unlink(file_spec); else diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 5b20713f18f5..758ece5b85ea 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -642,15 +642,14 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Size( std::string path; packet.GetHexByteString(path); if (!path.empty()) { - uint64_t Size; - if (llvm::sys::fs::file_size(path, Size)) - return SendErrorResponse(5); + lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path, false)); StreamString response; response.PutChar('F'); - response.PutHex64(Size); - if (Size == UINT64_MAX) { + response.PutHex64(retcode); + if (retcode == UINT64_MAX) { response.PutChar(','); - response.PutHex64(Size); // TODO: replace with Host::GetSyswideErrorCode() + response.PutHex64( + retcode); // TODO: replace with Host::GetSyswideErrorCode() } return SendPacketNoLock(response.GetString()); } @@ -682,7 +681,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Exists( std::string path; packet.GetHexByteString(path); if (!path.empty()) { - bool retcode = llvm::sys::fs::exists(path); + bool retcode = FileSystem::GetFileExists(FileSpec(path, false)); StreamString response; response.PutChar('F'); response.PutChar(','); @@ -715,7 +714,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_unlink( packet.SetFilePos(::strlen("vFile:unlink:")); std::string path; packet.GetHexByteString(path); - Error error(llvm::sys::fs::remove(path)); + Error error = FileSystem::Unlink(FileSpec{path, true}); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetString()); diff --git a/lldb/source/Target/ModuleCache.cpp b/lldb/source/Target/ModuleCache.cpp index a4aa26a0e480..b35e2d79b20e 100644 --- a/lldb/source/Target/ModuleCache.cpp +++ b/lldb/source/Target/ModuleCache.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/LockFile.h" #include "lldb/Utility/Log.h" #include "llvm/Support/FileSystem.h" @@ -100,12 +101,11 @@ void DeleteExistingModule(const FileSpec &root_dir_spec, module_uuid.GetAsString().c_str(), error.AsCString()); } - namespace fs = llvm::sys::fs; - fs::file_status st; - if (status(sysroot_module_path_spec.GetPath(), st)) + auto link_count = FileSystem::GetHardlinkCount(sysroot_module_path_spec); + if (link_count == -1) return; - if (st.getLinkCount() > 2) // module is referred by other hosts. + if (link_count > 2) // module is referred by other hosts. return; const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid); @@ -119,10 +119,11 @@ void DecrementRefExistingModule(const FileSpec &root_dir_spec, DeleteExistingModule(root_dir_spec, sysroot_module_path_spec); // Remove sysroot link. - llvm::sys::fs::remove(sysroot_module_path_spec.GetPath()); + FileSystem::Unlink(sysroot_module_path_spec); FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec); - llvm::sys::fs::remove(symfile_spec.GetPath()); + if (symfile_spec.Exists()) // delete module's symbol file if exists. + FileSystem::Unlink(symfile_spec); } Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec, @@ -145,8 +146,7 @@ Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec, if (error.Fail()) return error; - return llvm::sys::fs::create_hard_link(local_module_spec.GetPath(), - sysroot_module_path_spec.GetPath()); + return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec); } } // namespace @@ -179,7 +179,7 @@ void ModuleLock::Delete() { return; m_file.Close(); - llvm::sys::fs::remove(m_file_spec.GetPath()); + FileSystem::Unlink(m_file_spec); } ///////////////////////////////////////////////////////////////////////// diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index acafa8b35c59..ac8a168b93e5 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -696,7 +696,8 @@ Error Platform::Install(const FileSpec &src, const FileSpec &dst) { namespace fs = llvm::sys::fs; switch (fs::get_file_type(src.GetPath(), false)) { case fs::file_type::directory_file: { - llvm::sys::fs::remove(fixed_dst.GetPath()); + if (GetFileExists(fixed_dst)) + Unlink(fixed_dst); uint32_t permissions = src.GetPermissions(); if (permissions == 0) permissions = eFilePermissionsDirectoryDefault; @@ -715,12 +716,14 @@ Error Platform::Install(const FileSpec &src, const FileSpec &dst) { } break; case fs::file_type::regular_file: - llvm::sys::fs::remove(fixed_dst.GetPath()); + if (GetFileExists(fixed_dst)) + Unlink(fixed_dst); error = PutFile(src, fixed_dst); break; case fs::file_type::symlink_file: { - llvm::sys::fs::remove(fixed_dst.GetPath()); + if (GetFileExists(fixed_dst)) + Unlink(fixed_dst); FileSpec src_resolved; error = FileSystem::Readlink(src, src_resolved); if (error.Success())