fetch-clone.con commit send-pack/receive-pack: allow errors to be reported back to pusher. (cfee10a)
   1#include "cache.h"
   2#include <sys/wait.h>
   3
   4static int finish_pack(const char *pack_tmp_name, const char *me)
   5{
   6        int pipe_fd[2];
   7        pid_t pid;
   8        char idx[PATH_MAX];
   9        char final[PATH_MAX];
  10        char hash[41];
  11        unsigned char sha1[20];
  12        char *cp;
  13        int err = 0;
  14
  15        if (pipe(pipe_fd) < 0)
  16                die("%s: unable to set up pipe", me);
  17
  18        strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
  19        cp = strrchr(idx, '/');
  20        memcpy(cp, "/pidx", 5);
  21
  22        pid = fork();
  23        if (pid < 0)
  24                die("git-clone-pack: unable to fork off git-index-pack");
  25        if (!pid) {
  26                close(0);
  27                dup2(pipe_fd[1], 1);
  28                close(pipe_fd[0]);
  29                close(pipe_fd[1]);
  30                execlp("git-index-pack","git-index-pack",
  31                       "-o", idx, pack_tmp_name, NULL);
  32                error("cannot exec git-index-pack <%s> <%s>",
  33                      idx, pack_tmp_name);
  34                exit(1);
  35        }
  36        close(pipe_fd[1]);
  37        if (read(pipe_fd[0], hash, 40) != 40) {
  38                error("%s: unable to read from git-index-pack", me);
  39                err = 1;
  40        }
  41        close(pipe_fd[0]);
  42
  43        for (;;) {
  44                int status, code;
  45                int retval = waitpid(pid, &status, 0);
  46
  47                if (retval < 0) {
  48                        if (errno == EINTR)
  49                                continue;
  50                        error("waitpid failed (%s)", strerror(retval));
  51                        goto error_die;
  52                }
  53                if (WIFSIGNALED(status)) {
  54                        int sig = WTERMSIG(status);
  55                        error("git-index-pack died of signal %d", sig);
  56                        goto error_die;
  57                }
  58                if (!WIFEXITED(status)) {
  59                        error("git-index-pack died of unnatural causes %d",
  60                              status);
  61                        goto error_die;
  62                }
  63                code = WEXITSTATUS(status);
  64                if (code) {
  65                        error("git-index-pack died with error code %d", code);
  66                        goto error_die;
  67                }
  68                if (err)
  69                        goto error_die;
  70                break;
  71        }
  72        hash[40] = 0;
  73        if (get_sha1_hex(hash, sha1)) {
  74                error("git-index-pack reported nonsense '%s'", hash);
  75                goto error_die;
  76        }
  77        /* Now we have pack in pack_tmp_name[], and
  78         * idx in idx[]; rename them to their final names.
  79         */
  80        snprintf(final, sizeof(final),
  81                 "%s/pack/pack-%s.pack", get_object_directory(), hash);
  82        move_temp_to_file(pack_tmp_name, final);
  83        chmod(final, 0444);
  84        snprintf(final, sizeof(final),
  85                 "%s/pack/pack-%s.idx", get_object_directory(), hash);
  86        move_temp_to_file(idx, final);
  87        chmod(final, 0444);
  88        return 0;
  89
  90 error_die:
  91        unlink(idx);
  92        unlink(pack_tmp_name);
  93        exit(1);
  94}
  95
  96int receive_unpack_pack(int fd[2], const char *me, int quiet)
  97{
  98        int status;
  99        pid_t pid;
 100
 101        pid = fork();
 102        if (pid < 0)
 103                die("%s: unable to fork off git-unpack-objects", me);
 104        if (!pid) {
 105                dup2(fd[0], 0);
 106                close(fd[0]);
 107                close(fd[1]);
 108                execlp("git-unpack-objects", "git-unpack-objects",
 109                       quiet ? "-q" : NULL, NULL);
 110                die("git-unpack-objects exec failed");
 111        }
 112        close(fd[0]);
 113        close(fd[1]);
 114        while (waitpid(pid, &status, 0) < 0) {
 115                if (errno != EINTR)
 116                        die("waiting for git-unpack-objects: %s",
 117                            strerror(errno));
 118        }
 119        if (WIFEXITED(status)) {
 120                int code = WEXITSTATUS(status);
 121                if (code)
 122                        die("git-unpack-objects died with error code %d",
 123                            code);
 124                return 0;
 125        }
 126        if (WIFSIGNALED(status)) {
 127                int sig = WTERMSIG(status);
 128                die("git-unpack-objects died of signal %d", sig);
 129        }
 130        die("git-unpack-objects died of unnatural causes %d", status);
 131}
 132
 133int receive_keep_pack(int fd[2], const char *me)
 134{
 135        char tmpfile[PATH_MAX];
 136        int ofd, ifd;
 137
 138        ifd = fd[0];
 139        snprintf(tmpfile, sizeof(tmpfile),
 140                 "%s/pack/tmp-XXXXXX", get_object_directory());
 141        ofd = mkstemp(tmpfile);
 142        if (ofd < 0)
 143                return error("unable to create temporary file %s", tmpfile);
 144
 145        while (1) {
 146                char buf[8192];
 147                ssize_t sz, wsz, pos;
 148                sz = read(ifd, buf, sizeof(buf));
 149                if (sz == 0)
 150                        break;
 151                if (sz < 0) {
 152                        error("error reading pack (%s)", strerror(errno));
 153                        close(ofd);
 154                        unlink(tmpfile);
 155                        return -1;
 156                }
 157                pos = 0;
 158                while (pos < sz) {
 159                        wsz = write(ofd, buf + pos, sz - pos);
 160                        if (wsz < 0) {
 161                                error("error writing pack (%s)",
 162                                      strerror(errno));
 163                                close(ofd);
 164                                unlink(tmpfile);
 165                                return -1;
 166                        }
 167                        pos += wsz;
 168                }
 169        }
 170        close(ofd);
 171        return finish_pack(tmpfile, me);
 172}