/
dir.cc
114 lines (99 loc) · 2.96 KB
/
dir.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "getmode.h"
#include "uv.h"
#undef ERROR
#include "CollectorList.h"
#include "Rcpp.h"
#include "error.h"
#include "utils.h"
using namespace Rcpp;
// [[Rcpp::export]]
void mkdir_(CharacterVector path, mode_t mode) {
R_xlen_t n = Rf_xlength(path);
for (R_xlen_t i = 0; i < n; ++i) {
uv_fs_t req;
const char* p = CHAR(STRING_ELT(path, i));
int fd = uv_fs_mkdir(uv_default_loop(), &req, p, mode, NULL);
// We want to fail silently if the directory already exists or if we don't
// have permissions to create the directory and it is not the last
// directory we are trying to create. (In this case we assume the directory
// already exists).
uv_dirent_type_t t = get_dirent_type(p);
if ((fd == UV_EEXIST && (t == UV_DIRENT_DIR || t == UV_DIRENT_LINK)) ||
(fd == UV_EPERM && i < n - 1)) {
uv_fs_req_cleanup(&req);
continue;
}
stop_for_error(req, "Failed to make directory '%s'", p);
}
}
// [[Rcpp::export]]
void rmdir_(CharacterVector path) {
for (R_xlen_t i = 0; i < Rf_xlength(path); ++i) {
uv_fs_t req;
const char* p = CHAR(STRING_ELT(path, i));
uv_fs_rmdir(uv_default_loop(), &req, p, NULL);
stop_for_error(req, "Failed to remove '%s'", p);
uv_fs_req_cleanup(&req);
}
}
void dir_map(
Function fun,
const char* path,
bool all,
int file_type,
bool recurse,
CollectorList* value) {
uv_fs_t req;
uv_fs_scandir(uv_default_loop(), &req, path, 0, NULL);
if (stop_for_error(req, "Failed to search directory '%s'", path) == false) {
uv_fs_req_cleanup(&req);
return;
}
uv_dirent_t e;
for (int next_res = uv_fs_scandir_next(&req, &e); next_res != UV_EOF;
next_res = uv_fs_scandir_next(&req, &e)) {
if (!all && e.name[0] == '.') {
continue;
}
std::string name;
// If path is '.', just return the name
if (strcmp(path, ".") == 0) {
name = e.name;
}
// If path already ends with '/' just concatenate them.
else if (path[strlen(path) - 1] == '/') {
name = std::string(path) + e.name;
} else {
name = std::string(path) + '/' + e.name;
}
uv_dirent_type_t entry_type = get_dirent_type(name.c_str(), e.type);
if (file_type == -1 || (((1 << (entry_type)) & file_type) > 0)) {
value->push_back(fun(asCharacterVector(name)));
}
if (recurse && entry_type == UV_DIRENT_DIR) {
dir_map(fun, name.c_str(), all, file_type, true, value);
}
if (next_res != UV_EOF) {
if (stop_for_error(req, "Failed to search directory '%s'", path) ==
false) {
break;
}
}
}
uv_fs_req_cleanup(&req);
}
// [[Rcpp::export]]
List dir_map_(
CharacterVector path,
Function fun,
bool all,
IntegerVector type,
bool recurse) {
int file_type = INTEGER(type)[0];
CollectorList out;
for (R_xlen_t i = 0; i < Rf_xlength(path); ++i) {
const char* p = CHAR(STRING_ELT(path, i));
dir_map(fun, p, all, file_type, recurse, &out);
}
return out.vector();
}