44#include "quote.h"
55#include "sigchain.h"
66#include "pkt-line.h"
7+ #include "sub-process.h"
78
89/*
910 * convert.c - convert a file when checking it out and checking it in.
@@ -497,126 +498,26 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
497498#define CAP_SMUDGE (1u<<1)
498499
499500struct cmd2process {
500- struct hashmap_entry ent ; /* must be the first member! */
501+ struct subprocess_entry subprocess ; /* must be the first member! */
501502 unsigned int supported_capabilities ;
502- const char * cmd ;
503- struct child_process process ;
504503};
505504
506- static int cmd_process_map_initialized ;
507- static struct hashmap cmd_process_map ;
508-
509- static int cmd2process_cmp (const struct cmd2process * e1 ,
510- const struct cmd2process * e2 ,
511- const void * unused )
512- {
513- return strcmp (e1 -> cmd , e2 -> cmd );
514- }
515-
516- static struct cmd2process * find_multi_file_filter_entry (struct hashmap * hashmap , const char * cmd )
517- {
518- struct cmd2process key ;
519- hashmap_entry_init (& key , strhash (cmd ));
520- key .cmd = cmd ;
521- return hashmap_get (hashmap , & key , NULL );
522- }
505+ static int subprocess_map_initialized ;
506+ static struct hashmap subprocess_map ;
523507
524- static int packet_write_list ( int fd , const char * line , ... )
508+ static int start_multi_file_filter_fn ( struct subprocess_entry * subprocess )
525509{
526- va_list args ;
527510 int err ;
528- va_start (args , line );
529- for (;;) {
530- if (!line )
531- break ;
532- if (strlen (line ) > LARGE_PACKET_DATA_MAX )
533- return -1 ;
534- err = packet_write_fmt_gently (fd , "%s\n" , line );
535- if (err )
536- return err ;
537- line = va_arg (args , const char * );
538- }
539- va_end (args );
540- return packet_flush_gently (fd );
541- }
542-
543- static void read_multi_file_filter_status (int fd , struct strbuf * status )
544- {
545- struct strbuf * * pair ;
546- char * line ;
547- for (;;) {
548- line = packet_read_line (fd , NULL );
549- if (!line )
550- break ;
551- pair = strbuf_split_str (line , '=' , 2 );
552- if (pair [0 ] && pair [0 ]-> len && pair [1 ]) {
553- /* the last "status=<foo>" line wins */
554- if (!strcmp (pair [0 ]-> buf , "status=" )) {
555- strbuf_reset (status );
556- strbuf_addbuf (status , pair [1 ]);
557- }
558- }
559- strbuf_list_free (pair );
560- }
561- }
562-
563- static void kill_multi_file_filter (struct hashmap * hashmap , struct cmd2process * entry )
564- {
565- if (!entry )
566- return ;
567-
568- entry -> process .clean_on_exit = 0 ;
569- kill (entry -> process .pid , SIGTERM );
570- finish_command (& entry -> process );
571-
572- hashmap_remove (hashmap , entry , NULL );
573- free (entry );
574- }
575-
576- static void stop_multi_file_filter (struct child_process * process )
577- {
578- sigchain_push (SIGPIPE , SIG_IGN );
579- /* Closing the pipe signals the filter to initiate a shutdown. */
580- close (process -> in );
581- close (process -> out );
582- sigchain_pop (SIGPIPE );
583- /* Finish command will wait until the shutdown is complete. */
584- finish_command (process );
585- }
586-
587- static struct cmd2process * start_multi_file_filter (struct hashmap * hashmap , const char * cmd )
588- {
589- int err ;
590- struct cmd2process * entry ;
591- struct child_process * process ;
592- const char * argv [] = { cmd , NULL };
511+ struct cmd2process * entry = (struct cmd2process * )subprocess ;
593512 struct string_list cap_list = STRING_LIST_INIT_NODUP ;
594513 char * cap_buf ;
595514 const char * cap_name ;
596-
597- entry = xmalloc (sizeof (* entry ));
598- entry -> cmd = cmd ;
599- entry -> supported_capabilities = 0 ;
600- process = & entry -> process ;
601-
602- child_process_init (process );
603- process -> argv = argv ;
604- process -> use_shell = 1 ;
605- process -> in = -1 ;
606- process -> out = -1 ;
607- process -> clean_on_exit = 1 ;
608- process -> clean_on_exit_handler = stop_multi_file_filter ;
609-
610- if (start_command (process )) {
611- error ("cannot fork to run external filter '%s'" , cmd );
612- return NULL ;
613- }
614-
615- hashmap_entry_init (entry , strhash (cmd ));
515+ struct child_process * process = & subprocess -> process ;
516+ const char * cmd = subprocess -> cmd ;
616517
617518 sigchain_push (SIGPIPE , SIG_IGN );
618519
619- err = packet_write_list (process -> in , "git-filter-client" , "version=2" , NULL );
520+ err = packet_writel (process -> in , "git-filter-client" , "version=2" , NULL );
620521 if (err )
621522 goto done ;
622523
@@ -632,7 +533,7 @@ static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, cons
632533 if (err )
633534 goto done ;
634535
635- err = packet_write_list (process -> in , "capability=clean" , "capability=smudge" , NULL );
536+ err = packet_writel (process -> in , "capability=clean" , "capability=smudge" , NULL );
636537
637538 for (;;) {
638539 cap_buf = packet_read_line (process -> out , NULL );
@@ -661,14 +562,7 @@ static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, cons
661562done :
662563 sigchain_pop (SIGPIPE );
663564
664- if (err || errno == EPIPE ) {
665- error ("initialization for external filter '%s' failed" , cmd );
666- kill_multi_file_filter (hashmap , entry );
667- return NULL ;
668- }
669-
670- hashmap_add (hashmap , entry );
671- return entry ;
565+ return err ;
672566}
673567
674568static int apply_multi_file_filter (const char * path , const char * src , size_t len ,
@@ -682,22 +576,26 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
682576 struct strbuf filter_status = STRBUF_INIT ;
683577 const char * filter_type ;
684578
685- if (!cmd_process_map_initialized ) {
686- cmd_process_map_initialized = 1 ;
687- hashmap_init (& cmd_process_map , (hashmap_cmp_fn ) cmd2process_cmp , 0 );
579+ if (!subprocess_map_initialized ) {
580+ subprocess_map_initialized = 1 ;
581+ hashmap_init (& subprocess_map , (hashmap_cmp_fn ) cmd2process_cmp , 0 );
688582 entry = NULL ;
689583 } else {
690- entry = find_multi_file_filter_entry ( & cmd_process_map , cmd );
584+ entry = ( struct cmd2process * ) subprocess_find_entry ( & subprocess_map , cmd );
691585 }
692586
693587 fflush (NULL );
694588
695589 if (!entry ) {
696- entry = start_multi_file_filter (& cmd_process_map , cmd );
697- if (!entry )
590+ entry = xmalloc (sizeof (* entry ));
591+ entry -> supported_capabilities = 0 ;
592+
593+ if (subprocess_start (& subprocess_map , & entry -> subprocess , cmd , start_multi_file_filter_fn )) {
594+ free (entry );
698595 return 0 ;
596+ }
699597 }
700- process = & entry -> process ;
598+ process = & entry -> subprocess . process ;
701599
702600 if (!(wanted_capability & entry -> supported_capabilities ))
703601 return 0 ;
@@ -737,7 +635,10 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
737635 if (err )
738636 goto done ;
739637
740- read_multi_file_filter_status (process -> out , & filter_status );
638+ err = subprocess_read_status (process -> out , & filter_status );
639+ if (err )
640+ goto done ;
641+
741642 err = strcmp (filter_status .buf , "success" );
742643 if (err )
743644 goto done ;
@@ -746,13 +647,16 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
746647 if (err )
747648 goto done ;
748649
749- read_multi_file_filter_status (process -> out , & filter_status );
650+ err = subprocess_read_status (process -> out , & filter_status );
651+ if (err )
652+ goto done ;
653+
750654 err = strcmp (filter_status .buf , "success" );
751655
752656done :
753657 sigchain_pop (SIGPIPE );
754658
755- if (err || errno == EPIPE ) {
659+ if (err ) {
756660 if (!strcmp (filter_status .buf , "error" )) {
757661 /* The filter signaled a problem with the file. */
758662 } else if (!strcmp (filter_status .buf , "abort" )) {
@@ -768,7 +672,8 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
768672 * Force shutdown and restart if another blob requires filtering.
769673 */
770674 error ("external filter '%s' failed" , cmd );
771- kill_multi_file_filter (& cmd_process_map , entry );
675+ subprocess_stop (& subprocess_map , & entry -> subprocess );
676+ free (entry );
772677 }
773678 } else {
774679 strbuf_swap (dst , & nbuf );
0 commit comments