← Commit list

f656837720

Daniel Stenberg
Daniel Stenberg
2026-09-07
SUCCESS Duration: 432s

Subject

ftp: URL encode file names when wildcarding

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/ftp.c+6 -1
@@ -4083,8 +4083,13 @@ static CURLcode wc_statemach(struct Curl_easy *data,
/* filelist has at least one file, lets get first one */
struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist);
struct curl_fileinfo *finfo = Curl_node_elem(head);
+ char *tmp_path;
+ char *enc = curl_easy_escape(NULL, finfo->filename, 0);
+ if(!enc)
+ return CURLE_OUT_OF_MEMORY;
- char *tmp_path = curl_maprintf("%s%s", wildcard->path, finfo->filename);
+ tmp_path = curl_maprintf("%s%s", wildcard->path, enc);
+ curl_free(enc);
if(!tmp_path)
return CURLE_OUT_OF_MEMORY;
tests/data/Makefile.am+1 -0
@@ -2009,6 +2009,7 @@ TESTCASES = \
test2721 \
test2722 \
test2723 \
+ test2805 \
test2885 \
test3000 \
test3001 \
tests/data/test2805+60 -0
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+FTP
+LIST
+wildcardmatch
+ftplistparser
+</keywords>
+</info>
+
+# Directory content is generated by the ftp server itself
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+<tool>
+lib%TESTNUMBER
+</tool>
+<name>
+FTP wildcards with percent sign in file name
+</name>
+<command>
+ftp://%HOSTIP:%FTPPORT/fully_simulated/percen%74/*.txt
+</command>
+</client>
+
+############################################
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+0
+</errorcode>
+
+<protocol crlf="yes">
+USER anonymous
+PASS [email protected]
+PWD
+CWD fully_simulated
+CWD percent
+EPSV
+TYPE A
+LIST
+EPSV
+TYPE I
+RETR someothertext.txt
+EPSV
+RETR some%2etxt
+QUIT
+</protocol>
+<stdout>
+match: 'someothertext.txt' against pattern '*.txt'
+match: 'some%2etxt' against pattern '*.txt'
+Some junk ;-) This file does not really exist.
+percent in file name.
+</stdout>
+</verify>
+</testcase>
tests/directories.pm+13 -0
@@ -179,7 +179,20 @@ my %file_someothertext_txt = (
'perm' => "rw-r--r--"
);
+my %file_percent_txt = (
+ 'name' => "some%2etxt",
+ 'content' => "percent in file name.\n",
+ 'time' => "Apr 17 11:01",
+ 'dostime' => "04-17-10 11:01AM",
+ 'perm' => "rw-r--r--"
+);
+
my %lists = (
+ '/fully_simulated/percent/' => {
+ 'files' => [ \%file_someothertext_txt, \%file_percent_txt],
+ 'eol' => "\r\n",
+ 'type' => "unix"
+ },
'/fully_simulated/' => {
'files' => [ \%dir_dot, \%dir_ddot, \%dir_DOS, \%dir_UNIX ],
'eol' => "\r\n",
tests/ftpserver.pl+1 -0
@@ -2115,6 +2115,7 @@ sub LIST_ftp {
my @ftpdir = ftp_contentlist($ftptargetdir);
# old hard-coded style
for(@ftpdir) {
+ logmsg "LIST: $_";
senddata $_;
}
}
tests/libtest/Makefile.inc+1 -0
@@ -313,6 +313,7 @@ TESTS_C = \
lib2505.c \
lib2506.c \
lib2700.c \
+ lib2805.c \
lib3010.c \
lib3025.c \
lib3026.c \
tests/libtest/lib2805.c+65 -0
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "first.h"
+
+static int fnmatch2805(void *ptr, const char *pattern, const char *string)
+{
+ (void)ptr;
+ curl_mprintf("match: '%s' against pattern '%s'\n", string, pattern);
+ return CURL_FNMATCHFUNC_MATCH;
+}
+
+static CURLcode test_lib2805(const char *URL)
+{
+ CURLcode result;
+ CURL *curl;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ curl_mfprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ curl = curl_easy_init();
+ if(!curl) {
+ curl_mfprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ easy_setopt(curl, CURLOPT_URL, URL);
+ easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L);
+ easy_setopt(curl, CURLOPT_FNMATCH_FUNCTION, fnmatch2805);
+ easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)TEST_HANG_TIMEOUT);
+
+ result = curl_easy_perform(curl);
+ if(result) {
+ curl_mfprintf(stderr, "curl_easy_perform() failed %d\n", (int)result);
+ goto test_cleanup;
+ }
+
+test_cleanup:
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+ return result;
+}