| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $Id: acquire-item.cc,v 1.14 1998/11/29 01:24:14 jgg 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 /*{{{*/
- #ifdef __GNUG__
- #pragma implementation "apt-pkg/acquire-item.h"
- #endif
- #include <apt-pkg/acquire-item.h>
- #include <apt-pkg/configuration.h>
- #include <apt-pkg/error.h>
- #include <strutl.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <stdio.h>
- /*}}}*/
- // Acquire::Item::Item - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
- Mode(0), ID(0), Complete(false), Local(false),
- QueueCounter(0)
- {
- Owner->Add(this);
- Status = StatIdle;
- }
- /*}}}*/
- // 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)
- {
- Status = StatIdle;
- 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 */
- if (StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
- {
- Status = StatIdle;
- Owner->Dequeue(this);
- return;
- }
-
- ErrorText = LookupTag(Message,"Message");
- Status = StatError;
- Owner->Dequeue(this);
- }
- }
- /*}}}*/
- // Acquire::Item::Start - Item has begun to download /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcquire::Item::Start(string Message,unsigned 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 Size,string)
- {
- // We just downloaded something..
- string FileName = LookupTag(Message,"Filename");
- if (Complete == false && FileName == DestFile)
- {
- if (Owner->Log != 0)
- Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
- }
-
- Status = StatDone;
- ErrorText = string();
- Owner->Dequeue(this);
- }
- /*}}}*/
- // Acquire::Item::Rename - Rename a file /*{{{*/
- // ---------------------------------------------------------------------
- /* This helper function is used by alot of item methods as thier final
- step */
- void pkgAcquire::Item::Rename(string From,string To)
- {
- if (rename(From.c_str(),To.c_str()) != 0)
- {
- char S[300];
- sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno),
- From.c_str(),To.c_str());
- Status = StatError;
- ErrorText = S;
- }
- }
- /*}}}*/
- // 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,const pkgSourceList::Item *Location) :
- Item(Owner), Location(Location)
- {
- Decompression = false;
- Erase = false;
-
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(Location->PackagesURI());
- // Create the item
- Desc.URI = Location->PackagesURI() + ".gz";
- Desc.Description = Location->PackagesInfo();
- Desc.Owner = this;
- // Set the short description to the archive component
- if (Location->Dist[Location->Dist.size() - 1] == '/')
- Desc.ShortDesc = Location->Dist;
- else
- Desc.ShortDesc = Location->Dist + '/' + Location->Section;
-
- QueueURI(Desc);
-
- // Create the Release fetch class
- new pkgAcqIndexRel(Owner,Location);
- }
- /*}}}*/
- // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqIndex::Custom600Headers()
- {
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(Location->PackagesURI());
-
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nIndex-File: true";
-
- return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- // 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 Size,string MD5)
- {
- Item::Done(Message,Size,MD5);
- if (Decompression == true)
- {
- // Done, move it into position
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(Location->PackagesURI());
- Rename(DestFile,FinalFile);
-
- /* We restore the original name to DestFile so that the clean operation
- will work OK */
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(Location->PackagesURI());
-
- // 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)
- {
- // The files timestamp matches
- if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
- return;
-
- Decompression = true;
- Local = true;
- DestFile += ".decomp";
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- Mode = "copy";
- return;
- }
- FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- }
-
- // The files timestamp matches
- if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
- return;
- if (FileName == DestFile)
- Erase = true;
- else
- Local = true;
-
- Decompression = true;
- DestFile += ".decomp";
- Desc.URI = "gzip:" + FileName,Location->PackagesInfo();
- QueueURI(Desc);
- Mode = "gzip";
- }
- /*}}}*/
- // AcqIndex::Describe - Describe the Item /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- string pkgAcqIndex::Describe()
- {
- return Location->PackagesURI();
- }
- /*}}}*/
- // AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* The Release file is added to the queue */
- pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
- const pkgSourceList::Item *Location) :
- Item(Owner), Location(Location)
- {
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(Location->ReleaseURI());
-
- // Create the item
- Desc.URI = Location->ReleaseURI();
- Desc.Description = Location->ReleaseInfo();
- Desc.Owner = this;
- // Set the short description to the archive component
- if (Location->Dist[Location->Dist.size() - 1] == '/')
- Desc.ShortDesc = Location->Dist;
- else
- Desc.ShortDesc = Location->Dist + '/' + Location->Section;
-
- QueueURI(Desc);
- }
- /*}}}*/
- // AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
- // ---------------------------------------------------------------------
- /* The only header we use is the last-modified header. */
- string pkgAcqIndexRel::Custom600Headers()
- {
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(Location->ReleaseURI());
-
- struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
- return "\nIndex-File: true";
-
- return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
- }
- /*}}}*/
- // AcqIndexRel::Done - Item downloaded OK /*{{{*/
- // ---------------------------------------------------------------------
- /* The release file was not placed into the download directory then
- a copy URI is generated and it is copied there otherwise the file
- in the partial directory is moved into .. and the URI is finished. */
- void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5)
- {
- Item::Done(Message,Size,MD5);
- 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;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- return;
- }
-
- // Done, move it into position
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(Location->ReleaseURI());
- Rename(DestFile,FinalFile);
- }
- /*}}}*/
- // AcqIndexRel::Describe - Describe the Item /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- string pkgAcqIndexRel::Describe()
- {
- return Location->ReleaseURI();
- }
- /*}}}*/
- // AcqArchive::AcqArchive - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
- pkgRecords *Recs,pkgCache::VerIterator const &Version,
- string &StoreFilename) :
- Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
- StoreFilename(StoreFilename)
- {
- // Select a source
- pkgCache::VerFileIterator Vf = Version.FileList();
- 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
- string PkgFile = flNotDir(Vf.File().FileName());
- pkgSourceList::const_iterator Location;
- for (Location = Sources->begin(); Location != Sources->end(); Location++)
- if (PkgFile == URItoFileName(Location->PackagesURI()))
- break;
- if (Location == Sources->end())
- continue;
-
- // Grab the text package record
- pkgRecords::Parser &Parse = Recs->Lookup(Vf);
- if (_error->PendingError() == true)
- return;
-
- PkgFile = Parse.FileName();
- MD5 = Parse.MD5Hash();
- if (PkgFile.empty() == true)
- {
- _error->Error("Unable to locate a file name for package %s, "
- "perhaps the package files are corrupted.",
- Version.ParentPkg().Name());
- return;
- }
- // See if we already have the file.
- 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)Buf.st_size == Version->Size)
- {
- Complete = true;
- Local = true;
- Status = StatDone;
- StoreFilename = DestFile = FinalFile;
- return;
- }
-
- /* Hmm, we have a file and its size does not match, this shouldnt
- happen.. */
- unlink(FinalFile.c_str());
- }
-
- DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(PkgFile);
-
- // Create the item
- Desc.URI = Location->ArchiveURI(PkgFile);
- Desc.Description = Location->ArchiveInfo(Version);
- Desc.Owner = this;
- Desc.ShortDesc = Version.ParentPkg().Name();
- QueueURI(Desc);
-
- return;
- }
-
- _error->Error("I wasn't able to locate file for the %s package. "
- "This probably means you need to rerun update.",
- Version.ParentPkg().Name());
- }
- /*}}}*/
- // AcqArchive::Done - Finished fetching /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash)
- {
- Item::Done(Message,Size,MD5);
-
- // Check the size
- if (Size != Version->Size)
- {
- _error->Error("Size mismatch for package %s",Version.ParentPkg().Name());
- return;
- }
-
- // Check the md5
- if (Md5Hash.empty() == false && MD5.empty() == false)
- {
- if (Md5Hash != MD5)
- {
- _error->Error("MD5Sum mismatch for package %s",Version.ParentPkg().Name());
- 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(DestFile);
- Rename(DestFile,FinalFile);
-
- StoreFilename = DestFile = FinalFile;
- Complete = true;
- }
- /*}}}*/
- // AcqArchive::Describe - Describe the Item /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- string pkgAcqArchive::Describe()
- {
- return Desc.URI;
- }
- /*}}}*/
|