1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #include <sys/stat.h>
27*6236dae4SAndroid Build Coastguard Worker
28*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
29*6236dae4SAndroid Build Coastguard Worker # include <direct.h>
30*6236dae4SAndroid Build Coastguard Worker #endif
31*6236dae4SAndroid Build Coastguard Worker
32*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
33*6236dae4SAndroid Build Coastguard Worker
34*6236dae4SAndroid Build Coastguard Worker #include "tool_dirhie.h"
35*6236dae4SAndroid Build Coastguard Worker #include "tool_msgs.h"
36*6236dae4SAndroid Build Coastguard Worker
37*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
38*6236dae4SAndroid Build Coastguard Worker
39*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || (defined(MSDOS) && !defined(__DJGPP__))
40*6236dae4SAndroid Build Coastguard Worker # define mkdir(x,y) (mkdir)((x))
41*6236dae4SAndroid Build Coastguard Worker # ifndef F_OK
42*6236dae4SAndroid Build Coastguard Worker # define F_OK 0
43*6236dae4SAndroid Build Coastguard Worker # endif
44*6236dae4SAndroid Build Coastguard Worker #endif
45*6236dae4SAndroid Build Coastguard Worker
show_dir_errno(struct GlobalConfig * global,const char * name)46*6236dae4SAndroid Build Coastguard Worker static void show_dir_errno(struct GlobalConfig *global, const char *name)
47*6236dae4SAndroid Build Coastguard Worker {
48*6236dae4SAndroid Build Coastguard Worker switch(errno) {
49*6236dae4SAndroid Build Coastguard Worker #ifdef EACCES
50*6236dae4SAndroid Build Coastguard Worker case EACCES:
51*6236dae4SAndroid Build Coastguard Worker errorf(global, "You do not have permission to create %s", name);
52*6236dae4SAndroid Build Coastguard Worker break;
53*6236dae4SAndroid Build Coastguard Worker #endif
54*6236dae4SAndroid Build Coastguard Worker #ifdef ENAMETOOLONG
55*6236dae4SAndroid Build Coastguard Worker case ENAMETOOLONG:
56*6236dae4SAndroid Build Coastguard Worker errorf(global, "The directory name %s is too long", name);
57*6236dae4SAndroid Build Coastguard Worker break;
58*6236dae4SAndroid Build Coastguard Worker #endif
59*6236dae4SAndroid Build Coastguard Worker #ifdef EROFS
60*6236dae4SAndroid Build Coastguard Worker case EROFS:
61*6236dae4SAndroid Build Coastguard Worker errorf(global, "%s resides on a read-only file system", name);
62*6236dae4SAndroid Build Coastguard Worker break;
63*6236dae4SAndroid Build Coastguard Worker #endif
64*6236dae4SAndroid Build Coastguard Worker #ifdef ENOSPC
65*6236dae4SAndroid Build Coastguard Worker case ENOSPC:
66*6236dae4SAndroid Build Coastguard Worker errorf(global, "No space left on the file system that will "
67*6236dae4SAndroid Build Coastguard Worker "contain the directory %s", name);
68*6236dae4SAndroid Build Coastguard Worker break;
69*6236dae4SAndroid Build Coastguard Worker #endif
70*6236dae4SAndroid Build Coastguard Worker #ifdef EDQUOT
71*6236dae4SAndroid Build Coastguard Worker case EDQUOT:
72*6236dae4SAndroid Build Coastguard Worker errorf(global, "Cannot create directory %s because you "
73*6236dae4SAndroid Build Coastguard Worker "exceeded your quota", name);
74*6236dae4SAndroid Build Coastguard Worker break;
75*6236dae4SAndroid Build Coastguard Worker #endif
76*6236dae4SAndroid Build Coastguard Worker default:
77*6236dae4SAndroid Build Coastguard Worker errorf(global, "Error creating directory %s", name);
78*6236dae4SAndroid Build Coastguard Worker break;
79*6236dae4SAndroid Build Coastguard Worker }
80*6236dae4SAndroid Build Coastguard Worker }
81*6236dae4SAndroid Build Coastguard Worker
82*6236dae4SAndroid Build Coastguard Worker /*
83*6236dae4SAndroid Build Coastguard Worker * Create the needed directory hierarchy recursively in order to save
84*6236dae4SAndroid Build Coastguard Worker * multi-GETs in file output, ie:
85*6236dae4SAndroid Build Coastguard Worker * curl "http://example.org/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
86*6236dae4SAndroid Build Coastguard Worker * should create all the dir* automagically
87*6236dae4SAndroid Build Coastguard Worker */
88*6236dae4SAndroid Build Coastguard Worker
89*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(__DJGPP__)
90*6236dae4SAndroid Build Coastguard Worker /* systems that may use either or when specifying a path */
91*6236dae4SAndroid Build Coastguard Worker #define PATH_DELIMITERS "\\/"
92*6236dae4SAndroid Build Coastguard Worker #else
93*6236dae4SAndroid Build Coastguard Worker #define PATH_DELIMITERS DIR_CHAR
94*6236dae4SAndroid Build Coastguard Worker #endif
95*6236dae4SAndroid Build Coastguard Worker
96*6236dae4SAndroid Build Coastguard Worker
create_dir_hierarchy(const char * outfile,struct GlobalConfig * global)97*6236dae4SAndroid Build Coastguard Worker CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global)
98*6236dae4SAndroid Build Coastguard Worker {
99*6236dae4SAndroid Build Coastguard Worker char *tempdir;
100*6236dae4SAndroid Build Coastguard Worker char *tempdir2;
101*6236dae4SAndroid Build Coastguard Worker char *outdup;
102*6236dae4SAndroid Build Coastguard Worker char *dirbuildup;
103*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
104*6236dae4SAndroid Build Coastguard Worker size_t outlen;
105*6236dae4SAndroid Build Coastguard Worker
106*6236dae4SAndroid Build Coastguard Worker outlen = strlen(outfile);
107*6236dae4SAndroid Build Coastguard Worker outdup = strdup(outfile);
108*6236dae4SAndroid Build Coastguard Worker if(!outdup)
109*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
110*6236dae4SAndroid Build Coastguard Worker
111*6236dae4SAndroid Build Coastguard Worker dirbuildup = malloc(outlen + 1);
112*6236dae4SAndroid Build Coastguard Worker if(!dirbuildup) {
113*6236dae4SAndroid Build Coastguard Worker Curl_safefree(outdup);
114*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
115*6236dae4SAndroid Build Coastguard Worker }
116*6236dae4SAndroid Build Coastguard Worker dirbuildup[0] = '\0';
117*6236dae4SAndroid Build Coastguard Worker
118*6236dae4SAndroid Build Coastguard Worker /* Allow strtok() here since this is not used threaded */
119*6236dae4SAndroid Build Coastguard Worker /* !checksrc! disable BANNEDFUNC 2 */
120*6236dae4SAndroid Build Coastguard Worker tempdir = strtok(outdup, PATH_DELIMITERS);
121*6236dae4SAndroid Build Coastguard Worker
122*6236dae4SAndroid Build Coastguard Worker while(tempdir) {
123*6236dae4SAndroid Build Coastguard Worker bool skip = false;
124*6236dae4SAndroid Build Coastguard Worker tempdir2 = strtok(NULL, PATH_DELIMITERS);
125*6236dae4SAndroid Build Coastguard Worker /* since strtok returns a token for the last word even
126*6236dae4SAndroid Build Coastguard Worker if not ending with DIR_CHAR, we need to prune it */
127*6236dae4SAndroid Build Coastguard Worker if(tempdir2) {
128*6236dae4SAndroid Build Coastguard Worker size_t dlen = strlen(dirbuildup);
129*6236dae4SAndroid Build Coastguard Worker if(dlen)
130*6236dae4SAndroid Build Coastguard Worker msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir);
131*6236dae4SAndroid Build Coastguard Worker else {
132*6236dae4SAndroid Build Coastguard Worker if(outdup == tempdir) {
133*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(MSDOS)
134*6236dae4SAndroid Build Coastguard Worker /* Skip creating a drive's current directory.
135*6236dae4SAndroid Build Coastguard Worker It may seem as though that would harmlessly fail but it could be
136*6236dae4SAndroid Build Coastguard Worker a corner case if X: did not exist, since we would be creating it
137*6236dae4SAndroid Build Coastguard Worker erroneously.
138*6236dae4SAndroid Build Coastguard Worker eg if outfile is X:\foo\bar\filename then do not mkdir X:
139*6236dae4SAndroid Build Coastguard Worker This logic takes into account unsupported drives !:, 1:, etc. */
140*6236dae4SAndroid Build Coastguard Worker char *p = strchr(tempdir, ':');
141*6236dae4SAndroid Build Coastguard Worker if(p && !p[1])
142*6236dae4SAndroid Build Coastguard Worker skip = true;
143*6236dae4SAndroid Build Coastguard Worker #endif
144*6236dae4SAndroid Build Coastguard Worker /* the output string does not start with a separator */
145*6236dae4SAndroid Build Coastguard Worker strcpy(dirbuildup, tempdir);
146*6236dae4SAndroid Build Coastguard Worker }
147*6236dae4SAndroid Build Coastguard Worker else
148*6236dae4SAndroid Build Coastguard Worker msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir);
149*6236dae4SAndroid Build Coastguard Worker }
150*6236dae4SAndroid Build Coastguard Worker /* Create directory. Ignore access denied error to allow traversal. */
151*6236dae4SAndroid Build Coastguard Worker if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) &&
152*6236dae4SAndroid Build Coastguard Worker (errno != EACCES) && (errno != EEXIST)) {
153*6236dae4SAndroid Build Coastguard Worker show_dir_errno(global, dirbuildup);
154*6236dae4SAndroid Build Coastguard Worker result = CURLE_WRITE_ERROR;
155*6236dae4SAndroid Build Coastguard Worker break; /* get out of loop */
156*6236dae4SAndroid Build Coastguard Worker }
157*6236dae4SAndroid Build Coastguard Worker }
158*6236dae4SAndroid Build Coastguard Worker tempdir = tempdir2;
159*6236dae4SAndroid Build Coastguard Worker }
160*6236dae4SAndroid Build Coastguard Worker
161*6236dae4SAndroid Build Coastguard Worker Curl_safefree(dirbuildup);
162*6236dae4SAndroid Build Coastguard Worker Curl_safefree(outdup);
163*6236dae4SAndroid Build Coastguard Worker
164*6236dae4SAndroid Build Coastguard Worker return result;
165*6236dae4SAndroid Build Coastguard Worker }
166