enhance clone and fetch -k experience
[git] / builtin-upload-archive.c
1 /*
2  * Copyright (c) 2006 Franck Bui-Huu
3  */
4 #include <time.h>
5 #include <sys/wait.h>
6 #include <sys/poll.h>
7 #include "cache.h"
8 #include "builtin.h"
9 #include "archive.h"
10 #include "pkt-line.h"
11 #include "sideband.h"
12
13 static const char upload_archive_usage[] =
14         "git-upload-archive <repo>";
15
16 static const char deadchild[] =
17 "git-upload-archive: archiver died with error";
18
19 static const char lostchild[] =
20 "git-upload-archive: archiver process was lost";
21
22
23 static int run_upload_archive(int argc, const char **argv, const char *prefix)
24 {
25         struct archiver ar;
26         const char *sent_argv[MAX_ARGS];
27         const char *arg_cmd = "argument ";
28         char *p, buf[4096];
29         int treeish_idx;
30         int sent_argc;
31         int len;
32
33         if (argc != 2)
34                 usage(upload_archive_usage);
35
36         if (strlen(argv[1]) > sizeof(buf))
37                 die("insanely long repository name");
38
39         strcpy(buf, argv[1]); /* enter-repo smudges its argument */
40
41         if (!enter_repo(buf, 0))
42                 die("not a git archive");
43
44         /* put received options in sent_argv[] */
45         sent_argc = 1;
46         sent_argv[0] = "git-upload-archive";
47         for (p = buf;;) {
48                 /* This will die if not enough free space in buf */
49                 len = packet_read_line(0, p, (buf + sizeof buf) - p);
50                 if (len == 0)
51                         break;  /* got a flush */
52                 if (sent_argc > MAX_ARGS - 2)
53                         die("Too many options (>29)");
54
55                 if (p[len-1] == '\n') {
56                         p[--len] = 0;
57                 }
58                 if (len < strlen(arg_cmd) ||
59                     strncmp(arg_cmd, p, strlen(arg_cmd)))
60                         die("'argument' token or flush expected");
61
62                 len -= strlen(arg_cmd);
63                 memmove(p, p + strlen(arg_cmd), len);
64                 sent_argv[sent_argc++] = p;
65                 p += len;
66                 *p++ = 0;
67         }
68         sent_argv[sent_argc] = NULL;
69
70         /* parse all options sent by the client */
71         treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar);
72
73         parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix);
74         parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args);
75
76         return ar.write_archive(&ar.args);
77 }
78
79 static void error_clnt(const char *fmt, ...)
80 {
81         char buf[1024];
82         va_list params;
83         int len;
84
85         va_start(params, fmt);
86         len = vsprintf(buf, fmt, params);
87         va_end(params);
88         send_sideband(1, 3, buf, len, LARGE_PACKET_MAX);
89         die("sent error to the client: %s", buf);
90 }
91
92 static void process_input(int child_fd, int band)
93 {
94         char buf[16384];
95         ssize_t sz = read(child_fd, buf, sizeof(buf));
96         if (sz < 0) {
97                 if (errno != EINTR)
98                         error_clnt("read error: %s\n", strerror(errno));
99                 return;
100         }
101         send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
102 }
103
104 int cmd_upload_archive(int argc, const char **argv, const char *prefix)
105 {
106         pid_t writer;
107         int fd1[2], fd2[2];
108         /*
109          * Set up sideband subprocess.
110          *
111          * We (parent) monitor and read from child, sending its fd#1 and fd#2
112          * multiplexed out to our fd#1.  If the child dies, we tell the other
113          * end over channel #3.
114          */
115         if (pipe(fd1) < 0 || pipe(fd2) < 0) {
116                 int err = errno;
117                 packet_write(1, "NACK pipe failed on the remote side\n");
118                 die("upload-archive: %s", strerror(err));
119         }
120         writer = fork();
121         if (writer < 0) {
122                 int err = errno;
123                 packet_write(1, "NACK fork failed on the remote side\n");
124                 die("upload-archive: %s", strerror(err));
125         }
126         if (!writer) {
127                 /* child - connect fd#1 and fd#2 to the pipe */
128                 dup2(fd1[1], 1);
129                 dup2(fd2[1], 2);
130                 close(fd1[1]); close(fd2[1]);
131                 close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
132
133                 exit(run_upload_archive(argc, argv, prefix));
134         }
135
136         /* parent - read from child, multiplex and send out to fd#1 */
137         close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
138         packet_write(1, "ACK\n");
139         packet_flush(1);
140
141         while (1) {
142                 struct pollfd pfd[2];
143                 int status;
144
145                 pfd[0].fd = fd1[0];
146                 pfd[0].events = POLLIN;
147                 pfd[1].fd = fd2[0];
148                 pfd[1].events = POLLIN;
149                 if (poll(pfd, 2, -1) < 0) {
150                         if (errno != EINTR) {
151                                 error("poll failed resuming: %s",
152                                       strerror(errno));
153                                 sleep(1);
154                         }
155                         continue;
156                 }
157                 if (pfd[0].revents & POLLIN)
158                         /* Data stream ready */
159                         process_input(pfd[0].fd, 1);
160                 if (pfd[1].revents & POLLIN)
161                         /* Status stream ready */
162                         process_input(pfd[1].fd, 2);
163                 /* Always finish to read data when available */
164                 if ((pfd[0].revents | pfd[1].revents) & POLLIN)
165                         continue;
166
167                 if (waitpid(writer, &status, 0) < 0)
168                         error_clnt("%s", lostchild);
169                 else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
170                         error_clnt("%s", deadchild);
171                 packet_flush(1);
172                 break;
173         }
174         return 0;
175 }