Line data Source code
1 : /* mkdir_p.c - Create a directory and any missing parents.
2 : * Copyright (C) 2015 g10 Code GmbH
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * This file is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * This file is distributed in the hope that it will be useful,
22 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 : * GNU General Public License for more details.
25 : *
26 : * You should have received a copy of the GNU General Public License
27 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
28 : */
29 :
30 : #include <config.h>
31 : #include <sys/stat.h>
32 : #include <errno.h>
33 : #include <assert.h>
34 : #include <stdarg.h>
35 :
36 : #include "util.h"
37 : #include "stringhelp.h"
38 : #include "logging.h"
39 : #include "sysutils.h"
40 : #include "mkdir_p.h"
41 :
42 :
43 : gpg_error_t
44 0 : gnupg_amkdir_p (const char **directory_components)
45 : {
46 0 : gpg_error_t err = 0;
47 : int count;
48 : char **dirs;
49 : int i;
50 :
51 0 : for (count = 0; directory_components[count]; count ++)
52 : ;
53 :
54 : /* log_debug ("%s: %d directory components.\n", __func__, count); */
55 :
56 0 : dirs = xtrycalloc (count, sizeof *dirs);
57 0 : if (!dirs)
58 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
59 :
60 0 : for (i = 0; directory_components[i]; i ++)
61 : {
62 0 : if (i == 0)
63 0 : dirs[i] = make_filename_try (directory_components[i], NULL);
64 : else
65 0 : dirs[i] = make_filename_try (dirs[i-1], directory_components[i], NULL);
66 0 : if (!dirs[i])
67 : {
68 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
69 0 : goto out;
70 : }
71 :
72 : /* log_debug ("%s: Directory %d: `%s'.\n", __func__, i, dirs[i]); */
73 : }
74 :
75 0 : for (i = count - 1; i >= 0; i --)
76 : {
77 : struct stat s;
78 :
79 : /* log_debug ("%s: stat(%s)\n", __func__, dirs[i]); */
80 :
81 0 : if (!stat (dirs[i], &s))
82 : {
83 0 : if ( ! S_ISDIR (s.st_mode))
84 : {
85 : /* log_debug ("%s: %s exists, but is not a directory!\n", */
86 : /* __func__, dirs[i]); */
87 0 : err = gpg_err_make (default_errsource, GPG_ERR_ENOTDIR);
88 0 : goto out;
89 : }
90 : else
91 : {
92 : /* Got a directory. */
93 : /* log_debug ("%s: %s exists and is a directory!\n", */
94 : /* __func__, dirs[i]); */
95 0 : err = 0;
96 0 : break;
97 : }
98 : }
99 0 : else if (errno == ENOENT)
100 : /* This directory does not exist yet. Continue walking up the
101 : hierarchy. */
102 : {
103 : /* log_debug ("%s: %s does not exist!\n", */
104 : /* __func__, dirs[i]); */
105 0 : continue;
106 : }
107 : else
108 : /* Some other error code. Die. Note: this could be ENOTDIR
109 : (we return this above), which means that a component of the
110 : path prefix is not a directory. */
111 : {
112 : /* log_debug ("%s: stat(%s) => %s!\n", */
113 : /* __func__, dirs[i], strerror (errno)); */
114 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
115 0 : goto out;
116 : }
117 : }
118 :
119 0 : assert (i >= -1);
120 : /* DIRS[I] exists. Start with the following entry. */
121 0 : i ++;
122 :
123 0 : for (; i < count; i ++)
124 : {
125 : /* log_debug ("Creating directory: %s\n", dirs[i]); */
126 :
127 0 : if (gnupg_mkdir (dirs[i], "-rwx"))
128 : {
129 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
130 0 : goto out;
131 : }
132 : }
133 :
134 : out:
135 0 : for (i = 0; i < count; i ++)
136 0 : xfree (dirs[i]);
137 0 : xfree (dirs);
138 :
139 : /* log_debug ("%s: Returning %s\n", __func__, gpg_strerror (rc)); */
140 :
141 0 : return err;
142 : }
143 :
144 :
145 : gpg_error_t
146 0 : gnupg_mkdir_p (const char *directory_component, ...)
147 : {
148 : va_list ap;
149 0 : gpg_error_t err = 0;
150 : int i;
151 0 : int space = 1;
152 : const char **dirs;
153 :
154 0 : dirs = xtrymalloc (space * sizeof (char *));
155 0 : if (!dirs)
156 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
157 :
158 0 : dirs[0] = directory_component;
159 :
160 0 : va_start (ap, directory_component);
161 0 : for (i = 1; dirs[i - 1]; i ++)
162 : {
163 0 : if (i == space)
164 : {
165 : const char **tmp_dirs;
166 :
167 0 : space = 2 * space;
168 0 : tmp_dirs = xtryrealloc (dirs, space * sizeof (char *));
169 0 : if (!tmp_dirs)
170 : {
171 0 : err = gpg_err_make (default_errsource,
172 : gpg_err_code_from_syserror ());
173 0 : break;
174 : }
175 0 : dirs = tmp_dirs;
176 : }
177 0 : dirs[i] = va_arg (ap, char *);
178 : }
179 0 : va_end (ap);
180 :
181 0 : if (!err)
182 0 : err = gnupg_amkdir_p (dirs);
183 :
184 0 : xfree (dirs);
185 :
186 0 : return err;
187 : }
|