xref: /aosp_15_r20/external/curl/src/tool_dirhie.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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