This just moves code around; the behavior of read_ref_at (currently the only user) should be identical. Signed-off-by: Jeff King <peff@xxxxxxxx> --- This patch is in preparation for doing more interesting things with reflogs, like git-describe. refs.c | 176 +++++++++++++++++++++++++++++++++++++++------------------------ refs.h | 21 ++++++++ 2 files changed, 130 insertions(+), 67 deletions(-) diff --git a/refs.c b/refs.c index 3d4cdd1..f5dfe4d 100644 --- a/refs.c +++ b/refs.c @@ -615,83 +615,125 @@ int write_ref_sha1(struct ref_lock *lock return 0; } -int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1) +int reflog_open(struct reflog *log, const char *ref) { - const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec; - char *tz_c; - int logfd, tz; + int logfd; struct stat st; - unsigned long date; - unsigned char logged_sha1[20]; - logfile = git_path("logs/%s", ref); - logfd = open(logfile, O_RDONLY, 0); + log->file = xstrdup(git_path("logs/%s", ref)); + logfd = open(log->file, O_RDONLY, 0); if (logfd < 0) - die("Unable to read log %s: %s", logfile, strerror(errno)); + return -1; fstat(logfd, &st); - if (!st.st_size) - die("Log %s is empty.", logfile); - logdata = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0); + log->size = st.st_size; + log->data = mmap(NULL, log->size, PROT_READ, MAP_PRIVATE, logfd, 0); close(logfd); + return 0; +} - lastrec = NULL; - rec = logend = logdata + st.st_size; - while (logdata < rec) { - if (logdata < rec && *(rec-1) == '\n') - rec--; - lastgt = NULL; - while (logdata < rec && *(rec-1) != '\n') { - rec--; - if (*rec == '>') - lastgt = rec; - } - if (!lastgt) - die("Log %s is corrupt.", logfile); - date = strtoul(lastgt + 1, &tz_c, 10); - if (date <= at_time) { - if (lastrec) { - if (get_sha1_hex(lastrec, logged_sha1)) - die("Log %s is corrupt.", logfile); - if (get_sha1_hex(rec + 41, sha1)) - die("Log %s is corrupt.", logfile); - if (hashcmp(logged_sha1, sha1)) { - tz = strtoul(tz_c, NULL, 10); - fprintf(stderr, - "warning: Log %s has gap after %s.\n", - logfile, show_rfc2822_date(date, tz)); - } - } - else if (date == at_time) { - if (get_sha1_hex(rec + 41, sha1)) - die("Log %s is corrupt.", logfile); - } - else { - if (get_sha1_hex(rec + 41, logged_sha1)) - die("Log %s is corrupt.", logfile); - if (hashcmp(logged_sha1, sha1)) { - tz = strtoul(tz_c, NULL, 10); - fprintf(stderr, - "warning: Log %s unexpectedly ended on %s.\n", - logfile, show_rfc2822_date(date, tz)); - } - } - munmap((void*)logdata, st.st_size); +void reflog_close(struct reflog *log) +{ + free(log->file); + munmap((void *)log->data, log->size); +} + +int reflog_next(struct reflog *log, struct reflog_entry *out) +{ + const char *rec, *lastgt; + char *tz_c; + + rec = log->rec; + if (rec == log->data) + return 0; + + lastgt = NULL; + if (log->data < rec && *(rec-1) == '\n') + rec--; + while (log->data < rec && *(rec-1) != '\n') { + rec--; + if (*rec == '>') + lastgt = rec; + } + if (log->data == rec - 1) + rec--; + if (!lastgt) + die("Log %s is corrupt (nolastgt).", log->file); + + out->date = strtoul(lastgt + 1, &tz_c, 10); + out->tz = strtoul(tz_c, NULL, 10); + out->rec = rec; + out->log = log; + log->rec = rec; + + return 1; +} + +void reflog_start(struct reflog *log) +{ + log->rec = log->data + log->size; +} + +void reflog_entry_from(const struct reflog_entry *e, unsigned char *sha1) +{ + if (get_sha1_hex(e->rec, sha1)) + die("Log %s is corrupt.", e->log->file); +} + +void reflog_entry_to(const struct reflog_entry *e, unsigned char *sha1) +{ + if (get_sha1_hex(e->rec+41, sha1)) + die("Log %s is corrupt.", e->log->file); +} + +int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1) +{ + struct reflog log; + struct reflog_entry cur, last; + int last_is_valid; + unsigned char sha1_from[20]; + unsigned char sha1_to[20]; + + if (reflog_open(&log, ref) < 0) + die("Unable to read log %s: %s", log.file, strerror(errno)); + + last_is_valid = 0; + reflog_start(&log); + do { + if (!reflog_next(&log, &cur)) { + if (!last_is_valid) + die("Log %s is empty.", log.file); + reflog_entry_to(&last, sha1); + fprintf(stderr, + "warning: Log %s only goes back to %s.\n", + log.file, + show_rfc2822_date(last.date, last.tz)); + reflog_close(&log); return 0; } - lastrec = rec; + last = cur; + last_is_valid = 1; + } while (at_time < cur.date); + + reflog_entry_to(&cur, sha1_to); + if (last_is_valid) { + reflog_entry_from(&last, sha1_from); + if (hashcmp(sha1_to, sha1_from)) { + fprintf(stderr, + "warning: Log %s has gap after %s.\n", + log.file, + show_rfc2822_date(cur.date, cur.tz)); + } + } + else if(cur.date != at_time) { + if (hashcmp(sha1_to, sha1)) { + fprintf(stderr, + "warning: Log %s unexpectedly ended on %s.\n", + log.file, + show_rfc2822_date(cur.date, cur.tz)); + } } - rec = logdata; - while (rec < logend && *rec != '>' && *rec != '\n') - rec++; - if (rec == logend || *rec == '\n') - die("Log %s is corrupt.", logfile); - date = strtoul(rec + 1, &tz_c, 10); - tz = strtoul(tz_c, NULL, 10); - if (get_sha1_hex(logdata, sha1)) - die("Log %s is corrupt.", logfile); - munmap((void*)logdata, st.st_size); - fprintf(stderr, "warning: Log %s only goes back to %s.\n", - logfile, show_rfc2822_date(date, tz)); + reflog_close(&log); + hashcpy(sha1, sha1_to); return 0; } diff --git a/refs.h b/refs.h index 0d4d79e..9f2667b 100644 --- a/refs.h +++ b/refs.h @@ -10,6 +10,20 @@ struct ref_lock { int force_write; }; +struct reflog { + char *file; + const char *data; + unsigned long size; + const char *rec; +}; + +struct reflog_entry { + unsigned long date; + unsigned tz; + const char *rec; + const struct reflog *log; +}; + /* * Calls the specified function for each ref file until it returns nonzero, * and returns the value @@ -44,4 +58,11 @@ extern int read_ref_at(const char *ref, /** Returns 0 if target has the right format for a ref. **/ extern int check_ref_format(const char *target); +int reflog_open(struct reflog *log, const char *ref); +void reflog_close(struct reflog *log); +void reflog_start(struct reflog *log); +int reflog_next(struct reflog *log, struct reflog_entry *out); +void reflog_entry_from(const struct reflog_entry *e, unsigned char *sha1); +void reflog_entry_to(const struct reflog_entry *e, unsigned char *sha1); + #endif /* REFS_H */ -- 1.4.2.1.g67e7-dirty - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html