@@ -415,6 +415,12 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
415
415
return error ;
416
416
}
417
417
418
+ struct dir_state {
419
+ void * tree ;
420
+ unsigned long size ;
421
+ unsigned char sha1 [20 ];
422
+ };
423
+
418
424
static int find_tree_entry (struct tree_desc * t , const char * name , unsigned char * result , unsigned * mode )
419
425
{
420
426
int namelen = strlen (name );
@@ -478,6 +484,206 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
478
484
return retval ;
479
485
}
480
486
487
+ /*
488
+ * This is Linux's built-in max for the number of symlinks to follow.
489
+ * That limit, of course, does not affect git, but it's a reasonable
490
+ * choice.
491
+ */
492
+ #define GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS 40
493
+
494
+ /**
495
+ * Find a tree entry by following symlinks in tree_sha (which is
496
+ * assumed to be the root of the repository). In the event that a
497
+ * symlink points outside the repository (e.g. a link to /foo or a
498
+ * root-level link to ../foo), the portion of the link which is
499
+ * outside the repository will be returned in result_path, and *mode
500
+ * will be set to 0. It is assumed that result_path is uninitialized.
501
+ * If there are no symlinks, or the end result of the symlink chain
502
+ * points to an object inside the repository, result will be filled in
503
+ * with the sha1 of the found object, and *mode will hold the mode of
504
+ * the object.
505
+ *
506
+ * See the code for enum follow_symlink_result for a description of
507
+ * the return values.
508
+ */
509
+ enum follow_symlinks_result get_tree_entry_follow_symlinks (unsigned char * tree_sha1 , const char * name , unsigned char * result , struct strbuf * result_path , unsigned * mode )
510
+ {
511
+ int retval = MISSING_OBJECT ;
512
+ struct dir_state * parents = NULL ;
513
+ size_t parents_alloc = 0 ;
514
+ ssize_t parents_nr = 0 ;
515
+ unsigned char current_tree_sha1 [20 ];
516
+ struct strbuf namebuf = STRBUF_INIT ;
517
+ struct tree_desc t ;
518
+ int follows_remaining = GET_TREE_ENTRY_FOLLOW_SYMLINKS_MAX_LINKS ;
519
+ int i ;
520
+
521
+ init_tree_desc (& t , NULL , 0UL );
522
+ strbuf_init (result_path , 0 );
523
+ strbuf_addstr (& namebuf , name );
524
+ hashcpy (current_tree_sha1 , tree_sha1 );
525
+
526
+ while (1 ) {
527
+ int find_result ;
528
+ char * first_slash ;
529
+ char * remainder = NULL ;
530
+
531
+ if (!t .buffer ) {
532
+ void * tree ;
533
+ unsigned char root [20 ];
534
+ unsigned long size ;
535
+ tree = read_object_with_reference (current_tree_sha1 ,
536
+ tree_type , & size ,
537
+ root );
538
+ if (!tree )
539
+ goto done ;
540
+
541
+ ALLOC_GROW (parents , parents_nr + 1 , parents_alloc );
542
+ parents [parents_nr ].tree = tree ;
543
+ parents [parents_nr ].size = size ;
544
+ hashcpy (parents [parents_nr ].sha1 , root );
545
+ parents_nr ++ ;
546
+
547
+ if (namebuf .buf [0 ] == '\0' ) {
548
+ hashcpy (result , root );
549
+ retval = FOUND ;
550
+ goto done ;
551
+ }
552
+
553
+ if (!size )
554
+ goto done ;
555
+
556
+ /* descend */
557
+ init_tree_desc (& t , tree , size );
558
+ }
559
+
560
+ /* Handle symlinks to e.g. a//b by removing leading slashes */
561
+ while (namebuf .buf [0 ] == '/' ) {
562
+ strbuf_remove (& namebuf , 0 , 1 );
563
+ }
564
+
565
+ /* Split namebuf into a first component and a remainder */
566
+ if ((first_slash = strchr (namebuf .buf , '/' ))) {
567
+ * first_slash = 0 ;
568
+ remainder = first_slash + 1 ;
569
+ }
570
+
571
+ if (!strcmp (namebuf .buf , ".." )) {
572
+ struct dir_state * parent ;
573
+ /*
574
+ * We could end up with .. in the namebuf if it
575
+ * appears in a symlink.
576
+ */
577
+
578
+ if (parents_nr == 1 ) {
579
+ if (remainder )
580
+ * first_slash = '/' ;
581
+ strbuf_add (result_path , namebuf .buf ,
582
+ namebuf .len );
583
+ * mode = 0 ;
584
+ retval = FOUND ;
585
+ goto done ;
586
+ }
587
+ parent = & parents [parents_nr - 1 ];
588
+ free (parent -> tree );
589
+ parents_nr -- ;
590
+ parent = & parents [parents_nr - 1 ];
591
+ init_tree_desc (& t , parent -> tree , parent -> size );
592
+ strbuf_remove (& namebuf , 0 , remainder ? 3 : 2 );
593
+ continue ;
594
+ }
595
+
596
+ /* We could end up here via a symlink to dir/.. */
597
+ if (namebuf .buf [0 ] == '\0' ) {
598
+ hashcpy (result , parents [parents_nr - 1 ].sha1 );
599
+ retval = FOUND ;
600
+ goto done ;
601
+ }
602
+
603
+ /* Look up the first (or only) path component in the tree. */
604
+ find_result = find_tree_entry (& t , namebuf .buf ,
605
+ current_tree_sha1 , mode );
606
+ if (find_result ) {
607
+ goto done ;
608
+ }
609
+
610
+ if (S_ISDIR (* mode )) {
611
+ if (!remainder ) {
612
+ hashcpy (result , current_tree_sha1 );
613
+ retval = FOUND ;
614
+ goto done ;
615
+ }
616
+ /* Descend the tree */
617
+ t .buffer = NULL ;
618
+ strbuf_remove (& namebuf , 0 ,
619
+ 1 + first_slash - namebuf .buf );
620
+ } else if (S_ISREG (* mode )) {
621
+ if (!remainder ) {
622
+ hashcpy (result , current_tree_sha1 );
623
+ retval = FOUND ;
624
+ } else {
625
+ retval = NOT_DIR ;
626
+ }
627
+ goto done ;
628
+ } else if (S_ISLNK (* mode )) {
629
+ /* Follow a symlink */
630
+ unsigned long link_len ;
631
+ size_t len ;
632
+ char * contents , * contents_start ;
633
+ struct dir_state * parent ;
634
+ enum object_type type ;
635
+
636
+ if (follows_remaining -- == 0 ) {
637
+ /* Too many symlinks followed */
638
+ retval = SYMLINK_LOOP ;
639
+ goto done ;
640
+ }
641
+
642
+ /*
643
+ * At this point, we have followed at a least
644
+ * one symlink, so on error we need to report this.
645
+ */
646
+ retval = DANGLING_SYMLINK ;
647
+
648
+ contents = read_sha1_file (current_tree_sha1 , & type ,
649
+ & link_len );
650
+
651
+ if (!contents )
652
+ goto done ;
653
+
654
+ if (contents [0 ] == '/' ) {
655
+ strbuf_addstr (result_path , contents );
656
+ free (contents );
657
+ * mode = 0 ;
658
+ retval = FOUND ;
659
+ goto done ;
660
+ }
661
+
662
+ if (remainder )
663
+ len = first_slash - namebuf .buf ;
664
+ else
665
+ len = namebuf .len ;
666
+
667
+ contents_start = contents ;
668
+
669
+ parent = & parents [parents_nr - 1 ];
670
+ init_tree_desc (& t , parent -> tree , parent -> size );
671
+ strbuf_splice (& namebuf , 0 , len ,
672
+ contents_start , link_len );
673
+ if (remainder )
674
+ namebuf .buf [link_len ] = '/' ;
675
+ free (contents );
676
+ }
677
+ }
678
+ done :
679
+ for (i = 0 ; i < parents_nr ; i ++ )
680
+ free (parents [i ].tree );
681
+ free (parents );
682
+
683
+ strbuf_release (& namebuf );
684
+ return retval ;
685
+ }
686
+
481
687
static int match_entry (const struct pathspec_item * item ,
482
688
const struct name_entry * entry , int pathlen ,
483
689
const char * match , int matchlen ,
0 commit comments