]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl_path: make Curl_get_pathname use dynbuf
authorDaniel Stenberg <daniel@haxx.se>
Tue, 7 May 2024 12:28:29 +0000 (14:28 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 8 May 2024 08:10:12 +0000 (10:10 +0200)
... instead of malloc and memcpy

- unit test 2604 verifies Curl_get_pathname()

Closes #13550

lib/curl_path.c
lib/curl_path.h
tests/data/Makefile.inc
tests/data/test2604 [new file with mode: 0644]
tests/unit/Makefile.inc
tests/unit/unit2604.c [new file with mode: 0644]

index 856423db997da61cd2335ecc84915cd8435f6dfd..144f8803d3a668aae3d7e15a4edf832d617d9ed4 100644 (file)
@@ -98,8 +98,8 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-/* The get_pathname() function is being borrowed from OpenSSH sftp.c
-   version 4.6p1. */
+/* The original get_pathname() function came from OpenSSH sftp.c version
+   4.6p1. */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -115,38 +115,37 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
+
+#define MAX_PATHLENGTH 65535 /* arbitrary long */
+
+CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir)
 {
   const char *cp = *cpp, *end;
   char quot;
-  unsigned int i, j;
-  size_t fullPathLength, pathLength;
-  bool relativePath = false;
+  unsigned int i;
   static const char WHITESPACE[] = " \t\r\n";
+  struct dynbuf out;
+  CURLcode result;
 
   DEBUGASSERT(homedir);
-  if(!*cp || !homedir) {
-    *cpp = NULL;
-    *path = NULL;
+  *path = NULL;
+  *cpp = NULL;
+  if(!*cp || !homedir)
     return CURLE_QUOTE_ERROR;
-  }
+
+  Curl_dyn_init(&out, MAX_PATHLENGTH);
+
   /* Ignore leading whitespace */
   cp += strspn(cp, WHITESPACE);
-  /* Allocate enough space for home directory and filename + separator */
-  fullPathLength = strlen(cp) + strlen(homedir) + 2;
-  *path = malloc(fullPathLength);
-  if(!*path)
-    return CURLE_OUT_OF_MEMORY;
 
   /* Check for quoted filenames */
   if(*cp == '\"' || *cp == '\'') {
     quot = *cp++;
 
     /* Search for terminating quote, unescape some chars */
-    for(i = j = 0; i <= strlen(cp); i++) {
+    for(i = 0; i <= strlen(cp); i++) {
       if(cp[i] == quot) {  /* Found quote */
         i++;
-        (*path)[j] = '\0';
         break;
       }
       if(cp[i] == '\0') {  /* End of string */
@@ -159,40 +158,45 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
           goto fail;
         }
       }
-      (*path)[j++] = cp[i];
+      result = Curl_dyn_addn(&out, &cp[i], 1);
+      if(result)
+        return result;
     }
 
-    if(j == 0) {
+    if(!Curl_dyn_len(&out))
       goto fail;
-    }
-    *cpp = cp + i + strspn(cp + i, WHITESPACE);
+
+    /* return pointer to second parameter if it exists */
+    *cpp = &cp[i] + strspn(&cp[i], WHITESPACE);
   }
   else {
     /* Read to end of filename - either to whitespace or terminator */
     end = strpbrk(cp, WHITESPACE);
     if(!end)
       end = strchr(cp, '\0');
+
     /* return pointer to second parameter if it exists */
     *cpp = end + strspn(end, WHITESPACE);
-    pathLength = 0;
-    relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/');
+
     /* Handling for relative path - prepend home directory */
-    if(relativePath) {
-      strcpy(*path, homedir);
-      pathLength = strlen(homedir);
-      (*path)[pathLength++] = '/';
-      (*path)[pathLength] = '\0';
+    if(cp[0] == '/' && cp[1] == '~' && cp[2] == '/') {
+      result = Curl_dyn_add(&out, homedir);
+      if(!result)
+        result = Curl_dyn_addn(&out, "/", 1);
+      if(result)
+        return result;
       cp += 3;
     }
     /* Copy path name up until first "whitespace" */
-    memcpy(&(*path)[pathLength], cp, (int)(end - cp));
-    pathLength += (int)(end - cp);
-    (*path)[pathLength] = '\0';
+    result = Curl_dyn_addn(&out, cp, (end - cp));
+    if(result)
+      return result;
   }
+  *path = Curl_dyn_ptr(&out);
   return CURLE_OK;
 
 fail:
-  Curl_safefree(*path);
+  Curl_dyn_free(&out);
   return CURLE_QUOTE_ERROR;
 }
 
index cbe51c221761fed9c02511f896d10cf1d5068346..6fdb2fddfff47370afcab4a2e2a4179b775bfe58 100644 (file)
@@ -45,5 +45,5 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,
                              char **path);
 
-CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
+CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir);
 #endif /* HEADER_CURL_PATH_H */
index 75eb68e843742b791548e2e1aaf8b919f488f791..6f6b1792416eff11a3d033bc3b82ee4d771ab1d9 100644 (file)
@@ -252,7 +252,7 @@ test2400 test2401 test2402 test2403 test2404 test2405 test2406 \
 \
 test2500 test2501 test2502 test2503 \
 \
-test2600 test2601 test2602 test2603 \
+test2600 test2601 test2602 test2603 test2604 \
 \
 test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
 test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \
diff --git a/tests/data/test2604 b/tests/data/test2604
new file mode 100644 (file)
index 0000000..4e825aa
--- /dev/null
@@ -0,0 +1,22 @@
+<testcase>
+<info>
+<keywords>
+unittest
+</keywords>
+</info>
+
+#
+# Client-side
+<client>
+<server>
+none
+</server>
+<features>
+unittest
+sftp
+</features>
+<name>
+Curl_get_pathname unit test
+</name>
+</client>
+</testcase>
index 677850cec37356c63eb69fbabdaec6bdf6f93649..1e48aadf918f9631af95daf67ed2511a3905faba 100644 (file)
@@ -38,7 +38,7 @@ UNITPROGS = unit1300          unit1302 unit1303 unit1304 unit1305 unit1307 \
  unit1620 unit1621 \
  unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
  unit1660 unit1661 \
- unit2600 unit2601 unit2602 unit2603 \
+ unit2600 unit2601 unit2602 unit2603 unit2604 \
  unit3200 \
  unit3205
 
@@ -134,6 +134,8 @@ unit2602_SOURCES = unit2602.c $(UNITFILES)
 
 unit2603_SOURCES = unit2603.c $(UNITFILES)
 
+unit2604_SOURCES = unit2604.c $(UNITFILES)
+
 unit3200_SOURCES = unit3200.c $(UNITFILES)
 
 unit3205_SOURCES = unit3205.c $(UNITFILES)
diff --git a/tests/unit/unit2604.c b/tests/unit/unit2604.c
new file mode 100644 (file)
index 0000000..9b5669a
--- /dev/null
@@ -0,0 +1,105 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 "curlcheck.h"
+#include "curl_path.h"
+
+static CURLcode unit_setup(void)
+{
+  return CURLE_OK;
+}
+
+static void unit_stop(void)
+{
+}
+
+
+struct set {
+  const char *cp;
+  const char *expect; /* the returned content */
+  const char *next;   /* what cp points to after the call */
+  const char *home;
+  CURLcode result;
+};
+
+UNITTEST_START
+#ifdef USE_SSH
+{
+#define LONG_A "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+#define LONG_AA LONG_A LONG_A LONG_A LONG_A LONG_A LONG_A LONG_A LONG_A LONG_A
+#define LONG_AAA LONG_AA LONG_AA LONG_AA LONG_AA LONG_AA LONG_AA LONG_AA
+#define LONG_AAAA LONG_AAA LONG_AAA LONG_AAA LONG_AAA LONG_AAA LONG_AAA
+#define LONG_AAAAA LONG_AAAA LONG_AAAA LONG_AAAA LONG_AAAA
+  int i;
+  int error = 0;
+  struct set list[] = {
+    { LONG_AAAAA " b", "", "", "", CURLE_TOO_LARGE},
+    { LONG_AA " c", LONG_AA, "c", "/", CURLE_OK},
+    { "\" " LONG_AA "\" c", " " LONG_AA, "c", "/", CURLE_OK},
+    { "a a", "a", "a", "/home/", CURLE_OK},
+    { "b a", "b", "a", "/", CURLE_OK},
+    { "a", "a", "", "/home/", CURLE_OK},
+    { "b", "b", "", "/", CURLE_OK},
+    { "\"foo bar\"\tb", "foo bar", "b", "/", CURLE_OK},
+    { "/~/hej", "/home/user/hej", "", "/home/user", CURLE_OK},
+    { "\"foo bar", "", "", "/", CURLE_QUOTE_ERROR},
+    { "\"foo\\\"bar\" a", "foo\"bar", "a", "/", CURLE_OK},
+    { "\"foo\\\'bar\" b", "foo\'bar", "b", "/", CURLE_OK},
+    { "\"foo\\\\bar\" c", "foo\\bar", "c", "/", CURLE_OK},
+    { "\"foo\\pbar\" c", "foo\\bar", "", "/", CURLE_QUOTE_ERROR},
+    { "\"\" c", "", "", "", CURLE_QUOTE_ERROR},
+    { "foo\"", "foo\"", "", "/", CURLE_OK},
+    { "foo \"", "foo", "\"", "/", CURLE_OK},
+    { NULL, NULL, NULL, NULL, CURLE_OK }
+  };
+
+  for(i = 0; list[i].home; i++) {
+    char *path;
+    const char *cp = list[i].cp;
+    CURLcode result = Curl_get_pathname(&cp, &path, list[i].home);
+    printf("%u - Curl_get_pathname(\"%s\", ... \"%s\") == %u\n", i,
+           list[i].cp, list[i].home, list[i].result);
+    if(result != list[i].result) {
+      printf("... returned %d\n", result);
+      error++;
+    }
+    if(!result) {
+      if(cp && strcmp(cp, list[i].next)) {
+        printf("... cp points to '%s', not '%s' as expected \n",
+               cp, list[i].next);
+        error++;
+      }
+      if(path && strcmp(path, list[i].expect)) {
+        printf("... gave '%s', not '%s' as expected \n",
+               path, list[i].expect);
+        error++;
+      }
+      curl_free(path);
+
+    }
+  }
+  return error;
+}
+#endif
+
+UNITTEST_STOP