/src/CMake/Source/kwsys/Directory.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ |
3 | | #include "kwsysPrivate.h" |
4 | | #include KWSYS_HEADER(Directory.hxx) |
5 | | |
6 | | #include KWSYS_HEADER(Configure.hxx) |
7 | | |
8 | | #include KWSYS_HEADER(Encoding.hxx) |
9 | | |
10 | | #include KWSYS_HEADER(SystemTools.hxx) |
11 | | |
12 | | // Work-around CMake dependency scanning limitation. This must |
13 | | // duplicate the above list of headers. |
14 | | #if 0 |
15 | | # include "Configure.hxx.in" |
16 | | # include "Directory.hxx.in" |
17 | | # include "Encoding.hxx.in" |
18 | | #endif |
19 | | |
20 | | #include <string> |
21 | | #include <utility> |
22 | | #include <vector> |
23 | | |
24 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
25 | | # include <windows.h> |
26 | | |
27 | | # include <ctype.h> |
28 | | # include <fcntl.h> |
29 | | # include <io.h> |
30 | | # include <stdio.h> |
31 | | # include <stdlib.h> |
32 | | # include <string.h> |
33 | | # include <sys/stat.h> |
34 | | # include <sys/types.h> |
35 | | #endif |
36 | | |
37 | | namespace KWSYS_NAMESPACE { |
38 | | |
39 | | class DirectoryInternals |
40 | | { |
41 | | public: |
42 | | struct FileData |
43 | | { |
44 | | std::string Name; |
45 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
46 | | WIN32_FIND_DATAW FindData; |
47 | | #endif |
48 | | FileData(std::string name |
49 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
50 | | , |
51 | | WIN32_FIND_DATAW data |
52 | | #endif |
53 | | ) |
54 | 3.79M | : Name(std::move(name)) |
55 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
56 | | , FindData(std::move(data)) |
57 | | #endif |
58 | 3.79M | { |
59 | 3.79M | } |
60 | | }; |
61 | | // Array of Files |
62 | | std::vector<FileData> Files; |
63 | | |
64 | | // Path to Open'ed directory |
65 | | std::string Path; |
66 | | }; |
67 | | |
68 | | Directory::Directory() |
69 | 63.0k | { |
70 | 63.0k | this->Internal = new DirectoryInternals; |
71 | 63.0k | } |
72 | | |
73 | | Directory::Directory(Directory&& other) |
74 | 0 | { |
75 | 0 | this->Internal = other.Internal; |
76 | 0 | other.Internal = nullptr; |
77 | 0 | } |
78 | | |
79 | | Directory& Directory::operator=(Directory&& other) |
80 | 0 | { |
81 | 0 | std::swap(this->Internal, other.Internal); |
82 | 0 | return *this; |
83 | 0 | } |
84 | | |
85 | | Directory::~Directory() |
86 | 63.0k | { |
87 | 63.0k | delete this->Internal; |
88 | 63.0k | } |
89 | | |
90 | | unsigned long Directory::GetNumberOfFiles() const |
91 | 157k | { |
92 | 157k | return static_cast<unsigned long>(this->Internal->Files.size()); |
93 | 157k | } |
94 | | |
95 | | char const* Directory::GetFile(unsigned long dindex) const |
96 | 0 | { |
97 | 0 | return this->Internal->Files[dindex].Name.c_str(); |
98 | 0 | } |
99 | | |
100 | | std::string const& Directory::GetFileName(std::size_t i) const |
101 | 141k | { |
102 | 141k | return this->Internal->Files[i].Name; |
103 | 141k | } |
104 | | |
105 | | std::string Directory::GetFilePath(std::size_t i) const |
106 | 0 | { |
107 | 0 | std::string abs = this->Internal->Path; |
108 | 0 | if (!abs.empty() && abs.back() != '/') { |
109 | 0 | abs += '/'; |
110 | 0 | } |
111 | 0 | abs += this->Internal->Files[i].Name; |
112 | 0 | return abs; |
113 | 0 | } |
114 | | |
115 | | bool Directory::FileIsDirectory(std::size_t i) const |
116 | 0 | { |
117 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
118 | | auto const& data = this->Internal->Files[i].FindData; |
119 | | return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; |
120 | | #else |
121 | 0 | std::string const& path = this->GetFilePath(i); |
122 | 0 | return kwsys::SystemTools::FileIsDirectory(path); |
123 | 0 | #endif |
124 | 0 | } |
125 | | |
126 | | bool Directory::FileIsSymlink(std::size_t i) const |
127 | 0 | { |
128 | 0 | std::string const& path = this->GetFilePath(i); |
129 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
130 | | auto const& data = this->Internal->Files[i].FindData; |
131 | | return kwsys::SystemTools::FileIsSymlinkWithAttr( |
132 | | Encoding::ToWindowsExtendedPath(path), data.dwFileAttributes); |
133 | | #else |
134 | 0 | return kwsys::SystemTools::FileIsSymlink(path); |
135 | 0 | #endif |
136 | 0 | } |
137 | | |
138 | | char const* Directory::GetPath() const |
139 | 0 | { |
140 | 0 | return this->Internal->Path.c_str(); |
141 | 0 | } |
142 | | |
143 | | void Directory::Clear() |
144 | 63.0k | { |
145 | 63.0k | this->Internal->Path.resize(0); |
146 | 63.0k | this->Internal->Files.clear(); |
147 | 63.0k | } |
148 | | |
149 | | } // namespace KWSYS_NAMESPACE |
150 | | |
151 | | // First Windows platforms |
152 | | |
153 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
154 | | |
155 | | namespace KWSYS_NAMESPACE { |
156 | | |
157 | | Status Directory::Load(std::string const& name, std::string* errorMessage) |
158 | | { |
159 | | this->Clear(); |
160 | | HANDLE srchHandle; |
161 | | char* buf; |
162 | | size_t bufLength; |
163 | | size_t n = name.size(); |
164 | | if (name.back() == '/' || name.back() == '\\') { |
165 | | bufLength = n + 1 + 1; |
166 | | buf = new char[bufLength]; |
167 | | snprintf(buf, bufLength, "%s*", name.c_str()); |
168 | | } else { |
169 | | // Make sure the slashes in the wildcard suffix are consistent with the |
170 | | // rest of the path |
171 | | bufLength = n + 2 + 1; |
172 | | buf = new char[bufLength]; |
173 | | if (name.find('\\') != std::string::npos) { |
174 | | snprintf(buf, bufLength, "%s\\*", name.c_str()); |
175 | | } else { |
176 | | snprintf(buf, bufLength, "%s/*", name.c_str()); |
177 | | } |
178 | | } |
179 | | WIN32_FIND_DATAW data; // data of current file |
180 | | |
181 | | // Now put them into the file array |
182 | | srchHandle = |
183 | | FindFirstFileW(Encoding::ToWindowsExtendedPath(buf).c_str(), &data); |
184 | | delete[] buf; |
185 | | |
186 | | if (srchHandle == INVALID_HANDLE_VALUE) { |
187 | | Status status = Status::Windows_GetLastError(); |
188 | | if (errorMessage) { |
189 | | *errorMessage = status.GetString(); |
190 | | } |
191 | | return status; |
192 | | } |
193 | | |
194 | | // Loop through names |
195 | | do { |
196 | | this->Internal->Files.emplace_back(Encoding::ToNarrow(data.cFileName), |
197 | | data); |
198 | | } while (FindNextFileW(srchHandle, &data)); |
199 | | this->Internal->Path = name; |
200 | | if (!FindClose(srchHandle)) { |
201 | | Status status = Status::Windows_GetLastError(); |
202 | | if (errorMessage) { |
203 | | *errorMessage = status.GetString(); |
204 | | } |
205 | | return status; |
206 | | } |
207 | | return Status::Success(); |
208 | | } |
209 | | |
210 | | unsigned long Directory::GetNumberOfFilesInDirectory(std::string const& name, |
211 | | std::string* errorMessage) |
212 | | { |
213 | | HANDLE srchHandle; |
214 | | char* buf; |
215 | | size_t bufLength; |
216 | | size_t n = name.size(); |
217 | | if (name.back() == '/') { |
218 | | bufLength = n + 1 + 1; |
219 | | buf = new char[n + 1 + 1]; |
220 | | snprintf(buf, bufLength, "%s*", name.c_str()); |
221 | | } else { |
222 | | bufLength = n + 2 + 1; |
223 | | buf = new char[n + 2 + 1]; |
224 | | snprintf(buf, bufLength, "%s/*", name.c_str()); |
225 | | } |
226 | | WIN32_FIND_DATAW data; // data of current file |
227 | | |
228 | | // Now put them into the file array |
229 | | srchHandle = FindFirstFileW(Encoding::ToWide(buf).c_str(), &data); |
230 | | delete[] buf; |
231 | | |
232 | | if (srchHandle == INVALID_HANDLE_VALUE) { |
233 | | if (errorMessage) { |
234 | | if (unsigned int errorId = GetLastError()) { |
235 | | LPSTR message = nullptr; |
236 | | DWORD size = FormatMessageA( |
237 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
238 | | FORMAT_MESSAGE_IGNORE_INSERTS, |
239 | | nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
240 | | (LPSTR)&message, 0, nullptr); |
241 | | *errorMessage = std::string(message, size); |
242 | | LocalFree(message); |
243 | | } else { |
244 | | *errorMessage = "Unknown error."; |
245 | | } |
246 | | } |
247 | | return 0; |
248 | | } |
249 | | |
250 | | // Loop through names |
251 | | unsigned long count = 0; |
252 | | do { |
253 | | count++; |
254 | | } while (FindNextFileW(srchHandle, &data)); |
255 | | FindClose(srchHandle); |
256 | | return count; |
257 | | } |
258 | | |
259 | | } // namespace KWSYS_NAMESPACE |
260 | | |
261 | | #else |
262 | | |
263 | | // Now the POSIX style directory access |
264 | | |
265 | | # include <sys/types.h> |
266 | | |
267 | | # include <dirent.h> |
268 | | # include <errno.h> |
269 | | # include <string.h> |
270 | | |
271 | | // PGI with glibc has trouble with dirent and large file support: |
272 | | // https://www.pgroup.com/userforum/viewtopic.php? |
273 | | // p=1992&sid=f16167f51964f1a68fe5041b8eb213b6 |
274 | | // Work around the problem by mapping dirent the same way as readdir. |
275 | | # if defined(__PGI) && defined(__GLIBC__) |
276 | | # define kwsys_dirent_readdir dirent |
277 | | # define kwsys_dirent_readdir64 dirent64 |
278 | | # define kwsys_dirent kwsys_dirent_lookup(readdir) |
279 | | # define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x) |
280 | | # define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x |
281 | | # else |
282 | 54.9k | # define kwsys_dirent dirent |
283 | | # endif |
284 | | |
285 | | namespace KWSYS_NAMESPACE { |
286 | | |
287 | | Status Directory::Load(std::string const& name, std::string* errorMessage) |
288 | 63.0k | { |
289 | 63.0k | this->Clear(); |
290 | | |
291 | 63.0k | errno = 0; |
292 | 63.0k | DIR* dir = opendir(name.c_str()); |
293 | | |
294 | 63.0k | if (!dir) { |
295 | 8.04k | if (errorMessage) { |
296 | 0 | *errorMessage = std::string(strerror(errno)); |
297 | 0 | } |
298 | 8.04k | return Status::POSIX_errno(); |
299 | 8.04k | } |
300 | | |
301 | 63.0k | errno = 0; |
302 | 3.85M | for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { |
303 | 3.79M | this->Internal->Files.emplace_back(d->d_name); |
304 | 3.79M | } |
305 | 54.9k | if (errno != 0) { |
306 | 0 | if (errorMessage) { |
307 | 0 | *errorMessage = std::string(strerror(errno)); |
308 | 0 | } |
309 | 0 | return Status::POSIX_errno(); |
310 | 0 | } |
311 | | |
312 | 54.9k | this->Internal->Path = name; |
313 | 54.9k | closedir(dir); |
314 | 54.9k | return Status::Success(); |
315 | 54.9k | } |
316 | | |
317 | | unsigned long Directory::GetNumberOfFilesInDirectory(std::string const& name, |
318 | | std::string* errorMessage) |
319 | 0 | { |
320 | 0 | errno = 0; |
321 | 0 | DIR* dir = opendir(name.c_str()); |
322 | |
|
323 | 0 | if (!dir) { |
324 | 0 | if (errorMessage) { |
325 | 0 | *errorMessage = std::string(strerror(errno)); |
326 | 0 | } |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | 0 | unsigned long count = 0; |
331 | 0 | for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { |
332 | 0 | count++; |
333 | 0 | } |
334 | 0 | if (errno != 0) { |
335 | 0 | if (errorMessage) { |
336 | 0 | *errorMessage = std::string(strerror(errno)); |
337 | 0 | } |
338 | 0 | return false; |
339 | 0 | } |
340 | | |
341 | 0 | closedir(dir); |
342 | 0 | return count; |
343 | 0 | } |
344 | | |
345 | | } // namespace KWSYS_NAMESPACE |
346 | | |
347 | | #endif |