@@ -2292,69 +2292,138 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
22922292 return 1 ;
22932293}
22942294
2295- int for_each_recent_reflog_ent (const char * refname , each_reflog_ent_fn fn , long ofs , void * cb_data )
2295+ static int show_one_reflog_ent (struct strbuf * sb , each_reflog_ent_fn fn , void * cb_data )
2296+ {
2297+ unsigned char osha1 [20 ], nsha1 [20 ];
2298+ char * email_end , * message ;
2299+ unsigned long timestamp ;
2300+ int tz ;
2301+
2302+ /* old SP new SP name <email> SP time TAB msg LF */
2303+ if (sb -> len < 83 || sb -> buf [sb -> len - 1 ] != '\n' ||
2304+ get_sha1_hex (sb -> buf , osha1 ) || sb -> buf [40 ] != ' ' ||
2305+ get_sha1_hex (sb -> buf + 41 , nsha1 ) || sb -> buf [81 ] != ' ' ||
2306+ !(email_end = strchr (sb -> buf + 82 , '>' )) ||
2307+ email_end [1 ] != ' ' ||
2308+ !(timestamp = strtoul (email_end + 2 , & message , 10 )) ||
2309+ !message || message [0 ] != ' ' ||
2310+ (message [1 ] != '+' && message [1 ] != '-' ) ||
2311+ !isdigit (message [2 ]) || !isdigit (message [3 ]) ||
2312+ !isdigit (message [4 ]) || !isdigit (message [5 ]))
2313+ return 0 ; /* corrupt? */
2314+ email_end [1 ] = '\0' ;
2315+ tz = strtol (message + 1 , NULL , 10 );
2316+ if (message [6 ] != '\t' )
2317+ message += 6 ;
2318+ else
2319+ message += 7 ;
2320+ return fn (osha1 , nsha1 , sb -> buf + 82 , timestamp , tz , message , cb_data );
2321+ }
2322+
2323+ static char * find_beginning_of_line (char * bob , char * scan )
2324+ {
2325+ while (bob < scan && * (-- scan ) != '\n' )
2326+ ; /* keep scanning backwards */
2327+ /*
2328+ * Return either beginning of the buffer, or LF at the end of
2329+ * the previous line.
2330+ */
2331+ return scan ;
2332+ }
2333+
2334+ int for_each_reflog_ent_reverse (const char * refname , each_reflog_ent_fn fn , void * cb_data )
22962335{
2297- const char * logfile ;
2298- FILE * logfp ;
22992336 struct strbuf sb = STRBUF_INIT ;
2300- int ret = 0 ;
2337+ FILE * logfp ;
2338+ long pos ;
2339+ int ret = 0 , at_tail = 1 ;
23012340
2302- logfile = git_path ("logs/%s" , refname );
2303- logfp = fopen (logfile , "r" );
2341+ logfp = fopen (git_path ("logs/%s" , refname ), "r" );
23042342 if (!logfp )
23052343 return -1 ;
23062344
2307- if (ofs ) {
2308- struct stat statbuf ;
2309- if (fstat (fileno (logfp ), & statbuf ) ||
2310- statbuf .st_size < ofs ||
2311- fseek (logfp , - ofs , SEEK_END ) ||
2312- strbuf_getwholeline (& sb , logfp , '\n' )) {
2313- fclose (logfp );
2314- strbuf_release (& sb );
2315- return -1 ;
2345+ /* Jump to the end */
2346+ if (fseek (logfp , 0 , SEEK_END ) < 0 )
2347+ return error ("cannot seek back reflog for %s: %s" ,
2348+ refname , strerror (errno ));
2349+ pos = ftell (logfp );
2350+ while (!ret && 0 < pos ) {
2351+ int cnt ;
2352+ size_t nread ;
2353+ char buf [BUFSIZ ];
2354+ char * endp , * scanp ;
2355+
2356+ /* Fill next block from the end */
2357+ cnt = (sizeof (buf ) < pos ) ? sizeof (buf ) : pos ;
2358+ if (fseek (logfp , pos - cnt , SEEK_SET ))
2359+ return error ("cannot seek back reflog for %s: %s" ,
2360+ refname , strerror (errno ));
2361+ nread = fread (buf , cnt , 1 , logfp );
2362+ if (nread < 0 )
2363+ return error ("cannot read %d bytes from reflog for %s: %s" ,
2364+ cnt , refname , strerror (errno ));
2365+ pos -= cnt ;
2366+
2367+ scanp = endp = buf + cnt ;
2368+ if (at_tail && scanp [-1 ] == '\n' )
2369+ /* Looking at the final LF at the end of the file */
2370+ scanp -- ;
2371+ at_tail = 0 ;
2372+
2373+ while (buf < scanp ) {
2374+ /*
2375+ * terminating LF of the previous line, or the beginning
2376+ * of the buffer.
2377+ */
2378+ char * bp ;
2379+
2380+ bp = find_beginning_of_line (buf , scanp );
2381+
2382+ if (* bp != '\n' ) {
2383+ strbuf_splice (& sb , 0 , 0 , buf , endp - buf );
2384+ if (pos )
2385+ break ; /* need to fill another block */
2386+ scanp = buf - 1 ; /* leave loop */
2387+ } else {
2388+ /*
2389+ * (bp + 1) thru endp is the beginning of the
2390+ * current line we have in sb
2391+ */
2392+ strbuf_splice (& sb , 0 , 0 , bp + 1 , endp - (bp + 1 ));
2393+ scanp = bp ;
2394+ endp = bp + 1 ;
2395+ }
2396+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2397+ strbuf_reset (& sb );
2398+ if (ret )
2399+ break ;
23162400 }
2317- }
23182401
2319- while (!strbuf_getwholeline (& sb , logfp , '\n' )) {
2320- unsigned char osha1 [20 ], nsha1 [20 ];
2321- char * email_end , * message ;
2322- unsigned long timestamp ;
2323- int tz ;
2324-
2325- /* old SP new SP name <email> SP time TAB msg LF */
2326- if (sb .len < 83 || sb .buf [sb .len - 1 ] != '\n' ||
2327- get_sha1_hex (sb .buf , osha1 ) || sb .buf [40 ] != ' ' ||
2328- get_sha1_hex (sb .buf + 41 , nsha1 ) || sb .buf [81 ] != ' ' ||
2329- !(email_end = strchr (sb .buf + 82 , '>' )) ||
2330- email_end [1 ] != ' ' ||
2331- !(timestamp = strtoul (email_end + 2 , & message , 10 )) ||
2332- !message || message [0 ] != ' ' ||
2333- (message [1 ] != '+' && message [1 ] != '-' ) ||
2334- !isdigit (message [2 ]) || !isdigit (message [3 ]) ||
2335- !isdigit (message [4 ]) || !isdigit (message [5 ]))
2336- continue ; /* corrupt? */
2337- email_end [1 ] = '\0' ;
2338- tz = strtol (message + 1 , NULL , 10 );
2339- if (message [6 ] != '\t' )
2340- message += 6 ;
2341- else
2342- message += 7 ;
2343- ret = fn (osha1 , nsha1 , sb .buf + 82 , timestamp , tz , message ,
2344- cb_data );
2345- if (ret )
2346- break ;
23472402 }
2403+ if (!ret && sb .len )
2404+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2405+
23482406 fclose (logfp );
23492407 strbuf_release (& sb );
23502408 return ret ;
23512409}
23522410
23532411int for_each_reflog_ent (const char * refname , each_reflog_ent_fn fn , void * cb_data )
23542412{
2355- return for_each_recent_reflog_ent (refname , fn , 0 , cb_data );
2356- }
2413+ FILE * logfp ;
2414+ struct strbuf sb = STRBUF_INIT ;
2415+ int ret = 0 ;
2416+
2417+ logfp = fopen (git_path ("logs/%s" , refname ), "r" );
2418+ if (!logfp )
2419+ return -1 ;
23572420
2421+ while (!ret && !strbuf_getwholeline (& sb , logfp , '\n' ))
2422+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2423+ fclose (logfp );
2424+ strbuf_release (& sb );
2425+ return ret ;
2426+ }
23582427/*
23592428 * Call fn for each reflog in the namespace indicated by name. name
23602429 * must be empty or end with '/'. Name will be used as a scratch
0 commit comments