Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/curl/src/tool_dirhie.c
2065 views
1
/***************************************************************************
2
* _ _ ____ _
3
* Project ___| | | | _ \| |
4
* / __| | | | |_) | |
5
* | (__| |_| | _ <| |___
6
* \___|\___/|_| \_\_____|
7
*
8
* Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9
*
10
* This software is licensed as described in the file COPYING, which
11
* you should have received as part of this distribution. The terms
12
* are also available at https://curl.se/docs/copyright.html.
13
*
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
* copies of the Software, and permit persons to whom the Software is
16
* furnished to do so, under the terms of the COPYING file.
17
*
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
* KIND, either express or implied.
20
*
21
* SPDX-License-Identifier: curl
22
*
23
***************************************************************************/
24
#include "tool_setup.h"
25
26
#include <sys/stat.h>
27
28
#if defined(_WIN32) && !defined(UNDER_CE)
29
# include <direct.h>
30
#endif
31
32
#include <curlx.h>
33
34
#include "tool_dirhie.h"
35
#include "tool_msgs.h"
36
37
#include <memdebug.h> /* keep this as LAST include */
38
39
#if defined(_WIN32) || (defined(MSDOS) && !defined(__DJGPP__))
40
# define mkdir(x,y) (mkdir)((x))
41
# ifndef F_OK
42
# define F_OK 0
43
# endif
44
#endif
45
46
static void show_dir_errno(struct GlobalConfig *global, const char *name)
47
{
48
switch(errno) {
49
#ifdef EACCES
50
/* !checksrc! disable ERRNOVAR 1 */
51
case EACCES:
52
errorf(global, "You do not have permission to create %s", name);
53
break;
54
#endif
55
#ifdef ENAMETOOLONG
56
case ENAMETOOLONG:
57
errorf(global, "The directory name %s is too long", name);
58
break;
59
#endif
60
#ifdef EROFS
61
case EROFS:
62
errorf(global, "%s resides on a read-only file system", name);
63
break;
64
#endif
65
#ifdef ENOSPC
66
case ENOSPC:
67
errorf(global, "No space left on the file system that will "
68
"contain the directory %s", name);
69
break;
70
#endif
71
#ifdef EDQUOT
72
case EDQUOT:
73
errorf(global, "Cannot create directory %s because you "
74
"exceeded your quota", name);
75
break;
76
#endif
77
default:
78
errorf(global, "Error creating directory %s", name);
79
break;
80
}
81
}
82
83
/*
84
* Create the needed directory hierarchy recursively in order to save
85
* multi-GETs in file output, ie:
86
* curl "http://example.org/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
87
* should create all the dir* automagically
88
*/
89
90
#if defined(_WIN32) || defined(__DJGPP__)
91
/* systems that may use either or when specifying a path */
92
#define PATH_DELIMITERS "\\/"
93
#else
94
#define PATH_DELIMITERS DIR_CHAR
95
#endif
96
97
CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global)
98
{
99
CURLcode result = CURLE_OK;
100
size_t outlen = strlen(outfile);
101
struct dynbuf dirbuf;
102
103
curlx_dyn_init(&dirbuf, outlen + 1);
104
105
while(*outfile) {
106
bool skip = FALSE;
107
size_t seplen = strspn(outfile, PATH_DELIMITERS);
108
size_t len = strcspn(&outfile[seplen], PATH_DELIMITERS);
109
110
/* the last path component is the file and it ends with a null byte */
111
if(!outfile[len + seplen])
112
break;
113
114
#if defined(_WIN32) || defined(MSDOS)
115
if(!curlx_dyn_len(&dirbuf)) {
116
/* Skip creating a drive's current directory. It may seem as though that
117
would harmlessly fail but it could be a corner case if X: did not
118
exist, since we would be creating it erroneously. eg if outfile is
119
X:\foo\bar\filename then do not mkdir X: This logic takes into
120
account unsupported drives !:, 1:, etc. */
121
if(len > 1 && (outfile[1]==':'))
122
skip = TRUE;
123
}
124
#endif
125
/* insert the leading separators (possibly plural) plus the following
126
directory name */
127
result = curlx_dyn_addn(&dirbuf, outfile, seplen + len);
128
if(result)
129
return result;
130
131
/* Create directory. Ignore access denied error to allow traversal. */
132
/* !checksrc! disable ERRNOVAR 1 */
133
if(!skip && (-1 == mkdir(curlx_dyn_ptr(&dirbuf), (mode_t)0000750)) &&
134
(errno != EACCES) && (errno != EEXIST)) {
135
show_dir_errno(global, curlx_dyn_ptr(&dirbuf));
136
result = CURLE_WRITE_ERROR;
137
break; /* get out of loop */
138
}
139
outfile += len + seplen;
140
}
141
142
curlx_dyn_free(&dirbuf);
143
144
return result;
145
}
146
147