GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/mkdir.cpp Lines: 23 27 85.2 %
Date: 2017-11-29 Branches: 12 16 75.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2010  The Mana Developers
4
 *  Copyright (C) 2011-2017  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
107
/// Create a directory, making leading components first if necessary
108
1764
int mkdir_r(const char *const pathname)
109
{
110
1764
    if (pathname == nullptr)
111
        return -1;
112
113
1764
    const size_t len = CAST_SIZE(strlen(pathname));
114
1764
    char *tmp = new char[len + 2];
115
1764
    char *p = nullptr;
116
117
1764
    strcpy(tmp, pathname);
118
119
    // terminate the pathname with '/'
120
1764
    if (tmp[len - 1] != '/')
121
    {
122
1764
        tmp[len] = '/';
123
1764
        tmp[len + 1] = '\0';
124
    }
125
126
96256
    for (p = tmp; *p != 0; p++)
127
    {
128
47246
        if (*p == '/')
129
        {
130
9498
            *p = '\0';
131
            // ignore a slash at the beginning of a path
132
11258
            if (tmp[0] == 0)
133
            {
134
1760
                *p = '/';
135
11250
                continue;
136
            }
137
138
            // check if the name already exists, but not as directory
139
            struct stat statbuf;
140
7738
            if (stat(tmp, &statbuf) == 0)
141
            {
142
15460
                if (S_ISDIR(statbuf.st_mode))
143
                {
144
7730
                    *p = '/';
145
7730
                    continue;
146
                }
147
                else
148
                {
149
                    delete []tmp;
150
                    return -1;
151
                }
152
            }
153
154
8
            if (mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
155
            {
156
                delete []tmp;
157
                return -1;
158
            }
159
160
8
            *p = '/';
161
        }
162
    }
163
1764
    delete []tmp;
164
1764
    return 0;
165
}
166
#endif  // WIN32