44#include "fetch.h"
55#include "http.h"
66
7+ #ifndef NO_EXPAT
8+ #include <expat.h>
9+
10+ /* Definitions for DAV requests */
11+ #define DAV_PROPFIND "PROPFIND"
12+ #define DAV_PROPFIND_RESP ".multistatus.response"
13+ #define DAV_PROPFIND_NAME ".multistatus.response.href"
14+ #define DAV_PROPFIND_COLLECTION ".multistatus.response.propstat.prop.resourcetype.collection"
15+ #define PROPFIND_ALL_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:allprop/>\n</D:propfind>"
16+
17+ /* Definitions for processing XML DAV responses */
18+ #ifndef XML_STATUS_OK
19+ enum XML_Status {
20+ XML_STATUS_OK = 1 ,
21+ XML_STATUS_ERROR = 0
22+ };
23+ #define XML_STATUS_OK 1
24+ #define XML_STATUS_ERROR 0
25+ #endif
26+
27+ /* Flags that control remote_ls processing */
28+ #define PROCESS_FILES (1u << 0)
29+ #define PROCESS_DIRS (1u << 1)
30+ #define RECURSIVE (1u << 2)
31+
32+ /* Flags that remote_ls passes to callback functions */
33+ #define IS_DIR (1u << 0)
34+ #endif
35+
736#define PREV_BUF_SIZE 4096
837#define RANGE_HEADER_SIZE 30
938
@@ -15,6 +44,7 @@ static struct curl_slist *no_pragma_header;
1544struct alt_base
1645{
1746 char * base ;
47+ int path_len ;
1848 int got_indices ;
1949 struct packed_git * packs ;
2050 struct alt_base * next ;
@@ -58,6 +88,30 @@ struct alternates_request {
5888 int http_specific ;
5989};
6090
91+ #ifndef NO_EXPAT
92+ struct xml_ctx
93+ {
94+ char * name ;
95+ int len ;
96+ char * cdata ;
97+ void (* userFunc )(struct xml_ctx * ctx , int tag_closed );
98+ void * userData ;
99+ };
100+
101+ struct remote_ls_ctx
102+ {
103+ struct alt_base * repo ;
104+ char * path ;
105+ void (* userFunc )(struct remote_ls_ctx * ls );
106+ void * userData ;
107+ int flags ;
108+ char * dentry_name ;
109+ int dentry_flags ;
110+ int rc ;
111+ struct remote_ls_ctx * parent ;
112+ };
113+ #endif
114+
61115static struct object_request * object_queue_head = NULL ;
62116
63117static size_t fwrite_sha1_file (void * ptr , size_t eltsize , size_t nmemb ,
@@ -500,6 +554,7 @@ static void process_alternates_response(void *callback_data)
500554 int serverlen = 0 ;
501555 struct alt_base * newalt ;
502556 char * target = NULL ;
557+ char * path ;
503558 if (data [i ] == '/' ) {
504559 serverlen = strchr (base + 8 , '/' ) - base ;
505560 okay = 1 ;
@@ -540,6 +595,13 @@ static void process_alternates_response(void *callback_data)
540595 newalt -> base = target ;
541596 newalt -> got_indices = 0 ;
542597 newalt -> packs = NULL ;
598+ path = strstr (target , "//" );
599+ if (path ) {
600+ path = index (path + 2 , '/' );
601+ if (path )
602+ newalt -> path_len = strlen (path );
603+ }
604+
543605 while (tail -> next != NULL )
544606 tail = tail -> next ;
545607 tail -> next = newalt ;
@@ -611,6 +673,209 @@ static void fetch_alternates(char *base)
611673 free (url );
612674}
613675
676+ #ifndef NO_EXPAT
677+ static void
678+ xml_start_tag (void * userData , const char * name , const char * * atts )
679+ {
680+ struct xml_ctx * ctx = (struct xml_ctx * )userData ;
681+ const char * c = index (name , ':' );
682+ int new_len ;
683+
684+ if (c == NULL )
685+ c = name ;
686+ else
687+ c ++ ;
688+
689+ new_len = strlen (ctx -> name ) + strlen (c ) + 2 ;
690+
691+ if (new_len > ctx -> len ) {
692+ ctx -> name = xrealloc (ctx -> name , new_len );
693+ ctx -> len = new_len ;
694+ }
695+ strcat (ctx -> name , "." );
696+ strcat (ctx -> name , c );
697+
698+ if (ctx -> cdata ) {
699+ free (ctx -> cdata );
700+ ctx -> cdata = NULL ;
701+ }
702+
703+ ctx -> userFunc (ctx , 0 );
704+ }
705+
706+ static void
707+ xml_end_tag (void * userData , const char * name )
708+ {
709+ struct xml_ctx * ctx = (struct xml_ctx * )userData ;
710+ const char * c = index (name , ':' );
711+ char * ep ;
712+
713+ ctx -> userFunc (ctx , 1 );
714+
715+ if (c == NULL )
716+ c = name ;
717+ else
718+ c ++ ;
719+
720+ ep = ctx -> name + strlen (ctx -> name ) - strlen (c ) - 1 ;
721+ * ep = 0 ;
722+ }
723+
724+ static void
725+ xml_cdata (void * userData , const XML_Char * s , int len )
726+ {
727+ struct xml_ctx * ctx = (struct xml_ctx * )userData ;
728+ if (ctx -> cdata )
729+ free (ctx -> cdata );
730+ ctx -> cdata = xcalloc (len + 1 , 1 );
731+ strncpy (ctx -> cdata , s , len );
732+ }
733+
734+ static int remote_ls (struct alt_base * repo , const char * path , int flags ,
735+ void (* userFunc )(struct remote_ls_ctx * ls ),
736+ void * userData );
737+
738+ static void handle_remote_ls_ctx (struct xml_ctx * ctx , int tag_closed )
739+ {
740+ struct remote_ls_ctx * ls = (struct remote_ls_ctx * )ctx -> userData ;
741+
742+ if (tag_closed ) {
743+ if (!strcmp (ctx -> name , DAV_PROPFIND_RESP ) && ls -> dentry_name ) {
744+ if (ls -> dentry_flags & IS_DIR ) {
745+ if (ls -> flags & PROCESS_DIRS ) {
746+ ls -> userFunc (ls );
747+ }
748+ if (strcmp (ls -> dentry_name , ls -> path ) &&
749+ ls -> flags & RECURSIVE ) {
750+ ls -> rc = remote_ls (ls -> repo ,
751+ ls -> dentry_name ,
752+ ls -> flags ,
753+ ls -> userFunc ,
754+ ls -> userData );
755+ }
756+ } else if (ls -> flags & PROCESS_FILES ) {
757+ ls -> userFunc (ls );
758+ }
759+ } else if (!strcmp (ctx -> name , DAV_PROPFIND_NAME ) && ctx -> cdata ) {
760+ ls -> dentry_name = xmalloc (strlen (ctx -> cdata ) -
761+ ls -> repo -> path_len + 1 );
762+ strcpy (ls -> dentry_name , ctx -> cdata + ls -> repo -> path_len );
763+ } else if (!strcmp (ctx -> name , DAV_PROPFIND_COLLECTION )) {
764+ ls -> dentry_flags |= IS_DIR ;
765+ }
766+ } else if (!strcmp (ctx -> name , DAV_PROPFIND_RESP )) {
767+ if (ls -> dentry_name ) {
768+ free (ls -> dentry_name );
769+ }
770+ ls -> dentry_name = NULL ;
771+ ls -> dentry_flags = 0 ;
772+ }
773+ }
774+
775+ static int remote_ls (struct alt_base * repo , const char * path , int flags ,
776+ void (* userFunc )(struct remote_ls_ctx * ls ),
777+ void * userData )
778+ {
779+ char * url = xmalloc (strlen (repo -> base ) + strlen (path ) + 1 );
780+ struct active_request_slot * slot ;
781+ struct slot_results results ;
782+ struct buffer in_buffer ;
783+ struct buffer out_buffer ;
784+ char * in_data ;
785+ char * out_data ;
786+ XML_Parser parser = XML_ParserCreate (NULL );
787+ enum XML_Status result ;
788+ struct curl_slist * dav_headers = NULL ;
789+ struct xml_ctx ctx ;
790+ struct remote_ls_ctx ls ;
791+
792+ ls .flags = flags ;
793+ ls .repo = repo ;
794+ ls .path = strdup (path );
795+ ls .dentry_name = NULL ;
796+ ls .dentry_flags = 0 ;
797+ ls .userData = userData ;
798+ ls .userFunc = userFunc ;
799+ ls .rc = 0 ;
800+
801+ sprintf (url , "%s%s" , repo -> base , path );
802+
803+ out_buffer .size = strlen (PROPFIND_ALL_REQUEST );
804+ out_data = xmalloc (out_buffer .size + 1 );
805+ snprintf (out_data , out_buffer .size + 1 , PROPFIND_ALL_REQUEST );
806+ out_buffer .posn = 0 ;
807+ out_buffer .buffer = out_data ;
808+
809+ in_buffer .size = 4096 ;
810+ in_data = xmalloc (in_buffer .size );
811+ in_buffer .posn = 0 ;
812+ in_buffer .buffer = in_data ;
813+
814+ dav_headers = curl_slist_append (dav_headers , "Depth: 1" );
815+ dav_headers = curl_slist_append (dav_headers , "Content-Type: text/xml" );
816+
817+ slot = get_active_slot ();
818+ slot -> results = & results ;
819+ curl_easy_setopt (slot -> curl , CURLOPT_INFILE , & out_buffer );
820+ curl_easy_setopt (slot -> curl , CURLOPT_INFILESIZE , out_buffer .size );
821+ curl_easy_setopt (slot -> curl , CURLOPT_READFUNCTION , fread_buffer );
822+ curl_easy_setopt (slot -> curl , CURLOPT_FILE , & in_buffer );
823+ curl_easy_setopt (slot -> curl , CURLOPT_WRITEFUNCTION , fwrite_buffer );
824+ curl_easy_setopt (slot -> curl , CURLOPT_URL , url );
825+ curl_easy_setopt (slot -> curl , CURLOPT_UPLOAD , 1 );
826+ curl_easy_setopt (slot -> curl , CURLOPT_CUSTOMREQUEST , DAV_PROPFIND );
827+ curl_easy_setopt (slot -> curl , CURLOPT_HTTPHEADER , dav_headers );
828+
829+ if (start_active_slot (slot )) {
830+ run_active_slot (slot );
831+ if (results .curl_result == CURLE_OK ) {
832+ ctx .name = xcalloc (10 , 1 );
833+ ctx .len = 0 ;
834+ ctx .cdata = NULL ;
835+ ctx .userFunc = handle_remote_ls_ctx ;
836+ ctx .userData = & ls ;
837+ XML_SetUserData (parser , & ctx );
838+ XML_SetElementHandler (parser , xml_start_tag ,
839+ xml_end_tag );
840+ XML_SetCharacterDataHandler (parser , xml_cdata );
841+ result = XML_Parse (parser , in_buffer .buffer ,
842+ in_buffer .posn , 1 );
843+ free (ctx .name );
844+
845+ if (result != XML_STATUS_OK ) {
846+ ls .rc = error ("XML error: %s" ,
847+ XML_ErrorString (
848+ XML_GetErrorCode (parser )));
849+ }
850+ } else {
851+ ls .rc = -1 ;
852+ }
853+ } else {
854+ ls .rc = error ("Unable to start PROPFIND request" );
855+ }
856+
857+ free (ls .path );
858+ free (url );
859+ free (out_data );
860+ free (in_buffer .buffer );
861+ curl_slist_free_all (dav_headers );
862+
863+ return ls .rc ;
864+ }
865+
866+ static void process_ls_pack (struct remote_ls_ctx * ls )
867+ {
868+ unsigned char sha1 [20 ];
869+
870+ if (strlen (ls -> dentry_name ) == 63 &&
871+ !strncmp (ls -> dentry_name , "objects/pack/pack-" , 18 ) &&
872+ !strncmp (ls -> dentry_name + 58 , ".pack" , 5 )) {
873+ get_sha1_hex (ls -> dentry_name + 18 , sha1 );
874+ setup_index (ls -> repo , sha1 );
875+ }
876+ }
877+ #endif
878+
614879static int fetch_indices (struct alt_base * repo )
615880{
616881 unsigned char sha1 [20 ];
@@ -633,6 +898,12 @@ static int fetch_indices(struct alt_base *repo)
633898 if (get_verbosely )
634899 fprintf (stderr , "Getting pack list for %s\n" , repo -> base );
635900
901+ #ifndef NO_EXPAT
902+ if (remote_ls (repo , "objects/pack/" , PROCESS_FILES ,
903+ process_ls_pack , NULL ) == 0 )
904+ return 0 ;
905+ #endif
906+
636907 url = xmalloc (strlen (repo -> base ) + 21 );
637908 sprintf (url , "%s/objects/info/packs" , repo -> base );
638909
@@ -947,6 +1218,7 @@ int main(int argc, char **argv)
9471218{
9481219 char * commit_id ;
9491220 char * url ;
1221+ char * path ;
9501222 int arg = 1 ;
9511223 int rc = 0 ;
9521224
@@ -987,6 +1259,12 @@ int main(int argc, char **argv)
9871259 alt -> got_indices = 0 ;
9881260 alt -> packs = NULL ;
9891261 alt -> next = NULL ;
1262+ path = strstr (url , "//" );
1263+ if (path ) {
1264+ path = index (path + 2 , '/' );
1265+ if (path )
1266+ alt -> path_len = strlen (path );
1267+ }
9901268
9911269 if (pull (commit_id ))
9921270 rc = 1 ;
0 commit comments