X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/076cc664137ec4b8983a1d9fe69eaaec6a9d4788..3b5607fc31371190470074371793cb8500b5139e:/methods/ftp.cc diff --git a/methods/ftp.cc b/methods/ftp.cc index bbc4a3f22..66787a7be 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -1,9 +1,9 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: ftp.cc,v 1.28 2001/05/22 04:02:00 jgg Exp $ +// $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,14 +15,21 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#include + #include #include #include #include +#include +#include +#include +#include +#include +#include #include #include -#include #include #include #include @@ -39,6 +46,8 @@ #include "rfc2553emu.h" #include "connect.h" #include "ftp.h" + +#include /*}}}*/ using namespace std; @@ -52,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; @@ -67,10 +76,12 @@ time_t FtpMethod::FailTime = 0; // --------------------------------------------------------------------- /* */ FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(-1), DataFd(-1), - DataListenFd(-1), ServerName(Srv) + DataListenFd(-1), ServerName(Srv), + ForceExtended(false), TryPassive(true) { Debug = _config->FindB("Debug::Acquire::Ftp",false); PasvAddr = 0; + Buffer[0] = '\0'; } /*}}}*/ // FTPConn::~FTPConn - Destructor /*{{{*/ @@ -111,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) { @@ -158,18 +174,18 @@ bool FTPConn::Open(pkgAcqMethod *Owner) return false; // Login must be before getpeername otherwise dante won't work. - Owner->Status("Logging in"); + Owner->Status(_("Logging in")); bool Res = Login(); // Get the remote server's address PeerAddrLen = sizeof(PeerAddr); if (getpeername(ServerFd,(sockaddr *)&PeerAddr,&PeerAddrLen) != 0) - return _error->Errno("getpeername","Unable to determine the peer name"); + return _error->Errno("getpeername",_("Unable to determine the peer name")); // Get the local machine's address ServerAddrLen = sizeof(ServerAddr); if (getsockname(ServerFd,(sockaddr *)&ServerAddr,&ServerAddrLen) != 0) - return _error->Errno("getsockname","Unable to determine the local name"); + return _error->Errno("getsockname",_("Unable to determine the local name")); return Res; } @@ -200,19 +216,21 @@ bool FTPConn::Login() if (ReadResp(Tag,Msg) == false) return false; if (Tag >= 400) - return _error->Error("Server refused our connection and said: %s",Msg.c_str()); + return _error->Error(_("The server refused the connection and said: %s"),Msg.c_str()); // Send the user if (WriteMsg(Tag,Msg,"USER %s",User.c_str()) == false) return false; if (Tag >= 400) - return _error->Error("USER failed, server said: %s",Msg.c_str()); + return _error->Error(_("USER failed, server said: %s"),Msg.c_str()); - // Send the Password - if (WriteMsg(Tag,Msg,"PASS %s",Pass.c_str()) == false) - return false; - if (Tag >= 400) - return _error->Error("PASS failed, server said: %s",Msg.c_str()); + if (Tag == 331) { // 331 User name okay, need password. + // Send the Password + if (WriteMsg(Tag,Msg,"PASS %s",Pass.c_str()) == false) + return false; + if (Tag >= 400) + return _error->Error(_("PASS failed, server said: %s"),Msg.c_str()); + } // Enter passive mode if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true) @@ -226,13 +244,13 @@ bool FTPConn::Login() if (ReadResp(Tag,Msg) == false) return false; if (Tag >= 400) - return _error->Error("Server refused our connection and said: %s",Msg.c_str()); + return _error->Error(_("The server refused the connection and said: %s"),Msg.c_str()); // Perform proxy script execution Configuration::Item const *Opts = _config->Tree("Acquire::ftp::ProxyLogin"); if (Opts == 0 || Opts->Child == 0) - return _error->Error("A proxy server was specified but no login " - "script, Acquire::ftp::ProxyLogin is empty."); + return _error->Error(_("A proxy server was specified but no login " + "script, Acquire::ftp::ProxyLogin is empty.")); Opts = Opts->Child; // Iterate over the entire login script @@ -259,7 +277,7 @@ bool FTPConn::Login() if (WriteMsg(Tag,Msg,"%s",Tmp.c_str()) == false) return false; if (Tag >= 400) - return _error->Error("Login script command '%s' failed, server said: %s",Tmp.c_str(),Msg.c_str()); + return _error->Error(_("Login script command '%s' failed, server said: %s"),Tmp.c_str(),Msg.c_str()); } // Enter passive mode @@ -285,7 +303,7 @@ bool FTPConn::Login() if (WriteMsg(Tag,Msg,"TYPE I") == false) return false; if (Tag >= 400) - return _error->Error("TYPE failed, server said: %s",Msg.c_str()); + return _error->Error(_("TYPE failed, server said: %s"),Msg.c_str()); return true; } @@ -323,23 +341,23 @@ bool FTPConn::ReadLine(string &Text) if (WaitFd(ServerFd,false,TimeOut) == false) { Close(); - return _error->Error("Connection timeout"); + return _error->Error(_("Connection timeout")); } // Suck it back int Res = read(ServerFd,Buffer + Len,sizeof(Buffer) - Len); if (Res == 0) - _error->Error("Server closed the connection"); + _error->Error(_("Server closed the connection")); if (Res <= 0) { - _error->Errno("read","Read error"); + _error->Errno("read",_("Read error")); Close(); return false; } Len += Res; } - return _error->Error("A response overflowed the buffer."); + return _error->Error(_("A response overflowed the buffer.")); } /*}}}*/ // FTPConn::ReadResp - Read a full response from the server /*{{{*/ @@ -356,7 +374,7 @@ bool FTPConn::ReadResp(unsigned int &Ret,string &Text) char *End; Ret = strtol(Msg.c_str(),&End,10); if (End - Msg.c_str() != 3) - return _error->Error("Protocol corruption"); + return _error->Error(_("Protocol corruption")); // All done ? Text = Msg.c_str()+4; @@ -368,7 +386,7 @@ bool FTPConn::ReadResp(unsigned int &Ret,string &Text) } if (*End != '-') - return _error->Error("Protocol corruption"); + return _error->Error(_("Protocol corruption")); /* Okay, here we do the continued message trick. This is foolish, but proftpd follows the protocol as specified and wu-ftpd doesn't, so @@ -422,6 +440,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; @@ -434,13 +453,13 @@ bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...) if (WaitFd(ServerFd,true,TimeOut) == false) { Close(); - return _error->Error("Connection timeout"); + return _error->Error(_("Connection timeout")); } int Res = write(ServerFd,S + Start,Len); if (Res <= 0) { - _error->Errno("write","Write Error"); + _error->Errno("write",_("Write error")); Close(); return false; } @@ -550,7 +569,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; @@ -608,8 +627,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; @@ -618,7 +636,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; @@ -628,7 +646,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; @@ -652,8 +670,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 /*{{{*/ @@ -681,24 +698,24 @@ bool FTPConn::CreateDataFd() // Get a socket if ((DataFd = socket(PasvAddr->ai_family,PasvAddr->ai_socktype, PasvAddr->ai_protocol)) < 0) - return _error->Errno("socket","Could not create a socket"); + return _error->Errno("socket",_("Could not create a socket")); // Connect to the server SetNonBlock(DataFd,true); if (connect(DataFd,PasvAddr->ai_addr,PasvAddr->ai_addrlen) < 0 && errno != EINPROGRESS) - return _error->Errno("socket","Could not create a socket"); + return _error->Errno("socket",_("Could not create a socket")); /* This implements a timeout for connect by opening the connection nonblocking */ if (WaitFd(DataFd,true,TimeOut) == false) - return _error->Error("Could not connect data socket, connection timed out"); + return _error->Error(_("Could not connect data socket, connection timed out")); unsigned int Err; unsigned int Len = sizeof(Err); if (getsockopt(DataFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) - return _error->Errno("getsockopt","Failed"); + return _error->Errno("getsockopt",_("Failed")); if (Err != 0) - return _error->Error("Could not connect passive socket."); + return _error->Error(_("Could not connect passive socket.")); return true; } @@ -708,40 +725,40 @@ 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) - return _error->Error("getaddrinfo was unable to get a listening socket"); + if (getaddrinfo(0,"0",&Hints,&BindAddr) != 0 || BindAddr == NULL) + return _error->Error(_("getaddrinfo was unable to get a listening socket")); // Construct the socket if ((DataListenFd = socket(BindAddr->ai_family,BindAddr->ai_socktype, BindAddr->ai_protocol)) < 0) { freeaddrinfo(BindAddr); - return _error->Errno("socket","Could not create a socket"); + return _error->Errno("socket",_("Could not create a socket")); } // Bind and listen if (bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0) { freeaddrinfo(BindAddr); - return _error->Errno("bind","Could not bind a socket"); + return _error->Errno("bind",_("Could not bind a socket")); } freeaddrinfo(BindAddr); if (listen(DataListenFd,1) < 0) - return _error->Errno("listen","Could not listen on the socket"); + return _error->Errno("listen",_("Could not listen on the socket")); SetNonBlock(DataListenFd,true); // Determine the name to send to the remote struct sockaddr_storage Addr; socklen_t AddrLen = sizeof(Addr); if (getsockname(DataListenFd,(sockaddr *)&Addr,&AddrLen) < 0) - return _error->Errno("getsockname","Could not determine the socket's name"); + return _error->Errno("getsockname",_("Could not determine the socket's name")); + // Reverse the address. We need the server address and the data port. char Name[NI_MAXHOST]; @@ -772,7 +789,7 @@ bool FTPConn::CreateDataFd() (int)(Port >> 8) & 0xff, (int)(Port & 0xff)) == false) return false; if (Tag >= 400) - return _error->Error("Unable to send PORT command"); + return _error->Error(_("Unable to send PORT command")); return true; } @@ -782,7 +799,7 @@ bool FTPConn::CreateDataFd() if (AFMap[J].Family == ((struct sockaddr *)&Addr)->sa_family) Proto = AFMap[J].IETFFamily; if (Proto == 0) - return _error->Error("Unkonwn address family %u (AF_*)", + return _error->Error(_("Unknown address family %u (AF_*)"), ((struct sockaddr *)&Addr)->sa_family); // Send the EPRT command @@ -791,7 +808,7 @@ bool FTPConn::CreateDataFd() if (WriteMsg(Tag,Msg,"EPRT |%u|%s|%s|",Proto,Name,Service) == false) return false; if (Tag >= 400) - return _error->Error("EPRT failed, server said: %s",Msg.c_str()); + return _error->Error(_("EPRT failed, server said: %s"),Msg.c_str()); return true; } /*}}}*/ @@ -811,14 +828,14 @@ bool FTPConn::Finalize() // Wait for someone to connect.. if (WaitFd(DataListenFd,false,TimeOut) == false) - return _error->Error("Data socket connect timed out"); + return _error->Error(_("Data socket connect timed out")); // Accept the connection struct sockaddr_in Addr; socklen_t Len = sizeof(Addr); DataFd = accept(DataListenFd,(struct sockaddr *)&Addr,&Len); if (DataFd < 0) - return _error->Errno("accept","Unable to accept connection"); + return _error->Errno("accept",_("Unable to accept connection")); close(DataListenFd); DataListenFd = -1; @@ -830,7 +847,7 @@ 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, +bool FTPConn::Get(const char *Path,FileFd &To,unsigned long long Resume, Hashes &Hash,bool &Missing) { Missing = false; @@ -855,9 +872,9 @@ 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"); + _error->Errno("read",_("Problem hashing file")); return false; } } @@ -870,7 +887,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, { if (Tag == 550) Missing = true; - return _error->Error("Unable to fetch file, server said '%s'",Msg.c_str()); + return _error->Error(_("Unable to fetch file, server said '%s'"),Msg.c_str()); } // Finish off the data connection @@ -885,7 +902,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, if (WaitFd(DataFd,false,TimeOut) == false) { Close(); - return _error->Error("Data socket timed out"); + return _error->Error(_("Data socket timed out")); } // Read the data.. @@ -915,7 +932,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, if (ReadResp(Tag,Msg) == false) return false; if (Tag >= 400) - return _error->Error("Data transfer failed, server said '%s'",Msg.c_str()); + return _error->Error(_("Data transfer failed, server said '%s'"),Msg.c_str()); return true; } /*}}}*/ @@ -934,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); } /*}}}*/ @@ -973,7 +992,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) { @@ -990,8 +1011,8 @@ bool FtpMethod::Fetch(FetchItem *Itm) } // Get the files information - Status("Query"); - unsigned long Size; + Status(_("Query")); + unsigned long long Size; if (Server->Size(File,Size) == false || Server->ModTime(File,FailTime) == false) { @@ -1013,7 +1034,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; @@ -1023,7 +1044,7 @@ 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; } @@ -1044,41 +1065,48 @@ 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); - - // If the file is missing we hard fail otherwise transient fail - if (Missing == true) + 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()); return false; + } Fail(true); return true; } 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, ""); + /* See if we should be come the http client - we do this for http proxy urls */ if (getenv("ftp_proxy") != 0) @@ -1092,12 +1120,12 @@ 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"; - execl(Path.c_str(),Path.c_str(),0); - cerr << "Unable to invoke " << Path << endl; + string Path = flNotFile(argv[0]) + "http"; + execl(Path.c_str(),Path.c_str(),(char *)NULL); + cerr << _("Unable to invoke ") << Path << endl; exit(100); } }