diff options
author | emaste <emaste@FreeBSD.org> | 2013-11-06 16:48:53 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-11-06 16:48:53 +0000 |
commit | c727fe695d28799acb499e9961f11ec07d4f9fe2 (patch) | |
tree | 56d79f94966870db1cecd65a7264510a25fd1cba /source/Plugins/Platform/POSIX/PlatformPOSIX.cpp | |
parent | 2e8c9206a971efee1b77ad2ae852265d6f4ecaa0 (diff) | |
download | FreeBSD-src-c727fe695d28799acb499e9961f11ec07d4f9fe2.zip FreeBSD-src-c727fe695d28799acb499e9961f11ec07d4f9fe2.tar.gz |
Import lldb as of SVN r194122
Sponsored by: DARPA, AFRL
Diffstat (limited to 'source/Plugins/Platform/POSIX/PlatformPOSIX.cpp')
-rw-r--r-- | source/Plugins/Platform/POSIX/PlatformPOSIX.cpp | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp new file mode 100644 index 0000000..34316c4 --- /dev/null +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -0,0 +1,541 @@ +//===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PlatformPOSIX.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/File.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" + +using namespace lldb; +using namespace lldb_private; + + +//------------------------------------------------------------------ +/// Default Constructor +//------------------------------------------------------------------ +PlatformPOSIX::PlatformPOSIX (bool is_host) : +Platform(is_host), // This is the local host platform +m_remote_platform_sp () +{ +} + +//------------------------------------------------------------------ +/// Destructor. +/// +/// The destructor is virtual since this class is designed to be +/// inherited from by the plug-in instance. +//------------------------------------------------------------------ +PlatformPOSIX::~PlatformPOSIX() +{ +} + +lldb_private::OptionGroupOptions* +PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter) +{ + if (m_options.get() == NULL) + { + m_options.reset(new OptionGroupOptions(interpreter)); + m_options->Append(new OptionGroupPlatformRSync()); + m_options->Append(new OptionGroupPlatformSSH()); + m_options->Append(new OptionGroupPlatformCaching()); + } + return m_options.get(); +} + +lldb_private::Error +PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be NULL + const char *working_dir, // Pass NULL to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish +{ + if (IsHost()) + return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); + else + { + if (m_remote_platform_sp) + return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); + else + return Error("unable to run a remote command without a platform"); + } +} + +uint32_t +PlatformPOSIX::MakeDirectory (const std::string &path, + mode_t mode) +{ + if (IsHost()) + { + return Host::MakeDirectory (path.c_str(), mode); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->MakeDirectory(path, mode); + return Platform::MakeDirectory(path,mode); +} + +lldb::user_id_t +PlatformPOSIX::OpenFile (const FileSpec& file_spec, + uint32_t flags, + mode_t mode, + Error &error) +{ + if (IsHost()) + { + return Host::OpenFile(file_spec, flags, mode, error); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); + return Platform::OpenFile(file_spec, flags, mode, error); +} + +bool +PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error) +{ + if (IsHost()) + { + return Host::CloseFile(fd, error); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->CloseFile(fd, error); + return Platform::CloseFile(fd, error); +} + +uint64_t +PlatformPOSIX::ReadFile (lldb::user_id_t fd, + uint64_t offset, + void *dst, + uint64_t dst_len, + Error &error) +{ + if (IsHost()) + { + return Host::ReadFile(fd, offset, dst, dst_len, error); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); + return Platform::ReadFile(fd, offset, dst, dst_len, error); +} + +uint64_t +PlatformPOSIX::WriteFile (lldb::user_id_t fd, + uint64_t offset, + const void* src, + uint64_t src_len, + Error &error) +{ + if (IsHost()) + { + return Host::WriteFile(fd, offset, src, src_len, error); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); + + return Platform::WriteFile(fd, offset, src, src_len, error); +} + +static uint32_t +chown_file(Platform *platform, + const char* path, + uint32_t uid = UINT32_MAX, + uint32_t gid = UINT32_MAX) +{ + if (!platform || !path || *path == 0) + return UINT32_MAX; + + if (uid == UINT32_MAX && gid == UINT32_MAX) + return 0; // pretend I did chown correctly - actually I just didn't care + + StreamString command; + command.PutCString("chown "); + if (uid != UINT32_MAX) + command.Printf("%d",uid); + if (gid != UINT32_MAX) + command.Printf(":%d",gid); + command.Printf("%s",path); + int status; + platform->RunShellCommand(command.GetData(), + NULL, + &status, + NULL, + NULL, + 10); + return status; +} + +lldb_private::Error +PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, + const lldb_private::FileSpec& destination, + uint32_t uid, + uint32_t gid) +{ + if (IsHost()) + { + if (FileSpec::Equal(source, destination, true)) + return Error(); + // cp src dst + // chown uid:gid dst + std::string src_path (source.GetPath()); + if (src_path.empty()) + return Error("unable to get file path for source"); + std::string dst_path (destination.GetPath()); + if (dst_path.empty()) + return Error("unable to get file path for destination"); + StreamString command; + command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); + int status; + RunShellCommand(command.GetData(), + NULL, + &status, + NULL, + NULL, + 10); + if (status != 0) + return Error("unable to perform copy"); + if (uid == UINT32_MAX && gid == UINT32_MAX) + return Error(); + if (chown_file(this,dst_path.c_str(),uid,gid) != 0) + return Error("unable to perform chown"); + return Error(); + } + else if (IsRemote() && m_remote_platform_sp) + { + if (GetSupportsRSync()) + { + std::string src_path (source.GetPath()); + if (src_path.empty()) + return Error("unable to get file path for source"); + std::string dst_path (destination.GetPath()); + if (dst_path.empty()) + return Error("unable to get file path for destination"); + StreamString command; + if (GetIgnoresRemoteHostname()) + { + if (!GetRSyncPrefix()) + command.Printf("rsync %s %s %s", + GetRSyncOpts(), + src_path.c_str(), + dst_path.c_str()); + else + command.Printf("rsync %s %s %s%s", + GetRSyncOpts(), + src_path.c_str(), + GetRSyncPrefix(), + dst_path.c_str()); + } + else + command.Printf("rsync %s %s %s:%s", + GetRSyncOpts(), + src_path.c_str(), + GetHostname(), + dst_path.c_str()); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("[PutFile] Running command: %s\n", command.GetData()); + int retcode; + Host::RunShellCommand(command.GetData(), + NULL, + &retcode, + NULL, + NULL, + 60); + if (retcode == 0) + { + // Don't chown a local file for a remote system +// if (chown_file(this,dst_path.c_str(),uid,gid) != 0) +// return Error("unable to perform chown"); + return Error(); + } + // if we are still here rsync has failed - let's try the slow way before giving up + } + // open + // read, write, read, write, ... + // close + // chown uid:gid dst + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("[PutFile] Using block by block transfer....\n"); + File source_file(source, File::eOpenOptionRead, File::ePermissionsUserRW); + if (!source_file.IsValid()) + return Error("unable to open source file"); + Error error; + lldb::user_id_t dest_file = OpenFile (destination, + File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, + File::ePermissionsUserRWX | File::ePermissionsGroupRX | File::ePermissionsWorldRX, + error); + if (log) + log->Printf ("dest_file = %" PRIu64 "\n", dest_file); + if (error.Fail()) + return error; + if (dest_file == UINT64_MAX) + return Error("unable to open target file"); + lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); + uint64_t offset = 0; + while (error.Success()) + { + size_t bytes_read = buffer_sp->GetByteSize(); + error = source_file.Read(buffer_sp->GetBytes(), bytes_read); + if (bytes_read) + { + WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); + offset += bytes_read; + } + else + break; + } + CloseFile(dest_file, error); + if (uid == UINT32_MAX && gid == UINT32_MAX) + return error; + // This is remopve, don't chown a local file... +// std::string dst_path (destination.GetPath()); +// if (chown_file(this,dst_path.c_str(),uid,gid) != 0) +// return Error("unable to perform chown"); + return error; + } + return Platform::PutFile(source,destination,uid,gid); +} + +lldb::user_id_t +PlatformPOSIX::GetFileSize (const FileSpec& file_spec) +{ + if (IsHost()) + { + return Host::GetFileSize(file_spec); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetFileSize(file_spec); + return Platform::GetFileSize(file_spec); +} + +bool +PlatformPOSIX::GetFileExists (const FileSpec& file_spec) +{ + if (IsHost()) + { + return file_spec.Exists(); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetFileExists(file_spec); + return Platform::GetFileExists(file_spec); +} + +uint32_t +PlatformPOSIX::GetFilePermissions (const lldb_private::FileSpec &file_spec, + lldb_private::Error &error) +{ + if (IsHost()) + { + return File::GetPermissions(file_spec.GetPath().c_str(), error); + } + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetFilePermissions(file_spec, error); + return Platform::GetFilePermissions(file_spec, error); + +} + + +lldb_private::Error +PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */, + const lldb_private::FileSpec& destination /* local file path */) +{ + // Check the args, first. + std::string src_path (source.GetPath()); + if (src_path.empty()) + return Error("unable to get file path for source"); + std::string dst_path (destination.GetPath()); + if (dst_path.empty()) + return Error("unable to get file path for destination"); + if (IsHost()) + { + if (FileSpec::Equal(source, destination, true)) + return Error("local scenario->source and destination are the same file path: no operation performed"); + // cp src dst + StreamString cp_command; + cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); + int status; + RunShellCommand(cp_command.GetData(), + NULL, + &status, + NULL, + NULL, + 10); + if (status != 0) + return Error("unable to perform copy"); + return Error(); + } + else if (IsRemote() && m_remote_platform_sp) + { + if (GetSupportsRSync()) + { + StreamString command; + if (GetIgnoresRemoteHostname()) + { + if (!GetRSyncPrefix()) + command.Printf("rsync %s %s %s", + GetRSyncOpts(), + src_path.c_str(), + dst_path.c_str()); + else + command.Printf("rsync %s %s%s %s", + GetRSyncOpts(), + GetRSyncPrefix(), + src_path.c_str(), + dst_path.c_str()); + } + else + command.Printf("rsync %s %s:%s %s", + GetRSyncOpts(), + m_remote_platform_sp->GetHostname(), + src_path.c_str(), + dst_path.c_str()); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("[GetFile] Running command: %s\n", command.GetData()); + int retcode; + Host::RunShellCommand(command.GetData(), + NULL, + &retcode, + NULL, + NULL, + 60); + if (retcode == 0) + return Error(); + // If we are here, rsync has failed - let's try the slow way before giving up + } + // open src and dst + // read/write, read/write, read/write, ... + // close src + // close dst + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("[GetFile] Using block by block transfer....\n"); + Error error; + user_id_t fd_src = OpenFile (source, + File::eOpenOptionRead, + File::ePermissionsDefault, + error); + + if (fd_src == UINT64_MAX) + return Error("unable to open source file"); + + uint32_t permissions = GetFilePermissions(source, error); + + if (permissions == 0) + permissions = File::ePermissionsDefault; + + user_id_t fd_dst = Host::OpenFile(destination, + File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, + permissions, + error); + + if (fd_dst == UINT64_MAX) + { + if (error.Success()) + error.SetErrorString("unable to open destination file"); + } + + if (error.Success()) + { + lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); + uint64_t offset = 0; + error.Clear(); + while (error.Success()) + { + const uint64_t n_read = ReadFile (fd_src, + offset, + buffer_sp->GetBytes(), + buffer_sp->GetByteSize(), + error); + if (error.Fail()) + break; + if (n_read == 0) + break; + if (Host::WriteFile(fd_dst, + offset, + buffer_sp->GetBytes(), + n_read, + error) != n_read) + { + if (!error.Fail()) + error.SetErrorString("unable to write to destination file"); + break; + } + offset += n_read; + } + } + // Ignore the close error of src. + if (fd_src != UINT64_MAX) + CloseFile(fd_src, error); + // And close the dst file descriptot. + if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error)) + { + if (!error.Fail()) + error.SetErrorString("unable to close destination file"); + + } + return error; + } + return Platform::GetFile(source,destination); +} + +std::string +PlatformPOSIX::GetPlatformSpecificConnectionInformation() +{ + StreamString stream; + if (GetSupportsRSync()) + { + stream.PutCString("rsync"); + if ( (GetRSyncOpts() && *GetRSyncOpts()) || + (GetRSyncPrefix() && *GetRSyncPrefix()) || + GetIgnoresRemoteHostname()) + { + stream.Printf(", options: "); + if (GetRSyncOpts() && *GetRSyncOpts()) + stream.Printf("'%s' ",GetRSyncOpts()); + stream.Printf(", prefix: "); + if (GetRSyncPrefix() && *GetRSyncPrefix()) + stream.Printf("'%s' ",GetRSyncPrefix()); + if (GetIgnoresRemoteHostname()) + stream.Printf("ignore remote-hostname "); + } + } + if (GetSupportsSSH()) + { + stream.PutCString("ssh"); + if (GetSSHOpts() && *GetSSHOpts()) + stream.Printf(", options: '%s' ",GetSSHOpts()); + } + if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) + stream.Printf("cache dir: %s",GetLocalCacheDirectory()); + if (stream.GetSize()) + return stream.GetData(); + else + return ""; +} + +bool +PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec, + uint64_t &low, + uint64_t &high) +{ + if (IsHost()) + return Platform::CalculateMD5 (file_spec, low, high); + if (m_remote_platform_sp) + return m_remote_platform_sp->CalculateMD5(file_spec, low, high); + return false; +} |