2930
return 0;
2931
}
2932
2933
-static char *ref_msg(const char *line, const char *endp)
2934
-{
2935
- const char *ep;
2936
- line += 82;
2937
- ep = memchr(line, '\n', endp - line);
2938
- if (!ep)
2939
- ep = endp;
2940
- return xmemdupz(line, ep - line);
2933
+struct read_ref_at_cb {
2934
+ const char *refname;
2935
+ unsigned long at_time;
2936
+ int cnt;
2937
+ int reccnt;
2938
+ unsigned char *sha1;
2939
+ int found_it;
2940
+
2941
+ unsigned char osha1[20];
2942
+ unsigned char nsha1[20];
2943
+ int tz;
2944
+ unsigned long date;
2945
+ char **msg;
2946
+ unsigned long *cutoff_time;
2947
+ int *cutoff_tz;
2948
+ int *cutoff_cnt;
2949
+};
2950
+
2951
+static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,
2952
+ const char *email, unsigned long timestamp, int tz,
2953
+ const char *message, void *cb_data)
2954
+{
2955
+ struct read_ref_at_cb *cb = cb_data;
2956
+
2957
+ cb->reccnt++;
2958
+ cb->tz = tz;
2959
+ cb->date = timestamp;
2960
+
2961
+ if (timestamp <= cb->at_time || cb->cnt == 0) {
2962
+ if (cb->msg)
2963
+ *cb->msg = xstrdup(message);
2964
+ if (cb->cutoff_time)
2965
+ *cb->cutoff_time = timestamp;
2966
+ if (cb->cutoff_tz)
2967
+ *cb->cutoff_tz = tz;
2968
+ if (cb->cutoff_cnt)
2969
+ *cb->cutoff_cnt = cb->reccnt - 1;
2970
+ /*
2971
+ * we have not yet updated cb->[n|o]sha1 so they still
2972
+ * hold the values for the previous record.
2973
+ */
2974
+ if (!is_null_sha1(cb->osha1)) {
2975
+ hashcpy(cb->sha1, nsha1);
2976
+ if (hashcmp(cb->osha1, nsha1))
2977
+ warning("Log for ref %s has gap after %s.",
2978
+ cb->refname, show_date(cb->date, cb->tz, DATE_RFC2822));
2979
+ }
2980
+ else if (cb->date == cb->at_time)
2981
+ hashcpy(cb->sha1, nsha1);
2982
+ else if (hashcmp(nsha1, cb->sha1))
2983
+ warning("Log for ref %s unexpectedly ended on %s.",
2984
+ cb->refname, show_date(cb->date, cb->tz,
2985
+ DATE_RFC2822));
2986
+ hashcpy(cb->osha1, osha1);
2987
+ hashcpy(cb->nsha1, nsha1);
2988
+ cb->found_it = 1;
2989
+ return 1;
2990
+ }
2991
+ hashcpy(cb->osha1, osha1);
2992
+ hashcpy(cb->nsha1, nsha1);
2993
+ if (cb->cnt > 0)
2994
+ cb->cnt--;
2995
+ return 0;
2996
+}
2997
+
2998
+static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,
2999
+ const char *email, unsigned long timestamp,
3000
+ int tz, const char *message, void *cb_data)
3001
+{
3002
+ struct read_ref_at_cb *cb = cb_data;
3003
+
3004
+ if (cb->msg)
3005
+ *cb->msg = xstrdup(message);
3006
+ if (cb->cutoff_time)
3007
+ *cb->cutoff_time = timestamp;
3008
+ if (cb->cutoff_tz)
3009
+ *cb->cutoff_tz = tz;
3010
+ if (cb->cutoff_cnt)
3011
+ *cb->cutoff_cnt = cb->reccnt;
3012
+ hashcpy(cb->sha1, osha1);
3013
+ if (is_null_sha1(cb->sha1))
3014
+ hashcpy(cb->sha1, nsha1);
3015
+ /* We just want the first entry */
3016
+ return 1;
3017
}
3018
3019
int read_ref_at(const char *refname, unsigned long at_time, int cnt,
3020
unsigned char *sha1, char **msg,
3021
unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
3022
{
2947
- const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;
2948
- char *tz_c;
2949
- int logfd, tz, reccnt = 0;
2950
- struct stat st;
2951
- unsigned long date;
2952
- unsigned char logged_sha1[20];
2953
- void *log_mapped;
2954
- size_t mapsz;
3023
+ struct read_ref_at_cb cb;
3024
2956
- logfile = git_path("logs/%s", refname);
2957
- logfd = open(logfile, O_RDONLY, 0);
2958
- if (logfd < 0)
2959
- die_errno("Unable to read log '%s'", logfile);
2960
- fstat(logfd, &st);
2961
- if (!st.st_size)
2962
- die("Log %s is empty.", logfile);
2963
- mapsz = xsize_t(st.st_size);
2964
- log_mapped = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, logfd, 0);
2965
- logdata = log_mapped;
2966
- close(logfd);
3025
+ memset(&cb, 0, sizeof(cb));
3026
+ cb.refname = refname;
3027
+ cb.at_time = at_time;
3028
+ cb.cnt = cnt;
3029
+ cb.msg = msg;
3030
+ cb.cutoff_time = cutoff_time;
3031
+ cb.cutoff_tz = cutoff_tz;
3032
+ cb.cutoff_cnt = cutoff_cnt;
3033
+ cb.sha1 = sha1;
3034
+
3035
+ for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
3036
+
3037
+ if (!cb.reccnt)
3038
+ die("Log for %s is empty.", refname);
3039
+ if (cb.found_it)
3040
+ return 0;
3041
+
3042
+ for_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb);
3043
2968
- lastrec = NULL;
2969
- rec = logend = logdata + st.st_size;
2970
- while (logdata < rec) {
2971
- reccnt++;
2972
- if (logdata < rec && *(rec-1) == '\n')
2973
- rec--;
2974
- lastgt = NULL;
2975
- while (logdata < rec && *(rec-1) != '\n') {
2976
- rec--;
2977
- if (*rec == '>')
2978
- lastgt = rec;
2979
- }
2980
- if (!lastgt)
2981
- die("Log %s is corrupt.", logfile);
2982
- date = strtoul(lastgt + 1, &tz_c, 10);
2983
- if (date <= at_time || cnt == 0) {
2984
- tz = strtoul(tz_c, NULL, 10);
2985
- if (msg)
2986
- *msg = ref_msg(rec, logend);
2987
- if (cutoff_time)
2988
- *cutoff_time = date;
2989
- if (cutoff_tz)
2990
- *cutoff_tz = tz;
2991
- if (cutoff_cnt)
2992
- *cutoff_cnt = reccnt - 1;
2993
- if (lastrec) {
2994
- if (get_sha1_hex(lastrec, logged_sha1))
2995
- die("Log %s is corrupt.", logfile);
2996
- if (get_sha1_hex(rec + 41, sha1))
2997
- die("Log %s is corrupt.", logfile);
2998
- if (hashcmp(logged_sha1, sha1)) {
2999
- warning("Log %s has gap after %s.",
3000
- logfile, show_date(date, tz, DATE_RFC2822));
3001
- }
3002
- }
3003
- else if (date == at_time) {
3004
- if (get_sha1_hex(rec + 41, sha1))
3005
- die("Log %s is corrupt.", logfile);
3006
- }
3007
- else {
3008
- if (get_sha1_hex(rec + 41, logged_sha1))
3009
- die("Log %s is corrupt.", logfile);
3010
- if (hashcmp(logged_sha1, sha1)) {
3011
- warning("Log %s unexpectedly ended on %s.",
3012
- logfile, show_date(date, tz, DATE_RFC2822));
3013
- }
3014
- }
3015
- munmap(log_mapped, mapsz);
3016
- return 0;
3017
- }
3018
- lastrec = rec;
3019
- if (cnt > 0)
3020
- cnt--;
3021
- }
3022
-
3023
- rec = logdata;
3024
- while (rec < logend && *rec != '>' && *rec != '\n')
3025
- rec++;
3026
- if (rec == logend || *rec == '\n')
3027
- die("Log %s is corrupt.", logfile);
3028
- date = strtoul(rec + 1, &tz_c, 10);
3029
- tz = strtoul(tz_c, NULL, 10);
3030
- if (get_sha1_hex(logdata, sha1))
3031
- die("Log %s is corrupt.", logfile);
3032
- if (is_null_sha1(sha1)) {
3033
- if (get_sha1_hex(logdata + 41, sha1))
3034
- die("Log %s is corrupt.", logfile);
3035
- }
3036
- if (msg)
3037
- *msg = ref_msg(logdata, logend);
3038
- munmap(log_mapped, mapsz);
3039
-
3040
- if (cutoff_time)
3041
- *cutoff_time = date;
3042
- if (cutoff_tz)
3043
- *cutoff_tz = tz;
3044
- if (cutoff_cnt)
3045
- *cutoff_cnt = reccnt;
3044
return 1;
3045
}
3046