]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/acquire-worker.cc
mark internal interfaces as hidden
[apt.git] / apt-pkg / acquire-worker.cc
index 4f0b52af9739e213d5ef55d578bcbf5250c8f74e..724bdfd49ee313e4e0a27fabc9ea21f23a8f05c3 100644 (file)
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include <config.h>
+
+#include <apt-pkg/acquire.h>
 #include <apt-pkg/acquire-worker.h>
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/hashes.h>
 
-#include <apti18n.h>
-
+#include <string>
+#include <vector>
 #include <iostream>
 #include <sstream>
-#include <fstream>
-    
+
 #include <sys/stat.h>
+#include <stdlib.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <apti18n.h>
                                                                        /*}}}*/
 
 using namespace std;
 
+static void ChangeOwnerAndPermissionOfFile(char const * const requester, char const * const file, char const * const user, char const * const group, mode_t const mode) /*{{{*/
+{
+   if (getuid() == 0 && strlen(user) != 0 && strlen(group) != 0) // if we aren't root, we can't chown, so don't try it
+   {
+      // ensure the file is owned by root and has good permissions
+      struct passwd const * const pw = getpwnam(user);
+      struct group const * const gr = getgrnam(group);
+      if (pw != NULL && gr != NULL && chown(file, pw->pw_uid, gr->gr_gid) != 0)
+        _error->WarningE(requester, "chown to %s:%s of file %s failed", user, group, file);
+   }
+   if (chmod(file, mode) != 0)
+      _error->WarningE(requester, "chmod 0%o of file %s failed", mode, file);
+}
+                                                                       /*}}}*/
 // Worker::Worker - Constructor for Queue startup                      /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -107,7 +129,12 @@ bool pkgAcquire::Worker::Start()
    // Get the method path
    string Method = _config->FindDir("Dir::Bin::Methods") + Access;
    if (FileExists(Method) == false)
-      return _error->Error(_("The method driver %s could not be found."),Method.c_str());
+   {
+      _error->Error(_("The method driver %s could not be found."),Method.c_str());
+      if (Access == "https")
+        _error->Notice(_("Is the package %s installed?"), "apt-transport-https");
+      return false;
+   }
 
    if (Debug == true)
       clog << "Starting method '" << Method << '\'' << endl;
@@ -199,6 +226,17 @@ bool pkgAcquire::Worker::RunMessages()
       pkgAcquire::Queue::QItem *Itm = 0;
       if (URI.empty() == false)
         Itm = OwnerQ->FindItem(URI,this);
+
+      // update used mirror
+      string UsedMirror = LookupTag(Message,"UsedMirror", "");
+      if (!UsedMirror.empty() && 
+          Itm && 
+          Itm->Description.find(" ") != string::npos) 
+      {
+         Itm->Description.replace(0, Itm->Description.find(" "), UsedMirror);
+         // FIXME: will we need this as well?
+         //Itm->ShortDesc = UsedMirror;
+      }
       
       // Determine the message number and dispatch
       switch (Number)
@@ -231,6 +269,21 @@ bool pkgAcquire::Worker::RunMessages()
  
             string NewURI = LookupTag(Message,"New-URI",URI.c_str());
             Itm->URI = NewURI;
+
+           ItemDone();
+
+           pkgAcquire::Item *Owner = Itm->Owner;
+           pkgAcquire::ItemDesc Desc = *Itm;
+
+           // Change the status so that it can be dequeued
+           Owner->Status = pkgAcquire::Item::StatIdle;
+           // Mark the item as done (taking care of all queues)
+           // and then put it in the main queue again
+           OwnerQ->ItemDone(Itm);
+           OwnerQ->Owner->Enqueue(Desc);
+
+           if (Log != 0)
+              Log->Done(Desc);
             break;
          }
    
@@ -245,9 +298,9 @@ bool pkgAcquire::Worker::RunMessages()
            
            CurrentItem = Itm;
            CurrentSize = 0;
-           TotalSize = atoi(LookupTag(Message,"Size","0").c_str());
-           ResumePoint = atoi(LookupTag(Message,"Resume-Point","0").c_str());
-           Itm->Owner->Start(Message,atoi(LookupTag(Message,"Size","0").c_str()));
+           TotalSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
+           ResumePoint = strtoull(LookupTag(Message,"Resume-Point","0").c_str(), NULL, 10);
+           Itm->Owner->Start(Message,strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10));
 
            // Display update before completion
            if (Log != 0 && Log->MorePulses == true)
@@ -270,43 +323,57 @@ bool pkgAcquire::Worker::RunMessages()
            
            pkgAcquire::Item *Owner = Itm->Owner;
            pkgAcquire::ItemDesc Desc = *Itm;
-           
+
+           if (RealFileExists(Owner->DestFile))
+              ChangeOwnerAndPermissionOfFile("201::URIDone", Owner->DestFile.c_str(), "root", "root", 0644);
+
            // Display update before completion
            if (Log != 0 && Log->MorePulses == true)
               Log->Pulse(Owner->GetOwner());
            
            OwnerQ->ItemDone(Itm);
-           if (TotalSize != 0 &&
-               (unsigned)atoi(LookupTag(Message,"Size","0").c_str()) != TotalSize)
-              _error->Warning("Bizarre Error - File size is not what the server reported %s %lu",
-                              LookupTag(Message,"Size","0").c_str(),TotalSize);
+           unsigned long long const ServerSize = strtoull(LookupTag(Message,"Size","0").c_str(), NULL, 10);
+            bool isHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
+                         StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
+            // Using the https method the server might return 200, but the
+            // If-Modified-Since condition is not satsified, libcurl will
+            // discard the download. In this case, however, TotalSize will be
+            // set to the actual size of the file, while ServerSize will be set
+            // to 0. Therefore, if the item is marked as a hit and the
+            // downloaded size (ServerSize) is 0, we ignore TotalSize.
+           if (TotalSize != 0 && (!isHit || ServerSize != 0) && ServerSize != TotalSize)
+              _error->Warning("Size of file %s is not what the server reported %s %llu",
+                              Owner->DestFile.c_str(), LookupTag(Message,"Size","0").c_str(),TotalSize);
 
            // see if there is a hash to verify
-           string RecivedHash;
-           HashString expectedHash(Owner->HashSum());
-           if(!expectedHash.empty()) 
+           HashStringList RecivedHashes;
+           HashStringList expectedHashes = Owner->HashSums();
+           for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
            {
-              string hashTag = expectedHash.HashType()+"-Hash";
-              string hashSum = LookupTag(Message, hashTag.c_str());
-              if(!hashSum.empty())
-                 RecivedHash = expectedHash.HashType() + ":" + hashSum;
-              if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
-              {
-                 clog << "201 URI Done: " << Owner->DescURI() << endl
-                      << "RecivedHash: " << RecivedHash << endl
-                      << "ExpectedHash: " << expectedHash.toStr() 
-                      << endl << endl;
-              }
+              std::string const tagname = hs->HashType() + "-Hash";
+              std::string const hashsum = LookupTag(Message, tagname.c_str());
+              if (hashsum.empty() == false)
+                 RecivedHashes.push_back(HashString(hs->HashType(), hashsum));
+           }
+
+           if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
+           {
+              std::clog << "201 URI Done: " << Owner->DescURI() << endl
+                 << "RecivedHash:" << endl;
+              for (HashStringList::const_iterator hs = RecivedHashes.begin(); hs != RecivedHashes.end(); ++hs)
+                 std::clog <<  "\t- " << hs->toStr() << std::endl;
+              std::clog << "ExpectedHash:" << endl;
+              for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
+                 std::clog <<  "\t- " << hs->toStr() << std::endl;
+              std::clog << endl;
            }
-           Owner->Done(Message,atoi(LookupTag(Message,"Size","0").c_str()),
-                       RecivedHash.c_str(), Config);
+           Owner->Done(Message, ServerSize, RecivedHashes, Config);
            ItemDone();
-           
+
            // Log that we are done
            if (Log != 0)
            {
-              if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true ||
-                  StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
+              if (isHit)
               {
                  /* Hide 'hits' for local only sources - we also manage to
                     hide gets */
@@ -324,16 +391,21 @@ bool pkgAcquire::Worker::RunMessages()
         {
            if (Itm == 0)
            {
-              _error->Error("Method gave invalid 400 URI Failure message");
+              std::string const msg = LookupTag(Message,"Message");
+              _error->Error("Method gave invalid 400 URI Failure message: %s", msg.c_str());
               break;
            }
 
            // Display update before completion
            if (Log != 0 && Log->MorePulses == true)
               Log->Pulse(Itm->Owner->GetOwner());
-           
+
            pkgAcquire::Item *Owner = Itm->Owner;
            pkgAcquire::ItemDesc Desc = *Itm;
+
+           if (RealFileExists(Owner->DestFile))
+              ChangeOwnerAndPermissionOfFile("400::URIFailure", Owner->DestFile.c_str(), "root", "root", 0644);
+
            OwnerQ->ItemDone(Itm);
 
            // set some status
@@ -419,7 +491,9 @@ bool pkgAcquire::Worker::MediaChange(string Message)
             << Drive  << ":"     // drive
             << msg.str()         // l10n message
             << endl;
-      write(status_fd, status.str().c_str(), status.str().size());
+
+      std::string const dlstatus = status.str();
+      FileFd::Write(status_fd, dlstatus.c_str(), dlstatus.size());
    }
 
    if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
@@ -453,40 +527,19 @@ bool pkgAcquire::Worker::SendConfiguration()
 
    if (OutFd == -1)
       return false;
-   
-   string Message = "601 Configuration\n";
-   Message.reserve(2000);
 
-   /* Write out all of the configuration directives by walking the 
+   /* Write out all of the configuration directives by walking the
       configuration tree */
-   const Configuration::Item *Top = _config->Tree(0);
-   for (; Top != 0;)
-   {
-      if (Top->Value.empty() == false)
-      {
-        string Line = "Config-Item: " + QuoteString(Top->FullTag(),"=\"\n") + "=";
-        Line += QuoteString(Top->Value,"\n") + '\n';
-        Message += Line;
-      }
-      
-      if (Top->Child != 0)
-      {
-        Top = Top->Child;
-        continue;
-      }
-      
-      while (Top != 0 && Top->Next == 0)
-        Top = Top->Parent;
-      if (Top != 0)
-        Top = Top->Next;
-   }   
-   Message += '\n';
+   std::ostringstream Message;
+   Message << "601 Configuration\n";
+   _config->Dump(Message, NULL, "Config-Item: %F=%V\n", false);
+   Message << '\n';
 
    if (Debug == true)
-      clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
-   OutQueue += Message;
-   OutReady = true; 
-   
+      clog << " -> " << Access << ':' << QuoteString(Message.str(),"\n") << endl;
+   OutQueue += Message.str();
+   OutReady = true;
+
    return true;
 }
                                                                        /*}}}*/
@@ -502,9 +555,25 @@ bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
    Message.reserve(300);
    Message += "URI: " + Item->URI;
    Message += "\nFilename: " + Item->Owner->DestFile;
+   HashStringList const hsl = Item->Owner->HashSums();
+   for (HashStringList::const_iterator hs = hsl.begin(); hs != hsl.end(); ++hs)
+      Message += "\nExpected-" + hs->HashType() + ": " + hs->HashValue();
+   if(Item->Owner->FileSize > 0)
+   {
+      string MaximumSize;
+      strprintf(MaximumSize, "%llu", Item->Owner->FileSize);
+      Message += "\nMaximum-Size: " + MaximumSize;
+   }
    Message += Item->Owner->Custom600Headers();
    Message += "\n\n";
-   
+
+   if (RealFileExists(Item->Owner->DestFile))
+   {
+      std::string SandboxUser = _config->Find("APT::Sandbox::User");
+      ChangeOwnerAndPermissionOfFile("Item::QueueURI", Item->Owner->DestFile.c_str(),
+                                     SandboxUser.c_str(), "root", 0600);
+   }
+
    if (Debug == true)
       clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
    OutQueue += Message;
@@ -524,10 +593,10 @@ bool pkgAcquire::Worker::OutFdReady()
       Res = write(OutFd,OutQueue.c_str(),OutQueue.length());
    }
    while (Res < 0 && errno == EINTR);
-   
+
    if (Res <= 0)
       return MethodFailure();
-   
+
    OutQueue.erase(0,Res);
    if (OutQueue.empty() == true)
       OutReady = false;
@@ -548,7 +617,7 @@ bool pkgAcquire::Worker::InFdReady()
                                                                        /*}}}*/
 // Worker::MethodFailure - Called when the method fails                        /*{{{*/
 // ---------------------------------------------------------------------
-/* This is called when the method is belived to have failed, probably because
+/* This is called when the method is believed to have failed, probably because
    read returned -1. */
 bool pkgAcquire::Worker::MethodFailure()
 {