util: add new function create_directories with unit tests (#21871)

* util::create_directories

* check bool ret

* don't assume mask

* rename with_umask to no_umask

* remove umask

* rebase master

* rebase master

* 0755
old-commit-hash: 1f39d8cee69cf28576cd9bd27ef52be57d44371e
This commit is contained in:
Dean Lee
2021-10-29 18:27:35 +08:00
committed by GitHub
parent af7c9ccf6f
commit 0afe7d74bc
7 changed files with 73 additions and 43 deletions

View File

@@ -1,14 +1,15 @@
#include "selfdrive/common/util.h"
#include <sys/stat.h>
#include <dirent.h>
#include <cassert>
#include <cerrno>
#include <cstring>
#include <dirent.h>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <sstream>
#ifdef __linux__
#include <sys/prctl.h>
@@ -121,6 +122,37 @@ bool file_exists(const std::string& fn) {
return stat(fn.c_str(), &st) != -1;
}
static bool createDirectory(std::string dir, mode_t mode) {
auto verify_dir = [](const std::string& dir) -> bool {
struct stat st = {};
return (stat(dir.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR);
};
// remove trailing /'s
while (dir.size() > 1 && dir.back() == '/') {
dir.pop_back();
}
// try to mkdir this directory
if (mkdir(dir.c_str(), mode) == 0) return true;
if (errno == EEXIST) return verify_dir(dir);
if (errno != ENOENT) return false;
// mkdir failed because the parent dir doesn't exist, so try to create it
size_t slash = dir.rfind('/');
if ((slash == std::string::npos || slash < 1) ||
!createDirectory(dir.substr(0, slash), mode)) {
return false;
}
// try again
if (mkdir(dir.c_str(), mode) == 0) return true;
return errno == EEXIST && verify_dir(dir);
}
bool create_directories(const std::string& dir, mode_t mode) {
if (dir.empty()) return false;
return createDirectory(dir, mode);
}
std::string getenv(const char* key, const char* default_val) {
const char* val = ::getenv(key);
return val ? val : default_val;