| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
- /* ######################################################################
- Acquire Item - Item to acquire
- Each item can download to exactly one file at a time. This means you
- cannot create an item that fetches two uri's to two files at the same
- time. The pkgAcqIndex class creates a second class upon instantiation
- to fetch the other index files because of this.
- ##################################################################### */
- /*}}}*/
- // Include Files /*{{{*/
- #include <config.h>
- #include <apt-pkg/acquire-item.h>
- #include <apt-pkg/configuration.h>
- #include <apt-pkg/aptconfiguration.h>
- #include <apt-pkg/sourcelist.h>
- #include <apt-pkg/error.h>
- #include <apt-pkg/strutl.h>
- #include <apt-pkg/fileutl.h>
- #include <apt-pkg/sha1.h>
- #include <apt-pkg/tagfile.h>
- #include <apt-pkg/indexrecords.h>
- #include <apt-pkg/acquire.h>
- #include <apt-pkg/hashes.h>
- #include <apt-pkg/indexfile.h>
- #include <apt-pkg/pkgcache.h>
- #include <apt-pkg/cacheiterators.h>
- #include <apt-pkg/pkgrecords.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <iostream>
- #include <vector>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string>
- #include <sstream>
- #include <stdio.h>
- #include <ctime>
- #include <apti18n.h>
- /*}}}*/
- using namespace std;
- static void printHashSumComparision(std::string const &URI, HashStringList const &Expected, HashStringList const &Actual) /*{{{*/
- {
- if (_config->FindB("Debug::Acquire::HashSumMismatch", false) == false)
- return;
- std::cerr << std::endl << URI << ":" << std::endl << " Expected Hash: " << std::endl;
- for (HashStringList::const_iterator hs = Expected.begin(); hs != Expected.end(); ++hs)
- std::cerr << "\t- " << hs->toStr() << std::endl;
- std::cerr << " Actual Hash: " << std::endl;
- for (HashStringList::const_iterator hs = Actual.begin(); hs != Actual.end(); ++hs)
- std::cerr << "\t- " << hs->toStr() << std::endl;
- }
- /*}}}*/
- // Acquire::Item::Item - Constructor /*{{{*/
- #if __GNUC__ >= 4
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- pkgAcquire::Item::Item(pkgAcquire *Owner, HashStringList const &ExpectedHashes) :
- Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
- Local(false), QueueCounter(0), ExpectedAdditionalItems(0),
- ExpectedHashes(ExpectedHashes)
- {
- Owner->Add(this);
- Status = StatIdle;
- }
- #if __GNUC__ >= 4
- #pragma GCC diagnostic pop
- #endif
- /*}}}*/
- // Acquire::Item::~Item - Destructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- pkgAcquire::Item::~Item()
- {
- Owner->Remove(this);
- }
- /*}}}*/
- // Acquire::Item::Failed - Item failed to download /*{{{*/
- // ---------------------------------------------------------------------
- /* We return to an idle state if there are still other queues that could
- fetch this object */
- void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
- {
- Status = StatIdle;
- ErrorText = LookupTag(Message,"Message");
- UsedMirror = LookupTag(Message,"UsedMirror");
- if (QueueCounter <= 1)
- {
- /* This indicates that the file is not available right now but might
- be sometime later. If we do a retry cycle then this should be
- retried [CDROMs] */
- if (Cnf->LocalOnly == true &&
- StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
- {
- Status = StatIdle;
- Dequeue();
- return;
- }
- Status = StatError;
- Dequeue();
- }
- // report mirror failure back to LP if we actually use a mirror
- string FailReason = LookupTag(Message, "FailReason");
- if(FailReason.size() != 0)
- ReportMirrorFailure(FailReason);
- else
- ReportMirrorFailure(ErrorText);
- }
- /*}}}*/
- // Acquire::Item::Start - Item has begun to download /*{{{*/
- // ---------------------------------------------------------------------
- /* Stash status and the file size. Note that setting Complete means
- sub-phases of the acquire process such as decompresion are operating */
- void pkgAcquire::Item::Start(string /*Message*/,unsigned long long Size)
- {
- Status = StatFetching;
- if (FileSize == 0 && Complete == false)
- FileSize = Size;
- }
- /*}}}*/
- // Acquire::Item::Done - Item downloaded OK /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcquire::Item::Done(string Message,unsigned long long Size,HashStringList const &/*Hash*/,
- pkgAcquire::MethodConfig * /*Cnf*/)
- {
- // We just downloaded something..
- string FileName = LookupTag(Message,"Filename");
- UsedMirror = LookupTag(Message,"UsedMirror");
- if (Complete == false && !Local && FileName == DestFile)
- {
- if (Owner->Log != 0)
- Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
- }
- if (FileSize == 0)
- FileSize= Size;
- Status = StatDone;
- ErrorText = string();
- Owner->Dequeue(this);
- }
- /*}}}*/
- // Acquire::Item::Rename - Rename a file /*{{{*/
- // ---------------------------------------------------------------------
- /* This helper function is used by a lot of item methods as their final
- step */
- void pkgAcquire::Item::Rename(string From,string To)
- {
- if (rename(From.c_str(),To.c_str()) != 0)
- {
- char S[300];
- snprintf(S,sizeof(S),_("rename failed, %s (%s -> %s)."),strerror(errno),
- From.c_str(),To.c_str());
- Status = StatError;
- ErrorText = S;
- }
- }
- /*}}}*/
- bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState const error)/*{{{*/
- {
- if(FileExists(DestFile))
- Rename(DestFile, DestFile + ".FAILED");
- switch (error)
- {
- case HashSumMismatch:
- ErrorText = _("Hash Sum mismatch");
- Status = StatAuthError;
- ReportMirrorFailure("HashChecksumFailure");
- break;
- case SizeMismatch:
- ErrorText = _("Size mismatch");
- Status = StatAuthError;
- ReportMirrorFailure("SizeFailure");
- break;
- case InvalidFormat:
- ErrorText = _("Invalid file format");
- Status = StatError;
- // do not report as usually its not the mirrors fault, but Portal/Proxy
- break;
- }
- return false;
- }
- /*}}}*/
- // Acquire::Item::ReportMirrorFailure /*{{{*/
- // ---------------------------------------------------------------------
- void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
- {
- // we only act if a mirror was used at all
- if(UsedMirror.empty())
- return;
- #if 0
- std::cerr << "\nReportMirrorFailure: "
- << UsedMirror
- << " Uri: " << DescURI()
- << " FailCode: "
- << FailCode << std::endl;
- #endif
- const char *Args[40];
- unsigned int i = 0;
- string report = _config->Find("Methods::Mirror::ProblemReporting",
- "/usr/lib/apt/apt-report-mirror-failure");
- if(!FileExists(report))
- return;
- Args[i++] = report.c_str();
- Args[i++] = UsedMirror.c_str();
- Args[i++] = DescURI().c_str();
- Args[i++] = FailCode.c_str();
- Args[i++] = NULL;
- pid_t pid = ExecFork();
- if(pid < 0)
- {
- _error->Error("ReportMirrorFailure Fork failed");
- return;
- }
- else if(pid == 0)
- {
- execvp(Args[0], (char**)Args);
- std::cerr << "Could not exec " << Args[0] << std::endl;
- _exit(100);
- }
- if(!ExecWait(pid, "report-mirror-failure"))
- {
- _error->Warning("Couldn't report problem to '%s'",
- _config->Find("Methods::Mirror::ProblemReporting").c_str());
- }
- }
- /*}}}*/
- // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* Get a sub-index file based on checksums from a 'master' file and
- possibly query additional files */
- pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, string const &URI,
- string const &URIDesc, string const &ShortDesc,
- HashStringList const &ExpectedHashes)
- : Item(Owner, ExpectedHashes)
- {
- /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
- Debug = _config->FindB("Debug::pkgAcquire::SubIndex",false);
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(URI);
- Desc.URI = URI;
- Desc.Description = URIDesc;
- Desc.Owner = this;
- Desc.ShortDesc = ShortDesc;
- QueueURI(Desc);
- if(Debug)
- std::clog << "pkgAcqSubIndex: " << Desc.URI << std::endl;
- }
- /*}}}*/
- // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqSubIndex::Custom600Headers() const
- {
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(Desc.URI);
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nIndex-File: true\nFail-Ignore: true\n";
- return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- void pkgAcqSubIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/*{{{*/
- {
- if(Debug)
- std::clog << "pkgAcqSubIndex failed: " << Desc.URI << " with " << Message << std::endl;
- Complete = false;
- Status = StatDone;
- Dequeue();
- // No good Index is provided
- }
- /*}}}*/
- void pkgAcqSubIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
- pkgAcquire::MethodConfig *Cnf)
- {
- if(Debug)
- std::clog << "pkgAcqSubIndex::Done(): " << Desc.URI << std::endl;
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
- if (FileName != DestFile)
- {
- Local = true;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- return;
- }
- Item::Done(Message, Size, Hashes, Cnf);
- string FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(Desc.URI);
- /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
- indexRecords SubIndexParser;
- if (FileExists(DestFile) == true && !SubIndexParser.Load(DestFile)) {
- Status = StatError;
- ErrorText = SubIndexParser.ErrorText;
- return;
- }
- // success in downloading the index
- // rename the index
- if(Debug)
- std::clog << "Renaming: " << DestFile << " -> " << FinalFile << std::endl;
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
- DestFile = FinalFile;
- if(ParseIndex(DestFile) == false)
- return Failed("", NULL);
- Complete = true;
- Status = StatDone;
- Dequeue();
- return;
- }
- /*}}}*/
- bool pkgAcqSubIndex::ParseIndex(string const &IndexFile) /*{{{*/
- {
- indexRecords SubIndexParser;
- if (FileExists(IndexFile) == false || SubIndexParser.Load(IndexFile) == false)
- return false;
- // so something with the downloaded index
- return true;
- }
- /*}}}*/
- // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* Get the DiffIndex file first and see if there are patches available
- * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
- * patches. If anything goes wrong in that process, it will fall back to
- * the original packages file
- */
- pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
- IndexTarget const * const Target,
- HashStringList const &ExpectedHashes,
- indexRecords *MetaIndexParser)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser)
- {
-
- Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
- RealURI = Target->URI;
- Desc.Owner = this;
- Desc.Description = Target->Description + "/DiffIndex";
- Desc.ShortDesc = Target->ShortDesc;
- Desc.URI = Target->URI + ".diff/Index";
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(Desc.URI);
- if(Debug)
- std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
- // look for the current package file
- CurrentPackagesFile = _config->FindDir("Dir::State::lists");
- CurrentPackagesFile += URItoFileName(RealURI);
- // FIXME: this file:/ check is a hack to prevent fetching
- // from local sources. this is really silly, and
- // should be fixed cleanly as soon as possible
- if(!FileExists(CurrentPackagesFile) ||
- Desc.URI.substr(0,strlen("file:/")) == "file:/")
- {
- // we don't have a pkg file or we don't want to queue
- Failed("No index file, local or canceld by user", NULL);
- return;
- }
- if(Debug)
- std::clog << "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
- << CurrentPackagesFile << std::endl;
- QueueURI(Desc);
- }
- /*}}}*/
- // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqDiffIndex::Custom600Headers() const
- {
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(Desc.URI);
-
- if(Debug)
- std::clog << "Custom600Header-IMS: " << Final << std::endl;
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nIndex-File: true";
-
- return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/
- {
- // failing here is fine: our caller will take care of trying to
- // get the complete file if patching fails
- if(Debug)
- std::clog << "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
- << std::endl;
- FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
- pkgTagFile TF(&Fd);
- if (_error->PendingError() == true)
- return false;
- pkgTagSection Tags;
- if(unlikely(TF.Step(Tags) == false))
- return false;
- HashStringList ServerHashes;
- unsigned long long ServerSize = 0;
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
- {
- std::string tagname = *type;
- tagname.append("-Current");
- std::string const tmp = Tags.FindS(tagname.c_str());
- if (tmp.empty() == true)
- continue;
- string hash;
- unsigned long long size;
- std::stringstream ss(tmp);
- ss >> hash >> size;
- if (unlikely(hash.empty() == true))
- continue;
- if (unlikely(ServerSize != 0 && ServerSize != size))
- continue;
- ServerHashes.push_back(HashString(*type, hash));
- ServerSize = size;
- }
- if (ServerHashes.usable() == false)
- {
- if (Debug == true)
- std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Did not find a good hashsum in the index" << std::endl;
- return false;
- }
- if (ServerHashes != HashSums())
- {
- if (Debug == true)
- std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl;
- return false;
- }
- if (ServerHashes.VerifyFile(CurrentPackagesFile) == true)
- {
- // we have the same sha1 as the server so we are done here
- if(Debug)
- std::clog << "pkgAcqDiffIndex: Package file is up-to-date" << std::endl;
- // list cleanup needs to know that this file as well as the already
- // present index is ours, so we create an empty diff to save it for us
- new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser);
- return true;
- }
- FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
- Hashes LocalHashesCalc;
- LocalHashesCalc.AddFD(fd);
- HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
- if(Debug)
- std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
- << fd.Name() << " " << fd.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
- // parse all of (provided) history
- vector<DiffInfo> available_patches;
- bool firstAcceptedHashes = true;
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
- {
- if (LocalHashes.find(*type) == NULL)
- continue;
- std::string tagname = *type;
- tagname.append("-History");
- std::string const tmp = Tags.FindS(tagname.c_str());
- if (tmp.empty() == true)
- continue;
- string hash, filename;
- unsigned long long size;
- std::stringstream ss(tmp);
- while (ss >> hash >> size >> filename)
- {
- if (unlikely(hash.empty() == true || filename.empty() == true))
- continue;
- // see if we have a record for this file already
- std::vector<DiffInfo>::iterator cur = available_patches.begin();
- for (; cur != available_patches.end(); ++cur)
- {
- if (cur->file != filename || unlikely(cur->result_size != size))
- continue;
- cur->result_hashes.push_back(HashString(*type, hash));
- break;
- }
- if (cur != available_patches.end())
- continue;
- if (firstAcceptedHashes == true)
- {
- DiffInfo next;
- next.file = filename;
- next.result_hashes.push_back(HashString(*type, hash));
- next.result_size = size;
- next.patch_size = 0;
- available_patches.push_back(next);
- }
- else
- {
- if (Debug == true)
- std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
- << " wasn't in the list for the first parsed hash! (history)" << std::endl;
- break;
- }
- }
- firstAcceptedHashes = false;
- }
- if (unlikely(available_patches.empty() == true))
- {
- if (Debug)
- std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
- << "Couldn't find any patches for the patch series." << std::endl;
- return false;
- }
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
- {
- if (LocalHashes.find(*type) == NULL)
- continue;
- std::string tagname = *type;
- tagname.append("-Patches");
- std::string const tmp = Tags.FindS(tagname.c_str());
- if (tmp.empty() == true)
- continue;
- string hash, filename;
- unsigned long long size;
- std::stringstream ss(tmp);
- while (ss >> hash >> size >> filename)
- {
- if (unlikely(hash.empty() == true || filename.empty() == true))
- continue;
- // see if we have a record for this file already
- std::vector<DiffInfo>::iterator cur = available_patches.begin();
- for (; cur != available_patches.end(); ++cur)
- {
- if (cur->file != filename)
- continue;
- if (unlikely(cur->patch_size != 0 && cur->patch_size != size))
- continue;
- cur->patch_hashes.push_back(HashString(*type, hash));
- cur->patch_size = size;
- break;
- }
- if (cur != available_patches.end())
- continue;
- if (Debug == true)
- std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": File " << filename
- << " wasn't in the list for the first parsed hash! (patches)" << std::endl;
- break;
- }
- }
- bool foundStart = false;
- for (std::vector<DiffInfo>::iterator cur = available_patches.begin();
- cur != available_patches.end(); ++cur)
- {
- if (LocalHashes != cur->result_hashes)
- continue;
- available_patches.erase(available_patches.begin(), cur);
- foundStart = true;
- break;
- }
- if (foundStart == false || unlikely(available_patches.empty() == true))
- {
- if (Debug)
- std::clog << "pkgAcqDiffIndex: " << IndexDiffFile << ": "
- << "Couldn't find the start of the patch series." << std::endl;
- return false;
- }
- // patching with too many files is rather slow compared to a fast download
- unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0);
- if (fileLimit != 0 && fileLimit < available_patches.size())
- {
- if (Debug)
- std::clog << "Need " << available_patches.size() << " diffs (Limit is " << fileLimit
- << ") so fallback to complete download" << std::endl;
- return false;
- }
- // calculate the size of all patches we have to get
- // note that all sizes are uncompressed, while we download compressed files
- unsigned long long patchesSize = 0;
- for (std::vector<DiffInfo>::const_iterator cur = available_patches.begin();
- cur != available_patches.end(); ++cur)
- patchesSize += cur->patch_size;
- unsigned long long const sizeLimit = ServerSize * _config->FindI("Acquire::PDiffs::SizeLimit", 100);
- if (false && sizeLimit > 0 && (sizeLimit/100) < patchesSize)
- {
- if (Debug)
- std::clog << "Need " << patchesSize << " bytes (Limit is " << sizeLimit/100
- << ") so fallback to complete download" << std::endl;
- return false;
- }
- // we have something, queue the diffs
- string::size_type const last_space = Description.rfind(" ");
- if(last_space != string::npos)
- Description.erase(last_space, Description.size()-last_space);
- /* decide if we should download patches one by one or in one go:
- The first is good if the server merges patches, but many don't so client
- based merging can be attempt in which case the second is better.
- "bad things" will happen if patches are merged on the server,
- but client side merging is attempt as well */
- bool pdiff_merge = _config->FindB("Acquire::PDiffs::Merge", true);
- if (pdiff_merge == true)
- {
- // reprepro adds this flag if it has merged patches on the server
- std::string const precedence = Tags.FindS("X-Patch-Precedence");
- pdiff_merge = (precedence != "merged");
- }
- if (pdiff_merge == false)
- {
- new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser,
- available_patches);
- }
- else
- {
- std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
- for(size_t i = 0; i < available_patches.size(); ++i)
- (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, Target,
- ExpectedHashes,
- MetaIndexParser,
- available_patches[i],
- diffs);
- }
- Complete = false;
- Status = StatDone;
- Dequeue();
- return true;
- }
- /*}}}*/
- void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/*{{{*/
- {
- if(Debug)
- std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
- << "Falling back to normal index file acquire" << std::endl;
- new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
- Complete = false;
- Status = StatDone;
- Dequeue();
- }
- /*}}}*/
- void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
- pkgAcquire::MethodConfig *Cnf)
- {
- if(Debug)
- std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
- Item::Done(Message, Size, Hashes, Cnf);
- string FinalFile;
- FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
- // success in downloading the index
- // rename the index
- FinalFile += string(".IndexDiff");
- if(Debug)
- std::clog << "Renaming: " << DestFile << " -> " << FinalFile
- << std::endl;
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
- DestFile = FinalFile;
- if(!ParseDiffIndex(DestFile))
- return Failed("Parsing pdiff Index failed", NULL);
- Complete = true;
- Status = StatDone;
- Dequeue();
- return;
- }
- /*}}}*/
- // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* The package diff is added to the queue. one object is constructed
- * for each diff and the index
- */
- pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
- struct IndexTarget const * const Target,
- HashStringList const &ExpectedHashes,
- indexRecords *MetaIndexParser,
- vector<DiffInfo> diffs)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser),
- available_patches(diffs)
- {
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(Target->URI);
- Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
- RealURI = Target->URI;
- Desc.Owner = this;
- Description = Target->Description;
- Desc.ShortDesc = Target->ShortDesc;
- if(available_patches.empty() == true)
- {
- // we are done (yeah!)
- Finish(true);
- }
- else
- {
- // get the next diff
- State = StateFetchDiff;
- QueueNextDiff();
- }
- }
- /*}}}*/
- void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/*{{{*/
- {
- if(Debug)
- std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
- << "Falling back to normal index file acquire" << std::endl;
- new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
- Finish();
- }
- /*}}}*/
- // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
- void pkgAcqIndexDiffs::Finish(bool allDone)
- {
- // we restore the original name, this is required, otherwise
- // the file will be cleaned
- if(allDone)
- {
- DestFile = _config->FindDir("Dir::State::lists");
- DestFile += URItoFileName(RealURI);
- if(HashSums().usable() && !HashSums().VerifyFile(DestFile))
- {
- RenameOnError(HashSumMismatch);
- Dequeue();
- return;
- }
- // this is for the "real" finish
- Complete = true;
- Status = StatDone;
- Dequeue();
- if(Debug)
- std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
- return;
- }
- if(Debug)
- std::clog << "Finishing: " << Desc.URI << std::endl;
- Complete = false;
- Status = StatDone;
- Dequeue();
- return;
- }
- /*}}}*/
- bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
- {
- // calc sha1 of the just patched file
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(RealURI);
- FileFd fd(FinalFile, FileFd::ReadOnly);
- Hashes LocalHashesCalc;
- LocalHashesCalc.AddFD(fd);
- HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
- if(Debug)
- std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
- if (unlikely(LocalHashes.usable() == false || ExpectedHashes.usable() == false))
- {
- Failed("Local/Expected hashes are not usable", NULL);
- return false;
- }
- // final file reached before all patches are applied
- if(LocalHashes == ExpectedHashes)
- {
- Finish(true);
- return true;
- }
- // remove all patches until the next matching patch is found
- // this requires the Index file to be ordered
- for(vector<DiffInfo>::iterator I = available_patches.begin();
- available_patches.empty() == false &&
- I != available_patches.end() &&
- I->result_hashes != LocalHashes;
- ++I)
- {
- available_patches.erase(I);
- }
- // error checking and falling back if no patch was found
- if(available_patches.empty() == true)
- {
- Failed("No patches left to reach target", NULL);
- return false;
- }
- // queue the right diff
- Desc.URI = RealURI + ".diff/" + available_patches[0].file + ".gz";
- Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI + ".diff/" + available_patches[0].file);
- if(Debug)
- std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
- QueueURI(Desc);
- return true;
- }
- /*}}}*/
- void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringList const &Hashes, /*{{{*/
- pkgAcquire::MethodConfig *Cnf)
- {
- if(Debug)
- std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
- Item::Done(Message, Size, Hashes, Cnf);
- string FinalFile;
- FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
- // success in downloading a diff, enter ApplyDiff state
- if(State == StateFetchDiff)
- {
- FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Gzip);
- class Hashes LocalHashesCalc;
- LocalHashesCalc.AddFD(fd);
- HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
- if (fd.Size() != available_patches[0].patch_size ||
- available_patches[0].patch_hashes != LocalHashes)
- {
- Failed("Patch has Size/Hashsum mismatch", NULL);
- return;
- }
- // rred excepts the patch as $FinalFile.ed
- Rename(DestFile,FinalFile+".ed");
- if(Debug)
- std::clog << "Sending to rred method: " << FinalFile << std::endl;
- State = StateApplyDiff;
- Local = true;
- Desc.URI = "rred:" + FinalFile;
- QueueURI(Desc);
- ActiveSubprocess = "rred";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- Mode = "rred";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic pop
- #endif
- return;
- }
- // success in download/apply a diff, queue next (if needed)
- if(State == StateApplyDiff)
- {
- // remove the just applied patch
- available_patches.erase(available_patches.begin());
- unlink((FinalFile + ".ed").c_str());
- // move into place
- if(Debug)
- {
- std::clog << "Moving patched file in place: " << std::endl
- << DestFile << " -> " << FinalFile << std::endl;
- }
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
- // see if there is more to download
- if(available_patches.empty() == false) {
- new pkgAcqIndexDiffs(Owner, Target,
- ExpectedHashes, MetaIndexParser,
- available_patches);
- return Finish();
- } else
- return Finish(true);
- }
- }
- /*}}}*/
- // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
- pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire *Owner,
- struct IndexTarget const * const Target,
- HashStringList const &ExpectedHashes,
- indexRecords *MetaIndexParser,
- DiffInfo const &patch,
- std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser),
- patch(patch), allPatches(allPatches), State(StateFetchDiff)
- {
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(Target->URI);
- Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
- RealURI = Target->URI;
- Desc.Owner = this;
- Description = Target->Description;
- Desc.ShortDesc = Target->ShortDesc;
- Desc.URI = RealURI + ".diff/" + patch.file + ".gz";
- Desc.Description = Description + " " + patch.file + string(".pdiff");
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI + ".diff/" + patch.file);
- if(Debug)
- std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl;
- QueueURI(Desc);
- }
- /*}}}*/
- void pkgAcqIndexMergeDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/*{{{*/
- {
- if(Debug)
- std::clog << "pkgAcqIndexMergeDiffs failed: " << Desc.URI << " with " << Message << std::endl;
- Complete = false;
- Status = StatDone;
- Dequeue();
- // check if we are the first to fail, otherwise we are done here
- State = StateDoneDiff;
- for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
- I != allPatches->end(); ++I)
- if ((*I)->State == StateErrorDiff)
- return;
- // first failure means we should fallback
- State = StateErrorDiff;
- std::clog << "Falling back to normal index file acquire" << std::endl;
- new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
- }
- /*}}}*/
- void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
- pkgAcquire::MethodConfig *Cnf)
- {
- if(Debug)
- std::clog << "pkgAcqIndexMergeDiffs::Done(): " << Desc.URI << std::endl;
- Item::Done(Message,Size,Hashes,Cnf);
- string const FinalFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- if (State == StateFetchDiff)
- {
- FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Gzip);
- class Hashes LocalHashesCalc;
- LocalHashesCalc.AddFD(fd);
- HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
- if (fd.Size() != patch.patch_size || patch.patch_hashes != LocalHashes)
- {
- Failed("Patch has Size/Hashsum mismatch", NULL);
- return;
- }
- // rred expects the patch as $FinalFile.ed.$patchname.gz
- Rename(DestFile, FinalFile + ".ed." + patch.file + ".gz");
- // check if this is the last completed diff
- State = StateDoneDiff;
- for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
- I != allPatches->end(); ++I)
- if ((*I)->State != StateDoneDiff)
- {
- if(Debug)
- std::clog << "Not the last done diff in the batch: " << Desc.URI << std::endl;
- return;
- }
- // this is the last completed diff, so we are ready to apply now
- State = StateApplyDiff;
- if(Debug)
- std::clog << "Sending to rred method: " << FinalFile << std::endl;
- Local = true;
- Desc.URI = "rred:" + FinalFile;
- QueueURI(Desc);
- ActiveSubprocess = "rred";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- Mode = "rred";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic pop
- #endif
- return;
- }
- // success in download/apply all diffs, clean up
- else if (State == StateApplyDiff)
- {
- // see if we really got the expected file
- if(ExpectedHashes.usable() && !ExpectedHashes.VerifyFile(DestFile))
- {
- RenameOnError(HashSumMismatch);
- return;
- }
- // move the result into place
- if(Debug)
- std::clog << "Moving patched file in place: " << std::endl
- << DestFile << " -> " << FinalFile << std::endl;
- Rename(DestFile, FinalFile);
- chmod(FinalFile.c_str(), 0644);
- // otherwise lists cleanup will eat the file
- DestFile = FinalFile;
- // ensure the ed's are gone regardless of list-cleanup
- for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
- I != allPatches->end(); ++I)
- {
- std::string patch = FinalFile + ".ed." + (*I)->patch.file + ".gz";
- unlink(patch.c_str());
- }
- // all set and done
- Complete = true;
- if(Debug)
- std::clog << "allDone: " << DestFile << "\n" << std::endl;
- }
- }
- /*}}}*/
- // AcqIndex::AcqIndex - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* The package file is added to the queue and a second class is
- instantiated to fetch the revision file */
- pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
- string URI,string URIDesc,string ShortDesc,
- HashStringList const &ExpectedHash, string comprExt)
- : pkgAcqBaseIndex(Owner, NULL, ExpectedHash, NULL), RealURI(URI)
- {
- if(comprExt.empty() == true)
- {
- // autoselect the compression method
- std::vector<std::string> types = APT::Configuration::getCompressionTypes();
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- comprExt.append(*t).append(" ");
- if (comprExt.empty() == false)
- comprExt.erase(comprExt.end()-1);
- }
- CompressionExtension = comprExt;
- Init(URI, URIDesc, ShortDesc);
- }
- pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target,
- HashStringList const &ExpectedHash,
- indexRecords *MetaIndexParser)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHash, MetaIndexParser),
- RealURI(Target->URI)
- {
- // autoselect the compression method
- std::vector<std::string> types = APT::Configuration::getCompressionTypes();
- CompressionExtension = "";
- if (ExpectedHashes.usable())
- {
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- if (*t == "uncompressed" || MetaIndexParser->Exists(string(Target->MetaKey).append(".").append(*t)) == true)
- CompressionExtension.append(*t).append(" ");
- }
- else
- {
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- CompressionExtension.append(*t).append(" ");
- }
- if (CompressionExtension.empty() == false)
- CompressionExtension.erase(CompressionExtension.end()-1);
- Init(Target->URI, Target->Description, Target->ShortDesc);
- }
- /*}}}*/
- // AcqIndex::Init - defered Constructor /*{{{*/
- void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) {
- Decompression = false;
- Erase = false;
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(URI);
- std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- std::string MetaKey;
- if (comprExt == "uncompressed")
- {
- Desc.URI = URI;
- if(Target)
- MetaKey = string(Target->MetaKey);
- }
- else
- {
- Desc.URI = URI + '.' + comprExt;
- DestFile = DestFile + '.' + comprExt;
- if(Target)
- MetaKey = string(Target->MetaKey) + '.' + comprExt;
- }
- // load the filesize
- if(MetaIndexParser)
- {
- indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
- if(Record)
- FileSize = Record->Size;
-
- InitByHashIfNeeded(MetaKey);
- }
- Desc.Description = URIDesc;
- Desc.Owner = this;
- Desc.ShortDesc = ShortDesc;
- QueueURI(Desc);
- }
- /*}}}*/
- // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey)
- {
- // TODO:
- // - (maybe?) add support for by-hash into the sources.list as flag
- // - make apt-ftparchive generate the hashes (and expire?)
- std::string HostKnob = "APT::Acquire::" + ::URI(Desc.URI).Host + "::By-Hash";
- if(_config->FindB("APT::Acquire::By-Hash", false) == true ||
- _config->FindB(HostKnob, false) == true ||
- MetaIndexParser->GetSupportsAcquireByHash())
- {
- indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
- if(Record)
- {
- // FIXME: should we really use the best hash here? or a fixed one?
- const HashString *TargetHash = Record->Hashes.find("");
- std::string ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
- size_t trailing_slash = Desc.URI.find_last_of("/");
- Desc.URI = Desc.URI.replace(
- trailing_slash,
- Desc.URI.substr(trailing_slash+1).size()+1,
- ByHash);
- } else {
- _error->Warning(
- "Fetching ByHash requested but can not find record for %s",
- MetaKey.c_str());
- }
- }
- }
- /*}}}*/
- // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqIndex::Custom600Headers() const
- {
- std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(RealURI);
- if (_config->FindB("Acquire::GzipIndexes",false))
- Final += compExt;
-
- string msg = "\nIndex-File: true";
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) == 0)
- msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- return msg;
- }
- /*}}}*/
- void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
- {
- size_t const nextExt = CompressionExtension.find(' ');
- if (nextExt != std::string::npos)
- {
- CompressionExtension = CompressionExtension.substr(nextExt+1);
- Init(RealURI, Desc.Description, Desc.ShortDesc);
- return;
- }
- // on decompression failure, remove bad versions in partial/
- if (Decompression && Erase) {
- string s = _config->FindDir("Dir::State::lists") + "partial/";
- s.append(URItoFileName(RealURI));
- unlink(s.c_str());
- }
- Item::Failed(Message,Cnf);
- }
- /*}}}*/
- // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
- std::string pkgAcqIndex::GetFinalFilename(std::string const &URI,
- std::string const &compExt)
- {
- std::string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(URI);
- if (_config->FindB("Acquire::GzipIndexes",false) == true)
- FinalFile += '.' + compExt;
- return FinalFile;
- }
- /*}}}*/
- // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
- void pkgAcqIndex::ReverifyAfterIMS(std::string const &FileName)
- {
- std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- if (_config->FindB("Acquire::GzipIndexes",false) == true)
- DestFile += compExt;
- string FinalFile = GetFinalFilename(RealURI, compExt);
- Rename(FinalFile, FileName);
- Decompression = true;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- }
- /*}}}*/
- // AcqIndex::Done - Finished a fetch /*{{{*/
- // ---------------------------------------------------------------------
- /* This goes through a number of states.. On the initial fetch the
- method could possibly return an alternate filename which points
- to the uncompressed version of the file. If this is so the file
- is copied into the partial directory. In all other cases the file
- is decompressed with a gzip uri. */
- void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,
- pkgAcquire::MethodConfig *Cfg)
- {
- Item::Done(Message,Size,Hashes,Cfg);
- std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- if (Decompression == true)
- {
- if (ExpectedHashes.usable() && ExpectedHashes != Hashes)
- {
- Desc.URI = RealURI;
- RenameOnError(HashSumMismatch);
- printHashSumComparision(RealURI, ExpectedHashes, Hashes);
- return;
- }
- // FIXME: this can go away once we only ever download stuff that
- // has a valid hash and we never do GET based probing
- //
- /* Always verify the index file for correctness (all indexes must
- * have a Package field) (LP: #346386) (Closes: #627642)
- */
- FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension);
- // Only test for correctness if the file is not empty (empty is ok)
- if (fd.Size() > 0)
- {
- pkgTagSection sec;
- pkgTagFile tag(&fd);
-
- // all our current indexes have a field 'Package' in each section
- if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
- {
- RenameOnError(InvalidFormat);
- return;
- }
- }
-
- // Done, move it into position
- string FinalFile = GetFinalFilename(RealURI, compExt);
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
- /* We restore the original name to DestFile so that the clean operation
- will work OK */
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI);
- if (_config->FindB("Acquire::GzipIndexes",false))
- DestFile += '.' + compExt;
- // Remove the compressed version.
- if (Erase == true)
- unlink(DestFile.c_str());
- return;
- }
- Erase = false;
- Complete = true;
-
- // Handle the unzipd case
- string FileName = LookupTag(Message,"Alt-Filename");
- if (FileName.empty() == false)
- {
- Decompression = true;
- Local = true;
- DestFile += ".decomp";
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- ActiveSubprocess = "copy";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- Mode = "copy";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic pop
- #endif
- return;
- }
- FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- }
- if (FileName == DestFile)
- Erase = true;
- else
- Local = true;
- // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
- // file when its doing the indexcopy
- if (RealURI.substr(0,6) == "cdrom:" &&
- StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
- return;
- // The files timestamp matches, for non-local URLs reverify the local
- // file, for local file, uncompress again to ensure the hashsum is still
- // matching the Release file
- if (!Local && StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
- {
- // set destfile to the final destfile
- if(_config->FindB("Acquire::GzipIndexes",false) == false)
- {
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI);
- }
- ReverifyAfterIMS(FileName);
- return;
- }
- string decompProg;
- // If we enable compressed indexes, queue for hash verification
- if (_config->FindB("Acquire::GzipIndexes",false))
- {
- DestFile = _config->FindDir("Dir::State::lists");
- DestFile += URItoFileName(RealURI) + '.' + compExt;
- Decompression = true;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- return;
- }
- // get the binary name for your used compression type
- decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),"");
- if(decompProg.empty() == false);
- else if(compExt == "uncompressed")
- decompProg = "copy";
- else {
- _error->Error("Unsupported extension: %s", compExt.c_str());
- return;
- }
- Decompression = true;
- DestFile += ".decomp";
- Desc.URI = decompProg + ":" + FileName;
- QueueURI(Desc);
- ActiveSubprocess = decompProg;
- #if __GNUC__ >= 4
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- Mode = ActiveSubprocess.c_str();
- #if __GNUC__ >= 4
- #pragma GCC diagnostic pop
- #endif
- }
- /*}}}*/
- // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* The Translation file is added to the queue */
- pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
- string URI,string URIDesc,string ShortDesc)
- : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashStringList(), "")
- {
- }
- pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const * const Target,
- HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser)
- : pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser)
- {
- // load the filesize
- indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
- if(Record)
- FileSize = Record->Size;
- }
- /*}}}*/
- // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- string pkgAcqIndexTrans::Custom600Headers() const
- {
- std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(RealURI);
- if (_config->FindB("Acquire::GzipIndexes",false))
- Final += compExt;
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nFail-Ignore: true\nIndex-File: true";
- return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
- {
- size_t const nextExt = CompressionExtension.find(' ');
- if (nextExt != std::string::npos)
- {
- CompressionExtension = CompressionExtension.substr(nextExt+1);
- Init(RealURI, Desc.Description, Desc.ShortDesc);
- Status = StatIdle;
- return;
- }
- if (Cnf->LocalOnly == true ||
- StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
- {
- // Ignore this
- Status = StatDone;
- Complete = false;
- Dequeue();
- return;
- }
- Item::Failed(Message,Cnf);
- }
- /*}}}*/
- pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
- string URI,string URIDesc,string ShortDesc,
- string MetaIndexURI, string MetaIndexURIDesc,
- string MetaIndexShortDesc,
- const vector<IndexTarget*>* IndexTargets,
- indexRecords* MetaIndexParser) :
- Item(Owner, HashStringList()), RealURI(URI), MetaIndexURI(MetaIndexURI),
- MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
- MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
- {
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(URI);
- // remove any partial downloaded sig-file in partial/.
- // it may confuse proxies and is too small to warrant a
- // partial download anyway
- unlink(DestFile.c_str());
- // Create the item
- Desc.Description = URIDesc;
- Desc.Owner = this;
- Desc.ShortDesc = ShortDesc;
- Desc.URI = URI;
-
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(RealURI);
- if (RealFileExists(Final) == true)
- {
- // File was already in place. It needs to be re-downloaded/verified
- // because Release might have changed, we do give it a different
- // name than DestFile because otherwise the http method will
- // send If-Range requests and there are too many broken servers
- // out there that do not understand them
- LastGoodSig = DestFile+".reverify";
- Rename(Final,LastGoodSig);
- }
- // we expect the indextargets + one additional Release file
- ExpectedAdditionalItems = IndexTargets->size() + 1;
- QueueURI(Desc);
- }
- /*}}}*/
- pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
- {
- // if the file was never queued undo file-changes done in the constructor
- if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false &&
- LastGoodSig.empty() == false)
- {
- string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
- Rename(LastGoodSig, Final);
- }
- }
- /*}}}*/
- // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqMetaSig::Custom600Headers() const
- {
- struct stat Buf;
- if (stat(LastGoodSig.c_str(),&Buf) != 0)
- return "\nIndex-File: true";
- return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- void pkgAcqMetaSig::Done(string Message,unsigned long long Size, HashStringList const &Hashes,
- pkgAcquire::MethodConfig *Cfg)
- {
- Item::Done(Message, Size, Hashes, Cfg);
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
- if (FileName != DestFile)
- {
- // We have to copy it into place
- Local = true;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- return;
- }
- Complete = true;
- // at this point pkgAcqMetaIndex takes over
- ExpectedAdditionalItems = 0;
- // put the last known good file back on i-m-s hit (it will
- // be re-verified again)
- // Else do nothing, we have the new file in DestFile then
- if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
- Rename(LastGoodSig, DestFile);
- // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
- new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc,
- MetaIndexShortDesc, DestFile, IndexTargets,
- MetaIndexParser);
- }
- /*}}}*/
- void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
- {
- string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- // at this point pkgAcqMetaIndex takes over
- ExpectedAdditionalItems = 0;
- // if we get a network error we fail gracefully
- if(Status == StatTransientNetworkError)
- {
- Item::Failed(Message,Cnf);
- // move the sigfile back on transient network failures
- if(FileExists(LastGoodSig))
- Rename(LastGoodSig,Final);
- // set the status back to , Item::Failed likes to reset it
- Status = pkgAcquire::Item::StatTransientNetworkError;
- return;
- }
- // Delete any existing sigfile when the acquire failed
- unlink(Final.c_str());
- // queue a pkgAcqMetaIndex with no sigfile
- new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
- "", IndexTargets, MetaIndexParser);
- if (Cnf->LocalOnly == true ||
- StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
- {
- // Ignore this
- Status = StatDone;
- Complete = false;
- Dequeue();
- return;
- }
-
- Item::Failed(Message,Cnf);
- }
- /*}}}*/
- pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
- string URI,string URIDesc,string ShortDesc,
- string SigFile,
- const vector<IndexTarget*>* IndexTargets,
- indexRecords* MetaIndexParser) :
- Item(Owner, HashStringList()), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets),
- MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false)
- {
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(URI);
- // Create the item
- Desc.Description = URIDesc;
- Desc.Owner = this;
- Desc.ShortDesc = ShortDesc;
- Desc.URI = URI;
- // we expect more item
- ExpectedAdditionalItems = IndexTargets->size();
- QueueURI(Desc);
- }
- /*}}}*/
- // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqMetaIndex::Custom600Headers() const
- {
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(RealURI);
-
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nIndex-File: true";
-
- return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
- pkgAcquire::MethodConfig *Cfg)
- {
- Item::Done(Message,Size,Hashes,Cfg);
- // MetaIndexes are done in two passes: one to download the
- // metaindex with an appropriate method, and a second to verify it
- // with the gpgv method
- if (AuthPass == true)
- {
- AuthDone(Message);
- // all cool, move Release file into place
- Complete = true;
- }
- else
- {
- RetrievalDone(Message);
- if (!Complete)
- // Still more retrieving to do
- return;
- if (SigFile == "")
- {
- // There was no signature file, so we are finished. Download
- // the indexes and do only hashsum verification if possible
- MetaIndexParser->Load(DestFile);
- QueueIndexes(false);
- }
- else
- {
- // FIXME: move this into pkgAcqMetaClearSig::Done on the next
- // ABI break
- // if we expect a ClearTextSignature (InRelase), ensure that
- // this is what we get and if not fail to queue a
- // Release/Release.gpg, see #346386
- if (SigFile == DestFile && !StartsWithGPGClearTextSignature(DestFile))
- {
- Failed(Message, Cfg);
- return;
- }
- // There was a signature file, so pass it to gpgv for
- // verification
- if (_config->FindB("Debug::pkgAcquire::Auth", false))
- std::cerr << "Metaindex acquired, queueing gpg verification ("
- << SigFile << "," << DestFile << ")\n";
- AuthPass = true;
- Desc.URI = "gpgv:" + SigFile;
- QueueURI(Desc);
- ActiveSubprocess = "gpgv";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- Mode = "gpgv";
- #if __GNUC__ >= 4
- #pragma GCC diagnostic pop
- #endif
- return;
- }
- }
- if (Complete == true)
- {
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(RealURI);
- if (SigFile == DestFile)
- SigFile = FinalFile;
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
- DestFile = FinalFile;
- }
- }
- /*}}}*/
- void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/
- {
- // We have just finished downloading a Release file (it is not
- // verified yet)
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
- if (FileName != DestFile)
- {
- Local = true;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- return;
- }
- // make sure to verify against the right file on I-M-S hit
- IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
- if(IMSHit)
- {
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(RealURI);
- if (SigFile == DestFile)
- {
- SigFile = FinalFile;
- // constructor of pkgAcqMetaClearSig moved it out of the way,
- // now move it back in on IMS hit for the 'old' file
- string const OldClearSig = DestFile + ".reverify";
- if (RealFileExists(OldClearSig) == true)
- Rename(OldClearSig, FinalFile);
- }
- DestFile = FinalFile;
- }
- Complete = true;
- }
- /*}}}*/
- void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/
- {
- // At this point, the gpgv method has succeeded, so there is a
- // valid signature from a key in the trusted keyring. We
- // perform additional verification of its contents, and use them
- // to verify the indexes we are about to download
- if (!MetaIndexParser->Load(DestFile))
- {
- Status = StatAuthError;
- ErrorText = MetaIndexParser->ErrorText;
- return;
- }
- if (!VerifyVendor(Message))
- {
- return;
- }
- if (_config->FindB("Debug::pkgAcquire::Auth", false))
- std::cerr << "Signature verification succeeded: "
- << DestFile << std::endl;
- // do not trust any previously unverified content that we may have
- string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
- if (DestFile != SigFile)
- LastGoodSigFile.append(".gpg");
- LastGoodSigFile.append(".reverify");
- if(IMSHit == false && RealFileExists(LastGoodSigFile) == false)
- {
- for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
- Target != IndexTargets->end();
- ++Target)
- {
- // remove old indexes
- std::string index = _config->FindDir("Dir::State::lists") +
- URItoFileName((*Target)->URI);
- unlink(index.c_str());
- // and also old gzipindexes
- std::vector<std::string> types = APT::Configuration::getCompressionTypes();
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- {
- index += '.' + (*t);
- unlink(index.c_str());
- }
- }
- }
- // Download further indexes with verification
- QueueIndexes(true);
- // is it a clearsigned MetaIndex file?
- if (DestFile == SigFile)
- return;
- // Done, move signature file into position
- string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
- URItoFileName(RealURI) + ".gpg";
- Rename(SigFile,VerifiedSigFile);
- chmod(VerifiedSigFile.c_str(),0644);
- }
- /*}}}*/
- void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
- {
- #if 0
- /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
- * FIXME: Disabled; it breaks unsigned repositories without hashes */
- if (!verify && FileExists(DestFile) && !MetaIndexParser->Load(DestFile))
- {
- Status = StatError;
- ErrorText = MetaIndexParser->ErrorText;
- return;
- }
- #endif
- bool transInRelease = false;
- {
- std::vector<std::string> const keys = MetaIndexParser->MetaKeys();
- for (std::vector<std::string>::const_iterator k = keys.begin(); k != keys.end(); ++k)
- // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
- if (k->find("Translation-") != std::string::npos)
- {
- transInRelease = true;
- break;
- }
- }
- // at this point the real Items are loaded in the fetcher
- ExpectedAdditionalItems = 0;
- for (vector <IndexTarget*>::const_iterator Target = IndexTargets->begin();
- Target != IndexTargets->end();
- ++Target)
- {
- HashStringList ExpectedIndexHashes;
- const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
- bool compressedAvailable = false;
- if (Record == NULL)
- {
- if ((*Target)->IsOptional() == true)
- {
- std::vector<std::string> types = APT::Configuration::getCompressionTypes();
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- if (MetaIndexParser->Exists((*Target)->MetaKey + "." + *t) == true)
- {
- compressedAvailable = true;
- break;
- }
- }
- else if (verify == true)
- {
- Status = StatAuthError;
- strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
- return;
- }
- }
- else
- {
- ExpectedIndexHashes = Record->Hashes;
- if (_config->FindB("Debug::pkgAcquire::Auth", false))
- {
- std::cerr << "Queueing: " << (*Target)->URI << std::endl
- << "Expected Hash:" << std::endl;
- for (HashStringList::const_iterator hs = ExpectedIndexHashes.begin(); hs != ExpectedIndexHashes.end(); ++hs)
- std::cerr << "\t- " << hs->toStr() << std::endl;
- std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
- }
- if (verify == true && ExpectedIndexHashes.empty() == true && (*Target)->IsOptional() == false)
- {
- Status = StatAuthError;
- strprintf(ErrorText, _("Unable to find hash sum for '%s' in Release file"), (*Target)->MetaKey.c_str());
- return;
- }
- }
- if ((*Target)->IsOptional() == true)
- {
- if ((*Target)->IsSubIndex() == true)
- new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
- (*Target)->ShortDesc, ExpectedIndexHashes);
- else if (transInRelease == false || Record != NULL || compressedAvailable == true)
- {
- if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
- MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
- new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
- else
- new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
- }
- continue;
- }
- /* Queue Packages file (either diff or full packages files, depending
- on the users option) - we also check if the PDiff Index file is listed
- in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
- instead, but passing the required info to it is to much hassle */
- if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
- MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
- new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
- else
- new pkgAcqIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
- }
- }
- /*}}}*/
- bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/
- {
- string::size_type pos;
- // check for missing sigs (that where not fatal because otherwise we had
- // bombed earlier)
- string missingkeys;
- string msg = _("There is no public key available for the "
- "following key IDs:\n");
- pos = Message.find("NO_PUBKEY ");
- if (pos != std::string::npos)
- {
- string::size_type start = pos+strlen("NO_PUBKEY ");
- string Fingerprint = Message.substr(start, Message.find("\n")-start);
- missingkeys += (Fingerprint);
- }
- if(!missingkeys.empty())
- _error->Warning("%s", (msg + missingkeys).c_str());
- string Transformed = MetaIndexParser->GetExpectedDist();
- if (Transformed == "../project/experimental")
- {
- Transformed = "experimental";
- }
- pos = Transformed.rfind('/');
- if (pos != string::npos)
- {
- Transformed = Transformed.substr(0, pos);
- }
- if (Transformed == ".")
- {
- Transformed = "";
- }
- if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
- MetaIndexParser->GetValidUntil() > 0) {
- time_t const invalid_since = time(NULL) - MetaIndexParser->GetValidUntil();
- if (invalid_since > 0)
- // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
- // the time since then the file is invalid - formated in the same way as in
- // the download progress display (e.g. 7d 3h 42min 1s)
- return _error->Error(
- _("Release file for %s is expired (invalid since %s). "
- "Updates for this repository will not be applied."),
- RealURI.c_str(), TimeToStr(invalid_since).c_str());
- }
- if (_config->FindB("Debug::pkgAcquire::Auth", false))
- {
- std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
- std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
- std::cerr << "Transformed Dist: " << Transformed << std::endl;
- }
- if (MetaIndexParser->CheckDist(Transformed) == false)
- {
- // This might become fatal one day
- // Status = StatAuthError;
- // ErrorText = "Conflicting distribution; expected "
- // + MetaIndexParser->GetExpectedDist() + " but got "
- // + MetaIndexParser->GetDist();
- // return false;
- if (!Transformed.empty())
- {
- _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
- Desc.Description.c_str(),
- Transformed.c_str(),
- MetaIndexParser->GetDist().c_str());
- }
- }
- return true;
- }
- /*}}}*/
- // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)
- {
- if (AuthPass == true)
- {
- // gpgv method failed, if we have a good signature
- string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
- if (DestFile != SigFile)
- LastGoodSigFile.append(".gpg");
- LastGoodSigFile.append(".reverify");
- if(FileExists(LastGoodSigFile))
- {
- string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- if (DestFile != SigFile)
- VerifiedSigFile.append(".gpg");
- Rename(LastGoodSigFile, VerifiedSigFile);
- Status = StatTransientNetworkError;
- _error->Warning(_("An error occurred during the signature "
- "verification. The repository is not updated "
- "and the previous index files will be used. "
- "GPG error: %s: %s\n"),
- Desc.Description.c_str(),
- LookupTag(Message,"Message").c_str());
- RunScripts("APT::Update::Auth-Failure");
- return;
- } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
- /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
- _error->Error(_("GPG error: %s: %s"),
- Desc.Description.c_str(),
- LookupTag(Message,"Message").c_str());
- return;
- } else {
- _error->Warning(_("GPG error: %s: %s"),
- Desc.Description.c_str(),
- LookupTag(Message,"Message").c_str());
- }
- // gpgv method failed
- ReportMirrorFailure("GPGFailure");
- }
- /* Always move the meta index, even if gpgv failed. This ensures
- * that PackageFile objects are correctly filled in */
- if (FileExists(DestFile)) {
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(RealURI);
- /* InRelease files become Release files, otherwise
- * they would be considered as trusted later on */
- if (SigFile == DestFile) {
- RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
- "Release");
- FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
- "Release");
- SigFile = FinalFile;
- }
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
- DestFile = FinalFile;
- }
- // No Release file was present, or verification failed, so fall
- // back to queueing Packages files without verification
- QueueIndexes(false);
- }
- /*}}}*/
- pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
- string const &URI, string const &URIDesc, string const &ShortDesc,
- string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
- string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
- const vector<IndexTarget*>* IndexTargets,
- indexRecords* MetaIndexParser) :
- pkgAcqMetaIndex(Owner, URI, URIDesc, ShortDesc, "", IndexTargets, MetaIndexParser),
- MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
- MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
- {
- SigFile = DestFile;
- // index targets + (worst case:) Release/Release.gpg
- ExpectedAdditionalItems = IndexTargets->size() + 2;
- // keep the old InRelease around in case of transistent network errors
- string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- if (RealFileExists(Final) == true)
- {
- string const LastGoodSig = DestFile + ".reverify";
- Rename(Final,LastGoodSig);
- }
- }
- /*}}}*/
- pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
- {
- // if the file was never queued undo file-changes done in the constructor
- if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false)
- {
- string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- string const LastGoodSig = DestFile + ".reverify";
- if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
- Rename(LastGoodSig, Final);
- }
- }
- /*}}}*/
- // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- // FIXME: this can go away once the InRelease file is used widely
- string pkgAcqMetaClearSig::Custom600Headers() const
- {
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(RealURI);
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- {
- Final = DestFile + ".reverify";
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nIndex-File: true\nFail-Ignore: true\n";
- }
- return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
- {
- // we failed, we will not get additional items from this method
- ExpectedAdditionalItems = 0;
- if (AuthPass == false)
- {
- // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
- // the file will stay around and gives a false-auth impression (CVE-2012-0214)
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile.append(URItoFileName(RealURI));
- if (FileExists(FinalFile))
- unlink(FinalFile.c_str());
- new pkgAcqMetaSig(Owner,
- MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
- MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
- IndexTargets, MetaIndexParser);
- if (Cnf->LocalOnly == true ||
- StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)
- Dequeue();
- }
- else
- pkgAcqMetaIndex::Failed(Message, Cnf);
- }
- /*}}}*/
- // AcqArchive::AcqArchive - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* This just sets up the initial fetch environment and queues the first
- possibilitiy */
- pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
- pkgRecords *Recs,pkgCache::VerIterator const &Version,
- string &StoreFilename) :
- Item(Owner, HashStringList()), Version(Version), Sources(Sources), Recs(Recs),
- StoreFilename(StoreFilename), Vf(Version.FileList()),
- Trusted(false)
- {
- Retries = _config->FindI("Acquire::Retries",0);
- if (Version.Arch() == 0)
- {
- _error->Error(_("I wasn't able to locate a file for the %s package. "
- "This might mean you need to manually fix this package. "
- "(due to missing arch)"),
- Version.ParentPkg().FullName().c_str());
- return;
- }
-
- /* We need to find a filename to determine the extension. We make the
- assumption here that all the available sources for this version share
- the same extension.. */
- // Skip not source sources, they do not have file fields.
- for (; Vf.end() == false; ++Vf)
- {
- if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
- continue;
- break;
- }
-
- // Does not really matter here.. we are going to fail out below
- if (Vf.end() != true)
- {
- // If this fails to get a file name we will bomb out below.
- pkgRecords::Parser &Parse = Recs->Lookup(Vf);
- if (_error->PendingError() == true)
- return;
-
- // Generate the final file name as: package_version_arch.foo
- StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
- QuoteString(Version.VerStr(),"_:") + '_' +
- QuoteString(Version.Arch(),"_:.") +
- "." + flExtension(Parse.FileName());
- }
- // check if we have one trusted source for the package. if so, switch
- // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
- bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false);
- bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false);
- bool seenUntrusted = false;
- for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; ++i)
- {
- pkgIndexFile *Index;
- if (Sources->FindIndex(i.File(),Index) == false)
- continue;
- if (debugAuth == true)
- std::cerr << "Checking index: " << Index->Describe()
- << "(Trusted=" << Index->IsTrusted() << ")" << std::endl;
- if (Index->IsTrusted() == true)
- {
- Trusted = true;
- if (allowUnauth == false)
- break;
- }
- else
- seenUntrusted = true;
- }
- // "allow-unauthenticated" restores apts old fetching behaviour
- // that means that e.g. unauthenticated file:// uris are higher
- // priority than authenticated http:// uris
- if (allowUnauth == true && seenUntrusted == true)
- Trusted = false;
- // Select a source
- if (QueueNext() == false && _error->PendingError() == false)
- _error->Error(_("Can't find a source to download version '%s' of '%s'"),
- Version.VerStr(), Version.ParentPkg().FullName(false).c_str());
- }
- /*}}}*/
- // AcqArchive::QueueNext - Queue the next file source /*{{{*/
- // ---------------------------------------------------------------------
- /* This queues the next available file version for download. It checks if
- the archive is already available in the cache and stashs the MD5 for
- checking later. */
- bool pkgAcqArchive::QueueNext()
- {
- for (; Vf.end() == false; ++Vf)
- {
- // Ignore not source sources
- if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
- continue;
- // Try to cross match against the source list
- pkgIndexFile *Index;
- if (Sources->FindIndex(Vf.File(),Index) == false)
- continue;
-
- // only try to get a trusted package from another source if that source
- // is also trusted
- if(Trusted && !Index->IsTrusted())
- continue;
- // Grab the text package record
- pkgRecords::Parser &Parse = Recs->Lookup(Vf);
- if (_error->PendingError() == true)
- return false;
- string PkgFile = Parse.FileName();
- ExpectedHashes = Parse.Hashes();
- if (PkgFile.empty() == true)
- return _error->Error(_("The package index files are corrupted. No Filename: "
- "field for package %s."),
- Version.ParentPkg().Name());
- Desc.URI = Index->ArchiveURI(PkgFile);
- Desc.Description = Index->ArchiveInfo(Version);
- Desc.Owner = this;
- Desc.ShortDesc = Version.ParentPkg().FullName(true);
- // See if we already have the file. (Legacy filenames)
- FileSize = Version->Size;
- string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
- struct stat Buf;
- if (stat(FinalFile.c_str(),&Buf) == 0)
- {
- // Make sure the size matches
- if ((unsigned long long)Buf.st_size == Version->Size)
- {
- Complete = true;
- Local = true;
- Status = StatDone;
- StoreFilename = DestFile = FinalFile;
- return true;
- }
-
- /* Hmm, we have a file and its size does not match, this means it is
- an old style mismatched arch */
- unlink(FinalFile.c_str());
- }
- // Check it again using the new style output filenames
- FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
- if (stat(FinalFile.c_str(),&Buf) == 0)
- {
- // Make sure the size matches
- if ((unsigned long long)Buf.st_size == Version->Size)
- {
- Complete = true;
- Local = true;
- Status = StatDone;
- StoreFilename = DestFile = FinalFile;
- return true;
- }
-
- /* Hmm, we have a file and its size does not match, this shouldn't
- happen.. */
- unlink(FinalFile.c_str());
- }
- DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
-
- // Check the destination file
- if (stat(DestFile.c_str(),&Buf) == 0)
- {
- // Hmm, the partial file is too big, erase it
- if ((unsigned long long)Buf.st_size > Version->Size)
- unlink(DestFile.c_str());
- else
- PartialSize = Buf.st_size;
- }
- // Disables download of archives - useful if no real installation follows,
- // e.g. if we are just interested in proposed installation order
- if (_config->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
- {
- Complete = true;
- Local = true;
- Status = StatDone;
- StoreFilename = DestFile = FinalFile;
- return true;
- }
- // Create the item
- Local = false;
- QueueURI(Desc);
- ++Vf;
- return true;
- }
- return false;
- }
- /*}}}*/
- // AcqArchive::Done - Finished fetching /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqArchive::Done(string Message,unsigned long long Size, HashStringList const &CalcHashes,
- pkgAcquire::MethodConfig *Cfg)
- {
- Item::Done(Message, Size, CalcHashes, Cfg);
-
- // Check the size
- if (Size != Version->Size)
- {
- RenameOnError(SizeMismatch);
- return;
- }
- // FIXME: could this empty() check impose *any* sort of security issue?
- if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
- {
- RenameOnError(HashSumMismatch);
- printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
- return;
- }
- // Grab the output filename
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
- Complete = true;
- // Reference filename
- if (FileName != DestFile)
- {
- StoreFilename = DestFile = FileName;
- Local = true;
- return;
- }
-
- // Done, move it into position
- string FinalFile = _config->FindDir("Dir::Cache::Archives");
- FinalFile += flNotDir(StoreFilename);
- Rename(DestFile,FinalFile);
-
- StoreFilename = DestFile = FinalFile;
- Complete = true;
- }
- /*}}}*/
- // AcqArchive::Failed - Failure handler /*{{{*/
- // ---------------------------------------------------------------------
- /* Here we try other sources */
- void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
- {
- ErrorText = LookupTag(Message,"Message");
-
- /* We don't really want to retry on failed media swaps, this prevents
- that. An interesting observation is that permanent failures are not
- recorded. */
- if (Cnf->Removable == true &&
- StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
- {
- // Vf = Version.FileList();
- while (Vf.end() == false) ++Vf;
- StoreFilename = string();
- Item::Failed(Message,Cnf);
- return;
- }
-
- if (QueueNext() == false)
- {
- // This is the retry counter
- if (Retries != 0 &&
- Cnf->LocalOnly == false &&
- StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
- {
- Retries--;
- Vf = Version.FileList();
- if (QueueNext() == true)
- return;
- }
-
- StoreFilename = string();
- Item::Failed(Message,Cnf);
- }
- }
- /*}}}*/
- // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
- // ---------------------------------------------------------------------
- APT_PURE bool pkgAcqArchive::IsTrusted() const
- {
- return Trusted;
- }
- /*}}}*/
- // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqArchive::Finished()
- {
- if (Status == pkgAcquire::Item::StatDone &&
- Complete == true)
- return;
- StoreFilename = string();
- }
- /*}}}*/
- // AcqFile::pkgAcqFile - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* The file is added to the queue */
- pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI, HashStringList const &Hashes,
- unsigned long long Size,string Dsc,string ShortDesc,
- const string &DestDir, const string &DestFilename,
- bool IsIndexFile) :
- Item(Owner, Hashes), IsIndexFile(IsIndexFile)
- {
- Retries = _config->FindI("Acquire::Retries",0);
-
- if(!DestFilename.empty())
- DestFile = DestFilename;
- else if(!DestDir.empty())
- DestFile = DestDir + "/" + flNotDir(URI);
- else
- DestFile = flNotDir(URI);
- // Create the item
- Desc.URI = URI;
- Desc.Description = Dsc;
- Desc.Owner = this;
- // Set the short description to the archive component
- Desc.ShortDesc = ShortDesc;
-
- // Get the transfer sizes
- FileSize = Size;
- struct stat Buf;
- if (stat(DestFile.c_str(),&Buf) == 0)
- {
- // Hmm, the partial file is too big, erase it
- if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
- unlink(DestFile.c_str());
- else
- PartialSize = Buf.st_size;
- }
- QueueURI(Desc);
- }
- /*}}}*/
- // AcqFile::Done - Item downloaded OK /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqFile::Done(string Message,unsigned long long Size,HashStringList const &CalcHashes,
- pkgAcquire::MethodConfig *Cnf)
- {
- Item::Done(Message,Size,CalcHashes,Cnf);
- // Check the hash
- if(ExpectedHashes.usable() && ExpectedHashes != CalcHashes)
- {
- RenameOnError(HashSumMismatch);
- printHashSumComparision(DestFile, ExpectedHashes, CalcHashes);
- return;
- }
-
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
- Complete = true;
-
- // The files timestamp matches
- if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
- return;
-
- // We have to copy it into place
- if (FileName != DestFile)
- {
- Local = true;
- if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
- Cnf->Removable == true)
- {
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- return;
- }
-
- // Erase the file if it is a symlink so we can overwrite it
- struct stat St;
- if (lstat(DestFile.c_str(),&St) == 0)
- {
- if (S_ISLNK(St.st_mode) != 0)
- unlink(DestFile.c_str());
- }
-
- // Symlink the file
- if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
- {
- ErrorText = "Link to " + DestFile + " failure ";
- Status = StatError;
- Complete = false;
- }
- }
- }
- /*}}}*/
- // AcqFile::Failed - Failure handler /*{{{*/
- // ---------------------------------------------------------------------
- /* Here we try other sources */
- void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
- {
- ErrorText = LookupTag(Message,"Message");
-
- // This is the retry counter
- if (Retries != 0 &&
- Cnf->LocalOnly == false &&
- StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
- {
- Retries--;
- QueueURI(Desc);
- return;
- }
-
- Item::Failed(Message,Cnf);
- }
- /*}}}*/
- // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqFile::Custom600Headers() const
- {
- if (IsIndexFile)
- return "\nIndex-File: true";
- return "";
- }
- /*}}}*/
|