]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_dirhie: create dir hierarchy without strtok
authorDaniel Stenberg <daniel@haxx.se>
Wed, 5 Mar 2025 08:10:21 +0000 (09:10 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 5 Mar 2025 12:26:33 +0000 (13:26 +0100)
And use dynbuf

Closes #16566

src/tool_dirhie.c

index 0536dff7d25c0530cc0c2ba77e97aa98e5d9ad97..1360ddd6bb2a098bc122c9e2421960c7bdaad045 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "tool_dirhie.h"
 #include "tool_msgs.h"
+#include "dynbuf.h"
 
 #include "memdebug.h" /* keep this as LAST include */
 
@@ -93,73 +94,51 @@ static void show_dir_errno(struct GlobalConfig *global, const char *name)
 #define PATH_DELIMITERS DIR_CHAR
 #endif
 
-
 CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global)
 {
-  char *tempdir;
-  char *tempdir2;
-  char *outdup;
-  char *dirbuildup;
   CURLcode result = CURLE_OK;
-  size_t outlen;
+  size_t outlen = strlen(outfile);
+  struct curlx_dynbuf dirbuf;
 
-  outlen = strlen(outfile);
-  outdup = strdup(outfile);
-  if(!outdup)
-    return CURLE_OUT_OF_MEMORY;
+  curlx_dyn_init(&dirbuf, outlen + 1);
+
+  while(*outfile) {
+    bool skip = FALSE;
+    size_t seplen = strspn(outfile, PATH_DELIMITERS);
+    size_t len = strcspn(&outfile[seplen], PATH_DELIMITERS);
+
+    /* the last path component is the file and it ends with a null byte */
+    if(!outfile[len + seplen])
+      break;
 
-  dirbuildup = malloc(outlen + 1);
-  if(!dirbuildup) {
-    Curl_safefree(outdup);
-    return CURLE_OUT_OF_MEMORY;
-  }
-  dirbuildup[0] = '\0';
-
-  /* Allow strtok() here since this is not used threaded */
-  /* !checksrc! disable BANNEDFUNC 2 */
-  tempdir = strtok(outdup, PATH_DELIMITERS);
-
-  while(tempdir) {
-    bool skip = false;
-    tempdir2 = strtok(NULL, PATH_DELIMITERS);
-    /* since strtok returns a token for the last word even
-       if not ending with DIR_CHAR, we need to prune it */
-    if(tempdir2) {
-      size_t dlen = strlen(dirbuildup);
-      if(dlen)
-        msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir);
-      else {
-        if(outdup == tempdir) {
 #if defined(_WIN32) || defined(MSDOS)
-          /* Skip creating a drive's current directory.
-             It may seem as though that would harmlessly fail but it could be
-             a corner case if X: did not exist, since we would be creating it
-             erroneously.
-             eg if outfile is X:\foo\bar\filename then do not mkdir X:
-             This logic takes into account unsupported drives !:, 1:, etc. */
-          char *p = strchr(tempdir, ':');
-          if(p && !p[1])
-            skip = true;
+    if(!curlx_dyn_len(&dirbuf)) {
+      /* Skip creating a drive's current directory. It may seem as though that
+         would harmlessly fail but it could be a corner case if X: did not
+         exist, since we would be creating it erroneously. eg if outfile is
+         X:\foo\bar\filename then do not mkdir X: This logic takes into
+         account unsupported drives !:, 1:, etc. */
+      if(len > 1 && (outfile[1]==':'))
+        skip = TRUE;
+    }
 #endif
-          /* the output string does not start with a separator */
-          strcpy(dirbuildup, tempdir);
-        }
-        else
-          msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir);
-      }
-      /* Create directory. Ignore access denied error to allow traversal. */
-      if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) &&
-         (errno != EACCES) && (errno != EEXIST)) {
-        show_dir_errno(global, dirbuildup);
-        result = CURLE_WRITE_ERROR;
-        break; /* get out of loop */
-      }
+    /* insert the leading separators (possibly plural) plus the following
+       directory name */
+    result = curlx_dyn_addn(&dirbuf, outfile, seplen + len);
+    if(result)
+      return result;
+
+    /* Create directory. Ignore access denied error to allow traversal. */
+    if(!skip && (-1 == mkdir(curlx_dyn_ptr(&dirbuf), (mode_t)0000750)) &&
+       (errno != EACCES) && (errno != EEXIST)) {
+      show_dir_errno(global, curlx_dyn_ptr(&dirbuf));
+      result = CURLE_WRITE_ERROR;
+      break; /* get out of loop */
     }
-    tempdir = tempdir2;
+    outfile += len + seplen;
   }
 
-  Curl_safefree(dirbuildup);
-  Curl_safefree(outdup);
+  curlx_dyn_free(&dirbuf);
 
   return result;
 }