@@ -415,6 +415,12 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
415415 return error ;
416416}
417417
418+ struct dir_state {
419+ void * tree ;
420+ unsigned long size ;
421+ unsigned char sha1 [20 ];
422+ };
423+
418424static int find_tree_entry (struct tree_desc * t , const char * name , unsigned char * result , unsigned * mode )
419425{
420426 int namelen = strlen (name );
@@ -478,6 +484,206 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
478484 return retval ;
479485}
480486
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+
481687static int match_entry (const struct pathspec_item * item ,
482688 const struct name_entry * entry , int pathlen ,
483689 const char * match , int matchlen ,
0 commit comments