@@ -2930,119 +2930,117 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
29302930 return 0 ;
29312931}
29322932
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 ;
29413017}
29423018
29433019int read_ref_at (const char * refname , unsigned long at_time , int cnt ,
29443020 unsigned char * sha1 , char * * msg ,
29453021 unsigned long * cutoff_time , int * cutoff_tz , int * cutoff_cnt )
29463022{
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 ;
29553024
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 );
29673043
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 ;
30463044 return 1 ;
30473045}
30483046
0 commit comments