summaryrefslogtreecommitdiff
path: root/methods
diff options
context:
space:
mode:
authorMichael Vogt <mvo@ubuntu.com>2014-04-01 12:28:56 +0200
committerMichael Vogt <mvo@ubuntu.com>2014-04-01 12:28:56 +0200
commitbe20eef52da4b7f361333ea70a8d705a98ae779e (patch)
tree4177a110ce6b1335fc4b85d5e53b298a65661f39 /methods
parenta555cf8be53d8b5557f004ecbde8482a169b79f3 (diff)
parent21b3eac8f9ab8e12b43fa8998a5aa5465f29adc5 (diff)
Merge remote-tracking branch 'upstream/debian/sid' into feature/apt-manpage
Conflicts: cmdline/apt.cc
Diffstat (limited to 'methods')
-rw-r--r--methods/cdrom.cc6
-rw-r--r--methods/connect.cc8
-rw-r--r--methods/copy.cc23
-rw-r--r--methods/file.cc5
-rw-r--r--methods/ftp.cc64
-rw-r--r--methods/ftp.h6
-rw-r--r--methods/gpgv.cc17
-rw-r--r--methods/gzip.cc67
-rw-r--r--methods/http.cc41
-rw-r--r--methods/http.h6
-rw-r--r--methods/http_main.cc5
-rw-r--r--methods/https.cc40
-rw-r--r--methods/https.h27
-rw-r--r--methods/mirror.cc54
-rw-r--r--methods/mirror.h4
-rw-r--r--methods/rfc2553emu.h2
-rw-r--r--methods/rred.cc1186
-rw-r--r--methods/rsh.cc48
-rw-r--r--methods/rsh.h4
-rw-r--r--methods/server.cc90
-rw-r--r--methods/server.h11
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() {};
};