Loading lib/ftp.c +555 −499 Original line number Diff line number Diff line Loading @@ -92,8 +92,8 @@ #endif /* Local API functions */ static CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode _ftp_cwd(struct connectdata *conn, char *path); static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode ftp_cwd(struct connectdata *conn, char *path); /* easy-to-use macro: */ #define ftpsendf Curl_ftpsendf Loading Loading @@ -590,7 +590,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn) /* Send any post-transfer QUOTE strings? */ if(data->set.postquote) { CURLcode result = _ftp_sendquote(conn, data->set.postquote); CURLcode result = ftp_sendquote(conn, data->set.postquote); return result; } Loading @@ -599,7 +599,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn) static CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) { struct curl_slist *item; ssize_t nread; Loading Loading @@ -628,7 +628,7 @@ CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) } static CURLcode _ftp_cwd(struct connectdata *conn, char *path) CURLcode ftp_cwd(struct connectdata *conn, char *path) { ssize_t nread; int ftpcode; Loading @@ -648,7 +648,7 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path) } static CURLcode _ftp_getfiletime(struct connectdata *conn, char *file) CURLcode ftp_getfiletime(struct connectdata *conn, char *file) { CURLcode result=CURLE_OK; int ftpcode; /* for ftp status */ Loading Loading @@ -683,7 +683,7 @@ CURLcode _ftp_getfiletime(struct connectdata *conn, char *file) return result; } static CURLcode _ftp_transfertype(struct connectdata *conn, static CURLcode ftp_transfertype(struct connectdata *conn, bool ascii) { struct SessionHandle *data = conn->data; Loading @@ -707,7 +707,7 @@ static CURLcode _ftp_transfertype(struct connectdata *conn, } static CURLcode _ftp_getsize(struct connectdata *conn, char *file, CURLcode ftp_getsize(struct connectdata *conn, char *file, ssize_t *size) { struct SessionHandle *data = conn->data; Loading Loading @@ -741,12 +741,9 @@ CURLcode _ftp_getsize(struct connectdata *conn, char *file, */ static void ftp_pasv_verbose(struct connectdata *conn, #ifdef ENABLE_IPV6 struct addrinfo *newhost #else char *newhost /* ipv4 */ #endif ) Curl_addrinfo *addr, char *newhost, /* ascii version */ int port) { #ifndef ENABLE_IPV6 /***************************************************************** Loading @@ -757,11 +754,10 @@ ftp_pasv_verbose(struct connectdata *conn, struct in_addr in; struct hostent * answer; #if defined (HAVE_INET_NTOA_R) #ifdef HAVE_INET_NTOA_R char ntoa_buf[64]; #endif #ifndef ENABLE_IPV6 struct sockaddr_in serv_addr; char hostent_buf[8192]; #endif Loading Loading @@ -817,11 +813,11 @@ ftp_pasv_verbose(struct connectdata *conn, infof(conn->data, "Connecting to %s (%s) port %u\n", answer?answer->h_name:newhost, #if defined(HAVE_INET_NTOA_R) inet_ntoa_r(in, ip_addr=ntoa_buf, sizeof(ntoa_buf)), inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)), #else ip_addr = inet_ntoa(in), inet_ntoa(in), #endif connectport); port); #else /***************************************************************** Loading @@ -836,13 +832,13 @@ ftp_pasv_verbose(struct connectdata *conn, #else const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; #endif if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen, if (getnameinfo(addr->ai_addr, addr->ai_addrlen, nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) { snprintf(nbuf, sizeof(nbuf), "?"); snprintf(sbuf, sizeof(sbuf), "?"); } if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen, if (getnameinfo(addr->ai_addr, addr->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, 0)) { infof(conn->data, "Connecting to %s port %s\n", nbuf, sbuf); } Loading @@ -850,104 +846,30 @@ ftp_pasv_verbose(struct connectdata *conn, infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf); } #endif } /********** * PORT is the ftp client's way of telling the server that *WE* open a port * that we listen on an awaits the server to connect to. This is the opposite * of PASV. */ static CURLcode _ftp(struct connectdata *conn) CURLcode ftp_use_port(struct connectdata *conn) { /* this is FTP and no proxy */ ssize_t nread; CURLcode result; struct SessionHandle *data=conn->data; char *buf = data->state.buffer; /* this is our buffer */ /* for the ftp PORT mode */ int portsock=-1; /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = conn->proto.ftp; long *bytecountp = ftp->bytecountp; int ftpcode; /* for ftp status */ /* Send any QUOTE strings? */ if(data->set.quote) { if ((result = _ftp_sendquote(conn, data->set.quote)) != CURLE_OK) return result; } /* This is a re-used connection. Since we change directory to where the transfer is taking place, we must now get back to the original dir where we ended up after login: */ if (conn->bits.reuse) { if ((result = _ftp_cwd(conn, ftp->entrypath)) != CURLE_OK) return result; } /* change directory first! */ if(ftp->dir && ftp->dir[0]) { if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK) return result; } /* Requested time of file? */ if(data->set.get_filetime && ftp->file) { result = _ftp_getfiletime(conn, ftp->file); if(result) return result; } /* If we have selected NOBODY, it means that we only want file information. Which in FTP can't be much more than the file size! */ if(data->set.no_body) { /* The SIZE command is _not_ RFC 959 specified, and therefor many servers may not support it! It is however the only way we have to get a file's size! */ ssize_t filesize; /* Some servers return different sizes for different modes, and thus we must set the proper type before we check the size */ result = _ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; /* failing to get size is not a serious error */ result = _ftp_getsize(conn, ftp->file, &filesize); if(CURLE_OK == result) { sprintf(buf, "Content-Length: %d\r\n", filesize); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } /* If we asked for a time of the file and we actually got one as well, we "emulate" a HTTP-style header in our output. */ #ifdef HAVE_STRFTIME if(data->set.get_filetime && data->info.filetime) { struct tm *tm; #ifdef HAVE_LOCALTIME_R struct tm buffer; tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); #else tm = localtime(&data->info.filetime); #endif /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", tm); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } #endif return CURLE_OK; } ssize_t nread; char *buf = data->state.buffer; /* this is our buffer */ int ftpcode; /* receive FTP response codes in this */ /* We have chosen to use the PORT command */ if(data->set.ftp_use_port) { #ifdef ENABLE_IPV6 /****************************************************************** * * Here's a piece of IPv6-specific code coming up * */ struct addrinfo hints, *res, *ai; struct sockaddr_storage ss; socklen_t sslen; Loading Loading @@ -1076,7 +998,8 @@ CURLcode _ftp(struct connectdata *conn) portmsgbuf[0] = '\0'; if (strcmp(*modep, "LPRT") == 0) { snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen); if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { continue; } } Loading @@ -1087,7 +1010,8 @@ CURLcode _ftp(struct connectdata *conn) else snprintf(tmp, sizeof(tmp), "%u", ap[i]); if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { continue; } } Loading @@ -1102,7 +1026,8 @@ CURLcode _ftp(struct connectdata *conn) for (i = 0; i < plen; i++) { snprintf(tmp, sizeof(tmp), ",%u", pp[i]); if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { continue; } } Loading @@ -1117,7 +1042,8 @@ CURLcode _ftp(struct connectdata *conn) if (ftpcode != 200) { failf(data, "Server does not grok %s", *modep); continue; } else } else break; } Loading @@ -1132,6 +1058,11 @@ CURLcode _ftp(struct connectdata *conn) conn->secondarysocket = portsock; #else /****************************************************************** * * Here's a piece of IPv4-specific code coming up * */ struct sockaddr_in sa; struct hostent *h=NULL; char *hostdataptr=NULL; Loading Loading @@ -1212,10 +1143,13 @@ CURLcode _ftp(struct connectdata *conn) return CURLE_FTP_PORT_FAILED; } { #ifdef HAVE_INET_NTOA_R char ntoa_buf[64]; #endif struct in_addr in; unsigned short ip[5]; (void) memcpy(&in.s_addr, *h->h_addr_list, sizeof (in.s_addr)); #if defined (HAVE_INET_NTOA_R) #ifdef HAVE_INET_NTOA_R /* ignore the return code from inet_ntoa_r() as it is int or char * depending on system */ inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)); Loading @@ -1239,9 +1173,26 @@ CURLcode _ftp(struct connectdata *conn) failf(data, "Server does not grok PORT, try without it!"); return CURLE_FTP_PORT_FAILED; } #endif /* ENABLE_IPV6 */ #endif /* end of ipv4-specific code */ return CURLE_OK; } else { /* we use the PASV command */ /********** * PASV is the ftp client's way of asking the server to open a second port * that we can connect to (for the data transfer). This is the opposite of * PORT. */ static CURLcode ftp_use_pasv(struct connectdata *conn) { struct SessionHandle *data = conn->data; ssize_t nread; char *buf = data->state.buffer; /* this is our buffer */ int ftpcode; /* receive FTP response codes in this */ CURLcode result; #if 0 /* no support for IPv6 passive mode yet */ char *mode[] = { "EPSV", "LPSV", "PASV", NULL }; Loading Loading @@ -1276,10 +1227,10 @@ CURLcode _ftp(struct connectdata *conn) Curl_addrinfo *addr; char *hostdataptr=NULL; #ifndef ENABLE_IPV6 char *ip_addr; #else #ifdef ENABLE_IPV6 struct addrinfo *ai; #else struct sockaddr_in serv_addr; #endif char *str=buf; Loading Loading @@ -1349,7 +1300,7 @@ CURLcode _ftp(struct connectdata *conn) if(data->set.verbose) /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, ai); ftp_pasv_verbose(conn, ai, newhost, 0 /* port not really known */); break; } Loading @@ -1369,7 +1320,7 @@ CURLcode _ftp(struct connectdata *conn) if(data->set.verbose) /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, newhost); ftp_pasv_verbose(conn, addr, newhost, connectport); if(hostdataptr) free(hostdataptr); Loading Loading @@ -1403,17 +1354,122 @@ CURLcode _ftp(struct connectdata *conn) if(CURLE_OK != result) return result; } } else { } else return CURLE_FTP_CANT_RECONNECT; return CURLE_OK; } static CURLcode ftp_perform(struct connectdata *conn) { /* this is FTP and no proxy */ ssize_t nread; CURLcode result; struct SessionHandle *data=conn->data; char *buf = data->state.buffer; /* this is our buffer */ /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = conn->proto.ftp; long *bytecountp = ftp->bytecountp; int ftpcode; /* for ftp status */ /* Send any QUOTE strings? */ if(data->set.quote) { if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK) return result; } /* This is a re-used connection. Since we change directory to where the transfer is taking place, we must now get back to the original dir where we ended up after login: */ if (conn->bits.reuse) { if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK) return result; } /* change directory first! */ if(ftp->dir && ftp->dir[0]) { if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK) return result; } /* Requested time of file? */ if(data->set.get_filetime && ftp->file) { result = ftp_getfiletime(conn, ftp->file); if(result) return result; } /* If we have selected NOBODY, it means that we only want file information. Which in FTP can't be much more than the file size! */ if(data->set.no_body) { /* The SIZE command is _not_ RFC 959 specified, and therefor many servers may not support it! It is however the only way we have to get a file's size! */ ssize_t filesize; /* Some servers return different sizes for different modes, and thus we must set the proper type before we check the size */ result = ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; /* failing to get size is not a serious error */ result = ftp_getsize(conn, ftp->file, &filesize); if(CURLE_OK == result) { sprintf(buf, "Content-Length: %d\r\n", filesize); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } /* we have the (new) data connection ready */ /* If we asked for a time of the file and we actually got one as well, we "emulate" a HTTP-style header in our output. */ #ifdef HAVE_STRFTIME if(data->set.get_filetime && data->info.filetime) { struct tm *tm; #ifdef HAVE_LOCALTIME_R struct tm buffer; tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); #else tm = localtime(&data->info.filetime); #endif /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", tm); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } #endif return CURLE_OK; } /* Get us a second connection up and connected */ if(data->set.ftp_use_port) /* We have chosen to use the PORT command */ result = ftp_use_port(conn); else /* We have chosen (this is default) to use the PASV command */ result = ftp_use_pasv(conn); if(result) return result; /* we have the data connection ready */ infof(data, "Connected the data stream!\n"); if(data->set.upload) { /* Set type to binary (unless specified ASCII) */ result = _ftp_transfertype(conn, data->set.ftp_ascii); result = ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; Loading @@ -1435,7 +1491,7 @@ CURLcode _ftp(struct connectdata *conn) /* we could've got a specified offset from the command line, but now we know we didn't */ if(CURLE_OK != _ftp_getsize(conn, ftp->file, &conn->resume_from)) { if(CURLE_OK != ftp_getsize(conn, ftp->file, &conn->resume_from)) { failf(data, "Couldn't get remote file size"); return CURLE_FTP_COULDNT_GET_SIZE; } Loading Loading @@ -1510,7 +1566,7 @@ CURLcode _ftp(struct connectdata *conn) if(data->set.ftp_use_port) { /* PORT means we are now awaiting the server to connect to us. */ result = AllowServerConnect(data, conn, portsock); result = AllowServerConnect(data, conn, conn->secondarysocket); if( result ) return result; } Loading Loading @@ -1578,7 +1634,7 @@ CURLcode _ftp(struct connectdata *conn) dirlist = TRUE; /* Set type to ASCII */ result = _ftp_transfertype(conn, TRUE /* ASCII enforced */); result = ftp_transfertype(conn, TRUE /* ASCII enforced */); if(result) return result; Loading @@ -1592,7 +1648,7 @@ CURLcode _ftp(struct connectdata *conn) } else { /* Set type to binary (unless specified ASCII) */ result = _ftp_transfertype(conn, data->set.ftp_ascii); result = ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; Loading @@ -1605,7 +1661,7 @@ CURLcode _ftp(struct connectdata *conn) * the best way to know if we're trying to resume beyond the EOF. */ int foundsize=-1; result = _ftp_getsize(conn, ftp->file, &foundsize); result = ftp_getsize(conn, ftp->file, &foundsize); if(CURLE_OK != result) { infof(data, "ftp server doesn't support SIZE\n"); Loading Loading @@ -1736,7 +1792,7 @@ CURLcode _ftp(struct connectdata *conn) size = downloadsize; if(data->set.ftp_use_port) { result = AllowServerConnect(data, conn, portsock); result = AllowServerConnect(data, conn, conn->secondarysocket); if( result ) return result; } Loading Loading @@ -1813,7 +1869,7 @@ CURLcode Curl_ftp(struct connectdata *conn) else ftp->dir = NULL; retcode = _ftp(conn); retcode = ftp_perform(conn); /* clean up here, success or error doesn't matter */ if(ftp->file) Loading Loading
lib/ftp.c +555 −499 Original line number Diff line number Diff line Loading @@ -92,8 +92,8 @@ #endif /* Local API functions */ static CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode _ftp_cwd(struct connectdata *conn, char *path); static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode ftp_cwd(struct connectdata *conn, char *path); /* easy-to-use macro: */ #define ftpsendf Curl_ftpsendf Loading Loading @@ -590,7 +590,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn) /* Send any post-transfer QUOTE strings? */ if(data->set.postquote) { CURLcode result = _ftp_sendquote(conn, data->set.postquote); CURLcode result = ftp_sendquote(conn, data->set.postquote); return result; } Loading @@ -599,7 +599,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn) static CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) { struct curl_slist *item; ssize_t nread; Loading Loading @@ -628,7 +628,7 @@ CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) } static CURLcode _ftp_cwd(struct connectdata *conn, char *path) CURLcode ftp_cwd(struct connectdata *conn, char *path) { ssize_t nread; int ftpcode; Loading @@ -648,7 +648,7 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path) } static CURLcode _ftp_getfiletime(struct connectdata *conn, char *file) CURLcode ftp_getfiletime(struct connectdata *conn, char *file) { CURLcode result=CURLE_OK; int ftpcode; /* for ftp status */ Loading Loading @@ -683,7 +683,7 @@ CURLcode _ftp_getfiletime(struct connectdata *conn, char *file) return result; } static CURLcode _ftp_transfertype(struct connectdata *conn, static CURLcode ftp_transfertype(struct connectdata *conn, bool ascii) { struct SessionHandle *data = conn->data; Loading @@ -707,7 +707,7 @@ static CURLcode _ftp_transfertype(struct connectdata *conn, } static CURLcode _ftp_getsize(struct connectdata *conn, char *file, CURLcode ftp_getsize(struct connectdata *conn, char *file, ssize_t *size) { struct SessionHandle *data = conn->data; Loading Loading @@ -741,12 +741,9 @@ CURLcode _ftp_getsize(struct connectdata *conn, char *file, */ static void ftp_pasv_verbose(struct connectdata *conn, #ifdef ENABLE_IPV6 struct addrinfo *newhost #else char *newhost /* ipv4 */ #endif ) Curl_addrinfo *addr, char *newhost, /* ascii version */ int port) { #ifndef ENABLE_IPV6 /***************************************************************** Loading @@ -757,11 +754,10 @@ ftp_pasv_verbose(struct connectdata *conn, struct in_addr in; struct hostent * answer; #if defined (HAVE_INET_NTOA_R) #ifdef HAVE_INET_NTOA_R char ntoa_buf[64]; #endif #ifndef ENABLE_IPV6 struct sockaddr_in serv_addr; char hostent_buf[8192]; #endif Loading Loading @@ -817,11 +813,11 @@ ftp_pasv_verbose(struct connectdata *conn, infof(conn->data, "Connecting to %s (%s) port %u\n", answer?answer->h_name:newhost, #if defined(HAVE_INET_NTOA_R) inet_ntoa_r(in, ip_addr=ntoa_buf, sizeof(ntoa_buf)), inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)), #else ip_addr = inet_ntoa(in), inet_ntoa(in), #endif connectport); port); #else /***************************************************************** Loading @@ -836,13 +832,13 @@ ftp_pasv_verbose(struct connectdata *conn, #else const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; #endif if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen, if (getnameinfo(addr->ai_addr, addr->ai_addrlen, nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) { snprintf(nbuf, sizeof(nbuf), "?"); snprintf(sbuf, sizeof(sbuf), "?"); } if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen, if (getnameinfo(addr->ai_addr, addr->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, 0)) { infof(conn->data, "Connecting to %s port %s\n", nbuf, sbuf); } Loading @@ -850,104 +846,30 @@ ftp_pasv_verbose(struct connectdata *conn, infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf); } #endif } /********** * PORT is the ftp client's way of telling the server that *WE* open a port * that we listen on an awaits the server to connect to. This is the opposite * of PASV. */ static CURLcode _ftp(struct connectdata *conn) CURLcode ftp_use_port(struct connectdata *conn) { /* this is FTP and no proxy */ ssize_t nread; CURLcode result; struct SessionHandle *data=conn->data; char *buf = data->state.buffer; /* this is our buffer */ /* for the ftp PORT mode */ int portsock=-1; /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = conn->proto.ftp; long *bytecountp = ftp->bytecountp; int ftpcode; /* for ftp status */ /* Send any QUOTE strings? */ if(data->set.quote) { if ((result = _ftp_sendquote(conn, data->set.quote)) != CURLE_OK) return result; } /* This is a re-used connection. Since we change directory to where the transfer is taking place, we must now get back to the original dir where we ended up after login: */ if (conn->bits.reuse) { if ((result = _ftp_cwd(conn, ftp->entrypath)) != CURLE_OK) return result; } /* change directory first! */ if(ftp->dir && ftp->dir[0]) { if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK) return result; } /* Requested time of file? */ if(data->set.get_filetime && ftp->file) { result = _ftp_getfiletime(conn, ftp->file); if(result) return result; } /* If we have selected NOBODY, it means that we only want file information. Which in FTP can't be much more than the file size! */ if(data->set.no_body) { /* The SIZE command is _not_ RFC 959 specified, and therefor many servers may not support it! It is however the only way we have to get a file's size! */ ssize_t filesize; /* Some servers return different sizes for different modes, and thus we must set the proper type before we check the size */ result = _ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; /* failing to get size is not a serious error */ result = _ftp_getsize(conn, ftp->file, &filesize); if(CURLE_OK == result) { sprintf(buf, "Content-Length: %d\r\n", filesize); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } /* If we asked for a time of the file and we actually got one as well, we "emulate" a HTTP-style header in our output. */ #ifdef HAVE_STRFTIME if(data->set.get_filetime && data->info.filetime) { struct tm *tm; #ifdef HAVE_LOCALTIME_R struct tm buffer; tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); #else tm = localtime(&data->info.filetime); #endif /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", tm); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } #endif return CURLE_OK; } ssize_t nread; char *buf = data->state.buffer; /* this is our buffer */ int ftpcode; /* receive FTP response codes in this */ /* We have chosen to use the PORT command */ if(data->set.ftp_use_port) { #ifdef ENABLE_IPV6 /****************************************************************** * * Here's a piece of IPv6-specific code coming up * */ struct addrinfo hints, *res, *ai; struct sockaddr_storage ss; socklen_t sslen; Loading Loading @@ -1076,7 +998,8 @@ CURLcode _ftp(struct connectdata *conn) portmsgbuf[0] = '\0'; if (strcmp(*modep, "LPRT") == 0) { snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen); if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { continue; } } Loading @@ -1087,7 +1010,8 @@ CURLcode _ftp(struct connectdata *conn) else snprintf(tmp, sizeof(tmp), "%u", ap[i]); if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { continue; } } Loading @@ -1102,7 +1026,8 @@ CURLcode _ftp(struct connectdata *conn) for (i = 0; i < plen; i++) { snprintf(tmp, sizeof(tmp), ",%u", pp[i]); if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { continue; } } Loading @@ -1117,7 +1042,8 @@ CURLcode _ftp(struct connectdata *conn) if (ftpcode != 200) { failf(data, "Server does not grok %s", *modep); continue; } else } else break; } Loading @@ -1132,6 +1058,11 @@ CURLcode _ftp(struct connectdata *conn) conn->secondarysocket = portsock; #else /****************************************************************** * * Here's a piece of IPv4-specific code coming up * */ struct sockaddr_in sa; struct hostent *h=NULL; char *hostdataptr=NULL; Loading Loading @@ -1212,10 +1143,13 @@ CURLcode _ftp(struct connectdata *conn) return CURLE_FTP_PORT_FAILED; } { #ifdef HAVE_INET_NTOA_R char ntoa_buf[64]; #endif struct in_addr in; unsigned short ip[5]; (void) memcpy(&in.s_addr, *h->h_addr_list, sizeof (in.s_addr)); #if defined (HAVE_INET_NTOA_R) #ifdef HAVE_INET_NTOA_R /* ignore the return code from inet_ntoa_r() as it is int or char * depending on system */ inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)); Loading @@ -1239,9 +1173,26 @@ CURLcode _ftp(struct connectdata *conn) failf(data, "Server does not grok PORT, try without it!"); return CURLE_FTP_PORT_FAILED; } #endif /* ENABLE_IPV6 */ #endif /* end of ipv4-specific code */ return CURLE_OK; } else { /* we use the PASV command */ /********** * PASV is the ftp client's way of asking the server to open a second port * that we can connect to (for the data transfer). This is the opposite of * PORT. */ static CURLcode ftp_use_pasv(struct connectdata *conn) { struct SessionHandle *data = conn->data; ssize_t nread; char *buf = data->state.buffer; /* this is our buffer */ int ftpcode; /* receive FTP response codes in this */ CURLcode result; #if 0 /* no support for IPv6 passive mode yet */ char *mode[] = { "EPSV", "LPSV", "PASV", NULL }; Loading Loading @@ -1276,10 +1227,10 @@ CURLcode _ftp(struct connectdata *conn) Curl_addrinfo *addr; char *hostdataptr=NULL; #ifndef ENABLE_IPV6 char *ip_addr; #else #ifdef ENABLE_IPV6 struct addrinfo *ai; #else struct sockaddr_in serv_addr; #endif char *str=buf; Loading Loading @@ -1349,7 +1300,7 @@ CURLcode _ftp(struct connectdata *conn) if(data->set.verbose) /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, ai); ftp_pasv_verbose(conn, ai, newhost, 0 /* port not really known */); break; } Loading @@ -1369,7 +1320,7 @@ CURLcode _ftp(struct connectdata *conn) if(data->set.verbose) /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, newhost); ftp_pasv_verbose(conn, addr, newhost, connectport); if(hostdataptr) free(hostdataptr); Loading Loading @@ -1403,17 +1354,122 @@ CURLcode _ftp(struct connectdata *conn) if(CURLE_OK != result) return result; } } else { } else return CURLE_FTP_CANT_RECONNECT; return CURLE_OK; } static CURLcode ftp_perform(struct connectdata *conn) { /* this is FTP and no proxy */ ssize_t nread; CURLcode result; struct SessionHandle *data=conn->data; char *buf = data->state.buffer; /* this is our buffer */ /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = conn->proto.ftp; long *bytecountp = ftp->bytecountp; int ftpcode; /* for ftp status */ /* Send any QUOTE strings? */ if(data->set.quote) { if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK) return result; } /* This is a re-used connection. Since we change directory to where the transfer is taking place, we must now get back to the original dir where we ended up after login: */ if (conn->bits.reuse) { if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK) return result; } /* change directory first! */ if(ftp->dir && ftp->dir[0]) { if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK) return result; } /* Requested time of file? */ if(data->set.get_filetime && ftp->file) { result = ftp_getfiletime(conn, ftp->file); if(result) return result; } /* If we have selected NOBODY, it means that we only want file information. Which in FTP can't be much more than the file size! */ if(data->set.no_body) { /* The SIZE command is _not_ RFC 959 specified, and therefor many servers may not support it! It is however the only way we have to get a file's size! */ ssize_t filesize; /* Some servers return different sizes for different modes, and thus we must set the proper type before we check the size */ result = ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; /* failing to get size is not a serious error */ result = ftp_getsize(conn, ftp->file, &filesize); if(CURLE_OK == result) { sprintf(buf, "Content-Length: %d\r\n", filesize); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } /* we have the (new) data connection ready */ /* If we asked for a time of the file and we actually got one as well, we "emulate" a HTTP-style header in our output. */ #ifdef HAVE_STRFTIME if(data->set.get_filetime && data->info.filetime) { struct tm *tm; #ifdef HAVE_LOCALTIME_R struct tm buffer; tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); #else tm = localtime(&data->info.filetime); #endif /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", tm); result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } #endif return CURLE_OK; } /* Get us a second connection up and connected */ if(data->set.ftp_use_port) /* We have chosen to use the PORT command */ result = ftp_use_port(conn); else /* We have chosen (this is default) to use the PASV command */ result = ftp_use_pasv(conn); if(result) return result; /* we have the data connection ready */ infof(data, "Connected the data stream!\n"); if(data->set.upload) { /* Set type to binary (unless specified ASCII) */ result = _ftp_transfertype(conn, data->set.ftp_ascii); result = ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; Loading @@ -1435,7 +1491,7 @@ CURLcode _ftp(struct connectdata *conn) /* we could've got a specified offset from the command line, but now we know we didn't */ if(CURLE_OK != _ftp_getsize(conn, ftp->file, &conn->resume_from)) { if(CURLE_OK != ftp_getsize(conn, ftp->file, &conn->resume_from)) { failf(data, "Couldn't get remote file size"); return CURLE_FTP_COULDNT_GET_SIZE; } Loading Loading @@ -1510,7 +1566,7 @@ CURLcode _ftp(struct connectdata *conn) if(data->set.ftp_use_port) { /* PORT means we are now awaiting the server to connect to us. */ result = AllowServerConnect(data, conn, portsock); result = AllowServerConnect(data, conn, conn->secondarysocket); if( result ) return result; } Loading Loading @@ -1578,7 +1634,7 @@ CURLcode _ftp(struct connectdata *conn) dirlist = TRUE; /* Set type to ASCII */ result = _ftp_transfertype(conn, TRUE /* ASCII enforced */); result = ftp_transfertype(conn, TRUE /* ASCII enforced */); if(result) return result; Loading @@ -1592,7 +1648,7 @@ CURLcode _ftp(struct connectdata *conn) } else { /* Set type to binary (unless specified ASCII) */ result = _ftp_transfertype(conn, data->set.ftp_ascii); result = ftp_transfertype(conn, data->set.ftp_ascii); if(result) return result; Loading @@ -1605,7 +1661,7 @@ CURLcode _ftp(struct connectdata *conn) * the best way to know if we're trying to resume beyond the EOF. */ int foundsize=-1; result = _ftp_getsize(conn, ftp->file, &foundsize); result = ftp_getsize(conn, ftp->file, &foundsize); if(CURLE_OK != result) { infof(data, "ftp server doesn't support SIZE\n"); Loading Loading @@ -1736,7 +1792,7 @@ CURLcode _ftp(struct connectdata *conn) size = downloadsize; if(data->set.ftp_use_port) { result = AllowServerConnect(data, conn, portsock); result = AllowServerConnect(data, conn, conn->secondarysocket); if( result ) return result; } Loading Loading @@ -1813,7 +1869,7 @@ CURLcode Curl_ftp(struct connectdata *conn) else ftp->dir = NULL; retcode = _ftp(conn); retcode = ftp_perform(conn); /* clean up here, success or error doesn't matter */ if(ftp->file) Loading