comparison modules/fs/fs.cpp @ 547:ecf5fb9319da

Fs: switch to spaces, add FS_EXPORT
author David Demelier <markand@malikania.fr>
date Wed, 15 Jun 2016 11:59:17 +0200
parents d6dad57e9e6b
children 730358cb0648
comparison
equal deleted inserted replaced
546:40c27081958a 547:ecf5fb9319da
52 */ 52 */
53 #if defined(_WIN32) 53 #if defined(_WIN32)
54 54
55 std::string error() 55 std::string error()
56 { 56 {
57 LPSTR error = nullptr; 57 LPSTR error = nullptr;
58 std::string errmsg = "Unknown error"; 58 std::string errmsg = "Unknown error";
59 59
60 FormatMessageA( 60 FormatMessageA(
61 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 61 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
62 nullptr, 62 nullptr,
63 GetLastError(), 63 GetLastError(),
64 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 64 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
65 (LPSTR)&error, 0, nullptr); 65 (LPSTR)&error, 0, nullptr);
66 66
67 if (error) { 67 if (error) {
68 errmsg = std::string(error); 68 errmsg = std::string(error);
69 LocalFree(error); 69 LocalFree(error);
70 } 70 }
71 71
72 return errmsg; 72 return errmsg;
73 } 73 }
74 74
75 #endif 75 #endif
76 76
77 /* 77 /*
80 * 80 *
81 * Check if we have access to the file specified, mode is the same used as std::fopen. 81 * Check if we have access to the file specified, mode is the same used as std::fopen.
82 */ 82 */
83 bool hasAccess(const std::string &path, const std::string &mode) 83 bool hasAccess(const std::string &path, const std::string &mode)
84 { 84 {
85 assert(mode.length() == 1); 85 assert(mode.length() == 1);
86 assert(mode[0] == 'r' || mode[0] == 'w'); 86 assert(mode[0] == 'r' || mode[0] == 'w');
87 87
88 auto fp = std::fopen(path.c_str(), mode.c_str()); 88 auto fp = std::fopen(path.c_str(), mode.c_str());
89 89
90 if (fp == nullptr) 90 if (fp == nullptr)
91 return false; 91 return false;
92 92
93 std::fclose(fp); 93 std::fclose(fp);
94 94
95 return true; 95 return true;
96 } 96 }
97 97
98 /* 98 /*
99 * typeOf. 99 * typeOf.
100 * ------------------------------------------------------------------ 100 * ------------------------------------------------------------------
108 #if defined(_WIN32) 108 #if defined(_WIN32)
109 109
110 template <typename Predicate> 110 template <typename Predicate>
111 bool typeOf(const std::string &path, Predicate &&predicate) 111 bool typeOf(const std::string &path, Predicate &&predicate)
112 { 112 {
113 DWORD result = GetFileAttributesA(path.c_str()); 113 DWORD result = GetFileAttributesA(path.c_str());
114 114
115 if (result == INVALID_FILE_ATTRIBUTES) 115 if (result == INVALID_FILE_ATTRIBUTES)
116 return false; 116 return false;
117 117
118 return predicate(result); 118 return predicate(result);
119 } 119 }
120 120
121 #elif defined(FS_HAVE_STAT) 121 #elif defined(FS_HAVE_STAT)
122 122
123 template <typename Predicate> 123 template <typename Predicate>
124 bool typeOf(const std::string &path, Predicate &&predicate) noexcept 124 bool typeOf(const std::string &path, Predicate &&predicate) noexcept
125 { 125 {
126 struct stat st; 126 struct stat st;
127 127
128 if (::stat(path.c_str(), &st) < 0) 128 if (::stat(path.c_str(), &st) < 0)
129 return false; 129 return false;
130 130
131 return predicate(st); 131 return predicate(st);
132 } 132 }
133 133
134 #else 134 #else
135 135
136 template <typename Predicate> 136 template <typename Predicate>
137 bool typeOf(const std::string &path, Predicate &&predicate) noexcept 137 bool typeOf(const std::string &path, Predicate &&predicate) noexcept
138 { 138 {
139 throw std::runtime_error(std::strerror(ENOSYS)); 139 throw std::runtime_error(std::strerror(ENOSYS));
140 } 140 }
141 141
142 #endif 142 #endif
143 143
144 } // !namespace 144 } // !namespace
147 * clean. 147 * clean.
148 * ------------------------------------------------------------------ 148 * ------------------------------------------------------------------
149 */ 149 */
150 std::string clean(std::string input) 150 std::string clean(std::string input)
151 { 151 {
152 if (input.empty()) 152 if (input.empty())
153 return input; 153 return input;
154 154
155 /* First, remove any duplicates */ 155 // First, remove any duplicates.
156 input.erase(std::unique(input.begin(), input.end(), [&] (char c1, char c2) { 156 input.erase(std::unique(input.begin(), input.end(), [&] (char c1, char c2) {
157 return c1 == c2 && (c1 == '/' || c1 == '\\'); 157 return c1 == c2 && (c1 == '/' || c1 == '\\');
158 }), input.end()); 158 }), input.end());
159 159
160 /* Add a trailing / or \\ */ 160 // Add a trailing / or \\.
161 char c = input[input.length() - 1]; 161 char c = input[input.length() - 1];
162 162
163 if (c != '/' && c != '\\') 163 if (c != '/' && c != '\\')
164 input += separator(); 164 input += separator();
165 165
166 /* Now converts all / to \\ for Windows and the opposite for Unix */ 166 // Now converts all / to \\ for Windows and the opposite for Unix.
167 #if defined(_WIN32) 167 #if defined(_WIN32)
168 std::replace(input.begin(), input.end(), '/', '\\'); 168 std::replace(input.begin(), input.end(), '/', '\\');
169 #else 169 #else
170 std::replace(input.begin(), input.end(), '\\', '/'); 170 std::replace(input.begin(), input.end(), '\\', '/');
171 #endif 171 #endif
172 172
173 return input; 173 return input;
174 } 174 }
175 175
176 /* 176 /*
177 * baseName. 177 * baseName.
178 * ------------------------------------------------------------------ 178 * ------------------------------------------------------------------
179 */ 179 */
180 std::string baseName(std::string path) 180 std::string baseName(std::string path)
181 { 181 {
182 auto pos = path.find_last_of("\\/"); 182 auto pos = path.find_last_of("\\/");
183 183
184 if (pos != std::string::npos) 184 if (pos != std::string::npos)
185 path = path.substr(pos + 1); 185 path = path.substr(pos + 1);
186 186
187 return path; 187 return path;
188 } 188 }
189 189
190 /* 190 /*
191 * dirName. 191 * dirName.
192 * ------------------------------------------------------------------ 192 * ------------------------------------------------------------------
193 */ 193 */
194 std::string dirName(std::string path) 194 std::string dirName(std::string path)
195 { 195 {
196 auto pos = path.find_last_of("\\/"); 196 auto pos = path.find_last_of("\\/");
197 197
198 if (pos == std::string::npos) 198 if (pos == std::string::npos)
199 path = "."; 199 path = ".";
200 else 200 else
201 path = path.substr(0, pos); 201 path = path.substr(0, pos);
202 202
203 return path; 203 return path;
204 } 204 }
205 205
206 /* 206 /*
207 * isAbsolute. 207 * isAbsolute.
208 * ------------------------------------------------------------------ 208 * ------------------------------------------------------------------
209 */ 209 */
210 bool isAbsolute(const std::string &path) noexcept 210 bool isAbsolute(const std::string &path) noexcept
211 { 211 {
212 #if defined(_WIN32) 212 #if defined(_WIN32)
213 return !isRelative(path); 213 return !isRelative(path);
214 #else 214 #else
215 return path.size() > 0 && path[0] == '/'; 215 return path.size() > 0 && path[0] == '/';
216 #endif 216 #endif
217 } 217 }
218 218
219 /* 219 /*
220 * isRelative. 220 * isRelative.
221 * ------------------------------------------------------------------ 221 * ------------------------------------------------------------------
222 */ 222 */
223 bool isRelative(const std::string &path) noexcept 223 bool isRelative(const std::string &path) noexcept
224 { 224 {
225 #if defined(_WIN32) 225 #if defined(_WIN32)
226 return PathIsRelativeA(path.c_str()) == 1; 226 return PathIsRelativeA(path.c_str()) == 1;
227 #else 227 #else
228 return !isAbsolute(path); 228 return !isAbsolute(path);
229 #endif 229 #endif
230 } 230 }
231 231
232 /* 232 /*
233 * isReadable. 233 * isReadable.
234 * ------------------------------------------------------------------ 234 * ------------------------------------------------------------------
235 */ 235 */
236 bool isReadable(const std::string &path) noexcept 236 bool isReadable(const std::string &path) noexcept
237 { 237 {
238 return hasAccess(path, "r"); 238 return hasAccess(path, "r");
239 } 239 }
240 240
241 /* 241 /*
242 * isWritable. 242 * isWritable.
243 * ------------------------------------------------------------------ 243 * ------------------------------------------------------------------
244 */ 244 */
245 bool isWritable(const std::string &path) noexcept 245 bool isWritable(const std::string &path) noexcept
246 { 246 {
247 return hasAccess(path, "w"); 247 return hasAccess(path, "w");
248 } 248 }
249 249
250 /* 250 /*
251 * isFile. 251 * isFile.
252 * ------------------------------------------------------------------ 252 * ------------------------------------------------------------------
253 */ 253 */
254 bool isFile(const std::string &path) 254 bool isFile(const std::string &path)
255 { 255 {
256 return typeOf(path, [] (const auto &object) { 256 return typeOf(path, [] (const auto &object) {
257 #if defined(_WIN32) 257 #if defined(_WIN32)
258 return (object & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE; 258 return (object & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE;
259 #elif defined(FS_HAVE_STAT) 259 #elif defined(FS_HAVE_STAT)
260 return S_ISREG(object.st_mode); 260 return S_ISREG(object.st_mode);
261 #endif 261 #endif
262 }); 262 });
263 } 263 }
264 264
265 /* 265 /*
266 * isDirectory. 266 * isDirectory.
267 * ------------------------------------------------------------------ 267 * ------------------------------------------------------------------
268 */ 268 */
269 bool isDirectory(const std::string &path) 269 bool isDirectory(const std::string &path)
270 { 270 {
271 return typeOf(path, [] (const auto &object) { 271 return typeOf(path, [] (const auto &object) {
272 #if defined(_WIN32) 272 #if defined(_WIN32)
273 return (object & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; 273 return (object & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
274 #elif defined(FS_HAVE_STAT) 274 #elif defined(FS_HAVE_STAT)
275 return S_ISDIR(object.st_mode); 275 return S_ISDIR(object.st_mode);
276 #endif 276 #endif
277 }); 277 });
278 } 278 }
279 279
280 /* 280 /*
281 * isSymlink. 281 * isSymlink.
282 * ------------------------------------------------------------------ 282 * ------------------------------------------------------------------
283 */ 283 */
284 bool isSymlink(const std::string &path) 284 bool isSymlink(const std::string &path)
285 { 285 {
286 return typeOf(path, [] (const auto &object) { 286 return typeOf(path, [] (const auto &object) {
287 #if defined(_WIN32) 287 #if defined(_WIN32)
288 return (object & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT; 288 return (object & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT;
289 #elif defined(FS_HAVE_STAT) 289 #elif defined(FS_HAVE_STAT)
290 return S_ISLNK(object.st_mode); 290 return S_ISLNK(object.st_mode);
291 #endif 291 #endif
292 }); 292 });
293 } 293 }
294 294
295 /* 295 /*
296 * stat. 296 * stat.
297 * ------------------------------------------------------------------ 297 * ------------------------------------------------------------------
298 */ 298 */
299 #if defined(FS_HAVE_STAT) 299 #if defined(FS_HAVE_STAT)
300 300
301 struct stat stat(const std::string &path) 301 struct stat stat(const std::string &path)
302 { 302 {
303 struct stat st; 303 struct stat st;
304 304
305 if (::stat(path.c_str(), &st) < 0) 305 if (::stat(path.c_str(), &st) < 0)
306 throw std::runtime_error(std::strerror(errno)); 306 throw std::runtime_error(std::strerror(errno));
307 307
308 return st; 308 return st;
309 } 309 }
310 310
311 #endif 311 #endif
312 312
313 /* 313 /*
315 * ------------------------------------------------------------------ 315 * ------------------------------------------------------------------
316 */ 316 */
317 bool exists(const std::string &path) noexcept 317 bool exists(const std::string &path) noexcept
318 { 318 {
319 #if defined(FS_HAVE_STAT) 319 #if defined(FS_HAVE_STAT)
320 struct stat st; 320 struct stat st;
321 321
322 return ::stat(path.c_str(), &st) == 0; 322 return ::stat(path.c_str(), &st) == 0;
323 #else 323 #else
324 return hasAccess(path, "r"); 324 return hasAccess(path, "r");
325 #endif 325 #endif
326 } 326 }
327 327
328 /* 328 /*
329 * readdir. 329 * readdir.
330 * ------------------------------------------------------------------ 330 * ------------------------------------------------------------------
331 */ 331 */
332 std::vector<Entry> readdir(const std::string &path, int flags) 332 std::vector<Entry> readdir(const std::string &path, int flags)
333 { 333 {
334 std::vector<Entry> entries; 334 std::vector<Entry> entries;
335 335
336 #if defined(_WIN32) 336 #if defined(_WIN32)
337 std::ostringstream oss; 337 std::ostringstream oss;
338 HANDLE handle; 338 HANDLE handle;
339 WIN32_FIND_DATA fdata; 339 WIN32_FIND_DATA fdata;
340 340
341 oss << path << "\\*"; 341 oss << path << "\\*";
342 handle = FindFirstFile(oss.str().c_str(), &fdata); 342 handle = FindFirstFile(oss.str().c_str(), &fdata);
343 343
344 if (handle == nullptr) 344 if (handle == nullptr)
345 throw std::runtime_error(error()); 345 throw std::runtime_error(error());
346 346
347 do { 347 do {
348 Entry entry; 348 Entry entry;
349 349
350 entry.name = fdata.cFileName; 350 entry.name = fdata.cFileName;
351 351
352 if (entry.name == "." && !(flags & Dot)) 352 if (entry.name == "." && !(flags & Dot))
353 continue; 353 continue;
354 if (entry.name == ".." && !(flags & DotDot)) 354 if (entry.name == ".." && !(flags & DotDot))
355 continue; 355 continue;
356 356
357 switch (fdata.dwFileAttributes) { 357 switch (fdata.dwFileAttributes) {
358 case FILE_ATTRIBUTE_DIRECTORY: 358 case FILE_ATTRIBUTE_DIRECTORY:
359 entry.type = Entry::Dir; 359 entry.type = Entry::Dir;
360 break; 360 break;
361 case FILE_ATTRIBUTE_NORMAL: 361 case FILE_ATTRIBUTE_NORMAL:
362 entry.type = Entry::File; 362 entry.type = Entry::File;
363 break; 363 break;
364 case FILE_ATTRIBUTE_REPARSE_POINT: 364 case FILE_ATTRIBUTE_REPARSE_POINT:
365 entry.type = Entry::Link; 365 entry.type = Entry::Link;
366 break; 366 break;
367 default: 367 default:
368 break; 368 break;
369 } 369 }
370 370
371 entries.push_back(std::move(entry)); 371 entries.push_back(std::move(entry));
372 } while (FindNextFile(handle, &fdata) != 0); 372 } while (FindNextFile(handle, &fdata) != 0);
373 373
374 FindClose(handle); 374 FindClose(handle);
375 #else 375 #else
376 DIR *dp; 376 DIR *dp;
377 struct dirent *ent; 377 struct dirent *ent;
378 378
379 if ((dp = opendir(path.c_str())) == nullptr) 379 if ((dp = opendir(path.c_str())) == nullptr)
380 throw std::runtime_error(std::strerror(errno)); 380 throw std::runtime_error(std::strerror(errno));
381 381
382 while ((ent = readdir(dp)) != nullptr) { 382 while ((ent = readdir(dp)) != nullptr) {
383 Entry entry; 383 Entry entry;
384 384
385 entry.name = ent->d_name; 385 entry.name = ent->d_name;
386 if (entry.name == "." && !(flags & Dot)) 386 if (entry.name == "." && !(flags & Dot))
387 continue; 387 continue;
388 if (entry.name == ".." && !(flags & DotDot)) 388 if (entry.name == ".." && !(flags & DotDot))
389 continue; 389 continue;
390 390
391 switch (ent->d_type) { 391 switch (ent->d_type) {
392 case DT_DIR: 392 case DT_DIR:
393 entry.type = Entry::Dir; 393 entry.type = Entry::Dir;
394 break; 394 break;
395 case DT_REG: 395 case DT_REG:
396 entry.type = Entry::File; 396 entry.type = Entry::File;
397 break; 397 break;
398 case DT_LNK: 398 case DT_LNK:
399 entry.type = Entry::Link; 399 entry.type = Entry::Link;
400 break; 400 break;
401 default: 401 default:
402 break; 402 break;
403 } 403 }
404 404
405 entries.push_back(std::move(entry)); 405 entries.push_back(std::move(entry));
406 } 406 }
407 407
408 closedir(dp); 408 closedir(dp);
409 #endif 409 #endif
410 410
411 return entries; 411 return entries;
412 } 412 }
413 413
414 /* 414 /*
415 * mkdir. 415 * mkdir.
416 * ------------------------------------------------------------------ 416 * ------------------------------------------------------------------
417 */ 417 */
418 void mkdir(const std::string &path, int mode) 418 void mkdir(const std::string &path, int mode)
419 { 419 {
420 std::string::size_type next = 0; 420 std::string::size_type next = 0;
421 std::string part; 421 std::string part;
422 422
423 for (;;) { 423 for (;;) {
424 next = path.find_first_of("\\/", next); 424 next = path.find_first_of("\\/", next);
425 part = path.substr(0, next); 425 part = path.substr(0, next);
426 426
427 if (!part.empty()) { 427 if (!part.empty()) {
428 #if defined(_WIN32) 428 #if defined(_WIN32)
429 (void)mode; 429 (void)mode;
430 430
431 if (::_mkdir(part.c_str()) < 0 && errno != EEXIST) 431 if (::_mkdir(part.c_str()) < 0 && errno != EEXIST)
432 throw std::runtime_error(std::strerror(errno)); 432 throw std::runtime_error(std::strerror(errno));
433 #else 433 #else
434 if (::mkdir(part.c_str(), mode) < 0 && errno != EEXIST) 434 if (::mkdir(part.c_str(), mode) < 0 && errno != EEXIST)
435 throw std::runtime_error(std::strerror(errno)); 435 throw std::runtime_error(std::strerror(errno));
436 #endif 436 #endif
437 } 437 }
438 438
439 if (next++ == std::string::npos) 439 if (next++ == std::string::npos)
440 break; 440 break;
441 } 441 }
442 } 442 }
443 443
444 /* 444 /*
445 * rmdir. 445 * rmdir.
446 * ------------------------------------------------------------------ 446 * ------------------------------------------------------------------
447 */ 447 */
448 void rmdir(const std::string &base) noexcept 448 void rmdir(const std::string &base) noexcept
449 { 449 {
450 try { 450 try {
451 for (const auto &entry : readdir(base)) { 451 for (const auto &entry : readdir(base)) {
452 std::string path = base + separator() + entry.name; 452 std::string path = base + separator() + entry.name;
453 453
454 if (entry.type == Entry::Dir) 454 if (entry.type == Entry::Dir)
455 rmdir(path); 455 rmdir(path);
456 else 456 else
457 remove(path.c_str()); 457 ::remove(path.c_str());
458 } 458 }
459 } catch (...) { 459 } catch (...) {
460 /* Silently discard to remove as much as possible */ 460 // Silently discard to remove as much as possible.
461 } 461 }
462 462
463 #if defined(_WIN32) 463 #if defined(_WIN32)
464 RemoveDirectoryA(base.c_str()); 464 ::RemoveDirectoryA(base.c_str());
465 #else 465 #else
466 remove(base.c_str()); 466 ::remove(base.c_str());
467 #endif 467 #endif
468 } 468 }
469 469
470 /* 470 /*
471 * cwd. 471 * cwd.
472 * ------------------------------------------------------------------ 472 * ------------------------------------------------------------------
473 */ 473 */
474 std::string cwd() 474 std::string cwd()
475 { 475 {
476 #if defined(_WIN32) 476 #if defined(_WIN32)
477 char path[MAX_PATH]; 477 char path[MAX_PATH];
478 478
479 if (!GetCurrentDirectoryA(sizeof (path), path)) 479 if (!::GetCurrentDirectoryA(sizeof (path), path))
480 throw std::runtime_error("failed to get current working directory"); 480 throw std::runtime_error("failed to get current working directory");
481 481
482 return path; 482 return path;
483 #else 483 #else
484 char path[PATH_MAX]; 484 char path[PATH_MAX];
485 485
486 if (getcwd(path, sizeof (path)) == nullptr) 486 if (::getcwd(path, sizeof (path)) == nullptr)
487 throw std::runtime_error{std::strerror(errno)}; 487 throw std::runtime_error{std::strerror(errno)};
488 488
489 return path; 489 return path;
490 #endif 490 #endif
491 } 491 }
492 492
493 } // !fs 493 } // !fs