static void
create_initial_config_file(const char* path)
{
- if (create_parent_dirs(path) != 0) {
+ if (!util::create_dir(util::dir_name(path))) {
return;
}
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);
// 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
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;
}
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;
}
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)
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));
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)
{
// 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);
#include "framework.hpp"
+#include "../src/util.hpp"
#include "util.hpp"
#include <float.h>
printf("=== SUITE: %s ===\n", name);
}
dir_before_suite = gnu_getcwd();
- create_dir(name);
+ util::create_dir(name);
cct_chdir(name);
current_suite = name;
}
printf("--- TEST: %s ---\n", name);
}
dir_before_test = gnu_getcwd();
- create_dir(name);
+ util::create_dir(name);
cct_chdir(name);
current_test = 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("") == ".");