ManaPlus
mkdir.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2010 The Mana Developers
4  * Copyright (C) 2011-2019 The ManaPlus Developers
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "fs/mkdir.h"
23 
24 #include "utils/cast.h"
25 
26 #if defined WIN32
27 #include <limits.h>
28 #include <windows.h>
29 #endif // defined WIN32
30 
31 #include <sys/stat.h>
32 
33 #include "debug.h"
34 
35 #if defined WIN32
36 int mkdir_r(const char *const pathname)
37 {
38  if (!pathname)
39  return -1;
40 
41  char tmp[PATH_MAX];
42  char tmp2[PATH_MAX];
43  char *p;
44 
45  if (strlen(pathname) >= PATH_MAX - 2)
46  return -1;
47 
48  strncpy(tmp, pathname, sizeof(tmp) - 1);
49  tmp[PATH_MAX - 1] = '\0';
50 
51  const int len = CAST_S32(strlen(tmp));
52 
53  if (len < 1 || len >= INT_MAX)
54  return -1;
55 
56  // terminate the pathname with '/'
57  if (tmp[len - 1] != '/')
58  {
59  tmp[len] = '/';
60  tmp[len + 1] = '\0';
61  }
62 
63  for (p = tmp; *p; p++)
64  {
65  if (*p == '/' || *p == '\\')
66  {
67  *p = '\0';
68  // ignore a slash at the beginning of a path
69  if (tmp[0] == 0)
70  {
71  *p = '/';
72  continue;
73  }
74 
75  strcpy(tmp2, tmp);
76  char *p2 = tmp2 + strlen(tmp2) - 1;
77  if (*p2 == '/' || *p2 == '\\')
78  *p2 = 0;
79  // check if the name already exists, but not as directory
80  struct stat statbuf;
81  if (!stat(tmp2, &statbuf))
82  {
83  if (S_ISDIR(statbuf.st_mode))
84  {
85  *p = '/';
86  continue;
87  }
88  else
89  return -1;
90  }
91 
92  if (!CreateDirectory(tmp2, nullptr))
93  {
94  // hack, hack. just assume that x: might be a drive
95  // letter, and try again
96  if (!(strlen(tmp2) == 2 && !strcmp(tmp2 + 1, ":")))
97  return -1;
98  }
99 
100  *p = '/';
101  }
102  }
103  return 0;
104 }
105 #else // WIN32
106 
108 int mkdir_r(const char *const pathname)
109 {
110  if (pathname == nullptr)
111  return -1;
112 
113  const size_t len = CAST_SIZE(strlen(pathname));
114  char *tmp = new char[len + 2];
115  char *p = nullptr;
116 
117  strcpy(tmp, pathname);
118 
119  // terminate the pathname with '/'
120  if (tmp[len - 1] != '/')
121  {
122  tmp[len] = '/';
123  tmp[len + 1] = '\0';
124  }
125 
126  for (p = tmp; *p != 0; p++)
127  {
128  if (*p == '/')
129  {
130  *p = '\0';
131  // ignore a slash at the beginning of a path
132  if (tmp[0] == 0)
133  {
134  *p = '/';
135  continue;
136  }
137 
138  // check if the name already exists, but not as directory
139  struct stat statbuf;
140  if (stat(tmp, &statbuf) == 0)
141  {
142  if (S_ISDIR(statbuf.st_mode))
143  {
144  *p = '/';
145  continue;
146  }
147  else
148  {
149  delete []tmp;
150  return -1;
151  }
152  }
153 
154  if (mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
155  {
156  delete []tmp;
157  return -1;
158  }
159 
160  *p = '/';
161  }
162  }
163  delete []tmp;
164  return 0;
165 }
166 #endif // WIN32
cast.h
CAST_SIZE
#define CAST_SIZE
Definition: cast.h:33
mkdir.h
CAST_S32
#define CAST_S32
Definition: cast.h:29
mkdir_r
int mkdir_r(const char *const pathname)
Create a directory, making leading components first if necessary.
Definition: mkdir.cpp:108
VirtFs::mkdir
bool mkdir(const std::string &dirname)
Definition: fs.cpp:774
debug.h