diff options
| author | David Kalnischkies <david@kalnischkies.de> | 2022-05-09 11:42:48 +0200 |
|---|---|---|
| committer | David Kalnischkies <david@kalnischkies.de> | 2024-11-22 12:40:10 +0000 |
| commit | 7adf8c1fa8d519b8b57292763eb7703e7d3cc580 (patch) | |
| tree | 368c3cb410c9489f193562f06f656f753af29c2d /methods/file.cc | |
| parent | 15124923b4cdb19af6bf642f396dab7c3e6bd074 (diff) | |
Look at non by-hash paths in copy and file methods
Ideally copy and file mirrors would support by-hash as well, but its
harder to setup and maintain especially if you want to cache an online
mirror who has by-hash enabled.
We can avoid unneeded roundtrips (in the best case) and entire cache
misses (in the usual worst case) by "just" telling methods that the URI
we passed it has the requested file perhaps also in other paths.
This is done in pseudo-relative paths as we would otherwise need to
teach redirection code to rewrite those URIs as well. A method like http
can easily ignore this value and await explicit instructions to look at
that file, but inspecting the path in local sources via file or copy is
(comparatively) free, so we just do it immediately. If that ends up
being the wrong version of the file as by-hash would have protected us
from we are in this feature branch now falling back to other mirrors
which are like the ones online and in support of by-hash.
Diffstat (limited to 'methods/file.cc')
| -rw-r--r-- | methods/file.cc | 111 |
1 files changed, 62 insertions, 49 deletions
diff --git a/methods/file.cc b/methods/file.cc index ff93f83d0..279711195 100644 --- a/methods/file.cc +++ b/methods/file.cc @@ -29,7 +29,7 @@ class FileMethod : public aptMethod { - virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; + bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE; public: FileMethod() : aptMethod("file", "1.0", SingleInstance | SendConfig | LocalOnly | SendURIEncoded) @@ -41,88 +41,101 @@ class FileMethod : public aptMethod // FileMethod::Fetch - Fetch a file /*{{{*/ // --------------------------------------------------------------------- /* */ -bool FileMethod::Fetch(FetchItem *Itm) +bool FileMethod::URIAcquire(std::string const &Message, FetchItem *Itm) { URI Get(Itm->Uri); - std::string const File = DecodeSendURI(Get.Path); - FetchResult Res; if (Get.Host.empty() == false) return _error->Error(_("Invalid URI, local URIS must not start with //")); - struct stat Buf; + std::vector<std::string> Files; + Files.emplace_back(DecodeSendURI(Get.Path)); + for (auto const &AltPath : VectorizeString(LookupTag(Message, "Alternate-Paths"), '\n')) + Files.emplace_back(CombineWithAlternatePath(flNotFile(Files[0]), DecodeSendURI(AltPath))); + + FetchResult Res; // deal with destination files which might linger around - if (lstat(Itm->DestFile.c_str(), &Buf) == 0) + struct stat Buf; + if (lstat(Itm->DestFile.c_str(), &Buf) == 0 && S_ISLNK(Buf.st_mode) && Buf.st_size > 0) + { + char name[Buf.st_size + 1]; + if (ssize_t const sp = readlink(Itm->DestFile.c_str(), name, Buf.st_size); sp == -1) + { + Itm->LastModified = 0; + RemoveFile("file", Itm->DestFile); + } + } + + int olderrno = 0; + // See if the file exists + for (auto const &File : Files) { - if ((Buf.st_mode & S_IFREG) != 0) + if (stat(File.c_str(), &Buf) == 0) { + Res.Size = Buf.st_size; + Res.Filename = File; + Res.LastModified = Buf.st_mtime; + Res.IMSHit = false; if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) { - if (Itm->ExpectedHashes.VerifyFile(File)) - { - Res.Filename = Itm->DestFile; + auto const filesize = Itm->ExpectedHashes.FileSize(); + if (filesize != 0 && filesize == Res.Size) Res.IMSHit = true; - } } + break; } + if (olderrno == 0) + olderrno = errno; } - if (Res.IMSHit != true) - RemoveFile("file", Itm->DestFile); - int olderrno = 0; - // See if the file exists - if (stat(File.c_str(),&Buf) == 0) + if (not Res.IMSHit) { - Res.Size = Buf.st_size; - Res.Filename = File; - Res.LastModified = Buf.st_mtime; - Res.IMSHit = false; - if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) + RemoveFile("file", Itm->DestFile); + if (not Res.Filename.empty()) { - unsigned long long const filesize = Itm->ExpectedHashes.FileSize(); - if (filesize != 0 && filesize == Res.Size) - Res.IMSHit = true; + URIStart(Res); + CalculateHashes(Itm, Res); } - - CalculateHashes(Itm, Res); } - else - olderrno = errno; - if (Res.IMSHit == false) - URIStart(Res); // See if the uncompressed file exists and reuse it FetchResult AltRes; - AltRes.Filename.clear(); - std::vector<std::string> extensions = APT::Configuration::getCompressorExtensions(); - for (std::vector<std::string>::const_iterator ext = extensions.begin(); ext != extensions.end(); ++ext) + for (auto const &File : Files) { - if (APT::String::Endswith(File, *ext) == true) + for (const auto &ext : APT::Configuration::getCompressorExtensions()) { - std::string const unfile = File.substr(0, File.length() - ext->length()); - if (stat(unfile.c_str(),&Buf) == 0) + if (APT::String::Endswith(File, ext)) { - AltRes.Size = Buf.st_size; - AltRes.Filename = unfile; - AltRes.LastModified = Buf.st_mtime; - AltRes.IMSHit = false; - if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) - AltRes.IMSHit = true; - if (Res.Filename.empty()) - CalculateHashes(Itm, AltRes); - break; + std::string const unfile = File.substr(0, File.length() - ext.length()); + if (stat(unfile.c_str(), &Buf) == 0) + { + AltRes.Size = Buf.st_size; + AltRes.Filename = unfile; + AltRes.LastModified = Buf.st_mtime; + AltRes.IMSHit = false; + if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) + AltRes.IMSHit = true; + if (Res.Filename.empty()) + { + URIStart(Res); + CalculateHashes(Itm, AltRes); + } + break; + } + // no break here as we could have situations similar to '.gz' vs '.tar.gz' here } - // no break here as we could have situations similar to '.gz' vs '.tar.gz' here } + if (not AltRes.Filename.empty()) + break; } - if (AltRes.Filename.empty() == false) + if (not AltRes.Filename.empty()) URIDone(Res,&AltRes); - else if (Res.Filename.empty() == false) + else if (not Res.Filename.empty()) URIDone(Res); else { errno = olderrno; - return _error->Errno(File.c_str(), _("File not found")); + return _error->Errno(Files[0].c_str(), _("File not found")); } return true; |
