summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/buildtool/file_system/TARGETS1
-rw-r--r--src/buildtool/file_system/file_root.hpp16
-rw-r--r--src/buildtool/file_system/file_system_manager.hpp22
-rw-r--r--src/buildtool/file_system/git_repo.cpp16
-rw-r--r--src/buildtool/file_system/git_tree.hpp4
-rw-r--r--src/buildtool/file_system/object_type.hpp16
6 files changed, 63 insertions, 12 deletions
diff --git a/src/buildtool/file_system/TARGETS b/src/buildtool/file_system/TARGETS
index 53be1bae..81455fe6 100644
--- a/src/buildtool/file_system/TARGETS
+++ b/src/buildtool/file_system/TARGETS
@@ -106,6 +106,7 @@
, ["src/utils/cpp", "path"]
, ["src/utils/cpp", "hex_string"]
, ["src/utils/cpp", "gsl"]
+ , ["src/buildtool/file_system", "file_system_manager"]
]
, "cflags": ["-pthread"]
}
diff --git a/src/buildtool/file_system/file_root.hpp b/src/buildtool/file_system/file_root.hpp
index ed03f55d..1d4b6f1c 100644
--- a/src/buildtool/file_system/file_root.hpp
+++ b/src/buildtool/file_system/file_root.hpp
@@ -182,7 +182,7 @@ class FileRoot {
auto const& data = std::get<tree_t>(data_);
auto ptr = data->LookupEntryByName(name);
if (static_cast<bool>(ptr)) {
- return ptr->IsBlob();
+ return IsFileObject(ptr->Type());
}
return false;
}
@@ -250,7 +250,7 @@ class FileRoot {
auto const& data = std::get<tree_t>(data_);
return Iterator{FilteredIterator{
data->begin(), data->end(), [](auto const& x) noexcept -> bool {
- return x.second->IsBlob();
+ return IsFileObject(x.second->Type());
}}};
}
@@ -343,8 +343,8 @@ class FileRoot {
// std::holds_alternative<fs_root_t>(root_) == true
auto root_path = std::get<fs_root_t>(root_) / path;
auto exists = FileSystemManager::Exists(root_path);
- return (ignore_special_ ? exists and FileSystemManager::Type(
- root_path) != std::nullopt
+ auto type = FileSystemManager::Type(root_path);
+ return (ignore_special_ ? exists and type and IsNonSpecialObject(*type)
: exists);
}
@@ -354,7 +354,7 @@ class FileRoot {
if (auto entry =
std::get<git_root_t>(root_).tree->LookupEntryByPath(
file_path)) {
- return entry->IsBlob();
+ return IsFileObject(entry->Type());
}
return false;
}
@@ -385,7 +385,9 @@ class FileRoot {
if (auto entry =
std::get<git_root_t>(root_).tree->LookupEntryByPath(
file_path)) {
- return entry->Blob();
+ if (IsFileObject(entry->Type())) {
+ return entry->Blob();
+ }
}
return std::nullopt;
}
@@ -434,7 +436,7 @@ class FileRoot {
if (auto entry =
std::get<git_root_t>(root_).tree->LookupEntryByPath(
file_path)) {
- if (entry->IsBlob()) {
+ if (IsFileObject(entry->Type())) {
return entry->Type();
}
}
diff --git a/src/buildtool/file_system/file_system_manager.hpp b/src/buildtool/file_system/file_system_manager.hpp
index 49357130..8555e8dc 100644
--- a/src/buildtool/file_system/file_system_manager.hpp
+++ b/src/buildtool/file_system/file_system_manager.hpp
@@ -225,6 +225,7 @@ class FileSystemManager {
kSetEpochTime>(file_path,
link_path);
case ObjectType::Tree:
+ case ObjectType::Symlink:
return false;
}
}
@@ -336,6 +337,7 @@ class FileSystemManager {
return CopyFileAs<ObjectType::Executable,
kSetEpochTime,
kSetWritable>(src, dst, fd_less, opt);
+ case ObjectType::Symlink:
case ObjectType::Tree:
break;
}
@@ -539,6 +541,10 @@ class FileSystemManager {
if (std::filesystem::is_directory(status)) {
return ObjectType::Tree;
}
+ if (std::filesystem::is_symlink(status) and
+ IsNonUpwardsSymlink(path)) {
+ return ObjectType::Symlink;
+ }
if (std::filesystem::exists(status)) {
Logger::Log(LogLevel::Debug,
"object type for {} is not supported yet.",
@@ -633,9 +639,24 @@ class FileSystemManager {
else if (std::filesystem::is_directory(status)) {
type = ObjectType::Tree;
}
+ // if not file, executable, or tree, ignore every other entry
+ // type if asked to do so
else if (ignore_special) {
continue;
}
+ // if not already ignored, check symlinks and only add the
+ // non-upwards ones
+ else if (std::filesystem::is_symlink(status)) {
+ if (IsNonUpwardsSymlink(entry)) {
+ type = ObjectType::Symlink;
+ }
+ else {
+ Logger::Log(LogLevel::Error,
+ "unsupported upwards symlink dir entry {}",
+ entry.path().string());
+ return false;
+ }
+ }
else {
Logger::Log(LogLevel::Error,
"unsupported type for dir entry {}",
@@ -736,6 +757,7 @@ class FileSystemManager {
return WriteFileAs<ObjectType::Executable,
kSetEpochTime,
kSetWritable>(content, file, fd_less);
+ case ObjectType::Symlink:
case ObjectType::Tree:
return false;
}
diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp
index 01db8269..e10da57e 100644
--- a/src/buildtool/file_system/git_repo.cpp
+++ b/src/buildtool/file_system/git_repo.cpp
@@ -17,6 +17,7 @@
#include <thread>
#include <unordered_set>
+#include "src/buildtool/file_system/file_system_manager.hpp"
#include "src/buildtool/logging/logger.hpp"
#include "src/utils/cpp/gsl.hpp"
#include "src/utils/cpp/hex_string.hpp"
@@ -30,7 +31,8 @@ extern "C" {
#ifndef BOOTSTRAP_BUILD_TOOL
namespace {
-std::unordered_set<git_filemode_t> const kSupportedGitFileModes{
+/// \brief libgit2 file modes corresponding to non-special entries.
+std::unordered_set<git_filemode_t> const kNonSpecialGitFileModes{
GIT_FILEMODE_BLOB,
GIT_FILEMODE_BLOB_EXECUTABLE,
GIT_FILEMODE_TREE};
@@ -53,9 +55,9 @@ std::unordered_set<git_filemode_t> const kSupportedGitFileModes{
}
/// \brief Returns true if mode corresponds to a supported object type.
-[[nodiscard]] auto GitFileModeIsSupported(git_filemode_t const& mode) noexcept
+[[nodiscard]] auto GitFileModeIsNonSpecial(git_filemode_t const& mode) noexcept
-> bool {
- return kSupportedGitFileModes.contains(mode);
+ return kNonSpecialGitFileModes.contains(mode);
}
[[nodiscard]] auto GitFileModeToObjectType(git_filemode_t const& mode) noexcept
@@ -67,6 +69,8 @@ std::unordered_set<git_filemode_t> const kSupportedGitFileModes{
return ObjectType::Executable;
case GIT_FILEMODE_TREE:
return ObjectType::Tree;
+ case GIT_FILEMODE_LINK:
+ return ObjectType::Symlink; // condition not tested here
default: {
std::ostringstream str;
str << std::oct << static_cast<int>(mode);
@@ -86,6 +90,8 @@ std::unordered_set<git_filemode_t> const kSupportedGitFileModes{
return GIT_FILEMODE_BLOB_EXECUTABLE;
case ObjectType::Tree:
return GIT_FILEMODE_TREE;
+ case ObjectType::Symlink:
+ return GIT_FILEMODE_LINK;
}
return GIT_FILEMODE_UNREADABLE; // make gcc happy
}
@@ -132,11 +138,12 @@ std::unordered_set<git_filemode_t> const kSupportedGitFileModes{
std::string name = git_tree_entry_name(entry);
auto const* oid = git_tree_entry_id(entry);
if (auto raw_id = ToRawString(*oid)) {
- if (not GitFileModeIsSupported(git_tree_entry_filemode(entry))) {
+ if (not GitFileModeIsNonSpecial(git_tree_entry_filemode(entry))) {
return 0; // allow, but not store
}
if (auto type =
GitFileModeToObjectType(git_tree_entry_filemode(entry))) {
+ // no need to test for symlinks, as no symlink entry will reach this
(*entries)[*raw_id].emplace_back(std::move(name), *type);
return 1; // return >=0 on success, 1 == skip subtrees (flat)
}
@@ -156,6 +163,7 @@ std::unordered_set<git_filemode_t> const kSupportedGitFileModes{
if (auto raw_id = ToRawString(*oid)) {
if (auto type =
GitFileModeToObjectType(git_tree_entry_filemode(entry))) {
+ // symlinks need to be checked in caller for non-upwardness
(*entries)[*raw_id].emplace_back(std::move(name), *type);
return 1; // return >=0 on success, 1 == skip subtrees (flat)
}
diff --git a/src/buildtool/file_system/git_tree.hpp b/src/buildtool/file_system/git_tree.hpp
index b634ffb2..8dbfb4ed 100644
--- a/src/buildtool/file_system/git_tree.hpp
+++ b/src/buildtool/file_system/git_tree.hpp
@@ -114,7 +114,9 @@ class GitTreeEntry {
ObjectType type) noexcept
: cas_{cas}, raw_id_{std::move(raw_id)}, type_{type} {}
- [[nodiscard]] auto IsBlob() const noexcept { return IsFileObject(type_); }
+ [[nodiscard]] auto IsBlob() const noexcept {
+ return IsFileObject(type_) or IsSymlinkObject(type_);
+ }
[[nodiscard]] auto IsTree() const noexcept { return IsTreeObject(type_); }
[[nodiscard]] auto Blob() const noexcept -> std::optional<std::string>;
diff --git a/src/buildtool/file_system/object_type.hpp b/src/buildtool/file_system/object_type.hpp
index 36a451e8..28e34236 100644
--- a/src/buildtool/file_system/object_type.hpp
+++ b/src/buildtool/file_system/object_type.hpp
@@ -22,6 +22,7 @@ enum class ObjectType : std::int8_t {
File,
Executable,
Tree,
+ Symlink // non-upwards symbolic link
};
[[nodiscard]] constexpr auto FromChar(char c) -> ObjectType {
@@ -30,6 +31,8 @@ enum class ObjectType : std::int8_t {
return ObjectType::Executable;
case 't':
return ObjectType::Tree;
+ case 'l':
+ return ObjectType::Symlink;
default:
return ObjectType::File;
}
@@ -44,6 +47,8 @@ enum class ObjectType : std::int8_t {
return 'x';
case ObjectType::Tree:
return 't';
+ case ObjectType::Symlink:
+ return 'l';
}
Ensures(false); // unreachable
}
@@ -60,4 +65,15 @@ enum class ObjectType : std::int8_t {
return type == ObjectType::Tree;
}
+/// \brief Non-upwards symlinks are designated as first-class citizens.
+[[nodiscard]] constexpr auto IsSymlinkObject(ObjectType type) -> bool {
+ return type == ObjectType::Symlink;
+}
+
+/// \brief Only regular files, executables, and trees are non-special entries.
+[[nodiscard]] constexpr auto IsNonSpecialObject(ObjectType type) -> bool {
+ return type == ObjectType::File or type == ObjectType::Executable or
+ type == ObjectType::Tree;
+}
+
#endif // INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_OBJECT_TYPE_HPP