summaryrefslogtreecommitdiff
path: root/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'path.c')
-rw-r--r--path.c293
1 files changed, 245 insertions, 48 deletions
diff --git a/path.c b/path.c
index 07964f5d32..7f56eaf993 100644
--- a/path.c
+++ b/path.c
@@ -2,8 +2,6 @@
* Utilities for paths and pathnames
*/
-#define USE_THE_REPOSITORY_VARIABLE
-
#include "git-compat-util.h"
#include "abspath.h"
#include "environment.h"
@@ -17,7 +15,7 @@
#include "submodule-config.h"
#include "path.h"
#include "packfile.h"
-#include "object-store-ll.h"
+#include "odb.h"
#include "lockfile.h"
#include "exec-cmd.h"
@@ -30,7 +28,7 @@ static int get_st_mode_bits(const char *path, int *mode)
return 0;
}
-struct strbuf *get_pathname(void)
+static struct strbuf *get_pathname(void)
{
static struct strbuf pathname_array[4] = {
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -387,10 +385,11 @@ void report_linked_checkout_garbage(struct repository *r)
strbuf_release(&sb);
}
-static void adjust_git_path(const struct repository *repo,
+static void adjust_git_path(struct repository *repo,
struct strbuf *buf, int git_dir_len)
{
const char *base = buf->buf + git_dir_len;
+
if (is_dir_file(base, "info", "grafts"))
strbuf_splice(buf, 0, buf->len,
repo->graft_file, strlen(repo->graft_file));
@@ -398,9 +397,9 @@ static void adjust_git_path(const struct repository *repo,
strbuf_splice(buf, 0, buf->len,
repo->index_file, strlen(repo->index_file));
else if (dir_prefix(base, "objects"))
- replace_dir(buf, git_dir_len + 7, repo->objects->odb->path);
- else if (git_hooks_path && dir_prefix(base, "hooks"))
- replace_dir(buf, git_dir_len + 5, git_hooks_path);
+ replace_dir(buf, git_dir_len + 7, repo->objects->sources->path);
+ else if (repo_settings_get_hooks_path(repo) && dir_prefix(base, "hooks"))
+ replace_dir(buf, git_dir_len + 5, repo_settings_get_hooks_path(repo));
else if (repo->different_commondir)
update_common_dir(buf, git_dir_len, repo->commondir);
}
@@ -414,12 +413,12 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
else if (!wt->id)
strbuf_addstr(buf, repo->commondir);
else
- strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
+ repo_common_path_append(repo, buf, "worktrees/%s", wt->id);
}
-void repo_git_pathv(const struct repository *repo,
- const struct worktree *wt, struct strbuf *buf,
- const char *fmt, va_list args)
+static void repo_git_pathv(struct repository *repo,
+ const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args)
{
int gitdir_len;
strbuf_worktree_gitdir(buf, repo, wt);
@@ -432,7 +431,7 @@ void repo_git_pathv(const struct repository *repo,
strbuf_cleanup_path(buf);
}
-char *repo_git_path(const struct repository *repo,
+char *repo_git_path(struct repository *repo,
const char *fmt, ...)
{
struct strbuf path = STRBUF_INIT;
@@ -443,14 +442,27 @@ char *repo_git_path(const struct repository *repo,
return strbuf_detach(&path, NULL);
}
-void strbuf_repo_git_path(struct strbuf *sb,
- const struct repository *repo,
- const char *fmt, ...)
+const char *repo_git_path_append(struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
repo_git_pathv(repo, NULL, sb, fmt, args);
va_end(args);
+ return sb->buf;
+}
+
+const char *repo_git_path_replace(struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt, ...)
+{
+ va_list args;
+ strbuf_reset(sb);
+ va_start(args, fmt);
+ repo_git_pathv(repo, NULL, sb, fmt, args);
+ va_end(args);
+ return sb->buf;
}
char *mkpathdup(const char *fmt, ...)
@@ -506,39 +518,56 @@ char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
struct strbuf path = STRBUF_INIT;
va_list args;
+ va_start(args, fmt);
+ do_worktree_path(repo, &path, fmt, args);
+ va_end(args);
+
+ return strbuf_detach(&path, NULL);
+}
+
+const char *repo_worktree_path_append(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt, ...)
+{
+ va_list args;
+
if (!repo->worktree)
return NULL;
va_start(args, fmt);
- do_worktree_path(repo, &path, fmt, args);
+ do_worktree_path(repo, sb, fmt, args);
va_end(args);
- return strbuf_detach(&path, NULL);
+ return sb->buf;
}
-void strbuf_repo_worktree_path(struct strbuf *sb,
- const struct repository *repo,
- const char *fmt, ...)
+const char *repo_worktree_path_replace(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt, ...)
{
va_list args;
+ strbuf_reset(sb);
if (!repo->worktree)
- return;
+ return NULL;
va_start(args, fmt);
do_worktree_path(repo, sb, fmt, args);
va_end(args);
+
+ return sb->buf;
}
/* Returns 0 on success, negative on failure. */
-static int do_submodule_path(struct strbuf *buf, const char *path,
+static int do_submodule_path(struct repository *repo,
+ struct strbuf *buf, const char *path,
const char *fmt, va_list args)
{
struct strbuf git_submodule_common_dir = STRBUF_INIT;
struct strbuf git_submodule_dir = STRBUF_INIT;
int ret;
- ret = submodule_to_gitdir(&git_submodule_dir, path);
+ ret = submodule_to_gitdir(repo, &git_submodule_dir, path);
if (ret)
goto cleanup;
@@ -557,13 +586,14 @@ cleanup:
return ret;
}
-char *git_pathdup_submodule(const char *path, const char *fmt, ...)
+char *repo_submodule_path(struct repository *repo,
+ const char *path, const char *fmt, ...)
{
int err;
va_list args;
struct strbuf buf = STRBUF_INIT;
va_start(args, fmt);
- err = do_submodule_path(&buf, path, fmt, args);
+ err = do_submodule_path(repo, &buf, path, fmt, args);
va_end(args);
if (err) {
strbuf_release(&buf);
@@ -572,22 +602,41 @@ char *git_pathdup_submodule(const char *path, const char *fmt, ...)
return strbuf_detach(&buf, NULL);
}
-int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
- const char *fmt, ...)
+const char *repo_submodule_path_append(struct repository *repo,
+ struct strbuf *buf,
+ const char *path,
+ const char *fmt, ...)
{
int err;
va_list args;
va_start(args, fmt);
- err = do_submodule_path(buf, path, fmt, args);
+ err = do_submodule_path(repo, buf, path, fmt, args);
va_end(args);
+ if (err)
+ return NULL;
+ return buf->buf;
+}
- return err;
+const char *repo_submodule_path_replace(struct repository *repo,
+ struct strbuf *buf,
+ const char *path,
+ const char *fmt, ...)
+{
+ int err;
+ va_list args;
+ strbuf_reset(buf);
+ va_start(args, fmt);
+ err = do_submodule_path(repo, buf, path, fmt, args);
+ va_end(args);
+ if (err)
+ return NULL;
+ return buf->buf;
}
-void repo_common_pathv(const struct repository *repo,
- struct strbuf *sb,
- const char *fmt,
- va_list args)
+static void repo_common_pathv(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt,
+ va_list args)
{
strbuf_addstr(sb, repo->commondir);
if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
@@ -596,14 +645,38 @@ void repo_common_pathv(const struct repository *repo,
strbuf_cleanup_path(sb);
}
-void strbuf_git_common_path(struct strbuf *sb,
- const struct repository *repo,
- const char *fmt, ...)
+char *repo_common_path(const struct repository *repo,
+ const char *fmt, ...)
+{
+ struct strbuf sb = STRBUF_INIT;
+ va_list args;
+ va_start(args, fmt);
+ repo_common_pathv(repo, &sb, fmt, args);
+ va_end(args);
+ return strbuf_detach(&sb, NULL);
+}
+
+const char *repo_common_path_append(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
repo_common_pathv(repo, sb, fmt, args);
va_end(args);
+ return sb->buf;
+}
+
+const char *repo_common_path_replace(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt, ...)
+{
+ va_list args;
+ strbuf_reset(sb);
+ va_start(args, fmt);
+ repo_common_pathv(repo, sb, fmt, args);
+ va_end(args);
+ return sb->buf;
}
static struct passwd *getpw_str(const char *username, size_t len)
@@ -765,21 +838,22 @@ const char *enter_repo(const char *path, unsigned flags)
return NULL;
}
-int calc_shared_perm(int mode)
+int calc_shared_perm(struct repository *repo,
+ int mode)
{
int tweak;
- if (get_shared_repository() < 0)
- tweak = -get_shared_repository();
+ if (repo_settings_get_shared_repository(repo) < 0)
+ tweak = -repo_settings_get_shared_repository(repo);
else
- tweak = get_shared_repository();
+ tweak = repo_settings_get_shared_repository(repo);
if (!(mode & S_IWUSR))
tweak &= ~0222;
if (mode & S_IXUSR)
/* Copy read bits to execute bits */
tweak |= (tweak & 0444) >> 2;
- if (get_shared_repository() < 0)
+ if (repo_settings_get_shared_repository(repo) < 0)
mode = (mode & ~0777) | tweak;
else
mode |= tweak;
@@ -787,17 +861,17 @@ int calc_shared_perm(int mode)
return mode;
}
-
-int adjust_shared_perm(const char *path)
+int adjust_shared_perm(struct repository *repo,
+ const char *path)
{
int old_mode, new_mode;
- if (!get_shared_repository())
+ if (!repo_settings_get_shared_repository(repo))
return 0;
if (get_st_mode_bits(path, &old_mode) < 0)
return -1;
- new_mode = calc_shared_perm(old_mode);
+ new_mode = calc_shared_perm(repo, old_mode);
if (S_ISDIR(old_mode)) {
/* Copy read bits to execute bits */
new_mode |= (new_mode & 0444) >> 2;
@@ -816,7 +890,7 @@ int adjust_shared_perm(const char *path)
return 0;
}
-void safe_create_dir(const char *dir, int share)
+void safe_create_dir(struct repository *repo, const char *dir, int share)
{
if (mkdir(dir, 0777) < 0) {
if (errno != EEXIST) {
@@ -824,10 +898,133 @@ void safe_create_dir(const char *dir, int share)
exit(1);
}
}
- else if (share && adjust_shared_perm(dir))
+ else if (share && adjust_shared_perm(repo, dir))
die(_("Could not make %s writable by group"), dir);
}
+int safe_create_dir_in_gitdir(struct repository *repo, const char *path)
+{
+ if (mkdir(path, 0777)) {
+ int saved_errno = errno;
+ struct stat st;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (errno != EEXIST)
+ return -1;
+ /*
+ * Are we looking at a path in a symlinked worktree
+ * whose original repository does not yet have it?
+ * e.g. .git/rr-cache pointing at its original
+ * repository in which the user hasn't performed any
+ * conflict resolution yet?
+ */
+ if (lstat(path, &st) || !S_ISLNK(st.st_mode) ||
+ strbuf_readlink(&sb, path, st.st_size) ||
+ !is_absolute_path(sb.buf) ||
+ mkdir(sb.buf, 0777)) {
+ strbuf_release(&sb);
+ errno = saved_errno;
+ return -1;
+ }
+ strbuf_release(&sb);
+ }
+ return adjust_shared_perm(repo, path);
+}
+
+static enum scld_error safe_create_leading_directories_1(struct repository *repo,
+ char *path)
+{
+ char *next_component = path + offset_1st_component(path);
+ enum scld_error ret = SCLD_OK;
+
+ while (ret == SCLD_OK && next_component) {
+ struct stat st;
+ char *slash = next_component, slash_character;
+
+ while (*slash && !is_dir_sep(*slash))
+ slash++;
+
+ if (!*slash)
+ break;
+
+ next_component = slash + 1;
+ while (is_dir_sep(*next_component))
+ next_component++;
+ if (!*next_component)
+ break;
+
+ slash_character = *slash;
+ *slash = '\0';
+ if (!stat(path, &st)) {
+ /* path exists */
+ if (!S_ISDIR(st.st_mode)) {
+ errno = ENOTDIR;
+ ret = SCLD_EXISTS;
+ }
+ } else if (mkdir(path, 0777)) {
+ if (errno == EEXIST &&
+ !stat(path, &st) && S_ISDIR(st.st_mode))
+ ; /* somebody created it since we checked */
+ else if (errno == ENOENT)
+ /*
+ * Either mkdir() failed because
+ * somebody just pruned the containing
+ * directory, or stat() failed because
+ * the file that was in our way was
+ * just removed. Either way, inform
+ * the caller that it might be worth
+ * trying again:
+ */
+ ret = SCLD_VANISHED;
+ else
+ ret = SCLD_FAILED;
+ } else if (repo && adjust_shared_perm(repo, path)) {
+ ret = SCLD_PERMS;
+ }
+ *slash = slash_character;
+ }
+ return ret;
+}
+
+enum scld_error safe_create_leading_directories(struct repository *repo,
+ char *path)
+{
+ return safe_create_leading_directories_1(repo, path);
+}
+
+enum scld_error safe_create_leading_directories_no_share(char *path)
+{
+ return safe_create_leading_directories_1(NULL, path);
+}
+
+enum scld_error safe_create_leading_directories_const(struct repository *repo,
+ const char *path)
+{
+ int save_errno;
+ /* path points to cache entries, so xstrdup before messing with it */
+ char *buf = xstrdup(path);
+ enum scld_error result = safe_create_leading_directories(repo, buf);
+
+ save_errno = errno;
+ free(buf);
+ errno = save_errno;
+ return result;
+}
+
+int safe_create_file_with_leading_directories(struct repository *repo,
+ const char *path)
+{
+ int fd;
+
+ fd = open(path, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (0 <= fd)
+ return fd;
+
+ /* slow path */
+ safe_create_leading_directories_const(repo, path);
+ return open(path, O_RDWR|O_CREAT|O_EXCL, 0600);
+}
+
static int have_same_root(const char *path1, const char *path2)
{
int is_abs1, is_abs2;