Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Headers/DebugServer2/GDBRemote/Mixins/FileOperationsMixin.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ template <typename T> class FileOperationsMixin : public T {
explicit FileOperationsMixin(Args &&... args)
: T(std::forward<Args>(args)...) {}

private:
// vFile paths are frequently relative (e.g. a bare filename an inferior
// writes into its own working directory); unlike qPlatform_shell, the
// vFile packets carry no separate working-directory field, so ds2 has to
// apply the platform session's own configured working directory itself.
// This has to stay session-local rather than mutating ds2's actual
// process cwd: platform mode serves each connected client on its own
// thread with its own session (see PlatformMain in Sources/main.cpp), and
// the process cwd is shared state across all of them.
std::string resolvePath(Session &session, std::string const &path) const;

protected:
ErrorCode onFileOpen(Session &session, std::string const &path,
OpenFlags flags, uint32_t mode, int &fd) override;
Expand Down
40 changes: 30 additions & 10 deletions Sources/GDBRemote/Mixins/FileOperationsMixin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "DebugServer2/GDBRemote/Mixins/FileOperationsMixin.h"
#include "DebugServer2/Host/Platform.h"

#include <filesystem>
#include <iomanip>
#include <sstream>

Expand All @@ -23,12 +24,30 @@ namespace ds2 {
namespace GDBRemote {

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileOpen(Session &, std::string const &path,
std::string FileOperationsMixin<T>::resolvePath(Session &session,
std::string const &path) const {
if (std::filesystem::path(path).is_absolute()) {
return path;
}

std::string workingDirectory;
if (this->onQueryWorkingDirectory(session, workingDirectory) != kSuccess ||
workingDirectory.empty()) {
return path;
}

// onSetWorkingDirectory canonicalizes to an absolute path before storing
// it, so this join always yields an absolute result.
return (std::filesystem::path(workingDirectory) / path).string();
}

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileOpen(Session &session, std::string const &path,
OpenFlags flags, uint32_t mode,
int &fd) {
static int fileIdx = 0;

Host::File file(path, flags, mode);
Host::File file(resolvePath(session, path), flags, mode);
if (!file.valid()) {
return file.lastError();
}
Expand Down Expand Up @@ -76,29 +95,30 @@ ErrorCode FileOperationsMixin<T>::onFileWrite(Session &session, int fd,
}

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileCreateDirectory(Session &,
ErrorCode FileOperationsMixin<T>::onFileCreateDirectory(Session &session,
std::string const &path,
uint32_t flags) {
return Host::File::createDirectory(path, flags);
return Host::File::createDirectory(resolvePath(session, path), flags);
}

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileExists(Session &,
ErrorCode FileOperationsMixin<T>::onFileExists(Session &session,
std::string const &path) {
return Host::Platform::IsFilePresent(path) ? kSuccess : kErrorNotFound;
return Host::Platform::IsFilePresent(resolvePath(session, path)) ? kSuccess
: kErrorNotFound;
}

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileGetSize(Session &session, std::string const &path,
uint64_t &size){
return Host::File::fileSize(path, size);
return Host::File::fileSize(resolvePath(session, path), size);
}

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileGetMode(Session &session,
std::string const &path,
uint32_t &mode) const {
return Host::File::fileMode(path, mode);
return Host::File::fileMode(resolvePath(session, path), mode);
}

template <typename T>
Expand All @@ -114,14 +134,14 @@ ErrorCode FileOperationsMixin<T>::onFileFstat(Session &session, int fd,
template <typename T>
ErrorCode FileOperationsMixin<T>::onFileRemove(Session &session,
std::string const &path) {
return Host::File::unlink(path);
return Host::File::unlink(resolvePath(session, path));
}

template <typename T>
ErrorCode FileOperationsMixin<T>::onFileSetPermissions(Session &session,
std::string const &path,
uint32_t mode) {
return Host::File::chmod(path, mode);
return Host::File::chmod(resolvePath(session, path), mode);
}

template <typename T>
Expand Down
19 changes: 18 additions & 1 deletion Sources/GDBRemote/Mixins/ProcessLaunchMixin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "DebugServer2/GDBRemote/Mixins/ProcessLaunchMixin.h"

#include <algorithm>
#include <filesystem>

namespace ds2 {
namespace GDBRemote {
Expand All @@ -35,7 +36,23 @@ template <typename T>
ErrorCode
ProcessLaunchMixin<T>::onSetWorkingDirectory(Session &,
std::string const &path) {
_workingDirectory = path;
// ds2 serves each platform client on its own thread with its own session
// (see PlatformMain in Sources/main.cpp), so the working directory has to
// stay session-local state rather than ds2's actual process cwd, which is
// shared by every concurrently-connected client.
//
// Canonicalize to an absolute path here, once, rather than storing
// whatever the client sent verbatim: a relative path only means
// something relative to ds2's own starting directory (there is nothing
// else for it to be relative to, since ds2's cwd never changes), and
// resolving it eagerly means every later consumer of _workingDirectory
// (vFile path resolution, ProcessSpawner) can treat it as absolute
// without redoing this resolution or applying it a second time.
std::filesystem::path resolved(path);
if (!resolved.is_absolute())
resolved = std::filesystem::path(Platform::GetWorkingDirectory()) / resolved;

_workingDirectory = resolved.string();
return kSuccess;
}

Expand Down
Loading