Code

Fix memory leak in helper method for disconnect
[git.git] / transport-helper.c
1 #include "cache.h"
2 #include "transport.h"
4 #include "run-command.h"
5 #include "commit.h"
6 #include "diff.h"
7 #include "revision.h"
9 struct helper_data
10 {
11         const char *name;
12         struct child_process *helper;
13         unsigned fetch : 1;
14 };
16 static struct child_process *get_helper(struct transport *transport)
17 {
18         struct helper_data *data = transport->data;
19         struct strbuf buf = STRBUF_INIT;
20         struct child_process *helper;
21         FILE *file;
23         if (data->helper)
24                 return data->helper;
26         helper = xcalloc(1, sizeof(*helper));
27         helper->in = -1;
28         helper->out = -1;
29         helper->err = 0;
30         helper->argv = xcalloc(4, sizeof(*helper->argv));
31         strbuf_addf(&buf, "remote-%s", data->name);
32         helper->argv[0] = strbuf_detach(&buf, NULL);
33         helper->argv[1] = transport->remote->name;
34         helper->argv[2] = transport->url;
35         helper->git_cmd = 1;
36         if (start_command(helper))
37                 die("Unable to run helper: git %s", helper->argv[0]);
38         data->helper = helper;
40         write_str_in_full(helper->in, "capabilities\n");
42         file = xfdopen(helper->out, "r");
43         while (1) {
44                 if (strbuf_getline(&buf, file, '\n') == EOF)
45                         exit(128); /* child died, message supplied already */
47                 if (!*buf.buf)
48                         break;
49                 if (!strcmp(buf.buf, "fetch"))
50                         data->fetch = 1;
51         }
52         return data->helper;
53 }
55 static int disconnect_helper(struct transport *transport)
56 {
57         struct helper_data *data = transport->data;
58         if (data->helper) {
59                 write_str_in_full(data->helper->in, "\n");
60                 close(data->helper->in);
61                 finish_command(data->helper);
62                 free((char *)data->helper->argv[0]);
63                 free(data->helper->argv);
64                 free(data->helper);
65                 data->helper = NULL;
66         }
67         return 0;
68 }
70 static int release_helper(struct transport *transport)
71 {
72         disconnect_helper(transport);
73         free(transport->data);
74         return 0;
75 }
77 static int fetch_with_fetch(struct transport *transport,
78                             int nr_heads, const struct ref **to_fetch)
79 {
80         struct child_process *helper = get_helper(transport);
81         FILE *file = xfdopen(helper->out, "r");
82         int i;
83         struct strbuf buf = STRBUF_INIT;
85         for (i = 0; i < nr_heads; i++) {
86                 const struct ref *posn = to_fetch[i];
87                 if (posn->status & REF_STATUS_UPTODATE)
88                         continue;
90                 strbuf_addf(&buf, "fetch %s %s\n",
91                             sha1_to_hex(posn->old_sha1), posn->name);
92                 write_in_full(helper->in, buf.buf, buf.len);
93                 strbuf_reset(&buf);
95                 if (strbuf_getline(&buf, file, '\n') == EOF)
96                         exit(128); /* child died, message supplied already */
97         }
98         return 0;
99 }
101 static int fetch(struct transport *transport,
102                  int nr_heads, const struct ref **to_fetch)
104         struct helper_data *data = transport->data;
105         int i, count;
107         count = 0;
108         for (i = 0; i < nr_heads; i++)
109                 if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
110                         count++;
112         if (!count)
113                 return 0;
115         if (data->fetch)
116                 return fetch_with_fetch(transport, nr_heads, to_fetch);
118         return -1;
121 static struct ref *get_refs_list(struct transport *transport, int for_push)
123         struct child_process *helper;
124         struct ref *ret = NULL;
125         struct ref **tail = &ret;
126         struct ref *posn;
127         struct strbuf buf = STRBUF_INIT;
128         FILE *file;
130         helper = get_helper(transport);
132         write_str_in_full(helper->in, "list\n");
134         file = xfdopen(helper->out, "r");
135         while (1) {
136                 char *eov, *eon;
137                 if (strbuf_getline(&buf, file, '\n') == EOF)
138                         exit(128); /* child died, message supplied already */
140                 if (!*buf.buf)
141                         break;
143                 eov = strchr(buf.buf, ' ');
144                 if (!eov)
145                         die("Malformed response in ref list: %s", buf.buf);
146                 eon = strchr(eov + 1, ' ');
147                 *eov = '\0';
148                 if (eon)
149                         *eon = '\0';
150                 *tail = alloc_ref(eov + 1);
151                 if (buf.buf[0] == '@')
152                         (*tail)->symref = xstrdup(buf.buf + 1);
153                 else if (buf.buf[0] != '?')
154                         get_sha1_hex(buf.buf, (*tail)->old_sha1);
155                 tail = &((*tail)->next);
156         }
157         strbuf_release(&buf);
159         for (posn = ret; posn; posn = posn->next)
160                 resolve_remote_symref(posn, ret);
162         return ret;
165 int transport_helper_init(struct transport *transport, const char *name)
167         struct helper_data *data = xcalloc(sizeof(*data), 1);
168         data->name = name;
170         transport->data = data;
171         transport->get_refs_list = get_refs_list;
172         transport->fetch = fetch;
173         transport->disconnect = release_helper;
174         return 0;