diff --git a/lib/ftp.c b/lib/ftp.c deleted file mode 100644 index 0b9c9b7322b5e2098da9a93bc2746b18b20b523d..0000000000000000000000000000000000000000 --- a/lib/ftp.c +++ /dev/null @@ -1,4401 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2021, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FTP - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef __VMS -#include -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "if2ip.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "ftp.h" -#include "fileinfo.h" -#include "ftplistparser.h" -#include "curl_range.h" -#include "curl_krb5.h" -#include "strtoofft.h" -#include "strcase.h" -#include "vtls/vtls.h" -#include "connect.h" -#include "strerror.h" -#include "inet_ntop.h" -#include "inet_pton.h" -#include "select.h" -#include "parsedate.h" /* for the week day and month names */ -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "multiif.h" -#include "url.h" -#include "strcase.h" -#include "speedcheck.h" -#include "warnless.h" -#include "http_proxy.h" -#include "non-ascii.h" -#include "socks.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef NI_MAXHOST -#define NI_MAXHOST 1025 -#endif -#ifndef INET_ADDRSTRLEN -#define INET_ADDRSTRLEN 16 -#endif - -#ifdef CURL_DISABLE_VERBOSE_STRINGS -#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt -#endif - -/* Local API functions */ -#ifndef DEBUGBUILD -static void _state(struct Curl_easy *data, - ftpstate newstate); -#define state(x,y) _state(x,y) -#else -static void _state(struct Curl_easy *data, - ftpstate newstate, - int lineno); -#define state(x,y) _state(x,y,__LINE__) -#endif - -static CURLcode ftp_sendquote(struct Curl_easy *data, - struct connectdata *conn, - struct curl_slist *quote); -static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn); -static CURLcode ftp_parse_url_path(struct Curl_easy *data); -static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done); -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void ftp_pasv_verbose(struct Curl_easy *data, - struct Curl_addrinfo *ai, - char *newhost, /* ascii version */ - int port); -#endif -static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data); -static CURLcode ftp_state_mdtm(struct Curl_easy *data); -static CURLcode ftp_state_quote(struct Curl_easy *data, - bool init, ftpstate instate); -static CURLcode ftp_nb_type(struct Curl_easy *data, - struct connectdata *conn, - bool ascii, ftpstate newstate); -static int ftp_need_type(struct connectdata *conn, - bool ascii); -static CURLcode ftp_do(struct Curl_easy *data, bool *done); -static CURLcode ftp_done(struct Curl_easy *data, - CURLcode, bool premature); -static CURLcode ftp_connect(struct Curl_easy *data, bool *done); -static CURLcode ftp_disconnect(struct Curl_easy *data, - struct connectdata *conn, bool dead_connection); -static CURLcode ftp_do_more(struct Curl_easy *data, int *completed); -static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done); -static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks); -static int ftp_domore_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); -static CURLcode ftp_doing(struct Curl_easy *data, - bool *dophase_done); -static CURLcode ftp_setup_connection(struct Curl_easy *data, - struct connectdata *conn); -static CURLcode init_wc_data(struct Curl_easy *data); -static CURLcode wc_statemach(struct Curl_easy *data); -static void wc_data_dtor(void *ptr); -static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize); -static CURLcode ftp_readresp(struct Curl_easy *data, - curl_socket_t sockfd, - struct pingpong *pp, - int *ftpcode, - size_t *size); -static CURLcode ftp_dophase_done(struct Curl_easy *data, - bool connected); - -/* - * FTP protocol handler. - */ - -const struct Curl_handler Curl_handler_ftp = { - "FTP", /* scheme */ - ftp_setup_connection, /* setup_connection */ - ftp_do, /* do_it */ - ftp_done, /* done */ - ftp_do_more, /* do_more */ - ftp_connect, /* connect_it */ - ftp_multi_statemach, /* connecting */ - ftp_doing, /* doing */ - ftp_getsock, /* proto_getsock */ - ftp_getsock, /* doing_getsock */ - ftp_domore_getsock, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - PORT_FTP, /* defport */ - CURLPROTO_FTP, /* protocol */ - CURLPROTO_FTP, /* family */ - PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | - PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP | - PROTOPT_WILDCARD /* flags */ -}; - - -#ifdef USE_SSL -/* - * FTPS protocol handler. - */ - -const struct Curl_handler Curl_handler_ftps = { - "FTPS", /* scheme */ - ftp_setup_connection, /* setup_connection */ - ftp_do, /* do_it */ - ftp_done, /* done */ - ftp_do_more, /* do_more */ - ftp_connect, /* connect_it */ - ftp_multi_statemach, /* connecting */ - ftp_doing, /* doing */ - ftp_getsock, /* proto_getsock */ - ftp_getsock, /* doing_getsock */ - ftp_domore_getsock, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - PORT_FTPS, /* defport */ - CURLPROTO_FTPS, /* protocol */ - CURLPROTO_FTP, /* family */ - PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | - PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */ -}; -#endif - -static void close_secondarysocket(struct Curl_easy *data, - struct connectdata *conn) -{ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } - conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; -#ifndef CURL_DISABLE_PROXY - conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE; -#endif -} - -/* - * NOTE: back in the old days, we added code in the FTP code that made NOBODY - * requests on files respond with headers passed to the client/stdout that - * looked like HTTP ones. - * - * This approach is not very elegant, it causes confusion and is error-prone. - * It is subject for removal at the next (or at least a future) soname bump. - * Until then you can test the effects of the removal by undefining the - * following define named CURL_FTP_HTTPSTYLE_HEAD. - */ -#define CURL_FTP_HTTPSTYLE_HEAD 1 - -static void freedirs(struct ftp_conn *ftpc) -{ - if(ftpc->dirs) { - int i; - for(i = 0; i < ftpc->dirdepth; i++) { - free(ftpc->dirs[i]); - ftpc->dirs[i] = NULL; - } - free(ftpc->dirs); - ftpc->dirs = NULL; - ftpc->dirdepth = 0; - } - Curl_safefree(ftpc->file); - - /* no longer of any use */ - Curl_safefree(ftpc->newhost); -} - -/*********************************************************************** - * - * AcceptServerConnect() - * - * After connection request is received from the server this function is - * called to accept the connection and close the listening socket - * - */ -static CURLcode AcceptServerConnect(struct Curl_easy *data) -{ - struct connectdata *conn = data->conn; - curl_socket_t sock = conn->sock[SECONDARYSOCKET]; - curl_socket_t s = CURL_SOCKET_BAD; -#ifdef ENABLE_IPV6 - struct Curl_sockaddr_storage add; -#else - struct sockaddr_in add; -#endif - curl_socklen_t size = (curl_socklen_t) sizeof(add); - - if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { - size = sizeof(add); - - s = accept(sock, (struct sockaddr *) &add, &size); - } - Curl_closesocket(data, conn, sock); /* close the first socket */ - - if(CURL_SOCKET_BAD == s) { - failf(data, "Error accept()ing server connect"); - return CURLE_FTP_PORT_FAILED; - } - infof(data, "Connection accepted from server"); - /* when this happens within the DO state it is important that we mark us as - not needing DO_MORE anymore */ - conn->bits.do_more = FALSE; - - conn->sock[SECONDARYSOCKET] = s; - (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ - conn->bits.sock_accepted = TRUE; - - if(data->set.fsockopt) { - int error = 0; - - /* activate callback for setting socket options */ - Curl_set_in_callback(data, true); - error = data->set.fsockopt(data->set.sockopt_client, - s, - CURLSOCKTYPE_ACCEPT); - Curl_set_in_callback(data, false); - - if(error) { - close_secondarysocket(data, conn); - return CURLE_ABORTED_BY_CALLBACK; - } - } - - return CURLE_OK; - -} - -/* - * ftp_timeleft_accept() returns the amount of milliseconds left allowed for - * waiting server to connect. If the value is negative, the timeout time has - * already elapsed. - * - * The start time is stored in progress.t_acceptdata - as set with - * Curl_pgrsTime(..., TIMER_STARTACCEPT); - * - */ -static timediff_t ftp_timeleft_accept(struct Curl_easy *data) -{ - timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; - timediff_t other; - struct curltime now; - - if(data->set.accepttimeout > 0) - timeout_ms = data->set.accepttimeout; - - now = Curl_now(); - - /* check if the generic timeout possibly is set shorter */ - other = Curl_timeleft(data, &now, FALSE); - if(other && (other < timeout_ms)) - /* note that this also works fine for when other happens to be negative - due to it already having elapsed */ - timeout_ms = other; - else { - /* subtract elapsed time */ - timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata); - if(!timeout_ms) - /* avoid returning 0 as that means no timeout! */ - return -1; - } - - return timeout_ms; -} - - -/*********************************************************************** - * - * ReceivedServerConnect() - * - * After allowing server to connect to us from data port, this function - * checks both data connection for connection establishment and ctrl - * connection for a negative response regarding a failure in connecting - * - */ -static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received) -{ - struct connectdata *conn = data->conn; - curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; - curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - int result; - timediff_t timeout_ms; - ssize_t nread; - int ftpcode; - - *received = FALSE; - - timeout_ms = ftp_timeleft_accept(data); - infof(data, "Checking for server connect"); - if(timeout_ms < 0) { - /* if a timeout was already reached, bail out */ - failf(data, "Accept timeout occurred while waiting server connect"); - return CURLE_FTP_ACCEPT_TIMEOUT; - } - - /* First check whether there is a cached response from server */ - if(pp->cache_size && pp->cache && pp->cache[0] > '3') { - /* Data connection could not be established, let's return */ - infof(data, "There is negative response in cache while serv connect"); - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); - return CURLE_FTP_ACCEPT_FAILED; - } - - result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); - - /* see if the connection request is already here */ - switch(result) { - case -1: /* error */ - /* let's die here */ - failf(data, "Error while waiting for server connect"); - return CURLE_FTP_ACCEPT_FAILED; - case 0: /* Server connect is not received yet */ - break; /* loop */ - default: - - if(result & CURL_CSELECT_IN2) { - infof(data, "Ready to accept data connection from server"); - *received = TRUE; - } - else if(result & CURL_CSELECT_IN) { - infof(data, "Ctrl conn has data while waiting for data conn"); - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); - - if(ftpcode/100 > 3) - return CURLE_FTP_ACCEPT_FAILED; - - return CURLE_WEIRD_SERVER_REPLY; - } - - break; - } /* switch() */ - - return CURLE_OK; -} - - -/*********************************************************************** - * - * InitiateTransfer() - * - * After connection from server is accepted this function is called to - * setup transfer parameters and initiate the data transfer. - * - */ -static CURLcode InitiateTransfer(struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - - if(conn->bits.ftp_use_data_ssl) { - /* since we only have a plaintext TCP connection here, we must now - * do the TLS stuff */ - infof(data, "Doing the SSL/TLS handshake on the data stream"); - result = Curl_ssl_connect(data, conn, SECONDARYSOCKET); - if(result) - return result; - } - - if(conn->proto.ftpc.state_saved == FTP_STOR) { - /* When we know we're uploading a specified file, we can get the file - size prior to the actual upload. */ - Curl_pgrsSetUploadSize(data, data->state.infilesize); - - /* set the SO_SNDBUF for the secondary socket for those who need it */ - Curl_sndbufset(conn->sock[SECONDARYSOCKET]); - - Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET); - } - else { - /* FTP download: */ - Curl_setup_transfer(data, SECONDARYSOCKET, - conn->proto.ftpc.retr_size_saved, FALSE, -1); - } - - conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ - state(data, FTP_STOP); - - return CURLE_OK; -} - -/*********************************************************************** - * - * AllowServerConnect() - * - * When we've issue the PORT command, we have told the server to connect to - * us. This function checks whether data connection is established if so it is - * accepted. - * - */ -static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected) -{ - timediff_t timeout_ms; - CURLcode result = CURLE_OK; - - *connected = FALSE; - infof(data, "Preparing for accepting server on data port"); - - /* Save the time we start accepting server connect */ - Curl_pgrsTime(data, TIMER_STARTACCEPT); - - timeout_ms = ftp_timeleft_accept(data); - if(timeout_ms < 0) { - /* if a timeout was already reached, bail out */ - failf(data, "Accept timeout occurred while waiting server connect"); - return CURLE_FTP_ACCEPT_TIMEOUT; - } - - /* see if the connection request is already here */ - result = ReceivedServerConnect(data, connected); - if(result) - return result; - - if(*connected) { - result = AcceptServerConnect(data); - if(result) - return result; - - result = InitiateTransfer(data); - if(result) - return result; - } - else { - /* Add timeout to multi handle and break out of the loop */ - if(*connected == FALSE) { - Curl_expire(data, data->set.accepttimeout > 0 ? - data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0); - } - } - - return result; -} - -/* macro to check for a three-digit ftp status code at the start of the - given string */ -#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ - ISDIGIT(line[2])) - -/* macro to check for the last line in an FTP server response */ -#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) - -static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn, - char *line, size_t len, int *code) -{ - (void)data; - (void)conn; - - if((len > 3) && LASTLINE(line)) { - *code = curlx_sltosi(strtol(line, NULL, 10)); - return TRUE; - } - - return FALSE; -} - -static CURLcode ftp_readresp(struct Curl_easy *data, - curl_socket_t sockfd, - struct pingpong *pp, - int *ftpcode, /* return the ftp-code if done */ - size_t *size) /* size of the response */ -{ - int code; - CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size); - -#ifdef HAVE_GSSAPI - { - struct connectdata *conn = data->conn; - char * const buf = data->state.buffer; - - /* handle the security-oriented responses 6xx ***/ - switch(code) { - case 631: - code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE); - break; - case 632: - code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE); - break; - case 633: - code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL); - break; - default: - /* normal ftp stuff we pass through! */ - break; - } - } -#endif - - /* store the latest code for later retrieval */ - data->info.httpcode = code; - - if(ftpcode) - *ftpcode = code; - - if(421 == code) { - /* 421 means "Service not available, closing control connection." and FTP - * servers use it to signal that idle session timeout has been exceeded. - * If we ignored the response, it could end up hanging in some cases. - * - * This response code can come at any point so having it treated - * generically is a good idea. - */ - infof(data, "We got a 421 - timeout!"); - state(data, FTP_STOP); - return CURLE_OPERATION_TIMEDOUT; - } - - return result; -} - -/* --- parse FTP server responses --- */ - -/* - * Curl_GetFTPResponse() is a BLOCKING function to read the full response - * from a server after a command. - * - */ - -CURLcode Curl_GetFTPResponse(struct Curl_easy *data, - ssize_t *nreadp, /* return number of bytes read */ - int *ftpcode) /* return the ftp-code */ -{ - /* - * We cannot read just one byte per read() and then go back to select() as - * the OpenSSL read() doesn't grok that properly. - * - * Alas, read as much as possible, split up into lines, use the ending - * line in a response or continue reading. */ - - struct connectdata *conn = data->conn; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - size_t nread; - int cache_skip = 0; - int value_to_be_ignored = 0; - - if(ftpcode) - *ftpcode = 0; /* 0 for errors */ - else - /* make the pointer point to something for the rest of this function */ - ftpcode = &value_to_be_ignored; - - *nreadp = 0; - - while(!*ftpcode && !result) { - /* check and reset timeout value every lap */ - timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE); - timediff_t interval_ms; - - if(timeout <= 0) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; /* already too little time */ - } - - interval_ms = 1000; /* use 1 second timeout intervals */ - if(timeout < interval_ms) - interval_ms = timeout; - - /* - * Since this function is blocking, we need to wait here for input on the - * connection and only then we call the response reading function. We do - * timeout at least every second to make the timeout check run. - * - * A caution here is that the ftp_readresp() function has a cache that may - * contain pieces of a response from the previous invoke and we need to - * make sure we don't just wait for input while there is unhandled data in - * that cache. But also, if the cache is there, we call ftp_readresp() and - * the cache wasn't good enough to continue we must not just busy-loop - * around this function. - * - */ - - if(pp->cache && (cache_skip < 2)) { - /* - * There's a cache left since before. We then skipping the wait for - * socket action, unless this is the same cache like the previous round - * as then the cache was deemed not enough to act on and we then need to - * wait for more data anyway. - */ - } - else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) { - switch(SOCKET_READABLE(sockfd, interval_ms)) { - case -1: /* select() error, stop reading */ - failf(data, "FTP response aborted due to select/poll error: %d", - SOCKERRNO); - return CURLE_RECV_ERROR; - - case 0: /* timeout */ - if(Curl_pgrsUpdate(data)) - return CURLE_ABORTED_BY_CALLBACK; - continue; /* just continue in our loop for the timeout duration */ - - default: /* for clarity */ - break; - } - } - result = ftp_readresp(data, sockfd, pp, ftpcode, &nread); - if(result) - break; - - if(!nread && pp->cache) - /* bump cache skip counter as on repeated skips we must wait for more - data */ - cache_skip++; - else - /* when we got data or there is no cache left, we reset the cache skip - counter */ - cache_skip = 0; - - *nreadp += nread; - - } /* while there's buffer left and loop is requested */ - - pp->pending_resp = FALSE; - - return result; -} - -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ -static const char * const ftp_state_names[]={ - "STOP", - "WAIT220", - "AUTH", - "USER", - "PASS", - "ACCT", - "PBSZ", - "PROT", - "CCC", - "PWD", - "SYST", - "NAMEFMT", - "QUOTE", - "RETR_PREQUOTE", - "STOR_PREQUOTE", - "POSTQUOTE", - "CWD", - "MKD", - "MDTM", - "TYPE", - "LIST_TYPE", - "RETR_TYPE", - "STOR_TYPE", - "SIZE", - "RETR_SIZE", - "STOR_SIZE", - "REST", - "RETR_REST", - "PORT", - "PRET", - "PASV", - "LIST", - "RETR", - "STOR", - "QUIT" -}; -#endif - -/* This is the ONLY way to change FTP state! */ -static void _state(struct Curl_easy *data, - ftpstate newstate -#ifdef DEBUGBUILD - , int lineno -#endif - ) -{ - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - -#if defined(DEBUGBUILD) - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) lineno; -#else - if(ftpc->state != newstate) - infof(data, "FTP %p (line %d) state change from %s to %s", - (void *)ftpc, lineno, ftp_state_names[ftpc->state], - ftp_state_names[newstate]); -#endif -#endif - - ftpc->state = newstate; -} - -static CURLcode ftp_state_user(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = Curl_pp_sendf(data, - &conn->proto.ftpc.pp, "USER %s", - conn->user?conn->user:""); - if(!result) { - state(data, FTP_USER); - data->state.ftp_trying_alternative = FALSE; - } - return result; -} - -static CURLcode ftp_state_pwd(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD"); - if(!result) - state(data, FTP_PWD); - - return result; -} - -/* For the FTP "protocol connect" and "doing" phases only */ -static int ftp_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) -{ - return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks); -} - -/* For the FTP "DO_MORE" phase only */ -static int ftp_domore_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - (void)data; - - /* When in DO_MORE state, we could be either waiting for us to connect to a - * remote site, or we could wait for that site to connect to us. Or just - * handle ordinary commands. - */ - - if(SOCKS_STATE(conn->cnnct.state)) - return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET); - - if(FTP_STOP == ftpc->state) { - int bits = GETSOCK_READSOCK(0); - bool any = FALSE; - - /* if stopped and still in this state, then we're also waiting for a - connect on the secondary connection */ - socks[0] = conn->sock[FIRSTSOCKET]; - - if(!data->set.ftp_use_port) { - int s; - int i; - /* PORT is used to tell the server to connect to us, and during that we - don't do happy eyeballs, but we do if we connect to the server */ - for(s = 1, i = 0; i<2; i++) { - if(conn->tempsock[i] != CURL_SOCKET_BAD) { - socks[s] = conn->tempsock[i]; - bits |= GETSOCK_WRITESOCK(s++); - any = TRUE; - } - } - } - if(!any) { - socks[1] = conn->sock[SECONDARYSOCKET]; - bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); - } - - return bits; - } - return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks); -} - -/* This is called after the FTP_QUOTE state is passed. - - ftp_state_cwd() sends the range of CWD commands to the server to change to - the correct directory. It may also need to send MKD commands to create - missing ones, if that option is enabled. -*/ -static CURLcode ftp_state_cwd(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(ftpc->cwddone) - /* already done and fine */ - result = ftp_state_mdtm(data); - else { - /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */ - DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) || - !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')); - - ftpc->count2 = 0; /* count2 counts failed CWDs */ - - /* count3 is set to allow a MKD to fail once. In the case when first CWD - fails and then MKD fails (due to another session raced it to create the - dir) this then allows for a second try to CWD to it */ - ftpc->count3 = (data->set.ftp_create_missing_dirs == 2)?1:0; - - if(conn->bits.reuse && ftpc->entrypath && - /* no need to go to entrypath when we have an absolute path */ - !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { - /* This is a re-used connection. Since we change directory to where the - transfer is taking place, we must first get back to the original dir - where we ended up after login: */ - ftpc->cwdcount = 0; /* we count this as the first path, then we add one - for all upcoming ones in the ftp->dirs[] array */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath); - if(!result) - state(data, FTP_CWD); - } - else { - if(ftpc->dirdepth) { - ftpc->cwdcount = 1; - /* issue the first CWD, the rest is sent when the CWD responses are - received... */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", - ftpc->dirs[ftpc->cwdcount -1]); - if(!result) - state(data, FTP_CWD); - } - else { - /* No CWD necessary */ - result = ftp_state_mdtm(data); - } - } - } - return result; -} - -typedef enum { - EPRT, - PORT, - DONE -} ftpport; - -static CURLcode ftp_state_use_port(struct Curl_easy *data, - ftpport fcmd) /* start with this */ -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - curl_socket_t portsock = CURL_SOCKET_BAD; - char myhost[MAX_IPADR_LEN + 1] = ""; - - struct Curl_sockaddr_storage ss; - struct Curl_addrinfo *res, *ai; - curl_socklen_t sslen; - char hbuf[NI_MAXHOST]; - struct sockaddr *sa = (struct sockaddr *)&ss; - struct sockaddr_in * const sa4 = (void *)sa; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 * const sa6 = (void *)sa; -#endif - static const char mode[][5] = { "EPRT", "PORT" }; - enum resolve_t rc; - int error; - char *host = NULL; - char *string_ftpport = data->set.str[STRING_FTPPORT]; - struct Curl_dns_entry *h = NULL; - unsigned short port_min = 0; - unsigned short port_max = 0; - unsigned short port; - bool possibly_non_local = TRUE; - char buffer[STRERROR_LEN]; - char *addr = NULL; - - /* Step 1, figure out what is requested, - * accepted format : - * (ipv4|ipv6|domain|interface)?(:port(-range)?)? - */ - - if(data->set.str[STRING_FTPPORT] && - (strlen(data->set.str[STRING_FTPPORT]) > 1)) { - -#ifdef ENABLE_IPV6 - size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ? - INET6_ADDRSTRLEN : strlen(string_ftpport); -#else - size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ? - INET_ADDRSTRLEN : strlen(string_ftpport); -#endif - char *ip_start = string_ftpport; - char *ip_end = NULL; - char *port_start = NULL; - char *port_sep = NULL; - - addr = calloc(addrlen + 1, 1); - if(!addr) - return CURLE_OUT_OF_MEMORY; - -#ifdef ENABLE_IPV6 - if(*string_ftpport == '[') { - /* [ipv6]:port(-range) */ - ip_start = string_ftpport + 1; - ip_end = strchr(string_ftpport, ']'); - if(ip_end) - strncpy(addr, ip_start, ip_end - ip_start); - } - else -#endif - if(*string_ftpport == ':') { - /* :port */ - ip_end = string_ftpport; - } - else { - ip_end = strchr(string_ftpport, ':'); - if(ip_end) { - /* either ipv6 or (ipv4|domain|interface):port(-range) */ -#ifdef ENABLE_IPV6 - if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { - /* ipv6 */ - port_min = port_max = 0; - strcpy(addr, string_ftpport); - ip_end = NULL; /* this got no port ! */ - } - else -#endif - /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start); - } - else - /* ipv4|interface */ - strcpy(addr, string_ftpport); - } - - /* parse the port */ - if(ip_end != NULL) { - port_start = strchr(ip_end, ':'); - if(port_start) { - port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); - port_sep = strchr(port_start, '-'); - if(port_sep) { - port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); - } - else - port_max = port_min; - } - } - - /* correct errors like: - * :1234-1230 - * :-4711, in this case port_min is (unsigned)-1, - * therefore port_min > port_max for all cases - * but port_max = (unsigned)-1 - */ - if(port_min > port_max) - port_min = port_max = 0; - - - if(*addr != '\0') { - /* attempt to get the address of the given interface name */ - switch(Curl_if2ip(conn->ip_addr->ai_family, - Curl_ipv6_scope(conn->ip_addr->ai_addr), - conn->scope_id, addr, hbuf, sizeof(hbuf))) { - case IF2IP_NOT_FOUND: - /* not an interface, use the given string as host name instead */ - host = addr; - break; - case IF2IP_AF_NOT_SUPPORTED: - return CURLE_FTP_PORT_FAILED; - case IF2IP_FOUND: - host = hbuf; /* use the hbuf for host name */ - } - } - else - /* there was only a port(-range) given, default the host */ - host = NULL; - } /* data->set.ftpport */ - - if(!host) { - const char *r; - /* not an interface and not a host name, get default by extracting - the IP from the control connection */ - sslen = sizeof(ss); - if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); - free(addr); - return CURLE_FTP_PORT_FAILED; - } - switch(sa->sa_family) { -#ifdef ENABLE_IPV6 - case AF_INET6: - r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); - break; -#endif - default: - r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); - break; - } - if(!r) - return CURLE_FTP_PORT_FAILED; - host = hbuf; /* use this host name */ - possibly_non_local = FALSE; /* we know it is local now */ - } - - /* resolv ip/host to ip */ - rc = Curl_resolv(data, host, 0, FALSE, &h); - if(rc == CURLRESOLV_PENDING) - (void)Curl_resolver_wait_resolv(data, &h); - if(h) { - res = h->addr; - /* when we return from this function, we can forget about this entry - to we can unlock it now already */ - Curl_resolv_unlock(data, h); - } /* (h) */ - else - res = NULL; /* failure! */ - - if(!res) { - failf(data, "failed to resolve the address provided to PORT: %s", host); - free(addr); - return CURLE_FTP_PORT_FAILED; - } - - free(addr); - host = NULL; - - /* step 2, create a socket for the requested address */ - - portsock = CURL_SOCKET_BAD; - error = 0; - for(ai = res; ai; ai = ai->ai_next) { - result = Curl_socket(data, ai, NULL, &portsock); - if(result) { - error = SOCKERRNO; - continue; - } - break; - } - if(!ai) { - failf(data, "socket failure: %s", - Curl_strerror(error, buffer, sizeof(buffer))); - return CURLE_FTP_PORT_FAILED; - } - - /* step 3, bind to a suitable local address */ - - memcpy(sa, ai->ai_addr, ai->ai_addrlen); - sslen = ai->ai_addrlen; - - for(port = port_min; port <= port_max;) { - if(sa->sa_family == AF_INET) - sa4->sin_port = htons(port); -#ifdef ENABLE_IPV6 - else - sa6->sin6_port = htons(port); -#endif - /* Try binding the given address. */ - if(bind(portsock, sa, sslen) ) { - /* It failed. */ - error = SOCKERRNO; - if(possibly_non_local && (error == EADDRNOTAVAIL)) { - /* The requested bind address is not local. Use the address used for - * the control connection instead and restart the port loop - */ - infof(data, "bind(port=%hu) on non-local address failed: %s", port, - Curl_strerror(error, buffer, sizeof(buffer))); - - sslen = sizeof(ss); - if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); - Curl_closesocket(data, conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - port = port_min; - possibly_non_local = FALSE; /* don't try this again */ - continue; - } - if(error != EADDRINUSE && error != EACCES) { - failf(data, "bind(port=%hu) failed: %s", port, - Curl_strerror(error, buffer, sizeof(buffer))); - Curl_closesocket(data, conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - } - else - break; - - port++; - } - - /* maybe all ports were in use already*/ - if(port > port_max) { - failf(data, "bind() failed, we ran out of ports!"); - Curl_closesocket(data, conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* get the name again after the bind() so that we can extract the - port number it uses now */ - sslen = sizeof(ss); - if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); - Curl_closesocket(data, conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* step 4, listen on the socket */ - - if(listen(portsock, 1)) { - failf(data, "socket failure: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); - Curl_closesocket(data, conn, portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* step 5, send the proper FTP command */ - - /* get a plain printable version of the numerical address to work with - below */ - Curl_printable_address(ai, myhost, sizeof(myhost)); - -#ifdef ENABLE_IPV6 - if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) - /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the - request and enable EPRT again! */ - conn->bits.ftp_use_eprt = TRUE; -#endif - - for(; fcmd != DONE; fcmd++) { - - if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) - /* if disabled, goto next */ - continue; - - if((PORT == fcmd) && sa->sa_family != AF_INET) - /* PORT is IPv4 only */ - continue; - - switch(sa->sa_family) { - case AF_INET: - port = ntohs(sa4->sin_port); - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - port = ntohs(sa6->sin6_port); - break; -#endif - default: - continue; /* might as well skip this */ - } - - if(EPRT == fcmd) { - /* - * Two fine examples from RFC2428; - * - * EPRT |1|132.235.1.2|6275| - * - * EPRT |2|1080::8:800:200C:417A|5282| - */ - - result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], - sa->sa_family == AF_INET?1:2, - myhost, port); - if(result) { - failf(data, "Failure sending EPRT command: %s", - curl_easy_strerror(result)); - Curl_closesocket(data, conn, portsock); - /* don't retry using PORT */ - ftpc->count1 = PORT; - /* bail out */ - state(data, FTP_STOP); - return result; - } - break; - } - if(PORT == fcmd) { - /* large enough for [IP address],[num],[num] */ - char target[sizeof(myhost) + 20]; - char *source = myhost; - char *dest = target; - - /* translate x.x.x.x to x,x,x,x */ - while(source && *source) { - if(*source == '.') - *dest = ','; - else - *dest = *source; - dest++; - source++; - } - *dest = 0; - msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); - - result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target); - if(result) { - failf(data, "Failure sending PORT command: %s", - curl_easy_strerror(result)); - Curl_closesocket(data, conn, portsock); - /* bail out */ - state(data, FTP_STOP); - return result; - } - break; - } - } - - /* store which command was sent */ - ftpc->count1 = fcmd; - - close_secondarysocket(data, conn); - - /* we set the secondary socket variable to this for now, it is only so that - the cleanup function will close it in case we fail before the true - secondary stuff is made */ - conn->sock[SECONDARYSOCKET] = portsock; - - /* this tcpconnect assignment below is a hackish work-around to make the - multi interface with active FTP work - as it will not wait for a - (passive) connect in Curl_is_connected(). - - The *proper* fix is to make sure that the active connection from the - server is done in a non-blocking way. Currently, it is still BLOCKING. - */ - conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; - - state(data, FTP_PORT); - return result; -} - -static CURLcode ftp_state_use_pasv(struct Curl_easy *data, - struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - /* - Here's the executive summary on what to do: - - PASV is RFC959, expect: - 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) - - LPSV is RFC1639, expect: - 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) - - EPSV is RFC2428, expect: - 229 Entering Extended Passive Mode (|||port|) - - */ - - static const char mode[][5] = { "EPSV", "PASV" }; - int modeoff; - -#ifdef PF_INET6 - if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) - /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the - request and enable EPSV again! */ - conn->bits.ftp_use_epsv = TRUE; -#endif - - modeoff = conn->bits.ftp_use_epsv?0:1; - - result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]); - if(!result) { - ftpc->count1 = modeoff; - state(data, FTP_PASV); - infof(data, "Connect data stream passively"); - } - return result; -} - -/* - * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. - * - * REST is the last command in the chain of commands when a "head"-like - * request is made. Thus, if an actual transfer is to be made this is where we - * take off for real. - */ -static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - - if(ftp->transfer != PPTRANSFER_BODY) { - /* doesn't transfer any data */ - - /* still possibly do PRE QUOTE jobs */ - state(data, FTP_RETR_PREQUOTE); - result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE); - } - else if(data->set.ftp_use_port) { - /* We have chosen to use the PORT (or similar) command */ - result = ftp_state_use_port(data, EPRT); - } - else { - /* We have chosen (this is default) to use the PASV (or similar) command */ - if(data->set.ftp_use_pret) { - /* The user has requested that we send a PRET command - to prepare the server for the upcoming PASV */ - struct ftp_conn *ftpc = &conn->proto.ftpc; - if(!conn->proto.ftpc.file) - result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->state.list_only?"NLST":"LIST")); - else if(data->set.upload) - result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s", - conn->proto.ftpc.file); - else - result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s", - conn->proto.ftpc.file); - if(!result) - state(data, FTP_PRET); - } - else - result = ftp_state_use_pasv(data, conn); - } - return result; -} - -static CURLcode ftp_state_rest(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) { - /* if a "head"-like request is being made (on a file) */ - - /* Determine if server can respond to REST command and therefore - whether it supports range */ - result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0); - if(!result) - state(data, FTP_REST); - } - else - result = ftp_state_prepare_transfer(data); - - return result; -} - -static CURLcode ftp_state_size(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) { - /* if a "head"-like request is being made (on a file) */ - - /* we know ftpc->file is a valid pointer to a file name */ - result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); - if(!result) - state(data, FTP_SIZE); - } - else - result = ftp_state_rest(data, conn); - - return result; -} - -static CURLcode ftp_state_list(struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - - /* If this output is to be machine-parsed, the NLST command might be better - to use, since the LIST command output is not specified or standard in any - way. It has turned out that the NLST list output is not the same on all - servers either... */ - - /* - if FTPFILE_NOCWD was specified, we should add the path - as argument for the LIST / NLST / or custom command. - Whether the server will support this, is uncertain. - - The other ftp_filemethods will CWD into dir/dir/ first and - then just do LIST (in that case: nothing to do here) - */ - char *lstArg = NULL; - char *cmd; - - if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) { - /* url-decode before evaluation: e.g. paths starting/ending with %2f */ - const char *slashPos = NULL; - char *rawPath = NULL; - result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, REJECT_CTRL); - if(result) - return result; - - slashPos = strrchr(rawPath, '/'); - if(slashPos) { - /* chop off the file part if format is dir/file otherwise remove - the trailing slash for dir/dir/ except for absolute path / */ - size_t n = slashPos - rawPath; - if(n == 0) - ++n; - - lstArg = rawPath; - lstArg[n] = '\0'; - } - else - free(rawPath); - } - - cmd = aprintf("%s%s%s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->state.list_only?"NLST":"LIST"), - lstArg? " ": "", - lstArg? lstArg: ""); - free(lstArg); - - if(!cmd) - return CURLE_OUT_OF_MEMORY; - - result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd); - free(cmd); - - if(!result) - state(data, FTP_LIST); - - return result; -} - -static CURLcode ftp_state_retr_prequote(struct Curl_easy *data) -{ - /* We've sent the TYPE, now we must send the list of prequote strings */ - return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE); -} - -static CURLcode ftp_state_stor_prequote(struct Curl_easy *data) -{ - /* We've sent the TYPE, now we must send the list of prequote strings */ - return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE); -} - -static CURLcode ftp_state_type(struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - /* If we have selected NOBODY and HEADER, it means that we only want file - information. Which in FTP can't be much more than the file size and - date. */ - if(data->set.opt_no_body && ftpc->file && - ftp_need_type(conn, data->state.prefer_ascii)) { - /* The SIZE command is _not_ RFC 959 specified, and therefore many servers - may not support it! It is however the only way we have to get a file's - size! */ - - ftp->transfer = PPTRANSFER_INFO; - /* this means no actual transfer will be made */ - - /* Some servers return different sizes for different modes, and thus we - must set the proper type before we check the size */ - result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE); - if(result) - return result; - } - else - result = ftp_state_size(data, conn); - - return result; -} - -/* This is called after the CWD commands have been done in the beginning of - the DO phase */ -static CURLcode ftp_state_mdtm(struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - /* Requested time of file or time-depended transfer? */ - if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { - - /* we have requested to get the modified-time of the file, this is a white - spot as the MDTM is not mentioned in RFC959 */ - result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file); - - if(!result) - state(data, FTP_MDTM); - } - else - result = ftp_state_type(data); - - return result; -} - - -/* This is called after the TYPE and possible quote commands have been sent */ -static CURLcode ftp_state_ul_setup(struct Curl_easy *data, - bool sizechecked) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct FTP *ftp = data->req.p.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - bool append = data->set.remote_append; - - if((data->state.resume_from && !sizechecked) || - ((data->state.resume_from > 0) && sizechecked)) { - /* we're about to continue the uploading of a file */ - /* 1. get already existing file's size. We use the SIZE command for this - which may not exist in the server! The SIZE command is not in - RFC959. */ - - /* 2. This used to set REST. But since we can do append, we - don't another ftp command. We just skip the source file - offset and then we APPEND the rest on the file instead */ - - /* 3. pass file-size number of bytes in the source file */ - /* 4. lower the infilesize counter */ - /* => transfer as usual */ - int seekerr = CURL_SEEKFUNC_OK; - - if(data->state.resume_from < 0) { - /* Got no given size to start from, figure it out */ - result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); - if(!result) - state(data, FTP_STOR_SIZE); - return result; - } - - /* enable append */ - append = TRUE; - - /* Let's read off the proper amount of bytes from the input. */ - if(conn->seek_func) { - Curl_set_in_callback(data, true); - seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, - SEEK_SET); - Curl_set_in_callback(data, false); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_FTP_COULDNT_USE_REST; - } - /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - do { - size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, - data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } - /* now, decrease the size of the read */ - if(data->state.infilesize>0) { - data->state.infilesize -= data->state.resume_from; - - if(data->state.infilesize <= 0) { - infof(data, "File already completely uploaded"); - - /* no data to transfer */ - Curl_setup_transfer(data, -1, -1, FALSE, -1); - - /* Set ->transfer so that we won't get any error in - * ftp_done() because we didn't transfer anything! */ - ftp->transfer = PPTRANSFER_NONE; - - state(data, FTP_STOP); - return CURLE_OK; - } - } - /* we've passed, proceed as normal */ - } /* resume_from */ - - result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s", - ftpc->file); - if(!result) - state(data, FTP_STOR); - - return result; -} - -static CURLcode ftp_state_quote(struct Curl_easy *data, - bool init, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - bool quote = FALSE; - struct curl_slist *item; - - switch(instate) { - case FTP_QUOTE: - default: - item = data->set.quote; - break; - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - item = data->set.prequote; - break; - case FTP_POSTQUOTE: - item = data->set.postquote; - break; - } - - /* - * This state uses: - * 'count1' to iterate over the commands to send - * 'count2' to store whether to allow commands to fail - */ - - if(init) - ftpc->count1 = 0; - else - ftpc->count1++; - - if(item) { - int i = 0; - - /* Skip count1 items in the linked list */ - while((i< ftpc->count1) && item) { - item = item->next; - i++; - } - if(item) { - char *cmd = item->data; - if(cmd[0] == '*') { - cmd++; - ftpc->count2 = 1; /* the sent command is allowed to fail */ - } - else - ftpc->count2 = 0; /* failure means cancel operation */ - - result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); - if(result) - return result; - state(data, instate); - quote = TRUE; - } - } - - if(!quote) { - /* No more quote to send, continue to ... */ - switch(instate) { - case FTP_QUOTE: - default: - result = ftp_state_cwd(data, conn); - break; - case FTP_RETR_PREQUOTE: - if(ftp->transfer != PPTRANSFER_BODY) - state(data, FTP_STOP); - else { - if(ftpc->known_filesize != -1) { - Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); - result = ftp_state_retr(data, ftpc->known_filesize); - } - else { - if(data->set.ignorecl || data->state.prefer_ascii) { - /* 'ignorecl' is used to support download of growing files. It - prevents the state machine from requesting the file size from - the server. With an unknown file size the download continues - until the server terminates it, otherwise the client stops if - the received byte count exceeds the reported file size. Set - option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this - behavior. - - In addition: asking for the size for 'TYPE A' transfers is not - constructive since servers don't report the converted size. So - skip it. - */ - result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); - if(!result) - state(data, FTP_RETR); - } - else { - result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); - if(!result) - state(data, FTP_RETR_SIZE); - } - } - } - break; - case FTP_STOR_PREQUOTE: - result = ftp_state_ul_setup(data, FALSE); - break; - case FTP_POSTQUOTE: - break; - } - } - - return result; -} - -/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV - problems */ -static CURLcode ftp_epsv_disable(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if(conn->bits.ipv6 -#ifndef CURL_DISABLE_PROXY - && !(conn->bits.tunnel_proxy || conn->bits.socksproxy) -#endif - ) { - /* We can't disable EPSV when doing IPv6, so this is instead a fail */ - failf(data, "Failed EPSV attempt, exiting"); - return CURLE_WEIRD_SERVER_REPLY; - } - - infof(data, "Failed EPSV attempt. Disabling EPSV"); - /* disable it for next transfer */ - conn->bits.ftp_use_epsv = FALSE; - data->state.errorbuf = FALSE; /* allow error message to get - rewritten */ - result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV"); - if(!result) { - conn->proto.ftpc.count1++; - /* remain in/go to the FTP_PASV state */ - state(data, FTP_PASV); - } - return result; -} - - -static char *control_address(struct connectdata *conn) -{ - /* Returns the control connection IP address. - If a proxy tunnel is used, returns the original host name instead, because - the effective control connection address is the proxy address, - not the ftp host. */ -#ifndef CURL_DISABLE_PROXY - if(conn->bits.tunnel_proxy || conn->bits.socksproxy) - return conn->host.name; -#endif - return conn->primary_ip; -} - -static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, - int ftpcode) -{ - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result; - struct Curl_dns_entry *addr = NULL; - enum resolve_t rc; - unsigned short connectport; /* the local port connect() should use! */ - char *str = &data->state.buffer[4]; /* start on the first letter */ - - /* if we come here again, make sure the former name is cleared */ - Curl_safefree(ftpc->newhost); - - if((ftpc->count1 == 0) && - (ftpcode == 229)) { - /* positive EPSV response */ - char *ptr = strchr(str, '('); - if(ptr) { - unsigned int num; - char separator[4]; - ptr++; - if(5 == sscanf(ptr, "%c%c%c%u%c", - &separator[0], - &separator[1], - &separator[2], - &num, - &separator[3])) { - const char sep1 = separator[0]; - int i; - - /* The four separators should be identical, or else this is an oddly - formatted reply and we bail out immediately. */ - for(i = 1; i<4; i++) { - if(separator[i] != sep1) { - ptr = NULL; /* set to NULL to signal error */ - break; - } - } - if(num > 0xffff) { - failf(data, "Illegal port number in EPSV reply"); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - if(ptr) { - ftpc->newport = (unsigned short)(num & 0xffff); - ftpc->newhost = strdup(control_address(conn)); - if(!ftpc->newhost) - return CURLE_OUT_OF_MEMORY; - } - } - else - ptr = NULL; - } - if(!ptr) { - failf(data, "Weirdly formatted EPSV reply"); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - } - else if((ftpc->count1 == 1) && - (ftpcode == 227)) { - /* positive PASV response */ - unsigned int ip[4] = {0, 0, 0, 0}; - unsigned int port[2] = {0, 0}; - - /* - * Scan for a sequence of six comma-separated numbers and use them as - * IP+port indicators. - * - * Found reply-strings include: - * "227 Entering Passive Mode (127,0,0,1,4,51)" - * "227 Data transfer will passively listen to 127,0,0,1,4,51" - * "227 Entering passive mode. 127,0,0,1,4,51" - */ - while(*str) { - if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u", - &ip[0], &ip[1], &ip[2], &ip[3], - &port[0], &port[1])) - break; - str++; - } - - if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) || - (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) { - failf(data, "Couldn't interpret the 227-response"); - return CURLE_FTP_WEIRD_227_FORMAT; - } - - /* we got OK from server */ - if(data->set.ftp_skip_ip) { - /* told to ignore the remotely given IP but instead use the host we used - for the control connection */ - infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead", - ip[0], ip[1], ip[2], ip[3], - conn->host.name); - ftpc->newhost = strdup(control_address(conn)); - } - else - ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); - - if(!ftpc->newhost) - return CURLE_OUT_OF_MEMORY; - - ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); - } - else if(ftpc->count1 == 0) { - /* EPSV failed, move on to PASV */ - return ftp_epsv_disable(data, conn); - } - else { - failf(data, "Bad PASV/EPSV response: %03d", ftpcode); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - -#ifndef CURL_DISABLE_PROXY - if(conn->bits.proxy) { - /* - * This connection uses a proxy and we need to connect to the proxy again - * here. We don't want to rely on a former host lookup that might've - * expired now, instead we remake the lookup here and now! - */ - const char * const host_name = conn->bits.socksproxy ? - conn->socks_proxy.host.name : conn->http_proxy.host.name; - rc = Curl_resolv(data, host_name, (int)conn->port, FALSE, &addr); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING, ignores the return code but 'addr' will be NULL in - case of failure */ - (void)Curl_resolver_wait_resolv(data, &addr); - - connectport = - (unsigned short)conn->port; /* we connect to the proxy's port */ - - if(!addr) { - failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); - return CURLE_COULDNT_RESOLVE_PROXY; - } - } - else -#endif - { - /* normal, direct, ftp connection */ - DEBUGASSERT(ftpc->newhost); - - /* postponed address resolution in case of tcp fastopen */ - if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) { - Curl_conninfo_remote(data, conn, conn->sock[FIRSTSOCKET]); - Curl_safefree(ftpc->newhost); - ftpc->newhost = strdup(control_address(conn)); - if(!ftpc->newhost) - return CURLE_OUT_OF_MEMORY; - } - - rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING */ - (void)Curl_resolver_wait_resolv(data, &addr); - - connectport = ftpc->newport; /* we connect to the remote port */ - - if(!addr) { - failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); - return CURLE_FTP_CANT_GET_HOST; - } - } - - conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; - result = Curl_connecthost(data, conn, addr); - - if(result) { - Curl_resolv_unlock(data, addr); /* we're done using this address */ - if(ftpc->count1 == 0 && ftpcode == 229) - return ftp_epsv_disable(data, conn); - - return result; - } - - - /* - * When this is used from the multi interface, this might've returned with - * the 'connected' set to FALSE and thus we are now awaiting a non-blocking - * connect to connect. - */ - - if(data->set.verbose) - /* this just dumps information about this second connection */ - ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport); - - Curl_resolv_unlock(data, addr); /* we're done using this address */ - - Curl_safefree(conn->secondaryhostname); - conn->secondary_port = ftpc->newport; - conn->secondaryhostname = strdup(ftpc->newhost); - if(!conn->secondaryhostname) - return CURLE_OUT_OF_MEMORY; - - conn->bits.do_more = TRUE; - state(data, FTP_STOP); /* this phase is completed */ - - return result; -} - -static CURLcode ftp_state_port_resp(struct Curl_easy *data, - int ftpcode) -{ - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - ftpport fcmd = (ftpport)ftpc->count1; - CURLcode result = CURLE_OK; - - /* The FTP spec tells a positive response should have code 200. - Be more permissive here to tolerate deviant servers. */ - if(ftpcode / 100 != 2) { - /* the command failed */ - - if(EPRT == fcmd) { - infof(data, "disabling EPRT usage"); - conn->bits.ftp_use_eprt = FALSE; - } - fcmd++; - - if(fcmd == DONE) { - failf(data, "Failed to do PORT"); - result = CURLE_FTP_PORT_FAILED; - } - else - /* try next */ - result = ftp_state_use_port(data, fcmd); - } - else { - infof(data, "Connect data stream actively"); - state(data, FTP_STOP); /* end of DO phase */ - result = ftp_dophase_done(data, FALSE); - } - - return result; -} - -static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, - int ftpcode) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - switch(ftpcode) { - case 213: - { - /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the - last .sss part is optional and means fractions of a second */ - int year, month, day, hour, minute, second; - if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d", - &year, &month, &day, &hour, &minute, &second)) { - /* we have a time, reformat it */ - char timebuf[24]; - msnprintf(timebuf, sizeof(timebuf), - "%04d%02d%02d %02d:%02d:%02d GMT", - year, month, day, hour, minute, second); - /* now, convert this into a time() value: */ - data->info.filetime = Curl_getdate_capped(timebuf); - } - -#ifdef CURL_FTP_HTTPSTYLE_HEAD - /* 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. */ - - if(data->set.opt_no_body && - ftpc->file && - data->set.get_filetime && - (data->info.filetime >= 0) ) { - char headerbuf[128]; - int headerbuflen; - time_t filetime = data->info.filetime; - struct tm buffer; - const struct tm *tm = &buffer; - - result = Curl_gmtime(filetime, &buffer); - if(result) - return result; - - /* format: "Tue, 15 Nov 1994 12:45:26" */ - headerbuflen = msnprintf(headerbuf, sizeof(headerbuf), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf, - headerbuflen); - if(result) - return result; - } /* end of a ridiculous amount of conditionals */ -#endif - } - break; - default: - infof(data, "unsupported MDTM reply format"); - break; - case 550: /* "No such file or directory" */ - failf(data, "Given file does not exist"); - result = CURLE_REMOTE_FILE_NOT_FOUND; - break; - } - - if(data->set.timecondition) { - if((data->info.filetime > 0) && (data->set.timevalue > 0)) { - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - if(data->info.filetime <= data->set.timevalue) { - infof(data, "The requested document is not new enough"); - ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ - data->info.timecond = TRUE; - state(data, FTP_STOP); - return CURLE_OK; - } - break; - case CURL_TIMECOND_IFUNMODSINCE: - if(data->info.filetime > data->set.timevalue) { - infof(data, "The requested document is not old enough"); - ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ - data->info.timecond = TRUE; - state(data, FTP_STOP); - return CURLE_OK; - } - break; - } /* switch */ - } - else { - infof(data, "Skipping time comparison"); - } - } - - if(!result) - result = ftp_state_type(data); - - return result; -} - -static CURLcode ftp_state_type_resp(struct Curl_easy *data, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - - if(ftpcode/100 != 2) { - /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a - successful 'TYPE I'. While that is not as RFC959 says, it is still a - positive response code and we allow that. */ - failf(data, "Couldn't set desired mode"); - return CURLE_FTP_COULDNT_SET_TYPE; - } - if(ftpcode != 200) - infof(data, "Got a %03d response code instead of the assumed 200", - ftpcode); - - if(instate == FTP_TYPE) - result = ftp_state_size(data, conn); - else if(instate == FTP_LIST_TYPE) - result = ftp_state_list(data); - else if(instate == FTP_RETR_TYPE) - result = ftp_state_retr_prequote(data); - else if(instate == FTP_STOR_TYPE) - result = ftp_state_stor_prequote(data); - - return result; -} - -static CURLcode ftp_state_retr(struct Curl_easy *data, - curl_off_t filesize) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(data->set.max_filesize && (filesize > data->set.max_filesize)) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - ftp->downloadsize = filesize; - - if(data->state.resume_from) { - /* We always (attempt to) get the size of downloads, so it is done before - this even when not doing resumes. */ - if(filesize == -1) { - infof(data, "ftp server doesn't support SIZE"); - /* We couldn't get the size and therefore we can't know if there really - is a part of the file left to get, although the server will just - close the connection when we start the connection so it won't cause - us any harm, just not make us exit as nicely. */ - } - else { - /* We got a file size report, so we check that there actually is a - part of the file left to get, or else we go home. */ - if(data->state.resume_from< 0) { - /* We're supposed to download the last abs(from) bytes */ - if(filesize < -data->state.resume_from) { - failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T - ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", - data->state.resume_from, filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* convert to size to download */ - ftp->downloadsize = -data->state.resume_from; - /* download from where? */ - data->state.resume_from = filesize - ftp->downloadsize; - } - else { - if(filesize < data->state.resume_from) { - failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T - ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", - data->state.resume_from, filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* Now store the number of bytes we are expected to download */ - ftp->downloadsize = filesize-data->state.resume_from; - } - } - - if(ftp->downloadsize == 0) { - /* no data to transfer */ - Curl_setup_transfer(data, -1, -1, FALSE, -1); - infof(data, "File already completely downloaded"); - - /* Set ->transfer so that we won't get any error in ftp_done() - * because we didn't transfer the any file */ - ftp->transfer = PPTRANSFER_NONE; - state(data, FTP_STOP); - return CURLE_OK; - } - - /* Set resume file transfer offset */ - infof(data, "Instructs server to resume from offset %" - CURL_FORMAT_CURL_OFF_T, data->state.resume_from); - - result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, - data->state.resume_from); - if(!result) - state(data, FTP_RETR_REST); - } - else { - /* no resume */ - result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); - if(!result) - state(data, FTP_RETR); - } - - return result; -} - -static CURLcode ftp_state_size_resp(struct Curl_easy *data, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - curl_off_t filesize = -1; - char *buf = data->state.buffer; - - /* get the size from the ascii string: */ - if(ftpcode == 213) { - /* To allow servers to prepend "rubbish" in the response string, we scan - for all the digits at the end of the response and parse only those as a - number. */ - char *start = &buf[4]; - char *fdigit = strchr(start, '\r'); - if(fdigit) { - do - fdigit--; - while(ISDIGIT(*fdigit) && (fdigit > start)); - if(!ISDIGIT(*fdigit)) - fdigit++; - } - else - fdigit = start; - /* ignores parsing errors, which will make the size remain unknown */ - (void)curlx_strtoofft(fdigit, NULL, 0, &filesize); - - } - else if(ftpcode == 550) { /* "No such file or directory" */ - /* allow a SIZE failure for (resumed) uploads, when probing what command - to use */ - if(instate != FTP_STOR_SIZE) { - failf(data, "The file does not exist"); - return CURLE_REMOTE_FILE_NOT_FOUND; - } - } - - if(instate == FTP_SIZE) { -#ifdef CURL_FTP_HTTPSTYLE_HEAD - if(-1 != filesize) { - char clbuf[128]; - int clbuflen = msnprintf(clbuf, sizeof(clbuf), - "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); - result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen); - if(result) - return result; - } -#endif - Curl_pgrsSetDownloadSize(data, filesize); - result = ftp_state_rest(data, data->conn); - } - else if(instate == FTP_RETR_SIZE) { - Curl_pgrsSetDownloadSize(data, filesize); - result = ftp_state_retr(data, filesize); - } - else if(instate == FTP_STOR_SIZE) { - data->state.resume_from = filesize; - result = ftp_state_ul_setup(data, TRUE); - } - - return result; -} - -static CURLcode ftp_state_rest_resp(struct Curl_easy *data, - struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - switch(instate) { - case FTP_REST: - default: -#ifdef CURL_FTP_HTTPSTYLE_HEAD - if(ftpcode == 350) { - char buffer[24]= { "Accept-ranges: bytes\r\n" }; - result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer, - strlen(buffer)); - if(result) - return result; - } -#endif - result = ftp_state_prepare_transfer(data); - break; - - case FTP_RETR_REST: - if(ftpcode != 350) { - failf(data, "Couldn't use REST"); - result = CURLE_FTP_COULDNT_USE_REST; - } - else { - result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); - if(!result) - state(data, FTP_RETR); - } - break; - } - - return result; -} - -static CURLcode ftp_state_stor_resp(struct Curl_easy *data, - int ftpcode, ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - - if(ftpcode >= 400) { - failf(data, "Failed FTP upload: %0d", ftpcode); - state(data, FTP_STOP); - /* oops, we never close the sockets! */ - return CURLE_UPLOAD_FAILED; - } - - conn->proto.ftpc.state_saved = instate; - - /* PORT means we are now awaiting the server to connect to us. */ - if(data->set.ftp_use_port) { - bool connected; - - state(data, FTP_STOP); /* no longer in STOR state */ - - result = AllowServerConnect(data, &connected); - if(result) - return result; - - if(!connected) { - struct ftp_conn *ftpc = &conn->proto.ftpc; - infof(data, "Data conn was not available immediately"); - ftpc->wait_data_conn = TRUE; - } - - return CURLE_OK; - } - return InitiateTransfer(data); -} - -/* for LIST and RETR responses */ -static CURLcode ftp_state_get_resp(struct Curl_easy *data, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - - if((ftpcode == 150) || (ftpcode == 125)) { - - /* - A; - 150 Opening BINARY mode data connection for /etc/passwd (2241 - bytes). (ok, the file is being transferred) - - B: - 150 Opening ASCII mode data connection for /bin/ls - - C: - 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). - - D: - 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) - - E: - 125 Data connection already open; Transfer starting. */ - - curl_off_t size = -1; /* default unknown size */ - - - /* - * It appears that there are FTP-servers that return size 0 for files when - * SIZE is used on the file while being in BINARY mode. To work around - * that (stupid) behavior, we attempt to parse the RETR response even if - * the SIZE returned size zero. - * - * Debugging help from Salvatore Sorrentino on February 26, 2003. - */ - - if((instate != FTP_LIST) && - !data->state.prefer_ascii && - (ftp->downloadsize < 1)) { - /* - * It seems directory listings either don't show the size or very - * often uses size 0 anyway. ASCII transfers may very well turn out - * that the transferred amount of data is not the same as this line - * tells, why using this number in those cases only confuses us. - * - * Example D above makes this parsing a little tricky */ - char *bytes; - char *buf = data->state.buffer; - bytes = strstr(buf, " bytes"); - if(bytes) { - long in = (long)(--bytes-buf); - /* this is a hint there is size information in there! ;-) */ - while(--in) { - /* scan for the left parenthesis and break there */ - if('(' == *bytes) - break; - /* skip only digits */ - if(!ISDIGIT(*bytes)) { - bytes = NULL; - break; - } - /* one more estep backwards */ - bytes--; - } - /* if we have nothing but digits: */ - if(bytes) { - ++bytes; - /* get the number! */ - (void)curlx_strtoofft(bytes, NULL, 0, &size); - } - } - } - else if(ftp->downloadsize > -1) - size = ftp->downloadsize; - - if(size > data->req.maxdownload && data->req.maxdownload > 0) - size = data->req.size = data->req.maxdownload; - else if((instate != FTP_LIST) && (data->state.prefer_ascii)) - size = -1; /* kludge for servers that understate ASCII mode file size */ - - infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T, - data->req.maxdownload); - - if(instate != FTP_LIST) - infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T, - size); - - /* FTP download: */ - conn->proto.ftpc.state_saved = instate; - conn->proto.ftpc.retr_size_saved = size; - - if(data->set.ftp_use_port) { - bool connected; - - result = AllowServerConnect(data, &connected); - if(result) - return result; - - if(!connected) { - struct ftp_conn *ftpc = &conn->proto.ftpc; - infof(data, "Data conn was not available immediately"); - state(data, FTP_STOP); - ftpc->wait_data_conn = TRUE; - } - } - else - return InitiateTransfer(data); - } - else { - if((instate == FTP_LIST) && (ftpcode == 450)) { - /* simply no matching files in the dir listing */ - ftp->transfer = PPTRANSFER_NONE; /* don't download anything */ - state(data, FTP_STOP); /* this phase is over */ - } - else { - failf(data, "RETR response: %03d", ftpcode); - return instate == FTP_RETR && ftpcode == 550? - CURLE_REMOTE_FILE_NOT_FOUND: - CURLE_FTP_COULDNT_RETR_FILE; - } - } - - return result; -} - -/* after USER, PASS and ACCT */ -static CURLcode ftp_state_loggedin(struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - - if(conn->bits.ftp_use_control_ssl) { - /* PBSZ = PROTECTION BUFFER SIZE. - - The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: - - Specifically, the PROT command MUST be preceded by a PBSZ - command and a PBSZ command MUST be preceded by a successful - security data exchange (the TLS negotiation in this case) - - ... (and on page 8): - - Thus the PBSZ command must still be issued, but must have a - parameter of '0' to indicate that no buffering is taking place - and the data connection should not be encapsulated. - */ - result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0); - if(!result) - state(data, FTP_PBSZ); - } - else { - result = ftp_state_pwd(data, conn); - } - return result; -} - -/* for USER and PASS responses */ -static CURLcode ftp_state_user_resp(struct Curl_easy *data, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - (void)instate; /* no use for this yet */ - - /* some need password anyway, and others just return 2xx ignored */ - if((ftpcode == 331) && (ftpc->state == FTP_USER)) { - /* 331 Password required for ... - (the server requires to send the user's password too) */ - result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", - conn->passwd?conn->passwd:""); - if(!result) - state(data, FTP_PASS); - } - else if(ftpcode/100 == 2) { - /* 230 User ... logged in. - (the user logged in with or without password) */ - result = ftp_state_loggedin(data); - } - else if(ftpcode == 332) { - if(data->set.str[STRING_FTP_ACCOUNT]) { - result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s", - data->set.str[STRING_FTP_ACCOUNT]); - if(!result) - state(data, FTP_ACCT); - } - else { - failf(data, "ACCT requested but none available"); - result = CURLE_LOGIN_DENIED; - } - } - else { - /* All other response codes, like: - - 530 User ... access denied - (the server denies to log the specified user) */ - - if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && - !data->state.ftp_trying_alternative) { - /* Ok, USER failed. Let's try the supplied command. */ - result = - Curl_pp_sendf(data, &ftpc->pp, "%s", - data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); - if(!result) { - data->state.ftp_trying_alternative = TRUE; - state(data, FTP_USER); - } - } - else { - failf(data, "Access denied: %03d", ftpcode); - result = CURLE_LOGIN_DENIED; - } - } - return result; -} - -/* for ACCT response */ -static CURLcode ftp_state_acct_resp(struct Curl_easy *data, - int ftpcode) -{ - CURLcode result = CURLE_OK; - if(ftpcode != 230) { - failf(data, "ACCT rejected by server: %03d", ftpcode); - result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ - } - else - result = ftp_state_loggedin(data); - - return result; -} - - -static CURLcode ftp_statemachine(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int ftpcode; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - static const char ftpauth[][4] = { "SSL", "TLS" }; - size_t nread = 0; - - if(pp->sendleft) - return Curl_pp_flushsend(data, pp); - - result = ftp_readresp(data, sock, pp, &ftpcode, &nread); - if(result) - return result; - - if(ftpcode) { - /* we have now received a full FTP server response */ - switch(ftpc->state) { - case FTP_WAIT220: - if(ftpcode == 230) { - /* 230 User logged in - already! Take as 220 if TLS required. */ - if(data->set.use_ssl <= CURLUSESSL_TRY || - conn->bits.ftp_use_control_ssl) - return ftp_state_user_resp(data, ftpcode, ftpc->state); - } - else if(ftpcode != 220) { - failf(data, "Got a %03d ftp-server response when 220 was expected", - ftpcode); - return CURLE_WEIRD_SERVER_REPLY; - } - - /* We have received a 220 response fine, now we proceed. */ -#ifdef HAVE_GSSAPI - if(data->set.krb) { - /* If not anonymous login, try a secure login. Note that this - procedure is still BLOCKING. */ - - Curl_sec_request_prot(conn, "private"); - /* We set private first as default, in case the line below fails to - set a valid level */ - Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - - if(Curl_sec_login(data, conn)) - infof(data, "Logging in with password in cleartext!"); - else - infof(data, "Authentication successful"); - } -#endif - - if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { - /* We don't have a SSL/TLS control connection yet, but FTPS is - requested. Try a FTPS connection now */ - - ftpc->count3 = 0; - switch(data->set.ftpsslauth) { - case CURLFTPAUTH_DEFAULT: - case CURLFTPAUTH_SSL: - ftpc->count2 = 1; /* add one to get next */ - ftpc->count1 = 0; - break; - case CURLFTPAUTH_TLS: - ftpc->count2 = -1; /* subtract one to get next */ - ftpc->count1 = 1; - break; - default: - failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", - (int)data->set.ftpsslauth); - return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ - } - result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", - ftpauth[ftpc->count1]); - if(!result) - state(data, FTP_AUTH); - } - else - result = ftp_state_user(data, conn); - break; - - case FTP_AUTH: - /* we have gotten the response to a previous AUTH command */ - - if(pp->cache_size) - return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ - - /* RFC2228 (page 5) says: - * - * If the server is willing to accept the named security mechanism, - * and does not require any security data, it must respond with - * reply code 234/334. - */ - - if((ftpcode == 234) || (ftpcode == 334)) { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(data, conn, FIRSTSOCKET); - if(!result) { - conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ - conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ - result = ftp_state_user(data, conn); - } - } - else if(ftpc->count3 < 1) { - ftpc->count3++; - ftpc->count1 += ftpc->count2; /* get next attempt */ - result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", - ftpauth[ftpc->count1]); - /* remain in this same state */ - } - else { - if(data->set.use_ssl > CURLUSESSL_TRY) - /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ - result = CURLE_USE_SSL_FAILED; - else - /* ignore the failure and continue */ - result = ftp_state_user(data, conn); - } - break; - - case FTP_USER: - case FTP_PASS: - result = ftp_state_user_resp(data, ftpcode, ftpc->state); - break; - - case FTP_ACCT: - result = ftp_state_acct_resp(data, ftpcode); - break; - - case FTP_PBSZ: - result = - Curl_pp_sendf(data, &ftpc->pp, "PROT %c", - data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); - if(!result) - state(data, FTP_PROT); - break; - - case FTP_PROT: - if(ftpcode/100 == 2) - /* We have enabled SSL for the data connection! */ - conn->bits.ftp_use_data_ssl = - (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; - /* FTP servers typically responds with 500 if they decide to reject - our 'P' request */ - else if(data->set.use_ssl > CURLUSESSL_CONTROL) - /* we failed and bails out */ - return CURLE_USE_SSL_FAILED; - - if(data->set.ftp_ccc) { - /* CCC - Clear Command Channel - */ - result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); - if(!result) - state(data, FTP_CCC); - } - else - result = ftp_state_pwd(data, conn); - break; - - case FTP_CCC: - if(ftpcode < 500) { - /* First shut down the SSL layer (note: this call will block) */ - result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET); - - if(result) - failf(data, "Failed to clear the command channel (CCC)"); - } - if(!result) - /* Then continue as normal */ - result = ftp_state_pwd(data, conn); - break; - - case FTP_PWD: - if(ftpcode == 257) { - char *ptr = &data->state.buffer[4]; /* start on the first letter */ - const size_t buf_size = data->set.buffer_size; - char *dir; - bool entry_extracted = FALSE; - - dir = malloc(nread + 1); - if(!dir) - return CURLE_OUT_OF_MEMORY; - - /* Reply format is like - 257[rubbish]"" and the - RFC959 says - - The directory name can contain any character; embedded - double-quotes should be escaped by double-quotes (the - "quote-doubling" convention). - */ - - /* scan for the first double-quote for non-standard responses */ - while(ptr < &data->state.buffer[buf_size] - && *ptr != '\n' && *ptr != '\0' && *ptr != '"') - ptr++; - - if('\"' == *ptr) { - /* it started good */ - char *store; - ptr++; - for(store = dir; *ptr;) { - if('\"' == *ptr) { - if('\"' == ptr[1]) { - /* "quote-doubling" */ - *store = ptr[1]; - ptr++; - } - else { - /* end of path */ - entry_extracted = TRUE; - break; /* get out of this loop */ - } - } - else - *store = *ptr; - store++; - ptr++; - } - *store = '\0'; /* null-terminate */ - } - if(entry_extracted) { - /* If the path name does not look like an absolute path (i.e.: it - does not start with a '/'), we probably need some server-dependent - adjustments. For example, this is the case when connecting to - an OS400 FTP server: this server supports two name syntaxes, - the default one being incompatible with standard paths. In - addition, this server switches automatically to the regular path - syntax when one is encountered in a command: this results in - having an entrypath in the wrong syntax when later used in CWD. - The method used here is to check the server OS: we do it only - if the path name looks strange to minimize overhead on other - systems. */ - - if(!ftpc->server_os && dir[0] != '/') { - result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); - if(result) { - free(dir); - return result; - } - Curl_safefree(ftpc->entrypath); - ftpc->entrypath = dir; /* remember this */ - infof(data, "Entry path is '%s'", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; - state(data, FTP_SYST); - break; - } - - Curl_safefree(ftpc->entrypath); - ftpc->entrypath = dir; /* remember this */ - infof(data, "Entry path is '%s'", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; - } - else { - /* couldn't get the path */ - free(dir); - infof(data, "Failed to figure out path"); - } - } - state(data, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE")); - break; - - case FTP_SYST: - if(ftpcode == 215) { - char *ptr = &data->state.buffer[4]; /* start on the first letter */ - char *os; - char *store; - - os = malloc(nread + 1); - if(!os) - return CURLE_OUT_OF_MEMORY; - - /* Reply format is like - 215 - */ - while(*ptr == ' ') - ptr++; - for(store = os; *ptr && *ptr != ' ';) - *store++ = *ptr++; - *store = '\0'; /* null-terminate */ - - /* Check for special servers here. */ - - if(strcasecompare(os, "OS/400")) { - /* Force OS400 name format 1. */ - result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); - if(result) { - free(os); - return result; - } - /* remember target server OS */ - Curl_safefree(ftpc->server_os); - ftpc->server_os = os; - state(data, FTP_NAMEFMT); - break; - } - /* Nothing special for the target server. */ - /* remember target server OS */ - Curl_safefree(ftpc->server_os); - ftpc->server_os = os; - } - else { - /* Cannot identify server OS. Continue anyway and cross fingers. */ - } - - state(data, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE")); - break; - - case FTP_NAMEFMT: - if(ftpcode == 250) { - /* Name format change successful: reload initial path. */ - ftp_state_pwd(data, conn); - break; - } - - state(data, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE")); - break; - - case FTP_QUOTE: - case FTP_POSTQUOTE: - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - if((ftpcode >= 400) && !ftpc->count2) { - /* failure response code, and not allowed to fail */ - failf(data, "QUOT command failed with %03d", ftpcode); - result = CURLE_QUOTE_ERROR; - } - else - result = ftp_state_quote(data, FALSE, ftpc->state); - break; - - case FTP_CWD: - if(ftpcode/100 != 2) { - /* failure to CWD there */ - if(data->set.ftp_create_missing_dirs && - ftpc->cwdcount && !ftpc->count2) { - /* try making it */ - ftpc->count2++; /* counter to prevent CWD-MKD loops */ - result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", - ftpc->dirs[ftpc->cwdcount - 1]); - if(!result) - state(data, FTP_MKD); - } - else { - /* return failure */ - failf(data, "Server denied you to change to the given directory"); - ftpc->cwdfail = TRUE; /* don't remember this path as we failed - to enter it */ - result = CURLE_REMOTE_ACCESS_DENIED; - } - } - else { - /* success */ - ftpc->count2 = 0; - if(++ftpc->cwdcount <= ftpc->dirdepth) - /* send next CWD */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", - ftpc->dirs[ftpc->cwdcount - 1]); - else - result = ftp_state_mdtm(data); - } - break; - - case FTP_MKD: - if((ftpcode/100 != 2) && !ftpc->count3--) { - /* failure to MKD the dir */ - failf(data, "Failed to MKD dir: %03d", ftpcode); - result = CURLE_REMOTE_ACCESS_DENIED; - } - else { - state(data, FTP_CWD); - /* send CWD */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", - ftpc->dirs[ftpc->cwdcount - 1]); - } - break; - - case FTP_MDTM: - result = ftp_state_mdtm_resp(data, ftpcode); - break; - - case FTP_TYPE: - case FTP_LIST_TYPE: - case FTP_RETR_TYPE: - case FTP_STOR_TYPE: - result = ftp_state_type_resp(data, ftpcode, ftpc->state); - break; - - case FTP_SIZE: - case FTP_RETR_SIZE: - case FTP_STOR_SIZE: - result = ftp_state_size_resp(data, ftpcode, ftpc->state); - break; - - case FTP_REST: - case FTP_RETR_REST: - result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); - break; - - case FTP_PRET: - if(ftpcode != 200) { - /* there only is this one standard OK return code. */ - failf(data, "PRET command not accepted: %03d", ftpcode); - return CURLE_FTP_PRET_FAILED; - } - result = ftp_state_use_pasv(data, conn); - break; - - case FTP_PASV: - result = ftp_state_pasv_resp(data, ftpcode); - break; - - case FTP_PORT: - result = ftp_state_port_resp(data, ftpcode); - break; - - case FTP_LIST: - case FTP_RETR: - result = ftp_state_get_resp(data, ftpcode, ftpc->state); - break; - - case FTP_STOR: - result = ftp_state_stor_resp(data, ftpcode, ftpc->state); - break; - - case FTP_QUIT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(data, FTP_STOP); - break; - } - } /* if(ftpcode) */ - - return result; -} - - -/* called repeatedly until done from multi.c */ -static CURLcode ftp_multi_statemach(struct Curl_easy *data, - bool *done) -{ - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE); - - /* Check for the state outside of the Curl_socket_check() return code checks - since at times we are in fact already in this state when this function - gets called. */ - *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; - - return result; -} - -static CURLcode ftp_block_statemach(struct Curl_easy *data, - struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - CURLcode result = CURLE_OK; - - while(ftpc->state != FTP_STOP) { - result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */); - if(result) - break; - } - - return result; -} - -/* - * ftp_connect() should do everything that is to be considered a part of - * the connection phase. - * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE if not. - * - */ -static CURLcode ftp_connect(struct Curl_easy *data, - bool *done) /* see description above */ -{ - CURLcode result; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - - *done = FALSE; /* default to not done yet */ - - /* We always support persistent connections on ftp */ - connkeep(conn, "FTP default"); - - PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp); - - if(conn->handler->flags & PROTOPT_SSL) { - /* BLOCKING */ - result = Curl_ssl_connect(data, conn, FIRSTSOCKET); - if(result) - return result; - conn->bits.ftp_use_control_ssl = TRUE; - } - - Curl_pp_setup(pp); /* once per transfer */ - Curl_pp_init(data, pp); /* init the generic pingpong data */ - - /* When we connect, we start in the state where we await the 220 - response */ - state(data, FTP_WAIT220); - - result = ftp_multi_statemach(data, done); - - return result; -} - -/*********************************************************************** - * - * ftp_done() - * - * The DONE function. This does what needs to be done after a single DO has - * performed. - * - * Input argument is already checked for validity. - */ -static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, - bool premature) -{ - struct connectdata *conn = data->conn; - struct FTP *ftp = data->req.p.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - ssize_t nread; - int ftpcode; - CURLcode result = CURLE_OK; - char *rawPath = NULL; - size_t pathLen = 0; - - if(!ftp) - return CURLE_OK; - - switch(status) { - case CURLE_BAD_DOWNLOAD_RESUME: - case CURLE_FTP_WEIRD_PASV_REPLY: - case CURLE_FTP_PORT_FAILED: - case CURLE_FTP_ACCEPT_FAILED: - case CURLE_FTP_ACCEPT_TIMEOUT: - case CURLE_FTP_COULDNT_SET_TYPE: - case CURLE_FTP_COULDNT_RETR_FILE: - case CURLE_PARTIAL_FILE: - case CURLE_UPLOAD_FAILED: - case CURLE_REMOTE_ACCESS_DENIED: - case CURLE_FILESIZE_EXCEEDED: - case CURLE_REMOTE_FILE_NOT_FOUND: - case CURLE_WRITE_ERROR: - /* the connection stays alive fine even though this happened */ - /* fall-through */ - case CURLE_OK: /* doesn't affect the control connection's status */ - if(!premature) - break; - - /* until we cope better with prematurely ended requests, let them - * fallback as if in complete failure */ - /* FALLTHROUGH */ - default: /* by default, an error means the control connection is - wedged and should not be used anymore */ - ftpc->ctl_valid = FALSE; - ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the - current path, as this connection is going */ - connclose(conn, "FTP ended with bad error code"); - result = status; /* use the already set error code */ - break; - } - - if(data->state.wildcardmatch) { - if(data->set.chunk_end && ftpc->file) { - Curl_set_in_callback(data, true); - data->set.chunk_end(data->wildcard.customptr); - Curl_set_in_callback(data, false); - } - ftpc->known_filesize = -1; - } - - if(!result) - /* get the url-decoded "raw" path */ - result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, - REJECT_CTRL); - if(result) { - /* We can limp along anyway (and should try to since we may already be in - * the error path) */ - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ - free(ftpc->prevpath); - ftpc->prevpath = NULL; /* no path remembering */ - } - else { /* remember working directory for connection reuse */ - if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) - free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */ - else { - free(ftpc->prevpath); - - if(!ftpc->cwdfail) { - if(data->set.ftp_filemethod == FTPFILE_NOCWD) - pathLen = 0; /* relative path => working directory is FTP home */ - else - pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */ - - rawPath[pathLen] = '\0'; - ftpc->prevpath = rawPath; - } - else { - free(rawPath); - ftpc->prevpath = NULL; /* no path */ - } - } - - if(ftpc->prevpath) - infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath); - } - - /* free the dir tree and file parts */ - freedirs(ftpc); - - /* shut down the socket to inform the server we're done */ - -#ifdef _WIN32_WCE - shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ -#endif - - if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { - if(!result && ftpc->dont_check && data->req.maxdownload > 0) { - /* partial download completed */ - result = Curl_pp_sendf(data, pp, "%s", "ABOR"); - if(result) { - failf(data, "Failure sending ABOR command: %s", - curl_easy_strerror(result)); - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "ABOR command failed"); /* connection closure */ - } - } - - if(conn->ssl[SECONDARYSOCKET].use) { - /* The secondary socket is using SSL so we must close down that part - first before we close the socket for real */ - Curl_ssl_close(data, conn, SECONDARYSOCKET); - - /* Note that we keep "use" set to TRUE since that (next) connection is - still requested to use SSL */ - } - close_secondarysocket(data, conn); - } - - if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid && - pp->pending_resp && !premature) { - /* - * Let's see what the server says about the transfer we just performed, - * but lower the timeout as sometimes this connection has died while the - * data has been transferred. This happens when doing through NATs etc that - * abandon old silent connections. - */ - timediff_t old_time = pp->response_time; - - pp->response_time = 60*1000; /* give it only a minute for now */ - pp->response = Curl_now(); /* timeout relative now */ - - result = Curl_GetFTPResponse(data, &nread, &ftpcode); - - pp->response_time = old_time; /* set this back to previous value */ - - if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { - failf(data, "control connection looks dead"); - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ - } - - if(result) { - Curl_safefree(ftp->pathalloc); - return result; - } - - if(ftpc->dont_check && data->req.maxdownload > 0) { - /* we have just sent ABOR and there is no reliable way to check if it was - * successful or not; we have to close the connection now */ - infof(data, "partial download completed, closing connection"); - connclose(conn, "Partial download with no ability to check"); - return result; - } - - if(!ftpc->dont_check) { - /* 226 Transfer complete, 250 Requested file action okay, completed. */ - switch(ftpcode) { - case 226: - case 250: - break; - case 552: - failf(data, "Exceeded storage allocation"); - result = CURLE_REMOTE_DISK_FULL; - break; - default: - failf(data, "server did not report OK, got %d", ftpcode); - result = CURLE_PARTIAL_FILE; - break; - } - } - } - - if(result || premature) - /* the response code from the transfer showed an error already so no - use checking further */ - ; - else if(data->set.upload) { - if((-1 != data->state.infilesize) && - (data->state.infilesize != data->req.writebytecount) && - !data->set.crlf && - (ftp->transfer == PPTRANSFER_BODY)) { - failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T - " out of %" CURL_FORMAT_CURL_OFF_T " bytes)", - data->req.bytecount, data->state.infilesize); - result = CURLE_PARTIAL_FILE; - } - } - else { - if((-1 != data->req.size) && - (data->req.size != data->req.bytecount) && -#ifdef CURL_DO_LINEEND_CONV - /* Most FTP servers don't adjust their file SIZE response for CRLFs, so - * we'll check to see if the discrepancy can be explained by the number - * of CRLFs we've changed to LFs. - */ - ((data->req.size + data->state.crlf_conversions) != - data->req.bytecount) && -#endif /* CURL_DO_LINEEND_CONV */ - (data->req.maxdownload != data->req.bytecount)) { - failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T - " bytes", data->req.bytecount); - result = CURLE_PARTIAL_FILE; - } - else if(!ftpc->dont_check && - !data->req.bytecount && - (data->req.size>0)) { - failf(data, "No data was received!"); - result = CURLE_FTP_COULDNT_RETR_FILE; - } - } - - /* clear these for next connection */ - ftp->transfer = PPTRANSFER_BODY; - ftpc->dont_check = FALSE; - - /* Send any post-transfer QUOTE strings? */ - if(!status && !result && !premature && data->set.postquote) - result = ftp_sendquote(data, conn, data->set.postquote); - Curl_safefree(ftp->pathalloc); - return result; -} - -/*********************************************************************** - * - * ftp_sendquote() - * - * Where a 'quote' means a list of custom commands to send to the server. - * The quote list is passed as an argument. - * - * BLOCKING - */ - -static -CURLcode ftp_sendquote(struct Curl_easy *data, - struct connectdata *conn, struct curl_slist *quote) -{ - struct curl_slist *item; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - - item = quote; - while(item) { - if(item->data) { - ssize_t nread; - char *cmd = item->data; - bool acceptfail = FALSE; - CURLcode result; - int ftpcode = 0; - - /* if a command starts with an asterisk, which a legal FTP command never - can, the command will be allowed to fail without it causing any - aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ - - if(cmd[0] == '*') { - cmd++; - acceptfail = TRUE; - } - - result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); - if(!result) { - pp->response = Curl_now(); /* timeout relative now */ - result = Curl_GetFTPResponse(data, &nread, &ftpcode); - } - if(result) - return result; - - if(!acceptfail && (ftpcode >= 400)) { - failf(data, "QUOT string not accepted: %s", cmd); - return CURLE_QUOTE_ERROR; - } - } - - item = item->next; - } - - return CURLE_OK; -} - -/*********************************************************************** - * - * ftp_need_type() - * - * Returns TRUE if we in the current situation should send TYPE - */ -static int ftp_need_type(struct connectdata *conn, - bool ascii_wanted) -{ - return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); -} - -/*********************************************************************** - * - * ftp_nb_type() - * - * Set TYPE. We only deal with ASCII or BINARY so this function - * sets one of them. - * If the transfer type is not sent, simulate on OK response in newstate - */ -static CURLcode ftp_nb_type(struct Curl_easy *data, - struct connectdata *conn, - bool ascii, ftpstate newstate) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result; - char want = (char)(ascii?'A':'I'); - - if(ftpc->transfertype == want) { - state(data, newstate); - return ftp_state_type_resp(data, 200, newstate); - } - - result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want); - if(!result) { - state(data, newstate); - - /* keep track of our current transfer type */ - ftpc->transfertype = want; - } - return result; -} - -/*************************************************************************** - * - * ftp_pasv_verbose() - * - * This function only outputs some informationals about this second connection - * when we've issued a PASV command before and thus we have connected to a - * possibly new IP address. - * - */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS -static void -ftp_pasv_verbose(struct Curl_easy *data, - struct Curl_addrinfo *ai, - char *newhost, /* ascii version */ - int port) -{ - char buf[256]; - Curl_printable_address(ai, buf, sizeof(buf)); - infof(data, "Connecting to %s (%s) port %d", newhost, buf, port); -} -#endif - -/* - * ftp_do_more() - * - * This function shall be called when the second FTP (data) connection is - * connected. - * - * 'complete' can return 0 for incomplete, 1 for done and -1 for go back - * (which basically is only for when PASV is being sent to retry a failed - * EPSV). - */ - -static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) -{ - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - bool connected = FALSE; - bool complete = FALSE; - - /* the ftp struct is inited in ftp_connect() */ - struct FTP *ftp = data->req.p.ftp; - - /* if the second connection isn't done yet, wait for it */ - if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { - if(Curl_connect_ongoing(conn)) { - /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port - aren't used so we blank their arguments. */ - result = Curl_proxyCONNECT(data, SECONDARYSOCKET, NULL, 0); - - return result; - } - - result = Curl_is_connected(data, conn, SECONDARYSOCKET, &connected); - - /* Ready to do more? */ - if(connected) { - DEBUGF(infof(data, "DO-MORE connected phase starts")); - } - else { - if(result && (ftpc->count1 == 0)) { - *completep = -1; /* go back to DOING please */ - /* this is a EPSV connect failing, try PASV instead */ - return ftp_epsv_disable(data, conn); - } - return result; - } - } - -#ifndef CURL_DISABLE_PROXY - result = Curl_proxy_connect(data, SECONDARYSOCKET); - if(result) - return result; - - if(CONNECT_SECONDARYSOCKET_PROXY_SSL()) - return result; - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy && - Curl_connect_ongoing(conn)) - return result; -#endif - - if(ftpc->state) { - /* already in a state so skip the initial commands. - They are only done to kickstart the do_more state */ - result = ftp_multi_statemach(data, &complete); - - *completep = (int)complete; - - /* if we got an error or if we don't wait for a data connection return - immediately */ - if(result || !ftpc->wait_data_conn) - return result; - - /* if we reach the end of the FTP state machine here, *complete will be - TRUE but so is ftpc->wait_data_conn, which says we need to wait for the - data connection and therefore we're not actually complete */ - *completep = 0; - } - - if(ftp->transfer <= PPTRANSFER_INFO) { - /* a transfer is about to take place, or if not a file name was given - so we'll do a SIZE on it later and then we need the right TYPE first */ - - if(ftpc->wait_data_conn == TRUE) { - bool serv_conned; - - result = ReceivedServerConnect(data, &serv_conned); - if(result) - return result; /* Failed to accept data connection */ - - if(serv_conned) { - /* It looks data connection is established */ - result = AcceptServerConnect(data); - ftpc->wait_data_conn = FALSE; - if(!result) - result = InitiateTransfer(data); - - if(result) - return result; - - *completep = 1; /* this state is now complete when the server has - connected back to us */ - } - } - else if(data->set.upload) { - result = ftp_nb_type(data, conn, data->state.prefer_ascii, - FTP_STOR_TYPE); - if(result) - return result; - - result = ftp_multi_statemach(data, &complete); - if(ftpc->wait_data_conn) - /* if we reach the end of the FTP state machine here, *complete will be - TRUE but so is ftpc->wait_data_conn, which says we need to wait for - the data connection and therefore we're not actually complete */ - *completep = 0; - else - *completep = (int)complete; - } - else { - /* download */ - ftp->downloadsize = -1; /* unknown as of yet */ - - result = Curl_range(data); - - if(result == CURLE_OK && data->req.maxdownload >= 0) { - /* Don't check for successful transfer */ - ftpc->dont_check = TRUE; - } - - if(result) - ; - else if(data->state.list_only || !ftpc->file) { - /* The specified path ends with a slash, and therefore we think this - is a directory that is requested, use LIST. But before that we - need to set ASCII transfer mode. */ - - /* But only if a body transfer was requested. */ - if(ftp->transfer == PPTRANSFER_BODY) { - result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE); - if(result) - return result; - } - /* otherwise just fall through */ - } - else { - result = ftp_nb_type(data, conn, data->state.prefer_ascii, - FTP_RETR_TYPE); - if(result) - return result; - } - - result = ftp_multi_statemach(data, &complete); - *completep = (int)complete; - } - return result; - } - - /* no data to transfer */ - Curl_setup_transfer(data, -1, -1, FALSE, -1); - - if(!ftpc->wait_data_conn) { - /* no waiting for the data connection so this is now complete */ - *completep = 1; - DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result)); - } - - return result; -} - - - -/*********************************************************************** - * - * ftp_perform() - * - * This is the actual DO function for FTP. Get a file/directory according to - * the options previously setup. - */ - -static -CURLcode ftp_perform(struct Curl_easy *data, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) -{ - /* this is FTP and no proxy */ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - - DEBUGF(infof(data, "DO phase starts")); - - if(data->set.opt_no_body) { - /* requested no body means no transfer... */ - struct FTP *ftp = data->req.p.ftp; - ftp->transfer = PPTRANSFER_INFO; - } - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - result = ftp_state_quote(data, TRUE, FTP_QUOTE); - if(result) - return result; - - /* run the state-machine */ - result = ftp_multi_statemach(data, dophase_done); - - *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; - - infof(data, "ftp_perform ends with SECONDARY: %d", *connected); - - if(*dophase_done) - DEBUGF(infof(data, "DO phase is complete1")); - - return result; -} - -static void wc_data_dtor(void *ptr) -{ - struct ftp_wc *ftpwc = ptr; - if(ftpwc && ftpwc->parser) - Curl_ftp_parselist_data_free(&ftpwc->parser); - free(ftpwc); -} - -static CURLcode init_wc_data(struct Curl_easy *data) -{ - char *last_slash; - struct FTP *ftp = data->req.p.ftp; - char *path = ftp->path; - struct WildcardData *wildcard = &(data->wildcard); - CURLcode result = CURLE_OK; - struct ftp_wc *ftpwc = NULL; - - last_slash = strrchr(ftp->path, '/'); - if(last_slash) { - last_slash++; - if(last_slash[0] == '\0') { - wildcard->state = CURLWC_CLEAN; - result = ftp_parse_url_path(data); - return result; - } - wildcard->pattern = strdup(last_slash); - if(!wildcard->pattern) - return CURLE_OUT_OF_MEMORY; - last_slash[0] = '\0'; /* cut file from path */ - } - else { /* there is only 'wildcard pattern' or nothing */ - if(path[0]) { - wildcard->pattern = strdup(path); - if(!wildcard->pattern) - return CURLE_OUT_OF_MEMORY; - path[0] = '\0'; - } - else { /* only list */ - wildcard->state = CURLWC_CLEAN; - result = ftp_parse_url_path(data); - return result; - } - } - - /* program continues only if URL is not ending with slash, allocate needed - resources for wildcard transfer */ - - /* allocate ftp protocol specific wildcard data */ - ftpwc = calloc(1, sizeof(struct ftp_wc)); - if(!ftpwc) { - result = CURLE_OUT_OF_MEMORY; - goto fail; - } - - /* INITIALIZE parselist structure */ - ftpwc->parser = Curl_ftp_parselist_data_alloc(); - if(!ftpwc->parser) { - result = CURLE_OUT_OF_MEMORY; - goto fail; - } - - wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */ - wildcard->dtor = wc_data_dtor; - - /* wildcard does not support NOCWD option (assert it?) */ - if(data->set.ftp_filemethod == FTPFILE_NOCWD) - data->set.ftp_filemethod = FTPFILE_MULTICWD; - - /* try to parse ftp url */ - result = ftp_parse_url_path(data); - if(result) { - goto fail; - } - - wildcard->path = strdup(ftp->path); - if(!wildcard->path) { - result = CURLE_OUT_OF_MEMORY; - goto fail; - } - - /* backup old write_function */ - ftpwc->backup.write_function = data->set.fwrite_func; - /* parsing write function */ - data->set.fwrite_func = Curl_ftp_parselist; - /* backup old file descriptor */ - ftpwc->backup.file_descriptor = data->set.out; - /* let the writefunc callback know the transfer */ - data->set.out = data; - - infof(data, "Wildcard - Parsing started"); - return CURLE_OK; - - fail: - if(ftpwc) { - Curl_ftp_parselist_data_free(&ftpwc->parser); - free(ftpwc); - } - Curl_safefree(wildcard->pattern); - wildcard->dtor = ZERO_NULL; - wildcard->protdata = NULL; - return result; -} - -static CURLcode wc_statemach(struct Curl_easy *data) -{ - struct WildcardData * const wildcard = &(data->wildcard); - struct connectdata *conn = data->conn; - CURLcode result = CURLE_OK; - - for(;;) { - switch(wildcard->state) { - case CURLWC_INIT: - result = init_wc_data(data); - if(wildcard->state == CURLWC_CLEAN) - /* only listing! */ - return result; - wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; - return result; - - case CURLWC_MATCHING: { - /* In this state is LIST response successfully parsed, so lets restore - previous WRITEFUNCTION callback and WRITEDATA pointer */ - struct ftp_wc *ftpwc = wildcard->protdata; - data->set.fwrite_func = ftpwc->backup.write_function; - data->set.out = ftpwc->backup.file_descriptor; - ftpwc->backup.write_function = ZERO_NULL; - ftpwc->backup.file_descriptor = NULL; - wildcard->state = CURLWC_DOWNLOADING; - - if(Curl_ftp_parselist_geterror(ftpwc->parser)) { - /* error found in LIST parsing */ - wildcard->state = CURLWC_CLEAN; - continue; - } - if(wildcard->filelist.size == 0) { - /* no corresponding file */ - wildcard->state = CURLWC_CLEAN; - return CURLE_REMOTE_FILE_NOT_FOUND; - } - continue; - } - - case CURLWC_DOWNLOADING: { - /* filelist has at least one file, lets get first one */ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; - struct FTP *ftp = data->req.p.ftp; - - char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); - if(!tmp_path) - return CURLE_OUT_OF_MEMORY; - - /* switch default ftp->path and tmp_path */ - free(ftp->pathalloc); - ftp->pathalloc = ftp->path = tmp_path; - - infof(data, "Wildcard - START of \"%s\"", finfo->filename); - if(data->set.chunk_bgn) { - long userresponse; - Curl_set_in_callback(data, true); - userresponse = data->set.chunk_bgn( - finfo, wildcard->customptr, (int)wildcard->filelist.size); - Curl_set_in_callback(data, false); - switch(userresponse) { - case CURL_CHUNK_BGN_FUNC_SKIP: - infof(data, "Wildcard - \"%s\" skipped by user", - finfo->filename); - wildcard->state = CURLWC_SKIP; - continue; - case CURL_CHUNK_BGN_FUNC_FAIL: - return CURLE_CHUNK_FAILED; - } - } - - if(finfo->filetype != CURLFILETYPE_FILE) { - wildcard->state = CURLWC_SKIP; - continue; - } - - if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) - ftpc->known_filesize = finfo->size; - - result = ftp_parse_url_path(data); - if(result) - return result; - - /* we don't need the Curl_fileinfo of first file anymore */ - Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); - - if(wildcard->filelist.size == 0) { /* remains only one file to down. */ - wildcard->state = CURLWC_CLEAN; - /* after that will be ftp_do called once again and no transfer - will be done because of CURLWC_CLEAN state */ - return CURLE_OK; - } - return result; - } - - case CURLWC_SKIP: { - if(data->set.chunk_end) { - Curl_set_in_callback(data, true); - data->set.chunk_end(data->wildcard.customptr); - Curl_set_in_callback(data, false); - } - Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); - wildcard->state = (wildcard->filelist.size == 0) ? - CURLWC_CLEAN : CURLWC_DOWNLOADING; - continue; - } - - case CURLWC_CLEAN: { - struct ftp_wc *ftpwc = wildcard->protdata; - result = CURLE_OK; - if(ftpwc) - result = Curl_ftp_parselist_geterror(ftpwc->parser); - - wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; - return result; - } - - case CURLWC_DONE: - case CURLWC_ERROR: - case CURLWC_CLEAR: - if(wildcard->dtor) - wildcard->dtor(wildcard->protdata); - return result; - } - } - /* UNREACHABLE */ -} - -/*********************************************************************** - * - * ftp_do() - * - * This function is registered as 'curl_do' function. It decodes the path - * parts etc as a wrapper to the actual DO function (ftp_perform). - * - * The input argument is already checked for validity. - */ -static CURLcode ftp_do(struct Curl_easy *data, bool *done) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - *done = FALSE; /* default to false */ - ftpc->wait_data_conn = FALSE; /* default to no such wait */ - - if(data->state.wildcardmatch) { - result = wc_statemach(data); - if(data->wildcard.state == CURLWC_SKIP || - data->wildcard.state == CURLWC_DONE) { - /* do not call ftp_regular_transfer */ - return CURLE_OK; - } - if(result) /* error, loop or skipping the file */ - return result; - } - else { /* no wildcard FSM needed */ - result = ftp_parse_url_path(data); - if(result) - return result; - } - - result = ftp_regular_transfer(data, done); - - return result; -} - -/*********************************************************************** - * - * ftp_quit() - * - * This should be called before calling sclose() on an ftp control connection - * (not data connections). We should then wait for the response from the - * server before returning. The calling code should then try to close the - * connection. - * - */ -static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if(conn->proto.ftpc.ctl_valid) { - result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT"); - if(result) { - failf(data, "Failure sending QUIT command: %s", - curl_easy_strerror(result)); - conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ - connclose(conn, "QUIT command failed"); /* mark for connection closure */ - state(data, FTP_STOP); - return result; - } - - state(data, FTP_QUIT); - - result = ftp_block_statemach(data, conn); - } - - return result; -} - -/*********************************************************************** - * - * ftp_disconnect() - * - * Disconnect from an FTP server. Cleanup protocol-specific per-connection - * resources. BLOCKING. - */ -static CURLcode ftp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead_connection) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct pingpong *pp = &ftpc->pp; - - /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. - - ftp_quit() will check the state of ftp->ctl_valid. If it's ok it - will try to send the QUIT command, otherwise it will just return. - */ - if(dead_connection) - ftpc->ctl_valid = FALSE; - - /* The FTP session may or may not have been allocated/setup at this point! */ - (void)ftp_quit(data, conn); /* ignore errors on the QUIT */ - - if(ftpc->entrypath) { - if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { - data->state.most_recent_ftp_entrypath = NULL; - } - Curl_safefree(ftpc->entrypath); - } - - freedirs(ftpc); - Curl_safefree(ftpc->prevpath); - Curl_safefree(ftpc->server_os); - Curl_pp_disconnect(pp); - Curl_sec_end(conn); - return CURLE_OK; -} - -/*********************************************************************** - * - * ftp_parse_url_path() - * - * Parse the URL path into separate path components. - * - */ -static -CURLcode ftp_parse_url_path(struct Curl_easy *data) -{ - /* the ftp struct is already inited in ftp_connect() */ - struct FTP *ftp = data->req.p.ftp; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - const char *slashPos = NULL; - const char *fileName = NULL; - CURLcode result = CURLE_OK; - char *rawPath = NULL; /* url-decoded "raw" path */ - size_t pathLen = 0; - - ftpc->ctl_valid = FALSE; - ftpc->cwdfail = FALSE; - - /* url-decode ftp path before further evaluation */ - result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL); - if(result) - return result; - - switch(data->set.ftp_filemethod) { - case FTPFILE_NOCWD: /* fastest, but less standard-compliant */ - - if((pathLen > 0) && (rawPath[pathLen - 1] != '/')) - fileName = rawPath; /* this is a full file path */ - /* - else: ftpc->file is not used anywhere other than for operations on - a file. In other words, never for directory operations. - So we can safely leave filename as NULL here and use it as a - argument in dir/file decisions. - */ - break; - - case FTPFILE_SINGLECWD: - slashPos = strrchr(rawPath, '/'); - if(slashPos) { - /* get path before last slash, except for / */ - size_t dirlen = slashPos - rawPath; - if(dirlen == 0) - dirlen++; - - ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) { - free(rawPath); - return CURLE_OUT_OF_MEMORY; - } - - ftpc->dirs[0] = calloc(1, dirlen + 1); - if(!ftpc->dirs[0]) { - free(rawPath); - return CURLE_OUT_OF_MEMORY; - } - - strncpy(ftpc->dirs[0], rawPath, dirlen); - ftpc->dirdepth = 1; /* we consider it to be a single dir */ - fileName = slashPos + 1; /* rest is file name */ - } - else - fileName = rawPath; /* file name only (or empty) */ - break; - - default: /* allow pretty much anything */ - case FTPFILE_MULTICWD: { - /* current position: begin of next path component */ - const char *curPos = rawPath; - - int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */ - const char *str = rawPath; - for(; *str != 0; ++str) - if (*str == '/') - ++dirAlloc; - - if(dirAlloc > 0) { - ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) { - free(rawPath); - return CURLE_OUT_OF_MEMORY; - } - - /* parse the URL path into separate path components */ - while((slashPos = strchr(curPos, '/')) != NULL) { - size_t compLen = slashPos - curPos; - - /* path starts with a slash: add that as a directory */ - if((compLen == 0) && (ftpc->dirdepth == 0)) - ++compLen; - - /* we skip empty path components, like "x//y" since the FTP command - CWD requires a parameter and a non-existent parameter a) doesn't - work on many servers and b) has no effect on the others. */ - if(compLen > 0) { - char *comp = calloc(1, compLen + 1); - if(!comp) { - free(rawPath); - return CURLE_OUT_OF_MEMORY; - } - strncpy(comp, curPos, compLen); - ftpc->dirs[ftpc->dirdepth++] = comp; - } - curPos = slashPos + 1; - } - } - DEBUGASSERT(ftpc->dirdepth <= dirAlloc); - fileName = curPos; /* the rest is the file name (or empty) */ - } - break; - } /* switch */ - - if(fileName && *fileName) - ftpc->file = strdup(fileName); - else - ftpc->file = NULL; /* instead of point to a zero byte, - we make it a NULL pointer */ - - if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) { - /* We need a file name when uploading. Return error! */ - failf(data, "Uploading to a URL without a file name!"); - free(rawPath); - return CURLE_URL_MALFORMAT; - } - - ftpc->cwddone = FALSE; /* default to not done */ - - if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) - ftpc->cwddone = TRUE; /* skip CWD for absolute paths */ - else { /* newly created FTP connections are already in entry path */ - const char *oldPath = conn->bits.reuse ? ftpc->prevpath : ""; - if(oldPath) { - size_t n = pathLen; - if(data->set.ftp_filemethod == FTPFILE_NOCWD) - n = 0; /* CWD to entry for relative paths */ - else - n -= ftpc->file?strlen(ftpc->file):0; - - if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) { - infof(data, "Request has same path as previous transfer"); - ftpc->cwddone = TRUE; - } - } - } - - free(rawPath); - return CURLE_OK; -} - -/* call this when the DO phase has completed */ -static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected) -{ - struct connectdata *conn = data->conn; - struct FTP *ftp = data->req.p.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(connected) { - int completed; - CURLcode result = ftp_do_more(data, &completed); - - if(result) { - close_secondarysocket(data, conn); - return result; - } - } - - if(ftp->transfer != PPTRANSFER_BODY) - /* no data to transfer */ - Curl_setup_transfer(data, -1, -1, FALSE, -1); - else if(!connected) - /* since we didn't connect now, we want do_more to get called */ - conn->bits.do_more = TRUE; - - ftpc->ctl_valid = TRUE; /* seems good */ - - return CURLE_OK; -} - -/* called from multi.c while DOing */ -static CURLcode ftp_doing(struct Curl_easy *data, - bool *dophase_done) -{ - CURLcode result = ftp_multi_statemach(data, dophase_done); - - if(result) - DEBUGF(infof(data, "DO phase failed")); - else if(*dophase_done) { - result = ftp_dophase_done(data, FALSE /* not connected */); - - DEBUGF(infof(data, "DO phase is complete2")); - } - return result; -} - -/*********************************************************************** - * - * ftp_regular_transfer() - * - * The input argument is already checked for validity. - * - * Performs all commands done before a regular transfer between a local and a - * remote host. - * - * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the - * ftp_done() function without finding any major problem. - */ -static -CURLcode ftp_regular_transfer(struct Curl_easy *data, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - bool connected = FALSE; - struct connectdata *conn = data->conn; - struct ftp_conn *ftpc = &conn->proto.ftpc; - data->req.size = -1; /* make sure this is unknown at this point */ - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - ftpc->ctl_valid = TRUE; /* starts good */ - - result = ftp_perform(data, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ - - if(!result) { - - if(!*dophase_done) - /* the DO phase has not completed yet */ - return CURLE_OK; - - result = ftp_dophase_done(data, connected); - - if(result) - return result; - } - else - freedirs(ftpc); - - return result; -} - -static CURLcode ftp_setup_connection(struct Curl_easy *data, - struct connectdata *conn) -{ - char *type; - struct FTP *ftp; - - data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1); - if(NULL == ftp) - return CURLE_OUT_OF_MEMORY; - - ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ - - /* FTP URLs support an extension like ";type=" that - * we'll try to get now! */ - type = strstr(ftp->path, ";type="); - - if(!type) - type = strstr(conn->host.rawalloc, ";type="); - - if(type) { - char command; - *type = 0; /* it was in the middle of the hostname */ - command = Curl_raw_toupper(type[6]); - - switch(command) { - case 'A': /* ASCII mode */ - data->state.prefer_ascii = TRUE; - break; - - case 'D': /* directory mode */ - data->state.list_only = TRUE; - break; - - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->state.prefer_ascii = FALSE; - break; - } - } - - /* get some initial data into the ftp struct */ - ftp->transfer = PPTRANSFER_BODY; - ftp->downloadsize = 0; - conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ - - return CURLE_OK; -} - -#endif /* CURL_DISABLE_FTP */ diff --git a/lib/ftp.rs b/lib/ftp.rs new file mode 100644 index 0000000000000000000000000000000000000000..145b971a8a6c3e934682a309e4acb79d2ca03265 --- /dev/null +++ b/lib/ftp.rs @@ -0,0 +1,7463 @@ +use ::libc; +use ::c2rust_bitfields; +extern "C" { + pub type _IO_wide_data; + pub type _IO_codecvt; + pub type _IO_marker; + pub type Curl_URL; + pub type thread_data; + pub type altsvcinfo; + pub type hsts; + pub type TELNET; + pub type smb_request; + pub type ldapreqinfo; + pub type contenc_writer; + pub type Curl_share; + pub type curl_pushheaders; + pub type ldapconninfo; + pub type tftp_state_data; + pub type ssl_backend_data; + pub type ftp_parselist_data; + fn bind(__fd: libc::c_int, __addr: *const sockaddr, __len: socklen_t) -> libc::c_int; + fn getsockname( + __fd: libc::c_int, + __addr: *mut sockaddr, + __len: *mut socklen_t, + ) -> libc::c_int; + fn listen(__fd: libc::c_int, __n: libc::c_int) -> libc::c_int; + fn accept( + __fd: libc::c_int, + __addr: *mut sockaddr, + __addr_len: *mut socklen_t, + ) -> libc::c_int; + fn sscanf(_: *const libc::c_char, _: *const libc::c_char, _: ...) -> libc::c_int; + fn Curl_isdigit(c: libc::c_int) -> libc::c_int; + fn curl_easy_strerror(_: CURLcode) -> *const libc::c_char; + fn strtol( + _: *const libc::c_char, + _: *mut *mut libc::c_char, + _: libc::c_int, + ) -> libc::c_long; + fn strtoul( + _: *const libc::c_char, + _: *mut *mut libc::c_char, + _: libc::c_int, + ) -> libc::c_ulong; + fn memcpy( + _: *mut libc::c_void, + _: *const libc::c_void, + _: libc::c_ulong, + ) -> *mut libc::c_void; + fn strcpy(_: *mut libc::c_char, _: *const libc::c_char) -> *mut libc::c_char; + fn strncpy( + _: *mut libc::c_char, + _: *const libc::c_char, + _: libc::c_ulong, + ) -> *mut libc::c_char; + fn strncmp( + _: *const libc::c_char, + _: *const libc::c_char, + _: libc::c_ulong, + ) -> libc::c_int; + fn strchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char; + fn strrchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char; + fn strstr(_: *const libc::c_char, _: *const libc::c_char) -> *mut libc::c_char; + fn strlen(_: *const libc::c_char) -> libc::c_ulong; + fn __errno_location() -> *mut libc::c_int; + fn inet_pton( + __af: libc::c_int, + __cp: *const libc::c_char, + __buf: *mut libc::c_void, + ) -> libc::c_int; + fn inet_ntop( + __af: libc::c_int, + __cp: *const libc::c_void, + __buf: *mut libc::c_char, + __len: socklen_t, + ) -> *const libc::c_char; + fn Curl_resolv( + data: *mut Curl_easy, + hostname: *const libc::c_char, + port: libc::c_int, + allowDOH: bool, + dnsentry: *mut *mut Curl_dns_entry, + ) -> resolve_t; + fn Curl_resolv_unlock(data: *mut Curl_easy, dns: *mut Curl_dns_entry); + fn Curl_now() -> curltime; + fn Curl_timediff(t1: curltime, t2: curltime) -> timediff_t; + fn Curl_llist_remove( + _: *mut Curl_llist, + _: *mut Curl_llist_element, + _: *mut libc::c_void, + ); + fn Curl_resolver_wait_resolv( + data: *mut Curl_easy, + dnsentry: *mut *mut Curl_dns_entry, + ) -> CURLcode; + fn Curl_printable_address( + ip: *const Curl_addrinfo, + buf: *mut libc::c_char, + bufsize: size_t, + ); + fn Curl_pp_statemach( + data: *mut Curl_easy, + pp: *mut pingpong, + block: bool, + disconnecting: bool, + ) -> CURLcode; + fn Curl_pp_init(data: *mut Curl_easy, pp: *mut pingpong); + fn Curl_pp_setup(pp: *mut pingpong); + fn Curl_pp_state_timeout( + data: *mut Curl_easy, + pp: *mut pingpong, + disconnecting: bool, + ) -> timediff_t; + fn Curl_pp_sendf( + data: *mut Curl_easy, + pp: *mut pingpong, + fmt: *const libc::c_char, + _: ... + ) -> CURLcode; + fn Curl_pp_readresp( + data: *mut Curl_easy, + sockfd: curl_socket_t, + pp: *mut pingpong, + code: *mut libc::c_int, + size: *mut size_t, + ) -> CURLcode; + fn Curl_pp_flushsend(data: *mut Curl_easy, pp: *mut pingpong) -> CURLcode; + fn Curl_pp_disconnect(pp: *mut pingpong) -> CURLcode; + fn Curl_pp_getsock( + data: *mut Curl_easy, + pp: *mut pingpong, + socks: *mut curl_socket_t, + ) -> libc::c_int; + fn Curl_infof(_: *mut Curl_easy, fmt: *const libc::c_char, _: ...); + fn Curl_failf(_: *mut Curl_easy, fmt: *const libc::c_char, _: ...); + fn Curl_client_write( + data: *mut Curl_easy, + type_0: libc::c_int, + ptr: *mut libc::c_char, + len: size_t, + ) -> CURLcode; + fn Curl_ipv6_scope(sa: *const sockaddr) -> libc::c_uint; + fn Curl_if2ip( + af: libc::c_int, + remote_scope: libc::c_uint, + local_scope_id: libc::c_uint, + interf: *const libc::c_char, + buf: *mut libc::c_char, + buf_size: libc::c_int, + ) -> if2ip_result_t; + fn Curl_pgrsSetDownloadSize(data: *mut Curl_easy, size: curl_off_t); + fn Curl_pgrsSetUploadSize(data: *mut Curl_easy, size: curl_off_t); + fn Curl_pgrsSetDownloadCounter(data: *mut Curl_easy, size: curl_off_t); + fn Curl_pgrsSetUploadCounter(data: *mut Curl_easy, size: curl_off_t); + fn Curl_pgrsUpdate(data: *mut Curl_easy) -> libc::c_int; + fn Curl_pgrsTime(data: *mut Curl_easy, timer: timerid) -> curltime; + fn Curl_setup_transfer( + data: *mut Curl_easy, + sockindex: libc::c_int, + size: curl_off_t, + getheader: bool, + writesockindex: libc::c_int, + ); + fn Curl_urldecode( + data: *mut Curl_easy, + string: *const libc::c_char, + length: size_t, + ostring: *mut *mut libc::c_char, + olen: *mut size_t, + ctrl: urlreject, + ) -> CURLcode; + fn Curl_ftp_parselist( + buffer: *mut libc::c_char, + size: size_t, + nmemb: size_t, + connptr: *mut libc::c_void, + ) -> size_t; + fn Curl_ftp_parselist_geterror(pl_data: *mut ftp_parselist_data) -> CURLcode; + fn Curl_ftp_parselist_data_alloc() -> *mut ftp_parselist_data; + fn Curl_ftp_parselist_data_free(pl_data: *mut *mut ftp_parselist_data); + fn Curl_range(data: *mut Curl_easy) -> CURLcode; + fn curlx_strtoofft( + str: *const libc::c_char, + endp: *mut *mut libc::c_char, + base: libc::c_int, + num: *mut curl_off_t, + ) -> CURLofft; + fn Curl_strcasecompare( + first: *const libc::c_char, + second: *const libc::c_char, + ) -> libc::c_int; + fn Curl_raw_toupper(in_0: libc::c_char) -> libc::c_char; + fn Curl_ssl_close( + data: *mut Curl_easy, + conn: *mut connectdata, + sockindex: libc::c_int, + ); + fn Curl_ssl_shutdown( + data: *mut Curl_easy, + conn: *mut connectdata, + sockindex: libc::c_int, + ) -> CURLcode; + fn Curl_ssl_connect( + data: *mut Curl_easy, + conn: *mut connectdata, + sockindex: libc::c_int, + ) -> CURLcode; + fn Curl_is_connected( + data: *mut Curl_easy, + conn: *mut connectdata, + sockindex: libc::c_int, + connected: *mut bool, + ) -> CURLcode; + fn Curl_connecthost( + data: *mut Curl_easy, + conn: *mut connectdata, + host: *const Curl_dns_entry, + ) -> CURLcode; + fn Curl_timeleft( + data: *mut Curl_easy, + nowp: *mut curltime, + duringconnect: bool, + ) -> timediff_t; + fn Curl_conninfo_remote( + data: *mut Curl_easy, + conn: *mut connectdata, + sockfd: curl_socket_t, + ); + fn Curl_closesocket( + data: *mut Curl_easy, + conn: *mut connectdata, + sock: curl_socket_t, + ) -> libc::c_int; + fn Curl_socket( + data: *mut Curl_easy, + ai: *const Curl_addrinfo, + addr: *mut Curl_sockaddr_ex, + sockfd: *mut curl_socket_t, + ) -> CURLcode; + fn Curl_conn_data_pending(conn: *mut connectdata, sockindex: libc::c_int) -> bool; + fn curlx_nonblock(sockfd: curl_socket_t, nonblock: libc::c_int) -> libc::c_int; + fn Curl_conncontrol(conn: *mut connectdata, closeit: libc::c_int); + fn Curl_strerror( + err: libc::c_int, + buf: *mut libc::c_char, + buflen: size_t, + ) -> *const libc::c_char; + fn Curl_socket_check( + readfd: curl_socket_t, + readfd2: curl_socket_t, + writefd: curl_socket_t, + timeout_ms: timediff_t, + ) -> libc::c_int; + static Curl_wkday: [*const libc::c_char; 7]; + static Curl_month: [*const libc::c_char; 12]; + fn Curl_gmtime(intime: time_t, store: *mut tm) -> CURLcode; + fn Curl_getdate_capped(p: *const libc::c_char) -> time_t; + fn Curl_expire(data: *mut Curl_easy, milli: timediff_t, _: expire_id); + fn Curl_set_in_callback(data: *mut Curl_easy, value: bool); + fn curlx_ultous(ulnum: libc::c_ulong) -> libc::c_ushort; + fn curlx_sltosi(slnum: libc::c_long) -> libc::c_int; + fn curlx_sotouz(sonum: curl_off_t) -> size_t; + fn Curl_proxyCONNECT( + data: *mut Curl_easy, + tunnelsocket: libc::c_int, + hostname: *const libc::c_char, + remote_port: libc::c_int, + ) -> CURLcode; + fn Curl_proxy_connect(data: *mut Curl_easy, sockindex: libc::c_int) -> CURLcode; + fn Curl_connect_ongoing(conn: *mut connectdata) -> bool; + fn Curl_SOCKS_getsock( + conn: *mut connectdata, + sock: *mut curl_socket_t, + sockindex: libc::c_int, + ) -> libc::c_int; + fn curl_msnprintf( + buffer: *mut libc::c_char, + maxlength: size_t, + format: *const libc::c_char, + _: ... + ) -> libc::c_int; + fn curl_maprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char; + static mut Curl_cmalloc: curl_malloc_callback; + static mut Curl_cfree: curl_free_callback; + static mut Curl_cstrdup: curl_strdup_callback; + static mut Curl_ccalloc: curl_calloc_callback; +} +pub type __uint8_t = libc::c_uchar; +pub type __uint16_t = libc::c_ushort; +pub type __uint32_t = libc::c_uint; +pub type __off_t = libc::c_long; +pub type __off64_t = libc::c_long; +pub type __pid_t = libc::c_int; +pub type __time_t = libc::c_long; +pub type __ssize_t = libc::c_long; +pub type __socklen_t = libc::c_uint; +pub type pid_t = __pid_t; +pub type ssize_t = __ssize_t; +pub type time_t = __time_t; +pub type size_t = libc::c_ulong; +pub type socklen_t = __socklen_t; +pub type sa_family_t = libc::c_ushort; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [libc::c_char; 14], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr_storage { + pub ss_family: sa_family_t, + pub __ss_padding: [libc::c_char; 118], + pub __ss_align: libc::c_ulong, +} +pub type curl_socklen_t = socklen_t; +pub type curl_off_t = libc::c_long; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct _IO_FILE { + pub _flags: libc::c_int, + pub _IO_read_ptr: *mut libc::c_char, + pub _IO_read_end: *mut libc::c_char, + pub _IO_read_base: *mut libc::c_char, + pub _IO_write_base: *mut libc::c_char, + pub _IO_write_ptr: *mut libc::c_char, + pub _IO_write_end: *mut libc::c_char, + pub _IO_buf_base: *mut libc::c_char, + pub _IO_buf_end: *mut libc::c_char, + pub _IO_save_base: *mut libc::c_char, + pub _IO_backup_base: *mut libc::c_char, + pub _IO_save_end: *mut libc::c_char, + pub _markers: *mut _IO_marker, + pub _chain: *mut _IO_FILE, + pub _fileno: libc::c_int, + pub _flags2: libc::c_int, + pub _old_offset: __off_t, + pub _cur_column: libc::c_ushort, + pub _vtable_offset: libc::c_schar, + pub _shortbuf: [libc::c_char; 1], + pub _lock: *mut libc::c_void, + pub _offset: __off64_t, + pub _codecvt: *mut _IO_codecvt, + pub _wide_data: *mut _IO_wide_data, + pub _freeres_list: *mut _IO_FILE, + pub _freeres_buf: *mut libc::c_void, + pub __pad5: size_t, + pub _mode: libc::c_int, + pub _unused2: [libc::c_char; 20], +} +pub type _IO_lock_t = (); +pub type FILE = _IO_FILE; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct tm { + pub tm_sec: libc::c_int, + pub tm_min: libc::c_int, + pub tm_hour: libc::c_int, + pub tm_mday: libc::c_int, + pub tm_mon: libc::c_int, + pub tm_year: libc::c_int, + pub tm_wday: libc::c_int, + pub tm_yday: libc::c_int, + pub tm_isdst: libc::c_int, + pub tm_gmtoff: libc::c_long, + pub tm_zone: *const libc::c_char, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_easy { + pub magic: libc::c_uint, + pub next: *mut Curl_easy, + pub prev: *mut Curl_easy, + pub conn: *mut connectdata, + pub connect_queue: Curl_llist_element, + pub conn_queue: Curl_llist_element, + pub mstate: CURLMstate, + pub result: CURLcode, + pub msg: Curl_message, + pub sockets: [curl_socket_t; 5], + pub actions: [libc::c_uchar; 5], + pub numsocks: libc::c_int, + pub dns: Names, + pub multi: *mut Curl_multi, + pub multi_easy: *mut Curl_multi, + pub share: *mut Curl_share, + pub req: SingleRequest, + pub set: UserDefined, + pub cookies: *mut CookieInfo, + pub hsts: *mut hsts, + pub asi: *mut altsvcinfo, + pub progress: Progress, + pub state: UrlState, + pub wildcard: WildcardData, + pub info: PureInfo, + pub tsi: curl_tlssessioninfo, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_tlssessioninfo { + pub backend: curl_sslbackend, + pub internals: *mut libc::c_void, +} +pub type curl_sslbackend = libc::c_uint; +pub const CURLSSLBACKEND_RUSTLS: curl_sslbackend = 14; +pub const CURLSSLBACKEND_BEARSSL: curl_sslbackend = 13; +pub const CURLSSLBACKEND_MESALINK: curl_sslbackend = 12; +pub const CURLSSLBACKEND_MBEDTLS: curl_sslbackend = 11; +pub const CURLSSLBACKEND_AXTLS: curl_sslbackend = 10; +pub const CURLSSLBACKEND_SECURETRANSPORT: curl_sslbackend = 9; +pub const CURLSSLBACKEND_SCHANNEL: curl_sslbackend = 8; +pub const CURLSSLBACKEND_WOLFSSL: curl_sslbackend = 7; +pub const CURLSSLBACKEND_POLARSSL: curl_sslbackend = 6; +pub const CURLSSLBACKEND_GSKIT: curl_sslbackend = 5; +pub const CURLSSLBACKEND_OBSOLETE4: curl_sslbackend = 4; +pub const CURLSSLBACKEND_NSS: curl_sslbackend = 3; +pub const CURLSSLBACKEND_GNUTLS: curl_sslbackend = 2; +pub const CURLSSLBACKEND_OPENSSL: curl_sslbackend = 1; +pub const CURLSSLBACKEND_NONE: curl_sslbackend = 0; +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct PureInfo { + pub httpcode: libc::c_int, + pub httpproxycode: libc::c_int, + pub httpversion: libc::c_int, + pub filetime: time_t, + pub header_size: curl_off_t, + pub request_size: curl_off_t, + pub proxyauthavail: libc::c_ulong, + pub httpauthavail: libc::c_ulong, + pub numconnects: libc::c_long, + pub contenttype: *mut libc::c_char, + pub wouldredirect: *mut libc::c_char, + pub retry_after: curl_off_t, + pub conn_primary_ip: [libc::c_char; 46], + pub conn_primary_port: libc::c_int, + pub conn_local_ip: [libc::c_char; 46], + pub conn_local_port: libc::c_int, + pub conn_scheme: *const libc::c_char, + pub conn_protocol: libc::c_uint, + pub certs: curl_certinfo, + pub pxcode: CURLproxycode, + #[bitfield(name = "timecond", ty = "bit", bits = "0..=0")] + pub timecond: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 3], +} +pub type bit = libc::c_uint; +pub type CURLproxycode = libc::c_uint; +pub const CURLPX_LAST: CURLproxycode = 34; +pub const CURLPX_USER_REJECTED: CURLproxycode = 33; +pub const CURLPX_UNKNOWN_MODE: CURLproxycode = 32; +pub const CURLPX_UNKNOWN_FAIL: CURLproxycode = 31; +pub const CURLPX_SEND_REQUEST: CURLproxycode = 30; +pub const CURLPX_SEND_CONNECT: CURLproxycode = 29; +pub const CURLPX_SEND_AUTH: CURLproxycode = 28; +pub const CURLPX_RESOLVE_HOST: CURLproxycode = 27; +pub const CURLPX_REQUEST_FAILED: CURLproxycode = 26; +pub const CURLPX_REPLY_UNASSIGNED: CURLproxycode = 25; +pub const CURLPX_REPLY_TTL_EXPIRED: CURLproxycode = 24; +pub const CURLPX_REPLY_NOT_ALLOWED: CURLproxycode = 23; +pub const CURLPX_REPLY_NETWORK_UNREACHABLE: CURLproxycode = 22; +pub const CURLPX_REPLY_HOST_UNREACHABLE: CURLproxycode = 21; +pub const CURLPX_REPLY_GENERAL_SERVER_FAILURE: CURLproxycode = 20; +pub const CURLPX_REPLY_CONNECTION_REFUSED: CURLproxycode = 19; +pub const CURLPX_REPLY_COMMAND_NOT_SUPPORTED: CURLproxycode = 18; +pub const CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: CURLproxycode = 17; +pub const CURLPX_RECV_REQACK: CURLproxycode = 16; +pub const CURLPX_RECV_CONNECT: CURLproxycode = 15; +pub const CURLPX_RECV_AUTH: CURLproxycode = 14; +pub const CURLPX_RECV_ADDRESS: CURLproxycode = 13; +pub const CURLPX_NO_AUTH: CURLproxycode = 12; +pub const CURLPX_LONG_USER: CURLproxycode = 11; +pub const CURLPX_LONG_PASSWD: CURLproxycode = 10; +pub const CURLPX_LONG_HOSTNAME: CURLproxycode = 9; +pub const CURLPX_IDENTD_DIFFER: CURLproxycode = 8; +pub const CURLPX_IDENTD: CURLproxycode = 7; +pub const CURLPX_GSSAPI_PROTECTION: CURLproxycode = 6; +pub const CURLPX_GSSAPI_PERMSG: CURLproxycode = 5; +pub const CURLPX_GSSAPI: CURLproxycode = 4; +pub const CURLPX_CLOSED: CURLproxycode = 3; +pub const CURLPX_BAD_VERSION: CURLproxycode = 2; +pub const CURLPX_BAD_ADDRESS_TYPE: CURLproxycode = 1; +pub const CURLPX_OK: CURLproxycode = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_certinfo { + pub num_of_certs: libc::c_int, + pub certinfo: *mut *mut curl_slist, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_slist { + pub data: *mut libc::c_char, + pub next: *mut curl_slist, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct WildcardData { + pub state: wildcard_states, + pub path: *mut libc::c_char, + pub pattern: *mut libc::c_char, + pub filelist: Curl_llist, + pub protdata: *mut libc::c_void, + pub dtor: wildcard_dtor, + pub customptr: *mut libc::c_void, +} +pub type wildcard_dtor = Option:: ()>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_llist { + pub head: *mut Curl_llist_element, + pub tail: *mut Curl_llist_element, + pub dtor: Curl_llist_dtor, + pub size: size_t, +} +pub type Curl_llist_dtor = Option::< + unsafe extern "C" fn(*mut libc::c_void, *mut libc::c_void) -> (), +>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_llist_element { + pub ptr: *mut libc::c_void, + pub prev: *mut Curl_llist_element, + pub next: *mut Curl_llist_element, +} +pub type wildcard_states = libc::c_uint; +pub const CURLWC_DONE: wildcard_states = 7; +pub const CURLWC_ERROR: wildcard_states = 6; +pub const CURLWC_SKIP: wildcard_states = 5; +pub const CURLWC_CLEAN: wildcard_states = 4; +pub const CURLWC_DOWNLOADING: wildcard_states = 3; +pub const CURLWC_MATCHING: wildcard_states = 2; +pub const CURLWC_INIT: wildcard_states = 1; +pub const CURLWC_CLEAR: wildcard_states = 0; +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct UrlState { + pub conn_cache: *mut conncache, + pub keeps_speed: curltime, + pub lastconnect_id: libc::c_long, + pub headerb: dynbuf, + pub buffer: *mut libc::c_char, + pub ulbuf: *mut libc::c_char, + pub current_speed: curl_off_t, + pub first_host: *mut libc::c_char, + pub retrycount: libc::c_int, + pub first_remote_port: libc::c_int, + pub session: *mut Curl_ssl_session, + pub sessionage: libc::c_long, + pub tempwrite: [tempbuf; 3], + pub tempcount: libc::c_uint, + pub os_errno: libc::c_int, + pub scratch: *mut libc::c_char, + pub followlocation: libc::c_long, + pub prev_signal: Option:: ()>, + pub digest: digestdata, + pub proxydigest: digestdata, + pub authhost: auth, + pub authproxy: auth, + pub async_0: Curl_async, + pub engine: *mut libc::c_void, + pub expiretime: curltime, + pub timenode: Curl_tree, + pub timeoutlist: Curl_llist, + pub expires: [time_node; 13], + pub most_recent_ftp_entrypath: *mut libc::c_char, + pub httpwant: libc::c_uchar, + pub httpversion: libc::c_uchar, + #[bitfield(name = "prev_block_had_trailing_cr", ty = "bit", bits = "0..=0")] + pub prev_block_had_trailing_cr: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 5], + pub crlf_conversions: curl_off_t, + pub range: *mut libc::c_char, + pub resume_from: curl_off_t, + pub rtsp_next_client_CSeq: libc::c_long, + pub rtsp_next_server_CSeq: libc::c_long, + pub rtsp_CSeq_recv: libc::c_long, + pub infilesize: curl_off_t, + pub drain: size_t, + pub fread_func: curl_read_callback, + pub in_0: *mut libc::c_void, + pub stream_depends_on: *mut Curl_easy, + pub stream_weight: libc::c_int, + pub uh: *mut CURLU, + pub up: urlpieces, + pub httpreq: Curl_HttpReq, + pub url: *mut libc::c_char, + pub referer: *mut libc::c_char, + pub cookielist: *mut curl_slist, + pub resolve: *mut curl_slist, + pub trailers_bytes_sent: size_t, + pub trailers_buf: dynbuf, + pub trailers_state: trailers_state, + pub aptr: dynamically_allocated_data, + #[bitfield(name = "multi_owned_by_easy", ty = "bit", bits = "0..=0")] + #[bitfield(name = "this_is_a_follow", ty = "bit", bits = "1..=1")] + #[bitfield(name = "refused_stream", ty = "bit", bits = "2..=2")] + #[bitfield(name = "errorbuf", ty = "bit", bits = "3..=3")] + #[bitfield(name = "allow_port", ty = "bit", bits = "4..=4")] + #[bitfield(name = "authproblem", ty = "bit", bits = "5..=5")] + #[bitfield(name = "ftp_trying_alternative", ty = "bit", bits = "6..=6")] + #[bitfield(name = "wildcardmatch", ty = "bit", bits = "7..=7")] + #[bitfield(name = "expect100header", ty = "bit", bits = "8..=8")] + #[bitfield(name = "disableexpect", ty = "bit", bits = "9..=9")] + #[bitfield(name = "use_range", ty = "bit", bits = "10..=10")] + #[bitfield(name = "rangestringalloc", ty = "bit", bits = "11..=11")] + #[bitfield(name = "done", ty = "bit", bits = "12..=12")] + #[bitfield(name = "stream_depends_e", ty = "bit", bits = "13..=13")] + #[bitfield(name = "previouslypending", ty = "bit", bits = "14..=14")] + #[bitfield(name = "cookie_engine", ty = "bit", bits = "15..=15")] + #[bitfield(name = "prefer_ascii", ty = "bit", bits = "16..=16")] + #[bitfield(name = "list_only", ty = "bit", bits = "17..=17")] + #[bitfield(name = "url_alloc", ty = "bit", bits = "18..=18")] + #[bitfield(name = "referer_alloc", ty = "bit", bits = "19..=19")] + #[bitfield(name = "wildcard_resolve", ty = "bit", bits = "20..=20")] + pub multi_owned_by_easy_this_is_a_follow_refused_stream_errorbuf_allow_port_authproblem_ftp_trying_alternative_wildcardmatch_expect100header_disableexpect_use_range_rangestringalloc_done_stream_depends_e_previouslypending_cookie_engine_prefer_ascii_list_only_url_alloc_referer_alloc_wildcard_resolve: [u8; 3], + #[bitfield(padding)] + pub c2rust_padding_0: [u8; 5], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct dynamically_allocated_data { + pub proxyuserpwd: *mut libc::c_char, + pub uagent: *mut libc::c_char, + pub accept_encoding: *mut libc::c_char, + pub userpwd: *mut libc::c_char, + pub rangeline: *mut libc::c_char, + pub ref_0: *mut libc::c_char, + pub host: *mut libc::c_char, + pub cookiehost: *mut libc::c_char, + pub rtsp_transport: *mut libc::c_char, + pub te: *mut libc::c_char, + pub user: *mut libc::c_char, + pub passwd: *mut libc::c_char, + pub proxyuser: *mut libc::c_char, + pub proxypasswd: *mut libc::c_char, +} +pub type trailers_state = libc::c_uint; +pub const TRAILERS_DONE: trailers_state = 3; +pub const TRAILERS_SENDING: trailers_state = 2; +pub const TRAILERS_INITIALIZED: trailers_state = 1; +pub const TRAILERS_NONE: trailers_state = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct dynbuf { + pub bufr: *mut libc::c_char, + pub leng: size_t, + pub allc: size_t, + pub toobig: size_t, +} +pub type Curl_HttpReq = libc::c_uint; +pub const HTTPREQ_HEAD: Curl_HttpReq = 5; +pub const HTTPREQ_PUT: Curl_HttpReq = 4; +pub const HTTPREQ_POST_MIME: Curl_HttpReq = 3; +pub const HTTPREQ_POST_FORM: Curl_HttpReq = 2; +pub const HTTPREQ_POST: Curl_HttpReq = 1; +pub const HTTPREQ_GET: Curl_HttpReq = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct urlpieces { + pub scheme: *mut libc::c_char, + pub hostname: *mut libc::c_char, + pub port: *mut libc::c_char, + pub user: *mut libc::c_char, + pub password: *mut libc::c_char, + pub options: *mut libc::c_char, + pub path: *mut libc::c_char, + pub query: *mut libc::c_char, +} +pub type CURLU = Curl_URL; +pub type curl_read_callback = Option::< + unsafe extern "C" fn(*mut libc::c_char, size_t, size_t, *mut libc::c_void) -> size_t, +>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct time_node { + pub list: Curl_llist_element, + pub time: curltime, + pub eid: expire_id, +} +pub type expire_id = libc::c_uint; +pub const EXPIRE_LAST: expire_id = 13; +pub const EXPIRE_QUIC: expire_id = 12; +pub const EXPIRE_TOOFAST: expire_id = 11; +pub const EXPIRE_TIMEOUT: expire_id = 10; +pub const EXPIRE_SPEEDCHECK: expire_id = 9; +pub const EXPIRE_RUN_NOW: expire_id = 8; +pub const EXPIRE_MULTI_PENDING: expire_id = 7; +pub const EXPIRE_HAPPY_EYEBALLS: expire_id = 6; +pub const EXPIRE_HAPPY_EYEBALLS_DNS: expire_id = 5; +pub const EXPIRE_DNS_PER_NAME2: expire_id = 4; +pub const EXPIRE_DNS_PER_NAME: expire_id = 3; +pub const EXPIRE_CONNECTTIMEOUT: expire_id = 2; +pub const EXPIRE_ASYNC_NAME: expire_id = 1; +pub const EXPIRE_100_TIMEOUT: expire_id = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curltime { + pub tv_sec: time_t, + pub tv_usec: libc::c_int, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_tree { + pub smaller: *mut Curl_tree, + pub larger: *mut Curl_tree, + pub samen: *mut Curl_tree, + pub samep: *mut Curl_tree, + pub key: curltime, + pub payload: *mut libc::c_void, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct Curl_async { + pub hostname: *mut libc::c_char, + pub dns: *mut Curl_dns_entry, + pub tdata: *mut thread_data, + pub resolver: *mut libc::c_void, + pub port: libc::c_int, + pub status: libc::c_int, + #[bitfield(name = "done", ty = "bit", bits = "0..=0")] + pub done: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 7], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_dns_entry { + pub addr: *mut Curl_addrinfo, + pub timestamp: time_t, + pub inuse: libc::c_long, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_addrinfo { + pub ai_flags: libc::c_int, + pub ai_family: libc::c_int, + pub ai_socktype: libc::c_int, + pub ai_protocol: libc::c_int, + pub ai_addrlen: curl_socklen_t, + pub ai_canonname: *mut libc::c_char, + pub ai_addr: *mut sockaddr, + pub ai_next: *mut Curl_addrinfo, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct auth { + pub want: libc::c_ulong, + pub picked: libc::c_ulong, + pub avail: libc::c_ulong, + #[bitfield(name = "done", ty = "bit", bits = "0..=0")] + #[bitfield(name = "multipass", ty = "bit", bits = "1..=1")] + #[bitfield(name = "iestyle", ty = "bit", bits = "2..=2")] + pub done_multipass_iestyle: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 7], +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct digestdata { + pub nonce: *mut libc::c_char, + pub cnonce: *mut libc::c_char, + pub realm: *mut libc::c_char, + pub algo: libc::c_int, + pub opaque: *mut libc::c_char, + pub qop: *mut libc::c_char, + pub algorithm: *mut libc::c_char, + pub nc: libc::c_int, + #[bitfield(name = "stale", ty = "bit", bits = "0..=0")] + #[bitfield(name = "userhash", ty = "bit", bits = "1..=1")] + pub stale_userhash: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 3], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct tempbuf { + pub b: dynbuf, + pub type_0: libc::c_int, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_ssl_session { + pub name: *mut libc::c_char, + pub conn_to_host: *mut libc::c_char, + pub scheme: *const libc::c_char, + pub sessionid: *mut libc::c_void, + pub idsize: size_t, + pub age: libc::c_long, + pub remote_port: libc::c_int, + pub conn_to_port: libc::c_int, + pub ssl_config: ssl_primary_config, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct ssl_primary_config { + pub version: libc::c_long, + pub version_max: libc::c_long, + pub CApath: *mut libc::c_char, + pub CAfile: *mut libc::c_char, + pub issuercert: *mut libc::c_char, + pub clientcert: *mut libc::c_char, + pub random_file: *mut libc::c_char, + pub egdsocket: *mut libc::c_char, + pub cipher_list: *mut libc::c_char, + pub cipher_list13: *mut libc::c_char, + pub pinned_key: *mut libc::c_char, + pub cert_blob: *mut curl_blob, + pub ca_info_blob: *mut curl_blob, + pub issuercert_blob: *mut curl_blob, + pub curves: *mut libc::c_char, + #[bitfield(name = "verifypeer", ty = "bit", bits = "0..=0")] + #[bitfield(name = "verifyhost", ty = "bit", bits = "1..=1")] + #[bitfield(name = "verifystatus", ty = "bit", bits = "2..=2")] + #[bitfield(name = "sessionid", ty = "bit", bits = "3..=3")] + pub verifypeer_verifyhost_verifystatus_sessionid: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 7], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_blob { + pub data: *mut libc::c_void, + pub len: size_t, + pub flags: libc::c_uint, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct conncache { + pub hash: Curl_hash, + pub num_conn: size_t, + pub next_connection_id: libc::c_long, + pub last_cleanup: curltime, + pub closure_handle: *mut Curl_easy, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_hash { + pub table: *mut Curl_llist, + pub hash_func: hash_function, + pub comp_func: comp_function, + pub dtor: Curl_hash_dtor, + pub slots: libc::c_int, + pub size: size_t, +} +pub type Curl_hash_dtor = Option:: ()>; +pub type comp_function = Option::< + unsafe extern "C" fn(*mut libc::c_void, size_t, *mut libc::c_void, size_t) -> size_t, +>; +pub type hash_function = Option::< + unsafe extern "C" fn(*mut libc::c_void, size_t, size_t) -> size_t, +>; +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct Progress { + pub lastshow: time_t, + pub size_dl: curl_off_t, + pub size_ul: curl_off_t, + pub downloaded: curl_off_t, + pub uploaded: curl_off_t, + pub current_speed: curl_off_t, + pub width: libc::c_int, + pub flags: libc::c_int, + pub timespent: timediff_t, + pub dlspeed: curl_off_t, + pub ulspeed: curl_off_t, + pub t_nslookup: timediff_t, + pub t_connect: timediff_t, + pub t_appconnect: timediff_t, + pub t_pretransfer: timediff_t, + pub t_starttransfer: timediff_t, + pub t_redirect: timediff_t, + pub start: curltime, + pub t_startsingle: curltime, + pub t_startop: curltime, + pub t_acceptdata: curltime, + pub ul_limit_start: curltime, + pub ul_limit_size: curl_off_t, + pub dl_limit_start: curltime, + pub dl_limit_size: curl_off_t, + pub speeder: [curl_off_t; 6], + pub speeder_time: [curltime; 6], + pub speeder_c: libc::c_int, + #[bitfield(name = "callback", ty = "bit", bits = "0..=0")] + #[bitfield(name = "is_t_startransfer_set", ty = "bit", bits = "1..=1")] + pub callback_is_t_startransfer_set: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 3], +} +pub type timediff_t = curl_off_t; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct CookieInfo { + pub cookies: [*mut Cookie; 256], + pub filename: *mut libc::c_char, + pub numcookies: libc::c_long, + pub running: bool, + pub newsession: bool, + pub lastct: libc::c_int, + pub next_expiration: curl_off_t, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Cookie { + pub next: *mut Cookie, + pub name: *mut libc::c_char, + pub value: *mut libc::c_char, + pub path: *mut libc::c_char, + pub spath: *mut libc::c_char, + pub domain: *mut libc::c_char, + pub expires: curl_off_t, + pub expirestr: *mut libc::c_char, + pub version: *mut libc::c_char, + pub maxage: *mut libc::c_char, + pub tailmatch: bool, + pub secure: bool, + pub livecookie: bool, + pub httponly: bool, + pub creationtime: libc::c_int, + pub prefix: libc::c_uchar, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct UserDefined { + pub err: *mut FILE, + pub debugdata: *mut libc::c_void, + pub errorbuffer: *mut libc::c_char, + pub proxyport: libc::c_long, + pub out: *mut libc::c_void, + pub in_set: *mut libc::c_void, + pub writeheader: *mut libc::c_void, + pub rtp_out: *mut libc::c_void, + pub use_port: libc::c_long, + pub httpauth: libc::c_ulong, + pub proxyauth: libc::c_ulong, + pub socks5auth: libc::c_ulong, + pub maxredirs: libc::c_long, + pub keep_post: libc::c_int, + pub postfields: *mut libc::c_void, + pub seek_func: curl_seek_callback, + pub postfieldsize: curl_off_t, + pub localport: libc::c_ushort, + pub localportrange: libc::c_int, + pub fwrite_func: curl_write_callback, + pub fwrite_header: curl_write_callback, + pub fwrite_rtp: curl_write_callback, + pub fread_func_set: curl_read_callback, + pub fprogress: curl_progress_callback, + pub fxferinfo: curl_xferinfo_callback, + pub fdebug: curl_debug_callback, + pub ioctl_func: curl_ioctl_callback, + pub fsockopt: curl_sockopt_callback, + pub sockopt_client: *mut libc::c_void, + pub fopensocket: curl_opensocket_callback, + pub opensocket_client: *mut libc::c_void, + pub fclosesocket: curl_closesocket_callback, + pub closesocket_client: *mut libc::c_void, + pub seek_client: *mut libc::c_void, + pub convfromnetwork: curl_conv_callback, + pub convtonetwork: curl_conv_callback, + pub convfromutf8: curl_conv_callback, + pub hsts_read: curl_hstsread_callback, + pub hsts_read_userp: *mut libc::c_void, + pub hsts_write: curl_hstswrite_callback, + pub hsts_write_userp: *mut libc::c_void, + pub progress_client: *mut libc::c_void, + pub ioctl_client: *mut libc::c_void, + pub timeout: libc::c_long, + pub connecttimeout: libc::c_long, + pub accepttimeout: libc::c_long, + pub happy_eyeballs_timeout: libc::c_long, + pub server_response_timeout: libc::c_long, + pub maxage_conn: libc::c_long, + pub tftp_blksize: libc::c_long, + pub filesize: curl_off_t, + pub low_speed_limit: libc::c_long, + pub low_speed_time: libc::c_long, + pub max_send_speed: curl_off_t, + pub max_recv_speed: curl_off_t, + pub set_resume_from: curl_off_t, + pub headers: *mut curl_slist, + pub proxyheaders: *mut curl_slist, + pub httppost: *mut curl_httppost, + pub mimepost: curl_mimepart, + pub quote: *mut curl_slist, + pub postquote: *mut curl_slist, + pub prequote: *mut curl_slist, + pub source_quote: *mut curl_slist, + pub source_prequote: *mut curl_slist, + pub source_postquote: *mut curl_slist, + pub telnet_options: *mut curl_slist, + pub resolve: *mut curl_slist, + pub connect_to: *mut curl_slist, + pub timecondition: curl_TimeCond, + pub proxytype: curl_proxytype, + pub timevalue: time_t, + pub method: Curl_HttpReq, + pub httpwant: libc::c_uchar, + pub ssl: ssl_config_data, + pub proxy_ssl: ssl_config_data, + pub general_ssl: ssl_general_config, + pub dns_cache_timeout: libc::c_long, + pub buffer_size: libc::c_long, + pub upload_buffer_size: libc::c_uint, + pub private_data: *mut libc::c_void, + pub http200aliases: *mut curl_slist, + pub ipver: libc::c_uchar, + pub max_filesize: curl_off_t, + pub ftp_filemethod: curl_ftpfile, + pub ftpsslauth: curl_ftpauth, + pub ftp_ccc: curl_ftpccc, + pub ftp_create_missing_dirs: libc::c_int, + pub ssh_keyfunc: curl_sshkeycallback, + pub ssh_keyfunc_userp: *mut libc::c_void, + pub use_netrc: CURL_NETRC_OPTION, + pub use_ssl: curl_usessl, + pub new_file_perms: libc::c_long, + pub new_directory_perms: libc::c_long, + pub ssh_auth_types: libc::c_long, + pub str_0: [*mut libc::c_char; 80], + pub blobs: [*mut curl_blob; 8], + pub scope_id: libc::c_uint, + pub allowed_protocols: libc::c_long, + pub redir_protocols: libc::c_long, + pub mail_rcpt: *mut curl_slist, + pub rtspreq: Curl_RtspReq, + pub rtspversion: libc::c_long, + pub chunk_bgn: curl_chunk_bgn_callback, + pub chunk_end: curl_chunk_end_callback, + pub fnmatch: curl_fnmatch_callback, + pub fnmatch_data: *mut libc::c_void, + pub gssapi_delegation: libc::c_long, + pub tcp_keepidle: libc::c_long, + pub tcp_keepintvl: libc::c_long, + pub maxconnects: size_t, + pub expect_100_timeout: libc::c_long, + pub stream_depends_on: *mut Curl_easy, + pub stream_weight: libc::c_int, + pub stream_dependents: *mut Curl_http2_dep, + pub resolver_start: curl_resolver_start_callback, + pub resolver_start_client: *mut libc::c_void, + pub upkeep_interval_ms: libc::c_long, + pub fmultidone: multidone_func, + pub dohfor: *mut Curl_easy, + pub uh: *mut CURLU, + pub trailer_data: *mut libc::c_void, + pub trailer_callback: curl_trailer_callback, + #[bitfield(name = "is_fread_set", ty = "bit", bits = "0..=0")] + #[bitfield(name = "is_fwrite_set", ty = "bit", bits = "1..=1")] + #[bitfield(name = "free_referer", ty = "bit", bits = "2..=2")] + #[bitfield(name = "tftp_no_options", ty = "bit", bits = "3..=3")] + #[bitfield(name = "sep_headers", ty = "bit", bits = "4..=4")] + #[bitfield(name = "cookiesession", ty = "bit", bits = "5..=5")] + #[bitfield(name = "crlf", ty = "bit", bits = "6..=6")] + #[bitfield(name = "strip_path_slash", ty = "bit", bits = "7..=7")] + #[bitfield(name = "ssh_compression", ty = "bit", bits = "8..=8")] + #[bitfield(name = "get_filetime", ty = "bit", bits = "9..=9")] + #[bitfield(name = "tunnel_thru_httpproxy", ty = "bit", bits = "10..=10")] + #[bitfield(name = "prefer_ascii", ty = "bit", bits = "11..=11")] + #[bitfield(name = "remote_append", ty = "bit", bits = "12..=12")] + #[bitfield(name = "list_only", ty = "bit", bits = "13..=13")] + #[bitfield(name = "ftp_use_port", ty = "bit", bits = "14..=14")] + #[bitfield(name = "ftp_use_epsv", ty = "bit", bits = "15..=15")] + #[bitfield(name = "ftp_use_eprt", ty = "bit", bits = "16..=16")] + #[bitfield(name = "ftp_use_pret", ty = "bit", bits = "17..=17")] + #[bitfield(name = "ftp_skip_ip", ty = "bit", bits = "18..=18")] + #[bitfield(name = "hide_progress", ty = "bit", bits = "19..=19")] + #[bitfield(name = "http_fail_on_error", ty = "bit", bits = "20..=20")] + #[bitfield(name = "http_keep_sending_on_error", ty = "bit", bits = "21..=21")] + #[bitfield(name = "http_follow_location", ty = "bit", bits = "22..=22")] + #[bitfield(name = "http_transfer_encoding", ty = "bit", bits = "23..=23")] + #[bitfield(name = "allow_auth_to_other_hosts", ty = "bit", bits = "24..=24")] + #[bitfield(name = "include_header", ty = "bit", bits = "25..=25")] + #[bitfield(name = "http_set_referer", ty = "bit", bits = "26..=26")] + #[bitfield(name = "http_auto_referer", ty = "bit", bits = "27..=27")] + #[bitfield(name = "opt_no_body", ty = "bit", bits = "28..=28")] + #[bitfield(name = "upload", ty = "bit", bits = "29..=29")] + #[bitfield(name = "verbose", ty = "bit", bits = "30..=30")] + #[bitfield(name = "krb", ty = "bit", bits = "31..=31")] + #[bitfield(name = "reuse_forbid", ty = "bit", bits = "32..=32")] + #[bitfield(name = "reuse_fresh", ty = "bit", bits = "33..=33")] + #[bitfield(name = "no_signal", ty = "bit", bits = "34..=34")] + #[bitfield(name = "tcp_nodelay", ty = "bit", bits = "35..=35")] + #[bitfield(name = "ignorecl", ty = "bit", bits = "36..=36")] + #[bitfield(name = "connect_only", ty = "bit", bits = "37..=37")] + #[bitfield(name = "http_te_skip", ty = "bit", bits = "38..=38")] + #[bitfield(name = "http_ce_skip", ty = "bit", bits = "39..=39")] + #[bitfield(name = "proxy_transfer_mode", ty = "bit", bits = "40..=40")] + #[bitfield(name = "sasl_ir", ty = "bit", bits = "41..=41")] + #[bitfield(name = "wildcard_enabled", ty = "bit", bits = "42..=42")] + #[bitfield(name = "tcp_keepalive", ty = "bit", bits = "43..=43")] + #[bitfield(name = "tcp_fastopen", ty = "bit", bits = "44..=44")] + #[bitfield(name = "ssl_enable_npn", ty = "bit", bits = "45..=45")] + #[bitfield(name = "ssl_enable_alpn", ty = "bit", bits = "46..=46")] + #[bitfield(name = "path_as_is", ty = "bit", bits = "47..=47")] + #[bitfield(name = "pipewait", ty = "bit", bits = "48..=48")] + #[bitfield(name = "suppress_connect_headers", ty = "bit", bits = "49..=49")] + #[bitfield(name = "dns_shuffle_addresses", ty = "bit", bits = "50..=50")] + #[bitfield(name = "stream_depends_e", ty = "bit", bits = "51..=51")] + #[bitfield(name = "haproxyprotocol", ty = "bit", bits = "52..=52")] + #[bitfield(name = "abstract_unix_socket", ty = "bit", bits = "53..=53")] + #[bitfield(name = "disallow_username_in_url", ty = "bit", bits = "54..=54")] + #[bitfield(name = "doh", ty = "bit", bits = "55..=55")] + #[bitfield(name = "doh_get", ty = "bit", bits = "56..=56")] + #[bitfield(name = "doh_verifypeer", ty = "bit", bits = "57..=57")] + #[bitfield(name = "doh_verifyhost", ty = "bit", bits = "58..=58")] + #[bitfield(name = "doh_verifystatus", ty = "bit", bits = "59..=59")] + #[bitfield(name = "http09_allowed", ty = "bit", bits = "60..=60")] + #[bitfield(name = "mail_rcpt_allowfails", ty = "bit", bits = "61..=61")] + pub is_fread_set_is_fwrite_set_free_referer_tftp_no_options_sep_headers_cookiesession_crlf_strip_path_slash_ssh_compression_get_filetime_tunnel_thru_httpproxy_prefer_ascii_remote_append_list_only_ftp_use_port_ftp_use_epsv_ftp_use_eprt_ftp_use_pret_ftp_skip_ip_hide_progress_http_fail_on_error_http_keep_sending_on_error_http_follow_location_http_transfer_encoding_allow_auth_to_other_hosts_include_header_http_set_referer_http_auto_referer_opt_no_body_upload_verbose_krb_reuse_forbid_reuse_fresh_no_signal_tcp_nodelay_ignorecl_connect_only_http_te_skip_http_ce_skip_proxy_transfer_mode_sasl_ir_wildcard_enabled_tcp_keepalive_tcp_fastopen_ssl_enable_npn_ssl_enable_alpn_path_as_is_pipewait_suppress_connect_headers_dns_shuffle_addresses_stream_depends_e_haproxyprotocol_abstract_unix_socket_disallow_username_in_url_doh_doh_get_doh_verifypeer_doh_verifyhost_doh_verifystatus_http09_allowed_mail_rcpt_allowfails: [u8; 8], +} +pub type curl_trailer_callback = Option::< + unsafe extern "C" fn(*mut *mut curl_slist, *mut libc::c_void) -> libc::c_int, +>; +pub type multidone_func = Option::< + unsafe extern "C" fn(*mut Curl_easy, CURLcode) -> libc::c_int, +>; +pub type CURLcode = libc::c_uint; +pub const CURL_LAST: CURLcode = 99; +pub const CURLE_SSL_CLIENTCERT: CURLcode = 98; +pub const CURLE_PROXY: CURLcode = 97; +pub const CURLE_QUIC_CONNECT_ERROR: CURLcode = 96; +pub const CURLE_HTTP3: CURLcode = 95; +pub const CURLE_AUTH_ERROR: CURLcode = 94; +pub const CURLE_RECURSIVE_API_CALL: CURLcode = 93; +pub const CURLE_HTTP2_STREAM: CURLcode = 92; +pub const CURLE_SSL_INVALIDCERTSTATUS: CURLcode = 91; +pub const CURLE_SSL_PINNEDPUBKEYNOTMATCH: CURLcode = 90; +pub const CURLE_NO_CONNECTION_AVAILABLE: CURLcode = 89; +pub const CURLE_CHUNK_FAILED: CURLcode = 88; +pub const CURLE_FTP_BAD_FILE_LIST: CURLcode = 87; +pub const CURLE_RTSP_SESSION_ERROR: CURLcode = 86; +pub const CURLE_RTSP_CSEQ_ERROR: CURLcode = 85; +pub const CURLE_FTP_PRET_FAILED: CURLcode = 84; +pub const CURLE_SSL_ISSUER_ERROR: CURLcode = 83; +pub const CURLE_SSL_CRL_BADFILE: CURLcode = 82; +pub const CURLE_AGAIN: CURLcode = 81; +pub const CURLE_SSL_SHUTDOWN_FAILED: CURLcode = 80; +pub const CURLE_SSH: CURLcode = 79; +pub const CURLE_REMOTE_FILE_NOT_FOUND: CURLcode = 78; +pub const CURLE_SSL_CACERT_BADFILE: CURLcode = 77; +pub const CURLE_CONV_REQD: CURLcode = 76; +pub const CURLE_CONV_FAILED: CURLcode = 75; +pub const CURLE_TFTP_NOSUCHUSER: CURLcode = 74; +pub const CURLE_REMOTE_FILE_EXISTS: CURLcode = 73; +pub const CURLE_TFTP_UNKNOWNID: CURLcode = 72; +pub const CURLE_TFTP_ILLEGAL: CURLcode = 71; +pub const CURLE_REMOTE_DISK_FULL: CURLcode = 70; +pub const CURLE_TFTP_PERM: CURLcode = 69; +pub const CURLE_TFTP_NOTFOUND: CURLcode = 68; +pub const CURLE_LOGIN_DENIED: CURLcode = 67; +pub const CURLE_SSL_ENGINE_INITFAILED: CURLcode = 66; +pub const CURLE_SEND_FAIL_REWIND: CURLcode = 65; +pub const CURLE_USE_SSL_FAILED: CURLcode = 64; +pub const CURLE_FILESIZE_EXCEEDED: CURLcode = 63; +pub const CURLE_LDAP_INVALID_URL: CURLcode = 62; +pub const CURLE_BAD_CONTENT_ENCODING: CURLcode = 61; +pub const CURLE_PEER_FAILED_VERIFICATION: CURLcode = 60; +pub const CURLE_SSL_CIPHER: CURLcode = 59; +pub const CURLE_SSL_CERTPROBLEM: CURLcode = 58; +pub const CURLE_OBSOLETE57: CURLcode = 57; +pub const CURLE_RECV_ERROR: CURLcode = 56; +pub const CURLE_SEND_ERROR: CURLcode = 55; +pub const CURLE_SSL_ENGINE_SETFAILED: CURLcode = 54; +pub const CURLE_SSL_ENGINE_NOTFOUND: CURLcode = 53; +pub const CURLE_GOT_NOTHING: CURLcode = 52; +pub const CURLE_OBSOLETE51: CURLcode = 51; +pub const CURLE_OBSOLETE50: CURLcode = 50; +pub const CURLE_SETOPT_OPTION_SYNTAX: CURLcode = 49; +pub const CURLE_UNKNOWN_OPTION: CURLcode = 48; +pub const CURLE_TOO_MANY_REDIRECTS: CURLcode = 47; +pub const CURLE_OBSOLETE46: CURLcode = 46; +pub const CURLE_INTERFACE_FAILED: CURLcode = 45; +pub const CURLE_OBSOLETE44: CURLcode = 44; +pub const CURLE_BAD_FUNCTION_ARGUMENT: CURLcode = 43; +pub const CURLE_ABORTED_BY_CALLBACK: CURLcode = 42; +pub const CURLE_FUNCTION_NOT_FOUND: CURLcode = 41; +pub const CURLE_OBSOLETE40: CURLcode = 40; +pub const CURLE_LDAP_SEARCH_FAILED: CURLcode = 39; +pub const CURLE_LDAP_CANNOT_BIND: CURLcode = 38; +pub const CURLE_FILE_COULDNT_READ_FILE: CURLcode = 37; +pub const CURLE_BAD_DOWNLOAD_RESUME: CURLcode = 36; +pub const CURLE_SSL_CONNECT_ERROR: CURLcode = 35; +pub const CURLE_HTTP_POST_ERROR: CURLcode = 34; +pub const CURLE_RANGE_ERROR: CURLcode = 33; +pub const CURLE_OBSOLETE32: CURLcode = 32; +pub const CURLE_FTP_COULDNT_USE_REST: CURLcode = 31; +pub const CURLE_FTP_PORT_FAILED: CURLcode = 30; +pub const CURLE_OBSOLETE29: CURLcode = 29; +pub const CURLE_OPERATION_TIMEDOUT: CURLcode = 28; +pub const CURLE_OUT_OF_MEMORY: CURLcode = 27; +pub const CURLE_READ_ERROR: CURLcode = 26; +pub const CURLE_UPLOAD_FAILED: CURLcode = 25; +pub const CURLE_OBSOLETE24: CURLcode = 24; +pub const CURLE_WRITE_ERROR: CURLcode = 23; +pub const CURLE_HTTP_RETURNED_ERROR: CURLcode = 22; +pub const CURLE_QUOTE_ERROR: CURLcode = 21; +pub const CURLE_OBSOLETE20: CURLcode = 20; +pub const CURLE_FTP_COULDNT_RETR_FILE: CURLcode = 19; +pub const CURLE_PARTIAL_FILE: CURLcode = 18; +pub const CURLE_FTP_COULDNT_SET_TYPE: CURLcode = 17; +pub const CURLE_HTTP2: CURLcode = 16; +pub const CURLE_FTP_CANT_GET_HOST: CURLcode = 15; +pub const CURLE_FTP_WEIRD_227_FORMAT: CURLcode = 14; +pub const CURLE_FTP_WEIRD_PASV_REPLY: CURLcode = 13; +pub const CURLE_FTP_ACCEPT_TIMEOUT: CURLcode = 12; +pub const CURLE_FTP_WEIRD_PASS_REPLY: CURLcode = 11; +pub const CURLE_FTP_ACCEPT_FAILED: CURLcode = 10; +pub const CURLE_REMOTE_ACCESS_DENIED: CURLcode = 9; +pub const CURLE_WEIRD_SERVER_REPLY: CURLcode = 8; +pub const CURLE_COULDNT_CONNECT: CURLcode = 7; +pub const CURLE_COULDNT_RESOLVE_HOST: CURLcode = 6; +pub const CURLE_COULDNT_RESOLVE_PROXY: CURLcode = 5; +pub const CURLE_NOT_BUILT_IN: CURLcode = 4; +pub const CURLE_URL_MALFORMAT: CURLcode = 3; +pub const CURLE_FAILED_INIT: CURLcode = 2; +pub const CURLE_UNSUPPORTED_PROTOCOL: CURLcode = 1; +pub const CURLE_OK: CURLcode = 0; +pub type curl_resolver_start_callback = Option::< + unsafe extern "C" fn( + *mut libc::c_void, + *mut libc::c_void, + *mut libc::c_void, + ) -> libc::c_int, +>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_http2_dep { + pub next: *mut Curl_http2_dep, + pub data: *mut Curl_easy, +} +pub type curl_fnmatch_callback = Option::< + unsafe extern "C" fn( + *mut libc::c_void, + *const libc::c_char, + *const libc::c_char, + ) -> libc::c_int, +>; +pub type curl_chunk_end_callback = Option::< + unsafe extern "C" fn(*mut libc::c_void) -> libc::c_long, +>; +pub type curl_chunk_bgn_callback = Option::< + unsafe extern "C" fn( + *const libc::c_void, + *mut libc::c_void, + libc::c_int, + ) -> libc::c_long, +>; +pub type Curl_RtspReq = libc::c_uint; +pub const RTSPREQ_LAST: Curl_RtspReq = 12; +pub const RTSPREQ_RECEIVE: Curl_RtspReq = 11; +pub const RTSPREQ_RECORD: Curl_RtspReq = 10; +pub const RTSPREQ_SET_PARAMETER: Curl_RtspReq = 9; +pub const RTSPREQ_GET_PARAMETER: Curl_RtspReq = 8; +pub const RTSPREQ_TEARDOWN: Curl_RtspReq = 7; +pub const RTSPREQ_PAUSE: Curl_RtspReq = 6; +pub const RTSPREQ_PLAY: Curl_RtspReq = 5; +pub const RTSPREQ_SETUP: Curl_RtspReq = 4; +pub const RTSPREQ_ANNOUNCE: Curl_RtspReq = 3; +pub const RTSPREQ_DESCRIBE: Curl_RtspReq = 2; +pub const RTSPREQ_OPTIONS: Curl_RtspReq = 1; +pub const RTSPREQ_NONE: Curl_RtspReq = 0; +pub type curl_usessl = libc::c_uint; +pub const CURLUSESSL_LAST: curl_usessl = 4; +pub const CURLUSESSL_ALL: curl_usessl = 3; +pub const CURLUSESSL_CONTROL: curl_usessl = 2; +pub const CURLUSESSL_TRY: curl_usessl = 1; +pub const CURLUSESSL_NONE: curl_usessl = 0; +pub type CURL_NETRC_OPTION = libc::c_uint; +pub const CURL_NETRC_LAST: CURL_NETRC_OPTION = 3; +pub const CURL_NETRC_REQUIRED: CURL_NETRC_OPTION = 2; +pub const CURL_NETRC_OPTIONAL: CURL_NETRC_OPTION = 1; +pub const CURL_NETRC_IGNORED: CURL_NETRC_OPTION = 0; +pub type curl_sshkeycallback = Option::< + unsafe extern "C" fn( + *mut CURL, + *const curl_khkey, + *const curl_khkey, + curl_khmatch, + *mut libc::c_void, + ) -> libc::c_int, +>; +pub type curl_khmatch = libc::c_uint; +pub const CURLKHMATCH_LAST: curl_khmatch = 3; +pub const CURLKHMATCH_MISSING: curl_khmatch = 2; +pub const CURLKHMATCH_MISMATCH: curl_khmatch = 1; +pub const CURLKHMATCH_OK: curl_khmatch = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_khkey { + pub key: *const libc::c_char, + pub len: size_t, + pub keytype: curl_khtype, +} +pub type curl_khtype = libc::c_uint; +pub const CURLKHTYPE_ED25519: curl_khtype = 5; +pub const CURLKHTYPE_ECDSA: curl_khtype = 4; +pub const CURLKHTYPE_DSS: curl_khtype = 3; +pub const CURLKHTYPE_RSA: curl_khtype = 2; +pub const CURLKHTYPE_RSA1: curl_khtype = 1; +pub const CURLKHTYPE_UNKNOWN: curl_khtype = 0; +pub type CURL = Curl_easy; +pub type curl_ftpccc = libc::c_uint; +pub const CURLFTPSSL_CCC_LAST: curl_ftpccc = 3; +pub const CURLFTPSSL_CCC_ACTIVE: curl_ftpccc = 2; +pub const CURLFTPSSL_CCC_PASSIVE: curl_ftpccc = 1; +pub const CURLFTPSSL_CCC_NONE: curl_ftpccc = 0; +pub type curl_ftpauth = libc::c_uint; +pub const CURLFTPAUTH_LAST: curl_ftpauth = 3; +pub const CURLFTPAUTH_TLS: curl_ftpauth = 2; +pub const CURLFTPAUTH_SSL: curl_ftpauth = 1; +pub const CURLFTPAUTH_DEFAULT: curl_ftpauth = 0; +pub type curl_ftpfile = libc::c_uint; +pub const FTPFILE_SINGLECWD: curl_ftpfile = 3; +pub const FTPFILE_NOCWD: curl_ftpfile = 2; +pub const FTPFILE_MULTICWD: curl_ftpfile = 1; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ssl_general_config { + pub max_ssl_sessions: size_t, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct ssl_config_data { + pub primary: ssl_primary_config, + pub certverifyresult: libc::c_long, + pub CRLfile: *mut libc::c_char, + pub fsslctx: curl_ssl_ctx_callback, + pub fsslctxp: *mut libc::c_void, + pub cert_type: *mut libc::c_char, + pub key: *mut libc::c_char, + pub key_blob: *mut curl_blob, + pub key_type: *mut libc::c_char, + pub key_passwd: *mut libc::c_char, + pub username: *mut libc::c_char, + pub password: *mut libc::c_char, + pub authtype: CURL_TLSAUTH, + #[bitfield(name = "certinfo", ty = "bit", bits = "0..=0")] + #[bitfield(name = "falsestart", ty = "bit", bits = "1..=1")] + #[bitfield(name = "enable_beast", ty = "bit", bits = "2..=2")] + #[bitfield(name = "no_revoke", ty = "bit", bits = "3..=3")] + #[bitfield(name = "no_partialchain", ty = "bit", bits = "4..=4")] + #[bitfield(name = "revoke_best_effort", ty = "bit", bits = "5..=5")] + #[bitfield(name = "native_ca_store", ty = "bit", bits = "6..=6")] + #[bitfield(name = "auto_client_cert", ty = "bit", bits = "7..=7")] + pub certinfo_falsestart_enable_beast_no_revoke_no_partialchain_revoke_best_effort_native_ca_store_auto_client_cert: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 3], +} +pub type CURL_TLSAUTH = libc::c_uint; +pub const CURL_TLSAUTH_LAST: CURL_TLSAUTH = 2; +pub const CURL_TLSAUTH_SRP: CURL_TLSAUTH = 1; +pub const CURL_TLSAUTH_NONE: CURL_TLSAUTH = 0; +pub type curl_ssl_ctx_callback = Option::< + unsafe extern "C" fn(*mut CURL, *mut libc::c_void, *mut libc::c_void) -> CURLcode, +>; +pub type curl_proxytype = libc::c_uint; +pub const CURLPROXY_SOCKS5_HOSTNAME: curl_proxytype = 7; +pub const CURLPROXY_SOCKS4A: curl_proxytype = 6; +pub const CURLPROXY_SOCKS5: curl_proxytype = 5; +pub const CURLPROXY_SOCKS4: curl_proxytype = 4; +pub const CURLPROXY_HTTPS: curl_proxytype = 2; +pub const CURLPROXY_HTTP_1_0: curl_proxytype = 1; +pub const CURLPROXY_HTTP: curl_proxytype = 0; +pub type curl_TimeCond = libc::c_uint; +pub const CURL_TIMECOND_LAST: curl_TimeCond = 4; +pub const CURL_TIMECOND_LASTMOD: curl_TimeCond = 3; +pub const CURL_TIMECOND_IFUNMODSINCE: curl_TimeCond = 2; +pub const CURL_TIMECOND_IFMODSINCE: curl_TimeCond = 1; +pub const CURL_TIMECOND_NONE: curl_TimeCond = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_mimepart { + pub easy: *mut Curl_easy, + pub parent: *mut curl_mime, + pub nextpart: *mut curl_mimepart, + pub kind: mimekind, + pub flags: libc::c_uint, + pub data: *mut libc::c_char, + pub readfunc: curl_read_callback, + pub seekfunc: curl_seek_callback, + pub freefunc: curl_free_callback, + pub arg: *mut libc::c_void, + pub fp: *mut FILE, + pub curlheaders: *mut curl_slist, + pub userheaders: *mut curl_slist, + pub mimetype: *mut libc::c_char, + pub filename: *mut libc::c_char, + pub name: *mut libc::c_char, + pub datasize: curl_off_t, + pub state: mime_state, + pub encoder: *const mime_encoder, + pub encstate: mime_encoder_state, + pub lastreadstatus: size_t, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct mime_encoder_state { + pub pos: size_t, + pub bufbeg: size_t, + pub bufend: size_t, + pub buf: [libc::c_char; 256], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct mime_encoder { + pub name: *const libc::c_char, + pub encodefunc: Option::< + unsafe extern "C" fn( + *mut libc::c_char, + size_t, + bool, + *mut curl_mimepart, + ) -> size_t, + >, + pub sizefunc: Option:: curl_off_t>, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct mime_state { + pub state: mimestate, + pub ptr: *mut libc::c_void, + pub offset: curl_off_t, +} +pub type mimestate = libc::c_uint; +pub const MIMESTATE_LAST: mimestate = 9; +pub const MIMESTATE_END: mimestate = 8; +pub const MIMESTATE_CONTENT: mimestate = 7; +pub const MIMESTATE_BOUNDARY2: mimestate = 6; +pub const MIMESTATE_BOUNDARY1: mimestate = 5; +pub const MIMESTATE_BODY: mimestate = 4; +pub const MIMESTATE_EOH: mimestate = 3; +pub const MIMESTATE_USERHEADERS: mimestate = 2; +pub const MIMESTATE_CURLHEADERS: mimestate = 1; +pub const MIMESTATE_BEGIN: mimestate = 0; +pub type curl_free_callback = Option:: ()>; +pub type curl_seek_callback = Option::< + unsafe extern "C" fn(*mut libc::c_void, curl_off_t, libc::c_int) -> libc::c_int, +>; +pub type mimekind = libc::c_uint; +pub const MIMEKIND_LAST: mimekind = 5; +pub const MIMEKIND_MULTIPART: mimekind = 4; +pub const MIMEKIND_CALLBACK: mimekind = 3; +pub const MIMEKIND_FILE: mimekind = 2; +pub const MIMEKIND_DATA: mimekind = 1; +pub const MIMEKIND_NONE: mimekind = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_mime { + pub easy: *mut Curl_easy, + pub parent: *mut curl_mimepart, + pub firstpart: *mut curl_mimepart, + pub lastpart: *mut curl_mimepart, + pub boundary: [libc::c_char; 41], + pub state: mime_state, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_httppost { + pub next: *mut curl_httppost, + pub name: *mut libc::c_char, + pub namelength: libc::c_long, + pub contents: *mut libc::c_char, + pub contentslength: libc::c_long, + pub buffer: *mut libc::c_char, + pub bufferlength: libc::c_long, + pub contenttype: *mut libc::c_char, + pub contentheader: *mut curl_slist, + pub more: *mut curl_httppost, + pub flags: libc::c_long, + pub showfilename: *mut libc::c_char, + pub userp: *mut libc::c_void, + pub contentlen: curl_off_t, +} +pub type curl_hstswrite_callback = Option::< + unsafe extern "C" fn( + *mut CURL, + *mut curl_hstsentry, + *mut curl_index, + *mut libc::c_void, + ) -> CURLSTScode, +>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_index { + pub index: size_t, + pub total: size_t, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct curl_hstsentry { + pub name: *mut libc::c_char, + pub namelen: size_t, + #[bitfield(name = "includeSubDomains", ty = "libc::c_uint", bits = "0..=0")] + pub includeSubDomains: [u8; 1], + pub expire: [libc::c_char; 18], +} +pub type CURLSTScode = libc::c_uint; +pub const CURLSTS_FAIL: CURLSTScode = 2; +pub const CURLSTS_DONE: CURLSTScode = 1; +pub const CURLSTS_OK: CURLSTScode = 0; +pub type curl_hstsread_callback = Option::< + unsafe extern "C" fn( + *mut CURL, + *mut curl_hstsentry, + *mut libc::c_void, + ) -> CURLSTScode, +>; +pub type curl_conv_callback = Option::< + unsafe extern "C" fn(*mut libc::c_char, size_t) -> CURLcode, +>; +pub type curl_closesocket_callback = Option::< + unsafe extern "C" fn(*mut libc::c_void, curl_socket_t) -> libc::c_int, +>; +pub type curl_socket_t = libc::c_int; +pub type curl_opensocket_callback = Option::< + unsafe extern "C" fn( + *mut libc::c_void, + curlsocktype, + *mut curl_sockaddr, + ) -> curl_socket_t, +>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_sockaddr { + pub family: libc::c_int, + pub socktype: libc::c_int, + pub protocol: libc::c_int, + pub addrlen: libc::c_uint, + pub addr: sockaddr, +} +pub type curlsocktype = libc::c_uint; +pub const CURLSOCKTYPE_LAST: curlsocktype = 2; +pub const CURLSOCKTYPE_ACCEPT: curlsocktype = 1; +pub const CURLSOCKTYPE_IPCXN: curlsocktype = 0; +pub type curl_sockopt_callback = Option::< + unsafe extern "C" fn(*mut libc::c_void, curl_socket_t, curlsocktype) -> libc::c_int, +>; +pub type curl_ioctl_callback = Option::< + unsafe extern "C" fn(*mut CURL, libc::c_int, *mut libc::c_void) -> curlioerr, +>; +pub type curlioerr = libc::c_uint; +pub const CURLIOE_LAST: curlioerr = 3; +pub const CURLIOE_FAILRESTART: curlioerr = 2; +pub const CURLIOE_UNKNOWNCMD: curlioerr = 1; +pub const CURLIOE_OK: curlioerr = 0; +pub type curl_debug_callback = Option::< + unsafe extern "C" fn( + *mut CURL, + curl_infotype, + *mut libc::c_char, + size_t, + *mut libc::c_void, + ) -> libc::c_int, +>; +pub type curl_infotype = libc::c_uint; +pub const CURLINFO_END: curl_infotype = 7; +pub const CURLINFO_SSL_DATA_OUT: curl_infotype = 6; +pub const CURLINFO_SSL_DATA_IN: curl_infotype = 5; +pub const CURLINFO_DATA_OUT: curl_infotype = 4; +pub const CURLINFO_DATA_IN: curl_infotype = 3; +pub const CURLINFO_HEADER_OUT: curl_infotype = 2; +pub const CURLINFO_HEADER_IN: curl_infotype = 1; +pub const CURLINFO_TEXT: curl_infotype = 0; +pub type curl_xferinfo_callback = Option::< + unsafe extern "C" fn( + *mut libc::c_void, + curl_off_t, + curl_off_t, + curl_off_t, + curl_off_t, + ) -> libc::c_int, +>; +pub type curl_progress_callback = Option::< + unsafe extern "C" fn( + *mut libc::c_void, + libc::c_double, + libc::c_double, + libc::c_double, + libc::c_double, + ) -> libc::c_int, +>; +pub type curl_write_callback = Option::< + unsafe extern "C" fn(*mut libc::c_char, size_t, size_t, *mut libc::c_void) -> size_t, +>; +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct SingleRequest { + pub size: curl_off_t, + pub maxdownload: curl_off_t, + pub bytecount: curl_off_t, + pub writebytecount: curl_off_t, + pub headerbytecount: curl_off_t, + pub deductheadercount: curl_off_t, + pub pendingheader: curl_off_t, + pub start: curltime, + pub now: curltime, + pub badheader: C2RustUnnamed_1, + pub headerline: libc::c_int, + pub str_0: *mut libc::c_char, + pub offset: curl_off_t, + pub httpcode: libc::c_int, + pub keepon: libc::c_int, + pub start100: curltime, + pub exp100: expect100, + pub upgr101: upgrade101, + pub writer_stack: *mut contenc_writer, + pub timeofdoc: time_t, + pub bodywrites: libc::c_long, + pub location: *mut libc::c_char, + pub newurl: *mut libc::c_char, + pub upload_present: ssize_t, + pub upload_fromhere: *mut libc::c_char, + pub p: C2RustUnnamed, + pub doh: *mut dohdata, + #[bitfield(name = "header", ty = "bit", bits = "0..=0")] + #[bitfield(name = "content_range", ty = "bit", bits = "1..=1")] + #[bitfield(name = "upload_done", ty = "bit", bits = "2..=2")] + #[bitfield(name = "ignorebody", ty = "bit", bits = "3..=3")] + #[bitfield(name = "http_bodyless", ty = "bit", bits = "4..=4")] + #[bitfield(name = "chunk", ty = "bit", bits = "5..=5")] + #[bitfield(name = "ignore_cl", ty = "bit", bits = "6..=6")] + #[bitfield(name = "upload_chunky", ty = "bit", bits = "7..=7")] + #[bitfield(name = "getheader", ty = "bit", bits = "8..=8")] + #[bitfield(name = "forbidchunk", ty = "bit", bits = "9..=9")] + pub header_content_range_upload_done_ignorebody_http_bodyless_chunk_ignore_cl_upload_chunky_getheader_forbidchunk: [u8; 2], + #[bitfield(padding)] + pub c2rust_padding: [u8; 6], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct dohdata { + pub headers: *mut curl_slist, + pub probe: [dnsprobe; 2], + pub pending: libc::c_uint, + pub port: libc::c_int, + pub host: *const libc::c_char, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct dnsprobe { + pub easy: *mut CURL, + pub dnstype: libc::c_int, + pub dohbuffer: [libc::c_uchar; 512], + pub dohlen: size_t, + pub serverdoh: dynbuf, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub union C2RustUnnamed { + pub file: *mut FILEPROTO, + pub ftp: *mut FTP, + pub http: *mut HTTP, + pub imap: *mut IMAP, + pub ldap: *mut ldapreqinfo, + pub mqtt: *mut MQTT, + pub pop3: *mut POP3, + pub rtsp: *mut RTSP, + pub smb: *mut smb_request, + pub smtp: *mut SMTP, + pub ssh: *mut SSHPROTO, + pub telnet: *mut TELNET, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct SSHPROTO { + pub path: *mut libc::c_char, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct SMTP { + pub transfer: curl_pp_transfer, + pub custom: *mut libc::c_char, + pub rcpt: *mut curl_slist, + pub rcpt_had_ok: bool, + pub trailing_crlf: bool, + pub rcpt_last_error: libc::c_int, + pub eob: size_t, +} +pub type curl_pp_transfer = libc::c_uint; +pub const PPTRANSFER_NONE: curl_pp_transfer = 2; +pub const PPTRANSFER_INFO: curl_pp_transfer = 1; +pub const PPTRANSFER_BODY: curl_pp_transfer = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct RTSP { + pub http_wrapper: HTTP, + pub CSeq_sent: libc::c_long, + pub CSeq_recv: libc::c_long, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct HTTP { + pub sendit: *mut curl_mimepart, + pub postsize: curl_off_t, + pub postdata: *const libc::c_char, + pub p_pragma: *const libc::c_char, + pub form: curl_mimepart, + pub backup: back, + pub sending: C2RustUnnamed_0, + pub send_buffer: dynbuf, +} +pub type C2RustUnnamed_0 = libc::c_uint; +pub const HTTPSEND_BODY: C2RustUnnamed_0 = 2; +pub const HTTPSEND_REQUEST: C2RustUnnamed_0 = 1; +pub const HTTPSEND_NADA: C2RustUnnamed_0 = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct back { + pub fread_func: curl_read_callback, + pub fread_in: *mut libc::c_void, + pub postdata: *const libc::c_char, + pub postsize: curl_off_t, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct POP3 { + pub transfer: curl_pp_transfer, + pub id: *mut libc::c_char, + pub custom: *mut libc::c_char, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct MQTT { + pub sendleftovers: *mut libc::c_char, + pub nsend: size_t, + pub npacket: size_t, + pub firstbyte: libc::c_uchar, + pub remaining_length: size_t, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct IMAP { + pub transfer: curl_pp_transfer, + pub mailbox: *mut libc::c_char, + pub uidvalidity: *mut libc::c_char, + pub uid: *mut libc::c_char, + pub mindex: *mut libc::c_char, + pub section: *mut libc::c_char, + pub partial: *mut libc::c_char, + pub query: *mut libc::c_char, + pub custom: *mut libc::c_char, + pub custom_params: *mut libc::c_char, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct FTP { + pub path: *mut libc::c_char, + pub pathalloc: *mut libc::c_char, + pub transfer: curl_pp_transfer, + pub downloadsize: curl_off_t, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct FILEPROTO { + pub path: *mut libc::c_char, + pub freepath: *mut libc::c_char, + pub fd: libc::c_int, +} +pub type upgrade101 = libc::c_uint; +pub const UPGR101_WORKING: upgrade101 = 3; +pub const UPGR101_RECEIVED: upgrade101 = 2; +pub const UPGR101_REQUESTED: upgrade101 = 1; +pub const UPGR101_INIT: upgrade101 = 0; +pub type expect100 = libc::c_uint; +pub const EXP100_FAILED: expect100 = 3; +pub const EXP100_SENDING_REQUEST: expect100 = 2; +pub const EXP100_AWAITING_CONTINUE: expect100 = 1; +pub const EXP100_SEND_DATA: expect100 = 0; +pub type C2RustUnnamed_1 = libc::c_uint; +pub const HEADER_ALLBAD: C2RustUnnamed_1 = 2; +pub const HEADER_PARTHEADER: C2RustUnnamed_1 = 1; +pub const HEADER_NORMAL: C2RustUnnamed_1 = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_multi { + pub magic: libc::c_uint, + pub easyp: *mut Curl_easy, + pub easylp: *mut Curl_easy, + pub num_easy: libc::c_int, + pub num_alive: libc::c_int, + pub msglist: Curl_llist, + pub pending: Curl_llist, + pub socket_cb: curl_socket_callback, + pub socket_userp: *mut libc::c_void, + pub push_cb: curl_push_callback, + pub push_userp: *mut libc::c_void, + pub hostcache: Curl_hash, + pub timetree: *mut Curl_tree, + pub sockhash: Curl_hash, + pub conn_cache: conncache, + pub maxconnects: libc::c_long, + pub max_host_connections: libc::c_long, + pub max_total_connections: libc::c_long, + pub timer_cb: curl_multi_timer_callback, + pub timer_userp: *mut libc::c_void, + pub timer_lastcall: curltime, + pub max_concurrent_streams: libc::c_uint, + pub wakeup_pair: [curl_socket_t; 2], + pub multiplexing: bool, + pub recheckstate: bool, + pub in_callback: bool, + pub ipv6_works: bool, + pub ssl_seeded: bool, +} +pub type curl_multi_timer_callback = Option::< + unsafe extern "C" fn(*mut CURLM, libc::c_long, *mut libc::c_void) -> libc::c_int, +>; +pub type CURLM = Curl_multi; +pub type curl_push_callback = Option::< + unsafe extern "C" fn( + *mut CURL, + *mut CURL, + size_t, + *mut curl_pushheaders, + *mut libc::c_void, + ) -> libc::c_int, +>; +pub type curl_socket_callback = Option::< + unsafe extern "C" fn( + *mut CURL, + curl_socket_t, + libc::c_int, + *mut libc::c_void, + *mut libc::c_void, + ) -> libc::c_int, +>; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Names { + pub hostcache: *mut Curl_hash, + pub hostcachetype: C2RustUnnamed_2, +} +pub type C2RustUnnamed_2 = libc::c_uint; +pub const HCACHE_SHARED: C2RustUnnamed_2 = 2; +pub const HCACHE_MULTI: C2RustUnnamed_2 = 1; +pub const HCACHE_NONE: C2RustUnnamed_2 = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_message { + pub list: Curl_llist_element, + pub extmsg: CURLMsg, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct CURLMsg { + pub msg: CURLMSG, + pub easy_handle: *mut CURL, + pub data: C2RustUnnamed_3, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub union C2RustUnnamed_3 { + pub whatever: *mut libc::c_void, + pub result: CURLcode, +} +pub type CURLMSG = libc::c_uint; +pub const CURLMSG_LAST: CURLMSG = 2; +pub const CURLMSG_DONE: CURLMSG = 1; +pub const CURLMSG_NONE: CURLMSG = 0; +pub type CURLMstate = libc::c_uint; +pub const MSTATE_LAST: CURLMstate = 17; +pub const MSTATE_MSGSENT: CURLMstate = 16; +pub const MSTATE_COMPLETED: CURLMstate = 15; +pub const MSTATE_DONE: CURLMstate = 14; +pub const MSTATE_RATELIMITING: CURLMstate = 13; +pub const MSTATE_PERFORMING: CURLMstate = 12; +pub const MSTATE_DID: CURLMstate = 11; +pub const MSTATE_DOING_MORE: CURLMstate = 10; +pub const MSTATE_DOING: CURLMstate = 9; +pub const MSTATE_DO: CURLMstate = 8; +pub const MSTATE_PROTOCONNECTING: CURLMstate = 7; +pub const MSTATE_PROTOCONNECT: CURLMstate = 6; +pub const MSTATE_TUNNELING: CURLMstate = 5; +pub const MSTATE_CONNECTING: CURLMstate = 4; +pub const MSTATE_RESOLVING: CURLMstate = 3; +pub const MSTATE_CONNECT: CURLMstate = 2; +pub const MSTATE_PENDING: CURLMstate = 1; +pub const MSTATE_INIT: CURLMstate = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct connectdata { + pub cnnct: connstate, + pub bundle_node: Curl_llist_element, + pub chunk: Curl_chunker, + pub fclosesocket: curl_closesocket_callback, + pub closesocket_client: *mut libc::c_void, + pub connection_id: libc::c_long, + pub dns_entry: *mut Curl_dns_entry, + pub ip_addr: *mut Curl_addrinfo, + pub tempaddr: [*mut Curl_addrinfo; 2], + pub scope_id: libc::c_uint, + pub transport: C2RustUnnamed_6, + pub host: hostname, + pub hostname_resolve: *mut libc::c_char, + pub secondaryhostname: *mut libc::c_char, + pub conn_to_host: hostname, + pub socks_proxy: proxy_info, + pub http_proxy: proxy_info, + pub port: libc::c_int, + pub remote_port: libc::c_int, + pub conn_to_port: libc::c_int, + pub secondary_port: libc::c_ushort, + pub primary_ip: [libc::c_char; 46], + pub ip_version: libc::c_uchar, + pub user: *mut libc::c_char, + pub passwd: *mut libc::c_char, + pub options: *mut libc::c_char, + pub sasl_authzid: *mut libc::c_char, + pub httpversion: libc::c_uchar, + pub now: curltime, + pub created: curltime, + pub lastused: curltime, + pub sock: [curl_socket_t; 2], + pub tempsock: [curl_socket_t; 2], + pub tempfamily: [libc::c_int; 2], + pub recv: [Option::; 2], + pub send: [Option::; 2], + pub ssl: [ssl_connect_data; 2], + pub proxy_ssl: [ssl_connect_data; 2], + pub ssl_extra: *mut libc::c_void, + pub ssl_config: ssl_primary_config, + pub proxy_ssl_config: ssl_primary_config, + pub bits: ConnectBits, + pub num_addr: libc::c_int, + pub connecttime: curltime, + pub timeoutms_per_addr: [timediff_t; 2], + pub handler: *const Curl_handler, + pub given: *const Curl_handler, + pub keepalive: curltime, + pub sockfd: curl_socket_t, + pub writesockfd: curl_socket_t, + pub easyq: Curl_llist, + pub seek_func: curl_seek_callback, + pub seek_client: *mut libc::c_void, + pub http_ntlm_state: curlntlm, + pub proxy_ntlm_state: curlntlm, + pub ntlm: ntlmdata, + pub proxyntlm: ntlmdata, + pub trailer: dynbuf, + pub proto: C2RustUnnamed_5, + pub connect_state: *mut http_connect_state, + pub bundle: *mut connectbundle, + pub unix_domain_socket: *mut libc::c_char, + pub localdev: *mut libc::c_char, + pub localportrange: libc::c_int, + pub cselect_bits: libc::c_int, + pub waitfor: libc::c_int, + pub negnpn: libc::c_int, + pub localport: libc::c_ushort, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct connectbundle { + pub multiuse: libc::c_int, + pub num_connections: size_t, + pub conn_list: Curl_llist, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct http_connect_state { + pub http_proxy: HTTP, + pub prot_save: *mut HTTP, + pub rcvbuf: dynbuf, + pub req: dynbuf, + pub nsend: size_t, + pub keepon: keeponval, + pub cl: curl_off_t, + pub tunnel_state: C2RustUnnamed_4, + #[bitfield(name = "chunked_encoding", ty = "bit", bits = "0..=0")] + #[bitfield(name = "close_connection", ty = "bit", bits = "1..=1")] + pub chunked_encoding_close_connection: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 3], +} +pub type C2RustUnnamed_4 = libc::c_uint; +pub const TUNNEL_EXIT: C2RustUnnamed_4 = 3; +pub const TUNNEL_COMPLETE: C2RustUnnamed_4 = 2; +pub const TUNNEL_CONNECT: C2RustUnnamed_4 = 1; +pub const TUNNEL_INIT: C2RustUnnamed_4 = 0; +pub type keeponval = libc::c_uint; +pub const KEEPON_IGNORE: keeponval = 2; +pub const KEEPON_CONNECT: keeponval = 1; +pub const KEEPON_DONE: keeponval = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub union C2RustUnnamed_5 { + pub ftpc: ftp_conn, + pub httpc: http_conn, + pub sshc: ssh_conn, + pub tftpc: *mut tftp_state_data, + pub imapc: imap_conn, + pub pop3c: pop3_conn, + pub smtpc: smtp_conn, + pub rtspc: rtsp_conn, + pub smbc: smb_conn, + pub rtmp: *mut libc::c_void, + pub ldapc: *mut ldapconninfo, + pub mqtt: mqtt_conn, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct mqtt_conn { + pub state: mqttstate, + pub nextstate: mqttstate, + pub packetid: libc::c_uint, +} +pub type mqttstate = libc::c_uint; +pub const MQTT_NOSTATE: mqttstate = 7; +pub const MQTT_PUB_REMAIN: mqttstate = 6; +pub const MQTT_PUBWAIT: mqttstate = 5; +pub const MQTT_SUBACK_COMING: mqttstate = 4; +pub const MQTT_SUBACK: mqttstate = 3; +pub const MQTT_CONNACK: mqttstate = 2; +pub const MQTT_REMAINING_LENGTH: mqttstate = 1; +pub const MQTT_FIRST: mqttstate = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct smb_conn { + pub state: smb_conn_state, + pub user: *mut libc::c_char, + pub domain: *mut libc::c_char, + pub share: *mut libc::c_char, + pub challenge: [libc::c_uchar; 8], + pub session_key: libc::c_uint, + pub uid: libc::c_ushort, + pub recv_buf: *mut libc::c_char, + pub upload_size: size_t, + pub send_size: size_t, + pub sent: size_t, + pub got: size_t, +} +pub type smb_conn_state = libc::c_uint; +pub const SMB_CONNECTED: smb_conn_state = 4; +pub const SMB_SETUP: smb_conn_state = 3; +pub const SMB_NEGOTIATE: smb_conn_state = 2; +pub const SMB_CONNECTING: smb_conn_state = 1; +pub const SMB_NOT_CONNECTED: smb_conn_state = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct rtsp_conn { + pub rtp_buf: *mut libc::c_char, + pub rtp_bufsize: ssize_t, + pub rtp_channel: libc::c_int, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct smtp_conn { + pub pp: pingpong, + pub state: smtpstate, + pub ssldone: bool, + pub domain: *mut libc::c_char, + pub sasl: SASL, + pub tls_supported: bool, + pub size_supported: bool, + pub utf8_supported: bool, + pub auth_supported: bool, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct SASL { + pub params: *const SASLproto, + pub state: saslstate, + pub authmechs: libc::c_ushort, + pub prefmech: libc::c_ushort, + pub authused: libc::c_ushort, + pub resetprefs: bool, + pub mutual_auth: bool, + pub force_ir: bool, +} +pub type saslstate = libc::c_uint; +pub const SASL_FINAL: saslstate = 17; +pub const SASL_CANCEL: saslstate = 16; +pub const SASL_GSASL: saslstate = 15; +pub const SASL_OAUTH2_RESP: saslstate = 14; +pub const SASL_OAUTH2: saslstate = 13; +pub const SASL_GSSAPI_NO_DATA: saslstate = 12; +pub const SASL_GSSAPI_TOKEN: saslstate = 11; +pub const SASL_GSSAPI: saslstate = 10; +pub const SASL_NTLM_TYPE2MSG: saslstate = 9; +pub const SASL_NTLM: saslstate = 8; +pub const SASL_DIGESTMD5_RESP: saslstate = 7; +pub const SASL_DIGESTMD5: saslstate = 6; +pub const SASL_CRAMMD5: saslstate = 5; +pub const SASL_EXTERNAL: saslstate = 4; +pub const SASL_LOGIN_PASSWD: saslstate = 3; +pub const SASL_LOGIN: saslstate = 2; +pub const SASL_PLAIN: saslstate = 1; +pub const SASL_STOP: saslstate = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct SASLproto { + pub service: *const libc::c_char, + pub contcode: libc::c_int, + pub finalcode: libc::c_int, + pub maxirlen: size_t, + pub sendauth: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *const libc::c_char, + *const libc::c_char, + ) -> CURLcode, + >, + pub sendcont: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *const libc::c_char, + ) -> CURLcode, + >, + pub getmessage: Option::< + unsafe extern "C" fn(*mut libc::c_char, *mut *mut libc::c_char) -> (), + >, +} +pub type smtpstate = libc::c_uint; +pub const SMTP_LAST: smtpstate = 13; +pub const SMTP_QUIT: smtpstate = 12; +pub const SMTP_POSTDATA: smtpstate = 11; +pub const SMTP_DATA: smtpstate = 10; +pub const SMTP_RCPT: smtpstate = 9; +pub const SMTP_MAIL: smtpstate = 8; +pub const SMTP_COMMAND: smtpstate = 7; +pub const SMTP_AUTH: smtpstate = 6; +pub const SMTP_UPGRADETLS: smtpstate = 5; +pub const SMTP_STARTTLS: smtpstate = 4; +pub const SMTP_HELO: smtpstate = 3; +pub const SMTP_EHLO: smtpstate = 2; +pub const SMTP_SERVERGREET: smtpstate = 1; +pub const SMTP_STOP: smtpstate = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct pingpong { + pub cache: *mut libc::c_char, + pub cache_size: size_t, + pub nread_resp: size_t, + pub linestart_resp: *mut libc::c_char, + pub pending_resp: bool, + pub sendthis: *mut libc::c_char, + pub sendleft: size_t, + pub sendsize: size_t, + pub response: curltime, + pub response_time: timediff_t, + pub sendbuf: dynbuf, + pub statemachine: Option::< + unsafe extern "C" fn(*mut Curl_easy, *mut connectdata) -> CURLcode, + >, + pub endofresp: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut libc::c_char, + size_t, + *mut libc::c_int, + ) -> bool, + >, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct pop3_conn { + pub pp: pingpong, + pub state: pop3state, + pub ssldone: bool, + pub tls_supported: bool, + pub eob: size_t, + pub strip: size_t, + pub sasl: SASL, + pub authtypes: libc::c_uint, + pub preftype: libc::c_uint, + pub apoptimestamp: *mut libc::c_char, +} +pub type pop3state = libc::c_uint; +pub const POP3_LAST: pop3state = 11; +pub const POP3_QUIT: pop3state = 10; +pub const POP3_COMMAND: pop3state = 9; +pub const POP3_PASS: pop3state = 8; +pub const POP3_USER: pop3state = 7; +pub const POP3_APOP: pop3state = 6; +pub const POP3_AUTH: pop3state = 5; +pub const POP3_UPGRADETLS: pop3state = 4; +pub const POP3_STARTTLS: pop3state = 3; +pub const POP3_CAPA: pop3state = 2; +pub const POP3_SERVERGREET: pop3state = 1; +pub const POP3_STOP: pop3state = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct imap_conn { + pub pp: pingpong, + pub state: imapstate, + pub ssldone: bool, + pub preauth: bool, + pub sasl: SASL, + pub preftype: libc::c_uint, + pub cmdid: libc::c_uint, + pub resptag: [libc::c_char; 5], + pub tls_supported: bool, + pub login_disabled: bool, + pub ir_supported: bool, + pub mailbox: *mut libc::c_char, + pub mailbox_uidvalidity: *mut libc::c_char, + pub dyn_0: dynbuf, +} +pub type imapstate = libc::c_uint; +pub const IMAP_LAST: imapstate = 15; +pub const IMAP_LOGOUT: imapstate = 14; +pub const IMAP_SEARCH: imapstate = 13; +pub const IMAP_APPEND_FINAL: imapstate = 12; +pub const IMAP_APPEND: imapstate = 11; +pub const IMAP_FETCH_FINAL: imapstate = 10; +pub const IMAP_FETCH: imapstate = 9; +pub const IMAP_SELECT: imapstate = 8; +pub const IMAP_LIST: imapstate = 7; +pub const IMAP_LOGIN: imapstate = 6; +pub const IMAP_AUTHENTICATE: imapstate = 5; +pub const IMAP_UPGRADETLS: imapstate = 4; +pub const IMAP_STARTTLS: imapstate = 3; +pub const IMAP_CAPABILITY: imapstate = 2; +pub const IMAP_SERVERGREET: imapstate = 1; +pub const IMAP_STOP: imapstate = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ssh_conn { + pub authlist: *const libc::c_char, + pub passphrase: *const libc::c_char, + pub rsa_pub: *mut libc::c_char, + pub rsa: *mut libc::c_char, + pub authed: bool, + pub acceptfail: bool, + pub state: sshstate, + pub nextstate: sshstate, + pub actualcode: CURLcode, + pub quote_item: *mut curl_slist, + pub quote_path1: *mut libc::c_char, + pub quote_path2: *mut libc::c_char, + pub homedir: *mut libc::c_char, + pub readdir_line: *mut libc::c_char, + pub secondCreateDirs: libc::c_int, + pub orig_waitfor: libc::c_int, + pub slash_pos: *mut libc::c_char, +} +pub type sshstate = libc::c_int; +pub const SSH_LAST: sshstate = 60; +pub const SSH_QUIT: sshstate = 59; +pub const SSH_SESSION_FREE: sshstate = 58; +pub const SSH_SESSION_DISCONNECT: sshstate = 57; +pub const SSH_SCP_CHANNEL_FREE: sshstate = 56; +pub const SSH_SCP_WAIT_CLOSE: sshstate = 55; +pub const SSH_SCP_WAIT_EOF: sshstate = 54; +pub const SSH_SCP_SEND_EOF: sshstate = 53; +pub const SSH_SCP_DONE: sshstate = 52; +pub const SSH_SCP_DOWNLOAD: sshstate = 51; +pub const SSH_SCP_DOWNLOAD_INIT: sshstate = 50; +pub const SSH_SCP_UPLOAD_INIT: sshstate = 49; +pub const SSH_SCP_TRANS_INIT: sshstate = 48; +pub const SSH_SFTP_SHUTDOWN: sshstate = 47; +pub const SSH_SFTP_CLOSE: sshstate = 46; +pub const SSH_SFTP_DOWNLOAD_STAT: sshstate = 45; +pub const SSH_SFTP_DOWNLOAD_INIT: sshstate = 44; +pub const SSH_SFTP_READDIR_DONE: sshstate = 43; +pub const SSH_SFTP_READDIR_BOTTOM: sshstate = 42; +pub const SSH_SFTP_READDIR_LINK: sshstate = 41; +pub const SSH_SFTP_READDIR: sshstate = 40; +pub const SSH_SFTP_READDIR_INIT: sshstate = 39; +pub const SSH_SFTP_CREATE_DIRS_MKDIR: sshstate = 38; +pub const SSH_SFTP_CREATE_DIRS: sshstate = 37; +pub const SSH_SFTP_CREATE_DIRS_INIT: sshstate = 36; +pub const SSH_SFTP_UPLOAD_INIT: sshstate = 35; +pub const SSH_SFTP_TRANS_INIT: sshstate = 34; +pub const SSH_SFTP_FILETIME: sshstate = 33; +pub const SSH_SFTP_GETINFO: sshstate = 32; +pub const SSH_SFTP_QUOTE_STATVFS: sshstate = 31; +pub const SSH_SFTP_QUOTE_UNLINK: sshstate = 30; +pub const SSH_SFTP_QUOTE_RMDIR: sshstate = 29; +pub const SSH_SFTP_QUOTE_RENAME: sshstate = 28; +pub const SSH_SFTP_QUOTE_MKDIR: sshstate = 27; +pub const SSH_SFTP_QUOTE_SYMLINK: sshstate = 26; +pub const SSH_SFTP_QUOTE_SETSTAT: sshstate = 25; +pub const SSH_SFTP_QUOTE_STAT: sshstate = 24; +pub const SSH_SFTP_NEXT_QUOTE: sshstate = 23; +pub const SSH_SFTP_QUOTE: sshstate = 22; +pub const SSH_SFTP_POSTQUOTE_INIT: sshstate = 21; +pub const SSH_SFTP_QUOTE_INIT: sshstate = 20; +pub const SSH_SFTP_REALPATH: sshstate = 19; +pub const SSH_SFTP_INIT: sshstate = 18; +pub const SSH_AUTH_DONE: sshstate = 17; +pub const SSH_AUTH_GSSAPI: sshstate = 16; +pub const SSH_AUTH_KEY: sshstate = 15; +pub const SSH_AUTH_KEY_INIT: sshstate = 14; +pub const SSH_AUTH_HOST: sshstate = 13; +pub const SSH_AUTH_HOST_INIT: sshstate = 12; +pub const SSH_AUTH_AGENT: sshstate = 11; +pub const SSH_AUTH_AGENT_LIST: sshstate = 10; +pub const SSH_AUTH_AGENT_INIT: sshstate = 9; +pub const SSH_AUTH_PASS: sshstate = 8; +pub const SSH_AUTH_PASS_INIT: sshstate = 7; +pub const SSH_AUTH_PKEY: sshstate = 6; +pub const SSH_AUTH_PKEY_INIT: sshstate = 5; +pub const SSH_AUTHLIST: sshstate = 4; +pub const SSH_HOSTKEY: sshstate = 3; +pub const SSH_S_STARTUP: sshstate = 2; +pub const SSH_INIT: sshstate = 1; +pub const SSH_STOP: sshstate = 0; +pub const SSH_NO_STATE: sshstate = -1; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct http_conn { + pub unused: libc::c_int, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ftp_conn { + pub pp: pingpong, + pub entrypath: *mut libc::c_char, + pub file: *mut libc::c_char, + pub dirs: *mut *mut libc::c_char, + pub dirdepth: libc::c_int, + pub dont_check: bool, + pub ctl_valid: bool, + pub cwddone: bool, + pub cwdcount: libc::c_int, + pub cwdfail: bool, + pub wait_data_conn: bool, + pub newport: libc::c_ushort, + pub newhost: *mut libc::c_char, + pub prevpath: *mut libc::c_char, + pub transfertype: libc::c_char, + pub count1: libc::c_int, + pub count2: libc::c_int, + pub count3: libc::c_int, + pub state: ftpstate, + pub state_saved: ftpstate, + pub retr_size_saved: curl_off_t, + pub server_os: *mut libc::c_char, + pub known_filesize: curl_off_t, +} +pub type ftpstate = libc::c_uint; +pub const FTP_LAST: ftpstate = 35; +pub const FTP_QUIT: ftpstate = 34; +pub const FTP_STOR: ftpstate = 33; +pub const FTP_RETR: ftpstate = 32; +pub const FTP_LIST: ftpstate = 31; +pub const FTP_PASV: ftpstate = 30; +pub const FTP_PRET: ftpstate = 29; +pub const FTP_PORT: ftpstate = 28; +pub const FTP_RETR_REST: ftpstate = 27; +pub const FTP_REST: ftpstate = 26; +pub const FTP_STOR_SIZE: ftpstate = 25; +pub const FTP_RETR_SIZE: ftpstate = 24; +pub const FTP_SIZE: ftpstate = 23; +pub const FTP_STOR_TYPE: ftpstate = 22; +pub const FTP_RETR_TYPE: ftpstate = 21; +pub const FTP_LIST_TYPE: ftpstate = 20; +pub const FTP_TYPE: ftpstate = 19; +pub const FTP_MDTM: ftpstate = 18; +pub const FTP_MKD: ftpstate = 17; +pub const FTP_CWD: ftpstate = 16; +pub const FTP_POSTQUOTE: ftpstate = 15; +pub const FTP_STOR_PREQUOTE: ftpstate = 14; +pub const FTP_RETR_PREQUOTE: ftpstate = 13; +pub const FTP_QUOTE: ftpstate = 12; +pub const FTP_NAMEFMT: ftpstate = 11; +pub const FTP_SYST: ftpstate = 10; +pub const FTP_PWD: ftpstate = 9; +pub const FTP_CCC: ftpstate = 8; +pub const FTP_PROT: ftpstate = 7; +pub const FTP_PBSZ: ftpstate = 6; +pub const FTP_ACCT: ftpstate = 5; +pub const FTP_PASS: ftpstate = 4; +pub const FTP_USER: ftpstate = 3; +pub const FTP_AUTH: ftpstate = 2; +pub const FTP_WAIT220: ftpstate = 1; +pub const FTP_STOP: ftpstate = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ntlmdata { + pub flags: libc::c_uint, + pub nonce: [libc::c_uchar; 8], + pub target_info_len: libc::c_uint, + pub target_info: *mut libc::c_void, + pub ntlm_auth_hlpr_socket: curl_socket_t, + pub ntlm_auth_hlpr_pid: pid_t, + pub challenge: *mut libc::c_char, + pub response: *mut libc::c_char, +} +pub type curlntlm = libc::c_uint; +pub const NTLMSTATE_LAST: curlntlm = 4; +pub const NTLMSTATE_TYPE3: curlntlm = 3; +pub const NTLMSTATE_TYPE2: curlntlm = 2; +pub const NTLMSTATE_TYPE1: curlntlm = 1; +pub const NTLMSTATE_NONE: curlntlm = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_handler { + pub scheme: *const libc::c_char, + pub setup_connection: Option::< + unsafe extern "C" fn(*mut Curl_easy, *mut connectdata) -> CURLcode, + >, + pub do_it: Option:: CURLcode>, + pub done: Option:: CURLcode>, + pub do_more: Option::< + unsafe extern "C" fn(*mut Curl_easy, *mut libc::c_int) -> CURLcode, + >, + pub connect_it: Option::< + unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + >, + pub connecting: Option::< + unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + >, + pub doing: Option:: CURLcode>, + pub proto_getsock: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + >, + pub doing_getsock: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + >, + pub domore_getsock: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + >, + pub perform_getsock: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + >, + pub disconnect: Option::< + unsafe extern "C" fn(*mut Curl_easy, *mut connectdata, bool) -> CURLcode, + >, + pub readwrite: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut ssize_t, + *mut bool, + ) -> CURLcode, + >, + pub connection_check: Option::< + unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + libc::c_uint, + ) -> libc::c_uint, + >, + pub attach: Option:: ()>, + pub defport: libc::c_int, + pub protocol: libc::c_uint, + pub family: libc::c_uint, + pub flags: libc::c_uint, +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct ConnectBits { + pub tcpconnect: [bool; 2], + pub proxy_ssl_connected: [bool; 2], + #[bitfield(name = "httpproxy", ty = "bit", bits = "0..=0")] + #[bitfield(name = "socksproxy", ty = "bit", bits = "1..=1")] + #[bitfield(name = "proxy_user_passwd", ty = "bit", bits = "2..=2")] + #[bitfield(name = "tunnel_proxy", ty = "bit", bits = "3..=3")] + #[bitfield(name = "proxy_connect_closed", ty = "bit", bits = "4..=4")] + #[bitfield(name = "close", ty = "bit", bits = "5..=5")] + #[bitfield(name = "reuse", ty = "bit", bits = "6..=6")] + #[bitfield(name = "altused", ty = "bit", bits = "7..=7")] + #[bitfield(name = "conn_to_host", ty = "bit", bits = "8..=8")] + #[bitfield(name = "conn_to_port", ty = "bit", bits = "9..=9")] + #[bitfield(name = "proxy", ty = "bit", bits = "10..=10")] + #[bitfield(name = "user_passwd", ty = "bit", bits = "11..=11")] + #[bitfield(name = "ipv6_ip", ty = "bit", bits = "12..=12")] + #[bitfield(name = "ipv6", ty = "bit", bits = "13..=13")] + #[bitfield(name = "do_more", ty = "bit", bits = "14..=14")] + #[bitfield(name = "protoconnstart", ty = "bit", bits = "15..=15")] + #[bitfield(name = "retry", ty = "bit", bits = "16..=16")] + #[bitfield(name = "authneg", ty = "bit", bits = "17..=17")] + #[bitfield(name = "rewindaftersend", ty = "bit", bits = "18..=18")] + #[bitfield(name = "ftp_use_epsv", ty = "bit", bits = "19..=19")] + #[bitfield(name = "ftp_use_eprt", ty = "bit", bits = "20..=20")] + #[bitfield(name = "ftp_use_data_ssl", ty = "bit", bits = "21..=21")] + #[bitfield(name = "ftp_use_control_ssl", ty = "bit", bits = "22..=22")] + #[bitfield(name = "netrc", ty = "bit", bits = "23..=23")] + #[bitfield(name = "bound", ty = "bit", bits = "24..=24")] + #[bitfield(name = "multiplex", ty = "bit", bits = "25..=25")] + #[bitfield(name = "tcp_fastopen", ty = "bit", bits = "26..=26")] + #[bitfield(name = "tls_enable_npn", ty = "bit", bits = "27..=27")] + #[bitfield(name = "tls_enable_alpn", ty = "bit", bits = "28..=28")] + #[bitfield(name = "connect_only", ty = "bit", bits = "29..=29")] + #[bitfield(name = "doh", ty = "bit", bits = "30..=30")] + #[bitfield(name = "abstract_unix_socket", ty = "bit", bits = "31..=31")] + #[bitfield(name = "tls_upgraded", ty = "bit", bits = "32..=32")] + #[bitfield(name = "sock_accepted", ty = "bit", bits = "33..=33")] + #[bitfield(name = "parallel_connect", ty = "bit", bits = "34..=34")] + pub httpproxy_socksproxy_proxy_user_passwd_tunnel_proxy_proxy_connect_closed_close_reuse_altused_conn_to_host_conn_to_port_proxy_user_passwd_ipv6_ip_ipv6_do_more_protoconnstart_retry_authneg_rewindaftersend_ftp_use_epsv_ftp_use_eprt_ftp_use_data_ssl_ftp_use_control_ssl_netrc_bound_multiplex_tcp_fastopen_tls_enable_npn_tls_enable_alpn_connect_only_doh_abstract_unix_socket_tls_upgraded_sock_accepted_parallel_connect: [u8; 5], + #[bitfield(padding)] + pub c2rust_padding: [u8; 3], +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct ssl_connect_data { + pub state: ssl_connection_state, + pub connecting_state: ssl_connect_state, + pub backend: *mut ssl_backend_data, + #[bitfield(name = "use_0", ty = "bit", bits = "0..=0")] + pub use_0: [u8; 1], + #[bitfield(padding)] + pub c2rust_padding: [u8; 7], +} +pub type ssl_connect_state = libc::c_uint; +pub const ssl_connect_done: ssl_connect_state = 5; +pub const ssl_connect_3: ssl_connect_state = 4; +pub const ssl_connect_2_writing: ssl_connect_state = 3; +pub const ssl_connect_2_reading: ssl_connect_state = 2; +pub const ssl_connect_2: ssl_connect_state = 1; +pub const ssl_connect_1: ssl_connect_state = 0; +pub type ssl_connection_state = libc::c_uint; +pub const ssl_connection_complete: ssl_connection_state = 2; +pub const ssl_connection_negotiating: ssl_connection_state = 1; +pub const ssl_connection_none: ssl_connection_state = 0; +pub type Curl_send = unsafe extern "C" fn( + *mut Curl_easy, + libc::c_int, + *const libc::c_void, + size_t, + *mut CURLcode, +) -> ssize_t; +pub type Curl_recv = unsafe extern "C" fn( + *mut Curl_easy, + libc::c_int, + *mut libc::c_char, + size_t, + *mut CURLcode, +) -> ssize_t; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct proxy_info { + pub host: hostname, + pub port: libc::c_long, + pub proxytype: curl_proxytype, + pub user: *mut libc::c_char, + pub passwd: *mut libc::c_char, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct hostname { + pub rawalloc: *mut libc::c_char, + pub encalloc: *mut libc::c_char, + pub name: *mut libc::c_char, + pub dispname: *const libc::c_char, +} +pub type C2RustUnnamed_6 = libc::c_uint; +pub const TRNSPRT_QUIC: C2RustUnnamed_6 = 5; +pub const TRNSPRT_UDP: C2RustUnnamed_6 = 4; +pub const TRNSPRT_TCP: C2RustUnnamed_6 = 3; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_chunker { + pub datasize: curl_off_t, + pub state: ChunkyState, + pub hexindex: libc::c_uchar, + pub hexbuffer: [libc::c_char; 17], +} +pub type ChunkyState = libc::c_uint; +pub const CHUNK_TRAILER_POSTCR: ChunkyState = 7; +pub const CHUNK_TRAILER_CR: ChunkyState = 6; +pub const CHUNK_TRAILER: ChunkyState = 5; +pub const CHUNK_STOP: ChunkyState = 4; +pub const CHUNK_POSTLF: ChunkyState = 3; +pub const CHUNK_DATA: ChunkyState = 2; +pub const CHUNK_LF: ChunkyState = 1; +pub const CHUNK_HEX: ChunkyState = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct connstate { + pub state: connect_t, + pub outstanding: ssize_t, + pub outp: *mut libc::c_uchar, +} +pub type connect_t = libc::c_uint; +pub const CONNECT_DONE: connect_t = 17; +pub const CONNECT_REQ_READ_MORE: connect_t = 16; +pub const CONNECT_REQ_READ: connect_t = 15; +pub const CONNECT_REQ_SENDING: connect_t = 14; +pub const CONNECT_REQ_SEND: connect_t = 13; +pub const CONNECT_RESOLVE_REMOTE: connect_t = 12; +pub const CONNECT_RESOLVED: connect_t = 11; +pub const CONNECT_RESOLVING: connect_t = 10; +pub const CONNECT_REQ_INIT: connect_t = 9; +pub const CONNECT_AUTH_READ: connect_t = 8; +pub const CONNECT_AUTH_SEND: connect_t = 7; +pub const CONNECT_AUTH_INIT: connect_t = 6; +pub const CONNECT_GSSAPI_INIT: connect_t = 5; +pub const CONNECT_SOCKS_READ: connect_t = 4; +pub const CONNECT_SOCKS_READ_INIT: connect_t = 3; +pub const CONNECT_SOCKS_SEND: connect_t = 2; +pub const CONNECT_SOCKS_INIT: connect_t = 1; +pub const CONNECT_INIT: connect_t = 0; +pub type curlfiletype = libc::c_uint; +pub const CURLFILETYPE_UNKNOWN: curlfiletype = 8; +pub const CURLFILETYPE_DOOR: curlfiletype = 7; +pub const CURLFILETYPE_SOCKET: curlfiletype = 6; +pub const CURLFILETYPE_NAMEDPIPE: curlfiletype = 5; +pub const CURLFILETYPE_DEVICE_CHAR: curlfiletype = 4; +pub const CURLFILETYPE_DEVICE_BLOCK: curlfiletype = 3; +pub const CURLFILETYPE_SYMLINK: curlfiletype = 2; +pub const CURLFILETYPE_DIRECTORY: curlfiletype = 1; +pub const CURLFILETYPE_FILE: curlfiletype = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct curl_fileinfo { + pub filename: *mut libc::c_char, + pub filetype: curlfiletype, + pub time: time_t, + pub perm: libc::c_uint, + pub uid: libc::c_int, + pub gid: libc::c_int, + pub size: curl_off_t, + pub hardlinks: libc::c_long, + pub strings: C2RustUnnamed_7, + pub flags: libc::c_uint, + pub b_data: *mut libc::c_char, + pub b_size: size_t, + pub b_used: size_t, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct C2RustUnnamed_7 { + pub time: *mut libc::c_char, + pub perm: *mut libc::c_char, + pub user: *mut libc::c_char, + pub group: *mut libc::c_char, + pub target: *mut libc::c_char, +} +pub type curl_malloc_callback = Option::< + unsafe extern "C" fn(size_t) -> *mut libc::c_void, +>; +pub type curl_strdup_callback = Option::< + unsafe extern "C" fn(*const libc::c_char) -> *mut libc::c_char, +>; +pub type curl_calloc_callback = Option::< + unsafe extern "C" fn(size_t, size_t) -> *mut libc::c_void, +>; +pub type uint8_t = __uint8_t; +pub type uint16_t = __uint16_t; +pub type uint32_t = __uint32_t; +pub type in_addr_t = uint32_t; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct in_addr { + pub s_addr: in_addr_t, +} +pub type in_port_t = uint16_t; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct in6_addr { + pub __in6_u: C2RustUnnamed_8, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub union C2RustUnnamed_8 { + pub __u6_addr8: [uint8_t; 16], + pub __u6_addr16: [uint16_t; 8], + pub __u6_addr32: [uint32_t; 4], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [libc::c_uchar; 8], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: uint32_t, + pub sin6_addr: in6_addr, + pub sin6_scope_id: uint32_t, +} +pub type resolve_t = libc::c_int; +pub const CURLRESOLV_PENDING: resolve_t = 1; +pub const CURLRESOLV_RESOLVED: resolve_t = 0; +pub const CURLRESOLV_ERROR: resolve_t = -1; +pub const CURLRESOLV_TIMEDOUT: resolve_t = -2; +pub const STRING_CUSTOMREQUEST: dupstring = 6; +pub type ftpport = libc::c_uint; +pub const DONE: ftpport = 2; +pub const PORT: ftpport = 1; +pub const EPRT: ftpport = 0; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_sockaddr_storage { + pub buffer: C2RustUnnamed_9, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub union C2RustUnnamed_9 { + pub sa: sockaddr, + pub sa_in: sockaddr_in, + pub sa_in6: sockaddr_in6, + pub sa_stor: sockaddr_storage, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Curl_sockaddr_ex { + pub family: libc::c_int, + pub socktype: libc::c_int, + pub protocol: libc::c_int, + pub addrlen: libc::c_uint, + pub _sa_ex_u: C2RustUnnamed_10, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub union C2RustUnnamed_10 { + pub addr: sockaddr, + pub buff: Curl_sockaddr_storage, +} +pub const IF2IP_FOUND: if2ip_result_t = 2; +pub const IF2IP_AF_NOT_SUPPORTED: if2ip_result_t = 1; +pub const IF2IP_NOT_FOUND: if2ip_result_t = 0; +pub type if2ip_result_t = libc::c_uint; +pub const STRING_FTPPORT: dupstring = 12; +pub type urlreject = libc::c_uint; +pub const REJECT_ZERO: urlreject = 4; +pub const REJECT_CTRL: urlreject = 3; +pub const REJECT_NADA: urlreject = 2; +pub type timerid = libc::c_uint; +pub const TIMER_LAST: timerid = 11; +pub const TIMER_REDIRECT: timerid = 10; +pub const TIMER_STARTACCEPT: timerid = 9; +pub const TIMER_POSTRANSFER: timerid = 8; +pub const TIMER_STARTTRANSFER: timerid = 7; +pub const TIMER_PRETRANSFER: timerid = 6; +pub const TIMER_APPCONNECT: timerid = 5; +pub const TIMER_CONNECT: timerid = 4; +pub const TIMER_NAMELOOKUP: timerid = 3; +pub const TIMER_STARTSINGLE: timerid = 2; +pub const TIMER_STARTOP: timerid = 1; +pub const TIMER_NONE: timerid = 0; +pub type CURLofft = libc::c_uint; +pub const CURL_OFFT_INVAL: CURLofft = 2; +pub const CURL_OFFT_FLOW: CURLofft = 1; +pub const CURL_OFFT_OK: CURLofft = 0; +pub const STRING_FTP_ALTERNATIVE_TO_USER: dupstring = 11; +pub const STRING_FTP_ACCOUNT: dupstring = 10; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ftp_wc { + pub parser: *mut ftp_parselist_data, + pub backup: C2RustUnnamed_11, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct C2RustUnnamed_11 { + pub write_function: curl_write_callback, + pub file_descriptor: *mut FILE, +} +pub type dupstring = libc::c_uint; +pub const STRING_LAST: dupstring = 80; +pub const STRING_AWS_SIGV4: dupstring = 79; +pub const STRING_COPYPOSTFIELDS: dupstring = 78; +pub const STRING_LASTZEROTERMINATED: dupstring = 77; +pub const STRING_SSL_EC_CURVES: dupstring = 76; +pub const STRING_DNS_LOCAL_IP6: dupstring = 75; +pub const STRING_DNS_LOCAL_IP4: dupstring = 74; +pub const STRING_DNS_INTERFACE: dupstring = 73; +pub const STRING_DNS_SERVERS: dupstring = 72; +pub const STRING_SASL_AUTHZID: dupstring = 71; +pub const STRING_HSTS: dupstring = 70; +pub const STRING_ALTSVC: dupstring = 69; +pub const STRING_DOH: dupstring = 68; +pub const STRING_TARGET: dupstring = 67; +pub const STRING_UNIX_SOCKET_PATH: dupstring = 66; +pub const STRING_BEARER: dupstring = 65; +pub const STRING_TLSAUTH_PASSWORD_PROXY: dupstring = 64; +pub const STRING_TLSAUTH_PASSWORD: dupstring = 63; +pub const STRING_TLSAUTH_USERNAME_PROXY: dupstring = 62; +pub const STRING_TLSAUTH_USERNAME: dupstring = 61; +pub const STRING_MAIL_AUTH: dupstring = 60; +pub const STRING_MAIL_FROM: dupstring = 59; +pub const STRING_SERVICE_NAME: dupstring = 58; +pub const STRING_PROXY_SERVICE_NAME: dupstring = 57; +pub const STRING_SSH_KNOWNHOSTS: dupstring = 56; +pub const STRING_SSH_HOST_PUBLIC_KEY_MD5: dupstring = 55; +pub const STRING_SSH_PUBLIC_KEY: dupstring = 54; +pub const STRING_SSH_PRIVATE_KEY: dupstring = 53; +pub const STRING_RTSP_TRANSPORT: dupstring = 52; +pub const STRING_RTSP_STREAM_URI: dupstring = 51; +pub const STRING_RTSP_SESSION_ID: dupstring = 50; +pub const STRING_NOPROXY: dupstring = 49; +pub const STRING_PROXYPASSWORD: dupstring = 48; +pub const STRING_PROXYUSERNAME: dupstring = 47; +pub const STRING_OPTIONS: dupstring = 46; +pub const STRING_PASSWORD: dupstring = 45; +pub const STRING_USERNAME: dupstring = 44; +pub const STRING_SSL_ENGINE: dupstring = 43; +pub const STRING_SSL_ISSUERCERT_PROXY: dupstring = 42; +pub const STRING_SSL_ISSUERCERT: dupstring = 41; +pub const STRING_SSL_CRLFILE_PROXY: dupstring = 40; +pub const STRING_SSL_CRLFILE: dupstring = 39; +pub const STRING_USERAGENT: dupstring = 38; +pub const STRING_SSL_RANDOM_FILE: dupstring = 37; +pub const STRING_SSL_EGDSOCKET: dupstring = 36; +pub const STRING_SSL_CIPHER13_LIST_PROXY: dupstring = 35; +pub const STRING_SSL_CIPHER13_LIST: dupstring = 34; +pub const STRING_SSL_CIPHER_LIST_PROXY: dupstring = 33; +pub const STRING_SSL_CIPHER_LIST: dupstring = 32; +pub const STRING_SSL_PINNEDPUBLICKEY_PROXY: dupstring = 31; +pub const STRING_SSL_PINNEDPUBLICKEY: dupstring = 30; +pub const STRING_SSL_CAFILE_PROXY: dupstring = 29; +pub const STRING_SSL_CAFILE: dupstring = 28; +pub const STRING_SSL_CAPATH_PROXY: dupstring = 27; +pub const STRING_SSL_CAPATH: dupstring = 26; +pub const STRING_SET_URL: dupstring = 25; +pub const STRING_SET_REFERER: dupstring = 24; +pub const STRING_SET_RANGE: dupstring = 23; +pub const STRING_PRE_PROXY: dupstring = 22; +pub const STRING_PROXY: dupstring = 21; +pub const STRING_NETRC_FILE: dupstring = 20; +pub const STRING_KRB_LEVEL: dupstring = 19; +pub const STRING_KEY_TYPE_PROXY: dupstring = 18; +pub const STRING_KEY_TYPE: dupstring = 17; +pub const STRING_KEY_PASSWD_PROXY: dupstring = 16; +pub const STRING_KEY_PASSWD: dupstring = 15; +pub const STRING_KEY_PROXY: dupstring = 14; +pub const STRING_KEY: dupstring = 13; +pub const STRING_ENCODING: dupstring = 9; +pub const STRING_DEVICE: dupstring = 8; +pub const STRING_DEFAULT_PROTOCOL: dupstring = 7; +pub const STRING_COOKIEJAR: dupstring = 5; +pub const STRING_COOKIE: dupstring = 4; +pub const STRING_CERT_TYPE_PROXY: dupstring = 3; +pub const STRING_CERT_TYPE: dupstring = 2; +pub const STRING_CERT_PROXY: dupstring = 1; +pub const STRING_CERT: dupstring = 0; +#[inline] +unsafe extern "C" fn __bswap_16(mut __bsx: __uint16_t) -> __uint16_t { + return (__bsx as libc::c_int >> 8 as libc::c_int & 0xff as libc::c_int + | (__bsx as libc::c_int & 0xff as libc::c_int) << 8 as libc::c_int) + as __uint16_t; +} +#[no_mangle] +pub static mut Curl_handler_ftp: Curl_handler = unsafe { + { + let mut init = Curl_handler { + scheme: b"FTP\0" as *const u8 as *const libc::c_char, + setup_connection: Some( + ftp_setup_connection + as unsafe extern "C" fn(*mut Curl_easy, *mut connectdata) -> CURLcode, + ), + do_it: Some( + ftp_do as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + done: Some( + ftp_done + as unsafe extern "C" fn(*mut Curl_easy, CURLcode, bool) -> CURLcode, + ), + do_more: Some( + ftp_do_more + as unsafe extern "C" fn(*mut Curl_easy, *mut libc::c_int) -> CURLcode, + ), + connect_it: Some( + ftp_connect + as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + connecting: Some( + ftp_multi_statemach + as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + doing: Some( + ftp_doing as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + proto_getsock: Some( + ftp_getsock + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + ), + doing_getsock: Some( + ftp_getsock + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + ), + domore_getsock: Some( + ftp_domore_getsock + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + ), + perform_getsock: None, + disconnect: Some( + ftp_disconnect + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + bool, + ) -> CURLcode, + ), + readwrite: None, + connection_check: None, + attach: None, + defport: 21 as libc::c_int, + protocol: ((1 as libc::c_int) << 2 as libc::c_int) as libc::c_uint, + family: ((1 as libc::c_int) << 2 as libc::c_int) as libc::c_uint, + flags: ((1 as libc::c_int) << 1 as libc::c_int + | (1 as libc::c_int) << 2 as libc::c_int + | (1 as libc::c_int) << 5 as libc::c_int + | (1 as libc::c_int) << 6 as libc::c_int + | (1 as libc::c_int) << 11 as libc::c_int + | (1 as libc::c_int) << 12 as libc::c_int) as libc::c_uint, + }; + init + } +}; +#[no_mangle] +pub static mut Curl_handler_ftps: Curl_handler = unsafe { + { + let mut init = Curl_handler { + scheme: b"FTPS\0" as *const u8 as *const libc::c_char, + setup_connection: Some( + ftp_setup_connection + as unsafe extern "C" fn(*mut Curl_easy, *mut connectdata) -> CURLcode, + ), + do_it: Some( + ftp_do as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + done: Some( + ftp_done + as unsafe extern "C" fn(*mut Curl_easy, CURLcode, bool) -> CURLcode, + ), + do_more: Some( + ftp_do_more + as unsafe extern "C" fn(*mut Curl_easy, *mut libc::c_int) -> CURLcode, + ), + connect_it: Some( + ftp_connect + as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + connecting: Some( + ftp_multi_statemach + as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + doing: Some( + ftp_doing as unsafe extern "C" fn(*mut Curl_easy, *mut bool) -> CURLcode, + ), + proto_getsock: Some( + ftp_getsock + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + ), + doing_getsock: Some( + ftp_getsock + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + ), + domore_getsock: Some( + ftp_domore_getsock + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut curl_socket_t, + ) -> libc::c_int, + ), + perform_getsock: None, + disconnect: Some( + ftp_disconnect + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + bool, + ) -> CURLcode, + ), + readwrite: None, + connection_check: None, + attach: None, + defport: 990 as libc::c_int, + protocol: ((1 as libc::c_int) << 3 as libc::c_int) as libc::c_uint, + family: ((1 as libc::c_int) << 2 as libc::c_int) as libc::c_uint, + flags: ((1 as libc::c_int) << 0 as libc::c_int + | (1 as libc::c_int) << 1 as libc::c_int + | (1 as libc::c_int) << 2 as libc::c_int + | (1 as libc::c_int) << 5 as libc::c_int + | (1 as libc::c_int) << 6 as libc::c_int + | (1 as libc::c_int) << 12 as libc::c_int) as libc::c_uint, + }; + init + } +}; +unsafe extern "C" fn close_secondarysocket( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) { + if -(1 as libc::c_int) != (*conn).sock[1 as libc::c_int as usize] { + Curl_closesocket(data, conn, (*conn).sock[1 as libc::c_int as usize]); + (*conn).sock[1 as libc::c_int as usize] = -(1 as libc::c_int); + } + (*conn).bits.tcpconnect[1 as libc::c_int as usize] = 0 as libc::c_int != 0; + (*conn).bits.proxy_ssl_connected[1 as libc::c_int as usize] = 0 as libc::c_int != 0; +} +unsafe extern "C" fn freedirs(mut ftpc: *mut ftp_conn) { + if !((*ftpc).dirs).is_null() { + let mut i: libc::c_int = 0; + i = 0 as libc::c_int; + while i < (*ftpc).dirdepth { + Curl_cfree + .expect( + "non-null function pointer", + )(*((*ftpc).dirs).offset(i as isize) as *mut libc::c_void); + let ref mut fresh0 = *((*ftpc).dirs).offset(i as isize); + *fresh0 = 0 as *mut libc::c_char; + i += 1; + } + Curl_cfree + .expect("non-null function pointer")((*ftpc).dirs as *mut libc::c_void); + let ref mut fresh1 = (*ftpc).dirs; + *fresh1 = 0 as *mut *mut libc::c_char; + (*ftpc).dirdepth = 0 as libc::c_int; + } + Curl_cfree.expect("non-null function pointer")((*ftpc).file as *mut libc::c_void); + let ref mut fresh2 = (*ftpc).file; + *fresh2 = 0 as *mut libc::c_char; + Curl_cfree.expect("non-null function pointer")((*ftpc).newhost as *mut libc::c_void); + let ref mut fresh3 = (*ftpc).newhost; + *fresh3 = 0 as *mut libc::c_char; +} +unsafe extern "C" fn AcceptServerConnect(mut data: *mut Curl_easy) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut sock: curl_socket_t = (*conn).sock[1 as libc::c_int as usize]; + let mut s: curl_socket_t = -(1 as libc::c_int); + let mut add: Curl_sockaddr_storage = Curl_sockaddr_storage { + buffer: C2RustUnnamed_9 { + sa: sockaddr { + sa_family: 0, + sa_data: [0; 14], + }, + }, + }; + let mut size: curl_socklen_t = ::std::mem::size_of::() + as libc::c_ulong as curl_socklen_t; + if 0 as libc::c_int + == getsockname( + sock, + &mut add as *mut Curl_sockaddr_storage as *mut sockaddr, + &mut size, + ) + { + size = ::std::mem::size_of::() as libc::c_ulong + as curl_socklen_t; + s = accept( + sock, + &mut add as *mut Curl_sockaddr_storage as *mut sockaddr, + &mut size, + ); + } + Curl_closesocket(data, conn, sock); + if -(1 as libc::c_int) == s { + Curl_failf( + data, + b"Error accept()ing server connect\0" as *const u8 as *const libc::c_char, + ); + return CURLE_FTP_PORT_FAILED; + } + Curl_infof( + data, + b"Connection accepted from server\0" as *const u8 as *const libc::c_char, + ); + let ref mut fresh4 = (*conn).bits; + (*fresh4).set_do_more(0 as libc::c_int as bit); + (*conn).sock[1 as libc::c_int as usize] = s; + curlx_nonblock(s, 1 as libc::c_int); + let ref mut fresh5 = (*conn).bits; + (*fresh5).set_sock_accepted(1 as libc::c_int as bit); + if ((*data).set.fsockopt).is_some() { + let mut error: libc::c_int = 0 as libc::c_int; + Curl_set_in_callback(data, 1 as libc::c_int != 0); + error = ((*data).set.fsockopt) + .expect( + "non-null function pointer", + )((*data).set.sockopt_client, s, CURLSOCKTYPE_ACCEPT); + Curl_set_in_callback(data, 0 as libc::c_int != 0); + if error != 0 { + close_secondarysocket(data, conn); + return CURLE_ABORTED_BY_CALLBACK; + } + } + return CURLE_OK; +} +unsafe extern "C" fn ftp_timeleft_accept(mut data: *mut Curl_easy) -> timediff_t { + let mut timeout_ms: timediff_t = 60000 as libc::c_int as timediff_t; + let mut other: timediff_t = 0; + let mut now: curltime = curltime { tv_sec: 0, tv_usec: 0 }; + if (*data).set.accepttimeout > 0 as libc::c_int as libc::c_long { + timeout_ms = (*data).set.accepttimeout; + } + now = Curl_now(); + other = Curl_timeleft(data, &mut now, 0 as libc::c_int != 0); + if other != 0 && other < timeout_ms { + timeout_ms = other; + } else { + timeout_ms -= Curl_timediff(now, (*data).progress.t_acceptdata); + if timeout_ms == 0 { + return -(1 as libc::c_int) as timediff_t; + } + } + return timeout_ms; +} +unsafe extern "C" fn ReceivedServerConnect( + mut data: *mut Curl_easy, + mut received: *mut bool, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ctrl_sock: curl_socket_t = (*conn).sock[0 as libc::c_int as usize]; + let mut data_sock: curl_socket_t = (*conn).sock[1 as libc::c_int as usize]; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + let mut result: libc::c_int = 0; + let mut timeout_ms: timediff_t = 0; + let mut nread: ssize_t = 0; + let mut ftpcode: libc::c_int = 0; + *received = 0 as libc::c_int != 0; + timeout_ms = ftp_timeleft_accept(data); + Curl_infof( + data, + b"Checking for server connect\0" as *const u8 as *const libc::c_char, + ); + if timeout_ms < 0 as libc::c_int as libc::c_long { + Curl_failf( + data, + b"Accept timeout occurred while waiting server connect\0" as *const u8 + as *const libc::c_char, + ); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + if (*pp).cache_size != 0 && !((*pp).cache).is_null() + && *((*pp).cache).offset(0 as libc::c_int as isize) as libc::c_int > '3' as i32 + { + Curl_infof( + data, + b"There is negative response in cache while serv connect\0" as *const u8 + as *const libc::c_char, + ); + Curl_GetFTPResponse(data, &mut nread, &mut ftpcode); + return CURLE_FTP_ACCEPT_FAILED; + } + result = Curl_socket_check( + ctrl_sock, + data_sock, + -(1 as libc::c_int), + 0 as libc::c_int as timediff_t, + ); + match result { + -1 => { + Curl_failf( + data, + b"Error while waiting for server connect\0" as *const u8 + as *const libc::c_char, + ); + return CURLE_FTP_ACCEPT_FAILED; + } + 0 => {} + _ => { + if result & (0x4 as libc::c_int) << 1 as libc::c_int != 0 { + Curl_infof( + data, + b"Ready to accept data connection from server\0" as *const u8 + as *const libc::c_char, + ); + *received = 1 as libc::c_int != 0; + } else if result & 0x1 as libc::c_int != 0 { + Curl_infof( + data, + b"Ctrl conn has data while waiting for data conn\0" as *const u8 + as *const libc::c_char, + ); + Curl_GetFTPResponse(data, &mut nread, &mut ftpcode); + if ftpcode / 100 as libc::c_int > 3 as libc::c_int { + return CURLE_FTP_ACCEPT_FAILED; + } + return CURLE_WEIRD_SERVER_REPLY; + } + } + } + return CURLE_OK; +} +unsafe extern "C" fn InitiateTransfer(mut data: *mut Curl_easy) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + if ((*conn).bits).ftp_use_data_ssl() != 0 { + Curl_infof( + data, + b"Doing the SSL/TLS handshake on the data stream\0" as *const u8 + as *const libc::c_char, + ); + result = Curl_ssl_connect(data, conn, 1 as libc::c_int); + if result as u64 != 0 { + return result; + } + } + if (*conn).proto.ftpc.state_saved as libc::c_uint + == FTP_STOR as libc::c_int as libc::c_uint + { + Curl_pgrsSetUploadSize(data, (*data).state.infilesize); + Curl_setup_transfer( + data, + -(1 as libc::c_int), + -(1 as libc::c_int) as curl_off_t, + 0 as libc::c_int != 0, + 1 as libc::c_int, + ); + } else { + Curl_setup_transfer( + data, + 1 as libc::c_int, + (*conn).proto.ftpc.retr_size_saved, + 0 as libc::c_int != 0, + -(1 as libc::c_int), + ); + } + (*conn).proto.ftpc.pp.pending_resp = 1 as libc::c_int != 0; + _state(data, FTP_STOP); + return CURLE_OK; +} +unsafe extern "C" fn AllowServerConnect( + mut data: *mut Curl_easy, + mut connected: *mut bool, +) -> CURLcode { + let mut timeout_ms: timediff_t = 0; + let mut result: CURLcode = CURLE_OK; + *connected = 0 as libc::c_int != 0; + Curl_infof( + data, + b"Preparing for accepting server on data port\0" as *const u8 + as *const libc::c_char, + ); + Curl_pgrsTime(data, TIMER_STARTACCEPT); + timeout_ms = ftp_timeleft_accept(data); + if timeout_ms < 0 as libc::c_int as libc::c_long { + Curl_failf( + data, + b"Accept timeout occurred while waiting server connect\0" as *const u8 + as *const libc::c_char, + ); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + result = ReceivedServerConnect(data, connected); + if result as u64 != 0 { + return result; + } + if *connected { + result = AcceptServerConnect(data); + if result as u64 != 0 { + return result; + } + result = InitiateTransfer(data); + if result as u64 != 0 { + return result; + } + } else if *connected as libc::c_int == 0 as libc::c_int { + Curl_expire( + data, + if (*data).set.accepttimeout > 0 as libc::c_int as libc::c_long { + (*data).set.accepttimeout + } else { + 60000 as libc::c_int as libc::c_long + }, + EXPIRE_100_TIMEOUT, + ); + } + return result; +} +unsafe extern "C" fn ftp_endofresp( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut line: *mut libc::c_char, + mut len: size_t, + mut code: *mut libc::c_int, +) -> bool { + if len > 3 as libc::c_int as libc::c_ulong + && (Curl_isdigit( + *line.offset(0 as libc::c_int as isize) as libc::c_uchar as libc::c_int, + ) != 0 + && Curl_isdigit( + *line.offset(1 as libc::c_int as isize) as libc::c_uchar as libc::c_int, + ) != 0 + && Curl_isdigit( + *line.offset(2 as libc::c_int as isize) as libc::c_uchar as libc::c_int, + ) != 0 + && ' ' as i32 == *line.offset(3 as libc::c_int as isize) as libc::c_int) + { + *code = curlx_sltosi( + strtol(line, 0 as *mut *mut libc::c_char, 10 as libc::c_int), + ); + return 1 as libc::c_int != 0; + } + return 0 as libc::c_int != 0; +} +unsafe extern "C" fn ftp_readresp( + mut data: *mut Curl_easy, + mut sockfd: curl_socket_t, + mut pp: *mut pingpong, + mut ftpcode: *mut libc::c_int, + mut size: *mut size_t, +) -> CURLcode { + let mut code: libc::c_int = 0; + let mut result: CURLcode = Curl_pp_readresp(data, sockfd, pp, &mut code, size); + (*data).info.httpcode = code; + if !ftpcode.is_null() { + *ftpcode = code; + } + if 421 as libc::c_int == code { + Curl_infof( + data, + b"We got a 421 - timeout!\0" as *const u8 as *const libc::c_char, + ); + _state(data, FTP_STOP); + return CURLE_OPERATION_TIMEDOUT; + } + return result; +} +#[no_mangle] +pub unsafe extern "C" fn Curl_GetFTPResponse( + mut data: *mut Curl_easy, + mut nreadp: *mut ssize_t, + mut ftpcode: *mut libc::c_int, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut sockfd: curl_socket_t = (*conn).sock[0 as libc::c_int as usize]; + let mut result: CURLcode = CURLE_OK; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + let mut nread: size_t = 0; + let mut cache_skip: libc::c_int = 0 as libc::c_int; + let mut value_to_be_ignored: libc::c_int = 0 as libc::c_int; + if !ftpcode.is_null() { + *ftpcode = 0 as libc::c_int; + } else { + ftpcode = &mut value_to_be_ignored; + } + *nreadp = 0 as libc::c_int as ssize_t; + let mut current_block_20: u64; + while *ftpcode == 0 && result as u64 == 0 { + let mut timeout: timediff_t = Curl_pp_state_timeout( + data, + pp, + 0 as libc::c_int != 0, + ); + let mut interval_ms: timediff_t = 0; + if timeout <= 0 as libc::c_int as libc::c_long { + Curl_failf( + data, + b"FTP response timeout\0" as *const u8 as *const libc::c_char, + ); + return CURLE_OPERATION_TIMEDOUT; + } + interval_ms = 1000 as libc::c_int as timediff_t; + if timeout < interval_ms { + interval_ms = timeout; + } + if !(!((*pp).cache).is_null() && cache_skip < 2 as libc::c_int) { + if !Curl_conn_data_pending(conn, 0 as libc::c_int) { + match Curl_socket_check( + sockfd, + -(1 as libc::c_int), + -(1 as libc::c_int), + interval_ms, + ) { + -1 => { + current_block_20 = 30138434020917367; + match current_block_20 { + 30138434020917367 => { + Curl_failf( + data, + b"FTP response aborted due to select/poll error: %d\0" + as *const u8 as *const libc::c_char, + *__errno_location(), + ); + return CURLE_RECV_ERROR; + } + _ => { + if Curl_pgrsUpdate(data) != 0 { + return CURLE_ABORTED_BY_CALLBACK; + } + continue; + } + } + } + 0 => { + current_block_20 = 4838030885599732913; + match current_block_20 { + 30138434020917367 => { + Curl_failf( + data, + b"FTP response aborted due to select/poll error: %d\0" + as *const u8 as *const libc::c_char, + *__errno_location(), + ); + return CURLE_RECV_ERROR; + } + _ => { + if Curl_pgrsUpdate(data) != 0 { + return CURLE_ABORTED_BY_CALLBACK; + } + continue; + } + } + } + _ => {} + } + } + } + result = ftp_readresp(data, sockfd, pp, ftpcode, &mut nread); + if result as u64 != 0 { + break; + } + if nread == 0 && !((*pp).cache).is_null() { + cache_skip += 1; + } else { + cache_skip = 0 as libc::c_int; + } + *nreadp = (*nreadp as libc::c_ulong).wrapping_add(nread) as ssize_t as ssize_t; + } + (*pp).pending_resp = 0 as libc::c_int != 0; + return result; +} +unsafe extern "C" fn _state(mut data: *mut Curl_easy, mut newstate: ftpstate) { + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + (*ftpc).state = newstate; +} +unsafe extern "C" fn ftp_state_user( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = Curl_pp_sendf( + data, + &mut (*conn).proto.ftpc.pp as *mut pingpong, + b"USER %s\0" as *const u8 as *const libc::c_char, + if !((*conn).user).is_null() { + (*conn).user as *const libc::c_char + } else { + b"\0" as *const u8 as *const libc::c_char + }, + ); + if result as u64 == 0 { + _state(data, FTP_USER); + let ref mut fresh6 = (*data).state; + (*fresh6).set_ftp_trying_alternative(0 as libc::c_int as bit); + } + return result; +} +unsafe extern "C" fn ftp_state_pwd( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = Curl_pp_sendf( + data, + &mut (*conn).proto.ftpc.pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + b"PWD\0" as *const u8 as *const libc::c_char, + ); + if result as u64 == 0 { + _state(data, FTP_PWD); + } + return result; +} +unsafe extern "C" fn ftp_getsock( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut socks: *mut curl_socket_t, +) -> libc::c_int { + return Curl_pp_getsock(data, &mut (*conn).proto.ftpc.pp, socks); +} +unsafe extern "C" fn ftp_domore_getsock( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut socks: *mut curl_socket_t, +) -> libc::c_int { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if (*conn).cnnct.state as libc::c_uint + >= CONNECT_SOCKS_INIT as libc::c_int as libc::c_uint + && ((*conn).cnnct.state as libc::c_uint) + < CONNECT_DONE as libc::c_int as libc::c_uint + { + return Curl_SOCKS_getsock(conn, socks, 1 as libc::c_int); + } + if FTP_STOP as libc::c_int as libc::c_uint == (*ftpc).state as libc::c_uint { + let mut bits: libc::c_int = (1 as libc::c_int) << 0 as libc::c_int; + let mut any: bool = 0 as libc::c_int != 0; + *socks + .offset(0 as libc::c_int as isize) = (*conn).sock[0 as libc::c_int as usize]; + if ((*data).set).ftp_use_port() == 0 { + let mut s: libc::c_int = 0; + let mut i: libc::c_int = 0; + s = 1 as libc::c_int; + i = 0 as libc::c_int; + while i < 2 as libc::c_int { + if (*conn).tempsock[i as usize] != -(1 as libc::c_int) { + *socks.offset(s as isize) = (*conn).tempsock[i as usize]; + let fresh7 = s; + s = s + 1; + bits |= (1 as libc::c_int) << 16 as libc::c_int + fresh7; + any = 1 as libc::c_int != 0; + } + i += 1; + } + } + if !any { + *socks + .offset( + 1 as libc::c_int as isize, + ) = (*conn).sock[1 as libc::c_int as usize]; + bits + |= (1 as libc::c_int) << 16 as libc::c_int + 1 as libc::c_int + | (1 as libc::c_int) << 1 as libc::c_int; + } + return bits; + } + return Curl_pp_getsock(data, &mut (*conn).proto.ftpc.pp, socks); +} +unsafe extern "C" fn ftp_state_cwd( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if (*ftpc).cwddone { + result = ftp_state_mdtm(data); + } else { + (*ftpc).count2 = 0 as libc::c_int; + (*ftpc) + .count3 = if (*data).set.ftp_create_missing_dirs == 2 as libc::c_int { + 1 as libc::c_int + } else { + 0 as libc::c_int + }; + if ((*conn).bits).reuse() as libc::c_int != 0 && !((*ftpc).entrypath).is_null() + && !((*ftpc).dirdepth != 0 + && *(*((*ftpc).dirs).offset(0 as libc::c_int as isize)) + .offset(0 as libc::c_int as isize) as libc::c_int == '/' as i32) + { + (*ftpc).cwdcount = 0 as libc::c_int; + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"CWD %s\0" as *const u8 as *const libc::c_char, + (*ftpc).entrypath, + ); + if result as u64 == 0 { + _state(data, FTP_CWD); + } + } else if (*ftpc).dirdepth != 0 { + (*ftpc).cwdcount = 1 as libc::c_int; + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"CWD %s\0" as *const u8 as *const libc::c_char, + *((*ftpc).dirs).offset(((*ftpc).cwdcount - 1 as libc::c_int) as isize), + ); + if result as u64 == 0 { + _state(data, FTP_CWD); + } + } else { + result = ftp_state_mdtm(data); + } + } + return result; +} +unsafe extern "C" fn ftp_state_use_port( + mut data: *mut Curl_easy, + mut fcmd: ftpport, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut portsock: curl_socket_t = -(1 as libc::c_int); + let mut myhost: [libc::c_char; 47] = *::std::mem::transmute::< + &[u8; 47], + &mut [libc::c_char; 47], + >( + b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", + ); + let mut ss: Curl_sockaddr_storage = Curl_sockaddr_storage { + buffer: C2RustUnnamed_9 { + sa: sockaddr { + sa_family: 0, + sa_data: [0; 14], + }, + }, + }; + let mut res: *mut Curl_addrinfo = 0 as *mut Curl_addrinfo; + let mut ai: *mut Curl_addrinfo = 0 as *mut Curl_addrinfo; + let mut sslen: curl_socklen_t = 0; + let mut hbuf: [libc::c_char; 1025] = [0; 1025]; + let mut sa: *mut sockaddr = &mut ss as *mut Curl_sockaddr_storage as *mut sockaddr; + let sa4: *mut sockaddr_in = sa as *mut libc::c_void as *mut sockaddr_in; + let sa6: *mut sockaddr_in6 = sa as *mut libc::c_void as *mut sockaddr_in6; + static mut mode: [[libc::c_char; 5]; 2] = unsafe { + [ + *::std::mem::transmute::<&[u8; 5], &[libc::c_char; 5]>(b"EPRT\0"), + *::std::mem::transmute::<&[u8; 5], &[libc::c_char; 5]>(b"PORT\0"), + ] + }; + let mut rc: resolve_t = CURLRESOLV_RESOLVED; + let mut error: libc::c_int = 0; + let mut host: *mut libc::c_char = 0 as *mut libc::c_char; + let mut string_ftpport: *mut libc::c_char = (*data) + .set + .str_0[STRING_FTPPORT as libc::c_int as usize]; + let mut h: *mut Curl_dns_entry = 0 as *mut Curl_dns_entry; + let mut port_min: libc::c_ushort = 0 as libc::c_int as libc::c_ushort; + let mut port_max: libc::c_ushort = 0 as libc::c_int as libc::c_ushort; + let mut port: libc::c_ushort = 0; + let mut possibly_non_local: bool = 1 as libc::c_int != 0; + let mut buffer: [libc::c_char; 256] = [0; 256]; + let mut addr: *mut libc::c_char = 0 as *mut libc::c_char; + if !((*data).set.str_0[STRING_FTPPORT as libc::c_int as usize]).is_null() + && strlen((*data).set.str_0[STRING_FTPPORT as libc::c_int as usize]) + > 1 as libc::c_int as libc::c_ulong + { + let mut addrlen: size_t = if 46 as libc::c_int as libc::c_ulong + > strlen(string_ftpport) + { + 46 as libc::c_int as libc::c_ulong + } else { + strlen(string_ftpport) + }; + let mut ip_start: *mut libc::c_char = string_ftpport; + let mut ip_end: *mut libc::c_char = 0 as *mut libc::c_char; + let mut port_start: *mut libc::c_char = 0 as *mut libc::c_char; + let mut port_sep: *mut libc::c_char = 0 as *mut libc::c_char; + addr = Curl_ccalloc + .expect( + "non-null function pointer", + )( + addrlen.wrapping_add(1 as libc::c_int as libc::c_ulong), + 1 as libc::c_int as size_t, + ) as *mut libc::c_char; + if addr.is_null() { + return CURLE_OUT_OF_MEMORY; + } + if *string_ftpport as libc::c_int == '[' as i32 { + ip_start = string_ftpport.offset(1 as libc::c_int as isize); + ip_end = strchr(string_ftpport, ']' as i32); + if !ip_end.is_null() { + strncpy( + addr, + ip_start, + ip_end.offset_from(ip_start) as libc::c_long as libc::c_ulong, + ); + } + } else if *string_ftpport as libc::c_int == ':' as i32 { + ip_end = string_ftpport; + } else { + ip_end = strchr(string_ftpport, ':' as i32); + if !ip_end.is_null() { + if inet_pton(10 as libc::c_int, string_ftpport, sa6 as *mut libc::c_void) + == 1 as libc::c_int + { + port_max = 0 as libc::c_int as libc::c_ushort; + port_min = port_max; + strcpy(addr, string_ftpport); + ip_end = 0 as *mut libc::c_char; + } else { + strncpy( + addr, + string_ftpport, + ip_end.offset_from(ip_start) as libc::c_long as libc::c_ulong, + ); + } + } else { + strcpy(addr, string_ftpport); + } + } + if !ip_end.is_null() { + port_start = strchr(ip_end, ':' as i32); + if !port_start.is_null() { + port_min = curlx_ultous( + strtoul( + port_start.offset(1 as libc::c_int as isize), + 0 as *mut *mut libc::c_char, + 10 as libc::c_int, + ), + ); + port_sep = strchr(port_start, '-' as i32); + if !port_sep.is_null() { + port_max = curlx_ultous( + strtoul( + port_sep.offset(1 as libc::c_int as isize), + 0 as *mut *mut libc::c_char, + 10 as libc::c_int, + ), + ); + } else { + port_max = port_min; + } + } + } + if port_min as libc::c_int > port_max as libc::c_int { + port_max = 0 as libc::c_int as libc::c_ushort; + port_min = port_max; + } + if *addr as libc::c_int != '\u{0}' as i32 { + match Curl_if2ip( + (*(*conn).ip_addr).ai_family, + Curl_ipv6_scope((*(*conn).ip_addr).ai_addr), + (*conn).scope_id, + addr, + hbuf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1025]>() as libc::c_ulong + as libc::c_int, + ) as libc::c_uint + { + 0 => { + host = addr; + } + 1 => return CURLE_FTP_PORT_FAILED, + 2 => { + host = hbuf.as_mut_ptr(); + } + _ => {} + } + } else { + host = 0 as *mut libc::c_char; + } + } + if host.is_null() { + let mut r: *const libc::c_char = 0 as *const libc::c_char; + sslen = ::std::mem::size_of::() as libc::c_ulong + as curl_socklen_t; + if getsockname((*conn).sock[0 as libc::c_int as usize], sa, &mut sslen) != 0 { + Curl_failf( + data, + b"getsockname() failed: %s\0" as *const u8 as *const libc::c_char, + Curl_strerror( + *__errno_location(), + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + Curl_cfree.expect("non-null function pointer")(addr as *mut libc::c_void); + return CURLE_FTP_PORT_FAILED; + } + match (*sa).sa_family as libc::c_int { + 10 => { + r = inet_ntop( + (*sa).sa_family as libc::c_int, + &mut (*sa6).sin6_addr as *mut in6_addr as *const libc::c_void, + hbuf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1025]>() as libc::c_ulong + as curl_socklen_t, + ); + } + _ => { + r = inet_ntop( + (*sa).sa_family as libc::c_int, + &mut (*sa4).sin_addr as *mut in_addr as *const libc::c_void, + hbuf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1025]>() as libc::c_ulong + as curl_socklen_t, + ); + } + } + if r.is_null() { + return CURLE_FTP_PORT_FAILED; + } + host = hbuf.as_mut_ptr(); + possibly_non_local = 0 as libc::c_int != 0; + } + rc = Curl_resolv(data, host, 0 as libc::c_int, 0 as libc::c_int != 0, &mut h); + if rc as libc::c_int == CURLRESOLV_PENDING as libc::c_int { + Curl_resolver_wait_resolv(data, &mut h); + } + if !h.is_null() { + res = (*h).addr; + Curl_resolv_unlock(data, h); + } else { + res = 0 as *mut Curl_addrinfo; + } + if res.is_null() { + Curl_failf( + data, + b"failed to resolve the address provided to PORT: %s\0" as *const u8 + as *const libc::c_char, + host, + ); + Curl_cfree.expect("non-null function pointer")(addr as *mut libc::c_void); + return CURLE_FTP_PORT_FAILED; + } + Curl_cfree.expect("non-null function pointer")(addr as *mut libc::c_void); + host = 0 as *mut libc::c_char; + portsock = -(1 as libc::c_int); + error = 0 as libc::c_int; + ai = res; + while !ai.is_null() { + result = Curl_socket(data, ai, 0 as *mut Curl_sockaddr_ex, &mut portsock); + if !(result as u64 != 0) { + break; + } + error = *__errno_location(); + ai = (*ai).ai_next; + } + if ai.is_null() { + Curl_failf( + data, + b"socket failure: %s\0" as *const u8 as *const libc::c_char, + Curl_strerror( + error, + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + return CURLE_FTP_PORT_FAILED; + } + memcpy( + sa as *mut libc::c_void, + (*ai).ai_addr as *const libc::c_void, + (*ai).ai_addrlen as libc::c_ulong, + ); + sslen = (*ai).ai_addrlen; + port = port_min; + while port as libc::c_int <= port_max as libc::c_int { + if (*sa).sa_family as libc::c_int == 2 as libc::c_int { + (*sa4).sin_port = __bswap_16(port); + } else { + (*sa6).sin6_port = __bswap_16(port); + } + if !(bind(portsock, sa, sslen) != 0) { + break; + } + error = *__errno_location(); + if possibly_non_local as libc::c_int != 0 && error == 99 as libc::c_int { + Curl_infof( + data, + b"bind(port=%hu) on non-local address failed: %s\0" as *const u8 + as *const libc::c_char, + port as libc::c_int, + Curl_strerror( + error, + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + sslen = ::std::mem::size_of::() as libc::c_ulong + as curl_socklen_t; + if getsockname((*conn).sock[0 as libc::c_int as usize], sa, &mut sslen) != 0 + { + Curl_failf( + data, + b"getsockname() failed: %s\0" as *const u8 as *const libc::c_char, + Curl_strerror( + *__errno_location(), + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + Curl_closesocket(data, conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + port = port_min; + possibly_non_local = 0 as libc::c_int != 0; + } else { + if error != 98 as libc::c_int && error != 13 as libc::c_int { + Curl_failf( + data, + b"bind(port=%hu) failed: %s\0" as *const u8 as *const libc::c_char, + port as libc::c_int, + Curl_strerror( + error, + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + Curl_closesocket(data, conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + port = port.wrapping_add(1); + } + } + if port as libc::c_int > port_max as libc::c_int { + Curl_failf( + data, + b"bind() failed, we ran out of ports!\0" as *const u8 as *const libc::c_char, + ); + Curl_closesocket(data, conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + sslen = ::std::mem::size_of::() as libc::c_ulong + as curl_socklen_t; + if getsockname(portsock, sa, &mut sslen) != 0 { + Curl_failf( + data, + b"getsockname() failed: %s\0" as *const u8 as *const libc::c_char, + Curl_strerror( + *__errno_location(), + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + Curl_closesocket(data, conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + if listen(portsock, 1 as libc::c_int) != 0 { + Curl_failf( + data, + b"socket failure: %s\0" as *const u8 as *const libc::c_char, + Curl_strerror( + *__errno_location(), + buffer.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ), + ); + Curl_closesocket(data, conn, portsock); + return CURLE_FTP_PORT_FAILED; + } + Curl_printable_address( + ai, + myhost.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 47]>() as libc::c_ulong, + ); + if ((*conn).bits).ftp_use_eprt() == 0 && ((*conn).bits).ipv6() as libc::c_int != 0 { + let ref mut fresh8 = (*conn).bits; + (*fresh8).set_ftp_use_eprt(1 as libc::c_int as bit); + } + let mut current_block_152: u64; + while fcmd as libc::c_uint != DONE as libc::c_int as libc::c_uint { + if !(((*conn).bits).ftp_use_eprt() == 0 + && EPRT as libc::c_int as libc::c_uint == fcmd as libc::c_uint) + { + if !(PORT as libc::c_int as libc::c_uint == fcmd as libc::c_uint + && (*sa).sa_family as libc::c_int != 2 as libc::c_int) + { + match (*sa).sa_family as libc::c_int { + 2 => { + current_block_152 = 5173505947521674114; + match current_block_152 { + 6897641277760232815 => { + port = __bswap_16((*sa6).sin6_port); + } + _ => { + port = __bswap_16((*sa4).sin_port); + } + } + if EPRT as libc::c_int as libc::c_uint == fcmd as libc::c_uint { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s |%d|%s|%hu|\0" as *const u8 as *const libc::c_char, + (mode[fcmd as usize]).as_ptr(), + if (*sa).sa_family as libc::c_int == 2 as libc::c_int { + 1 as libc::c_int + } else { + 2 as libc::c_int + }, + myhost.as_mut_ptr(), + port as libc::c_int, + ); + if result as u64 != 0 { + Curl_failf( + data, + b"Failure sending EPRT command: %s\0" as *const u8 + as *const libc::c_char, + curl_easy_strerror(result), + ); + Curl_closesocket(data, conn, portsock); + (*ftpc).count1 = PORT as libc::c_int; + _state(data, FTP_STOP); + return result; + } + break; + } else if PORT as libc::c_int as libc::c_uint + == fcmd as libc::c_uint + { + let mut target: [libc::c_char; 67] = [0; 67]; + let mut source: *mut libc::c_char = myhost.as_mut_ptr(); + let mut dest: *mut libc::c_char = target.as_mut_ptr(); + while !source.is_null() && *source as libc::c_int != 0 { + if *source as libc::c_int == '.' as i32 { + *dest = ',' as i32 as libc::c_char; + } else { + *dest = *source; + } + dest = dest.offset(1); + source = source.offset(1); + } + *dest = 0 as libc::c_int as libc::c_char; + curl_msnprintf( + dest, + 20 as libc::c_int as size_t, + b",%d,%d\0" as *const u8 as *const libc::c_char, + port as libc::c_int >> 8 as libc::c_int, + port as libc::c_int & 0xff as libc::c_int, + ); + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s %s\0" as *const u8 as *const libc::c_char, + (mode[fcmd as usize]).as_ptr(), + target.as_mut_ptr(), + ); + if result as u64 != 0 { + Curl_failf( + data, + b"Failure sending PORT command: %s\0" as *const u8 + as *const libc::c_char, + curl_easy_strerror(result), + ); + Curl_closesocket(data, conn, portsock); + _state(data, FTP_STOP); + return result; + } + break; + } + } + 10 => { + current_block_152 = 6897641277760232815; + match current_block_152 { + 6897641277760232815 => { + port = __bswap_16((*sa6).sin6_port); + } + _ => { + port = __bswap_16((*sa4).sin_port); + } + } + if EPRT as libc::c_int as libc::c_uint == fcmd as libc::c_uint { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s |%d|%s|%hu|\0" as *const u8 as *const libc::c_char, + (mode[fcmd as usize]).as_ptr(), + if (*sa).sa_family as libc::c_int == 2 as libc::c_int { + 1 as libc::c_int + } else { + 2 as libc::c_int + }, + myhost.as_mut_ptr(), + port as libc::c_int, + ); + if result as u64 != 0 { + Curl_failf( + data, + b"Failure sending EPRT command: %s\0" as *const u8 + as *const libc::c_char, + curl_easy_strerror(result), + ); + Curl_closesocket(data, conn, portsock); + (*ftpc).count1 = PORT as libc::c_int; + _state(data, FTP_STOP); + return result; + } + break; + } else if PORT as libc::c_int as libc::c_uint + == fcmd as libc::c_uint + { + let mut target: [libc::c_char; 67] = [0; 67]; + let mut source: *mut libc::c_char = myhost.as_mut_ptr(); + let mut dest: *mut libc::c_char = target.as_mut_ptr(); + while !source.is_null() && *source as libc::c_int != 0 { + if *source as libc::c_int == '.' as i32 { + *dest = ',' as i32 as libc::c_char; + } else { + *dest = *source; + } + dest = dest.offset(1); + source = source.offset(1); + } + *dest = 0 as libc::c_int as libc::c_char; + curl_msnprintf( + dest, + 20 as libc::c_int as size_t, + b",%d,%d\0" as *const u8 as *const libc::c_char, + port as libc::c_int >> 8 as libc::c_int, + port as libc::c_int & 0xff as libc::c_int, + ); + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s %s\0" as *const u8 as *const libc::c_char, + (mode[fcmd as usize]).as_ptr(), + target.as_mut_ptr(), + ); + if result as u64 != 0 { + Curl_failf( + data, + b"Failure sending PORT command: %s\0" as *const u8 + as *const libc::c_char, + curl_easy_strerror(result), + ); + Curl_closesocket(data, conn, portsock); + _state(data, FTP_STOP); + return result; + } + break; + } + } + _ => {} + } + } + } + fcmd += 1; + } + (*ftpc).count1 = fcmd as libc::c_int; + close_secondarysocket(data, conn); + (*conn).sock[1 as libc::c_int as usize] = portsock; + (*conn).bits.tcpconnect[1 as libc::c_int as usize] = 1 as libc::c_int != 0; + _state(data, FTP_PORT); + return result; +} +unsafe extern "C" fn ftp_state_use_pasv( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut result: CURLcode = CURLE_OK; + static mut mode: [[libc::c_char; 5]; 2] = unsafe { + [ + *::std::mem::transmute::<&[u8; 5], &[libc::c_char; 5]>(b"EPSV\0"), + *::std::mem::transmute::<&[u8; 5], &[libc::c_char; 5]>(b"PASV\0"), + ] + }; + let mut modeoff: libc::c_int = 0; + if ((*conn).bits).ftp_use_epsv() == 0 && ((*conn).bits).ipv6() as libc::c_int != 0 { + let ref mut fresh9 = (*conn).bits; + (*fresh9).set_ftp_use_epsv(1 as libc::c_int as bit); + } + modeoff = if ((*conn).bits).ftp_use_epsv() as libc::c_int != 0 { + 0 as libc::c_int + } else { + 1 as libc::c_int + }; + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + (mode[modeoff as usize]).as_ptr(), + ); + if result as u64 == 0 { + (*ftpc).count1 = modeoff; + _state(data, FTP_PASV); + Curl_infof( + data, + b"Connect data stream passively\0" as *const u8 as *const libc::c_char, + ); + } + return result; +} +unsafe extern "C" fn ftp_state_prepare_transfer(mut data: *mut Curl_easy) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + if (*ftp).transfer as libc::c_uint != PPTRANSFER_BODY as libc::c_int as libc::c_uint + { + _state(data, FTP_RETR_PREQUOTE); + result = ftp_state_quote(data, 1 as libc::c_int != 0, FTP_RETR_PREQUOTE); + } else if ((*data).set).ftp_use_port() != 0 { + result = ftp_state_use_port(data, EPRT); + } else if ((*data).set).ftp_use_pret() != 0 { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if ((*conn).proto.ftpc.file).is_null() { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"PRET %s\0" as *const u8 as *const libc::c_char, + if !((*data).set.str_0[STRING_CUSTOMREQUEST as libc::c_int as usize]) + .is_null() + { + (*data).set.str_0[STRING_CUSTOMREQUEST as libc::c_int as usize] + as *const libc::c_char + } else if ((*data).state).list_only() as libc::c_int != 0 { + b"NLST\0" as *const u8 as *const libc::c_char + } else { + b"LIST\0" as *const u8 as *const libc::c_char + }, + ); + } else if ((*data).set).upload() != 0 { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"PRET STOR %s\0" as *const u8 as *const libc::c_char, + (*conn).proto.ftpc.file, + ); + } else { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"PRET RETR %s\0" as *const u8 as *const libc::c_char, + (*conn).proto.ftpc.file, + ); + } + if result as u64 == 0 { + _state(data, FTP_PRET); + } + } else { + result = ftp_state_use_pasv(data, conn); + } + return result; +} +unsafe extern "C" fn ftp_state_rest( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if (*ftp).transfer as libc::c_uint != PPTRANSFER_BODY as libc::c_int as libc::c_uint + && !((*ftpc).file).is_null() + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"REST %d\0" as *const u8 as *const libc::c_char, + 0 as libc::c_int, + ); + if result as u64 == 0 { + _state(data, FTP_REST); + } + } else { + result = ftp_state_prepare_transfer(data); + } + return result; +} +unsafe extern "C" fn ftp_state_size( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if (*ftp).transfer as libc::c_uint == PPTRANSFER_INFO as libc::c_int as libc::c_uint + && !((*ftpc).file).is_null() + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"SIZE %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_SIZE); + } + } else { + result = ftp_state_rest(data, conn); + } + return result; +} +unsafe extern "C" fn ftp_state_list(mut data: *mut Curl_easy) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + let mut lstArg: *mut libc::c_char = 0 as *mut libc::c_char; + let mut cmd: *mut libc::c_char = 0 as *mut libc::c_char; + if (*data).set.ftp_filemethod as libc::c_uint + == FTPFILE_NOCWD as libc::c_int as libc::c_uint && !((*ftp).path).is_null() + { + let mut slashPos: *const libc::c_char = 0 as *const libc::c_char; + let mut rawPath: *mut libc::c_char = 0 as *mut libc::c_char; + result = Curl_urldecode( + data, + (*ftp).path, + 0 as libc::c_int as size_t, + &mut rawPath, + 0 as *mut size_t, + REJECT_CTRL, + ); + if result as u64 != 0 { + return result; + } + slashPos = strrchr(rawPath, '/' as i32); + if !slashPos.is_null() { + let mut n: size_t = slashPos.offset_from(rawPath) as libc::c_long as size_t; + if n == 0 as libc::c_int as libc::c_ulong { + n = n.wrapping_add(1); + } + lstArg = rawPath; + *lstArg.offset(n as isize) = '\u{0}' as i32 as libc::c_char; + } else { + Curl_cfree.expect("non-null function pointer")(rawPath as *mut libc::c_void); + } + } + cmd = curl_maprintf( + b"%s%s%s\0" as *const u8 as *const libc::c_char, + if !((*data).set.str_0[STRING_CUSTOMREQUEST as libc::c_int as usize]).is_null() { + (*data).set.str_0[STRING_CUSTOMREQUEST as libc::c_int as usize] + as *const libc::c_char + } else if ((*data).state).list_only() as libc::c_int != 0 { + b"NLST\0" as *const u8 as *const libc::c_char + } else { + b"LIST\0" as *const u8 as *const libc::c_char + }, + if !lstArg.is_null() { + b" \0" as *const u8 as *const libc::c_char + } else { + b"\0" as *const u8 as *const libc::c_char + }, + if !lstArg.is_null() { + lstArg as *const libc::c_char + } else { + b"\0" as *const u8 as *const libc::c_char + }, + ); + Curl_cfree.expect("non-null function pointer")(lstArg as *mut libc::c_void); + if cmd.is_null() { + return CURLE_OUT_OF_MEMORY; + } + result = Curl_pp_sendf( + data, + &mut (*conn).proto.ftpc.pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + cmd, + ); + Curl_cfree.expect("non-null function pointer")(cmd as *mut libc::c_void); + if result as u64 == 0 { + _state(data, FTP_LIST); + } + return result; +} +unsafe extern "C" fn ftp_state_retr_prequote(mut data: *mut Curl_easy) -> CURLcode { + return ftp_state_quote(data, 1 as libc::c_int != 0, FTP_RETR_PREQUOTE); +} +unsafe extern "C" fn ftp_state_stor_prequote(mut data: *mut Curl_easy) -> CURLcode { + return ftp_state_quote(data, 1 as libc::c_int != 0, FTP_STOR_PREQUOTE); +} +unsafe extern "C" fn ftp_state_type(mut data: *mut Curl_easy) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if ((*data).set).opt_no_body() as libc::c_int != 0 && !((*ftpc).file).is_null() + && ftp_need_type(conn, ((*data).state).prefer_ascii() != 0) != 0 + { + (*ftp).transfer = PPTRANSFER_INFO; + result = ftp_nb_type(data, conn, ((*data).state).prefer_ascii() != 0, FTP_TYPE); + if result as u64 != 0 { + return result; + } + } else { + result = ftp_state_size(data, conn); + } + return result; +} +unsafe extern "C" fn ftp_state_mdtm(mut data: *mut Curl_easy) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if (((*data).set).get_filetime() as libc::c_int != 0 + || (*data).set.timecondition as libc::c_uint != 0) && !((*ftpc).file).is_null() + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"MDTM %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_MDTM); + } + } else { + result = ftp_state_type(data); + } + return result; +} +unsafe extern "C" fn ftp_state_ul_setup( + mut data: *mut Curl_easy, + mut sizechecked: bool, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut append: bool = ((*data).set).remote_append() != 0; + if (*data).state.resume_from != 0 && !sizechecked + || (*data).state.resume_from > 0 as libc::c_int as libc::c_long + && sizechecked as libc::c_int != 0 + { + let mut seekerr: libc::c_int = 0 as libc::c_int; + if (*data).state.resume_from < 0 as libc::c_int as libc::c_long { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"SIZE %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_STOR_SIZE); + } + return result; + } + append = 1 as libc::c_int != 0; + if ((*conn).seek_func).is_some() { + Curl_set_in_callback(data, 1 as libc::c_int != 0); + seekerr = ((*conn).seek_func) + .expect( + "non-null function pointer", + )((*conn).seek_client, (*data).state.resume_from, 0 as libc::c_int); + Curl_set_in_callback(data, 0 as libc::c_int != 0); + } + if seekerr != 0 as libc::c_int { + let mut passed: curl_off_t = 0 as libc::c_int as curl_off_t; + if seekerr != 2 as libc::c_int { + Curl_failf( + data, + b"Could not seek stream\0" as *const u8 as *const libc::c_char, + ); + return CURLE_FTP_COULDNT_USE_REST; + } + loop { + let mut readthisamountnow: size_t = if (*data).state.resume_from - passed + > (*data).set.buffer_size + { + (*data).set.buffer_size as size_t + } else { + curlx_sotouz((*data).state.resume_from - passed) + }; + let mut actuallyread: size_t = ((*data).state.fread_func) + .expect( + "non-null function pointer", + )( + (*data).state.buffer, + 1 as libc::c_int as size_t, + readthisamountnow, + (*data).state.in_0, + ); + passed = (passed as libc::c_ulong).wrapping_add(actuallyread) + as curl_off_t as curl_off_t; + if actuallyread == 0 as libc::c_int as libc::c_ulong + || actuallyread > readthisamountnow + { + Curl_failf( + data, + b"Failed to read data\0" as *const u8 as *const libc::c_char, + ); + return CURLE_FTP_COULDNT_USE_REST; + } + if !(passed < (*data).state.resume_from) { + break; + } + } + } + if (*data).state.infilesize > 0 as libc::c_int as libc::c_long { + let ref mut fresh10 = (*data).state.infilesize; + *fresh10 -= (*data).state.resume_from; + if (*data).state.infilesize <= 0 as libc::c_int as libc::c_long { + Curl_infof( + data, + b"File already completely uploaded\0" as *const u8 + as *const libc::c_char, + ); + Curl_setup_transfer( + data, + -(1 as libc::c_int), + -(1 as libc::c_int) as curl_off_t, + 0 as libc::c_int != 0, + -(1 as libc::c_int), + ); + (*ftp).transfer = PPTRANSFER_NONE; + _state(data, FTP_STOP); + return CURLE_OK; + } + } + } + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + if append as libc::c_int != 0 { + b"APPE %s\0" as *const u8 as *const libc::c_char + } else { + b"STOR %s\0" as *const u8 as *const libc::c_char + }, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_STOR); + } + return result; +} +unsafe extern "C" fn ftp_state_quote( + mut data: *mut Curl_easy, + mut init: bool, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut quote: bool = 0 as libc::c_int != 0; + let mut item: *mut curl_slist = 0 as *mut curl_slist; + match instate as libc::c_uint { + 13 | 14 => { + item = (*data).set.prequote; + } + 15 => { + item = (*data).set.postquote; + } + 12 | _ => { + item = (*data).set.quote; + } + } + if init { + (*ftpc).count1 = 0 as libc::c_int; + } else { + let ref mut fresh11 = (*ftpc).count1; + *fresh11 += 1; + } + if !item.is_null() { + let mut i: libc::c_int = 0 as libc::c_int; + while i < (*ftpc).count1 && !item.is_null() { + item = (*item).next; + i += 1; + } + if !item.is_null() { + let mut cmd: *mut libc::c_char = (*item).data; + if *cmd.offset(0 as libc::c_int as isize) as libc::c_int == '*' as i32 { + cmd = cmd.offset(1); + (*ftpc).count2 = 1 as libc::c_int; + } else { + (*ftpc).count2 = 0 as libc::c_int; + } + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + cmd, + ); + if result as u64 != 0 { + return result; + } + _state(data, instate); + quote = 1 as libc::c_int != 0; + } + } + if !quote { + match instate as libc::c_uint { + 13 => { + if (*ftp).transfer as libc::c_uint + != PPTRANSFER_BODY as libc::c_int as libc::c_uint + { + _state(data, FTP_STOP); + } else if (*ftpc).known_filesize != -(1 as libc::c_int) as libc::c_long { + Curl_pgrsSetDownloadSize(data, (*ftpc).known_filesize); + result = ftp_state_retr(data, (*ftpc).known_filesize); + } else if ((*data).set).ignorecl() as libc::c_int != 0 + || ((*data).state).prefer_ascii() as libc::c_int != 0 + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"RETR %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_RETR); + } + } else { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"SIZE %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_RETR_SIZE); + } + } + } + 14 => { + result = ftp_state_ul_setup(data, 0 as libc::c_int != 0); + } + 15 => {} + 12 | _ => { + result = ftp_state_cwd(data, conn); + } + } + } + return result; +} +unsafe extern "C" fn ftp_epsv_disable( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + if ((*conn).bits).ipv6() as libc::c_int != 0 + && !(((*conn).bits).tunnel_proxy() as libc::c_int != 0 + || ((*conn).bits).socksproxy() as libc::c_int != 0) + { + Curl_failf( + data, + b"Failed EPSV attempt, exiting\0" as *const u8 as *const libc::c_char, + ); + return CURLE_WEIRD_SERVER_REPLY; + } + Curl_infof( + data, + b"Failed EPSV attempt. Disabling EPSV\0" as *const u8 as *const libc::c_char, + ); + let ref mut fresh12 = (*conn).bits; + (*fresh12).set_ftp_use_epsv(0 as libc::c_int as bit); + let ref mut fresh13 = (*data).state; + (*fresh13).set_errorbuf(0 as libc::c_int as bit); + result = Curl_pp_sendf( + data, + &mut (*conn).proto.ftpc.pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + b"PASV\0" as *const u8 as *const libc::c_char, + ); + if result as u64 == 0 { + let ref mut fresh14 = (*conn).proto.ftpc.count1; + *fresh14 += 1; + _state(data, FTP_PASV); + } + return result; +} +unsafe extern "C" fn control_address(mut conn: *mut connectdata) -> *mut libc::c_char { + if ((*conn).bits).tunnel_proxy() as libc::c_int != 0 + || ((*conn).bits).socksproxy() as libc::c_int != 0 + { + return (*conn).host.name; + } + return ((*conn).primary_ip).as_mut_ptr(); +} +unsafe extern "C" fn ftp_state_pasv_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut result: CURLcode = CURLE_OK; + let mut addr: *mut Curl_dns_entry = 0 as *mut Curl_dns_entry; + let mut rc: resolve_t = CURLRESOLV_RESOLVED; + let mut connectport: libc::c_ushort = 0; + let mut str: *mut libc::c_char = &mut *((*data).state.buffer) + .offset(4 as libc::c_int as isize) as *mut libc::c_char; + Curl_cfree.expect("non-null function pointer")((*ftpc).newhost as *mut libc::c_void); + let ref mut fresh15 = (*ftpc).newhost; + *fresh15 = 0 as *mut libc::c_char; + if (*ftpc).count1 == 0 as libc::c_int && ftpcode == 229 as libc::c_int { + let mut ptr: *mut libc::c_char = strchr(str, '(' as i32); + if !ptr.is_null() { + let mut num: libc::c_uint = 0; + let mut separator: [libc::c_char; 4] = [0; 4]; + ptr = ptr.offset(1); + if 5 as libc::c_int + == sscanf( + ptr, + b"%c%c%c%u%c\0" as *const u8 as *const libc::c_char, + &mut *separator.as_mut_ptr().offset(0 as libc::c_int as isize) + as *mut libc::c_char, + &mut *separator.as_mut_ptr().offset(1 as libc::c_int as isize) + as *mut libc::c_char, + &mut *separator.as_mut_ptr().offset(2 as libc::c_int as isize) + as *mut libc::c_char, + &mut num as *mut libc::c_uint, + &mut *separator.as_mut_ptr().offset(3 as libc::c_int as isize) + as *mut libc::c_char, + ) + { + let sep1: libc::c_char = separator[0 as libc::c_int as usize]; + let mut i: libc::c_int = 0; + i = 1 as libc::c_int; + while i < 4 as libc::c_int { + if separator[i as usize] as libc::c_int != sep1 as libc::c_int { + ptr = 0 as *mut libc::c_char; + break; + } else { + i += 1; + } + } + if num > 0xffff as libc::c_int as libc::c_uint { + Curl_failf( + data, + b"Illegal port number in EPSV reply\0" as *const u8 + as *const libc::c_char, + ); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + if !ptr.is_null() { + (*ftpc) + .newport = (num & 0xffff as libc::c_int as libc::c_uint) + as libc::c_ushort; + let ref mut fresh16 = (*ftpc).newhost; + *fresh16 = Curl_cstrdup + .expect("non-null function pointer")(control_address(conn)); + if ((*ftpc).newhost).is_null() { + return CURLE_OUT_OF_MEMORY; + } + } + } else { + ptr = 0 as *mut libc::c_char; + } + } + if ptr.is_null() { + Curl_failf( + data, + b"Weirdly formatted EPSV reply\0" as *const u8 as *const libc::c_char, + ); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + } else if (*ftpc).count1 == 1 as libc::c_int && ftpcode == 227 as libc::c_int { + let mut ip: [libc::c_uint; 4] = [ + 0 as libc::c_int as libc::c_uint, + 0 as libc::c_int as libc::c_uint, + 0 as libc::c_int as libc::c_uint, + 0 as libc::c_int as libc::c_uint, + ]; + let mut port: [libc::c_uint; 2] = [ + 0 as libc::c_int as libc::c_uint, + 0 as libc::c_int as libc::c_uint, + ]; + while *str != 0 { + if 6 as libc::c_int + == sscanf( + str, + b"%u,%u,%u,%u,%u,%u\0" as *const u8 as *const libc::c_char, + &mut *ip.as_mut_ptr().offset(0 as libc::c_int as isize) + as *mut libc::c_uint, + &mut *ip.as_mut_ptr().offset(1 as libc::c_int as isize) + as *mut libc::c_uint, + &mut *ip.as_mut_ptr().offset(2 as libc::c_int as isize) + as *mut libc::c_uint, + &mut *ip.as_mut_ptr().offset(3 as libc::c_int as isize) + as *mut libc::c_uint, + &mut *port.as_mut_ptr().offset(0 as libc::c_int as isize) + as *mut libc::c_uint, + &mut *port.as_mut_ptr().offset(1 as libc::c_int as isize) + as *mut libc::c_uint, + ) + { + break; + } + str = str.offset(1); + } + if *str == 0 + || ip[0 as libc::c_int as usize] > 255 as libc::c_int as libc::c_uint + || ip[1 as libc::c_int as usize] > 255 as libc::c_int as libc::c_uint + || ip[2 as libc::c_int as usize] > 255 as libc::c_int as libc::c_uint + || ip[3 as libc::c_int as usize] > 255 as libc::c_int as libc::c_uint + || port[0 as libc::c_int as usize] > 255 as libc::c_int as libc::c_uint + || port[1 as libc::c_int as usize] > 255 as libc::c_int as libc::c_uint + { + Curl_failf( + data, + b"Couldn't interpret the 227-response\0" as *const u8 + as *const libc::c_char, + ); + return CURLE_FTP_WEIRD_227_FORMAT; + } + if ((*data).set).ftp_skip_ip() != 0 { + Curl_infof( + data, + b"Skip %u.%u.%u.%u for data connection, re-use %s instead\0" as *const u8 + as *const libc::c_char, + ip[0 as libc::c_int as usize], + ip[1 as libc::c_int as usize], + ip[2 as libc::c_int as usize], + ip[3 as libc::c_int as usize], + (*conn).host.name, + ); + let ref mut fresh17 = (*ftpc).newhost; + *fresh17 = Curl_cstrdup + .expect("non-null function pointer")(control_address(conn)); + } else { + let ref mut fresh18 = (*ftpc).newhost; + *fresh18 = curl_maprintf( + b"%u.%u.%u.%u\0" as *const u8 as *const libc::c_char, + ip[0 as libc::c_int as usize], + ip[1 as libc::c_int as usize], + ip[2 as libc::c_int as usize], + ip[3 as libc::c_int as usize], + ); + } + if ((*ftpc).newhost).is_null() { + return CURLE_OUT_OF_MEMORY; + } + (*ftpc) + .newport = ((port[0 as libc::c_int as usize] << 8 as libc::c_int) + .wrapping_add(port[1 as libc::c_int as usize]) + & 0xffff as libc::c_int as libc::c_uint) as libc::c_ushort; + } else if (*ftpc).count1 == 0 as libc::c_int { + return ftp_epsv_disable(data, conn) + } else { + Curl_failf( + data, + b"Bad PASV/EPSV response: %03d\0" as *const u8 as *const libc::c_char, + ftpcode, + ); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + if ((*conn).bits).proxy() != 0 { + let host_name: *const libc::c_char = if ((*conn).bits).socksproxy() + as libc::c_int != 0 + { + (*conn).socks_proxy.host.name + } else { + (*conn).http_proxy.host.name + }; + rc = Curl_resolv( + data, + host_name, + (*conn).port, + 0 as libc::c_int != 0, + &mut addr, + ); + if rc as libc::c_int == CURLRESOLV_PENDING as libc::c_int { + Curl_resolver_wait_resolv(data, &mut addr); + } + connectport = (*conn).port as libc::c_ushort; + if addr.is_null() { + Curl_failf( + data, + b"Can't resolve proxy host %s:%hu\0" as *const u8 as *const libc::c_char, + host_name, + connectport as libc::c_int, + ); + return CURLE_COULDNT_RESOLVE_PROXY; + } + } else { + if ((*conn).bits).tcp_fastopen() as libc::c_int != 0 + && ((*conn).bits).reuse() == 0 + && *((*ftpc).newhost).offset(0 as libc::c_int as isize) == 0 + { + Curl_conninfo_remote(data, conn, (*conn).sock[0 as libc::c_int as usize]); + Curl_cfree + .expect( + "non-null function pointer", + )((*ftpc).newhost as *mut libc::c_void); + let ref mut fresh19 = (*ftpc).newhost; + *fresh19 = 0 as *mut libc::c_char; + let ref mut fresh20 = (*ftpc).newhost; + *fresh20 = Curl_cstrdup + .expect("non-null function pointer")(control_address(conn)); + if ((*ftpc).newhost).is_null() { + return CURLE_OUT_OF_MEMORY; + } + } + rc = Curl_resolv( + data, + (*ftpc).newhost, + (*ftpc).newport as libc::c_int, + 0 as libc::c_int != 0, + &mut addr, + ); + if rc as libc::c_int == CURLRESOLV_PENDING as libc::c_int { + Curl_resolver_wait_resolv(data, &mut addr); + } + connectport = (*ftpc).newport; + if addr.is_null() { + Curl_failf( + data, + b"Can't resolve new host %s:%hu\0" as *const u8 as *const libc::c_char, + (*ftpc).newhost, + connectport as libc::c_int, + ); + return CURLE_FTP_CANT_GET_HOST; + } + } + (*conn).bits.tcpconnect[1 as libc::c_int as usize] = 0 as libc::c_int != 0; + result = Curl_connecthost(data, conn, addr); + if result as u64 != 0 { + Curl_resolv_unlock(data, addr); + if (*ftpc).count1 == 0 as libc::c_int && ftpcode == 229 as libc::c_int { + return ftp_epsv_disable(data, conn); + } + return result; + } + if ((*data).set).verbose() != 0 { + ftp_pasv_verbose( + data, + (*addr).addr, + (*ftpc).newhost, + connectport as libc::c_int, + ); + } + Curl_resolv_unlock(data, addr); + Curl_cfree + .expect( + "non-null function pointer", + )((*conn).secondaryhostname as *mut libc::c_void); + let ref mut fresh21 = (*conn).secondaryhostname; + *fresh21 = 0 as *mut libc::c_char; + (*conn).secondary_port = (*ftpc).newport; + let ref mut fresh22 = (*conn).secondaryhostname; + *fresh22 = Curl_cstrdup.expect("non-null function pointer")((*ftpc).newhost); + if ((*conn).secondaryhostname).is_null() { + return CURLE_OUT_OF_MEMORY; + } + let ref mut fresh23 = (*conn).bits; + (*fresh23).set_do_more(1 as libc::c_int as bit); + _state(data, FTP_STOP); + return result; +} +unsafe extern "C" fn ftp_state_port_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut fcmd: ftpport = (*ftpc).count1 as ftpport; + let mut result: CURLcode = CURLE_OK; + if ftpcode / 100 as libc::c_int != 2 as libc::c_int { + if EPRT as libc::c_int as libc::c_uint == fcmd as libc::c_uint { + Curl_infof( + data, + b"disabling EPRT usage\0" as *const u8 as *const libc::c_char, + ); + let ref mut fresh24 = (*conn).bits; + (*fresh24).set_ftp_use_eprt(0 as libc::c_int as bit); + } + fcmd += 1; + if fcmd as libc::c_uint == DONE as libc::c_int as libc::c_uint { + Curl_failf(data, b"Failed to do PORT\0" as *const u8 as *const libc::c_char); + result = CURLE_FTP_PORT_FAILED; + } else { + result = ftp_state_use_port(data, fcmd); + } + } else { + Curl_infof( + data, + b"Connect data stream actively\0" as *const u8 as *const libc::c_char, + ); + _state(data, FTP_STOP); + result = ftp_dophase_done(data, 0 as libc::c_int != 0); + } + return result; +} +unsafe extern "C" fn ftp_state_mdtm_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + match ftpcode { + 213 => { + let mut year: libc::c_int = 0; + let mut month: libc::c_int = 0; + let mut day: libc::c_int = 0; + let mut hour: libc::c_int = 0; + let mut minute: libc::c_int = 0; + let mut second: libc::c_int = 0; + if 6 as libc::c_int + == sscanf( + &mut *((*data).state.buffer).offset(4 as libc::c_int as isize) + as *mut libc::c_char, + b"%04d%02d%02d%02d%02d%02d\0" as *const u8 as *const libc::c_char, + &mut year as *mut libc::c_int, + &mut month as *mut libc::c_int, + &mut day as *mut libc::c_int, + &mut hour as *mut libc::c_int, + &mut minute as *mut libc::c_int, + &mut second as *mut libc::c_int, + ) + { + let mut timebuf: [libc::c_char; 24] = [0; 24]; + curl_msnprintf( + timebuf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 24]>() as libc::c_ulong, + b"%04d%02d%02d %02d:%02d:%02d GMT\0" as *const u8 + as *const libc::c_char, + year, + month, + day, + hour, + minute, + second, + ); + (*data).info.filetime = Curl_getdate_capped(timebuf.as_mut_ptr()); + } + if ((*data).set).opt_no_body() as libc::c_int != 0 + && !((*ftpc).file).is_null() + && ((*data).set).get_filetime() as libc::c_int != 0 + && (*data).info.filetime >= 0 as libc::c_int as libc::c_long + { + let mut headerbuf: [libc::c_char; 128] = [0; 128]; + let mut headerbuflen: libc::c_int = 0; + let mut filetime: time_t = (*data).info.filetime; + let mut buffer: tm = tm { + tm_sec: 0, + tm_min: 0, + tm_hour: 0, + tm_mday: 0, + tm_mon: 0, + tm_year: 0, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: 0 as *const libc::c_char, + }; + let mut tm: *const tm = &mut buffer; + result = Curl_gmtime(filetime, &mut buffer); + if result as u64 != 0 { + return result; + } + headerbuflen = curl_msnprintf( + headerbuf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 128]>() as libc::c_ulong, + b"Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n\0" + as *const u8 as *const libc::c_char, + Curl_wkday[(if (*tm).tm_wday != 0 { + (*tm).tm_wday - 1 as libc::c_int + } else { + 6 as libc::c_int + }) as usize], + (*tm).tm_mday, + Curl_month[(*tm).tm_mon as usize], + (*tm).tm_year + 1900 as libc::c_int, + (*tm).tm_hour, + (*tm).tm_min, + (*tm).tm_sec, + ); + result = Curl_client_write( + data, + (1 as libc::c_int) << 0 as libc::c_int + | (1 as libc::c_int) << 1 as libc::c_int, + headerbuf.as_mut_ptr(), + headerbuflen as size_t, + ); + if result as u64 != 0 { + return result; + } + } + } + 550 => { + Curl_failf( + data, + b"Given file does not exist\0" as *const u8 as *const libc::c_char, + ); + result = CURLE_REMOTE_FILE_NOT_FOUND; + } + _ => { + Curl_infof( + data, + b"unsupported MDTM reply format\0" as *const u8 as *const libc::c_char, + ); + } + } + if (*data).set.timecondition as u64 != 0 { + if (*data).info.filetime > 0 as libc::c_int as libc::c_long + && (*data).set.timevalue > 0 as libc::c_int as libc::c_long + { + match (*data).set.timecondition as libc::c_uint { + 2 => { + if (*data).info.filetime > (*data).set.timevalue { + Curl_infof( + data, + b"The requested document is not old enough\0" as *const u8 + as *const libc::c_char, + ); + (*ftp).transfer = PPTRANSFER_NONE; + let ref mut fresh26 = (*data).info; + (*fresh26).set_timecond(1 as libc::c_int as bit); + _state(data, FTP_STOP); + return CURLE_OK; + } + } + 1 | _ => { + if (*data).info.filetime <= (*data).set.timevalue { + Curl_infof( + data, + b"The requested document is not new enough\0" as *const u8 + as *const libc::c_char, + ); + (*ftp).transfer = PPTRANSFER_NONE; + let ref mut fresh25 = (*data).info; + (*fresh25).set_timecond(1 as libc::c_int as bit); + _state(data, FTP_STOP); + return CURLE_OK; + } + } + } + } else { + Curl_infof( + data, + b"Skipping time comparison\0" as *const u8 as *const libc::c_char, + ); + } + } + if result as u64 == 0 { + result = ftp_state_type(data); + } + return result; +} +unsafe extern "C" fn ftp_state_type_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + if ftpcode / 100 as libc::c_int != 2 as libc::c_int { + Curl_failf( + data, + b"Couldn't set desired mode\0" as *const u8 as *const libc::c_char, + ); + return CURLE_FTP_COULDNT_SET_TYPE; + } + if ftpcode != 200 as libc::c_int { + Curl_infof( + data, + b"Got a %03d response code instead of the assumed 200\0" as *const u8 + as *const libc::c_char, + ftpcode, + ); + } + if instate as libc::c_uint == FTP_TYPE as libc::c_int as libc::c_uint { + result = ftp_state_size(data, conn); + } else if instate as libc::c_uint == FTP_LIST_TYPE as libc::c_int as libc::c_uint { + result = ftp_state_list(data); + } else if instate as libc::c_uint == FTP_RETR_TYPE as libc::c_int as libc::c_uint { + result = ftp_state_retr_prequote(data); + } else if instate as libc::c_uint == FTP_STOR_TYPE as libc::c_int as libc::c_uint { + result = ftp_state_stor_prequote(data); + } + return result; +} +unsafe extern "C" fn ftp_state_retr( + mut data: *mut Curl_easy, + mut filesize: curl_off_t, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if (*data).set.max_filesize != 0 && filesize > (*data).set.max_filesize { + Curl_failf( + data, + b"Maximum file size exceeded\0" as *const u8 as *const libc::c_char, + ); + return CURLE_FILESIZE_EXCEEDED; + } + (*ftp).downloadsize = filesize; + if (*data).state.resume_from != 0 { + if filesize == -(1 as libc::c_int) as libc::c_long { + Curl_infof( + data, + b"ftp server doesn't support SIZE\0" as *const u8 as *const libc::c_char, + ); + } else if (*data).state.resume_from < 0 as libc::c_int as libc::c_long { + if filesize < -(*data).state.resume_from { + Curl_failf( + data, + b"Offset (%ld) was beyond file size (%ld)\0" as *const u8 + as *const libc::c_char, + (*data).state.resume_from, + filesize, + ); + return CURLE_BAD_DOWNLOAD_RESUME; + } + (*ftp).downloadsize = -(*data).state.resume_from; + (*data).state.resume_from = filesize - (*ftp).downloadsize; + } else { + if filesize < (*data).state.resume_from { + Curl_failf( + data, + b"Offset (%ld) was beyond file size (%ld)\0" as *const u8 + as *const libc::c_char, + (*data).state.resume_from, + filesize, + ); + return CURLE_BAD_DOWNLOAD_RESUME; + } + (*ftp).downloadsize = filesize - (*data).state.resume_from; + } + if (*ftp).downloadsize == 0 as libc::c_int as libc::c_long { + Curl_setup_transfer( + data, + -(1 as libc::c_int), + -(1 as libc::c_int) as curl_off_t, + 0 as libc::c_int != 0, + -(1 as libc::c_int), + ); + Curl_infof( + data, + b"File already completely downloaded\0" as *const u8 + as *const libc::c_char, + ); + (*ftp).transfer = PPTRANSFER_NONE; + _state(data, FTP_STOP); + return CURLE_OK; + } + Curl_infof( + data, + b"Instructs server to resume from offset %ld\0" as *const u8 + as *const libc::c_char, + (*data).state.resume_from, + ); + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"REST %ld\0" as *const u8 as *const libc::c_char, + (*data).state.resume_from, + ); + if result as u64 == 0 { + _state(data, FTP_RETR_REST); + } + } else { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"RETR %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_RETR); + } + } + return result; +} +unsafe extern "C" fn ftp_state_size_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut filesize: curl_off_t = -(1 as libc::c_int) as curl_off_t; + let mut buf: *mut libc::c_char = (*data).state.buffer; + if ftpcode == 213 as libc::c_int { + let mut start: *mut libc::c_char = &mut *buf.offset(4 as libc::c_int as isize) + as *mut libc::c_char; + let mut fdigit: *mut libc::c_char = strchr(start, '\r' as i32); + if !fdigit.is_null() { + loop { + fdigit = fdigit.offset(-1); + if !(Curl_isdigit(*fdigit as libc::c_uchar as libc::c_int) != 0 + && fdigit > start) + { + break; + } + } + if Curl_isdigit(*fdigit as libc::c_uchar as libc::c_int) == 0 { + fdigit = fdigit.offset(1); + } + } else { + fdigit = start; + } + curlx_strtoofft( + fdigit, + 0 as *mut *mut libc::c_char, + 0 as libc::c_int, + &mut filesize, + ); + } else if ftpcode == 550 as libc::c_int { + if instate as libc::c_uint != FTP_STOR_SIZE as libc::c_int as libc::c_uint { + Curl_failf( + data, + b"The file does not exist\0" as *const u8 as *const libc::c_char, + ); + return CURLE_REMOTE_FILE_NOT_FOUND; + } + } + if instate as libc::c_uint == FTP_SIZE as libc::c_int as libc::c_uint { + if -(1 as libc::c_int) as libc::c_long != filesize { + let mut clbuf: [libc::c_char; 128] = [0; 128]; + let mut clbuflen: libc::c_int = curl_msnprintf( + clbuf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 128]>() as libc::c_ulong, + b"Content-Length: %ld\r\n\0" as *const u8 as *const libc::c_char, + filesize, + ); + result = Curl_client_write( + data, + (1 as libc::c_int) << 0 as libc::c_int + | (1 as libc::c_int) << 1 as libc::c_int, + clbuf.as_mut_ptr(), + clbuflen as size_t, + ); + if result as u64 != 0 { + return result; + } + } + Curl_pgrsSetDownloadSize(data, filesize); + result = ftp_state_rest(data, (*data).conn); + } else if instate as libc::c_uint == FTP_RETR_SIZE as libc::c_int as libc::c_uint { + Curl_pgrsSetDownloadSize(data, filesize); + result = ftp_state_retr(data, filesize); + } else if instate as libc::c_uint == FTP_STOR_SIZE as libc::c_int as libc::c_uint { + (*data).state.resume_from = filesize; + result = ftp_state_ul_setup(data, 1 as libc::c_int != 0); + } + return result; +} +unsafe extern "C" fn ftp_state_rest_resp( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut ftpcode: libc::c_int, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + match instate as libc::c_uint { + 27 => { + if ftpcode != 350 as libc::c_int { + Curl_failf( + data, + b"Couldn't use REST\0" as *const u8 as *const libc::c_char, + ); + result = CURLE_FTP_COULDNT_USE_REST; + } else { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"RETR %s\0" as *const u8 as *const libc::c_char, + (*ftpc).file, + ); + if result as u64 == 0 { + _state(data, FTP_RETR); + } + } + } + 26 | _ => { + if ftpcode == 350 as libc::c_int { + let mut buffer: [libc::c_char; 24] = *::std::mem::transmute::< + &[u8; 24], + &mut [libc::c_char; 24], + >(b"Accept-ranges: bytes\r\n\0\0"); + result = Curl_client_write( + data, + (1 as libc::c_int) << 0 as libc::c_int + | (1 as libc::c_int) << 1 as libc::c_int, + buffer.as_mut_ptr(), + strlen(buffer.as_mut_ptr()), + ); + if result as u64 != 0 { + return result; + } + } + result = ftp_state_prepare_transfer(data); + } + } + return result; +} +unsafe extern "C" fn ftp_state_stor_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + if ftpcode >= 400 as libc::c_int { + Curl_failf( + data, + b"Failed FTP upload: %0d\0" as *const u8 as *const libc::c_char, + ftpcode, + ); + _state(data, FTP_STOP); + return CURLE_UPLOAD_FAILED; + } + (*conn).proto.ftpc.state_saved = instate; + if ((*data).set).ftp_use_port() != 0 { + let mut connected: bool = false; + _state(data, FTP_STOP); + result = AllowServerConnect(data, &mut connected); + if result as u64 != 0 { + return result; + } + if !connected { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + Curl_infof( + data, + b"Data conn was not available immediately\0" as *const u8 + as *const libc::c_char, + ); + (*ftpc).wait_data_conn = 1 as libc::c_int != 0; + } + return CURLE_OK; + } + return InitiateTransfer(data); +} +unsafe extern "C" fn ftp_state_get_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + if ftpcode == 150 as libc::c_int || ftpcode == 125 as libc::c_int { + let mut size: curl_off_t = -(1 as libc::c_int) as curl_off_t; + if instate as libc::c_uint != FTP_LIST as libc::c_int as libc::c_uint + && ((*data).state).prefer_ascii() == 0 + && (*ftp).downloadsize < 1 as libc::c_int as libc::c_long + { + let mut bytes: *mut libc::c_char = 0 as *mut libc::c_char; + let mut buf: *mut libc::c_char = (*data).state.buffer; + bytes = strstr(buf, b" bytes\0" as *const u8 as *const libc::c_char); + if !bytes.is_null() { + bytes = bytes.offset(-1); + let mut in_0: libc::c_long = bytes.offset_from(buf) as libc::c_long; + loop { + in_0 -= 1; + if !(in_0 != 0) { + break; + } + if '(' as i32 == *bytes as libc::c_int { + break; + } + if Curl_isdigit(*bytes as libc::c_uchar as libc::c_int) == 0 { + bytes = 0 as *mut libc::c_char; + break; + } else { + bytes = bytes.offset(-1); + } + } + if !bytes.is_null() { + bytes = bytes.offset(1); + curlx_strtoofft( + bytes, + 0 as *mut *mut libc::c_char, + 0 as libc::c_int, + &mut size, + ); + } + } + } else if (*ftp).downloadsize > -(1 as libc::c_int) as libc::c_long { + size = (*ftp).downloadsize; + } + if size > (*data).req.maxdownload + && (*data).req.maxdownload > 0 as libc::c_int as libc::c_long + { + let ref mut fresh27 = (*data).req.size; + *fresh27 = (*data).req.maxdownload; + size = *fresh27; + } else if instate as libc::c_uint != FTP_LIST as libc::c_int as libc::c_uint + && ((*data).state).prefer_ascii() as libc::c_int != 0 + { + size = -(1 as libc::c_int) as curl_off_t; + } + Curl_infof( + data, + b"Maxdownload = %ld\0" as *const u8 as *const libc::c_char, + (*data).req.maxdownload, + ); + if instate as libc::c_uint != FTP_LIST as libc::c_int as libc::c_uint { + Curl_infof( + data, + b"Getting file with size: %ld\0" as *const u8 as *const libc::c_char, + size, + ); + } + (*conn).proto.ftpc.state_saved = instate; + (*conn).proto.ftpc.retr_size_saved = size; + if ((*data).set).ftp_use_port() != 0 { + let mut connected: bool = false; + result = AllowServerConnect(data, &mut connected); + if result as u64 != 0 { + return result; + } + if !connected { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + Curl_infof( + data, + b"Data conn was not available immediately\0" as *const u8 + as *const libc::c_char, + ); + _state(data, FTP_STOP); + (*ftpc).wait_data_conn = 1 as libc::c_int != 0; + } + } else { + return InitiateTransfer(data) + } + } else if instate as libc::c_uint == FTP_LIST as libc::c_int as libc::c_uint + && ftpcode == 450 as libc::c_int + { + (*ftp).transfer = PPTRANSFER_NONE; + _state(data, FTP_STOP); + } else { + Curl_failf( + data, + b"RETR response: %03d\0" as *const u8 as *const libc::c_char, + ftpcode, + ); + return (if instate as libc::c_uint == FTP_RETR as libc::c_int as libc::c_uint + && ftpcode == 550 as libc::c_int + { + CURLE_REMOTE_FILE_NOT_FOUND as libc::c_int + } else { + CURLE_FTP_COULDNT_RETR_FILE as libc::c_int + }) as CURLcode; + } + return result; +} +unsafe extern "C" fn ftp_state_loggedin(mut data: *mut Curl_easy) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + if ((*conn).bits).ftp_use_control_ssl() != 0 { + result = Curl_pp_sendf( + data, + &mut (*conn).proto.ftpc.pp as *mut pingpong, + b"PBSZ %d\0" as *const u8 as *const libc::c_char, + 0 as libc::c_int, + ); + if result as u64 == 0 { + _state(data, FTP_PBSZ); + } + } else { + result = ftp_state_pwd(data, conn); + } + return result; +} +unsafe extern "C" fn ftp_state_user_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, + mut instate: ftpstate, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if ftpcode == 331 as libc::c_int + && (*ftpc).state as libc::c_uint == FTP_USER as libc::c_int as libc::c_uint + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"PASS %s\0" as *const u8 as *const libc::c_char, + if !((*conn).passwd).is_null() { + (*conn).passwd as *const libc::c_char + } else { + b"\0" as *const u8 as *const libc::c_char + }, + ); + if result as u64 == 0 { + _state(data, FTP_PASS); + } + } else if ftpcode / 100 as libc::c_int == 2 as libc::c_int { + result = ftp_state_loggedin(data); + } else if ftpcode == 332 as libc::c_int { + if !((*data).set.str_0[STRING_FTP_ACCOUNT as libc::c_int as usize]).is_null() { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"ACCT %s\0" as *const u8 as *const libc::c_char, + (*data).set.str_0[STRING_FTP_ACCOUNT as libc::c_int as usize], + ); + if result as u64 == 0 { + _state(data, FTP_ACCT); + } + } else { + Curl_failf( + data, + b"ACCT requested but none available\0" as *const u8 + as *const libc::c_char, + ); + result = CURLE_LOGIN_DENIED; + } + } else if !((*data) + .set + .str_0[STRING_FTP_ALTERNATIVE_TO_USER as libc::c_int as usize]) + .is_null() && ((*data).state).ftp_trying_alternative() == 0 + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + (*data).set.str_0[STRING_FTP_ALTERNATIVE_TO_USER as libc::c_int as usize], + ); + if result as u64 == 0 { + let ref mut fresh28 = (*data).state; + (*fresh28).set_ftp_trying_alternative(1 as libc::c_int as bit); + _state(data, FTP_USER); + } + } else { + Curl_failf( + data, + b"Access denied: %03d\0" as *const u8 as *const libc::c_char, + ftpcode, + ); + result = CURLE_LOGIN_DENIED; + } + return result; +} +unsafe extern "C" fn ftp_state_acct_resp( + mut data: *mut Curl_easy, + mut ftpcode: libc::c_int, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + if ftpcode != 230 as libc::c_int { + Curl_failf( + data, + b"ACCT rejected by server: %03d\0" as *const u8 as *const libc::c_char, + ftpcode, + ); + result = CURLE_FTP_WEIRD_PASS_REPLY; + } else { + result = ftp_state_loggedin(data); + } + return result; +} +unsafe extern "C" fn ftp_statemachine( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut sock: curl_socket_t = (*conn).sock[0 as libc::c_int as usize]; + let mut ftpcode: libc::c_int = 0; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + static mut ftpauth: [[libc::c_char; 4]; 2] = unsafe { + [ + *::std::mem::transmute::<&[u8; 4], &[libc::c_char; 4]>(b"SSL\0"), + *::std::mem::transmute::<&[u8; 4], &[libc::c_char; 4]>(b"TLS\0"), + ] + }; + let mut nread: size_t = 0 as libc::c_int as size_t; + if (*pp).sendleft != 0 { + return Curl_pp_flushsend(data, pp); + } + result = ftp_readresp(data, sock, pp, &mut ftpcode, &mut nread); + if result as u64 != 0 { + return result; + } + if ftpcode != 0 { + let mut current_block_187: u64; + match (*ftpc).state as libc::c_uint { + 1 => { + if ftpcode == 230 as libc::c_int { + if (*data).set.use_ssl as libc::c_uint + <= CURLUSESSL_TRY as libc::c_int as libc::c_uint + || ((*conn).bits).ftp_use_control_ssl() as libc::c_int != 0 + { + return ftp_state_user_resp(data, ftpcode, (*ftpc).state); + } + } else if ftpcode != 220 as libc::c_int { + Curl_failf( + data, + b"Got a %03d ftp-server response when 220 was expected\0" + as *const u8 as *const libc::c_char, + ftpcode, + ); + return CURLE_WEIRD_SERVER_REPLY; + } + if (*data).set.use_ssl as libc::c_uint != 0 + && ((*conn).bits).ftp_use_control_ssl() == 0 + { + (*ftpc).count3 = 0 as libc::c_int; + match (*data).set.ftpsslauth as libc::c_uint { + 0 | 1 => { + (*ftpc).count2 = 1 as libc::c_int; + (*ftpc).count1 = 0 as libc::c_int; + } + 2 => { + (*ftpc).count2 = -(1 as libc::c_int); + (*ftpc).count1 = 1 as libc::c_int; + } + _ => { + Curl_failf( + data, + b"unsupported parameter to CURLOPT_FTPSSLAUTH: %d\0" + as *const u8 as *const libc::c_char, + (*data).set.ftpsslauth as libc::c_int, + ); + return CURLE_UNKNOWN_OPTION; + } + } + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"AUTH %s\0" as *const u8 as *const libc::c_char, + (ftpauth[(*ftpc).count1 as usize]).as_ptr(), + ); + if result as u64 == 0 { + _state(data, FTP_AUTH); + } + } else { + result = ftp_state_user(data, conn); + } + } + 2 => { + if (*pp).cache_size != 0 { + return CURLE_WEIRD_SERVER_REPLY; + } + if ftpcode == 234 as libc::c_int || ftpcode == 334 as libc::c_int { + result = Curl_ssl_connect(data, conn, 0 as libc::c_int); + if result as u64 == 0 { + let ref mut fresh29 = (*conn).bits; + (*fresh29).set_ftp_use_data_ssl(0 as libc::c_int as bit); + let ref mut fresh30 = (*conn).bits; + (*fresh30).set_ftp_use_control_ssl(1 as libc::c_int as bit); + result = ftp_state_user(data, conn); + } + } else if (*ftpc).count3 < 1 as libc::c_int { + let ref mut fresh31 = (*ftpc).count3; + *fresh31 += 1; + (*ftpc).count1 += (*ftpc).count2; + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"AUTH %s\0" as *const u8 as *const libc::c_char, + (ftpauth[(*ftpc).count1 as usize]).as_ptr(), + ); + } else if (*data).set.use_ssl as libc::c_uint + > CURLUSESSL_TRY as libc::c_int as libc::c_uint + { + result = CURLE_USE_SSL_FAILED; + } else { + result = ftp_state_user(data, conn); + } + } + 3 | 4 => { + result = ftp_state_user_resp(data, ftpcode, (*ftpc).state); + } + 5 => { + result = ftp_state_acct_resp(data, ftpcode); + } + 6 => { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"PROT %c\0" as *const u8 as *const libc::c_char, + if (*data).set.use_ssl as libc::c_uint + == CURLUSESSL_CONTROL as libc::c_int as libc::c_uint + { + 'C' as i32 + } else { + 'P' as i32 + }, + ); + if result as u64 == 0 { + _state(data, FTP_PROT); + } + } + 7 => { + if ftpcode / 100 as libc::c_int == 2 as libc::c_int { + let ref mut fresh32 = (*conn).bits; + (*fresh32) + .set_ftp_use_data_ssl( + (if (*data).set.use_ssl as libc::c_uint + != CURLUSESSL_CONTROL as libc::c_int as libc::c_uint + { + 1 as libc::c_int + } else { + 0 as libc::c_int + }) as bit, + ); + } else if (*data).set.use_ssl as libc::c_uint + > CURLUSESSL_CONTROL as libc::c_int as libc::c_uint + { + return CURLE_USE_SSL_FAILED + } + if (*data).set.ftp_ccc as u64 != 0 { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + b"CCC\0" as *const u8 as *const libc::c_char, + ); + if result as u64 == 0 { + _state(data, FTP_CCC); + } + } else { + result = ftp_state_pwd(data, conn); + } + } + 8 => { + if ftpcode < 500 as libc::c_int { + result = Curl_ssl_shutdown(data, conn, 0 as libc::c_int); + if result as u64 != 0 { + Curl_failf( + data, + b"Failed to clear the command channel (CCC)\0" as *const u8 + as *const libc::c_char, + ); + } + } + if result as u64 == 0 { + result = ftp_state_pwd(data, conn); + } + } + 9 => { + if ftpcode == 257 as libc::c_int { + let mut ptr: *mut libc::c_char = &mut *((*data).state.buffer) + .offset(4 as libc::c_int as isize) as *mut libc::c_char; + let buf_size: size_t = (*data).set.buffer_size as size_t; + let mut dir: *mut libc::c_char = 0 as *mut libc::c_char; + let mut entry_extracted: bool = 0 as libc::c_int != 0; + dir = Curl_cmalloc + .expect( + "non-null function pointer", + )(nread.wrapping_add(1 as libc::c_int as libc::c_ulong)) + as *mut libc::c_char; + if dir.is_null() { + return CURLE_OUT_OF_MEMORY; + } + while ptr + < &mut *((*data).state.buffer).offset(buf_size as isize) + as *mut libc::c_char && *ptr as libc::c_int != '\n' as i32 + && *ptr as libc::c_int != '\u{0}' as i32 + && *ptr as libc::c_int != '"' as i32 + { + ptr = ptr.offset(1); + } + if '"' as i32 == *ptr as libc::c_int { + let mut store: *mut libc::c_char = 0 as *mut libc::c_char; + ptr = ptr.offset(1); + store = dir; + while *ptr != 0 { + if '"' as i32 == *ptr as libc::c_int { + if '"' as i32 + == *ptr.offset(1 as libc::c_int as isize) as libc::c_int + { + *store = *ptr.offset(1 as libc::c_int as isize); + ptr = ptr.offset(1); + } else { + entry_extracted = 1 as libc::c_int != 0; + break; + } + } else { + *store = *ptr; + } + store = store.offset(1); + ptr = ptr.offset(1); + } + *store = '\u{0}' as i32 as libc::c_char; + } + if entry_extracted { + if ((*ftpc).server_os).is_null() + && *dir.offset(0 as libc::c_int as isize) as libc::c_int + != '/' as i32 + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + b"SYST\0" as *const u8 as *const libc::c_char, + ); + if result as u64 != 0 { + Curl_cfree + .expect( + "non-null function pointer", + )(dir as *mut libc::c_void); + return result; + } + Curl_cfree + .expect( + "non-null function pointer", + )((*ftpc).entrypath as *mut libc::c_void); + let ref mut fresh33 = (*ftpc).entrypath; + *fresh33 = 0 as *mut libc::c_char; + let ref mut fresh34 = (*ftpc).entrypath; + *fresh34 = dir; + Curl_infof( + data, + b"Entry path is '%s'\0" as *const u8 as *const libc::c_char, + (*ftpc).entrypath, + ); + let ref mut fresh35 = (*data) + .state + .most_recent_ftp_entrypath; + *fresh35 = (*ftpc).entrypath; + _state(data, FTP_SYST); + current_block_187 = 10490607306284298299; + } else { + Curl_cfree + .expect( + "non-null function pointer", + )((*ftpc).entrypath as *mut libc::c_void); + let ref mut fresh36 = (*ftpc).entrypath; + *fresh36 = 0 as *mut libc::c_char; + let ref mut fresh37 = (*ftpc).entrypath; + *fresh37 = dir; + Curl_infof( + data, + b"Entry path is '%s'\0" as *const u8 as *const libc::c_char, + (*ftpc).entrypath, + ); + let ref mut fresh38 = (*data) + .state + .most_recent_ftp_entrypath; + *fresh38 = (*ftpc).entrypath; + current_block_187 = 17917672080766325409; + } + } else { + Curl_cfree + .expect( + "non-null function pointer", + )(dir as *mut libc::c_void); + Curl_infof( + data, + b"Failed to figure out path\0" as *const u8 + as *const libc::c_char, + ); + current_block_187 = 17917672080766325409; + } + } else { + current_block_187 = 17917672080766325409; + } + match current_block_187 { + 10490607306284298299 => {} + _ => { + _state(data, FTP_STOP); + } + } + } + 10 => { + if ftpcode == 215 as libc::c_int { + let mut ptr_0: *mut libc::c_char = &mut *((*data).state.buffer) + .offset(4 as libc::c_int as isize) as *mut libc::c_char; + let mut os: *mut libc::c_char = 0 as *mut libc::c_char; + let mut store_0: *mut libc::c_char = 0 as *mut libc::c_char; + os = Curl_cmalloc + .expect( + "non-null function pointer", + )(nread.wrapping_add(1 as libc::c_int as libc::c_ulong)) + as *mut libc::c_char; + if os.is_null() { + return CURLE_OUT_OF_MEMORY; + } + while *ptr_0 as libc::c_int == ' ' as i32 { + ptr_0 = ptr_0.offset(1); + } + store_0 = os; + while *ptr_0 as libc::c_int != 0 + && *ptr_0 as libc::c_int != ' ' as i32 + { + let fresh39 = ptr_0; + ptr_0 = ptr_0.offset(1); + let fresh40 = store_0; + store_0 = store_0.offset(1); + *fresh40 = *fresh39; + } + *store_0 = '\u{0}' as i32 as libc::c_char; + if Curl_strcasecompare( + os, + b"OS/400\0" as *const u8 as *const libc::c_char, + ) != 0 + { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + b"SITE NAMEFMT 1\0" as *const u8 as *const libc::c_char, + ); + if result as u64 != 0 { + Curl_cfree + .expect( + "non-null function pointer", + )(os as *mut libc::c_void); + return result; + } + Curl_cfree + .expect( + "non-null function pointer", + )((*ftpc).server_os as *mut libc::c_void); + let ref mut fresh41 = (*ftpc).server_os; + *fresh41 = 0 as *mut libc::c_char; + let ref mut fresh42 = (*ftpc).server_os; + *fresh42 = os; + _state(data, FTP_NAMEFMT); + current_block_187 = 10490607306284298299; + } else { + Curl_cfree + .expect( + "non-null function pointer", + )((*ftpc).server_os as *mut libc::c_void); + let ref mut fresh43 = (*ftpc).server_os; + *fresh43 = 0 as *mut libc::c_char; + let ref mut fresh44 = (*ftpc).server_os; + *fresh44 = os; + current_block_187 = 6938158527927677584; + } + } else { + current_block_187 = 6938158527927677584; + } + match current_block_187 { + 10490607306284298299 => {} + _ => { + _state(data, FTP_STOP); + } + } + } + 11 => { + if ftpcode == 250 as libc::c_int { + ftp_state_pwd(data, conn); + } else { + _state(data, FTP_STOP); + } + } + 12 | 15 | 13 | 14 => { + if ftpcode >= 400 as libc::c_int && (*ftpc).count2 == 0 { + Curl_failf( + data, + b"QUOT command failed with %03d\0" as *const u8 + as *const libc::c_char, + ftpcode, + ); + result = CURLE_QUOTE_ERROR; + } else { + result = ftp_state_quote(data, 0 as libc::c_int != 0, (*ftpc).state); + } + } + 16 => { + if ftpcode / 100 as libc::c_int != 2 as libc::c_int { + if (*data).set.ftp_create_missing_dirs != 0 && (*ftpc).cwdcount != 0 + && (*ftpc).count2 == 0 + { + let ref mut fresh45 = (*ftpc).count2; + *fresh45 += 1; + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"MKD %s\0" as *const u8 as *const libc::c_char, + *((*ftpc).dirs) + .offset(((*ftpc).cwdcount - 1 as libc::c_int) as isize), + ); + if result as u64 == 0 { + _state(data, FTP_MKD); + } + } else { + Curl_failf( + data, + b"Server denied you to change to the given directory\0" + as *const u8 as *const libc::c_char, + ); + (*ftpc).cwdfail = 1 as libc::c_int != 0; + result = CURLE_REMOTE_ACCESS_DENIED; + } + } else { + (*ftpc).count2 = 0 as libc::c_int; + let ref mut fresh46 = (*ftpc).cwdcount; + *fresh46 += 1; + if *fresh46 <= (*ftpc).dirdepth { + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"CWD %s\0" as *const u8 as *const libc::c_char, + *((*ftpc).dirs) + .offset(((*ftpc).cwdcount - 1 as libc::c_int) as isize), + ); + } else { + result = ftp_state_mdtm(data); + } + } + } + 17 => { + if ftpcode / 100 as libc::c_int != 2 as libc::c_int + && { + let ref mut fresh47 = (*ftpc).count3; + let fresh48 = *fresh47; + *fresh47 = *fresh47 - 1; + fresh48 == 0 + } + { + Curl_failf( + data, + b"Failed to MKD dir: %03d\0" as *const u8 as *const libc::c_char, + ftpcode, + ); + result = CURLE_REMOTE_ACCESS_DENIED; + } else { + _state(data, FTP_CWD); + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"CWD %s\0" as *const u8 as *const libc::c_char, + *((*ftpc).dirs) + .offset(((*ftpc).cwdcount - 1 as libc::c_int) as isize), + ); + } + } + 18 => { + result = ftp_state_mdtm_resp(data, ftpcode); + } + 19 | 20 | 21 | 22 => { + result = ftp_state_type_resp(data, ftpcode, (*ftpc).state); + } + 23 | 24 | 25 => { + result = ftp_state_size_resp(data, ftpcode, (*ftpc).state); + } + 26 | 27 => { + result = ftp_state_rest_resp(data, conn, ftpcode, (*ftpc).state); + } + 29 => { + if ftpcode != 200 as libc::c_int { + Curl_failf( + data, + b"PRET command not accepted: %03d\0" as *const u8 + as *const libc::c_char, + ftpcode, + ); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, conn); + } + 30 => { + result = ftp_state_pasv_resp(data, ftpcode); + } + 28 => { + result = ftp_state_port_resp(data, ftpcode); + } + 31 | 32 => { + result = ftp_state_get_resp(data, ftpcode, (*ftpc).state); + } + 33 => { + result = ftp_state_stor_resp(data, ftpcode, (*ftpc).state); + } + 34 | _ => { + _state(data, FTP_STOP); + } + } + } + return result; +} +unsafe extern "C" fn ftp_multi_statemach( + mut data: *mut Curl_easy, + mut done: *mut bool, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut result: CURLcode = Curl_pp_statemach( + data, + &mut (*ftpc).pp, + 0 as libc::c_int != 0, + 0 as libc::c_int != 0, + ); + *done = if (*ftpc).state as libc::c_uint == FTP_STOP as libc::c_int as libc::c_uint { + 1 as libc::c_int + } else { + 0 as libc::c_int + } != 0; + return result; +} +unsafe extern "C" fn ftp_block_statemach( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + let mut result: CURLcode = CURLE_OK; + while (*ftpc).state as libc::c_uint != FTP_STOP as libc::c_int as libc::c_uint { + result = Curl_pp_statemach( + data, + pp, + 1 as libc::c_int != 0, + 1 as libc::c_int != 0, + ); + if result as u64 != 0 { + break; + } + } + return result; +} +unsafe extern "C" fn ftp_connect( + mut data: *mut Curl_easy, + mut done: *mut bool, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + *done = 0 as libc::c_int != 0; + Curl_conncontrol(conn, 0 as libc::c_int); + (*pp).response_time = (120 as libc::c_int * 1000 as libc::c_int) as timediff_t; + let ref mut fresh49 = (*pp).statemachine; + *fresh49 = Some( + ftp_statemachine + as unsafe extern "C" fn(*mut Curl_easy, *mut connectdata) -> CURLcode, + ); + let ref mut fresh50 = (*pp).endofresp; + *fresh50 = Some( + ftp_endofresp + as unsafe extern "C" fn( + *mut Curl_easy, + *mut connectdata, + *mut libc::c_char, + size_t, + *mut libc::c_int, + ) -> bool, + ); + if (*(*conn).handler).flags + & ((1 as libc::c_int) << 0 as libc::c_int) as libc::c_uint != 0 + { + result = Curl_ssl_connect(data, conn, 0 as libc::c_int); + if result as u64 != 0 { + return result; + } + let ref mut fresh51 = (*conn).bits; + (*fresh51).set_ftp_use_control_ssl(1 as libc::c_int as bit); + } + Curl_pp_setup(pp); + Curl_pp_init(data, pp); + _state(data, FTP_WAIT220); + result = ftp_multi_statemach(data, done); + return result; +} +unsafe extern "C" fn ftp_done( + mut data: *mut Curl_easy, + mut status: CURLcode, + mut premature: bool, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + let mut nread: ssize_t = 0; + let mut ftpcode: libc::c_int = 0; + let mut result: CURLcode = CURLE_OK; + let mut rawPath: *mut libc::c_char = 0 as *mut libc::c_char; + let mut pathLen: size_t = 0 as libc::c_int as size_t; + if ftp.is_null() { + return CURLE_OK; + } + let mut current_block_5: u64; + match status as libc::c_uint { + 23 => { + current_block_5 = 16918468366916868703; + } + 36 | 13 | 30 | 10 | 12 | 17 | 19 | 18 | 25 | 9 | 63 | 78 | 0 => { + current_block_5 = 16918468366916868703; + } + _ => { + current_block_5 = 7406589960681110508; + } + } + match current_block_5 { + 16918468366916868703 => { + if !premature { + current_block_5 = 6057473163062296781; + } else { + current_block_5 = 7406589960681110508; + } + } + _ => {} + } + match current_block_5 { + 7406589960681110508 => { + (*ftpc).ctl_valid = 0 as libc::c_int != 0; + (*ftpc).cwdfail = 1 as libc::c_int != 0; + Curl_conncontrol(conn, 1 as libc::c_int); + result = status; + } + _ => {} + } + if ((*data).state).wildcardmatch() != 0 { + if ((*data).set.chunk_end).is_some() && !((*ftpc).file).is_null() { + Curl_set_in_callback(data, 1 as libc::c_int != 0); + ((*data).set.chunk_end) + .expect("non-null function pointer")((*data).wildcard.customptr); + Curl_set_in_callback(data, 0 as libc::c_int != 0); + } + (*ftpc).known_filesize = -(1 as libc::c_int) as curl_off_t; + } + if result as u64 == 0 { + result = Curl_urldecode( + data, + (*ftp).path, + 0 as libc::c_int as size_t, + &mut rawPath, + &mut pathLen, + REJECT_CTRL, + ); + } + if result as u64 != 0 { + (*ftpc).ctl_valid = 0 as libc::c_int != 0; + Curl_conncontrol(conn, 1 as libc::c_int); + Curl_cfree + .expect("non-null function pointer")((*ftpc).prevpath as *mut libc::c_void); + let ref mut fresh52 = (*ftpc).prevpath; + *fresh52 = 0 as *mut libc::c_char; + } else { + if (*data).set.ftp_filemethod as libc::c_uint + == FTPFILE_NOCWD as libc::c_int as libc::c_uint + && *rawPath.offset(0 as libc::c_int as isize) as libc::c_int == '/' as i32 + { + Curl_cfree.expect("non-null function pointer")(rawPath as *mut libc::c_void); + } else { + Curl_cfree + .expect( + "non-null function pointer", + )((*ftpc).prevpath as *mut libc::c_void); + if !(*ftpc).cwdfail { + if (*data).set.ftp_filemethod as libc::c_uint + == FTPFILE_NOCWD as libc::c_int as libc::c_uint + { + pathLen = 0 as libc::c_int as size_t; + } else { + pathLen = (pathLen as libc::c_ulong) + .wrapping_sub( + if !((*ftpc).file).is_null() { + strlen((*ftpc).file) + } else { + 0 as libc::c_int as libc::c_ulong + }, + ) as size_t as size_t; + } + *rawPath.offset(pathLen as isize) = '\u{0}' as i32 as libc::c_char; + let ref mut fresh53 = (*ftpc).prevpath; + *fresh53 = rawPath; + } else { + Curl_cfree + .expect("non-null function pointer")(rawPath as *mut libc::c_void); + let ref mut fresh54 = (*ftpc).prevpath; + *fresh54 = 0 as *mut libc::c_char; + } + } + if !((*ftpc).prevpath).is_null() { + Curl_infof( + data, + b"Remembering we are in dir \"%s\"\0" as *const u8 + as *const libc::c_char, + (*ftpc).prevpath, + ); + } + } + freedirs(ftpc); + if (*conn).sock[1 as libc::c_int as usize] != -(1 as libc::c_int) { + if result as u64 == 0 && (*ftpc).dont_check as libc::c_int != 0 + && (*data).req.maxdownload > 0 as libc::c_int as libc::c_long + { + result = Curl_pp_sendf( + data, + pp, + b"%s\0" as *const u8 as *const libc::c_char, + b"ABOR\0" as *const u8 as *const libc::c_char, + ); + if result as u64 != 0 { + Curl_failf( + data, + b"Failure sending ABOR command: %s\0" as *const u8 + as *const libc::c_char, + curl_easy_strerror(result), + ); + (*ftpc).ctl_valid = 0 as libc::c_int != 0; + Curl_conncontrol(conn, 1 as libc::c_int); + } + } + if ((*conn).ssl[1 as libc::c_int as usize]).use_0() != 0 { + Curl_ssl_close(data, conn, 1 as libc::c_int); + } + close_secondarysocket(data, conn); + } + if result as u64 == 0 + && (*ftp).transfer as libc::c_uint + == PPTRANSFER_BODY as libc::c_int as libc::c_uint + && (*ftpc).ctl_valid as libc::c_int != 0 + && (*pp).pending_resp as libc::c_int != 0 && !premature + { + let mut old_time: timediff_t = (*pp).response_time; + (*pp).response_time = (60 as libc::c_int * 1000 as libc::c_int) as timediff_t; + (*pp).response = Curl_now(); + result = Curl_GetFTPResponse(data, &mut nread, &mut ftpcode); + (*pp).response_time = old_time; + if nread == 0 + && CURLE_OPERATION_TIMEDOUT as libc::c_int as libc::c_uint + == result as libc::c_uint + { + Curl_failf( + data, + b"control connection looks dead\0" as *const u8 as *const libc::c_char, + ); + (*ftpc).ctl_valid = 0 as libc::c_int != 0; + Curl_conncontrol(conn, 1 as libc::c_int); + } + if result as u64 != 0 { + Curl_cfree + .expect( + "non-null function pointer", + )((*ftp).pathalloc as *mut libc::c_void); + let ref mut fresh55 = (*ftp).pathalloc; + *fresh55 = 0 as *mut libc::c_char; + return result; + } + if (*ftpc).dont_check as libc::c_int != 0 + && (*data).req.maxdownload > 0 as libc::c_int as libc::c_long + { + Curl_infof( + data, + b"partial download completed, closing connection\0" as *const u8 + as *const libc::c_char, + ); + Curl_conncontrol(conn, 1 as libc::c_int); + return result; + } + if !(*ftpc).dont_check { + match ftpcode { + 226 | 250 => {} + 552 => { + Curl_failf( + data, + b"Exceeded storage allocation\0" as *const u8 + as *const libc::c_char, + ); + result = CURLE_REMOTE_DISK_FULL; + } + _ => { + Curl_failf( + data, + b"server did not report OK, got %d\0" as *const u8 + as *const libc::c_char, + ftpcode, + ); + result = CURLE_PARTIAL_FILE; + } + } + } + } + if !(result as libc::c_uint != 0 || premature as libc::c_int != 0) { + if ((*data).set).upload() != 0 { + if -(1 as libc::c_int) as libc::c_long != (*data).state.infilesize + && (*data).state.infilesize != (*data).req.writebytecount + && ((*data).set).crlf() == 0 + && (*ftp).transfer as libc::c_uint + == PPTRANSFER_BODY as libc::c_int as libc::c_uint + { + Curl_failf( + data, + b"Uploaded unaligned file size (%ld out of %ld bytes)\0" as *const u8 + as *const libc::c_char, + (*data).req.bytecount, + (*data).state.infilesize, + ); + result = CURLE_PARTIAL_FILE; + } + } else if -(1 as libc::c_int) as libc::c_long != (*data).req.size + && (*data).req.size != (*data).req.bytecount + && (*data).req.size + (*data).state.crlf_conversions + != (*data).req.bytecount + && (*data).req.maxdownload != (*data).req.bytecount + { + Curl_failf( + data, + b"Received only partial file: %ld bytes\0" as *const u8 + as *const libc::c_char, + (*data).req.bytecount, + ); + result = CURLE_PARTIAL_FILE; + } else if !(*ftpc).dont_check && (*data).req.bytecount == 0 + && (*data).req.size > 0 as libc::c_int as libc::c_long + { + Curl_failf( + data, + b"No data was received!\0" as *const u8 as *const libc::c_char, + ); + result = CURLE_FTP_COULDNT_RETR_FILE; + } + } + (*ftp).transfer = PPTRANSFER_BODY; + (*ftpc).dont_check = 0 as libc::c_int != 0; + if status as u64 == 0 && result as u64 == 0 && !premature + && !((*data).set.postquote).is_null() + { + result = ftp_sendquote(data, conn, (*data).set.postquote); + } + Curl_cfree + .expect("non-null function pointer")((*ftp).pathalloc as *mut libc::c_void); + let ref mut fresh56 = (*ftp).pathalloc; + *fresh56 = 0 as *mut libc::c_char; + return result; +} +unsafe extern "C" fn ftp_sendquote( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut quote: *mut curl_slist, +) -> CURLcode { + let mut item: *mut curl_slist = 0 as *mut curl_slist; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + item = quote; + while !item.is_null() { + if !((*item).data).is_null() { + let mut nread: ssize_t = 0; + let mut cmd: *mut libc::c_char = (*item).data; + let mut acceptfail: bool = 0 as libc::c_int != 0; + let mut result: CURLcode = CURLE_OK; + let mut ftpcode: libc::c_int = 0 as libc::c_int; + if *cmd.offset(0 as libc::c_int as isize) as libc::c_int == '*' as i32 { + cmd = cmd.offset(1); + acceptfail = 1 as libc::c_int != 0; + } + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + cmd, + ); + if result as u64 == 0 { + (*pp).response = Curl_now(); + result = Curl_GetFTPResponse(data, &mut nread, &mut ftpcode); + } + if result as u64 != 0 { + return result; + } + if !acceptfail && ftpcode >= 400 as libc::c_int { + Curl_failf( + data, + b"QUOT string not accepted: %s\0" as *const u8 + as *const libc::c_char, + cmd, + ); + return CURLE_QUOTE_ERROR; + } + } + item = (*item).next; + } + return CURLE_OK; +} +unsafe extern "C" fn ftp_need_type( + mut conn: *mut connectdata, + mut ascii_wanted: bool, +) -> libc::c_int { + return ((*conn).proto.ftpc.transfertype as libc::c_int + != (if ascii_wanted as libc::c_int != 0 { 'A' as i32 } else { 'I' as i32 })) + as libc::c_int; +} +unsafe extern "C" fn ftp_nb_type( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut ascii: bool, + mut newstate: ftpstate, +) -> CURLcode { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut result: CURLcode = CURLE_OK; + let mut want: libc::c_char = (if ascii as libc::c_int != 0 { + 'A' as i32 + } else { + 'I' as i32 + }) as libc::c_char; + if (*ftpc).transfertype as libc::c_int == want as libc::c_int { + _state(data, newstate); + return ftp_state_type_resp(data, 200 as libc::c_int, newstate); + } + result = Curl_pp_sendf( + data, + &mut (*ftpc).pp as *mut pingpong, + b"TYPE %c\0" as *const u8 as *const libc::c_char, + want as libc::c_int, + ); + if result as u64 == 0 { + _state(data, newstate); + (*ftpc).transfertype = want; + } + return result; +} +unsafe extern "C" fn ftp_pasv_verbose( + mut data: *mut Curl_easy, + mut ai: *mut Curl_addrinfo, + mut newhost: *mut libc::c_char, + mut port: libc::c_int, +) { + let mut buf: [libc::c_char; 256] = [0; 256]; + Curl_printable_address( + ai, + buf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 256]>() as libc::c_ulong, + ); + Curl_infof( + data, + b"Connecting to %s (%s) port %d\0" as *const u8 as *const libc::c_char, + newhost, + buf.as_mut_ptr(), + port, + ); +} +unsafe extern "C" fn ftp_do_more( + mut data: *mut Curl_easy, + mut completep: *mut libc::c_int, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut result: CURLcode = CURLE_OK; + let mut connected: bool = 0 as libc::c_int != 0; + let mut complete: bool = 0 as libc::c_int != 0; + let mut ftp: *mut FTP = (*data).req.p.ftp; + if !(*conn).bits.tcpconnect[1 as libc::c_int as usize] { + if Curl_connect_ongoing(conn) { + result = Curl_proxyCONNECT( + data, + 1 as libc::c_int, + 0 as *const libc::c_char, + 0 as libc::c_int, + ); + return result; + } + result = Curl_is_connected(data, conn, 1 as libc::c_int, &mut connected); + if connected {} else { + if result as libc::c_uint != 0 && (*ftpc).count1 == 0 as libc::c_int { + *completep = -(1 as libc::c_int); + return ftp_epsv_disable(data, conn); + } + return result; + } + } + result = Curl_proxy_connect(data, 1 as libc::c_int); + if result as u64 != 0 { + return result; + } + if (*conn).http_proxy.proxytype as libc::c_uint + == CURLPROXY_HTTPS as libc::c_int as libc::c_uint + && !(*conn).bits.proxy_ssl_connected[1 as libc::c_int as usize] + { + return result; + } + if ((*conn).bits).tunnel_proxy() as libc::c_int != 0 + && ((*conn).bits).httpproxy() as libc::c_int != 0 + && Curl_connect_ongoing(conn) as libc::c_int != 0 + { + return result; + } + if (*ftpc).state as u64 != 0 { + result = ftp_multi_statemach(data, &mut complete); + *completep = complete as libc::c_int; + if result as libc::c_uint != 0 || !(*ftpc).wait_data_conn { + return result; + } + *completep = 0 as libc::c_int; + } + if (*ftp).transfer as libc::c_uint <= PPTRANSFER_INFO as libc::c_int as libc::c_uint + { + if (*ftpc).wait_data_conn as libc::c_int == 1 as libc::c_int { + let mut serv_conned: bool = false; + result = ReceivedServerConnect(data, &mut serv_conned); + if result as u64 != 0 { + return result; + } + if serv_conned { + result = AcceptServerConnect(data); + (*ftpc).wait_data_conn = 0 as libc::c_int != 0; + if result as u64 == 0 { + result = InitiateTransfer(data); + } + if result as u64 != 0 { + return result; + } + *completep = 1 as libc::c_int; + } + } else if ((*data).set).upload() != 0 { + result = ftp_nb_type( + data, + conn, + ((*data).state).prefer_ascii() != 0, + FTP_STOR_TYPE, + ); + if result as u64 != 0 { + return result; + } + result = ftp_multi_statemach(data, &mut complete); + if (*ftpc).wait_data_conn { + *completep = 0 as libc::c_int; + } else { + *completep = complete as libc::c_int; + } + } else { + (*ftp).downloadsize = -(1 as libc::c_int) as curl_off_t; + result = Curl_range(data); + if result as libc::c_uint == CURLE_OK as libc::c_int as libc::c_uint + && (*data).req.maxdownload >= 0 as libc::c_int as libc::c_long + { + (*ftpc).dont_check = 1 as libc::c_int != 0; + } + if !(result as u64 != 0) { + if ((*data).state).list_only() as libc::c_int != 0 + || ((*ftpc).file).is_null() + { + if (*ftp).transfer as libc::c_uint + == PPTRANSFER_BODY as libc::c_int as libc::c_uint + { + result = ftp_nb_type( + data, + conn, + 1 as libc::c_int != 0, + FTP_LIST_TYPE, + ); + if result as u64 != 0 { + return result; + } + } + } else { + result = ftp_nb_type( + data, + conn, + ((*data).state).prefer_ascii() != 0, + FTP_RETR_TYPE, + ); + if result as u64 != 0 { + return result; + } + } + } + result = ftp_multi_statemach(data, &mut complete); + *completep = complete as libc::c_int; + } + return result; + } + Curl_setup_transfer( + data, + -(1 as libc::c_int), + -(1 as libc::c_int) as curl_off_t, + 0 as libc::c_int != 0, + -(1 as libc::c_int), + ); + if !(*ftpc).wait_data_conn { + *completep = 1 as libc::c_int; + } + return result; +} +unsafe extern "C" fn ftp_perform( + mut data: *mut Curl_easy, + mut connected: *mut bool, + mut dophase_done: *mut bool, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + if ((*data).set).opt_no_body() != 0 { + let mut ftp: *mut FTP = (*data).req.p.ftp; + (*ftp).transfer = PPTRANSFER_INFO; + } + *dophase_done = 0 as libc::c_int != 0; + result = ftp_state_quote(data, 1 as libc::c_int != 0, FTP_QUOTE); + if result as u64 != 0 { + return result; + } + result = ftp_multi_statemach(data, dophase_done); + *connected = (*conn).bits.tcpconnect[1 as libc::c_int as usize]; + Curl_infof( + data, + b"ftp_perform ends with SECONDARY: %d\0" as *const u8 as *const libc::c_char, + *connected as libc::c_int, + ); + *dophase_done; + return result; +} +unsafe extern "C" fn wc_data_dtor(mut ptr: *mut libc::c_void) { + let mut ftpwc: *mut ftp_wc = ptr as *mut ftp_wc; + if !ftpwc.is_null() && !((*ftpwc).parser).is_null() { + Curl_ftp_parselist_data_free(&mut (*ftpwc).parser); + } + Curl_cfree.expect("non-null function pointer")(ftpwc as *mut libc::c_void); +} +unsafe extern "C" fn init_wc_data(mut data: *mut Curl_easy) -> CURLcode { + let mut last_slash: *mut libc::c_char = 0 as *mut libc::c_char; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut path: *mut libc::c_char = (*ftp).path; + let mut wildcard: *mut WildcardData = &mut (*data).wildcard; + let mut result: CURLcode = CURLE_OK; + let mut ftpwc: *mut ftp_wc = 0 as *mut ftp_wc; + last_slash = strrchr((*ftp).path, '/' as i32); + if !last_slash.is_null() { + last_slash = last_slash.offset(1); + if *last_slash.offset(0 as libc::c_int as isize) as libc::c_int == '\u{0}' as i32 + { + (*wildcard).state = CURLWC_CLEAN; + result = ftp_parse_url_path(data); + return result; + } + let ref mut fresh57 = (*wildcard).pattern; + *fresh57 = Curl_cstrdup.expect("non-null function pointer")(last_slash); + if ((*wildcard).pattern).is_null() { + return CURLE_OUT_OF_MEMORY; + } + *last_slash.offset(0 as libc::c_int as isize) = '\u{0}' as i32 as libc::c_char; + } else if *path.offset(0 as libc::c_int as isize) != 0 { + let ref mut fresh58 = (*wildcard).pattern; + *fresh58 = Curl_cstrdup.expect("non-null function pointer")(path); + if ((*wildcard).pattern).is_null() { + return CURLE_OUT_OF_MEMORY; + } + *path.offset(0 as libc::c_int as isize) = '\u{0}' as i32 as libc::c_char; + } else { + (*wildcard).state = CURLWC_CLEAN; + result = ftp_parse_url_path(data); + return result; + } + ftpwc = Curl_ccalloc + .expect( + "non-null function pointer", + )(1 as libc::c_int as size_t, ::std::mem::size_of::() as libc::c_ulong) + as *mut ftp_wc; + if ftpwc.is_null() { + result = CURLE_OUT_OF_MEMORY; + } else { + let ref mut fresh59 = (*ftpwc).parser; + *fresh59 = Curl_ftp_parselist_data_alloc(); + if ((*ftpwc).parser).is_null() { + result = CURLE_OUT_OF_MEMORY; + } else { + let ref mut fresh60 = (*wildcard).protdata; + *fresh60 = ftpwc as *mut libc::c_void; + let ref mut fresh61 = (*wildcard).dtor; + *fresh61 = Some( + wc_data_dtor as unsafe extern "C" fn(*mut libc::c_void) -> (), + ); + if (*data).set.ftp_filemethod as libc::c_uint + == FTPFILE_NOCWD as libc::c_int as libc::c_uint + { + (*data).set.ftp_filemethod = FTPFILE_MULTICWD; + } + result = ftp_parse_url_path(data); + if !(result as u64 != 0) { + let ref mut fresh62 = (*wildcard).path; + *fresh62 = Curl_cstrdup.expect("non-null function pointer")((*ftp).path); + if ((*wildcard).path).is_null() { + result = CURLE_OUT_OF_MEMORY; + } else { + let ref mut fresh63 = (*ftpwc).backup.write_function; + *fresh63 = (*data).set.fwrite_func; + let ref mut fresh64 = (*data).set.fwrite_func; + *fresh64 = Some( + Curl_ftp_parselist + as unsafe extern "C" fn( + *mut libc::c_char, + size_t, + size_t, + *mut libc::c_void, + ) -> size_t, + ); + let ref mut fresh65 = (*ftpwc).backup.file_descriptor; + *fresh65 = (*data).set.out as *mut FILE; + let ref mut fresh66 = (*data).set.out; + *fresh66 = data as *mut libc::c_void; + Curl_infof( + data, + b"Wildcard - Parsing started\0" as *const u8 + as *const libc::c_char, + ); + return CURLE_OK; + } + } + } + } + if !ftpwc.is_null() { + Curl_ftp_parselist_data_free(&mut (*ftpwc).parser); + Curl_cfree.expect("non-null function pointer")(ftpwc as *mut libc::c_void); + } + Curl_cfree + .expect("non-null function pointer")((*wildcard).pattern as *mut libc::c_void); + let ref mut fresh67 = (*wildcard).pattern; + *fresh67 = 0 as *mut libc::c_char; + let ref mut fresh68 = (*wildcard).dtor; + *fresh68 = None; + let ref mut fresh69 = (*wildcard).protdata; + *fresh69 = 0 as *mut libc::c_void; + return result; +} +unsafe extern "C" fn wc_statemach(mut data: *mut Curl_easy) -> CURLcode { + let wildcard: *mut WildcardData = &mut (*data).wildcard; + let mut conn: *mut connectdata = (*data).conn; + let mut result: CURLcode = CURLE_OK; + let mut current_block_53: u64; + loop { + match (*wildcard).state as libc::c_uint { + 1 => { + result = init_wc_data(data); + if (*wildcard).state as libc::c_uint + == CURLWC_CLEAN as libc::c_int as libc::c_uint + { + return result; + } + (*wildcard) + .state = (if result as libc::c_uint != 0 { + CURLWC_ERROR as libc::c_int + } else { + CURLWC_MATCHING as libc::c_int + }) as wildcard_states; + return result; + } + 2 => { + let mut ftpwc: *mut ftp_wc = (*wildcard).protdata as *mut ftp_wc; + let ref mut fresh70 = (*data).set.fwrite_func; + *fresh70 = (*ftpwc).backup.write_function; + let ref mut fresh71 = (*data).set.out; + *fresh71 = (*ftpwc).backup.file_descriptor as *mut libc::c_void; + let ref mut fresh72 = (*ftpwc).backup.write_function; + *fresh72 = None; + let ref mut fresh73 = (*ftpwc).backup.file_descriptor; + *fresh73 = 0 as *mut FILE; + (*wildcard).state = CURLWC_DOWNLOADING; + if Curl_ftp_parselist_geterror((*ftpwc).parser) as u64 != 0 { + (*wildcard).state = CURLWC_CLEAN; + } else if (*wildcard).filelist.size == 0 as libc::c_int as libc::c_ulong + { + (*wildcard).state = CURLWC_CLEAN; + return CURLE_REMOTE_FILE_NOT_FOUND; + } + } + 3 => { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut finfo: *mut curl_fileinfo = (*(*wildcard).filelist.head).ptr + as *mut curl_fileinfo; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut tmp_path: *mut libc::c_char = curl_maprintf( + b"%s%s\0" as *const u8 as *const libc::c_char, + (*wildcard).path, + (*finfo).filename, + ); + if tmp_path.is_null() { + return CURLE_OUT_OF_MEMORY; + } + Curl_cfree + .expect( + "non-null function pointer", + )((*ftp).pathalloc as *mut libc::c_void); + let ref mut fresh74 = (*ftp).path; + *fresh74 = tmp_path; + let ref mut fresh75 = (*ftp).pathalloc; + *fresh75 = *fresh74; + Curl_infof( + data, + b"Wildcard - START of \"%s\"\0" as *const u8 as *const libc::c_char, + (*finfo).filename, + ); + if ((*data).set.chunk_bgn).is_some() { + let mut userresponse: libc::c_long = 0; + Curl_set_in_callback(data, 1 as libc::c_int != 0); + userresponse = ((*data).set.chunk_bgn) + .expect( + "non-null function pointer", + )( + finfo as *const libc::c_void, + (*wildcard).customptr, + (*wildcard).filelist.size as libc::c_int, + ); + Curl_set_in_callback(data, 0 as libc::c_int != 0); + match userresponse { + 2 => { + current_block_53 = 1971663154222422012; + match current_block_53 { + 13600473290859035008 => return CURLE_CHUNK_FAILED, + _ => { + Curl_infof( + data, + b"Wildcard - \"%s\" skipped by user\0" as *const u8 + as *const libc::c_char, + (*finfo).filename, + ); + (*wildcard).state = CURLWC_SKIP; + continue; + } + } + } + 1 => { + current_block_53 = 13600473290859035008; + match current_block_53 { + 13600473290859035008 => return CURLE_CHUNK_FAILED, + _ => { + Curl_infof( + data, + b"Wildcard - \"%s\" skipped by user\0" as *const u8 + as *const libc::c_char, + (*finfo).filename, + ); + (*wildcard).state = CURLWC_SKIP; + continue; + } + } + } + _ => {} + } + } + if (*finfo).filetype as libc::c_uint + != CURLFILETYPE_FILE as libc::c_int as libc::c_uint + { + (*wildcard).state = CURLWC_SKIP; + } else { + if (*finfo).flags + & ((1 as libc::c_int) << 6 as libc::c_int) as libc::c_uint != 0 + { + (*ftpc).known_filesize = (*finfo).size; + } + result = ftp_parse_url_path(data); + if result as u64 != 0 { + return result; + } + Curl_llist_remove( + &mut (*wildcard).filelist, + (*wildcard).filelist.head, + 0 as *mut libc::c_void, + ); + if (*wildcard).filelist.size == 0 as libc::c_int as libc::c_ulong { + (*wildcard).state = CURLWC_CLEAN; + return CURLE_OK; + } + return result; + } + } + 5 => { + if ((*data).set.chunk_end).is_some() { + Curl_set_in_callback(data, 1 as libc::c_int != 0); + ((*data).set.chunk_end) + .expect("non-null function pointer")((*data).wildcard.customptr); + Curl_set_in_callback(data, 0 as libc::c_int != 0); + } + Curl_llist_remove( + &mut (*wildcard).filelist, + (*wildcard).filelist.head, + 0 as *mut libc::c_void, + ); + (*wildcard) + .state = (if (*wildcard).filelist.size + == 0 as libc::c_int as libc::c_ulong + { + CURLWC_CLEAN as libc::c_int + } else { + CURLWC_DOWNLOADING as libc::c_int + }) as wildcard_states; + } + 4 => { + let mut ftpwc_0: *mut ftp_wc = (*wildcard).protdata as *mut ftp_wc; + result = CURLE_OK; + if !ftpwc_0.is_null() { + result = Curl_ftp_parselist_geterror((*ftpwc_0).parser); + } + (*wildcard) + .state = (if result as libc::c_uint != 0 { + CURLWC_ERROR as libc::c_int + } else { + CURLWC_DONE as libc::c_int + }) as wildcard_states; + return result; + } + 7 | 6 | 0 => { + if ((*wildcard).dtor).is_some() { + ((*wildcard).dtor) + .expect("non-null function pointer")((*wildcard).protdata); + } + return result; + } + _ => {} + } + }; +} +unsafe extern "C" fn ftp_do(mut data: *mut Curl_easy, mut done: *mut bool) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + *done = 0 as libc::c_int != 0; + (*ftpc).wait_data_conn = 0 as libc::c_int != 0; + if ((*data).state).wildcardmatch() != 0 { + result = wc_statemach(data); + if (*data).wildcard.state as libc::c_uint + == CURLWC_SKIP as libc::c_int as libc::c_uint + || (*data).wildcard.state as libc::c_uint + == CURLWC_DONE as libc::c_int as libc::c_uint + { + return CURLE_OK; + } + if result as u64 != 0 { + return result; + } + } else { + result = ftp_parse_url_path(data); + if result as u64 != 0 { + return result; + } + } + result = ftp_regular_transfer(data, done); + return result; +} +unsafe extern "C" fn ftp_quit( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + if (*conn).proto.ftpc.ctl_valid { + result = Curl_pp_sendf( + data, + &mut (*conn).proto.ftpc.pp as *mut pingpong, + b"%s\0" as *const u8 as *const libc::c_char, + b"QUIT\0" as *const u8 as *const libc::c_char, + ); + if result as u64 != 0 { + Curl_failf( + data, + b"Failure sending QUIT command: %s\0" as *const u8 + as *const libc::c_char, + curl_easy_strerror(result), + ); + (*conn).proto.ftpc.ctl_valid = 0 as libc::c_int != 0; + Curl_conncontrol(conn, 1 as libc::c_int); + _state(data, FTP_STOP); + return result; + } + _state(data, FTP_QUIT); + result = ftp_block_statemach(data, conn); + } + return result; +} +unsafe extern "C" fn ftp_disconnect( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, + mut dead_connection: bool, +) -> CURLcode { + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut pp: *mut pingpong = &mut (*ftpc).pp; + if dead_connection { + (*ftpc).ctl_valid = 0 as libc::c_int != 0; + } + ftp_quit(data, conn); + if !((*ftpc).entrypath).is_null() { + if (*data).state.most_recent_ftp_entrypath == (*ftpc).entrypath { + let ref mut fresh76 = (*data).state.most_recent_ftp_entrypath; + *fresh76 = 0 as *mut libc::c_char; + } + Curl_cfree + .expect("non-null function pointer")((*ftpc).entrypath as *mut libc::c_void); + let ref mut fresh77 = (*ftpc).entrypath; + *fresh77 = 0 as *mut libc::c_char; + } + freedirs(ftpc); + Curl_cfree + .expect("non-null function pointer")((*ftpc).prevpath as *mut libc::c_void); + let ref mut fresh78 = (*ftpc).prevpath; + *fresh78 = 0 as *mut libc::c_char; + Curl_cfree + .expect("non-null function pointer")((*ftpc).server_os as *mut libc::c_void); + let ref mut fresh79 = (*ftpc).server_os; + *fresh79 = 0 as *mut libc::c_char; + Curl_pp_disconnect(pp); + return CURLE_OK; +} +unsafe extern "C" fn ftp_parse_url_path(mut data: *mut Curl_easy) -> CURLcode { + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + let mut slashPos: *const libc::c_char = 0 as *const libc::c_char; + let mut fileName: *const libc::c_char = 0 as *const libc::c_char; + let mut result: CURLcode = CURLE_OK; + let mut rawPath: *mut libc::c_char = 0 as *mut libc::c_char; + let mut pathLen: size_t = 0 as libc::c_int as size_t; + (*ftpc).ctl_valid = 0 as libc::c_int != 0; + (*ftpc).cwdfail = 0 as libc::c_int != 0; + result = Curl_urldecode( + data, + (*ftp).path, + 0 as libc::c_int as size_t, + &mut rawPath, + &mut pathLen, + REJECT_CTRL, + ); + if result as u64 != 0 { + return result; + } + match (*data).set.ftp_filemethod as libc::c_uint { + 2 => { + if pathLen > 0 as libc::c_int as libc::c_ulong + && *rawPath + .offset( + pathLen.wrapping_sub(1 as libc::c_int as libc::c_ulong) as isize, + ) as libc::c_int != '/' as i32 + { + fileName = rawPath; + } + } + 3 => { + slashPos = strrchr(rawPath, '/' as i32); + if !slashPos.is_null() { + let mut dirlen: size_t = slashPos.offset_from(rawPath) as libc::c_long + as size_t; + if dirlen == 0 as libc::c_int as libc::c_ulong { + dirlen = dirlen.wrapping_add(1); + } + let ref mut fresh80 = (*ftpc).dirs; + *fresh80 = Curl_ccalloc + .expect( + "non-null function pointer", + )( + 1 as libc::c_int as size_t, + ::std::mem::size_of::<*mut libc::c_char>() as libc::c_ulong, + ) as *mut *mut libc::c_char; + if ((*ftpc).dirs).is_null() { + Curl_cfree + .expect( + "non-null function pointer", + )(rawPath as *mut libc::c_void); + return CURLE_OUT_OF_MEMORY; + } + let ref mut fresh81 = *((*ftpc).dirs).offset(0 as libc::c_int as isize); + *fresh81 = Curl_ccalloc + .expect( + "non-null function pointer", + )( + 1 as libc::c_int as size_t, + dirlen.wrapping_add(1 as libc::c_int as libc::c_ulong), + ) as *mut libc::c_char; + if (*((*ftpc).dirs).offset(0 as libc::c_int as isize)).is_null() { + Curl_cfree + .expect( + "non-null function pointer", + )(rawPath as *mut libc::c_void); + return CURLE_OUT_OF_MEMORY; + } + strncpy( + *((*ftpc).dirs).offset(0 as libc::c_int as isize), + rawPath, + dirlen, + ); + (*ftpc).dirdepth = 1 as libc::c_int; + fileName = slashPos.offset(1 as libc::c_int as isize); + } else { + fileName = rawPath; + } + } + 1 | _ => { + let mut curPos: *const libc::c_char = rawPath; + let mut dirAlloc: libc::c_int = 0 as libc::c_int; + let mut str: *const libc::c_char = rawPath; + while *str as libc::c_int != 0 as libc::c_int { + if *str as libc::c_int == '/' as i32 { + dirAlloc += 1; + } + str = str.offset(1); + } + if dirAlloc > 0 as libc::c_int { + let ref mut fresh82 = (*ftpc).dirs; + *fresh82 = Curl_ccalloc + .expect( + "non-null function pointer", + )( + dirAlloc as size_t, + ::std::mem::size_of::<*mut libc::c_char>() as libc::c_ulong, + ) as *mut *mut libc::c_char; + if ((*ftpc).dirs).is_null() { + Curl_cfree + .expect( + "non-null function pointer", + )(rawPath as *mut libc::c_void); + return CURLE_OUT_OF_MEMORY; + } + loop { + slashPos = strchr(curPos, '/' as i32); + if slashPos.is_null() { + break; + } + let mut compLen: size_t = slashPos.offset_from(curPos) + as libc::c_long as size_t; + if compLen == 0 as libc::c_int as libc::c_ulong + && (*ftpc).dirdepth == 0 as libc::c_int + { + compLen = compLen.wrapping_add(1); + } + if compLen > 0 as libc::c_int as libc::c_ulong { + let mut comp: *mut libc::c_char = Curl_ccalloc + .expect( + "non-null function pointer", + )( + 1 as libc::c_int as size_t, + compLen.wrapping_add(1 as libc::c_int as libc::c_ulong), + ) as *mut libc::c_char; + if comp.is_null() { + Curl_cfree + .expect( + "non-null function pointer", + )(rawPath as *mut libc::c_void); + return CURLE_OUT_OF_MEMORY; + } + strncpy(comp, curPos, compLen); + let ref mut fresh83 = (*ftpc).dirdepth; + let fresh84 = *fresh83; + *fresh83 = *fresh83 + 1; + let ref mut fresh85 = *((*ftpc).dirs).offset(fresh84 as isize); + *fresh85 = comp; + } + curPos = slashPos.offset(1 as libc::c_int as isize); + } + } + fileName = curPos; + } + } + if !fileName.is_null() && *fileName as libc::c_int != 0 { + let ref mut fresh86 = (*ftpc).file; + *fresh86 = Curl_cstrdup.expect("non-null function pointer")(fileName); + } else { + let ref mut fresh87 = (*ftpc).file; + *fresh87 = 0 as *mut libc::c_char; + } + if ((*data).set).upload() as libc::c_int != 0 && ((*ftpc).file).is_null() + && (*ftp).transfer as libc::c_uint + == PPTRANSFER_BODY as libc::c_int as libc::c_uint + { + Curl_failf( + data, + b"Uploading to a URL without a file name!\0" as *const u8 + as *const libc::c_char, + ); + Curl_cfree.expect("non-null function pointer")(rawPath as *mut libc::c_void); + return CURLE_URL_MALFORMAT; + } + (*ftpc).cwddone = 0 as libc::c_int != 0; + if (*data).set.ftp_filemethod as libc::c_uint + == FTPFILE_NOCWD as libc::c_int as libc::c_uint + && *rawPath.offset(0 as libc::c_int as isize) as libc::c_int == '/' as i32 + { + (*ftpc).cwddone = 1 as libc::c_int != 0; + } else { + let mut oldPath: *const libc::c_char = if ((*conn).bits).reuse() as libc::c_int + != 0 + { + (*ftpc).prevpath as *const libc::c_char + } else { + b"\0" as *const u8 as *const libc::c_char + }; + if !oldPath.is_null() { + let mut n: size_t = pathLen; + if (*data).set.ftp_filemethod as libc::c_uint + == FTPFILE_NOCWD as libc::c_int as libc::c_uint + { + n = 0 as libc::c_int as size_t; + } else { + n = (n as libc::c_ulong) + .wrapping_sub( + if !((*ftpc).file).is_null() { + strlen((*ftpc).file) + } else { + 0 as libc::c_int as libc::c_ulong + }, + ) as size_t as size_t; + } + if strlen(oldPath) == n && strncmp(rawPath, oldPath, n) == 0 { + Curl_infof( + data, + b"Request has same path as previous transfer\0" as *const u8 + as *const libc::c_char, + ); + (*ftpc).cwddone = 1 as libc::c_int != 0; + } + } + } + Curl_cfree.expect("non-null function pointer")(rawPath as *mut libc::c_void); + return CURLE_OK; +} +unsafe extern "C" fn ftp_dophase_done( + mut data: *mut Curl_easy, + mut connected: bool, +) -> CURLcode { + let mut conn: *mut connectdata = (*data).conn; + let mut ftp: *mut FTP = (*data).req.p.ftp; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + if connected { + let mut completed: libc::c_int = 0; + let mut result: CURLcode = ftp_do_more(data, &mut completed); + if result as u64 != 0 { + close_secondarysocket(data, conn); + return result; + } + } + if (*ftp).transfer as libc::c_uint != PPTRANSFER_BODY as libc::c_int as libc::c_uint + { + Curl_setup_transfer( + data, + -(1 as libc::c_int), + -(1 as libc::c_int) as curl_off_t, + 0 as libc::c_int != 0, + -(1 as libc::c_int), + ); + } else if !connected { + let ref mut fresh88 = (*conn).bits; + (*fresh88).set_do_more(1 as libc::c_int as bit); + } + (*ftpc).ctl_valid = 1 as libc::c_int != 0; + return CURLE_OK; +} +unsafe extern "C" fn ftp_doing( + mut data: *mut Curl_easy, + mut dophase_done: *mut bool, +) -> CURLcode { + let mut result: CURLcode = ftp_multi_statemach(data, dophase_done); + if !(result as u64 != 0) { + if *dophase_done { + result = ftp_dophase_done(data, 0 as libc::c_int != 0); + } + } + return result; +} +unsafe extern "C" fn ftp_regular_transfer( + mut data: *mut Curl_easy, + mut dophase_done: *mut bool, +) -> CURLcode { + let mut result: CURLcode = CURLE_OK; + let mut connected: bool = 0 as libc::c_int != 0; + let mut conn: *mut connectdata = (*data).conn; + let mut ftpc: *mut ftp_conn = &mut (*conn).proto.ftpc; + (*data).req.size = -(1 as libc::c_int) as curl_off_t; + Curl_pgrsSetUploadCounter(data, 0 as libc::c_int as curl_off_t); + Curl_pgrsSetDownloadCounter(data, 0 as libc::c_int as curl_off_t); + Curl_pgrsSetUploadSize(data, -(1 as libc::c_int) as curl_off_t); + Curl_pgrsSetDownloadSize(data, -(1 as libc::c_int) as curl_off_t); + (*ftpc).ctl_valid = 1 as libc::c_int != 0; + result = ftp_perform(data, &mut connected, dophase_done); + if result as u64 == 0 { + if !*dophase_done { + return CURLE_OK; + } + result = ftp_dophase_done(data, connected); + if result as u64 != 0 { + return result; + } + } else { + freedirs(ftpc); + } + return result; +} +unsafe extern "C" fn ftp_setup_connection( + mut data: *mut Curl_easy, + mut conn: *mut connectdata, +) -> CURLcode { + let mut type_0: *mut libc::c_char = 0 as *mut libc::c_char; + let mut ftp: *mut FTP = 0 as *mut FTP; + ftp = Curl_ccalloc + .expect( + "non-null function pointer", + )(::std::mem::size_of::() as libc::c_ulong, 1 as libc::c_int as size_t) + as *mut FTP; + let ref mut fresh89 = (*data).req.p.ftp; + *fresh89 = ftp; + if ftp.is_null() { + return CURLE_OUT_OF_MEMORY; + } + let ref mut fresh90 = (*ftp).path; + *fresh90 = &mut *((*data).state.up.path).offset(1 as libc::c_int as isize) + as *mut libc::c_char; + type_0 = strstr((*ftp).path, b";type=\0" as *const u8 as *const libc::c_char); + if type_0.is_null() { + type_0 = strstr( + (*conn).host.rawalloc, + b";type=\0" as *const u8 as *const libc::c_char, + ); + } + if !type_0.is_null() { + let mut command: libc::c_char = 0; + *type_0 = 0 as libc::c_int as libc::c_char; + command = Curl_raw_toupper(*type_0.offset(6 as libc::c_int as isize)); + match command as libc::c_int { + 65 => { + let ref mut fresh91 = (*data).state; + (*fresh91).set_prefer_ascii(1 as libc::c_int as bit); + } + 68 => { + let ref mut fresh92 = (*data).state; + (*fresh92).set_list_only(1 as libc::c_int as bit); + } + 73 | _ => { + let ref mut fresh93 = (*data).state; + (*fresh93).set_prefer_ascii(0 as libc::c_int as bit); + } + } + } + (*ftp).transfer = PPTRANSFER_BODY; + (*ftp).downloadsize = 0 as libc::c_int as curl_off_t; + (*conn).proto.ftpc.known_filesize = -(1 as libc::c_int) as curl_off_t; + return CURLE_OK; +}