Skip to content

Commit

Permalink
translation/Protocol: add packet SYMLINK
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKellermann committed Feb 5, 2025
1 parent 5d16007 commit eade21e
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/spawn/Client.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ Serialize(SpawnSerializer &s, const NamespaceOptions &ns)
s.WriteString(i.source);
s.WriteBool(i.optional);
break;

case Mount::Type::SYMLINK:
s.WriteString(SpawnExecCommand::SYMLINK, i.target);
s.WriteString(i.source);
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/spawn/IProtocol.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum class SpawnExecCommand : uint8_t {
FD_BIND_MOUNT,
FD_BIND_MOUNT_FILE,
WRITE_FILE,
SYMLINK,
DIR_MODE,
HOSTNAME,
RLIMIT,
Expand Down
25 changes: 25 additions & 0 deletions src/spawn/Mount.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,19 @@ Mount::ApplyWriteFile(VfsBuilder &vfs_builder) const
}
}

inline void
Mount::ApplySymlink(VfsBuilder &vfs_builder) const
{
assert(type == Type::SYMLINK);
assert(source != nullptr);
assert(target != nullptr);

vfs_builder.Add(DirName(target));

if (symlink(source, target) < 0)
throw FmtErrno("Failed to create symlink {:?}", target);
}

inline void
Mount::Apply(VfsBuilder &vfs_builder) const
{
Expand All @@ -353,6 +366,10 @@ Mount::Apply(VfsBuilder &vfs_builder) const
case Type::WRITE_FILE:
ApplyWriteFile(vfs_builder);
break;

case Type::SYMLINK:
ApplySymlink(vfs_builder);
break;
}
}

Expand Down Expand Up @@ -397,6 +414,14 @@ Mount::MakeId(char *p) const noexcept
p = stpcpy(p, source);
*p++ = ';';
return p;

case Type::SYMLINK:
p = (char *)mempcpy(p, ";sy:", 4);
p = stpcpy(p, target);
*p++ = '>';
p = stpcpy(p, source);
*p++ = ';';
return p;
}

if (writable)
Expand Down
8 changes: 8 additions & 0 deletions src/spawn/Mount.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ struct Mount : IntrusiveForwardListHook {
* regular file).
*/
WRITE_FILE,

/**
* Create a symlink. #source is the symlink target,
* #target is the link path. Sorry for the confusing
* nomenclature!
*/
SYMLINK,
} type = Type::BIND;

#if TRANSLATION_ENABLE_EXPAND
Expand Down Expand Up @@ -147,6 +154,7 @@ private:
void ApplyTmpfs(VfsBuilder &vfs_builder) const;
void ApplyNamedTmpfs(VfsBuilder &vfs_builder) const;
void ApplyWriteFile(VfsBuilder &vfs_builder) const;
void ApplySymlink(VfsBuilder &vfs_builder) const;

public:
/**
Expand Down
12 changes: 12 additions & 0 deletions src/spawn/Server.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,18 @@ SpawnServerConnection::HandleExecMessage(SpawnPayload payload,
mounts.front());
break;

case SpawnExecCommand::SYMLINK:
{
const char *target = payload.ReadString();
const char *source = payload.ReadString();
mounts.emplace_front(source, target);
mounts.front().type = Mount::Type::SYMLINK;
}

mount_tail = p.ns.mount.mounts.insert_after(mount_tail,
mounts.front());
break;

case SpawnExecCommand::DIR_MODE:
payload.ReadT(p.ns.mount.dir_mode);
break;
Expand Down
25 changes: 25 additions & 0 deletions src/translation/Parser.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,22 @@ TranslateParser::HandleBindMount(std::string_view payload,
mount_list = ns_options->mount.mounts.insert_after(mount_list, *m);
}

inline void
TranslateParser::HandleSymlink(std::string_view payload)
{
const auto [target, linkpath] = Split(payload, '\0');
if (!IsValidNonEmptyString(target) ||
!IsValidAbsolutePath(linkpath))
throw std::runtime_error("malformed SYMLINK packet");

if (ns_options == nullptr)
throw std::runtime_error("misplaced SYMLINK packet");

auto *m = alloc.New<Mount>(target.data(), linkpath.data());
m->type = Mount::Type::SYMLINK;
mount_list = ns_options->mount.mounts.insert_after(mount_list, *m);
}

inline void
TranslateParser::HandleWriteFile(std::string_view payload)
{
Expand Down Expand Up @@ -4375,6 +4391,15 @@ TranslateParser::HandleRegularPacket(TranslationCommand command,
#else
break;
#endif

case TranslationCommand::SYMLINK:
#if TRANSLATION_ENABLE_SPAWN
previous_command = command;
HandleSymlink(string_payload);
return;
#else
break;
#endif
}

throw FmtRuntimeError("unknown translation packet: {}", (unsigned)command);
Expand Down
2 changes: 2 additions & 0 deletions src/translation/Parser.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ private:
bool expand, bool writable, bool exec=false,
bool file=false);

void HandleSymlink(std::string_view payload);

void HandleWriteFile(std::string_view payload);
#endif // TRANSLATION_ENABLE_SPAWN

Expand Down
6 changes: 6 additions & 0 deletions src/translation/Protocol.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,12 @@ enum class TranslationCommand : uint16_t {
* only "executable", but not "readable".
*/
TMPFS_DIRS_READABLE = 268,

/**
* Create a symlink. Payload is target and linkpath separated
* by a null byte.
*/
SYMLINK = 269,
};

struct TranslationHeader {
Expand Down
9 changes: 9 additions & 0 deletions src/translation/server/Response.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,15 @@ public:
return *this;
}

template<typename T, typename L>
auto Symlink(T &&target, L &&linkpath) noexcept {
response.StringPacket(TranslationCommand::SYMLINK,
std::forward<T>(target),
std::string_view{"", 1},
std::forward<L>(linkpath));
return *this;
}

auto Optional() noexcept {
response.Optional();
return *this;
Expand Down

0 comments on commit eade21e

Please sign in to comment.