From: Bartosz Ruszczak Date: Fri, 14 Mar 2025 20:53:42 +0000 (+0100) Subject: ftp: fix prequotes for a directory in URL X-Git-Tag: curl-8_15_0~213 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fdf50d64b8cd270bc733278f139dfd001d5cf0d7;p=thirdparty%2Fcurl.git ftp: fix prequotes for a directory in URL Allow prequotes to be sent after curl has changed the working directory, just before the listing command if the URL is a directory. FTP state machine is updated with the new FTP_LIST_PREQUOTE state and FTP_RETR_LIST_TYPE type. Test 754 verifies Fixes #8602 Closes #17616 --- diff --git a/lib/ftp.c b/lib/ftp.c index 583e33a967..aaf1e0e397 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -114,12 +114,14 @@ static const char * const ftp_state_names[]={ "QUOTE", "RETR_PREQUOTE", "STOR_PREQUOTE", + "LIST_PREQUOTE", "POSTQUOTE", "CWD", "MKD", "MDTM", "TYPE", "LIST_TYPE", + "RETR_LIST_TYPE", "RETR_TYPE", "STOR_TYPE", "SIZE", @@ -1459,6 +1461,14 @@ static CURLcode ftp_state_list(struct Curl_easy *data, return result; } +static CURLcode ftp_state_list_prequote(struct Curl_easy *data, + struct ftp_conn *ftpc, + struct FTP *ftp) +{ + /* We have sent the TYPE, now we must send the list of prequote strings */ + return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_LIST_PREQUOTE); +} + static CURLcode ftp_state_retr_prequote(struct Curl_easy *data, struct ftp_conn *ftpc, struct FTP *ftp) @@ -1647,6 +1657,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, break; case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: + case FTP_LIST_PREQUOTE: item = data->set.prequote; break; case FTP_POSTQUOTE: @@ -1736,6 +1747,10 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, break; case FTP_POSTQUOTE: break; + case FTP_LIST_PREQUOTE: + ftp_state(data, ftpc, FTP_LIST_TYPE); + result = ftp_state_list(data, ftpc, ftp); + break; } } @@ -2209,6 +2224,8 @@ static CURLcode ftp_state_type_resp(struct Curl_easy *data, result = ftp_state_retr_prequote(data, ftpc, ftp); else if(instate == FTP_STOR_TYPE) result = ftp_state_stor_prequote(data, ftpc, ftp); + else if(instate == FTP_RETR_LIST_TYPE) + result = ftp_state_list_prequote(data, ftpc, ftp); return result; } @@ -3013,6 +3030,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, case FTP_POSTQUOTE: case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: + case FTP_LIST_PREQUOTE: if((ftpcode >= 400) && !ftpc->count2) { /* failure response code, and not allowed to fail */ failf(data, "QUOT command failed with %03d", ftpcode); @@ -3082,6 +3100,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, case FTP_LIST_TYPE: case FTP_RETR_TYPE: case FTP_STOR_TYPE: + case FTP_RETR_LIST_TYPE: result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state); break; @@ -3686,7 +3705,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) if(result) ; - else if(data->state.list_only || !ftpc->file) { + else if((data->state.list_only || !ftpc->file) && + !(data->set.prequote)) { /* 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. */ @@ -3700,8 +3720,14 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) /* otherwise just fall through */ } else { - result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, - FTP_RETR_TYPE); + if(data->set.prequote && !ftpc->file) { + result = ftp_nb_type(data, ftpc, ftp, TRUE, + FTP_RETR_LIST_TYPE); + } + else { + result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, + FTP_RETR_TYPE); + } if(result) return result; } diff --git a/lib/ftp.h b/lib/ftp.h index c31aa93286..52661981ef 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -62,12 +62,14 @@ enum { FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ FTP_RETR_PREQUOTE, FTP_STOR_PREQUOTE, + FTP_LIST_PREQUOTE, FTP_POSTQUOTE, FTP_CWD, /* change dir */ FTP_MKD, /* if the dir did not exist */ FTP_MDTM, /* to figure out the datestamp */ FTP_TYPE, /* to set type when doing a head-like request */ FTP_LIST_TYPE, /* set type when about to do a dir list */ + FTP_RETR_LIST_TYPE, FTP_RETR_TYPE, /* set type when about to RETR a file */ FTP_STOR_TYPE, /* set type when about to STOR a file */ FTP_SIZE, /* get the remote file's size for head-like request */ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 7b519da8ae..3986eca6f1 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -108,7 +108,7 @@ test718 test719 test720 test721 test722 test723 test724 test725 test726 \ test727 test728 test729 test730 test731 test732 test733 test734 test735 \ test736 test737 test738 test739 test740 test741 test742 test743 test744 \ test745 test746 test747 test748 test749 test750 test751 test752 test753 \ -\ +test754 \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ test789 test790 test791 \ \ diff --git a/tests/data/test754 b/tests/data/test754 new file mode 100644 index 0000000000..9253d9f225 --- /dev/null +++ b/tests/data/test754 @@ -0,0 +1,64 @@ + + + +FTP +list +post-quote +pre-quote + + +# Server-side + + +total 20 +drwxr-xr-x 8 98 98 512 Oct 22 13:06 . +drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. +drwxr-xr-x 2 98 98 512 May 2 1996 .NeXT +-r--r--r-- 1 0 1 35 Jul 16 1996 README +lrwxrwxrwx 1 0 1 7 Dec 9 1999 bin -> usr/bin +dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev +drwxrwxrwx 2 98 98 512 May 29 16:04 download.html +dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc +drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub +dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr + + +REPLY FAIL 500 this might not be a failure! + + + +# Client-side + + +ftp + + +FTP list with quote ops + + +ftp://%HOSTIP:%FTPPORT/path/ -Q "NOOP 1" -Q "+NOOP 2" -Q "-NOOP 3" -Q "*FAIL" -Q "+*FAIL HARD" + + + +# Verify data after the test has been "shot" + + +QUIT + + +USER anonymous +PASS ftp@example.com +PWD +NOOP 1 +FAIL +CWD path +EPSV +TYPE A +NOOP 2 +FAIL HARD +LIST +NOOP 3 +QUIT + + +