diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/zen/cmds/copy_cmd.cpp | 8 | ||||
| -rw-r--r-- | src/zen/cmds/copy_cmd.h | 5 | ||||
| -rw-r--r-- | src/zencore/filesystem.cpp | 30 | ||||
| -rw-r--r-- | src/zenserver/main.cpp | 1 |
4 files changed, 40 insertions, 4 deletions
diff --git a/src/zen/cmds/copy_cmd.cpp b/src/zen/cmds/copy_cmd.cpp index d68a99616..956d9c9d2 100644 --- a/src/zen/cmds/copy_cmd.cpp +++ b/src/zen/cmds/copy_cmd.cpp @@ -14,6 +14,9 @@ CopyCommand::CopyCommand() { m_Options.add_options()("h,help", "Print help"); m_Options.add_options()("no-clone", "Do not perform block clone", cxxopts::value(m_NoClone)->default_value("false")); + m_Options.add_options()("must-clone", + "Always perform block clone (fails if clone is not possible)", + cxxopts::value(m_MustClone)->default_value("false")); m_Options.add_option("", "s", "source", "Copy source", cxxopts::value(m_CopySource), "<file/directory>"); m_Options.add_option("", "t", "target", "Copy target", cxxopts::value(m_CopyTarget), "<file/directory>"); m_Options.parse_positional({"source", "target"}); @@ -96,8 +99,8 @@ CopyCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) if (!Ec) { - if (!std::filesystem::relative(ToCanonical, FromCanonical).empty() || - !std::filesystem::relative(FromCanonical, ToCanonical).empty()) + if (ToCanonical.generic_string().starts_with(FromCanonical.generic_string()) || + FromCanonical.generic_string().starts_with(ToCanonical.generic_string())) { throw std::runtime_error("Invalid parent/child relationship for source/target directories"); } @@ -166,6 +169,7 @@ CopyCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) zen::CopyFileOptions CopyOptions; CopyOptions.EnableClone = !m_NoClone; + CopyOptions.MustClone = m_MustClone; CopyVisitor Visitor{FromPath, CopyOptions}; Visitor.TargetPath = ToPath; diff --git a/src/zen/cmds/copy_cmd.h b/src/zen/cmds/copy_cmd.h index 0dbebddfa..876aff3f5 100644 --- a/src/zen/cmds/copy_cmd.h +++ b/src/zen/cmds/copy_cmd.h @@ -19,10 +19,11 @@ public: virtual ZenCmdCategory& CommandCategory() const override { return g_UtilitiesCategory; } private: - cxxopts::Options m_Options{"copy", "Copy files"}; + cxxopts::Options m_Options{"copy", "Copy files efficiently"}; std::string m_CopySource; std::string m_CopyTarget; - bool m_NoClone = false; + bool m_NoClone = false; + bool m_MustClone = false; }; } // namespace zen diff --git a/src/zencore/filesystem.cpp b/src/zencore/filesystem.cpp index f117001b5..85f7690bd 100644 --- a/src/zencore/filesystem.cpp +++ b/src/zencore/filesystem.cpp @@ -624,6 +624,9 @@ CopyTree(std::filesystem::path FromPath, std::filesystem::path ToPath, const Cop if (ToPath.empty()) throw std::runtime_error("no CopyTree target specified"); + if (Options.MustClone && !SupportsBlockRefCounting(FromPath)) + throw std::runtime_error(fmt::format("cloning not possible from '{}'", FromPath)); + if (std::filesystem::exists(ToPath)) { if (!std::filesystem::is_directory(ToPath)) @@ -636,6 +639,33 @@ CopyTree(std::filesystem::path FromPath, std::filesystem::path ToPath, const Cop std::filesystem::create_directories(ToPath); } + if (Options.MustClone && !SupportsBlockRefCounting(ToPath)) + throw std::runtime_error(fmt::format("cloning not possible from '{}'", ToPath)); + + // Verify source/target relationships + + std::error_code Ec; + std::filesystem::path FromCanonical = std::filesystem::canonical(FromPath, Ec); + + if (!Ec) + { + std::filesystem::path ToCanonical = std::filesystem::canonical(ToPath, Ec); + + if (!Ec) + { + if (FromCanonical == ToCanonical) + { + throw std::runtime_error("Target and source must be distinct files or directories"); + } + + if (ToCanonical.generic_string().starts_with(FromCanonical.generic_string()) || + FromCanonical.generic_string().starts_with(ToCanonical.generic_string())) + { + throw std::runtime_error("Invalid parent/child relationship for source/target directories"); + } + } + } + struct CopyVisitor : public FileSystemTraversal::TreeVisitor { CopyVisitor(std::filesystem::path InBasePath, zen::CopyFileOptions InCopyOptions) : BasePath(InBasePath), CopyOptions(InCopyOptions) diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp index 1aa0aa4df..ff4df183e 100644 --- a/src/zenserver/main.cpp +++ b/src/zenserver/main.cpp @@ -349,6 +349,7 @@ main(int argc, char* argv[]) if (!ServerOptions.BaseSnapshotDir.empty()) { + ZEN_CONSOLE_INFO("copying snapshot from '{}' into '{}", ServerOptions.BaseSnapshotDir, ServerOptions.DataDir); CopyTree(ServerOptions.BaseSnapshotDir, ServerOptions.DataDir, {.EnableClone = true}); } |