/***************************************************************************1* _ _ ____ _2* Project ___| | | | _ \| |3* / __| | | | |_) | |4* | (__| |_| | _ <| |___5* \___|\___/|_| \_\_____|6*7* Copyright (C) Daniel Stenberg, <[email protected]>, et al.8*9* This software is licensed as described in the file COPYING, which10* you should have received as part of this distribution. The terms11* are also available at https://curl.se/docs/copyright.html.12*13* You may opt to use, copy, modify, merge, publish, distribute and/or sell14* copies of the Software, and permit persons to whom the Software is15* furnished to do so, under the terms of the COPYING file.16*17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY18* KIND, either express or implied.19*20* SPDX-License-Identifier: curl21*22***************************************************************************/23#include "tool_setup.h"2425#include <sys/stat.h>2627#if defined(_WIN32) && !defined(UNDER_CE)28# include <direct.h>29#endif3031#include <curlx.h>3233#include "tool_dirhie.h"34#include "tool_msgs.h"3536#include <memdebug.h> /* keep this as LAST include */3738#if defined(_WIN32) || (defined(MSDOS) && !defined(__DJGPP__))39# define mkdir(x,y) (mkdir)((x))40# ifndef F_OK41# define F_OK 042# endif43#endif4445static void show_dir_errno(struct GlobalConfig *global, const char *name)46{47switch(errno) {48#ifdef EACCES49/* !checksrc! disable ERRNOVAR 1 */50case EACCES:51errorf(global, "You do not have permission to create %s", name);52break;53#endif54#ifdef ENAMETOOLONG55case ENAMETOOLONG:56errorf(global, "The directory name %s is too long", name);57break;58#endif59#ifdef EROFS60case EROFS:61errorf(global, "%s resides on a read-only file system", name);62break;63#endif64#ifdef ENOSPC65case ENOSPC:66errorf(global, "No space left on the file system that will "67"contain the directory %s", name);68break;69#endif70#ifdef EDQUOT71case EDQUOT:72errorf(global, "Cannot create directory %s because you "73"exceeded your quota", name);74break;75#endif76default:77errorf(global, "Error creating directory %s", name);78break;79}80}8182/*83* Create the needed directory hierarchy recursively in order to save84* multi-GETs in file output, ie:85* curl "http://example.org/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"86* should create all the dir* automagically87*/8889#if defined(_WIN32) || defined(__DJGPP__)90/* systems that may use either or when specifying a path */91#define PATH_DELIMITERS "\\/"92#else93#define PATH_DELIMITERS DIR_CHAR94#endif9596CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global)97{98CURLcode result = CURLE_OK;99size_t outlen = strlen(outfile);100struct dynbuf dirbuf;101102curlx_dyn_init(&dirbuf, outlen + 1);103104while(*outfile) {105bool skip = FALSE;106size_t seplen = strspn(outfile, PATH_DELIMITERS);107size_t len = strcspn(&outfile[seplen], PATH_DELIMITERS);108109/* the last path component is the file and it ends with a null byte */110if(!outfile[len + seplen])111break;112113#if defined(_WIN32) || defined(MSDOS)114if(!curlx_dyn_len(&dirbuf)) {115/* Skip creating a drive's current directory. It may seem as though that116would harmlessly fail but it could be a corner case if X: did not117exist, since we would be creating it erroneously. eg if outfile is118X:\foo\bar\filename then do not mkdir X: This logic takes into119account unsupported drives !:, 1:, etc. */120if(len > 1 && (outfile[1]==':'))121skip = TRUE;122}123#endif124/* insert the leading separators (possibly plural) plus the following125directory name */126result = curlx_dyn_addn(&dirbuf, outfile, seplen + len);127if(result)128return result;129130/* Create directory. Ignore access denied error to allow traversal. */131/* !checksrc! disable ERRNOVAR 1 */132if(!skip && (-1 == mkdir(curlx_dyn_ptr(&dirbuf), (mode_t)0000750)) &&133(errno != EACCES) && (errno != EEXIST)) {134show_dir_errno(global, curlx_dyn_ptr(&dirbuf));135result = CURLE_WRITE_ERROR;136break; /* get out of loop */137}138outfile += len + seplen;139}140141curlx_dyn_free(&dirbuf);142143return result;144}145146147