Working acquire code
[ntk/apt.git] / apt-pkg / acquire-item.cc
index e92b611..9f9d082 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: acquire-item.cc,v 1.2 1998/10/20 02:39:12 jgg Exp $
+// $Id: acquire-item.cc,v 1.7 1998/11/05 07:21:35 jgg Exp $
 /* ######################################################################
 
    Acquire Item - Item to acquire
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/configuration.h>
 #include <strutl.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
                                                                        /*}}}*/
 
 // Acquire::Item::Item - Constructor                                   /*{{{*/
@@ -27,6 +33,7 @@
 pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), QueueCounter(0)
 {
    Owner->Add(this);
+   Status = StatIdle;
 }
                                                                        /*}}}*/
 // Acquire::Item::~Item - Destructor                                   /*{{{*/
@@ -37,6 +44,47 @@ 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)
+   {
+      ErrorText = LookupTag(Message,"Message");
+      Status = StatError;
+      Owner->Dequeue(this);
+   }   
+}
+                                                                       /*}}}*/
+// Acquire::Item::Done - Item downloaded OK                            /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcquire::Item::Done(string,unsigned long,string)
+{
+   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                                    /*{{{*/
 // ---------------------------------------------------------------------
@@ -45,20 +93,94 @@ pkgAcquire::Item::~Item()
 pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) :
              Item(Owner), Location(Location)
 {
-   QueueURI(Location->PackagesURI() + ".gz");
-   Description = Location->PackagesInfo();
+   Decompression = false;
+   Erase = false;
+   
+   DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+   DestFile += URItoFileName(Location->PackagesURI());
    
+   QueueURI(Location->PackagesURI() + ".gz",Location->PackagesInfo());
+   
+   // Create the Release fetch class
    new pkgAcqIndexRel(Owner,Location);
 }
                                                                        /*}}}*/
-// pkgAcqIndex::ToFile - File to write the download to                 /*{{{*/
+// AcqIndex::Custom600Headers - Insert custom request headers          /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-string pkgAcqIndex::ToFile()
+/* 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 string();
+   
+   return "\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)
 {
-   string PartialDir = _config->FindFile("Dir::State::lists") + "/partial/";
+   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);
+      
+      // Remove the compressed version.
+      if (Erase == true)
+      {
+        DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+        DestFile += URItoFileName(Location->PackagesURI());
+        unlink(DestFile.c_str());
+      }      
+      return;
+   }
+
+   Erase = false;
    
-   return PartialDir + URItoFileName(Location->PackagesURI());
+   // 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;
+      DestFile += ".decomp";
+      QueueURI("copy:" + FileName,string());
+      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;
+   
+   Decompression = true;
+   DestFile += ".decomp";
+   QueueURI("gzip:" + FileName,string());
 }
                                                                        /*}}}*/
 
@@ -69,17 +191,58 @@ pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
                               const pkgSourceList::Item *Location) :
                 Item(Owner), Location(Location)
 {
-   QueueURI(Location->ReleaseURI());
-   Description = Location->ReleaseInfo();
+   DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+   DestFile += URItoFileName(Location->ReleaseURI());
+   
+   QueueURI(Location->ReleaseURI(),Location->ReleaseInfo());
+}
+                                                                       /*}}}*/
+// 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 string();
+   
+   return "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
 }
                                                                        /*}}}*/
-// AcqIndexRel::ToFile - File to write the download to                 /*{{{*/
+// AcqIndexRel::Done - Item downloaded OK                              /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-string pkgAcqIndexRel::ToFile()
+/* 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)
 {
-   string PartialDir = _config->FindFile("Dir::State::lists") + "/partial/";
+   Item::Done(Message,Size,MD5);
+
+   string FileName = LookupTag(Message,"Filename");
+   if (FileName.empty() == true)
+   {
+      Status = StatError;
+      ErrorText = "Method gave a blank filename";
+      return;
+   }
+
+   // The files timestamp matches
+   if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+      return;
+   
+   // We have to copy it into place
+   if (FileName != DestFile)
+   {
+      QueueURI("copy:" + FileName,string());
+      return;
+   }
    
-   return PartialDir + URItoFileName(Location->ReleaseURI());
+   // Done, move it into position
+   string FinalFile = _config->FindDir("Dir::State::lists");
+   FinalFile += URItoFileName(Location->ReleaseURI());
+   Rename(DestFile,FinalFile);
 }
                                                                        /*}}}*/