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