ready for tagging
[util-vserver.git] / lib_internal / mkdir.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #ifdef HAVE_CONFIG_H
19 #  include <config.h>
20 #endif
21
22 #include <stdbool.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28
29 static enum { mkdirFAIL, mkdirSUCCESS, mkdirSKIP }
30 mkdirSingle(char const *path, char *end_ptr, int good_err)
31 {
32   *end_ptr = '\0';
33   if (mkdir(path, 0700)!=-1 || errno==EEXIST) {
34     *end_ptr = '/';
35     return mkdirSUCCESS;
36   }
37   else if (errno==good_err) {
38     *end_ptr = '/';
39     return mkdirSKIP;
40   }
41   else
42     return mkdirFAIL;
43 }
44
45 static char *
46 rstrchr(char *str, char c)
47 {
48   while (*str!=c) --str;
49   return str;
50 }
51
52 bool
53 mkdirRecursive(char const *path)
54 {
55   char                  buf[strlen(path)+1];
56   char *                ptr = buf + sizeof(buf) - 2;
57
58   if (path[0]!='/')      return false; // only absolute paths
59
60   strcpy(buf, path);
61
62   while (ptr>buf && (ptr = rstrchr(ptr, '/'))!=0) {
63     switch (mkdirSingle(buf, ptr, ENOENT)) {
64       case mkdirSUCCESS         :  break;
65       case mkdirSKIP            :  --ptr; continue;
66       case mkdirFAIL            :  return false;
67     }
68
69     break;      // implied by mkdirSUCCESS
70   }
71
72   assert(ptr!=0);
73   ++ptr;
74
75   while ((ptr=strchr(ptr, '/'))!=0) {
76     switch (mkdirSingle(buf, ptr, 0)) {
77       case mkdirSKIP            :
78       case mkdirFAIL            :  return false;
79       case mkdirSUCCESS         :  ++ptr; continue;
80     }
81   }
82
83   return true;
84 }