Fix two unused/possible-uninitialized var warnings.
[gnupg.git] / common / mkdir_p.c
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  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <sys/stat.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <stdarg.h>
25
26 #include "mkdir_p.h"
27 #include "stringhelp.h"
28 #include "logging.h"
29 #include "util.h"
30
31 #define DEBUG 0
32
33 int
34 amkdir_p (char **directory_components)
35 {
36   int count;
37   char **dirs;
38   int i;
39   int rc = 0;
40
41   for (count = 0; directory_components[count]; count ++)
42     ;
43
44   if (DEBUG)
45     log_debug ("%s: %d directory components.\n", __func__, count);
46
47   dirs = xcalloc (count, sizeof (char *));
48   for (i = 0; directory_components[i]; i ++)
49     {
50       if (i == 0)
51         dirs[i] = directory_components[i];
52       else
53         dirs[i] = make_filename (dirs[i - 1], directory_components[i], NULL);
54
55       if (DEBUG)
56         log_debug ("%s: Directory %d: `%s'.\n", __func__, i, dirs[i]);
57     }
58
59   for (i = count - 1; i >= 0; i --)
60     {
61       struct stat s;
62
63       if (DEBUG)
64         log_debug ("%s: stat(%s)\n", __func__, dirs[i]);
65
66       rc = stat (dirs[i], &s);
67       if (rc == 0 && ! S_ISDIR (s.st_mode))
68         {
69           if (DEBUG)
70             log_debug ("%s: %s exists, but is not a directory!\n",
71                        __func__, dirs[i]);
72           rc = gpg_error (GPG_ERR_ENOTDIR);
73           goto out;
74         }
75       else if (rc == 0)
76         {
77           /* Got a directory.  */
78           if (DEBUG)
79             log_debug ("%s: %s exists and is a directory!\n",
80                        __func__, dirs[i]);
81           break;
82         }
83       else if (errno == ENOENT)
84         /* This directory does not exist yet.  Continue walking up the
85            hierarchy.  */
86         {
87           if (DEBUG)
88             log_debug ("%s: %s does not exist!\n",
89                        __func__, dirs[i]);
90           continue;
91         }
92       else
93         /* Some other error code.  Die.  Note: this could be ENOTDIR
94            (we return this above), which means that a component of the
95            path prefix is not a directory.  */
96         {
97           if (DEBUG)
98             log_debug ("%s: stat(%s) => %s!\n",
99                        __func__, dirs[i], strerror (errno));
100           rc = gpg_error_from_syserror ();
101           goto out;
102         }
103     }
104
105   assert (i >= -1);
106   /* DIRS[I] exists.  Start with the following entry.  */
107   i ++;
108
109   for (; i < count; i ++)
110     {
111       if (DEBUG)
112         log_debug ("Creating directory: %s\n", dirs[i]);
113
114       rc = mkdir (dirs[i], S_IRUSR | S_IWUSR | S_IXUSR);
115       if (rc)
116         {
117           rc = gpg_error_from_syserror ();
118           goto out;
119         }
120     }
121
122  out:
123   for (i = 1; i < count; i ++)
124     xfree (dirs[i]);
125   xfree (dirs);
126
127   if (DEBUG)
128     log_debug ("%s: Returning %s\n", __func__, gpg_strerror (rc));
129
130   return rc;
131 }
132
133 int
134 mkdir_p (char *directory_component, ...)
135 {
136   va_list ap;
137   int i;
138   int space = 1;
139   char **dirs = xmalloc (space * sizeof (char *));
140   int rc;
141
142   dirs[0] = directory_component;
143
144   va_start (ap, directory_component);
145   for (i = 1; dirs[i - 1]; i ++)
146     {
147       if (i == space)
148         {
149           space = 2 * space;
150           dirs = xrealloc (dirs, space * sizeof (char *));
151         }
152       dirs[i] = va_arg (ap, char *);
153     }
154   va_end (ap);
155
156   rc = amkdir_p (dirs);
157
158   xfree (dirs);
159
160   return rc;
161 }