X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/79f24b42cfa60fa79a427c5e37a01de303543a4b..258b9e512c4001e806c5c0966acecd3d742ec6e9:/methods/ftp.cc diff --git a/methods/ftp.cc b/methods/ftp.cc index 0c2aa00a7..a8bc95938 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 @@ -15,31 +15,38 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#include + #include #include #include #include +#include +#include +#include +#include +#include +#include #include #include -#include #include #include #include #include #include #include -#include // Internet stuff #include -#include #include #include #include "rfc2553emu.h" #include "connect.h" #include "ftp.h" + +#include /*}}}*/ using namespace std; @@ -53,9 +60,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; @@ -67,11 +74,14 @@ time_t FtpMethod::FailTime = 0; // FTPConn::FTPConn - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(-1), DataFd(-1), - DataListenFd(-1), ServerName(Srv) +FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(-1), DataFd(-1), + DataListenFd(-1), ServerName(Srv), + ForceExtended(false), TryPassive(true), + PeerAddrLen(0), ServerAddrLen(0) { Debug = _config->FindB("Debug::Acquire::Ftp",false); PasvAddr = 0; + Buffer[0] = '\0'; } /*}}}*/ // FTPConn::~FTPConn - Destructor /*{{{*/ @@ -112,23 +122,28 @@ bool FTPConn::Open(pkgAcqMethod *Owner) Close(); // Determine the proxy setting - if (getenv("ftp_proxy") == 0) + string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host); + if (!SpecificProxy.empty()) { - string DefProxy = _config->Find("Acquire::ftp::Proxy"); - string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host); - if (SpecificProxy.empty() == false) - { - if (SpecificProxy == "DIRECT") - Proxy = ""; - else - Proxy = SpecificProxy; - } - else - Proxy = DefProxy; + if (SpecificProxy == "DIRECT") + Proxy = ""; + else + Proxy = SpecificProxy; } else - Proxy = getenv("ftp_proxy"); - + { + string DefProxy = _config->Find("Acquire::ftp::Proxy"); + if (!DefProxy.empty()) + { + Proxy = DefProxy; + } + else + { + char* result = getenv("ftp_proxy"); + Proxy = result ? result : ""; + } + } + // Parse no_proxy, a , separated list of domains if (getenv("no_proxy") != 0) { @@ -243,19 +258,21 @@ bool FTPConn::Login() { if (Opts->Value.empty() == true) continue; - + // Substitute the variables into the command - char SitePort[20]; - if (ServerName.Port != 0) - sprintf(SitePort,"%u",ServerName.Port); - else - strcpy(SitePort,"21"); string Tmp = Opts->Value; Tmp = SubstVar(Tmp,"$(PROXY_USER)",Proxy.User); Tmp = SubstVar(Tmp,"$(PROXY_PASS)",Proxy.Password); Tmp = SubstVar(Tmp,"$(SITE_USER)",User); Tmp = SubstVar(Tmp,"$(SITE_PASS)",Pass); - Tmp = SubstVar(Tmp,"$(SITE_PORT)",SitePort); + if (ServerName.Port != 0) + { + std::string SitePort; + strprintf(SitePort, "%u", ServerName.Port); + Tmp = SubstVar(Tmp,"$(SITE_PORT)", SitePort); + } + else + Tmp = SubstVar(Tmp,"$(SITE_PORT)", "21"); Tmp = SubstVar(Tmp,"$(SITE)",ServerName.Host); // Send the command @@ -425,6 +442,7 @@ bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...) char S[400]; vsnprintf(S,sizeof(S) - 4,Fmt,args); strcat(S,"\r\n"); + va_end(args); if (Debug == true) cerr << "-> '" << QuoteString(S,"") << "'" << endl; @@ -553,7 +571,7 @@ bool FTPConn::ExtGoPasv() string::const_iterator List[4]; unsigned Count = 0; Pos++; - for (string::const_iterator I = Msg.begin() + Pos; I < Msg.end(); I++) + for (string::const_iterator I = Msg.begin() + Pos; I < Msg.end(); ++I) { if (*I != Msg[Pos]) continue; @@ -611,8 +629,7 @@ bool FTPConn::ExtGoPasv() } // Get a new passive address. - int Res; - if ((Res = getaddrinfo(IP.c_str(),PStr,&Hints,&PasvAddr)) != 0) + if (getaddrinfo(IP.c_str(),PStr,&Hints,&PasvAddr) != 0) return true; return true; @@ -621,7 +638,7 @@ bool FTPConn::ExtGoPasv() // FTPConn::Size - Return the size of a file /*{{{*/ // --------------------------------------------------------------------- /* Grab the file size from the server, 0 means no size or empty file */ -bool FTPConn::Size(const char *Path,unsigned long &Size) +bool FTPConn::Size(const char *Path,unsigned long long &Size) { // Query the size unsigned int Tag; @@ -631,7 +648,7 @@ bool FTPConn::Size(const char *Path,unsigned long &Size) return false; char *End; - Size = strtol(Msg.c_str(),&End,10); + Size = strtoull(Msg.c_str(),&End,10); if (Tag >= 400 || End == Msg.c_str()) Size = 0; return true; @@ -655,8 +672,7 @@ bool FTPConn::ModTime(const char *Path, time_t &Time) return true; // Parse it - StrToTime(Msg,Time); - return true; + return FTPMDTMStrToTime(Msg.c_str(), Time); } /*}}}*/ // FTPConn::CreateDataFd - Get a data connection /*{{{*/ @@ -711,14 +727,13 @@ bool FTPConn::CreateDataFd() DataListenFd = -1; // Get the information for a listening socket. - struct addrinfo *BindAddr = 0; + struct addrinfo *BindAddr = NULL; struct addrinfo Hints; memset(&Hints,0,sizeof(Hints)); Hints.ai_socktype = SOCK_STREAM; Hints.ai_flags |= AI_PASSIVE; Hints.ai_family = ((struct sockaddr *)&ServerAddr)->sa_family; - int Res; - if ((Res = getaddrinfo(0,"0",&Hints,&BindAddr)) != 0) + if (getaddrinfo(0,"0",&Hints,&BindAddr) != 0 || BindAddr == NULL) return _error->Error(_("getaddrinfo was unable to get a listening socket")); // Construct the socket @@ -730,7 +745,7 @@ bool FTPConn::CreateDataFd() } // Bind and listen - if (bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0) + if (::bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0) { freeaddrinfo(BindAddr); return _error->Errno("bind",_("Could not bind a socket")); @@ -834,8 +849,9 @@ bool FTPConn::Finalize() // --------------------------------------------------------------------- /* This opens a data connection, sends REST and RETR and then transfers the file over. */ -bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, - Hashes &Hash,bool &Missing) +bool FTPConn::Get(const char *Path,FileFd &To,unsigned long long Resume, + Hashes &Hash,bool &Missing, unsigned long long MaximumSize, + pkgAcqMethod *Owner) { Missing = false; if (CreateDataFd() == false) @@ -859,7 +875,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, if (Resume != 0) { - if (Hash.AddFD(To.Fd(),Resume) == false) + if (Hash.AddFD(To,Resume) == false) { _error->Errno("read",_("Problem hashing file")); return false; @@ -908,7 +924,14 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, { Close(); return false; - } + } + + if (MaximumSize > 0 && To.Tell() > MaximumSize) + { + Owner->SetFailReason("MaximumSizeExceeded"); + return _error->Error("Writing more data than expected (%llu > %llu)", + To.Tell(), MaximumSize); + } } // All done @@ -927,7 +950,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, // FtpMethod::FtpMethod - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -FtpMethod::FtpMethod() : pkgAcqMethod("1.0",SendConfig) +FtpMethod::FtpMethod() : aptMethod("ftp","1.0",SendConfig) { signal(SIGTERM,SigTerm); signal(SIGINT,SigTerm); @@ -938,20 +961,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); } /*}}}*/ @@ -960,10 +985,11 @@ void FtpMethod::SigTerm(int) /* We stash the desired pipeline depth */ bool FtpMethod::Configuration(string Message) { - if (pkgAcqMethod::Configuration(Message) == false) + if (aptMethod::Configuration(Message) == false) return false; - + TimeOut = _config->FindI("Acquire::Ftp::Timeout",TimeOut); + return true; } /*}}}*/ @@ -977,7 +1003,9 @@ bool FtpMethod::Fetch(FetchItem *Itm) FetchResult Res; Res.Filename = Itm->DestFile; Res.IMSHit = false; - + + maybe_add_auth (Get, _config->FindFile("Dir::Etc::netrc")); + // Connect to the server if (Server == 0 || Server->Comp(Get) == false) { @@ -995,7 +1023,7 @@ bool FtpMethod::Fetch(FetchItem *Itm) // Get the files information Status(_("Query")); - unsigned long Size; + unsigned long long Size; if (Server->Size(File,Size) == false || Server->ModTime(File,FailTime) == false) { @@ -1017,7 +1045,7 @@ bool FtpMethod::Fetch(FetchItem *Itm) struct stat Buf; if (stat(Itm->DestFile.c_str(),&Buf) == 0) { - if (Size == (unsigned)Buf.st_size && FailTime == Buf.st_mtime) + if (Size == (unsigned long long)Buf.st_size && FailTime == Buf.st_mtime) { Res.Size = Buf.st_size; Res.LastModified = Buf.st_mtime; @@ -1027,12 +1055,12 @@ bool FtpMethod::Fetch(FetchItem *Itm) } // Resume? - if (FailTime == Buf.st_mtime && Size > (unsigned)Buf.st_size) + if (FailTime == Buf.st_mtime && Size > (unsigned long long)Buf.st_size) Res.ResumePoint = Buf.st_size; } // Open the file - Hashes Hash; + Hashes Hash(Itm->ExpectedHashes); { FileFd Fd(Itm->DestFile,FileFd::WriteAny); if (_error->PendingError() == true) @@ -1041,24 +1069,25 @@ bool FtpMethod::Fetch(FetchItem *Itm) URIStart(Res); FailFile = Itm->DestFile; - FailFile.c_str(); // Make sure we dont do a malloc in the signal handler + FailFile.c_str(); // Make sure we don't do a malloc in the signal handler FailFd = Fd.Fd(); bool Missing; - if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing) == false) + if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing,Itm->MaximumSize,this) == 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) { - unlink(FailFile.c_str()); + RemoveFile("ftp", FailFile); return false; } Fail(true); @@ -1066,25 +1095,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, ""); @@ -1101,7 +1131,7 @@ int main(int argc,const char *argv[]) char S[300]; snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy")); putenv(S); - putenv("no_proxy="); + putenv((char *)"no_proxy="); // Run the http method string Path = flNotFile(argv[0]) + "http"; @@ -1112,6 +1142,6 @@ int main(int argc,const char *argv[]) } FtpMethod Mth; - + return Mth.Run(); }