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