@@ -862,3 +862,314 @@ int transport_helper_init(struct transport *transport, const char *name)
862862 transport -> smart_options = & (data -> transport_options );
863863 return 0 ;
864864}
865+
866+ /*
867+ * Linux pipes can buffer 65536 bytes at once (and most platforms can
868+ * buffer less), so attempt reads and writes with up to that size.
869+ */
870+ #define BUFFERSIZE 65536
871+ /* This should be enough to hold debugging message. */
872+ #define PBUFFERSIZE 8192
873+
874+ /* Print bidirectional transfer loop debug message. */
875+ static void transfer_debug (const char * fmt , ...)
876+ {
877+ va_list args ;
878+ char msgbuf [PBUFFERSIZE ];
879+ static int debug_enabled = -1 ;
880+
881+ if (debug_enabled < 0 )
882+ debug_enabled = getenv ("GIT_TRANSLOOP_DEBUG" ) ? 1 : 0 ;
883+ if (!debug_enabled )
884+ return ;
885+
886+ va_start (args , fmt );
887+ vsnprintf (msgbuf , PBUFFERSIZE , fmt , args );
888+ va_end (args );
889+ fprintf (stderr , "Transfer loop debugging: %s\n" , msgbuf );
890+ }
891+
892+ /* Stream state: More data may be coming in this direction. */
893+ #define SSTATE_TRANSFERING 0
894+ /*
895+ * Stream state: No more data coming in this direction, flushing rest of
896+ * data.
897+ */
898+ #define SSTATE_FLUSHING 1
899+ /* Stream state: Transfer in this direction finished. */
900+ #define SSTATE_FINISHED 2
901+
902+ #define STATE_NEEDS_READING (state ) ((state) <= SSTATE_TRANSFERING)
903+ #define STATE_NEEDS_WRITING (state ) ((state) <= SSTATE_FLUSHING)
904+ #define STATE_NEEDS_CLOSING (state ) ((state) == SSTATE_FLUSHING)
905+
906+ /* Unidirectional transfer. */
907+ struct unidirectional_transfer {
908+ /* Source */
909+ int src ;
910+ /* Destination */
911+ int dest ;
912+ /* Is source socket? */
913+ int src_is_sock ;
914+ /* Is destination socket? */
915+ int dest_is_sock ;
916+ /* Transfer state (TRANSFERING/FLUSHING/FINISHED) */
917+ int state ;
918+ /* Buffer. */
919+ char buf [BUFFERSIZE ];
920+ /* Buffer used. */
921+ size_t bufuse ;
922+ /* Name of source. */
923+ const char * src_name ;
924+ /* Name of destination. */
925+ const char * dest_name ;
926+ };
927+
928+ /* Closes the target (for writing) if transfer has finished. */
929+ static void udt_close_if_finished (struct unidirectional_transfer * t )
930+ {
931+ if (STATE_NEEDS_CLOSING (t -> state ) && !t -> bufuse ) {
932+ t -> state = SSTATE_FINISHED ;
933+ if (t -> dest_is_sock )
934+ shutdown (t -> dest , SHUT_WR );
935+ else
936+ close (t -> dest );
937+ transfer_debug ("Closed %s." , t -> dest_name );
938+ }
939+ }
940+
941+ /*
942+ * Tries to read read data from source into buffer. If buffer is full,
943+ * no data is read. Returns 0 on success, -1 on error.
944+ */
945+ static int udt_do_read (struct unidirectional_transfer * t )
946+ {
947+ ssize_t bytes ;
948+
949+ if (t -> bufuse == BUFFERSIZE )
950+ return 0 ; /* No space for more. */
951+
952+ transfer_debug ("%s is readable" , t -> src_name );
953+ bytes = read (t -> src , t -> buf + t -> bufuse , BUFFERSIZE - t -> bufuse );
954+ if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
955+ errno != EINTR ) {
956+ error ("read(%s) failed: %s" , t -> src_name , strerror (errno ));
957+ return -1 ;
958+ } else if (bytes == 0 ) {
959+ transfer_debug ("%s EOF (with %i bytes in buffer)" ,
960+ t -> src_name , t -> bufuse );
961+ t -> state = SSTATE_FLUSHING ;
962+ } else if (bytes > 0 ) {
963+ t -> bufuse += bytes ;
964+ transfer_debug ("Read %i bytes from %s (buffer now at %i)" ,
965+ (int )bytes , t -> src_name , (int )t -> bufuse );
966+ }
967+ return 0 ;
968+ }
969+
970+ /* Tries to write data from buffer into destination. If buffer is empty,
971+ * no data is written. Returns 0 on success, -1 on error.
972+ */
973+ static int udt_do_write (struct unidirectional_transfer * t )
974+ {
975+ size_t bytes ;
976+
977+ if (t -> bufuse == 0 )
978+ return 0 ; /* Nothing to write. */
979+
980+ transfer_debug ("%s is writable" , t -> dest_name );
981+ bytes = write (t -> dest , t -> buf , t -> bufuse );
982+ if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
983+ errno != EINTR ) {
984+ error ("write(%s) failed: %s" , t -> dest_name , strerror (errno ));
985+ return -1 ;
986+ } else if (bytes > 0 ) {
987+ t -> bufuse -= bytes ;
988+ if (t -> bufuse )
989+ memmove (t -> buf , t -> buf + bytes , t -> bufuse );
990+ transfer_debug ("Wrote %i bytes to %s (buffer now at %i)" ,
991+ (int )bytes , t -> dest_name , (int )t -> bufuse );
992+ }
993+ return 0 ;
994+ }
995+
996+
997+ /* State of bidirectional transfer loop. */
998+ struct bidirectional_transfer_state {
999+ /* Direction from program to git. */
1000+ struct unidirectional_transfer ptg ;
1001+ /* Direction from git to program. */
1002+ struct unidirectional_transfer gtp ;
1003+ };
1004+
1005+ static void * udt_copy_task_routine (void * udt )
1006+ {
1007+ struct unidirectional_transfer * t = (struct unidirectional_transfer * )udt ;
1008+ while (t -> state != SSTATE_FINISHED ) {
1009+ if (STATE_NEEDS_READING (t -> state ))
1010+ if (udt_do_read (t ))
1011+ return NULL ;
1012+ if (STATE_NEEDS_WRITING (t -> state ))
1013+ if (udt_do_write (t ))
1014+ return NULL ;
1015+ if (STATE_NEEDS_CLOSING (t -> state ))
1016+ udt_close_if_finished (t );
1017+ }
1018+ return udt ; /* Just some non-NULL value. */
1019+ }
1020+
1021+ #ifndef NO_PTHREADS
1022+
1023+ /*
1024+ * Join thread, with apporiate errors on failure. Name is name for the
1025+ * thread (for error messages). Returns 0 on success, 1 on failure.
1026+ */
1027+ static int tloop_join (pthread_t thread , const char * name )
1028+ {
1029+ int err ;
1030+ void * tret ;
1031+ err = pthread_join (thread , & tret );
1032+ if (!tret ) {
1033+ error ("%s thread failed" , name );
1034+ return 1 ;
1035+ }
1036+ if (err ) {
1037+ error ("%s thread failed to join: %s" , name , strerror (err ));
1038+ return 1 ;
1039+ }
1040+ return 0 ;
1041+ }
1042+
1043+ /*
1044+ * Spawn the transfer tasks and then wait for them. Returns 0 on success,
1045+ * -1 on failure.
1046+ */
1047+ static int tloop_spawnwait_tasks (struct bidirectional_transfer_state * s )
1048+ {
1049+ pthread_t gtp_thread ;
1050+ pthread_t ptg_thread ;
1051+ int err ;
1052+ int ret = 0 ;
1053+ err = pthread_create (& gtp_thread , NULL , udt_copy_task_routine ,
1054+ & s -> gtp );
1055+ if (err )
1056+ die ("Can't start thread for copying data: %s" , strerror (err ));
1057+ err = pthread_create (& ptg_thread , NULL , udt_copy_task_routine ,
1058+ & s -> ptg );
1059+ if (err )
1060+ die ("Can't start thread for copying data: %s" , strerror (err ));
1061+
1062+ ret |= tloop_join (gtp_thread , "Git to program copy" );
1063+ ret |= tloop_join (ptg_thread , "Program to git copy" );
1064+ return ret ;
1065+ }
1066+ #else
1067+
1068+ /* Close the source and target (for writing) for transfer. */
1069+ static void udt_kill_transfer (struct unidirectional_transfer * t )
1070+ {
1071+ t -> state = SSTATE_FINISHED ;
1072+ /*
1073+ * Socket read end left open isn't a disaster if nobody
1074+ * attempts to read from it (mingw compat headers do not
1075+ * have SHUT_RD)...
1076+ *
1077+ * We can't fully close the socket since otherwise gtp
1078+ * task would first close the socket it sends data to
1079+ * while closing the ptg file descriptors.
1080+ */
1081+ if (!t -> src_is_sock )
1082+ close (t -> src );
1083+ if (t -> dest_is_sock )
1084+ shutdown (t -> dest , SHUT_WR );
1085+ else
1086+ close (t -> dest );
1087+ }
1088+
1089+ /*
1090+ * Join process, with apporiate errors on failure. Name is name for the
1091+ * process (for error messages). Returns 0 on success, 1 on failure.
1092+ */
1093+ static int tloop_join (pid_t pid , const char * name )
1094+ {
1095+ int tret ;
1096+ if (waitpid (pid , & tret , 0 ) < 0 ) {
1097+ error ("%s process failed to wait: %s" , name , strerror (errno ));
1098+ return 1 ;
1099+ }
1100+ if (!WIFEXITED (tret ) || WEXITSTATUS (tret )) {
1101+ error ("%s process failed" , name );
1102+ return 1 ;
1103+ }
1104+ return 0 ;
1105+ }
1106+
1107+ /*
1108+ * Spawn the transfer tasks and then wait for them. Returns 0 on success,
1109+ * -1 on failure.
1110+ */
1111+ static int tloop_spawnwait_tasks (struct bidirectional_transfer_state * s )
1112+ {
1113+ pid_t pid1 , pid2 ;
1114+ int ret = 0 ;
1115+
1116+ /* Fork thread #1: git to program. */
1117+ pid1 = fork ();
1118+ if (pid1 < 0 )
1119+ die_errno ("Can't start thread for copying data" );
1120+ else if (pid1 == 0 ) {
1121+ udt_kill_transfer (& s -> ptg );
1122+ exit (udt_copy_task_routine (& s -> gtp ) ? 0 : 1 );
1123+ }
1124+
1125+ /* Fork thread #2: program to git. */
1126+ pid2 = fork ();
1127+ if (pid2 < 0 )
1128+ die_errno ("Can't start thread for copying data" );
1129+ else if (pid2 == 0 ) {
1130+ udt_kill_transfer (& s -> gtp );
1131+ exit (udt_copy_task_routine (& s -> ptg ) ? 0 : 1 );
1132+ }
1133+
1134+ /*
1135+ * Close both streams in parent as to not interfere with
1136+ * end of file detection and wait for both tasks to finish.
1137+ */
1138+ udt_kill_transfer (& s -> gtp );
1139+ udt_kill_transfer (& s -> ptg );
1140+ ret |= tloop_join (pid1 , "Git to program copy" );
1141+ ret |= tloop_join (pid2 , "Program to git copy" );
1142+ return ret ;
1143+ }
1144+ #endif
1145+
1146+ /*
1147+ * Copies data from stdin to output and from input to stdout simultaneously.
1148+ * Additionally filtering through given filter. If filter is NULL, uses
1149+ * identity filter.
1150+ */
1151+ int bidirectional_transfer_loop (int input , int output )
1152+ {
1153+ struct bidirectional_transfer_state state ;
1154+
1155+ /* Fill the state fields. */
1156+ state .ptg .src = input ;
1157+ state .ptg .dest = 1 ;
1158+ state .ptg .src_is_sock = (input == output );
1159+ state .ptg .dest_is_sock = 0 ;
1160+ state .ptg .state = SSTATE_TRANSFERING ;
1161+ state .ptg .bufuse = 0 ;
1162+ state .ptg .src_name = "remote input" ;
1163+ state .ptg .dest_name = "stdout" ;
1164+
1165+ state .gtp .src = 0 ;
1166+ state .gtp .dest = output ;
1167+ state .gtp .src_is_sock = 0 ;
1168+ state .gtp .dest_is_sock = (input == output );
1169+ state .gtp .state = SSTATE_TRANSFERING ;
1170+ state .gtp .bufuse = 0 ;
1171+ state .gtp .src_name = "stdin" ;
1172+ state .gtp .dest_name = "remote output" ;
1173+
1174+ return tloop_spawnwait_tasks (& state );
1175+ }
0 commit comments