return get_ref_dir(refs->loose);
}
-/* We allow "recursive" symbolic refs. Only within reason, though */
-#define MAXDEPTH 5
#define MAXREFLEN (1024)
/*
char buffer[128], *p;
char *path;
- if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
+ if (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)
return -1;
path = *refs->name
? git_pathdup_submodule(refs->name, "%s", refname)
*/
static int resolve_missing_loose_ref(const char *refname,
unsigned char *sha1,
- int *flags)
+ unsigned int *flags)
{
struct ref_entry *entry;
* - in all other cases, symref will be untouched, and therefore
* refname will still be valid and unchanged.
*/
-static int read_raw_ref(const char *refname, unsigned char *sha1,
- struct strbuf *symref, struct strbuf *sb_path,
- struct strbuf *sb_contents, int *flags)
+int read_raw_ref(const char *refname, unsigned char *sha1,
+ struct strbuf *symref, unsigned int *flags)
{
+ struct strbuf sb_contents = STRBUF_INIT;
+ struct strbuf sb_path = STRBUF_INIT;
const char *path;
const char *buf;
struct stat st;
int fd;
+ int ret = -1;
+ int save_errno;
- strbuf_reset(sb_path);
- strbuf_git_path(sb_path, "%s", refname);
- path = sb_path->buf;
+ strbuf_reset(&sb_path);
+ strbuf_git_path(&sb_path, "%s", refname);
+ path = sb_path.buf;
stat_ref:
/*
if (lstat(path, &st) < 0) {
if (errno != ENOENT)
- return -1;
+ goto out;
if (resolve_missing_loose_ref(refname, sha1, flags)) {
errno = ENOENT;
- return -1;
+ goto out;
}
- return 0;
+ ret = 0;
+ goto out;
}
/* Follow "normalized" - ie "refs/.." symlinks by hand */
if (S_ISLNK(st.st_mode)) {
- strbuf_reset(sb_contents);
- if (strbuf_readlink(sb_contents, path, 0) < 0) {
+ strbuf_reset(&sb_contents);
+ if (strbuf_readlink(&sb_contents, path, 0) < 0) {
if (errno == ENOENT || errno == EINVAL)
/* inconsistent with lstat; retry */
goto stat_ref;
else
- return -1;
+ goto out;
}
- if (starts_with(sb_contents->buf, "refs/") &&
- !check_refname_format(sb_contents->buf, 0)) {
- strbuf_swap(sb_contents, symref);
+ if (starts_with(sb_contents.buf, "refs/") &&
+ !check_refname_format(sb_contents.buf, 0)) {
+ strbuf_swap(&sb_contents, symref);
*flags |= REF_ISSYMREF;
- return 0;
+ ret = 0;
+ goto out;
}
}
/* Is it a directory? */
if (S_ISDIR(st.st_mode)) {
errno = EISDIR;
- return -1;
+ goto out;
}
/*
/* inconsistent with lstat; retry */
goto stat_ref;
else
- return -1;
+ goto out;
}
- strbuf_reset(sb_contents);
- if (strbuf_read(sb_contents, fd, 256) < 0) {
+ strbuf_reset(&sb_contents);
+ if (strbuf_read(&sb_contents, fd, 256) < 0) {
int save_errno = errno;
close(fd);
errno = save_errno;
- return -1;
+ goto out;
}
close(fd);
- strbuf_rtrim(sb_contents);
- buf = sb_contents->buf;
+ strbuf_rtrim(&sb_contents);
+ buf = sb_contents.buf;
if (starts_with(buf, "ref:")) {
buf += 4;
while (isspace(*buf))
strbuf_reset(symref);
strbuf_addstr(symref, buf);
*flags |= REF_ISSYMREF;
- return 0;
+ ret = 0;
+ goto out;
}
/*
(buf[40] != '\0' && !isspace(buf[40]))) {
*flags |= REF_ISBROKEN;
errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-/* This function needs to return a meaningful errno on failure */
-static const char *resolve_ref_1(const char *refname,
- int resolve_flags,
- unsigned char *sha1,
- int *flags,
- struct strbuf *sb_refname,
- struct strbuf *sb_path,
- struct strbuf *sb_contents)
-{
- int symref_count;
-
- *flags = 0;
-
- if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
- if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
- !refname_is_safe(refname)) {
- errno = EINVAL;
- return NULL;
- }
-
- /*
- * dwim_ref() uses REF_ISBROKEN to distinguish between
- * missing refs and refs that were present but invalid,
- * to complain about the latter to stderr.
- *
- * We don't know whether the ref exists, so don't set
- * REF_ISBROKEN yet.
- */
- *flags |= REF_BAD_NAME;
- }
-
- for (symref_count = 0; symref_count < MAXDEPTH; symref_count++) {
- int read_flags = 0;
-
- if (read_raw_ref(refname, sha1, sb_refname,
- sb_path, sb_contents, &read_flags)) {
- *flags |= read_flags;
- if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))
- return NULL;
- hashclr(sha1);
- if (*flags & REF_BAD_NAME)
- *flags |= REF_ISBROKEN;
- return refname;
- }
-
- *flags |= read_flags;
-
- if (!(read_flags & REF_ISSYMREF)) {
- if (*flags & REF_BAD_NAME) {
- hashclr(sha1);
- *flags |= REF_ISBROKEN;
- }
- return refname;
- }
-
- refname = sb_refname->buf;
- if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
- hashclr(sha1);
- return refname;
- }
- if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
- if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
- !refname_is_safe(refname)) {
- errno = EINVAL;
- return NULL;
- }
-
- *flags |= REF_ISBROKEN | REF_BAD_NAME;
- }
+ goto out;
}
- errno = ELOOP;
- return NULL;
-}
-
-const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
- unsigned char *sha1, int *flags)
-{
- static struct strbuf sb_refname = STRBUF_INIT;
- struct strbuf sb_contents = STRBUF_INIT;
- struct strbuf sb_path = STRBUF_INIT;
- int unused_flags;
- const char *ret;
-
- if (!flags)
- flags = &unused_flags;
+ ret = 0;
- ret = resolve_ref_1(refname, resolve_flags, sha1, flags,
- &sb_refname, &sb_path, &sb_contents);
+out:
+ save_errno = errno;
strbuf_release(&sb_path);
strbuf_release(&sb_contents);
+ errno = save_errno;
return ret;
}
return ret;
}
+int set_worktree_head_symref(const char *gitdir, const char *target)
+{
+ static struct lock_file head_lock;
+ struct ref_lock *lock;
+ struct strbuf head_path = STRBUF_INIT;
+ const char *head_rel;
+ int ret;
+
+ strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir));
+ if (hold_lock_file_for_update(&head_lock, head_path.buf,
+ LOCK_NO_DEREF) < 0) {
+ struct strbuf err = STRBUF_INIT;
+ unable_to_lock_message(head_path.buf, errno, &err);
+ error("%s", err.buf);
+ strbuf_release(&err);
+ strbuf_release(&head_path);
+ return -1;
+ }
+
+ /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for
+ linked trees */
+ head_rel = remove_leading_path(head_path.buf,
+ absolute_path(get_git_common_dir()));
+ /* to make use of create_symref_locked(), initialize ref_lock */
+ lock = xcalloc(1, sizeof(struct ref_lock));
+ lock->lk = &head_lock;
+ lock->ref_name = xstrdup(head_rel);
+ lock->orig_ref_name = xstrdup(head_rel);
+
+ ret = create_symref_locked(lock, head_rel, target, NULL);
+
+ unlock_ref(lock); /* will free lock */
+ strbuf_release(&head_path);
+ return ret;
+}
+
int reflog_exists(const char *refname)
{
struct stat st;
* reference itself, plus we might need to update the
* reference if --updateref was specified:
*/
- lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, 0, &type, &err);
+ lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, REF_NODEREF,
+ &type, &err);
if (!lock) {
error("cannot lock ref '%s': %s", refname, err.buf);
strbuf_release(&err);