X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/f58a97d3de5b43fd2cf8c0928939241b7b01c67d..eb3947c6510042c054a319d8053821faf7244dea:/methods/ftp.cc?ds=inline diff --git a/methods/ftp.cc b/methods/ftp.cc index 1780ac740..97248f900 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -1,9 +1,9 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: ftp.cc,v 1.18 1999/12/10 07:21:52 jgg Exp $ +// $Id: ftp.cc,v 1.31.2.1 2004/01/16 18:58:50 mdz Exp $ /* ###################################################################### - HTTP Aquire Method - This is the FTP aquire method for APT. + FTP Aquire Method - This is the FTP aquire 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 @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include @@ -28,6 +29,8 @@ #include #include #include +#include +#include // Internet stuff #include @@ -40,6 +43,22 @@ #include "ftp.h" /*}}}*/ +using namespace std; + +/* This table is for the EPRT and EPSV commands, it maps the OS address + family to the IETF address families */ +struct AFMap +{ + unsigned long Family; + unsigned long IETFFamily; +}; + +#ifndef AF_INET6 +struct AFMap AFMap[] = {{AF_INET,1},{}}; +#else +struct AFMap AFMap[] = {{AF_INET,1},{AF_INET6,2},{}}; +#endif + unsigned long TimeOut = 120; URI Proxy; string FtpMethod::FailFile; @@ -53,7 +72,7 @@ FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(-1), DataFd(-1), DataListenFd(-1), ServerName(Srv) { Debug = _config->FindB("Debug::Acquire::Ftp",false); - memset(&PasvAddr,0,sizeof(PasvAddr)); + PasvAddr = 0; } /*}}}*/ // FTPConn::~FTPConn - Destructor /*{{{*/ @@ -75,7 +94,10 @@ void FTPConn::Close() DataFd = -1; close(DataListenFd); DataListenFd = -1; - memset(&PasvAddr,0,sizeof(PasvAddr)); + + if (PasvAddr != 0) + freeaddrinfo(PasvAddr); + PasvAddr = 0; } /*}}}*/ // FTPConn::Open - Open a new connection /*{{{*/ @@ -89,24 +111,36 @@ bool FTPConn::Open(pkgAcqMethod *Owner) return true; 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) + { + if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true) + Proxy = ""; + } // Determine what host and port to use based on the proxy settings int Port = 0; @@ -124,15 +158,27 @@ bool FTPConn::Open(pkgAcqMethod *Owner) Host = Proxy.Host; } - // Connect to the remote server + /* Connect to the remote server. Since FTP is connection oriented we + want to make sure we get a new server every time we reconnect */ + RotateDNS(); if (Connect(Host,Port,"ftp",21,ServerFd,TimeOut,Owner) == false) return false; - socklen_t Len = sizeof(Peer); - if (getpeername(ServerFd,(sockaddr *)&Peer,&Len) != 0) - return _error->Errno("getpeername","Unable to determine the peer name"); + + // Login must be before getpeername otherwise dante won't work. + 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")); + + // 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")); - Owner->Status("Logging in"); - return Login(); + return Res; } /*}}}*/ // FTPConn::Login - Login to the remote server /*{{{*/ @@ -146,7 +192,7 @@ bool FTPConn::Login() // Setup the variables needed for authentication string User = "anonymous"; - string Pass = "apt_get_ftp_2.0@debian.linux.user"; + string Pass = "apt_get_ftp_2.1@debian.linux.user"; // Fill in the user/pass if (ServerName.User.empty() == false) @@ -161,25 +207,27 @@ 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) TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true); else - TryPassive = _config->FindB("Acquire::FTP::Passive",true); + TryPassive = _config->FindB("Acquire::FTP::Passive",true); } else { @@ -187,13 +235,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 @@ -220,7 +268,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 @@ -236,11 +284,17 @@ bool FTPConn::Login() } } + // Force the use of extended commands + if (_config->Exists("Acquire::FTP::ForceExtended::" + ServerName.Host) == true) + ForceExtended = _config->FindB("Acquire::FTP::ForceExtended::" + ServerName.Host,true); + else + ForceExtended = _config->FindB("Acquire::FTP::ForceExtended",false); + // Binary mode 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; } @@ -278,21 +332,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")); 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 /*{{{*/ @@ -309,7 +365,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; @@ -321,7 +377,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 @@ -387,13 +443,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; } @@ -409,10 +465,19 @@ bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...) // --------------------------------------------------------------------- /* Try to enter passive mode, the return code does not indicate if passive mode could or could not be established, only if there was a fatal error. - Borrowed mostly from lftp. We have to enter passive mode every time - we make a data connection :| */ + We have to enter passive mode every time we make a data connection :| */ bool FTPConn::GoPasv() { + /* The PASV command only works on IPv4 sockets, even though it could + in theory suppory IPv6 via an all zeros reply */ + if (((struct sockaddr *)&PeerAddr)->sa_family != AF_INET || + ForceExtended == true) + return ExtGoPasv(); + + if (PasvAddr != 0) + freeaddrinfo(PasvAddr); + PasvAddr = 0; + // Try to enable pasv mode unsigned int Tag; string Msg; @@ -422,41 +487,139 @@ bool FTPConn::GoPasv() // Unsupported function string::size_type Pos = Msg.find('('); if (Tag >= 400 || Pos == string::npos) - { - memset(&PasvAddr,0,sizeof(PasvAddr)); return true; - } // Scan it unsigned a0,a1,a2,a3,p0,p1; if (sscanf(Msg.c_str() + Pos,"(%u,%u,%u,%u,%u,%u)",&a0,&a1,&a2,&a3,&p0,&p1) != 6) + return true; + + /* Some evil servers return 0 to mean their addr. We can actually speak + to these servers natively using IPv6 */ + if (a0 == 0 && a1 == 0 && a2 == 0 && a3 == 0) { - memset(&PasvAddr,0,sizeof(PasvAddr)); + // Get the IP in text form + char Name[NI_MAXHOST]; + char Service[NI_MAXSERV]; + getnameinfo((struct sockaddr *)&PeerAddr,PeerAddrLen, + Name,sizeof(Name),Service,sizeof(Service), + NI_NUMERICHOST|NI_NUMERICSERV); + + struct addrinfo Hints; + memset(&Hints,0,sizeof(Hints)); + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_family = ((struct sockaddr *)&PeerAddr)->sa_family; + Hints.ai_flags |= AI_NUMERICHOST; + + // Get a new passive address. + char Port[100]; + snprintf(Port,sizeof(Port),"%u",(p0 << 8) + p1); + if (getaddrinfo(Name,Port,&Hints,&PasvAddr) != 0) + return true; return true; } - // lftp used this horrid byte order manipulation.. Ik. - PasvAddr.sin_family = AF_INET; - unsigned char *a; - unsigned char *p; - a = (unsigned char *)&PasvAddr.sin_addr; - p = (unsigned char *)&PasvAddr.sin_port; + struct addrinfo Hints; + memset(&Hints,0,sizeof(Hints)); + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_family = AF_INET; + Hints.ai_flags |= AI_NUMERICHOST; - // Some evil servers return 0 to mean their addr - if (a0 == 0 && a1 == 0 && a2 == 0 && a3 == 0) + // Get a new passive address. + char Port[100]; + snprintf(Port,sizeof(Port),"%u",(p0 << 8) + p1); + char Name[100]; + snprintf(Name,sizeof(Name),"%u.%u.%u.%u",a0,a1,a2,a3); + if (getaddrinfo(Name,Port,&Hints,&PasvAddr) != 0) + return true; + return true; +} + /*}}}*/ +// FTPConn::ExtGoPasv - Enter Extended Passive mode /*{{{*/ +// --------------------------------------------------------------------- +/* Try to enter extended passive mode. See GoPasv above and RFC 2428 */ +bool FTPConn::ExtGoPasv() +{ + if (PasvAddr != 0) + freeaddrinfo(PasvAddr); + PasvAddr = 0; + + // Try to enable pasv mode + unsigned int Tag; + string Msg; + if (WriteMsg(Tag,Msg,"EPSV") == false) + return false; + + // Unsupported function + string::size_type Pos = Msg.find('('); + if (Tag >= 400 || Pos == string::npos) + return true; + + // Scan it + string::const_iterator List[4]; + unsigned Count = 0; + Pos++; + for (string::const_iterator I = Msg.begin() + Pos; I < Msg.end(); I++) { - PasvAddr.sin_addr = Peer.sin_addr; + if (*I != Msg[Pos]) + continue; + if (Count >= 4) + return true; + List[Count++] = I; + } + if (Count != 4) + return true; + + // Break it up .. + unsigned long Proto = 0; + unsigned long Port = 0; + string IP; + IP = string(List[1]+1,List[2]); + Port = atoi(string(List[2]+1,List[3]).c_str()); + if (IP.empty() == false) + Proto = atoi(string(List[0]+1,List[1]).c_str()); + + if (Port == 0) + return false; + + // String version of the port + char PStr[100]; + snprintf(PStr,sizeof(PStr),"%lu",Port); + + // Get the IP in text form + struct addrinfo Hints; + memset(&Hints,0,sizeof(Hints)); + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_flags |= AI_NUMERICHOST; + + /* The RFC defined case, connect to the old IP/protocol using the + new port. */ + if (IP.empty() == true) + { + // Get the IP in text form + char Name[NI_MAXHOST]; + char Service[NI_MAXSERV]; + getnameinfo((struct sockaddr *)&PeerAddr,PeerAddrLen, + Name,sizeof(Name),Service,sizeof(Service), + NI_NUMERICHOST|NI_NUMERICSERV); + IP = Name; + Hints.ai_family = ((struct sockaddr *)&PeerAddr)->sa_family; } else { - a[0] = a0; - a[1] = a1; - a[2] = a2; - a[3] = a3; + // Get the family.. + Hints.ai_family = 0; + for (unsigned J = 0; AFMap[J].Family != 0; J++) + if (AFMap[J].IETFFamily == Proto) + Hints.ai_family = AFMap[J].Family; + if (Hints.ai_family == 0) + return true; } - p[0] = p0; - p[1] = p1; + // Get a new passive address. + int Res; + if ((Res = getaddrinfo(IP.c_str(),PStr,&Hints,&PasvAddr)) != 0) + return true; return true; } @@ -498,8 +661,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 /*{{{*/ @@ -517,34 +679,35 @@ bool FTPConn::CreateDataFd() return false; // Oops, didn't work out, don't bother trying again. - if (PasvAddr.sin_port == 0) + if (PasvAddr == 0) TryPassive = false; } // Passive mode? - if (PasvAddr.sin_port != 0) + if (PasvAddr != 0) { // Get a socket - if ((DataFd = socket(AF_INET,SOCK_STREAM,0)) < 0) - return _error->Errno("socket","Could not create a socket"); + if ((DataFd = socket(PasvAddr->ai_family,PasvAddr->ai_socktype, + PasvAddr->ai_protocol)) < 0) + return _error->Errno("socket",_("Could not create a socket")); // Connect to the server SetNonBlock(DataFd,true); - if (connect(DataFd,(sockaddr *)&PasvAddr,sizeof(PasvAddr)) < 0 && + 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(ServerFd,true,TimeOut) == false) - return _error->Error("Could not connect data socket, connection timed out"); + if (WaitFd(DataFd,true,TimeOut) == false) + return _error->Error(_("Could not connect data socket, connection timed out")); unsigned int Err; unsigned int Len = sizeof(Err); - if (getsockopt(ServerFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) - return _error->Errno("getsockopt","Failed"); + if (getsockopt(DataFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) + return _error->Errno("getsockopt",_("Failed")); if (Err != 0) - return _error->Error("Could not connect."); - + return _error->Error(_("Could not connect passive socket.")); + return true; } @@ -552,43 +715,92 @@ bool FTPConn::CreateDataFd() close(DataListenFd); DataListenFd = -1; - // Get a socket - if ((DataListenFd = socket(AF_INET,SOCK_STREAM,0)) < 0) - return _error->Errno("socket","Could not create a socket"); + // Get the information for a listening socket. + struct addrinfo *BindAddr = 0; + 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")); + + // 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")); + } // Bind and listen - sockaddr_in Addr; - memset(&Addr,0,sizeof(Addr)); - if (bind(DataListenFd,(sockaddr *)&Addr,sizeof(Addr)) < 0) - return _error->Errno("bind","Could not bind a socket"); + if (bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0) + { + freeaddrinfo(BindAddr); + 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 - sockaddr_in Addr2; - socklen_t Jnk = sizeof(Addr); - if (getsockname(DataListenFd,(sockaddr *)&Addr,&Jnk) < 0) - return _error->Errno("getsockname","Could not determine the socket's name"); - Jnk = sizeof(Addr2); - if (getsockname(ServerFd,(sockaddr *)&Addr2,&Jnk) < 0) - return _error->Errno("getsockname","Could not determine the socket's name"); - - // This bit ripped from qftp - unsigned long badr = ntohl(*(unsigned long *)&Addr2.sin_addr); - unsigned long bp = ntohs(Addr.sin_port); - - // Send the port command + 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")); + + + // Reverse the address. We need the server address and the data port. + char Name[NI_MAXHOST]; + char Service[NI_MAXSERV]; + char Service2[NI_MAXSERV]; + getnameinfo((struct sockaddr *)&Addr,AddrLen, + Name,sizeof(Name),Service,sizeof(Service), + NI_NUMERICHOST|NI_NUMERICSERV); + getnameinfo((struct sockaddr *)&ServerAddr,ServerAddrLen, + Name,sizeof(Name),Service2,sizeof(Service2), + NI_NUMERICHOST|NI_NUMERICSERV); + + // Send off an IPv4 address in the old port format + if (((struct sockaddr *)&Addr)->sa_family == AF_INET && + ForceExtended == false) + { + // Convert the dots in the quad into commas + for (char *I = Name; *I != 0; I++) + if (*I == '.') + *I = ','; + unsigned long Port = atoi(Service); + + // Send the port command + unsigned int Tag; + string Msg; + if (WriteMsg(Tag,Msg,"PORT %s,%d,%d", + Name, + (int)(Port >> 8) & 0xff, (int)(Port & 0xff)) == false) + return false; + if (Tag >= 400) + return _error->Error(_("Unable to send PORT command")); + return true; + } + + // Construct an EPRT command + unsigned Proto = 0; + for (unsigned J = 0; AFMap[J].Family != 0; J++) + if (AFMap[J].Family == ((struct sockaddr *)&Addr)->sa_family) + Proto = AFMap[J].IETFFamily; + if (Proto == 0) + return _error->Error(_("Unknown address family %u (AF_*)"), + ((struct sockaddr *)&Addr)->sa_family); + + // Send the EPRT command unsigned int Tag; string Msg; - if (WriteMsg(Tag,Msg,"PORT %d,%d,%d,%d,%d,%d", - (int) (badr >> 24) & 0xff, (int) (badr >> 16) & 0xff, - (int) (badr >> 8) & 0xff, (int) badr & 0xff, - (int) (bp >> 8) & 0xff, (int) bp & 0xff) == false) + if (WriteMsg(Tag,Msg,"EPRT |%u|%s|%s|",Proto,Name,Service) == false) return false; if (Tag >= 400) - return _error->Error("Unable to send port command"); - + return _error->Error(_("EPRT failed, server said: %s"),Msg.c_str()); return true; } /*}}}*/ @@ -599,7 +811,7 @@ bool FTPConn::CreateDataFd() bool FTPConn::Finalize() { // Passive mode? Do nothing - if (PasvAddr.sin_port != 0) + if (PasvAddr != 0) return true; // Close any old socket.. @@ -608,14 +820,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; @@ -628,7 +840,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, - MD5Summation &MD5,bool &Missing) + Hashes &Hash,bool &Missing) { Missing = false; if (CreateDataFd() == false) @@ -652,9 +864,9 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, if (Resume != 0) { - if (MD5.AddFD(To.Fd(),Resume) == false) + if (Hash.AddFD(To.Fd(),Resume) == false) { - _error->Errno("read","Problem hashing file"); + _error->Errno("read",_("Problem hashing file")); return false; } } @@ -667,7 +879,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 @@ -682,7 +894,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.. @@ -696,7 +908,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume, break; } - MD5.Add(Buffer,Res); + Hash.Add(Buffer,Res); if (To.Write(Buffer,Res) == false) { Close(); @@ -712,7 +924,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; } /*}}}*/ @@ -770,7 +982,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) { @@ -787,7 +1001,7 @@ bool FtpMethod::Fetch(FetchItem *Itm) } // Get the files information - Status("Query"); + Status(_("Query")); unsigned long Size; if (Server->Size(File,Size) == false || Server->ModTime(File,FailTime) == false) @@ -814,6 +1028,7 @@ bool FtpMethod::Fetch(FetchItem *Itm) { Res.Size = Buf.st_size; Res.LastModified = Buf.st_mtime; + Res.ResumePoint = Buf.st_size; URIDone(Res); return true; } @@ -824,7 +1039,7 @@ bool FtpMethod::Fetch(FetchItem *Itm) } // Open the file - MD5Summation MD5; + Hashes Hash; { FileFd Fd(Itm->DestFile,FileFd::WriteAny); if (_error->PendingError() == true) @@ -837,20 +1052,22 @@ bool FtpMethod::Fetch(FetchItem *Itm) FailFd = Fd.Fd(); bool Missing; - if (Server->Get(File,Fd,Res.ResumePoint,MD5,Missing) == false) + if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing) == false) { Fd.Close(); // Timestamp struct utimbuf UBuf; - time(&UBuf.actime); 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) + // 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; } @@ -859,11 +1076,10 @@ bool FtpMethod::Fetch(FetchItem *Itm) } Res.LastModified = FailTime; - Res.MD5Sum = MD5.Result(); + Res.TakeHashes(Hash); // Timestamp struct utimbuf UBuf; - time(&UBuf.actime); UBuf.actime = FailTime; UBuf.modtime = FailTime; utime(Queue->DestFile.c_str(),&UBuf); @@ -877,22 +1093,27 @@ bool FtpMethod::Fetch(FetchItem *Itm) int main(int argc,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) { URI Proxy = string(getenv("ftp_proxy")); + + // Run the HTTP method if (Proxy.Access == "http") { // Copy over the environment setting char S[300]; snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy")); putenv(S); + 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); } }