// -*- mode: cpp; mode: fold -*- // Description /*{{{*/ /* ###################################################################### Copy URI - This method takes a uri like a file: uri and copies it to the destination file. ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ #include #include "aptmethod.h" #include #include #include #include #include #include #include #include #include /*}}}*/ class CopyMethod final : public aptMethod { bool URIAcquire(std::string const &Message, FetchItem *Itm) override; public: CopyMethod() : aptMethod("copy", "1.0", SingleInstance | SendConfig | SendURIEncoded) { SeccompFlags = aptMethod::BASE; } }; // CopyMethod::Fetch - Fetch a file /*{{{*/ bool CopyMethod::URIAcquire(std::string const &Message, FetchItem *Itm) { struct FileCopyType { std::string name; struct stat stat{}; explicit FileCopyType(std::string &&file) : name{std::move(file)} {} }; std::vector files; // this ensures that relative paths work files.emplace_back(DecodeSendURI(Itm->Uri.substr(Itm->Uri.find(':')+1))); for (auto const &AltPath : VectorizeString(LookupTag(Message, "Alternate-Paths"), '\n')) files.emplace_back(CombineWithAlternatePath(flNotFile(files[0].name), DecodeSendURI(AltPath))); files.erase(std::remove_if(files.begin(), files.end(), [](auto &file) { return stat(file.name.c_str(), &file.stat) != 0; }), files.end()); if (files.empty()) return _error->Errno("copy-stat", _("Failed to stat")); // Forumulate a result and send a start message FetchResult Res; Res.Filename = Itm->DestFile; Res.IMSHit = false; for (auto const &File : files) { Res.Size = File.stat.st_size; Res.LastModified = File.stat.st_mtime; // just calc the hashes if the source and destination are identical if (Itm->DestFile == "/dev/null" || File.name == Itm->DestFile) { URIStart(Res); CalculateHashes(Itm, Res); URIDone(Res); return true; } FileFd From(File.name, FileFd::ReadOnly); FileFd To(Itm->DestFile, FileFd::WriteAtomic); To.EraseOnFailure(); if (not From.IsOpen() || not To.IsOpen()) continue; // Copy the file URIStart(Res); if (not CopyFile(From, To)) { To.OpFail(); continue; } From.Close(); To.Close(); CalculateHashes(Itm, Res); if (not Itm->ExpectedHashes.empty() && Itm->ExpectedHashes != Res.Hashes) continue; if (not TransferModificationTimes(File.name.c_str(), Res.Filename.c_str(), Res.LastModified)) continue; URIDone(Res); return true; } return false; } /*}}}*/ int main() { return CopyMethod().Run(); }