@@ -2332,69 +2332,138 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
2332
2332
return 1 ;
2333
2333
}
2334
2334
2335
- int for_each_recent_reflog_ent (const char * refname , each_reflog_ent_fn fn , long ofs , void * cb_data )
2335
+ static int show_one_reflog_ent (struct strbuf * sb , each_reflog_ent_fn fn , void * cb_data )
2336
+ {
2337
+ unsigned char osha1 [20 ], nsha1 [20 ];
2338
+ char * email_end , * message ;
2339
+ unsigned long timestamp ;
2340
+ int tz ;
2341
+
2342
+ /* old SP new SP name <email> SP time TAB msg LF */
2343
+ if (sb -> len < 83 || sb -> buf [sb -> len - 1 ] != '\n' ||
2344
+ get_sha1_hex (sb -> buf , osha1 ) || sb -> buf [40 ] != ' ' ||
2345
+ get_sha1_hex (sb -> buf + 41 , nsha1 ) || sb -> buf [81 ] != ' ' ||
2346
+ !(email_end = strchr (sb -> buf + 82 , '>' )) ||
2347
+ email_end [1 ] != ' ' ||
2348
+ !(timestamp = strtoul (email_end + 2 , & message , 10 )) ||
2349
+ !message || message [0 ] != ' ' ||
2350
+ (message [1 ] != '+' && message [1 ] != '-' ) ||
2351
+ !isdigit (message [2 ]) || !isdigit (message [3 ]) ||
2352
+ !isdigit (message [4 ]) || !isdigit (message [5 ]))
2353
+ return 0 ; /* corrupt? */
2354
+ email_end [1 ] = '\0' ;
2355
+ tz = strtol (message + 1 , NULL , 10 );
2356
+ if (message [6 ] != '\t' )
2357
+ message += 6 ;
2358
+ else
2359
+ message += 7 ;
2360
+ return fn (osha1 , nsha1 , sb -> buf + 82 , timestamp , tz , message , cb_data );
2361
+ }
2362
+
2363
+ static char * find_beginning_of_line (char * bob , char * scan )
2364
+ {
2365
+ while (bob < scan && * (-- scan ) != '\n' )
2366
+ ; /* keep scanning backwards */
2367
+ /*
2368
+ * Return either beginning of the buffer, or LF at the end of
2369
+ * the previous line.
2370
+ */
2371
+ return scan ;
2372
+ }
2373
+
2374
+ int for_each_reflog_ent_reverse (const char * refname , each_reflog_ent_fn fn , void * cb_data )
2336
2375
{
2337
- const char * logfile ;
2338
- FILE * logfp ;
2339
2376
struct strbuf sb = STRBUF_INIT ;
2340
- int ret = 0 ;
2377
+ FILE * logfp ;
2378
+ long pos ;
2379
+ int ret = 0 , at_tail = 1 ;
2341
2380
2342
- logfile = git_path ("logs/%s" , refname );
2343
- logfp = fopen (logfile , "r" );
2381
+ logfp = fopen (git_path ("logs/%s" , refname ), "r" );
2344
2382
if (!logfp )
2345
2383
return -1 ;
2346
2384
2347
- if (ofs ) {
2348
- struct stat statbuf ;
2349
- if (fstat (fileno (logfp ), & statbuf ) ||
2350
- statbuf .st_size < ofs ||
2351
- fseek (logfp , - ofs , SEEK_END ) ||
2352
- strbuf_getwholeline (& sb , logfp , '\n' )) {
2353
- fclose (logfp );
2354
- strbuf_release (& sb );
2355
- return -1 ;
2385
+ /* Jump to the end */
2386
+ if (fseek (logfp , 0 , SEEK_END ) < 0 )
2387
+ return error ("cannot seek back reflog for %s: %s" ,
2388
+ refname , strerror (errno ));
2389
+ pos = ftell (logfp );
2390
+ while (!ret && 0 < pos ) {
2391
+ int cnt ;
2392
+ size_t nread ;
2393
+ char buf [BUFSIZ ];
2394
+ char * endp , * scanp ;
2395
+
2396
+ /* Fill next block from the end */
2397
+ cnt = (sizeof (buf ) < pos ) ? sizeof (buf ) : pos ;
2398
+ if (fseek (logfp , pos - cnt , SEEK_SET ))
2399
+ return error ("cannot seek back reflog for %s: %s" ,
2400
+ refname , strerror (errno ));
2401
+ nread = fread (buf , cnt , 1 , logfp );
2402
+ if (nread != 1 )
2403
+ return error ("cannot read %d bytes from reflog for %s: %s" ,
2404
+ cnt , refname , strerror (errno ));
2405
+ pos -= cnt ;
2406
+
2407
+ scanp = endp = buf + cnt ;
2408
+ if (at_tail && scanp [-1 ] == '\n' )
2409
+ /* Looking at the final LF at the end of the file */
2410
+ scanp -- ;
2411
+ at_tail = 0 ;
2412
+
2413
+ while (buf < scanp ) {
2414
+ /*
2415
+ * terminating LF of the previous line, or the beginning
2416
+ * of the buffer.
2417
+ */
2418
+ char * bp ;
2419
+
2420
+ bp = find_beginning_of_line (buf , scanp );
2421
+
2422
+ if (* bp != '\n' ) {
2423
+ strbuf_splice (& sb , 0 , 0 , buf , endp - buf );
2424
+ if (pos )
2425
+ break ; /* need to fill another block */
2426
+ scanp = buf - 1 ; /* leave loop */
2427
+ } else {
2428
+ /*
2429
+ * (bp + 1) thru endp is the beginning of the
2430
+ * current line we have in sb
2431
+ */
2432
+ strbuf_splice (& sb , 0 , 0 , bp + 1 , endp - (bp + 1 ));
2433
+ scanp = bp ;
2434
+ endp = bp + 1 ;
2435
+ }
2436
+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2437
+ strbuf_reset (& sb );
2438
+ if (ret )
2439
+ break ;
2356
2440
}
2357
- }
2358
2441
2359
- while (!strbuf_getwholeline (& sb , logfp , '\n' )) {
2360
- unsigned char osha1 [20 ], nsha1 [20 ];
2361
- char * email_end , * message ;
2362
- unsigned long timestamp ;
2363
- int tz ;
2364
-
2365
- /* old SP new SP name <email> SP time TAB msg LF */
2366
- if (sb .len < 83 || sb .buf [sb .len - 1 ] != '\n' ||
2367
- get_sha1_hex (sb .buf , osha1 ) || sb .buf [40 ] != ' ' ||
2368
- get_sha1_hex (sb .buf + 41 , nsha1 ) || sb .buf [81 ] != ' ' ||
2369
- !(email_end = strchr (sb .buf + 82 , '>' )) ||
2370
- email_end [1 ] != ' ' ||
2371
- !(timestamp = strtoul (email_end + 2 , & message , 10 )) ||
2372
- !message || message [0 ] != ' ' ||
2373
- (message [1 ] != '+' && message [1 ] != '-' ) ||
2374
- !isdigit (message [2 ]) || !isdigit (message [3 ]) ||
2375
- !isdigit (message [4 ]) || !isdigit (message [5 ]))
2376
- continue ; /* corrupt? */
2377
- email_end [1 ] = '\0' ;
2378
- tz = strtol (message + 1 , NULL , 10 );
2379
- if (message [6 ] != '\t' )
2380
- message += 6 ;
2381
- else
2382
- message += 7 ;
2383
- ret = fn (osha1 , nsha1 , sb .buf + 82 , timestamp , tz , message ,
2384
- cb_data );
2385
- if (ret )
2386
- break ;
2387
2442
}
2443
+ if (!ret && sb .len )
2444
+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2445
+
2388
2446
fclose (logfp );
2389
2447
strbuf_release (& sb );
2390
2448
return ret ;
2391
2449
}
2392
2450
2393
2451
int for_each_reflog_ent (const char * refname , each_reflog_ent_fn fn , void * cb_data )
2394
2452
{
2395
- return for_each_recent_reflog_ent (refname , fn , 0 , cb_data );
2396
- }
2453
+ FILE * logfp ;
2454
+ struct strbuf sb = STRBUF_INIT ;
2455
+ int ret = 0 ;
2456
+
2457
+ logfp = fopen (git_path ("logs/%s" , refname ), "r" );
2458
+ if (!logfp )
2459
+ return -1 ;
2397
2460
2461
+ while (!ret && !strbuf_getwholeline (& sb , logfp , '\n' ))
2462
+ ret = show_one_reflog_ent (& sb , fn , cb_data );
2463
+ fclose (logfp );
2464
+ strbuf_release (& sb );
2465
+ return ret ;
2466
+ }
2398
2467
/*
2399
2468
* Call fn for each reflog in the namespace indicated by name. name
2400
2469
* must be empty or end with '/'. Name will be used as a scratch
0 commit comments