7 #ifndef TREELITE_COMMON_FILESYSTEM_H_ 8 #define TREELITE_COMMON_FILESYSTEM_H_ 15 #include <dmlc/logging.h> 16 #include <treelite/common.h> 22 #pragma comment(lib, "Shlwapi.lib") 28 #include <sys/types.h> 35 namespace filesystem {
45 inline std::string GetBasename(
const std::string& path) {
50 std::string::size_type tmp = path.find_last_of(
"/\\");
51 if (tmp == path.length() - 1) {
53 while ((path[i] ==
'/' || path[i] ==
'\\') && i >= 0) {
56 path_ = path.substr(0, i + 1);
60 std::vector<char> fname(path_.length() + 1);
61 std::vector<char> ext(path_.length() + 1);
62 _splitpath_s(path_.c_str(), NULL, 0, NULL, 0,
63 &fname[0], path_.length() + 1, &ext[0], path_.length() + 1);
64 return std::string(&fname[0]) + std::string(&ext[0]);
66 char* path_ = strdup(path.c_str());
67 char* base = basename(path_);
68 std::string ret(base);
74 inline void HandleSystemError(
const std::string& msg) {
77 DWORD dw = GetLastError();
79 FORMAT_MESSAGE_ALLOCATE_BUFFER |
80 FORMAT_MESSAGE_FROM_SYSTEM |
81 FORMAT_MESSAGE_IGNORE_INSERTS,
84 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
87 const std::string msg_err(static_cast<const char*>(msg_buf));
90 const std::string msg_err(strerror(errno));
92 LOG(FATAL) << msg <<
"\nReason: " << msg_err;
95 inline void CreateDirectoryIfNotExist(
const char* dirpath) {
97 DWORD ftyp = GetFileAttributesA(dirpath);
98 if (ftyp == INVALID_FILE_ATTRIBUTES) {
100 if (CreateDirectoryA(dirpath, NULL) == 0) {
102 HandleSystemError(std::string(
"CreateDirectoryIfNotExist: " 103 "failed to create new directory ") + dirpath);
106 if (!(ftyp & FILE_ATTRIBUTE_DIRECTORY)) {
107 LOG(FATAL) <<
"CreateDirectoryIfNotExist: " 108 << dirpath <<
" is a file, not a directory";
113 if (stat(dirpath, &sb) != 0) {
115 if (mkdir(dirpath, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
117 HandleSystemError(std::string(
"CreateDirectoryIfNotExist: " 118 "failed to create new directory ") + dirpath);
121 if (!S_ISDIR(sb.st_mode)) {
122 LOG(FATAL) <<
"CreateDirectoryIfNotExist: " 123 << dirpath <<
" is a file, not a directory";
129 inline void CreateDirectoryIfNotExistRecursive(
const std::string& dirpath) {
130 std::string dirpath_;
132 if (dirpath.find(
"/") == std::string::npos
133 && dirpath.find(
"\\") != std::string::npos) {
135 dirpath_ = std::regex_replace(dirpath, std::regex(
"\\\\"),
"/");
142 const std::vector<std::string> tokens = common::Split(dirpath_,
'/');
145 if (tokens[0].empty()) {
146 accum =
"/" + tokens[1];
152 for (; i < tokens.size(); ++i) {
153 common::filesystem::CreateDirectoryIfNotExist(accum.c_str());
154 if (i < tokens.size() - 1 && !tokens[i + 1].empty()) {
156 accum += tokens[i + 1];
161 class TemporaryDirectory {
163 TemporaryDirectory() {
166 char tmproot[MAX_PATH] = {0};
167 const DWORD dw_retval = GetTempPathA(MAX_PATH, tmproot);
168 if (dw_retval > MAX_PATH || dw_retval == 0) {
169 LOG(FATAL) <<
"TemporaryDirectory(): " 170 <<
"Could not create temporary directory";
173 const std::string letters =
"abcdefghijklmnopqrstuvwxyz0123456789_";
174 std::string uniqstr(8,
'\0');
175 std::random_device rd;
176 std::mt19937 gen(rd());
177 std::uniform_int_distribution<int> dis(0, letters.length() - 1);
178 std::generate(uniqstr.begin(), uniqstr.end(),
179 [&dis, &gen, &letters]() ->
char {
180 return letters[dis(gen)];
183 char tmpdir[MAX_PATH] = {0};
184 PathCombineA(tmpdir, tmproot, uniqstr.c_str());
185 if (!CreateDirectoryA(tmpdir, NULL)) {
186 LOG(FATAL) <<
"TemporaryDirectory(): " 187 <<
"Could not create temporary directory";
189 path = std::string(tmpdir);
192 std::string dirtemplate;
195 const char* tmpenv = getenv(
"TMPDIR");
197 tmproot = std::string(tmpenv);
199 while (tmproot.length() != 0 && tmproot[tmproot.length() - 1] ==
'/') {
200 tmproot.resize(tmproot.length() - 1);
206 dirtemplate = tmproot +
"/tmpdir.XXXXXX";
207 std::vector<char> dirtemplate_buf(dirtemplate.begin(), dirtemplate.end());
208 dirtemplate_buf.push_back(
'\0');
209 char* tmpdir = mkdtemp(&dirtemplate_buf[0]);
211 LOG(FATAL) <<
"TemporaryDirectory(): " 212 <<
"Could not create temporary directory";
214 path = std::string(tmpdir);
216 LOG(INFO) <<
"Created temporary directory " << path;
218 ~TemporaryDirectory() {
219 for (
const std::string& filename : file_list) {
220 if (std::remove(filename.c_str()) != 0) {
221 LOG(FATAL) <<
"Couldn't remove file " << filename;
225 const bool rmdir_success = (RemoveDirectoryA(path.c_str()) != 0);
227 const bool rmdir_success = (rmdir(path.c_str()) == 0);
230 LOG(INFO) <<
"Successfully deleted temporary directory " << path;
232 LOG(FATAL) <<
"~TemporaryDirectory(): " 233 <<
"Could not remove temporary directory ";
237 std::string AddFile(
const std::string& filename) {
238 const std::string file_path = this->path +
"/" + filename;
239 file_list.push_back(file_path);
246 std::vector<std::string> file_list;
253 #endif // TREELITE_COMMON_FILESYSTEM_H_