struct ref_entry *old_current_ref;
int retval;
- if (prefixcmp(entry->name, data->base))
+ if (!starts_with(entry->name, data->base))
return 0;
if (!(data->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
if (refname) {
last = create_ref_entry(refname, sha1, REF_ISPACKED, 1);
if (peeled == PEELED_FULLY ||
- (peeled == PEELED_TAGS && !prefixcmp(refname, "refs/tags/")))
+ (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
last->flag |= REF_KNOWS_PEELED;
add_ref(dir, last);
continue;
return NULL;
}
buffer[len] = 0;
- if (!prefixcmp(buffer, "refs/") &&
+ if (starts_with(buffer, "refs/") &&
!check_refname_format(buffer, 0)) {
strcpy(refname_buffer, buffer);
refname = refname_buffer;
/*
* Is it a symbolic ref?
*/
- if (prefixcmp(buffer, "ref:")) {
+ if (!starts_with(buffer, "ref:")) {
/*
* Please note that FETCH_HEAD has a second
* line containing other data.
struct ref_filter filter;
int ret;
- if (!prefix && prefixcmp(pattern, "refs/"))
+ if (!prefix && !starts_with(pattern, "refs/"))
strbuf_addstr(&real_pattern, "refs/");
else if (prefix)
strbuf_addstr(&real_pattern, prefix);
const char *prettify_refname(const char *name)
{
return name + (
- !prefixcmp(name, "refs/heads/") ? 11 :
- !prefixcmp(name, "refs/tags/") ? 10 :
- !prefixcmp(name, "refs/remotes/") ? 13 :
+ starts_with(name, "refs/heads/") ? 11 :
+ starts_with(name, "refs/tags/") ? 10 :
+ starts_with(name, "refs/remotes/") ? 13 :
0);
}
-const char *ref_rev_parse_rules[] = {
+static const char *ref_rev_parse_rules[] = {
"%.*s",
"refs/%.*s",
"refs/tags/%.*s",
NULL
};
-int refname_match(const char *abbrev_name, const char *full_name, const char **rules)
+int refname_match(const char *abbrev_name, const char *full_name)
{
const char **p;
const int abbrev_name_len = strlen(abbrev_name);
- for (p = rules; *p; p++) {
+ for (p = ref_rev_parse_rules; *p; p++) {
if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
return 1;
}
lock->lk = xcalloc(1, sizeof(struct lock_file));
- lflags = LOCK_DIE_ON_ERROR;
+ lflags = 0;
if (flags & REF_NODEREF) {
refname = orig_refname;
lflags |= LOCK_NODEREF;
}
lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags);
+ if (lock->lock_fd < 0) {
+ if (errno == ENOENT && --attempts_remaining > 0)
+ /*
+ * Maybe somebody just deleted one of the
+ * directories leading to ref_file. Try
+ * again:
+ */
+ goto retry;
+ else
+ unable_to_lock_index_die(ref_file, errno);
+ }
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
error_return:
struct pack_refs_cb_data *cb = cb_data;
enum peel_status peel_status;
struct ref_entry *packed_entry;
- int is_tag_ref = !prefixcmp(entry->name, "refs/tags/");
+ int is_tag_ref = starts_with(entry->name, "refs/tags/");
/* ALWAYS pack tags */
if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
*/
#define TMP_RENAMED_LOG "logs/refs/.tmp-renamed-log"
+static int rename_tmp_log(const char *newrefname)
+{
+ int attempts_remaining = 4;
+
+ retry:
+ switch (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
+ case SCLD_OK:
+ break; /* success */
+ case SCLD_VANISHED:
+ if (--attempts_remaining > 0)
+ goto retry;
+ /* fall through */
+ default:
+ error("unable to create directory for %s", newrefname);
+ return -1;
+ }
+
+ if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) {
+ if ((errno==EISDIR || errno==ENOTDIR) && --attempts_remaining > 0) {
+ /*
+ * rename(a, b) when b is an existing
+ * directory ought to result in ISDIR, but
+ * Solaris 5.8 gives ENOTDIR. Sheesh.
+ */
+ if (remove_empty_directories(git_path("logs/%s", newrefname))) {
+ error("Directory not empty: logs/%s", newrefname);
+ return -1;
+ }
+ goto retry;
+ } else if (errno == ENOENT && --attempts_remaining > 0) {
+ /*
+ * Maybe another process just deleted one of
+ * the directories in the path to newrefname.
+ * Try again from the beginning.
+ */
+ goto retry;
+ } else {
+ error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
+ newrefname, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
{
unsigned char sha1[20], orig_sha1[20];
}
}
- if (log && safe_create_leading_directories(git_path("logs/%s", newrefname))) {
- error("unable to create directory for %s", newrefname);
+ if (log && rename_tmp_log(newrefname))
goto rollback;
- }
- retry:
- if (log && rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) {
- if (errno==EISDIR || errno==ENOTDIR) {
- /*
- * rename(a, b) when b is an existing
- * directory ought to result in ISDIR, but
- * Solaris 5.8 gives ENOTDIR. Sheesh.
- */
- if (remove_empty_directories(git_path("logs/%s", newrefname))) {
- error("Directory not empty: logs/%s", newrefname);
- goto rollback;
- }
- goto retry;
- } else {
- error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
- newrefname, strerror(errno));
- goto rollback;
- }
- }
logmoved = log;
lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL);
git_snpath(logfile, bufsize, "logs/%s", refname);
if (log_all_ref_updates &&
- (!prefixcmp(refname, "refs/heads/") ||
- !prefixcmp(refname, "refs/remotes/") ||
- !prefixcmp(refname, "refs/notes/") ||
+ (starts_with(refname, "refs/heads/") ||
+ starts_with(refname, "refs/remotes/") ||
+ starts_with(refname, "refs/notes/") ||
!strcmp(refname, "HEAD"))) {
if (safe_create_leading_directories(logfile) < 0)
return error("unable to create directory for %s",
static int is_branch(const char *refname)
{
- return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
+ return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
}
int write_ref_sha1(struct ref_lock *lock,
return ret;
}
-/*
- * generate a format suitable for scanf from a ref_rev_parse_rules
- * rule, that is replace the "%.*s" spec with a "%s" spec
- */
-static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
-{
- char *spec;
-
- spec = strstr(rule, "%.*s");
- if (!spec || strstr(spec + 4, "%.*s"))
- die("invalid rule in ref_rev_parse_rules: %s", rule);
-
- /* copy all until spec */
- strncpy(scanf_fmt, rule, spec - rule);
- scanf_fmt[spec - rule] = '\0';
- /* copy new spec */
- strcat(scanf_fmt, "%s");
- /* copy remaining rule */
- strcat(scanf_fmt, spec + 4);
-
- return;
-}
-
char *shorten_unambiguous_ref(const char *refname, int strict)
{
int i;
static int nr_rules;
char *short_name;
- /* pre generate scanf formats from ref_rev_parse_rules[] */
if (!nr_rules) {
+ /*
+ * Pre-generate scanf formats from ref_rev_parse_rules[].
+ * Generate a format suitable for scanf from a
+ * ref_rev_parse_rules rule by interpolating "%s" at the
+ * location of the "%.*s".
+ */
size_t total_len = 0;
+ size_t offset = 0;
/* the rule list is NULL terminated, count them first */
for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)
- /* no +1 because strlen("%s") < strlen("%.*s") */
- total_len += strlen(ref_rev_parse_rules[nr_rules]);
+ /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
+ total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;
scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
- total_len = 0;
+ offset = 0;
for (i = 0; i < nr_rules; i++) {
- scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
- + total_len;
- gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
- total_len += strlen(ref_rev_parse_rules[i]);
+ assert(offset < total_len);
+ scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
+ offset += snprintf(scanf_fmts[i], total_len - offset,
+ ref_rev_parse_rules[i], 2, "%s") + 1;
}
}
{
if (!strcmp("transfer.hiderefs", var) ||
/* NEEDSWORK: use parse_config_key() once both are merged */
- (!prefixcmp(var, section) && var[strlen(section)] == '.' &&
+ (starts_with(var, section) && var[strlen(section)] == '.' &&
!strcmp(var + strlen(section), ".hiderefs"))) {
char *ref;
int len;
return 0;
for_each_string_list_item(item, hide_refs) {
int len;
- if (prefixcmp(refname, item->string))
+ if (!starts_with(refname, item->string))
continue;
len = strlen(item->string);
if (!refname[len] || refname[len] == '/')