@@ -2292,69 +2292,138 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
2292
2292
return 1 ;
2293
2293
}
2294
2294
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 )
2296
2335
{
2297
- const char * logfile ;
2298
- FILE * logfp ;
2299
2336
struct strbuf sb = STRBUF_INIT ;
2300
- int ret = 0 ;
2337
+ FILE * logfp ;
2338
+ long pos ;
2339
+ int ret = 0 , at_tail = 1 ;
2301
2340
2302
- logfile = git_path ("logs/%s" , refname );
2303
- logfp = fopen (logfile , "r" );
2341
+ logfp = fopen (git_path ("logs/%s" , refname ), "r" );
2304
2342
if (!logfp )
2305
2343
return -1 ;
2306
2344
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 ;
2316
2400
}
2317
- }
2318
2401
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 ;
2347
2402
}
2403
+ if (!ret && sb .len )
2404
+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2405
+
2348
2406
fclose (logfp );
2349
2407
strbuf_release (& sb );
2350
2408
return ret ;
2351
2409
}
2352
2410
2353
2411
int for_each_reflog_ent (const char * refname , each_reflog_ent_fn fn , void * cb_data )
2354
2412
{
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 ;
2357
2420
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
+ }
2358
2427
/*
2359
2428
* Call fn for each reflog in the namespace indicated by name. name
2360
2429
* must be empty or end with '/'. Name will be used as a scratch
0 commit comments