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