#include "tool_dirhie.h"
#include "tool_msgs.h"
+#include "dynbuf.h"
#include "memdebug.h" /* keep this as LAST include */
#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;
}