Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/lib/libspl/mkdirp.c
48378 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* CDDL HEADER START
4
*
5
* The contents of this file are subject to the terms of the
6
* Common Development and Distribution License (the "License").
7
* You may not use this file except in compliance with the License.
8
*
9
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10
* or https://opensource.org/licenses/CDDL-1.0.
11
* See the License for the specific language governing permissions
12
* and limitations under the License.
13
*
14
* When distributing Covered Code, include this CDDL HEADER in each
15
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16
* If applicable, add the following below this CDDL HEADER, with the
17
* fields enclosed by brackets "[]" replaced with your own identifying
18
* information: Portions Copyright [yyyy] [name of copyright owner]
19
*
20
* CDDL HEADER END
21
*/
22
23
/*
24
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25
* Use is subject to license terms.
26
*/
27
28
/* Copyright (c) 1988 AT&T */
29
/* All Rights Reserved */
30
31
/*
32
* Creates directory and it's parents if the parents do not
33
* exist yet.
34
*
35
* Returns -1 if fails for reasons other than non-existing
36
* parents.
37
* Does NOT simplify pathnames with . or .. in them.
38
*/
39
40
#include <sys/types.h>
41
#include <libgen.h>
42
#include <stdlib.h>
43
#include <unistd.h>
44
#include <errno.h>
45
#include <string.h>
46
#include <sys/stat.h>
47
48
static char *simplify(const char *str);
49
50
int
51
mkdirp(const char *d, mode_t mode)
52
{
53
char *endptr, *ptr, *slash, *str;
54
55
str = simplify(d);
56
57
/* If space couldn't be allocated for the simplified names, return. */
58
59
if (str == NULL)
60
return (-1);
61
62
/* Try to make the directory */
63
64
if (mkdir(str, mode) == 0) {
65
free(str);
66
return (0);
67
}
68
if (errno != ENOENT) {
69
free(str);
70
return (-1);
71
}
72
endptr = strrchr(str, '\0');
73
slash = strrchr(str, '/');
74
75
/* Search upward for the non-existing parent */
76
77
while (slash != NULL) {
78
79
ptr = slash;
80
*ptr = '\0';
81
82
/* If reached an existing parent, break */
83
84
if (access(str, F_OK) == 0)
85
break;
86
87
/* If non-existing parent */
88
89
else {
90
slash = strrchr(str, '/');
91
92
/* If under / or current directory, make it. */
93
94
if (slash == NULL || slash == str) {
95
if (mkdir(str, mode) != 0 && errno != EEXIST) {
96
free(str);
97
return (-1);
98
}
99
break;
100
}
101
}
102
}
103
104
/* Create directories starting from upmost non-existing parent */
105
106
while ((ptr = strchr(str, '\0')) != endptr) {
107
*ptr = '/';
108
if (mkdir(str, mode) != 0 && errno != EEXIST) {
109
/*
110
* If the mkdir fails because str already
111
* exists (EEXIST), then str has the form
112
* "existing-dir/..", and this is really
113
* ok. (Remember, this loop is creating the
114
* portion of the path that didn't exist)
115
*/
116
free(str);
117
return (-1);
118
}
119
}
120
free(str);
121
return (0);
122
}
123
124
/*
125
* simplify - given a pathname, simplify that path by removing
126
* duplicate contiguous slashes.
127
*
128
* A simplified copy of the argument is returned to the
129
* caller, or NULL is returned on error.
130
*
131
* The caller should handle error reporting based upon the
132
* returned value, and should free the returned value,
133
* when appropriate.
134
*/
135
136
static char *
137
simplify(const char *str)
138
{
139
int i;
140
size_t mbPathlen; /* length of multi-byte path */
141
size_t wcPathlen; /* length of wide-character path */
142
wchar_t *wptr; /* scratch pointer */
143
wchar_t *wcPath; /* wide-character version of the path */
144
char *mbPath; /* The copy fo the path to be returned */
145
146
/*
147
* bail out if there is nothing there.
148
*/
149
150
if (!str) {
151
errno = ENOENT;
152
return (NULL);
153
}
154
155
/*
156
* Get a copy of the argument.
157
*/
158
159
if ((mbPath = strdup(str)) == NULL) {
160
return (NULL);
161
}
162
163
/*
164
* convert the multi-byte version of the path to a
165
* wide-character rendering, for doing our figuring.
166
*/
167
168
mbPathlen = strlen(mbPath);
169
170
if ((wcPath = calloc(mbPathlen+1, sizeof (wchar_t))) == NULL) {
171
free(mbPath);
172
return (NULL);
173
}
174
175
if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) {
176
free(mbPath);
177
free(wcPath);
178
return (NULL);
179
}
180
181
/*
182
* remove duplicate slashes first ("//../" -> "/")
183
*/
184
185
for (wptr = wcPath, i = 0; i < wcPathlen; i++) {
186
*wptr++ = wcPath[i];
187
188
if (wcPath[i] == '/') {
189
i++;
190
191
while (wcPath[i] == '/') {
192
i++;
193
}
194
195
i--;
196
}
197
}
198
199
*wptr = '\0';
200
201
/*
202
* now convert back to the multi-byte format.
203
*/
204
205
if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) {
206
free(mbPath);
207
free(wcPath);
208
return (NULL);
209
}
210
211
free(wcPath);
212
return (mbPath);
213
}
214
215