const unsigned char *sha1, int flag,
int check_name)
{
- int len;
struct ref_entry *ref;
if (check_name &&
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
die("Reference has invalid format: '%s'", refname);
- len = strlen(refname) + 1;
- ref = xmalloc(sizeof(struct ref_entry) + len);
+ FLEX_ALLOC_STR(ref, name, refname);
hashcpy(ref->u.value.oid.hash, sha1);
oidclr(&ref->u.value.peeled);
- memcpy(ref->name, refname, len);
ref->flag = flag;
return ref;
}
int incomplete)
{
struct ref_entry *direntry;
- direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1);
- memcpy(direntry->name, dirname, len);
- direntry->name[len] = '\0';
+ FLEX_ALLOC_MEM(direntry, name, dirname, len);
direntry->u.subdir.ref_cache = ref_cache;
direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);
return direntry;
dir->sorted = dir->nr = i;
}
-/* Include broken references in a do_for_each_ref*() iteration: */
-#define DO_FOR_EACH_INCLUDE_BROKEN 0x01
-
/*
* Return true iff the reference described by entry can be resolved to
* an object in the database. Emit a warning if the referred-to
*/
static struct ref_cache *create_ref_cache(const char *submodule)
{
- int len;
struct ref_cache *refs;
if (!submodule)
submodule = "";
- len = strlen(submodule) + 1;
- refs = xcalloc(1, sizeof(struct ref_cache) + len);
- memcpy(refs->name, submodule, len);
+ FLEX_ALLOC_STR(refs, name, submodule);
refs->next = submodule_ref_caches;
submodule_ref_caches = refs;
return refs;
}
/*
- * A loose ref file doesn't exist; check for a packed ref. The
- * options are forwarded from resolve_safe_unsafe().
+ * A loose ref file doesn't exist; check for a packed ref.
*/
static int resolve_missing_loose_ref(const char *refname,
- int resolve_flags,
unsigned char *sha1,
int *flags)
{
entry = get_packed_ref(refname);
if (entry) {
hashcpy(sha1, entry->u.value.oid.hash);
- if (flags)
- *flags |= REF_ISPACKED;
- return 0;
- }
- /* The reference is not a packed reference, either. */
- if (resolve_flags & RESOLVE_REF_READING) {
- errno = ENOENT;
- return -1;
- } else {
- hashclr(sha1);
+ *flags |= REF_ISPACKED;
return 0;
}
+ /* refname is not a packed reference. */
+ return -1;
}
/* This function needs to return a meaningful errno on failure */
struct strbuf *sb_path,
struct strbuf *sb_contents)
{
- int depth = MAXDEPTH;
int bad_name = 0;
+ int symref_count;
- if (flags)
- *flags = 0;
+ *flags = 0;
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
- if (flags)
- *flags |= REF_BAD_NAME;
+ *flags |= REF_BAD_NAME;
if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
!refname_is_safe(refname)) {
*/
bad_name = 1;
}
- for (;;) {
+
+ for (symref_count = 0; symref_count < MAXDEPTH; symref_count++) {
const char *path;
struct stat st;
- char *buf;
int fd;
- if (--depth < 0) {
- errno = ELOOP;
- return NULL;
- }
-
strbuf_reset(sb_path);
strbuf_git_path(sb_path, "%s", refname);
path = sb_path->buf;
if (lstat(path, &st) < 0) {
if (errno != ENOENT)
return NULL;
- if (resolve_missing_loose_ref(refname, resolve_flags,
- sha1, flags))
- return NULL;
+ if (resolve_missing_loose_ref(refname, sha1, flags)) {
+ if (resolve_flags & RESOLVE_REF_READING) {
+ errno = ENOENT;
+ return NULL;
+ }
+ hashclr(sha1);
+ }
if (bad_name) {
hashclr(sha1);
- if (flags)
- *flags |= REF_ISBROKEN;
+ *flags |= REF_ISBROKEN;
}
return refname;
}
!check_refname_format(sb_contents->buf, 0)) {
strbuf_swap(sb_refname, sb_contents);
refname = sb_refname->buf;
- if (flags)
- *flags |= REF_ISSYMREF;
+ *flags |= REF_ISSYMREF;
if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
hashclr(sha1);
return refname;
*/
if (get_sha1_hex(sb_contents->buf, sha1) ||
(sb_contents->buf[40] != '\0' && !isspace(sb_contents->buf[40]))) {
- if (flags)
- *flags |= REF_ISBROKEN;
+ *flags |= REF_ISBROKEN;
errno = EINVAL;
return NULL;
}
if (bad_name) {
hashclr(sha1);
- if (flags)
- *flags |= REF_ISBROKEN;
+ *flags |= REF_ISBROKEN;
}
return refname;
}
- if (flags)
- *flags |= REF_ISSYMREF;
- buf = sb_contents->buf + 4;
- while (isspace(*buf))
- buf++;
+ *flags |= REF_ISSYMREF;
+ refname = sb_contents->buf + 4;
+ while (isspace(*refname))
+ refname++;
strbuf_reset(sb_refname);
- strbuf_addstr(sb_refname, buf);
+ strbuf_addstr(sb_refname, refname);
refname = sb_refname->buf;
if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
hashclr(sha1);
return refname;
}
- if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
- if (flags)
- *flags |= REF_ISBROKEN;
+ if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+ *flags |= REF_ISBROKEN;
if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
- !refname_is_safe(buf)) {
+ !refname_is_safe(refname)) {
errno = EINVAL;
return NULL;
}
bad_name = 1;
}
}
+
+ errno = ELOOP;
+ return NULL;
}
const char *resolve_ref_unsafe(const char *refname, int resolve_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 = resolve_ref_1(refname, resolve_flags, sha1, flags,
&sb_refname, &sb_path, &sb_contents);
strbuf_release(&sb_path);
* value, stop the iteration and return that value; otherwise, return
* 0.
*/
-static int do_for_each_ref(struct ref_cache *refs, const char *base,
- each_ref_fn fn, int trim, int flags, void *cb_data)
+int do_for_each_ref(const char *submodule, const char *base,
+ each_ref_fn fn, int trim, int flags, void *cb_data)
{
struct ref_entry_cb data;
+ struct ref_cache *refs;
+
+ refs = get_ref_cache(submodule);
data.base = base;
data.trim = trim;
data.flags = flags;
return do_for_each_entry(refs, base, do_one_ref, &data);
}
-static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- struct object_id oid;
- int flag;
-
- if (submodule) {
- if (resolve_gitlink_ref(submodule, "HEAD", oid.hash) == 0)
- return fn("HEAD", &oid, 0, cb_data);
-
- return 0;
- }
-
- if (!read_ref_full("HEAD", RESOLVE_REF_READING, oid.hash, &flag))
- return fn("HEAD", &oid, flag, cb_data);
-
- return 0;
-}
-
-int head_ref(each_ref_fn fn, void *cb_data)
-{
- return do_head_ref(NULL, fn, cb_data);
-}
-
-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- return do_head_ref(submodule, fn, cb_data);
-}
-
-int for_each_ref(each_ref_fn fn, void *cb_data)
-{
- return do_for_each_ref(&ref_cache, "", fn, 0, 0, cb_data);
-}
-
-int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
-{
- return do_for_each_ref(get_ref_cache(submodule), "", fn, 0, 0, cb_data);
-}
-
-int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
-{
- return do_for_each_ref(&ref_cache, prefix, fn, strlen(prefix), 0, cb_data);
-}
-
-int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)
-{
- unsigned int flag = 0;
-
- if (broken)
- flag = DO_FOR_EACH_INCLUDE_BROKEN;
- return do_for_each_ref(&ref_cache, prefix, fn, 0, flag, cb_data);
-}
-
-int for_each_ref_in_submodule(const char *submodule, const char *prefix,
- each_ref_fn fn, void *cb_data)
-{
- return do_for_each_ref(get_ref_cache(submodule), prefix, fn, strlen(prefix), 0, cb_data);
-}
-
-int for_each_replace_ref(each_ref_fn fn, void *cb_data)
-{
- return do_for_each_ref(&ref_cache, git_replace_ref_base, fn,
- strlen(git_replace_ref_base), 0, cb_data);
-}
-
-int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
-{
- struct strbuf buf = STRBUF_INIT;
- int ret;
- strbuf_addf(&buf, "%srefs/", get_git_namespace());
- ret = do_for_each_ref(&ref_cache, buf.buf, fn, 0, 0, cb_data);
- strbuf_release(&buf);
- return ret;
-}
-
-int for_each_rawref(each_ref_fn fn, void *cb_data)
-{
- return do_for_each_ref(&ref_cache, "", fn, 0,
- DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
-}
-
static void unlock_ref(struct ref_lock *lock)
{
/* Do not free lock->lk -- atexit() still looks at them */
if (read_ref_full(lock->ref_name,
mustexist ? RESOLVE_REF_READING : 0,
lock->old_oid.hash, NULL)) {
- int save_errno = errno;
- strbuf_addf(err, "can't verify ref %s", lock->ref_name);
- errno = save_errno;
- return -1;
+ if (old_sha1) {
+ int save_errno = errno;
+ strbuf_addf(err, "can't verify ref %s", lock->ref_name);
+ errno = save_errno;
+ return -1;
+ } else {
+ hashclr(lock->old_oid.hash);
+ return 0;
+ }
}
- if (hashcmp(lock->old_oid.hash, old_sha1)) {
+ if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) {
strbuf_addf(err, "ref %s is at %s but expected %s",
lock->ref_name,
sha1_to_hex(lock->old_oid.hash),
const char *orig_refname = refname;
struct ref_lock *lock;
int last_errno = 0;
- int type, lflags;
+ int type;
+ int lflags = 0;
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
int resolve_flags = 0;
int attempts_remaining = 3;
if (mustexist)
resolve_flags |= RESOLVE_REF_READING;
- if (flags & REF_DELETING) {
+ if (flags & REF_DELETING)
resolve_flags |= RESOLVE_REF_ALLOW_BAD_NAME;
- if (flags & REF_NODEREF)
- resolve_flags |= RESOLVE_REF_NO_RECURSE;
+ if (flags & REF_NODEREF) {
+ resolve_flags |= RESOLVE_REF_NO_RECURSE;
+ lflags |= LOCK_NO_DEREF;
}
refname = resolve_ref_unsafe(refname, resolve_flags,
goto error_return;
}
+
+ if (flags & REF_NODEREF)
+ refname = orig_refname;
+
/*
* If the ref did not exist and we are creating it, make sure
* there is no existing packed ref whose name begins with our
lock->lk = xcalloc(1, sizeof(struct lock_file));
- lflags = 0;
- if (flags & REF_NODEREF) {
- refname = orig_refname;
- lflags |= LOCK_NO_DEREF;
- }
lock->ref_name = xstrdup(refname);
lock->orig_ref_name = xstrdup(orig_refname);
strbuf_git_path(&ref_file, "%s", refname);
goto error_return;
}
}
- if (old_sha1 && verify_lock(lock, old_sha1, mustexist, err)) {
+ if (verify_lock(lock, old_sha1, mustexist, err)) {
last_errno = errno;
goto error_return;
}
/* Schedule the loose reference for pruning if requested. */
if ((cb->flags & PACK_REFS_PRUNE)) {
- int namelen = strlen(entry->name) + 1;
- struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
+ struct ref_to_prune *n;
+ FLEX_ALLOC_STR(n, name, entry->name);
hashcpy(n->sha1, entry->u.value.oid.hash);
- memcpy(n->name, entry->name, namelen); /* includes NUL */
n->next = cb->ref_to_prune;
cb->ref_to_prune = n;
}
return 0;
}
-int create_symref(const char *ref_target, const char *refs_heads_master,
- const char *logmsg)
+static int create_ref_symlink(struct ref_lock *lock, const char *target)
{
- char *lockpath = NULL;
- char ref[1000];
- int fd, len, written;
- char *git_HEAD = git_pathdup("%s", ref_target);
- unsigned char old_sha1[20], new_sha1[20];
- struct strbuf err = STRBUF_INIT;
-
- if (logmsg && read_ref(ref_target, old_sha1))
- hashclr(old_sha1);
-
- if (safe_create_leading_directories(git_HEAD) < 0)
- return error("unable to create directory for %s", git_HEAD);
-
+ int ret = -1;
#ifndef NO_SYMLINK_HEAD
- if (prefer_symlink_refs) {
- unlink(git_HEAD);
- if (!symlink(refs_heads_master, git_HEAD))
- goto done;
+ char *ref_path = get_locked_file_path(lock->lk);
+ unlink(ref_path);
+ ret = symlink(target, ref_path);
+ free(ref_path);
+
+ if (ret)
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
- }
#endif
+ return ret;
+}
- len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
- if (sizeof(ref) <= len) {
- error("refname too long: %s", refs_heads_master);
- goto error_free_return;
- }
- lockpath = mkpathdup("%s.lock", git_HEAD);
- fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
- if (fd < 0) {
- error("Unable to open %s for writing", lockpath);
- goto error_free_return;
- }
- written = write_in_full(fd, ref, len);
- if (close(fd) != 0 || written != len) {
- error("Unable to write to %s", lockpath);
- goto error_unlink_return;
- }
- if (rename(lockpath, git_HEAD) < 0) {
- error("Unable to create %s", git_HEAD);
- goto error_unlink_return;
- }
- if (adjust_shared_perm(git_HEAD)) {
- error("Unable to fix permissions on %s", lockpath);
- error_unlink_return:
- unlink_or_warn(lockpath);
- error_free_return:
- free(lockpath);
- free(git_HEAD);
- return -1;
+static void update_symref_reflog(struct ref_lock *lock, const char *refname,
+ const char *target, const char *logmsg)
+{
+ struct strbuf err = STRBUF_INIT;
+ unsigned char new_sha1[20];
+ if (logmsg && !read_ref(target, new_sha1) &&
+ log_ref_write(refname, lock->old_oid.hash, new_sha1, logmsg, 0, &err)) {
+ error("%s", err.buf);
+ strbuf_release(&err);
}
- free(lockpath);
+}
-#ifndef NO_SYMLINK_HEAD
- done:
-#endif
- if (logmsg && !read_ref(refs_heads_master, new_sha1) &&
- log_ref_write(ref_target, old_sha1, new_sha1, logmsg, 0, &err)) {
+static int create_symref_locked(struct ref_lock *lock, const char *refname,
+ const char *target, const char *logmsg)
+{
+ if (prefer_symlink_refs && !create_ref_symlink(lock, target)) {
+ update_symref_reflog(lock, refname, target, logmsg);
+ return 0;
+ }
+
+ if (!fdopen_lock_file(lock->lk, "w"))
+ return error("unable to fdopen %s: %s",
+ lock->lk->tempfile.filename.buf, strerror(errno));
+
+ update_symref_reflog(lock, refname, target, logmsg);
+
+ /* no error check; commit_ref will check ferror */
+ fprintf(lock->lk->tempfile.fp, "ref: %s\n", target);
+ if (commit_ref(lock) < 0)
+ return error("unable to write symref for %s: %s", refname,
+ strerror(errno));
+ return 0;
+}
+
+int create_symref(const char *refname, const char *target, const char *logmsg)
+{
+ struct strbuf err = STRBUF_INIT;
+ struct ref_lock *lock;
+ int ret;
+
+ lock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL,
+ &err);
+ if (!lock) {
error("%s", err.buf);
strbuf_release(&err);
+ return -1;
}
- free(git_HEAD);
- return 0;
+ ret = create_symref_locked(lock, refname, target, logmsg);
+ unlock_ref(lock);
+ return ret;
}
int reflog_exists(const char *refname)