diff options
Diffstat (limited to 'methods')
-rw-r--r-- | methods/cdrom.cc | 6 | ||||
-rw-r--r-- | methods/connect.cc | 8 | ||||
-rw-r--r-- | methods/copy.cc | 23 | ||||
-rw-r--r-- | methods/file.cc | 5 | ||||
-rw-r--r-- | methods/ftp.cc | 64 | ||||
-rw-r--r-- | methods/ftp.h | 6 | ||||
-rw-r--r-- | methods/gpgv.cc | 17 | ||||
-rw-r--r-- | methods/gzip.cc | 67 | ||||
-rw-r--r-- | methods/http.cc | 41 | ||||
-rw-r--r-- | methods/http.h | 6 | ||||
-rw-r--r-- | methods/http_main.cc | 5 | ||||
-rw-r--r-- | methods/https.cc | 40 | ||||
-rw-r--r-- | methods/https.h | 27 | ||||
-rw-r--r-- | methods/mirror.cc | 54 | ||||
-rw-r--r-- | methods/mirror.h | 4 | ||||
-rw-r--r-- | methods/rfc2553emu.h | 2 | ||||
-rw-r--r-- | methods/rred.cc | 1186 | ||||
-rw-r--r-- | methods/rsh.cc | 48 | ||||
-rw-r--r-- | methods/rsh.h | 4 | ||||
-rw-r--r-- | methods/server.cc | 90 | ||||
-rw-r--r-- | methods/server.h | 11 |
21 files changed, 914 insertions, 800 deletions
diff --git a/methods/cdrom.cc b/methods/cdrom.cc index 22d4b9164..74e2ecc6b 100644 --- a/methods/cdrom.cc +++ b/methods/cdrom.cc @@ -19,9 +19,9 @@ #include <apt-pkg/strutl.h> #include <apt-pkg/hashes.h> +#include <string> +#include <vector> #include <sys/stat.h> -#include <unistd.h> -#include <dlfcn.h> #include <iostream> #include <apti18n.h> @@ -62,7 +62,7 @@ CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly | MountedByApt(false) { UdevCdroms.Dlopen(); -}; +} /*}}}*/ // CDROMMethod::Exit - Unmount the disc if necessary /*{{{*/ // --------------------------------------------------------------------- diff --git a/methods/connect.cc b/methods/connect.cc index fc7a72ee9..e2cbf4f5c 100644 --- a/methods/connect.cc +++ b/methods/connect.cc @@ -23,7 +23,7 @@ #include <errno.h> #include <unistd.h> #include <sstream> - +#include <string.h> #include<set> #include<string> @@ -142,9 +142,9 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, // Convert the port name/number char ServStr[300]; if (Port != 0) - snprintf(ServStr,sizeof(ServStr),"%u",Port); + snprintf(ServStr,sizeof(ServStr),"%i", Port); else - snprintf(ServStr,sizeof(ServStr),"%s",Service); + snprintf(ServStr,sizeof(ServStr),"%s", Service); /* We used a cached address record.. Yes this is against the spec but the way we have setup our rotating dns suggests that this is more @@ -190,7 +190,7 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, { if (DefPort != 0) { - snprintf(ServStr,sizeof(ServStr),"%u",DefPort); + snprintf(ServStr, sizeof(ServStr), "%i", DefPort); DefPort = 0; continue; } diff --git a/methods/copy.cc b/methods/copy.cc index e81d0022b..d59f032ff 100644 --- a/methods/copy.cc +++ b/methods/copy.cc @@ -17,9 +17,10 @@ #include <apt-pkg/error.h> #include <apt-pkg/hashes.h> +#include <string> #include <sys/stat.h> -#include <utime.h> -#include <unistd.h> +#include <sys/time.h> + #include <apti18n.h> /*}}}*/ @@ -72,17 +73,15 @@ bool CopyMethod::Fetch(FetchItem *Itm) From.Close(); To.Close(); - + // Transfer the modification times - struct utimbuf TimeBuf; - TimeBuf.actime = Buf.st_atime; - TimeBuf.modtime = Buf.st_mtime; - if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0) - { - To.OpFail(); - return _error->Errno("utime",_("Failed to set modification time")); - } - + struct timeval times[2]; + times[0].tv_sec = Buf.st_atime; + times[1].tv_sec = Buf.st_mtime; + times[0].tv_usec = times[1].tv_usec = 0; + if (utimes(Res.Filename.c_str(), times) != 0) + return _error->Errno("utimes",_("Failed to set modification time")); + Hashes Hash; FileFd Fd(Res.Filename, FileFd::ReadOnly); Hash.AddFD(Fd); diff --git a/methods/file.cc b/methods/file.cc index 7ed4e6f60..12db62203 100644 --- a/methods/file.cc +++ b/methods/file.cc @@ -5,7 +5,7 @@ File URI method for APT - This simply checks that the file specified exists, if so the relevent + This simply checks that the file specified exists, if so the relevant information is returned. If a .gz filename is specified then the file name with .gz removed will also be checked and information about it will be returned in Alt-* @@ -21,8 +21,9 @@ #include <apt-pkg/fileutl.h> #include <apt-pkg/strutl.h> +#include <string> #include <sys/stat.h> -#include <unistd.h> + #include <apti18n.h> /*}}}*/ diff --git a/methods/ftp.cc b/methods/ftp.cc index 979adca62..66787a7be 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -3,7 +3,7 @@ // $Id: ftp.cc,v 1.31.2.1 2004/01/16 18:58:50 mdz Exp $ /* ###################################################################### - FTP Aquire Method - This is the FTP aquire method for APT. + FTP Acquire Method - This is the FTP acquire method for APT. This is a very simple implementation that does not try to optimize at all. Commands are sent syncronously with the FTP server (as the @@ -23,10 +23,13 @@ #include <apt-pkg/hashes.h> #include <apt-pkg/netrc.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/strutl.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <sys/time.h> -#include <utime.h> #include <unistd.h> #include <signal.h> #include <stdio.h> @@ -43,6 +46,7 @@ #include "rfc2553emu.h" #include "connect.h" #include "ftp.h" + #include <apti18n.h> /*}}}*/ @@ -57,9 +61,9 @@ struct AFMap }; #ifndef AF_INET6 -struct AFMap AFMap[] = {{AF_INET,1},{}}; +struct AFMap AFMap[] = {{AF_INET,1},{0, 0}}; #else -struct AFMap AFMap[] = {{AF_INET,1},{AF_INET6,2},{}}; +struct AFMap AFMap[] = {{AF_INET,1},{AF_INET6,2},{0, 0}}; #endif unsigned long TimeOut = 120; @@ -947,20 +951,22 @@ FtpMethod::FtpMethod() : pkgAcqMethod("1.0",SendConfig) /*}}}*/ // FtpMethod::SigTerm - Handle a fatal signal /*{{{*/ // --------------------------------------------------------------------- -/* This closes and timestamps the open file. This is neccessary to get +/* This closes and timestamps the open file. This is necessary to get resume behavoir on user abort */ void FtpMethod::SigTerm(int) { if (FailFd == -1) _exit(100); - close(FailFd); - + // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(FailFile.c_str(), times); + + close(FailFd); + _exit(100); } /*}}}*/ @@ -1059,13 +1065,14 @@ bool FtpMethod::Fetch(FetchItem *Itm) if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing) == false) { Fd.Close(); - + // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(FailFile.c_str(), times); + // If the file is missing we hard fail and delete the destfile // otherwise transient fail if (Missing == true) { @@ -1077,25 +1084,26 @@ bool FtpMethod::Fetch(FetchItem *Itm) } Res.Size = Fd.Size(); + + // Timestamp + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(Fd.Name().c_str(), times); + FailFd = -1; } - + Res.LastModified = FailTime; Res.TakeHashes(Hash); - - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(Queue->DestFile.c_str(),&UBuf); - FailFd = -1; URIDone(Res); - + return true; } /*}}}*/ -int main(int argc,const char *argv[]) +int main(int, const char *argv[]) { setlocale(LC_ALL, ""); diff --git a/methods/ftp.h b/methods/ftp.h index 2634f0732..dd92f0086 100644 --- a/methods/ftp.h +++ b/methods/ftp.h @@ -3,7 +3,7 @@ // $Id: ftp.h,v 1.4 2001/03/06 07:15:29 jgg Exp $ /* ###################################################################### - FTP Aquire Method - This is the FTP aquire method for APT. + FTP Acquire Method - This is the FTP acquire method for APT. ##################################################################### */ /*}}}*/ @@ -12,6 +12,8 @@ #include <apt-pkg/strutl.h> +#include <sys/types.h> +#include <time.h> #include <string> class FTPConn @@ -76,7 +78,7 @@ class FtpMethod : public pkgAcqMethod static std::string FailFile; static int FailFd; static time_t FailTime; - static void SigTerm(int); + static APT_NORETURN void SigTerm(int); public: diff --git a/methods/gpgv.cc b/methods/gpgv.cc index ea8a26fd4..ae521a2ed 100644 --- a/methods/gpgv.cc +++ b/methods/gpgv.cc @@ -1,20 +1,21 @@ #include <config.h> -#include <apt-pkg/error.h> #include <apt-pkg/acquire-method.h> -#include <apt-pkg/strutl.h> -#include <apt-pkg/fileutl.h> -#include <apt-pkg/indexcopy.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> #include <apt-pkg/gpgv.h> +#include <apt-pkg/strutl.h> -#include <utime.h> -#include <stdio.h> -#include <fcntl.h> +#include <ctype.h> #include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/wait.h> +#include <unistd.h> #include <iostream> -#include <sstream> +#include <string> #include <vector> #include <apti18n.h> diff --git a/methods/gzip.cc b/methods/gzip.cc index 48c8e9892..df3f8828f 100644 --- a/methods/gzip.cc +++ b/methods/gzip.cc @@ -11,17 +11,20 @@ // Include Files /*{{{*/ #include <config.h> -#include <apt-pkg/fileutl.h> -#include <apt-pkg/error.h> +#include <apt-pkg/configuration.h> #include <apt-pkg/acquire-method.h> -#include <apt-pkg/strutl.h> +#include <apt-pkg/error.h> +#include <apt-pkg/fileutl.h> #include <apt-pkg/hashes.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/aptconfiguration.h> +#include <string.h> #include <sys/stat.h> -#include <unistd.h> -#include <utime.h> -#include <stdio.h> -#include <errno.h> +#include <sys/time.h> +#include <string> +#include <vector> + #include <apti18n.h> /*}}}*/ @@ -58,17 +61,25 @@ bool GzipMethod::Fetch(FetchItem *Itm) return _error->Error("Extraction of file %s requires unknown compressor %s", Path.c_str(), Prog); // Open the source and destination files - FileFd From; - From.Open(Path, FileFd::ReadOnly, *compressor); - - if(From.FileSize() == 0) - return _error->Error(_("Empty files can't be valid archives")); - - FileFd To(Itm->DestFile,FileFd::WriteAtomic); + FileFd From, To; + if (_config->FindB("Method::Compress", false) == false) + { + From.Open(Path, FileFd::ReadOnly, *compressor); + if(From.FileSize() == 0) + return _error->Error(_("Empty files can't be valid archives")); + To.Open(Itm->DestFile, FileFd::WriteAtomic); + } + else + { + From.Open(Path, FileFd::ReadOnly); + To.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty, *compressor); + } To.EraseOnFailure(); - if (_error->PendingError() == true) + + if (From.IsOpen() == false || From.Failed() == true || + To.IsOpen() == false || To.Failed() == true) return false; - + // Read data from source, generate checksums and write Hashes Hash; bool Failed = false; @@ -94,37 +105,33 @@ bool GzipMethod::Fetch(FetchItem *Itm) } From.Close(); + Res.Size = To.FileSize(); To.Close(); - + if (Failed == true) return false; - + // Transfer the modification times struct stat Buf; if (stat(Path.c_str(),&Buf) != 0) return _error->Errno("stat",_("Failed to stat")); - struct utimbuf TimeBuf; - TimeBuf.actime = Buf.st_atime; - TimeBuf.modtime = Buf.st_mtime; - if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0) - return _error->Errno("utime",_("Failed to set modification time")); + struct timeval times[2]; + times[0].tv_sec = Buf.st_atime; + Res.LastModified = times[1].tv_sec = Buf.st_mtime; + times[0].tv_usec = times[1].tv_usec = 0; + if (utimes(Itm->DestFile.c_str(), times) != 0) + return _error->Errno("utimes",_("Failed to set modification time")); - if (stat(Itm->DestFile.c_str(),&Buf) != 0) - return _error->Errno("stat",_("Failed to stat")); - // Return a Done response - Res.LastModified = Buf.st_mtime; - Res.Size = Buf.st_size; Res.TakeHashes(Hash); URIDone(Res); - return true; } /*}}}*/ -int main(int argc, char *argv[]) +int main(int, char *argv[]) { setlocale(LC_ALL, ""); diff --git a/methods/http.cc b/methods/http.cc index b22b61efc..ed6e3517d 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -3,7 +3,7 @@ // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ /* ###################################################################### - HTTP Acquire Method - This is the HTTP aquire method for APT. + HTTP Acquire Method - This is the HTTP acquire method for APT. It uses HTTP/1.1 and many of the fancy options there-in, such as pipelining, range, if-range and so on. @@ -33,25 +33,21 @@ #include <apt-pkg/error.h> #include <apt-pkg/hashes.h> #include <apt-pkg/netrc.h> +#include <apt-pkg/strutl.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/select.h> +#include <cstring> #include <sys/stat.h> #include <sys/time.h> -#include <utime.h> #include <unistd.h> -#include <signal.h> #include <stdio.h> #include <errno.h> -#include <string.h> -#include <climits> #include <iostream> -#include <map> - -// Internet stuff -#include <netdb.h> #include "config.h" #include "connect.h" -#include "rfc2553emu.h" #include "http.h" #include <apti18n.h> @@ -62,7 +58,7 @@ unsigned long long CircleBuf::BwReadLimit=0; unsigned long long CircleBuf::BwTickReadData=0; struct timeval CircleBuf::BwReadTick={0,0}; const unsigned int CircleBuf::BW_HZ=10; - + // CircleBuf::CircleBuf - Circular input buffer /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -88,8 +84,8 @@ void CircleBuf::Reset() { delete Hash; Hash = new Hashes; - } -}; + } +} /*}}}*/ // CircleBuf::Read - Read from a FD into the circular buffer /*{{{*/ // --------------------------------------------------------------------- @@ -97,8 +93,6 @@ void CircleBuf::Reset() is non-blocking.. */ bool CircleBuf::Read(int Fd) { - unsigned long long BwReadMax; - while (1) { // Woops, buffer is full @@ -106,7 +100,7 @@ bool CircleBuf::Read(int Fd) return true; // what's left to read in this tick - BwReadMax = CircleBuf::BwReadLimit/BW_HZ; + unsigned long long const BwReadMax = CircleBuf::BwReadLimit/BW_HZ; if(CircleBuf::BwReadLimit) { struct timeval now; @@ -476,7 +470,7 @@ bool HttpServerState::WriteResponse(const std::string &Data) /*{{{*/ return Out.Read(Data); } /*}}}*/ -bool HttpServerState::IsOpen() /*{{{*/ +APT_PURE bool HttpServerState::IsOpen() /*{{{*/ { return (ServerFd != -1); } @@ -487,16 +481,11 @@ bool HttpServerState::InitHashes(FileFd &File) /*{{{*/ In.Hash = new Hashes; // Set the expected size and read file for the hashes - if (StartPos >= 0) - { - File.Truncate(StartPos); - - return In.Hash->AddFD(File, StartPos); - } - return true; + File.Truncate(StartPos); + return In.Hash->AddFD(File, StartPos); } /*}}}*/ -Hashes * HttpServerState::GetHashes() /*{{{*/ +APT_PURE Hashes * HttpServerState::GetHashes() /*{{{*/ { return In.Hash; } @@ -735,7 +724,7 @@ void HttpMethod::SendReq(FetchItem *Itm) } // If we ask for uncompressed files servers might respond with content- - // negotation which lets us end up with compressed files we do not support, + // negotiation which lets us end up with compressed files we do not support, // see 657029, 657560 and co, so if we have no extension on the request // ask for text only. As a sidenote: If there is nothing to negotate servers // seem to be nice and ignore it. diff --git a/methods/http.h b/methods/http.h index 02c04e8ae..5406ce4a7 100644 --- a/methods/http.h +++ b/methods/http.h @@ -3,7 +3,7 @@ // $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ /* ###################################################################### - HTTP Acquire Method - This is the HTTP aquire method for APT. + HTTP Acquire Method - This is the HTTP acquire method for APT. ##################################################################### */ /*}}}*/ @@ -12,14 +12,18 @@ #define APT_HTTP_H #include <apt-pkg/strutl.h> +#include <apt-pkg/acquire-method.h> #include <string> +#include <sys/time.h> +#include <iostream> #include "server.h" using std::cout; using std::endl; +class FileFd; class HttpMethod; class Hashes; diff --git a/methods/http_main.cc b/methods/http_main.cc index 2ca91bfc9..3b346a514 100644 --- a/methods/http_main.cc +++ b/methods/http_main.cc @@ -1,14 +1,9 @@ #include <config.h> -#include <apt-pkg/fileutl.h> -#include <apt-pkg/acquire-method.h> #include <signal.h> -#include "connect.h" -#include "rfc2553emu.h" #include "http.h" - int main() { setlocale(LC_ALL, ""); diff --git a/methods/https.cc b/methods/https.cc index 2a562434b..c4aff8f38 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -3,7 +3,7 @@ // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ /* ###################################################################### - HTTPS Acquire Method - This is the HTTPS aquire method for APT. + HTTPS Acquire Method - This is the HTTPS acquire method for APT. It uses libcurl @@ -18,20 +18,20 @@ #include <apt-pkg/hashes.h> #include <apt-pkg/netrc.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/macros.h> +#include <apt-pkg/strutl.h> #include <sys/stat.h> #include <sys/time.h> -#include <utime.h> #include <unistd.h> -#include <signal.h> #include <stdio.h> -#include <errno.h> -#include <string.h> #include <iostream> #include <sstream> +#include <ctype.h> +#include <stdlib.h> -#include "config.h" #include "https.h" + #include <apti18n.h> /*}}}*/ using namespace std; @@ -76,26 +76,27 @@ HttpsMethod::write_data(void *buffer, size_t size, size_t nmemb, void *userp) { HttpsMethod *me = (HttpsMethod *)userp; + if (me->Res.Size == 0) + me->URIStart(me->Res); if(me->File->Write(buffer, size*nmemb) != true) return false; return size*nmemb; } -int -HttpsMethod::progress_callback(void *clientp, double dltotal, double dlnow, - double ultotal, double ulnow) +int +HttpsMethod::progress_callback(void *clientp, double dltotal, double /*dlnow*/, + double /*ultotal*/, double /*ulnow*/) { HttpsMethod *me = (HttpsMethod *)clientp; if(dltotal > 0 && me->Res.Size == 0) { me->Res.Size = (unsigned long long)dltotal; - me->URIStart(me->Res); } return 0; } // HttpsServerState::HttpsServerState - Constructor /*{{{*/ -HttpsServerState::HttpsServerState(URI Srv,HttpsMethod *Owner) : ServerState(Srv, NULL) +HttpsServerState::HttpsServerState(URI Srv,HttpsMethod * /*Owner*/) : ServerState(Srv, NULL) { TimeOut = _config->FindI("Acquire::https::Timeout",TimeOut); Reset(); @@ -185,8 +186,12 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback); curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this); + // options curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false); curl_easy_setopt(curl, CURLOPT_FILETIME, true); + // only allow curl to handle https, not the other stuff it supports + curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS); // SSL parameters are set by default to the common (non mirror-specific) value // if available (or a default one) and gets overload by mirror-specific ones. @@ -305,7 +310,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errorstr); // If we ask for uncompressed files servers might respond with content- - // negotation which lets us end up with compressed files we do not support, + // negotiation which lets us end up with compressed files we do not support, // see 657029, 657560 and co, so if we have no extension on the request // ask for text only. As a sidenote: If there is nothing to negotate servers // seem to be nice and ignore it. @@ -405,10 +410,11 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_getinfo(curl, CURLINFO_FILETIME, &Res.LastModified); if (Res.LastModified != -1) { - struct utimbuf UBuf; - UBuf.actime = Res.LastModified; - UBuf.modtime = Res.LastModified; - utime(File->Name().c_str(),&UBuf); + struct timeval times[2]; + times[0].tv_sec = Res.LastModified; + times[1].tv_sec = Res.LastModified; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(File->Name().c_str(), times); } else Res.LastModified = resultStat.st_mtime; @@ -427,7 +433,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm) delete File; return true; -}; +} int main() { diff --git a/methods/https.h b/methods/https.h index 8632d6d02..faac8a3cd 100644 --- a/methods/https.h +++ b/methods/https.h @@ -3,7 +3,7 @@ // $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ /* ###################################################################### - HTTP Acquire Method - This is the HTTP aquire method for APT. + HTTP Acquire Method - This is the HTTP acquire method for APT. ##################################################################### */ /*}}}*/ @@ -11,37 +11,42 @@ #ifndef APT_HTTPS_H #define APT_HTTPS_H -#include <iostream> +#include <apt-pkg/acquire-method.h> + #include <curl/curl.h> +#include <iostream> +#include <stddef.h> +#include <string> #include "server.h" using std::cout; using std::endl; +class Hashes; class HttpsMethod; class FileFd; class HttpsServerState : public ServerState { protected: - virtual bool ReadHeaderLines(std::string &Data) { return false; } - virtual bool LoadNextResponse(bool const ToFile, FileFd * const File) { return false; } + virtual bool ReadHeaderLines(std::string &/*Data*/) { return false; } + virtual bool LoadNextResponse(bool const /*ToFile*/, FileFd * const /*File*/) { return false; } public: - virtual bool WriteResponse(std::string const &Data) { return false; } + virtual bool WriteResponse(std::string const &/*Data*/) { return false; } /** \brief Transfer the data from the socket */ - virtual bool RunData(FileFd * const File) { return false; } + virtual bool RunData(FileFd * const /*File*/) { return false; } virtual bool Open() { return false; } virtual bool IsOpen() { return false; } virtual bool Close() { return false; } - virtual bool InitHashes(FileFd &File) { return false; } + virtual bool InitHashes(FileFd &/*File*/) { return false; } virtual Hashes * GetHashes() { return NULL; } - virtual bool Die(FileFd &File) { return false; } - virtual bool Flush(FileFd * const File) { return false; } - virtual bool Go(bool ToFile, FileFd * const File) { return false; } + virtual bool Die(FileFd &/*File*/) { return false; } + virtual bool Flush(FileFd * const /*File*/) { return false; } + virtual bool Go(bool /*ToFile*/, FileFd * const /*File*/) { return false; } HttpsServerState(URI Srv, HttpsMethod *Owner); virtual ~HttpsServerState() {Close();}; @@ -65,7 +70,7 @@ class HttpsMethod : public pkgAcqMethod public: FileFd *File; - HttpsMethod() : pkgAcqMethod("1.2",Pipeline | SendConfig) + HttpsMethod() : pkgAcqMethod("1.2",Pipeline | SendConfig), File(NULL) { File = 0; curl = curl_easy_init(); diff --git a/methods/mirror.cc b/methods/mirror.cc index 854366318..d3aef91bc 100644 --- a/methods/mirror.cc +++ b/methods/mirror.cc @@ -3,7 +3,7 @@ // $Id: mirror.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ /* ###################################################################### - Mirror Aquire Method - This is the Mirror aquire method for APT. + Mirror Acquire Method - This is the Mirror acquire method for APT. ##################################################################### */ /*}}}*/ @@ -16,18 +16,18 @@ #include <apt-pkg/acquire-item.h> #include <apt-pkg/acquire.h> #include <apt-pkg/error.h> -#include <apt-pkg/hashes.h> #include <apt-pkg/sourcelist.h> #include <apt-pkg/configuration.h> #include <apt-pkg/metaindex.h> +#include <apt-pkg/strutl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include <algorithm> -#include <fstream> #include <iostream> - -#include <stdarg.h> +#include <fstream> #include <sys/stat.h> -#include <sys/types.h> #include <sys/utsname.h> #include <dirent.h> @@ -49,7 +49,7 @@ using namespace std; * of the failure that is also send to LP * * TODO: - * - deal with runing as non-root because we can't write to the lists + * - deal with running as non-root because we can't write to the lists dir then -> use the cached mirror file * - better method to download than having a pkgAcquire interface here * and better error handling there! @@ -60,7 +60,7 @@ using namespace std; MirrorMethod::MirrorMethod() : HttpMethod(), DownloadedMirrorFile(false), Debug(false) { -}; +} // HttpMethod::Configuration - Handle a configuration message /*{{{*/ // --------------------------------------------------------------------- @@ -90,17 +90,17 @@ bool MirrorMethod::Clean(string Dir) pkgSourceList list; list.ReadMainList(); - DIR *D = opendir(Dir.c_str()); + DIR *D = opendir(Dir.c_str()); if (D == 0) return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); - + string StartDir = SafeGetCWD(); if (chdir(Dir.c_str()) != 0) { closedir(D); return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str()); } - + for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) { // Skip some files.. @@ -114,7 +114,7 @@ bool MirrorMethod::Clean(string Dir) for(I=list.begin(); I != list.end(); ++I) { string uri = (*I)->GetURI(); - if(uri.find("mirror://") != 0) + if(uri.compare(0, strlen("mirror://"), "mirror://") != 0) continue; string BaseUri = uri.substr(0,uri.size()-1); if (URItoFileName(BaseUri) == Dir->d_name) @@ -123,23 +123,23 @@ bool MirrorMethod::Clean(string Dir) // nothing found, nuke it if (I == list.end()) unlink(Dir->d_name); - }; + } closedir(D); if (chdir(StartDir.c_str()) != 0) return _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str()); - return true; + return true; } -bool MirrorMethod::DownloadMirrorFile(string mirror_uri_str) +bool MirrorMethod::DownloadMirrorFile(string /*mirror_uri_str*/) { - // not that great to use pkgAcquire here, but we do not have + // not that great to use pkgAcquire here, but we do not have // any other way right now string fetch = BaseUri; fetch.replace(0,strlen("mirror://"),"http://"); -#if 0 // no need for this, the getArchitectures() will also include the main +#if 0 // no need for this, the getArchitectures() will also include the main // arch // append main architecture fetch += "?arch=" + _config->Find("Apt::Architecture"); @@ -173,7 +173,7 @@ bool MirrorMethod::DownloadMirrorFile(string mirror_uri_str) if(Debug) clog << "MirrorMethod::DownloadMirrorFile() success: " << res << endl; - + return res; } @@ -187,20 +187,20 @@ bool MirrorMethod::RandomizeMirrorFile(string mirror_file) if (!FileExists(mirror_file)) return false; - // read + // read ifstream in(mirror_file.c_str()); while ( !in.eof() ) { getline(in, line); content.push_back(line); } - + // we want the file to be random for each different machine, but also // "stable" on the same machine. this is to avoid running into out-of-sync // issues (i.e. Release/Release.gpg different on each mirror) struct utsname buf; - int seed=1, i; + int seed=1; if(uname(&buf) == 0) { - for(i=0,seed=1; buf.nodename[i] != 0; i++) { + for(int i=0,seed=1; buf.nodename[i] != 0; ++i) { seed = seed * 31 + buf.nodename[i]; } } @@ -290,7 +290,7 @@ bool MirrorMethod::InitMirrors() // FIXME: make the mirror selection more clever, do not // just use the first one! // BUT: we can not make this random, the mirror has to be - // stable accross session, because otherwise we can + // stable across session, because otherwise we can // get into sync issues (got indexfiles from mirror A, // but packages from mirror B - one might be out of date etc) ifstream in(MirrorFile.c_str()); @@ -306,7 +306,7 @@ bool MirrorMethod::InitMirrors() if (s.size() == 0) continue; // ignore non http lines - if (s.find("http://") != 0) + if (s.compare(0, strlen("http://"), "http://") != 0) continue; AllMirrors.push_back(s); @@ -422,10 +422,10 @@ bool MirrorMethod::Fetch(FetchItem *Itm) if(Debug) clog << "Fetch: " << Itm->Uri << endl << endl; - + // now run the real fetcher return HttpMethod::Fetch(Itm); -}; +} void MirrorMethod::Fail(string Err,bool Transient) { @@ -437,7 +437,7 @@ void MirrorMethod::Fail(string Err,bool Transient) // try the next mirror on fail (if its not a expected failure, // e.g. translations are ok to ignore) - if (!Queue->FailIgnore && TryNextMirror()) + if (!Queue->FailIgnore && TryNextMirror()) return; // all mirrors failed, so bail out diff --git a/methods/mirror.h b/methods/mirror.h index 81e531e21..6c0ce370e 100644 --- a/methods/mirror.h +++ b/methods/mirror.h @@ -3,7 +3,7 @@ // $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ /* ###################################################################### - MIRROR Aquire Method - This is the MIRROR aquire method for APT. + MIRROR Acquire Method - This is the MIRROR acquire method for APT. ##################################################################### */ /*}}}*/ @@ -11,6 +11,8 @@ #ifndef APT_MIRROR_H #define APT_MIRROR_H +#include <apt-pkg/acquire-method.h> + #include <iostream> #include <string> #include <vector> diff --git a/methods/rfc2553emu.h b/methods/rfc2553emu.h index b15facb31..ad7ddf48a 100644 --- a/methods/rfc2553emu.h +++ b/methods/rfc2553emu.h @@ -75,7 +75,7 @@ #endif /* If we don't have getaddrinfo then we probably don't have - sockaddr_storage either (same RFC) so we definately will not be + sockaddr_storage either (same RFC) so we definitely will not be doing any IPv6 stuff. Do not use the members of this structure to retain portability, cast to a sockaddr. */ #define sockaddr_storage sockaddr_in diff --git a/methods/rred.cc b/methods/rred.cc index 7c65f8f92..cabb3c456 100644 --- a/methods/rred.cc +++ b/methods/rred.cc @@ -1,571 +1,659 @@ -// Includes /*{{{*/ +// Copyright (c) 2014 Anthony Towns +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. + #include <config.h> #include <apt-pkg/fileutl.h> -#include <apt-pkg/mmap.h> #include <apt-pkg/error.h> #include <apt-pkg/acquire-method.h> #include <apt-pkg/strutl.h> #include <apt-pkg/hashes.h> #include <apt-pkg/configuration.h> -#include <sys/stat.h> -#include <sys/uio.h> -#include <unistd.h> -#include <utime.h> +#include <stddef.h> +#include <iostream> +#include <string> +#include <list> +#include <vector> + +#include <assert.h> #include <stdio.h> -#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h> + #include <apti18n.h> - /*}}}*/ -/** \brief RredMethod - ed-style incremential patch method {{{ - * - * This method implements a patch functionality similar to "patch --ed" that is - * used by the "tiffany" incremental packages download stuff. It differs from - * "ed" insofar that it is way more restricted (and therefore secure). - * The currently supported ed commands are "<em>c</em>hange", "<em>a</em>dd" and - * "<em>d</em>elete" (diff doesn't output any other). - * Additionally the records must be reverse sorted by line number and - * may not overlap (diff *seems* to produce this kind of output). - * */ -class RredMethod : public pkgAcqMethod { - bool Debug; - // the size of this doesn't really matter (except for performance) - const static int BUF_SIZE = 1024; - // the supported ed commands - enum Mode {MODE_CHANGED='c', MODE_DELETED='d', MODE_ADDED='a'}; - // return values - enum State {ED_OK, ED_ORDERING, ED_PARSER, ED_FAILURE, MMAP_FAILED}; - - State applyFile(FileFd &ed_cmds, FileFd &in_file, FileFd &out_file, - unsigned long &line, char *buffer, Hashes *hash) const; - void ignoreLineInFile(FileFd &fin, char *buffer) const; - void copyLinesFromFileToFile(FileFd &fin, FileFd &fout, unsigned int lines, - Hashes *hash, char *buffer) const; - - State patchFile(FileFd &Patch, FileFd &From, FileFd &out_file, Hashes *hash) const; - State patchMMap(FileFd &Patch, FileFd &From, FileFd &out_file, Hashes *hash) const; - -protected: - // the methods main method - virtual bool Fetch(FetchItem *Itm); - -public: - RredMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig), Debug(false) {}; + +#define BLOCK_SIZE (512*1024) + +class MemBlock { + char *start; + size_t size; + char *free; + struct MemBlock *next; + + MemBlock(size_t size) : size(size), next(NULL) + { + free = start = new char[size]; + } + + size_t avail(void) { return size - (free - start); } + + public: + + MemBlock(void) { + free = start = new char[BLOCK_SIZE]; + size = BLOCK_SIZE; + next = NULL; + } + + ~MemBlock() { + delete [] start; + delete next; + } + + void clear(void) { + free = start; + if (next) + next->clear(); + } + + char *add_easy(char *src, size_t len, char *last) + { + if (last) { + for (MemBlock *k = this; k; k = k->next) { + if (k->free == last) { + if (len <= k->avail()) { + char *n = k->add(src, len); + assert(last == n); + if (last == n) + return NULL; + return n; + } else { + break; + } + } else if (last >= start && last < free) { + break; + } + } + } + return add(src, len); + } + + char *add(char *src, size_t len) { + if (len > avail()) { + if (!next) { + if (len > BLOCK_SIZE) { + next = new MemBlock(len); + } else { + next = new MemBlock; + } + } + return next->add(src, len); + } + char *dst = free; + free += len; + memcpy(dst, src, len); + return dst; + } }; - /*}}}*/ -/** \brief applyFile - in reverse order with a tail recursion {{{ - * - * As it is expected that the commands are in reversed order in the patch file - * we check in the first half if the command is valid, but doesn't execute it - * and move a step deeper. After reaching the end of the file we apply the - * patches in the correct order: last found command first. - * - * \param ed_cmds patch file to apply - * \param in_file base file we want to patch - * \param out_file file to write the patched result to - * \param line of command operation - * \param buffer internal used read/write buffer - * \param hash the created file for correctness - * \return the success State of the ed command executor - */ -RredMethod::State RredMethod::applyFile(FileFd &ed_cmds, FileFd &in_file, FileFd &out_file, - unsigned long &line, char *buffer, Hashes *hash) const { - // get the current command and parse it - if (ed_cmds.ReadLine(buffer, BUF_SIZE) == NULL) { - if (Debug == true) - std::clog << "rred: encounter end of file - we can start patching now." << std::endl; - line = 0; - return ED_OK; - } - - // parse in the effected linenumbers - char* idx; - errno=0; - unsigned long const startline = strtol(buffer, &idx, 10); - if (errno == ERANGE || errno == EINVAL) { - _error->Errno("rred", "startline is an invalid number"); - return ED_PARSER; - } - if (startline > line) { - _error->Error("rred: The start line (%lu) of the next command is higher than the last line (%lu). This is not allowed.", startline, line); - return ED_ORDERING; - } - unsigned long stopline; - if (*idx == ',') { - idx++; - errno=0; - stopline = strtol(idx, &idx, 10); - if (errno == ERANGE || errno == EINVAL) { - _error->Errno("rred", "stopline is an invalid number"); - return ED_PARSER; - } - } - else { - stopline = startline; - } - line = startline; - - // which command to execute on this line(s)? - switch (*idx) { - case MODE_CHANGED: - if (Debug == true) - std::clog << "Change from line " << startline << " to " << stopline << std::endl; - break; - case MODE_ADDED: - if (Debug == true) - std::clog << "Insert after line " << startline << std::endl; - break; - case MODE_DELETED: - if (Debug == true) - std::clog << "Delete from line " << startline << " to " << stopline << std::endl; - break; - default: - _error->Error("rred: Unknown ed command '%c'. Abort.", *idx); - return ED_PARSER; - } - unsigned char mode = *idx; - - // save the current position - unsigned const long long pos = ed_cmds.Tell(); - - // if this is add or change then go to the next full stop - unsigned int data_length = 0; - if (mode == MODE_CHANGED || mode == MODE_ADDED) { - do { - ignoreLineInFile(ed_cmds, buffer); - data_length++; - } - while (strncmp(buffer, ".", 1) != 0); - data_length--; // the dot should not be copied - } - - // do the recursive call - the last command is the one we need to execute at first - const State child = applyFile(ed_cmds, in_file, out_file, line, buffer, hash); - if (child != ED_OK) { - return child; - } - - // change and delete are working on "line" - add is done after "line" - if (mode != MODE_ADDED) - line++; - - // first wind to the current position and copy over all unchanged lines - if (line < startline) { - copyLinesFromFileToFile(in_file, out_file, (startline - line), hash, buffer); - line = startline; - } - - if (mode != MODE_ADDED) - line--; - - // include data from ed script - if (mode == MODE_CHANGED || mode == MODE_ADDED) { - ed_cmds.Seek(pos); - copyLinesFromFileToFile(ed_cmds, out_file, data_length, hash, buffer); - } - - // ignore the corresponding number of lines from input - if (mode == MODE_CHANGED || mode == MODE_DELETED) { - while (line < stopline) { - ignoreLineInFile(in_file, buffer); - line++; - } - } - return ED_OK; -} - /*}}}*/ -void RredMethod::copyLinesFromFileToFile(FileFd &fin, FileFd &fout, unsigned int lines,/*{{{*/ - Hashes *hash, char *buffer) const { - while (0 < lines--) { - do { - fin.ReadLine(buffer, BUF_SIZE); - unsigned long long const towrite = strlen(buffer); - fout.Write(buffer, towrite); - hash->Add((unsigned char*)buffer, towrite); - } while (strlen(buffer) == (BUF_SIZE - 1) && - buffer[BUF_SIZE - 2] != '\n'); - } -} - /*}}}*/ -void RredMethod::ignoreLineInFile(FileFd &fin, char *buffer) const { /*{{{*/ - fin.ReadLine(buffer, BUF_SIZE); - while (strlen(buffer) == (BUF_SIZE - 1) && - buffer[BUF_SIZE - 2] != '\n') { - fin.ReadLine(buffer, BUF_SIZE); - buffer[0] = ' '; - } -} - /*}}}*/ -RredMethod::State RredMethod::patchFile(FileFd &Patch, FileFd &From, /*{{{*/ - FileFd &out_file, Hashes *hash) const { - char buffer[BUF_SIZE]; - - /* we do a tail recursion to read the commands in the right order */ - unsigned long line = -1; // assign highest possible value - State const result = applyFile(Patch, From, out_file, line, buffer, hash); - - /* read the rest from infile */ - if (result == ED_OK) { - while (From.ReadLine(buffer, BUF_SIZE) != NULL) { - unsigned long long const towrite = strlen(buffer); - out_file.Write(buffer, towrite); - hash->Add((unsigned char*)buffer, towrite); + +struct Change { + /* Ordering: + * + * 1. write out <offset> lines unchanged + * 2. skip <del_cnt> lines from source + * 3. write out <add_cnt> lines (<add>/<add_len>) + */ + size_t offset; + size_t del_cnt; + size_t add_cnt; /* lines */ + size_t add_len; /* bytes */ + char *add; + + Change(int off) + { + offset = off; + del_cnt = add_cnt = add_len = 0; + add = NULL; + } + + /* actually, don't write <lines> lines from <add> */ + void skip_lines(size_t lines) + { + while (lines > 0) { + char *s = (char*) memchr(add, '\n', add_len); + assert(s != NULL); + s++; + add_len -= (s - add); + add_cnt--; + lines--; + if (add_len == 0) { + add = NULL; + assert(add_cnt == 0); + assert(lines == 0); + } else { + add = s; + assert(add_cnt > 0); + } } } - return result; -} - /*}}}*/ -/* struct EdCommand {{{*/ -#ifdef _POSIX_MAPPED_FILES -struct EdCommand { - size_t data_start; - size_t data_end; - size_t data_lines; - size_t first_line; - size_t last_line; - char type; }; -#define IOV_COUNT 1024 /* Don't really want IOV_MAX since it can be arbitrarily large */ -static ssize_t retry_writev(int fd, const struct iovec *iov, int iovcnt) { - ssize_t Res; - errno = 0; - ssize_t i = 0; - do { - Res = writev(fd, iov + i, iovcnt); - if (Res < 0 && errno == EINTR) - continue; - if (Res < 0) - return _error->Errno("writev",_("Write error")); - iovcnt -= Res; - i += Res; - } while (Res > 0 && iovcnt > 0); - return i; -} -#endif - /*}}}*/ -RredMethod::State RredMethod::patchMMap(FileFd &Patch, FileFd &From, /*{{{*/ - FileFd &out_file, Hashes *hash) const { -#ifdef _POSIX_MAPPED_FILES - MMap ed_cmds(Patch, MMap::ReadOnly); - MMap in_file(From, MMap::ReadOnly); - - unsigned long long const ed_size = ed_cmds.Size(); - unsigned long long const in_size = in_file.Size(); - if (ed_size == 0 || in_size == 0) - return MMAP_FAILED; - - EdCommand* commands = 0; - size_t command_count = 0; - size_t command_alloc = 0; - - const char* begin = (char*) ed_cmds.Data(); - const char* end = begin; - const char* ed_end = (char*) ed_cmds.Data() + ed_size; - - const char* input = (char*) in_file.Data(); - const char* input_end = (char*) in_file.Data() + in_size; - - size_t i; - - /* 1. Parse entire script. It is executed in reverse order, so we cather it - * in the `commands' buffer first - */ - - for(;;) { - EdCommand cmd; - cmd.data_start = 0; - cmd.data_end = 0; - - while(begin != ed_end && *begin == '\n') - ++begin; - while(end != ed_end && *end != '\n') - ++end; - if(end == ed_end && begin == end) - break; - - /* Determine command range */ - const char* tmp = begin; - - for(;;) { - /* atoll is safe despite lacking NUL-termination; we know there's an - * alphabetic character at end[-1] - */ - if(tmp == end) { - cmd.first_line = atol(begin); - cmd.last_line = cmd.first_line; - break; - } - if(*tmp == ',') { - cmd.first_line = atol(begin); - cmd.last_line = atol(tmp + 1); - break; - } - ++tmp; - } - - // which command to execute on this line(s)? - switch (end[-1]) { - case MODE_CHANGED: - if (Debug == true) - std::clog << "Change from line " << cmd.first_line << " to " << cmd.last_line << std::endl; - break; - case MODE_ADDED: - if (Debug == true) - std::clog << "Insert after line " << cmd.first_line << std::endl; - break; - case MODE_DELETED: - if (Debug == true) - std::clog << "Delete from line " << cmd.first_line << " to " << cmd.last_line << std::endl; - break; - default: - _error->Error("rred: Unknown ed command '%c'. Abort.", end[-1]); - free(commands); - return ED_PARSER; - } - cmd.type = end[-1]; - - /* Determine the size of the inserted text, so we don't have to scan this - * text again later. - */ - begin = end + 1; - end = begin; - cmd.data_lines = 0; - - if(cmd.type == MODE_ADDED || cmd.type == MODE_CHANGED) { - cmd.data_start = begin - (char*) ed_cmds.Data(); - while(end != ed_end) { - if(*end == '\n') { - if(end[-1] == '.' && end[-2] == '\n') - break; - ++cmd.data_lines; - } - ++end; - } - cmd.data_end = end - (char*) ed_cmds.Data() - 1; - begin = end + 1; - end = begin; - } - if(command_count == command_alloc) { - command_alloc = (command_alloc + 64) * 3 / 2; - EdCommand* newCommands = (EdCommand*) realloc(commands, command_alloc * sizeof(EdCommand)); - if (newCommands == NULL) { - free(commands); - return MMAP_FAILED; - } - commands = newCommands; - } - commands[command_count++] = cmd; - } - - struct iovec* iov = new struct iovec[IOV_COUNT]; - size_t iov_size = 0; - - size_t amount, remaining; - size_t line = 1; - EdCommand* cmd; - - /* 2. Execute script. We gather writes in a `struct iov' array, and flush - * using writev to minimize the number of system calls. Data is read - * directly from the memory mappings of the input file and the script. - */ - - for(i = command_count; i-- > 0; ) { - cmd = &commands[i]; - if(cmd->type == MODE_ADDED) - amount = cmd->first_line + 1; - else - amount = cmd->first_line; - - if(line < amount) { - begin = input; - while(line != amount) { - input = (const char*) memchr(input, '\n', input_end - input); - if(!input) - break; - ++line; - ++input; - } - - iov[iov_size].iov_base = (void*) begin; - iov[iov_size].iov_len = input - begin; - hash->Add((const unsigned char*) begin, input - begin); - - if(++iov_size == IOV_COUNT) { - retry_writev(out_file.Fd(), iov, IOV_COUNT); - iov_size = 0; - } - } - - if(cmd->type == MODE_DELETED || cmd->type == MODE_CHANGED) { - remaining = (cmd->last_line - cmd->first_line) + 1; - line += remaining; - while(remaining) { - input = (const char*) memchr(input, '\n', input_end - input); - if(!input) - break; - --remaining; - ++input; - } - } - - if(cmd->type == MODE_CHANGED || cmd->type == MODE_ADDED) { - if(cmd->data_end != cmd->data_start) { - iov[iov_size].iov_base = (void*) ((char*)ed_cmds.Data() + cmd->data_start); - iov[iov_size].iov_len = cmd->data_end - cmd->data_start; - hash->Add((const unsigned char*) ((char*)ed_cmds.Data() + cmd->data_start), - iov[iov_size].iov_len); - - if(++iov_size == IOV_COUNT) { - retry_writev(out_file.Fd(), iov, IOV_COUNT); - iov_size = 0; - } - } - } - } - - if(input != input_end) { - iov[iov_size].iov_base = (void*) input; - iov[iov_size].iov_len = input_end - input; - hash->Add((const unsigned char*) input, input_end - input); - ++iov_size; - } - - if(iov_size) { - retry_writev(out_file.Fd(), iov, iov_size); - iov_size = 0; - } - - for(i = 0; i < iov_size; i += IOV_COUNT) { - if(iov_size - i < IOV_COUNT) - retry_writev(out_file.Fd(), iov + i, iov_size - i); - else - retry_writev(out_file.Fd(), iov + i, IOV_COUNT); - } - - delete [] iov; - free(commands); - - return ED_OK; + +class FileChanges { + std::list<struct Change> changes; + std::list<struct Change>::iterator where; + size_t pos; // line number is as far left of iterator as possible + + bool pos_is_okay(void) + { +#ifdef POSDEBUG + size_t cpos = 0; + std::list<struct Change>::iterator x; + for (x = changes.begin(); x != where; ++x) { + assert(x != changes.end()); + cpos += x->offset + x->add_cnt; + } + return cpos == pos; #else - return MMAP_FAILED; + return true; #endif -} - /*}}}*/ -bool RredMethod::Fetch(FetchItem *Itm) /*{{{*/ -{ - Debug = _config->FindB("Debug::pkgAcquire::RRed", false); - URI Get = Itm->Uri; - std::string Path = Get.Host + Get.Path; // To account for relative paths - - FetchResult Res; - Res.Filename = Itm->DestFile; - if (Itm->Uri.empty() == true) { - Path = Itm->DestFile; - Itm->DestFile.append(".result"); - } else - URIStart(Res); - - if (Debug == true) - std::clog << "Patching " << Path << " with " << Path - << ".ed and putting result into " << Itm->DestFile << std::endl; - // Open the source and destination files (the d'tor of FileFd will do - // the cleanup/closing of the fds) - FileFd From(Path,FileFd::ReadOnly); - FileFd Patch(Path+".ed",FileFd::ReadOnly, FileFd::Gzip); - FileFd To(Itm->DestFile,FileFd::WriteAtomic); - To.EraseOnFailure(); - if (_error->PendingError() == true) - return false; - - Hashes Hash; - // now do the actual patching - State const result = patchMMap(Patch, From, To, &Hash); - if (result == MMAP_FAILED) { - // retry with patchFile - Patch.Seek(0); - From.Seek(0); - To.Open(Itm->DestFile,FileFd::WriteAtomic); - if (_error->PendingError() == true) - return false; - if (patchFile(Patch, From, To, &Hash) != ED_OK) { - return _error->WarningE("rred", _("Could not patch %s with mmap and with file operation usage - the patch seems to be corrupt."), Path.c_str()); - } else if (Debug == true) { - std::clog << "rred: finished file patching of " << Path << " after mmap failed." << std::endl; + } + + public: + FileChanges() { + where = changes.end(); + pos = 0; + } + + std::list<struct Change>::iterator begin(void) { return changes.begin(); } + std::list<struct Change>::iterator end(void) { return changes.end(); } + + std::list<struct Change>::reverse_iterator rbegin(void) { return changes.rbegin(); } + std::list<struct Change>::reverse_iterator rend(void) { return changes.rend(); } + + void add_change(Change c) { + assert(pos_is_okay()); + go_to_change_for(c.offset); + assert(pos + where->offset == c.offset); + if (c.del_cnt > 0) + delete_lines(c.del_cnt); + assert(pos + where->offset == c.offset); + if (c.add_len > 0) { + assert(pos_is_okay()); + if (where->add_len > 0) + new_change(); + assert(where->add_len == 0 && where->add_cnt == 0); + + where->add_len = c.add_len; + where->add_cnt = c.add_cnt; + where->add = c.add; } - } else if (result != ED_OK) { - return _error->Errno("rred", _("Could not patch %s with mmap (but no mmap specific fail) - the patch seems to be corrupt."), Path.c_str()); - } else if (Debug == true) { - std::clog << "rred: finished mmap patching of " << Path << std::endl; + assert(pos_is_okay()); + merge(); + assert(pos_is_okay()); } - // write out the result - From.Close(); - Patch.Close(); - To.Close(); - - /* Transfer the modification times from the patch file - to be able to see in which state the file should be - and use the access time from the "old" file */ - struct stat BufBase, BufPatch; - if (stat(Path.c_str(),&BufBase) != 0 || - stat(std::string(Path+".ed").c_str(),&BufPatch) != 0) - return _error->Errno("stat",_("Failed to stat")); - - struct utimbuf TimeBuf; - TimeBuf.actime = BufBase.st_atime; - TimeBuf.modtime = BufPatch.st_mtime; - if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0) - return _error->Errno("utime",_("Failed to set modification time")); - - if (stat(Itm->DestFile.c_str(),&BufBase) != 0) - return _error->Errno("stat",_("Failed to stat")); - - // return done - Res.LastModified = BufBase.st_mtime; - Res.Size = BufBase.st_size; - Res.TakeHashes(Hash); - URIDone(Res); - - return true; -} - /*}}}*/ -/** \brief Wrapper class for testing rred */ /*{{{*/ -class TestRredMethod : public RredMethod { -public: - /** \brief Run rred in debug test mode - * - * This method can be used to run the rred method outside - * of the "normal" acquire environment for easier testing. - * - * \param base basename of all files involved in this rred test - */ - bool Run(char const *base) { - _config->CndSet("Debug::pkgAcquire::RRed", "true"); - FetchItem *test = new FetchItem; - test->DestFile = base; - return Fetch(test); - } + private: + void merge(void) + { + while (where->offset == 0 && where != changes.begin()) { + left(); + } + std::list<struct Change>::iterator next = where; + ++next; + + while (next != changes.end() && next->offset == 0) { + where->del_cnt += next->del_cnt; + next->del_cnt = 0; + if (next->add == NULL) { + next = changes.erase(next); + } else if (where->add == NULL) { + where->add = next->add; + where->add_len = next->add_len; + where->add_cnt = next->add_cnt; + next = changes.erase(next); + } else { + ++next; + } + } + } + + void go_to_change_for(size_t line) + { + while(where != changes.end()) { + if (line < pos) { + left(); + continue; + } + if (pos + where->offset + where->add_cnt <= line) { + right(); + continue; + } + // line is somewhere in this slot + if (line < pos + where->offset) { + break; + } else if (line == pos + where->offset) { + return; + } else { + split(line - pos); + right(); + return; + } + } + /* it goes before this patch */ + insert(line-pos); + } + + void new_change(void) { insert(where->offset); } + + void insert(size_t offset) + { + assert(pos_is_okay()); + assert(where == changes.end() || offset <= where->offset); + if (where != changes.end()) + where->offset -= offset; + changes.insert(where, Change(offset)); + --where; + assert(pos_is_okay()); + } + + void split(size_t offset) + { + assert(pos_is_okay()); + + assert(where->offset < offset); + assert(offset < where->offset + where->add_cnt); + + size_t keep_lines = offset - where->offset; + + Change before(*where); + + where->del_cnt = 0; + where->offset = 0; + where->skip_lines(keep_lines); + + before.add_cnt = keep_lines; + before.add_len -= where->add_len; + + changes.insert(where, before); + --where; + assert(pos_is_okay()); + } + + void delete_lines(size_t cnt) + { + std::list<struct Change>::iterator x = where; + assert(pos_is_okay()); + while (cnt > 0) + { + size_t del; + del = x->add_cnt; + if (del > cnt) + del = cnt; + x->skip_lines(del); + cnt -= del; + + ++x; + if (x == changes.end()) { + del = cnt; + } else { + del = x->offset; + if (del > cnt) + del = cnt; + x->offset -= del; + } + where->del_cnt += del; + cnt -= del; + } + assert(pos_is_okay()); + } + + void left(void) { + assert(pos_is_okay()); + --where; + pos -= where->offset + where->add_cnt; + assert(pos_is_okay()); + } + + void right(void) { + assert(pos_is_okay()); + pos += where->offset + where->add_cnt; + ++where; + assert(pos_is_okay()); + } +}; + +class Patch { + FileChanges filechanges; + MemBlock add_text; + + static bool retry_fwrite(char *b, size_t l, FILE *f, Hashes *hash) + { + size_t r = 1; + while (r > 0 && l > 0) + { + r = fwrite(b, 1, l, f); + if (hash) + hash->Add((unsigned char*)b, r); + l -= r; + b += r; + } + return l == 0; + } + + static void dump_rest(FILE *o, FILE *i, Hashes *hash) + { + char buffer[BLOCK_SIZE]; + size_t l; + while (0 < (l = fread(buffer, 1, sizeof(buffer), i))) { + if (!retry_fwrite(buffer, l, o, hash)) + break; + } + } + + static void dump_lines(FILE *o, FILE *i, size_t n, Hashes *hash) + { + char buffer[BLOCK_SIZE]; + while (n > 0) { + if (fgets(buffer, sizeof(buffer), i) == 0) + buffer[0] = '\0'; + size_t const l = strlen(buffer); + if (l == 0 || buffer[l-1] == '\n') + n--; + retry_fwrite(buffer, l, o, hash); + } + } + + static void skip_lines(FILE *i, int n) + { + char buffer[BLOCK_SIZE]; + while (n > 0) { + if (fgets(buffer, sizeof(buffer), i) == 0) + buffer[0] = '\0'; + size_t const l = strlen(buffer); + if (l == 0 || buffer[l-1] == '\n') + n--; + } + } + + static void dump_mem(FILE *o, char *p, size_t s, Hashes *hash) { + retry_fwrite(p, s, o, hash); + } + + public: + + void read_diff(FileFd &f) + { + char buffer[BLOCK_SIZE]; + bool cmdwanted = true; + + Change ch(0); + while(f.ReadLine(buffer, sizeof(buffer))) + { + if (cmdwanted) { + char *m, *c; + size_t s, e; + s = strtol(buffer, &m, 10); + if (m == buffer) { + s = e = ch.offset + ch.add_cnt; + c = buffer; + } else if (*m == ',') { + m++; + e = strtol(m, &c, 10); + } else { + e = s; + c = m; + } + switch(*c) { + case 'a': + cmdwanted = false; + ch.add = NULL; + ch.add_cnt = 0; + ch.add_len = 0; + ch.offset = s; + ch.del_cnt = 0; + break; + case 'c': + cmdwanted = false; + ch.add = NULL; + ch.add_cnt = 0; + ch.add_len = 0; + ch.offset = s - 1; + ch.del_cnt = e - s + 1; + break; + case 'd': + ch.offset = s - 1; + ch.del_cnt = e - s + 1; + ch.add = NULL; + ch.add_cnt = 0; + ch.add_len = 0; + filechanges.add_change(ch); + break; + } + } else { /* !cmdwanted */ + if (buffer[0] == '.' && buffer[1] == '\n') { + cmdwanted = true; + filechanges.add_change(ch); + } else { + char *last = NULL; + char *add; + size_t l; + if (ch.add) + last = ch.add + ch.add_len; + l = strlen(buffer); + add = add_text.add_easy(buffer, l, last); + if (!add) { + ch.add_len += l; + ch.add_cnt++; + } else { + if (ch.add) { + filechanges.add_change(ch); + ch.del_cnt = 0; + } + ch.offset += ch.add_cnt; + ch.add = add; + ch.add_len = l; + ch.add_cnt = 1; + } + } + } + } + } + + void write_diff(FILE *f) + { + unsigned long long line = 0; + std::list<struct Change>::reverse_iterator ch; + for (ch = filechanges.rbegin(); ch != filechanges.rend(); ++ch) { + line += ch->offset + ch->del_cnt; + } + + for (ch = filechanges.rbegin(); ch != filechanges.rend(); ++ch) { + std::list<struct Change>::reverse_iterator mg_i, mg_e = ch; + while (ch->del_cnt == 0 && ch->offset == 0) + ++ch; + line -= ch->del_cnt; + if (ch->add_cnt > 0) { + if (ch->del_cnt == 0) { + fprintf(f, "%llua\n", line); + } else if (ch->del_cnt == 1) { + fprintf(f, "%lluc\n", line+1); + } else { + fprintf(f, "%llu,%lluc\n", line+1, line+ch->del_cnt); + } + + mg_i = ch; + do { + dump_mem(f, mg_i->add, mg_i->add_len, NULL); + } while (mg_i-- != mg_e); + + fprintf(f, ".\n"); + } else if (ch->del_cnt == 1) { + fprintf(f, "%llud\n", line+1); + } else if (ch->del_cnt > 1) { + fprintf(f, "%llu,%llud\n", line+1, line+ch->del_cnt); + } + line -= ch->offset; + } + } + + void apply_against_file(FILE *out, FILE *in, Hashes *hash = NULL) + { + std::list<struct Change>::iterator ch; + for (ch = filechanges.begin(); ch != filechanges.end(); ++ch) { + dump_lines(out, in, ch->offset, hash); + skip_lines(in, ch->del_cnt); + dump_mem(out, ch->add, ch->add_len, hash); + } + dump_rest(out, in, hash); + } }; - /*}}}*/ -/** \brief Starter for the rred method (or its test method) {{{ - * - * Used without parameters is the normal behavior for methods for - * the APT acquire system. While this works great for the acquire system - * it is very hard to test the method and therefore the method also - * accepts one parameter which will switch it directly to debug test mode: - * The test mode expects that if "Testfile" is given as parameter - * the file "Testfile" should be ed-style patched with "Testfile.ed" - * and will write the result to "Testfile.result". - */ -int main(int argc, char *argv[]) { - if (argc <= 1) { - RredMethod Mth; - return Mth.Run(); - } else { - TestRredMethod Mth; - bool result = Mth.Run(argv[1]); - _error->DumpErrors(); - return result; - } + +class RredMethod : public pkgAcqMethod { + private: + bool Debug; + + protected: + virtual bool Fetch(FetchItem *Itm) { + Debug = _config->FindB("Debug::pkgAcquire::RRed", false); + URI Get = Itm->Uri; + std::string Path = Get.Host + Get.Path; // rred:/path - no host + + FetchResult Res; + Res.Filename = Itm->DestFile; + if (Itm->Uri.empty()) + { + Path = Itm->DestFile; + Itm->DestFile.append(".result"); + } else + URIStart(Res); + + std::vector<std::string> patchpaths; + Patch patch; + + if (FileExists(Path + ".ed") == true) + patchpaths.push_back(Path + ".ed"); + else + { + _error->PushToStack(); + std::vector<std::string> patches = GetListOfFilesInDir(flNotFile(Path), "gz", true, false); + _error->RevertToStack(); + + std::string const baseName = Path + ".ed."; + for (std::vector<std::string>::const_iterator p = patches.begin(); + p != patches.end(); ++p) + if (p->compare(0, baseName.length(), baseName) == 0) + patchpaths.push_back(*p); + } + + std::string patch_name; + for (std::vector<std::string>::iterator I = patchpaths.begin(); + I != patchpaths.end(); + ++I) + { + patch_name = *I; + if (Debug == true) + std::clog << "Patching " << Path << " with " << patch_name + << std::endl; + + FileFd p; + // all patches are compressed, even if the name doesn't reflect it + if (p.Open(patch_name, FileFd::ReadOnly, FileFd::Gzip) == false) { + std::cerr << "Could not open patch file " << patch_name << std::endl; + _error->DumpErrors(std::cerr); + abort(); + } + patch.read_diff(p); + p.Close(); + } + + if (Debug == true) + std::clog << "Applying patches against " << Path + << " and writing results to " << Itm->DestFile + << std::endl; + + FILE *inp = fopen(Path.c_str(), "r"); + FILE *out = fopen(Itm->DestFile.c_str(), "w"); + + Hashes hash; + + patch.apply_against_file(out, inp, &hash); + + fclose(out); + fclose(inp); + + if (Debug == true) { + std::clog << "rred: finished file patching of " << Path << "." << std::endl; + } + + struct stat bufbase, bufpatch; + if (stat(Path.c_str(), &bufbase) != 0 || + stat(patch_name.c_str(), &bufpatch) != 0) + return _error->Errno("stat", _("Failed to stat")); + + struct timeval times[2]; + times[0].tv_sec = bufbase.st_atime; + times[1].tv_sec = bufpatch.st_mtime; + times[0].tv_usec = times[1].tv_usec = 0; + if (utimes(Itm->DestFile.c_str(), times) != 0) + return _error->Errno("utimes",_("Failed to set modification time")); + + if (stat(Itm->DestFile.c_str(), &bufbase) != 0) + return _error->Errno("stat", _("Failed to stat")); + + Res.LastModified = bufbase.st_mtime; + Res.Size = bufbase.st_size; + Res.TakeHashes(hash); + URIDone(Res); + + return true; + } + + public: + RredMethod() : pkgAcqMethod("2.0",SingleInstance | SendConfig), Debug(false) {} +}; + +int main(int argc, char **argv) +{ + int i; + bool just_diff = true; + Patch patch; + + if (argc <= 1) { + RredMethod Mth; + return Mth.Run(); + } + + if (argc > 1 && strcmp(argv[1], "-f") == 0) { + just_diff = false; + i = 2; + } else { + i = 1; + } + + for (; i < argc; i++) { + FileFd p; + if (p.Open(argv[i], FileFd::ReadOnly) == false) { + _error->DumpErrors(std::cerr); + exit(1); + } + patch.read_diff(p); + } + + if (just_diff) { + patch.write_diff(stdout); + } else { + FILE *out, *inp; + out = stdout; + inp = stdin; + + patch.apply_against_file(out, inp); + } + return 0; } - /*}}}*/ diff --git a/methods/rsh.cc b/methods/rsh.cc index d76dca6ef..bd46d2515 100644 --- a/methods/rsh.cc +++ b/methods/rsh.cc @@ -17,10 +17,13 @@ #include <apt-pkg/fileutl.h> #include <apt-pkg/hashes.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/acquire-method.h> +#include <apt-pkg/strutl.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <sys/time.h> -#include <utime.h> #include <unistd.h> #include <signal.h> #include <stdio.h> @@ -256,7 +259,7 @@ bool RSHConn::WriteMsg(std::string &Text,bool Sync,const char *Fmt,...) /*}}}*/ // RSHConn::Size - Return the size of the file /*{{{*/ // --------------------------------------------------------------------- -/* Right now for successfull transfer the file size must be known in +/* Right now for successful transfer the file size must be known in advance. */ bool RSHConn::Size(const char *Path,unsigned long long &Size) { @@ -369,7 +372,7 @@ RSHMethod::RSHMethod() : pkgAcqMethod("1.0",SendConfig) signal(SIGINT,SigTerm); Server = 0; FailFd = -1; -}; +} /*}}}*/ // RSHMethod::Configuration - Handle a configuration message /*{{{*/ // --------------------------------------------------------------------- @@ -391,17 +394,18 @@ bool RSHMethod::Configuration(std::string Message) // RSHMethod::SigTerm - Clean up and timestamp the files on exit /*{{{*/ // --------------------------------------------------------------------- /* */ -void RSHMethod::SigTerm(int sig) +void RSHMethod::SigTerm(int) { if (FailFd == -1) _exit(100); - close(FailFd); - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); + // Transfer the modification times + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(FailFile.c_str(), times); + close(FailFd); _exit(100); } @@ -488,10 +492,11 @@ bool RSHMethod::Fetch(FetchItem *Itm) Fd.Close(); // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(FailFile.c_str(), times); // If the file is missing we hard fail otherwise transient fail if (Missing == true) @@ -501,25 +506,24 @@ bool RSHMethod::Fetch(FetchItem *Itm) } Res.Size = Fd.Size(); + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(Fd.Name().c_str(), times); + FailFd = -1; } Res.LastModified = FailTime; Res.TakeHashes(Hash); - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(Queue->DestFile.c_str(),&UBuf); - FailFd = -1; - URIDone(Res); return true; } /*}}}*/ -int main(int argc, const char *argv[]) +int main(int, const char *argv[]) { setlocale(LC_ALL, ""); diff --git a/methods/rsh.h b/methods/rsh.h index d7efa3f06..dd259e744 100644 --- a/methods/rsh.h +++ b/methods/rsh.h @@ -11,6 +11,8 @@ #define APT_RSH_H #include <string> +#include <time.h> + #include <apt-pkg/strutl.h> class Hashes; @@ -62,7 +64,7 @@ class RSHMethod : public pkgAcqMethod static std::string FailFile; static int FailFd; static time_t FailTime; - static void SigTerm(int); + static APT_NORETURN void SigTerm(int); public: diff --git a/methods/server.cc b/methods/server.cc index a2128441c..5a13f18a7 100644 --- a/methods/server.cc +++ b/methods/server.cc @@ -10,32 +10,27 @@ // Include Files /*{{{*/ #include <config.h> -#include <apt-pkg/fileutl.h> #include <apt-pkg/acquire-method.h> #include <apt-pkg/configuration.h> #include <apt-pkg/error.h> -#include <apt-pkg/hashes.h> -#include <apt-pkg/netrc.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/strutl.h> +#include <ctype.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/stat.h> #include <sys/time.h> -#include <utime.h> +#include <time.h> #include <unistd.h> -#include <signal.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <climits> #include <iostream> +#include <limits> #include <map> +#include <string> +#include <vector> -// Internet stuff -#include <netdb.h> - -#include "config.h" -#include "connect.h" -#include "rfc2553emu.h" -#include "http.h" +#include "server.h" #include <apti18n.h> /*}}}*/ @@ -86,7 +81,7 @@ ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File) if (Result == 100) continue; - // Tidy up the connection persistance state. + // Tidy up the connection persistence state. if (Encoding == Closes && HaveContent == true) Persistent = false; @@ -119,10 +114,10 @@ bool ServerState::HeaderLine(string Line) string::size_type Pos2 = Pos; while (Pos2 < Line.length() && isspace(Line[Pos2]) != 0) Pos2++; - + string Tag = string(Line,0,Pos); string Val = string(Line,Pos2); - + if (stringcasecmp(Tag.c_str(),Tag.c_str()+4,"HTTP") == 0) { // Evil servers return no version @@ -146,7 +141,7 @@ bool ServerState::HeaderLine(string Line) return _error->Error(_("The HTTP server sent an invalid reply header")); } - /* Check the HTTP response header to get the default persistance + /* Check the HTTP response header to get the default persistence state. */ if (Major < 1) Persistent = false; @@ -159,14 +154,14 @@ bool ServerState::HeaderLine(string Line) } return true; - } - + } + if (stringcasecmp(Tag,"Content-Length:") == 0) { if (Encoding == Closes) Encoding = Stream; HaveContent = true; - + // The length is already set from the Content-Range header if (StartPos != 0) return true; @@ -184,7 +179,7 @@ bool ServerState::HeaderLine(string Line) HaveContent = true; return true; } - + if (stringcasecmp(Tag,"Content-Range:") == 0) { HaveContent = true; @@ -201,12 +196,12 @@ bool ServerState::HeaderLine(string Line) return _error->Error(_("This HTTP server has broken range support")); return true; } - + if (stringcasecmp(Tag,"Transfer-Encoding:") == 0) { HaveContent = true; if (stringcasecmp(Val,"chunked") == 0) - Encoding = Chunked; + Encoding = Chunked; return true; } @@ -218,7 +213,7 @@ bool ServerState::HeaderLine(string Line) Persistent = true; return true; } - + if (stringcasecmp(Tag,"Last-Modified:") == 0) { if (RFC1123StrToTime(Val.c_str(), Date) == false) @@ -291,11 +286,15 @@ ServerMethod::DealWithHeaders(FetchResult &Res) } else { - NextURI = DeQuoteString(Server->Location); - URI tmpURI = NextURI; - // Do not allow a redirection to switch protocol - if (tmpURI.Access == "http") - return TRY_AGAIN_OR_REDIRECT; + NextURI = DeQuoteString(Server->Location); + URI tmpURI = NextURI; + URI Uri = Queue->Uri; + // same protocol redirects are okay + if (tmpURI.Access == Uri.Access) + return TRY_AGAIN_OR_REDIRECT; + // as well as http to https + else if (Uri.Access == "http" && tmpURI.Access == "https") + return TRY_AGAIN_OR_REDIRECT; } /* else pass through for error message */ } @@ -362,20 +361,20 @@ ServerMethod::DealWithHeaders(FetchResult &Res) /*}}}*/ // ServerMethod::SigTerm - Handle a fatal signal /*{{{*/ // --------------------------------------------------------------------- -/* This closes and timestamps the open file. This is neccessary to get +/* This closes and timestamps the open file. This is necessary to get resume behavoir on user abort */ void ServerMethod::SigTerm(int) { if (FailFd == -1) _exit(100); + + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(FailFile.c_str(), times); close(FailFd); - - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + _exit(100); } /*}}}*/ @@ -409,7 +408,7 @@ bool ServerMethod::Fetch(FetchItem *) } return true; -}; +} /*}}}*/ // ServerMethod::Loop - Main loop /*{{{*/ int ServerMethod::Loop() @@ -539,11 +538,10 @@ int ServerMethod::Loop() File = 0; // Timestamp - struct utimbuf UBuf; - time(&UBuf.actime); - UBuf.actime = Server->Date; - UBuf.modtime = Server->Date; - utime(Queue->DestFile.c_str(),&UBuf); + struct timeval times[2]; + times[0].tv_sec = times[1].tv_sec = Server->Date; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(Queue->DestFile.c_str(), times); // Send status to APT if (Result == true) diff --git a/methods/server.h b/methods/server.h index 4dc6a1f2f..0f45ab994 100644 --- a/methods/server.h +++ b/methods/server.h @@ -12,7 +12,10 @@ #define APT_SERVER_H #include <apt-pkg/strutl.h> +#include <apt-pkg/acquire-method.h> +#include <time.h> +#include <iostream> #include <string> using std::cout; @@ -32,7 +35,7 @@ struct ServerState // These are some statistics from the last parsed header lines unsigned long long Size; - signed long long StartPos; + unsigned long long StartPos; time_t Date; bool HaveContent; enum {Chunked,Stream,Closes} Encoding; @@ -62,7 +65,7 @@ struct ServerState /** \brief IO error while retrieving */ RUN_HEADERS_IO_ERROR, /** \brief Parse error after retrieving */ - RUN_HEADERS_PARSE_ERROR, + RUN_HEADERS_PARSE_ERROR }; /** \brief Get the headers before the data */ RunHeadersResult RunHeaders(FileFd * const File); @@ -126,7 +129,7 @@ class ServerMethod : public pkgAcqMethod static std::string FailFile; static int FailFd; static time_t FailTime; - static void SigTerm(int); + static APT_NORETURN void SigTerm(int); virtual bool Configuration(std::string Message); virtual bool Flush() { return Server->Flush(File); }; @@ -137,7 +140,7 @@ class ServerMethod : public pkgAcqMethod virtual ServerState * CreateServerState(URI uri) = 0; virtual void RotateDNS() = 0; - ServerMethod(const char *Ver,unsigned long Flags = 0) : pkgAcqMethod(Ver, Flags), PipelineDepth(0), AllowRedirect(false), Debug(false) {}; + ServerMethod(const char *Ver,unsigned long Flags = 0) : pkgAcqMethod(Ver, Flags), Server(NULL), File(NULL), PipelineDepth(0), AllowRedirect(false), Debug(false) {}; virtual ~ServerMethod() {}; }; |