From: Joel Rosdahl Date: Sun, 25 Aug 2019 08:49:00 +0000 (+0200) Subject: Add util::create_dir, replacing create_parent_dirs and create_dir X-Git-Tag: v4.0~812 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=770d0cf6e65b9302bc595c528440321aa34d6306;p=thirdparty%2Fccache.git Add util::create_dir, replacing create_parent_dirs and create_dir --- diff --git a/src/ccache.cpp b/src/ccache.cpp index 96163a0a1..9142d355a 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -3432,7 +3432,7 @@ out: static void create_initial_config_file(const char* path) { - if (create_parent_dirs(path) != 0) { + if (!util::create_dir(util::dir_name(path))) { return; } diff --git a/src/ccache.hpp b/src/ccache.hpp index b34374e9a..9e2d0f6ce 100644 --- a/src/ccache.hpp +++ b/src/ccache.hpp @@ -163,8 +163,6 @@ bool copy_fd(int fd_in, int fd_out); bool clone_file(const char* src, const char* dest, bool via_tmp_file); bool copy_file(const char* src, const char* dest, bool via_tmp_file); bool move_file(const char* src, const char* dest); -int create_dir(const char* dir); -int create_parent_dirs(const char* path); const char* get_hostname(void); const char* tmp_string(void); char* format(const char* format, ...) ATTR_FORMAT(printf, 1, 2); diff --git a/src/lockfile.cpp b/src/lockfile.cpp index c717d0915..bc9d17453 100644 --- a/src/lockfile.cpp +++ b/src/lockfile.cpp @@ -17,6 +17,7 @@ // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "ccache.hpp" +#include "util.hpp" // This function acquires a lockfile for the given path. Returns true if the // lock was acquired, otherwise false. If the lock has been considered stale @@ -49,7 +50,7 @@ lockfile_acquire(const char* path, unsigned staleness_limit) cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno)); if (saved_errno == ENOENT) { // Directory doesn't exist? - if (create_parent_dirs(lockfile) == 0) { + if (util::create_dir(util::dir_name(lockfile))) { // OK. Retry. continue; } @@ -104,7 +105,7 @@ lockfile_acquire(const char* path, unsigned staleness_limit) cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(saved_errno)); if (saved_errno == ENOENT) { // Directory doesn't exist? - if (create_parent_dirs(lockfile) == 0) { + if (util::create_dir(util::dir_name(lockfile))) { // OK. Retry. continue; } diff --git a/src/util.cpp b/src/util.cpp index cb3815eb2..a826dc094 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -508,61 +508,6 @@ move_file(const char* src, const char* dest) return ok; } -// Make sure a directory exists. -int -create_dir(const char* dir) -{ - struct stat st; - if (stat(dir, &st) == 0) { - if (S_ISDIR(st.st_mode)) { - return 0; - } - errno = ENOTDIR; - return 1; - } - if (mkdir(dir, 0777) != 0 && errno != EEXIST) { - return 1; - } - return 0; -} - -// Create directories leading to path. Returns 0 on success, otherwise -1. -int -create_parent_dirs(const char* path) -{ - int res; - char* parent = x_dirname(path); - struct stat st; - if (stat(parent, &st) == 0) { - if (S_ISDIR(st.st_mode)) { - res = 0; - } else { - res = -1; - errno = ENOTDIR; - } - } else { - res = create_parent_dirs(parent); - if (res == 0) { - res = mkdir(parent, 0777); - // Have to handle the condition of the directory already existing because - // the file system could have changed in between calling stat and - // actually creating the directory. This can happen when there are - // multiple instances of ccache running and trying to create the same - // directory chain, which usually is the case when the cache root does - // not initially exist. As long as one of the processes creates the - // directories then our condition is satisfied and we avoid a race - // condition. - if (res != 0 && errno == EEXIST) { - res = 0; - } - } else { - res = -1; - } - } - free(parent); - return res; -} - // Return a static string with the current hostname. const char* get_hostname(void) @@ -1226,7 +1171,7 @@ create_tmp_fd(char** fname) char* tmpl = format("%s.%s", *fname, tmp_string()); int fd = mkstemp(tmpl); if (fd == -1 && errno == ENOENT) { - if (create_parent_dirs(*fname) != 0) { + if (!util::create_dir(util::dir_name(*fname))) { fatal("Failed to create directory %s: %s", x_dirname(*fname), strerror(errno)); @@ -1776,6 +1721,33 @@ base_name(const std::string& path) return n == std::string::npos ? path : path.substr(n + 1); } +bool +create_dir(const std::string& dir) +{ + struct stat st; + if (stat(dir.c_str(), &st) == 0) { + if (S_ISDIR(st.st_mode)) { + return true; + } else { + errno = ENOTDIR; + return false; + } + } else { + if (!create_dir(util::dir_name(dir))) { + return false; + } + int result = mkdir(dir.c_str(), 0777); + // Treat an already existing directory as OK since the file system could + // have changed in between calling stat and actually creating the + // directory. This can happen when there are multiple instances of ccache + // running and trying to create the same directory chain, which usually is + // the case when the cache root does not initially exist. As long as one of + // the processes creates the directories then our condition is satisfied + // and we avoid a race condition. + return result == 0 || errno == EEXIST; + } +} + std::string dir_name(const std::string& path) { diff --git a/src/util.hpp b/src/util.hpp index c3d58417a..7be3b5b13 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -27,6 +27,11 @@ namespace util { // Get base name of path. std::string base_name(const std::string& path); +// Create a directory if needed, including its parents if needed. +// +// Returns true if the directory exists or could be created, otherwise false. +bool create_dir(const std::string& dir); + // Get directory name of path. std::string dir_name(const std::string& path); diff --git a/unittest/framework.cpp b/unittest/framework.cpp index 5a219c707..648079e2d 100644 --- a/unittest/framework.cpp +++ b/unittest/framework.cpp @@ -18,6 +18,7 @@ #include "framework.hpp" +#include "../src/util.hpp" #include "util.hpp" #include @@ -109,7 +110,7 @@ cct_suite_begin(const char* name) printf("=== SUITE: %s ===\n", name); } dir_before_suite = gnu_getcwd(); - create_dir(name); + util::create_dir(name); cct_chdir(name); current_suite = name; } @@ -130,7 +131,7 @@ cct_test_begin(const char* name) printf("--- TEST: %s ---\n", name); } dir_before_test = gnu_getcwd(); - create_dir(name); + util::create_dir(name); cct_chdir(name); current_test = name; diff --git a/unittest/test_util.cpp b/unittest/test_util.cpp index 0ba3ffc51..952083446 100644 --- a/unittest/test_util.cpp +++ b/unittest/test_util.cpp @@ -30,6 +30,19 @@ TEST_CASE("util::base_name") CHECK(util::base_name("/foo/bar/f.txt") == "f.txt"); } +TEST_CASE("util::create_dir") +{ + CHECK(util::create_dir("/")); + + CHECK(util::create_dir("create/dir")); + struct stat st; + CHECK(stat("create/dir", &st) == 0); + CHECK(S_ISDIR(st.st_mode)); + + util::write_file("create/dir/file", ""); + CHECK(!util::create_dir("create/dir/file")); +} + TEST_CASE("util::dir_name") { CHECK(util::dir_name("") == ".");