diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 106 |
1 files changed, 87 insertions, 19 deletions
@@ -6,6 +6,7 @@ /* ISSYMREF=01 and ISPACKED=02 are public interfaces */ #define REF_KNOWS_PEELED 04 +#define REF_BROKEN 010 struct ref_list { struct ref_list *next; @@ -275,8 +276,10 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list) list = get_ref_dir(ref, list); continue; } - if (!resolve_ref(ref, sha1, 1, &flag)) + if (!resolve_ref(ref, sha1, 1, &flag)) { hashclr(sha1); + flag |= REF_BROKEN; + } list = add_ref(ref, sha1, flag, list, NULL); } free(ref); @@ -286,6 +289,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list) } struct warn_if_dangling_data { + FILE *fp; const char *refname; const char *msg_fmt; }; @@ -304,13 +308,13 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha if (!resolves_to || strcmp(resolves_to, d->refname)) return 0; - printf(d->msg_fmt, refname); + fprintf(d->fp, d->msg_fmt, refname); return 0; } -void warn_dangling_symref(const char *msg_fmt, const char *refname) +void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname) { - struct warn_if_dangling_data data = { refname, msg_fmt }; + struct warn_if_dangling_data data = { fp, refname, msg_fmt }; for_each_rawref(warn_if_dangling_symref, &data); } @@ -518,6 +522,13 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int * return ref; } +/* The argument to filter_refs */ +struct ref_filter { + const char *pattern; + each_ref_fn *fn; + void *cb_data; +}; + int read_ref(const char *ref, unsigned char *sha1) { if (resolve_ref(ref, sha1, 1, NULL)) @@ -531,9 +542,10 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, { if (strncmp(base, entry->name, trim)) return 0; + if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { - if (is_null_sha1(entry->sha1)) - return 0; + if (entry->flag & REF_BROKEN) + return 0; /* ignore dangling symref */ if (!has_sha1_file(entry->sha1)) { error("%s does not point to a valid object!", entry->name); return 0; @@ -543,6 +555,15 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, return fn(entry->name + trim, entry->sha1, entry->flag, cb_data); } +static int filter_refs(const char *ref, const unsigned char *sha, int flags, + void *data) +{ + struct ref_filter *filter = (struct ref_filter *)data; + if (fnmatch(filter->pattern, ref, 0)) + return 0; + return filter->fn(ref, sha, flags, filter->cb_data); +} + int peel_ref(const char *ref, unsigned char *sha1) { int flag; @@ -667,6 +688,46 @@ int for_each_remote_ref(each_ref_fn fn, void *cb_data) return for_each_ref_in("refs/remotes/", fn, cb_data); } +int for_each_replace_ref(each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref("refs/replace/", fn, 13, 0, cb_data); +} + +int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, + const char *prefix, void *cb_data) +{ + struct strbuf real_pattern = STRBUF_INIT; + struct ref_filter filter; + int ret; + + if (!prefix && prefixcmp(pattern, "refs/")) + strbuf_addstr(&real_pattern, "refs/"); + else if (prefix) + strbuf_addstr(&real_pattern, prefix); + strbuf_addstr(&real_pattern, pattern); + + if (!has_glob_specials(pattern)) { + /* Append implied '/' '*' if not present. */ + if (real_pattern.buf[real_pattern.len - 1] != '/') + strbuf_addch(&real_pattern, '/'); + /* No need to check for '*', there is none. */ + strbuf_addch(&real_pattern, '*'); + } + + filter.pattern = real_pattern.buf; + filter.fn = fn; + filter.cb_data = cb_data; + ret = for_each_ref(filter_refs, &filter); + + strbuf_release(&real_pattern); + return ret; +} + +int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data) +{ + return for_each_glob_ref_in(fn, pattern, NULL, cb_data); +} + int for_each_rawref(each_ref_fn fn, void *cb_data) { return do_for_each_ref("refs/", fn, 0, @@ -820,7 +881,7 @@ static int remove_empty_directories(const char *file) strbuf_init(&path, 20); strbuf_addstr(&path, file); - result = remove_dir_recursively(&path, 1); + result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY); strbuf_release(&path); @@ -966,8 +1027,10 @@ static int repack_without_ref(const char *refname) if (!found) return 0; fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0); - if (fd < 0) + if (fd < 0) { + unable_to_lock_error(git_path("packed-refs"), errno); return error("cannot delete '%s' from packed refs", refname); + } for (list = packed_ref_list; list; list = list->next) { char line[PATH_MAX + 100]; @@ -1213,6 +1276,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, if (log_all_ref_updates && (!prefixcmp(ref_name, "refs/heads/") || !prefixcmp(ref_name, "refs/remotes/") || + !prefixcmp(ref_name, "refs/notes/") || !strcmp(ref_name, "HEAD"))) { if (safe_create_leading_directories(log_file) < 0) return error("unable to create directory for %s", @@ -1418,7 +1482,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * logfile = git_path("logs/%s", ref); logfd = open(logfile, O_RDONLY, 0); if (logfd < 0) - die("Unable to read log %s: %s", logfile, strerror(errno)); + die_errno("Unable to read log '%s'", logfile); fstat(logfd, &st); if (!st.st_size) die("Log %s is empty.", logfile); @@ -1512,7 +1576,7 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs, { const char *logfile; FILE *logfp; - char buf[1024]; + struct strbuf sb = STRBUF_INIT; int ret = 0; logfile = git_path("logs/%s", ref); @@ -1525,22 +1589,24 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs, if (fstat(fileno(logfp), &statbuf) || statbuf.st_size < ofs || fseek(logfp, -ofs, SEEK_END) || - fgets(buf, sizeof(buf), logfp)) + strbuf_getwholeline(&sb, logfp, '\n')) { + fclose(logfp); + strbuf_release(&sb); return -1; + } } - while (fgets(buf, sizeof(buf), logfp)) { + while (!strbuf_getwholeline(&sb, logfp, '\n')) { unsigned char osha1[20], nsha1[20]; char *email_end, *message; unsigned long timestamp; - int len, tz; + int tz; /* old SP new SP name <email> SP time TAB msg LF */ - len = strlen(buf); - if (len < 83 || buf[len-1] != '\n' || - get_sha1_hex(buf, osha1) || buf[40] != ' ' || - get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ' || - !(email_end = strchr(buf + 82, '>')) || + if (sb.len < 83 || sb.buf[sb.len - 1] != '\n' || + get_sha1_hex(sb.buf, osha1) || sb.buf[40] != ' ' || + get_sha1_hex(sb.buf + 41, nsha1) || sb.buf[81] != ' ' || + !(email_end = strchr(sb.buf + 82, '>')) || email_end[1] != ' ' || !(timestamp = strtoul(email_end + 2, &message, 10)) || !message || message[0] != ' ' || @@ -1554,11 +1620,13 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs, message += 6; else message += 7; - ret = fn(osha1, nsha1, buf+82, timestamp, tz, message, cb_data); + ret = fn(osha1, nsha1, sb.buf + 82, timestamp, tz, message, + cb_data); if (ret) break; } fclose(logfp); + strbuf_release(&sb); return ret; } |