xref: /4.0.0/platform/src/dirutils.cc (revision bcdf4026)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2013 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17#include "config.h"
18#include <platform/dirutils.h>
19
20#ifdef _MSC_VER
21#include <direct.h>
22#define rmdir _rmdir
23#else
24#include <dirent.h>
25#include <unistd.h>
26#endif
27
28#include <stdio.h>
29#include <string.h>
30#include <sys/stat.h>
31
32namespace CouchbaseDirectoryUtilities
33{
34    using namespace std;
35
36    static string split(const string &input, bool directory)
37    {
38        string::size_type path = input.find_last_of("\\/");
39        string file;
40        string dir;
41
42        if (path == string::npos) {
43            dir = ".";
44            file = input;
45        } else {
46            dir = input.substr(0, path);
47            if (dir.length() == 0) {
48                dir = input.substr(0, 1);
49            }
50
51            while (dir.length() > 1 && dir.find_last_of("\\/") == (dir.length() - 1)) {
52                if (dir.length() > 1) {
53                    dir.resize(dir.length() - 1);
54                }
55            }
56
57            file = input.substr(path + 1);
58        }
59
60        if (directory) {
61            return dir;
62        } else {
63            return file;
64        }
65    }
66
67    PLATFORM_PUBLIC_API
68    string dirname(const string &dir)
69    {
70        return split(dir, true);
71    }
72
73    PLATFORM_PUBLIC_API
74    string basename(const string &name)
75    {
76        return split(name, false);
77    }
78
79#ifdef _MSC_VER
80    PLATFORM_PUBLIC_API
81    vector<string> findFilesWithPrefix(const string &dir, const string &name)
82    {
83        vector<string> files;
84        std::string match = dir + "\\" + name + "*";
85        WIN32_FIND_DATA FindFileData;
86
87        HANDLE hFind = FindFirstFileEx(match.c_str(), FindExInfoStandard,
88                                       &FindFileData, FindExSearchNameMatch,
89                                       NULL, 0);
90
91        if (hFind != INVALID_HANDLE_VALUE) {
92            do {
93                string fnm(FindFileData.cFileName);
94                if (fnm != "." && fnm != "..") {
95                    string entry = dir;
96                    entry.append("\\");
97                    entry.append(FindFileData.cFileName);
98                    files.push_back(entry);
99                }
100            } while (FindNextFile(hFind, &FindFileData));
101
102            FindClose(hFind);
103        }
104        return files;
105    }
106#else
107    PLATFORM_PUBLIC_API
108    vector<string> findFilesWithPrefix(const string &dir, const string &name)
109    {
110        vector<string> files;
111        DIR *dp = opendir(dir.c_str());
112        if (dp != NULL) {
113            struct dirent *de;
114            while ((de = readdir(dp)) != NULL) {
115                string fnm(de->d_name);
116                if (fnm == "." || fnm == "..") {
117                    continue;
118                }
119                if (strncmp(de->d_name, name.c_str(), name.length()) == 0) {
120                    string entry = dir;
121                    entry.append("/");
122                    entry.append(de->d_name);
123                    files.push_back(entry);
124                }
125            }
126
127            closedir(dp);
128        }
129        return files;
130    }
131#endif
132
133    PLATFORM_PUBLIC_API
134    vector<string> findFilesWithPrefix(const string &name)
135    {
136        return findFilesWithPrefix(dirname(name), basename(name));
137    }
138
139#ifdef _MSC_VER
140    PLATFORM_PUBLIC_API
141    vector<string> findFilesContaining(const string &dir, const string &name)
142    {
143        vector<string> files;
144        std::string match = dir + "\\*" + name + "*";
145        WIN32_FIND_DATA FindFileData;
146
147        HANDLE hFind = FindFirstFileEx(match.c_str(), FindExInfoStandard,
148                                       &FindFileData, FindExSearchNameMatch,
149                                       NULL, 0);
150
151        if (hFind != INVALID_HANDLE_VALUE) {
152            do {
153                string fnm(FindFileData.cFileName);
154                if (fnm != "." && fnm != "..") {
155                    string entry = dir;
156                    entry.append("\\");
157                    entry.append(FindFileData.cFileName);
158                    files.push_back(entry);
159                }
160            } while (FindNextFile(hFind, &FindFileData));
161
162            FindClose(hFind);
163        }
164        return files;
165    }
166#else
167    PLATFORM_PUBLIC_API
168    vector<string> findFilesContaining(const string &dir, const string &name)
169    {
170        vector<string> files;
171        DIR *dp = opendir(dir.c_str());
172        if (dp != NULL) {
173            struct dirent *de;
174            while ((de = readdir(dp)) != NULL) {
175                if (name.empty() || strstr(de->d_name, name.c_str()) != NULL) {
176                    string fnm(de->d_name);
177                    if (fnm != "." && fnm != "..") {
178                        string entry = dir;
179                        entry.append("/");
180                        entry.append(de->d_name);
181                        files.push_back(entry);
182                    }
183                }
184            }
185
186            closedir(dp);
187        }
188
189        return files;
190    }
191#endif
192
193    PLATFORM_PUBLIC_API
194    bool rmrf(const std::string &path) {
195        struct stat st;
196        if (stat(path.c_str(), &st) == -1) {
197            return false;
198        }
199
200        if ((st.st_mode & S_IFDIR) != S_IFDIR) {
201            return remove(path.c_str()) == 0;
202        }
203
204        if (rmdir(path.c_str()) == 0) {
205            return true;
206        }
207
208        // Ok, this is a directory. Go ahead and delete it recurively
209        std::vector<std::string> directories;
210        directories.push_back(path);
211        do {
212            std::vector<std::string> vec = findFilesContaining(directories.back(), "");
213            directories.pop_back();
214            std::vector<std::string>::iterator ii;
215
216            for (ii = vec.begin(); ii != vec.end(); ++ii) {
217                if (stat(ii->c_str(), &st) == -1) {
218                    return false;
219                }
220
221                if ((st.st_mode & S_IFDIR) == S_IFDIR) {
222                    if (rmdir(ii->c_str()) != 0) {
223                        directories.push_back(*ii);
224                    }
225                } else if (remove(ii->c_str()) != 0) {
226                    return false;
227                }
228            }
229        } while (!directories.empty());
230
231        return rmdir(path.c_str()) == 0;
232    }
233
234    PLATFORM_PUBLIC_API
235    bool isDirectory(const std::string &directory) {
236#ifdef WIN32
237        DWORD dwAttrib = GetFileAttributes(directory.c_str());
238        if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
239            return false;
240        }
241        return (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
242#else
243        struct stat st;
244        if (stat(directory.c_str(), &st) == -1) {
245            return false;
246        }
247        return (S_ISDIR(st.st_mode));
248#endif
249    }
250}
251