upload-pack.con commit upload-pack: ignore write errors to stderr (5f490ce)
   1#include <signal.h>
   2#include <sys/wait.h>
   3#include <sys/poll.h>
   4#include "cache.h"
   5#include "refs.h"
   6#include "pkt-line.h"
   7#include "tag.h"
   8#include "object.h"
   9#include "commit.h"
  10#include "exec_cmd.h"
  11
  12static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
  13
  14#define THEY_HAVE (1U << 0)
  15#define OUR_REF (1U << 1)
  16#define WANTED (1U << 2)
  17#define MAX_HAS 256
  18#define MAX_NEEDS 256
  19static int nr_has = 0, nr_needs = 0, multi_ack = 0, nr_our_refs = 0;
  20static int use_thin_pack = 0;
  21static unsigned char has_sha1[MAX_HAS][20];
  22static unsigned char needs_sha1[MAX_NEEDS][20];
  23static unsigned int timeout = 0;
  24static int use_sideband = 0;
  25
  26static void reset_timeout(void)
  27{
  28        alarm(timeout);
  29}
  30
  31static int strip(char *line, int len)
  32{
  33        if (len && line[len-1] == '\n')
  34                line[--len] = 0;
  35        return len;
  36}
  37
  38#define PACKET_MAX 1000
  39static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
  40{
  41        ssize_t ssz;
  42        const char *p;
  43
  44        if (!data) {
  45                if (!use_sideband)
  46                        return 0;
  47                packet_flush(1);
  48        }
  49
  50        if (!use_sideband) {
  51                if (fd == 3)
  52                        /* emergency quit */
  53                        fd = 2;
  54                if (fd == 2) {
  55                        xwrite(fd, data, sz);
  56                        return sz;
  57                }
  58                return safe_write(fd, data, sz);
  59        }
  60        p = data;
  61        ssz = sz;
  62        while (sz) {
  63                unsigned n;
  64                char hdr[5];
  65
  66                n = sz;
  67                if (PACKET_MAX - 5 < n)
  68                        n = PACKET_MAX - 5;
  69                sprintf(hdr, "%04x", n + 5);
  70                hdr[4] = fd;
  71                safe_write(1, hdr, 5);
  72                safe_write(1, p, n);
  73                p += n;
  74                sz -= n;
  75        }
  76        return ssz;
  77}
  78
  79static void create_pack_file(void)
  80{
  81        /* Pipes between rev-list to pack-objects, pack-objects to us
  82         * and pack-objects error stream for progress bar.
  83         */
  84        int lp_pipe[2], pu_pipe[2], pe_pipe[2];
  85        pid_t pid_rev_list, pid_pack_objects;
  86        int create_full_pack = (nr_our_refs == nr_needs && !nr_has);
  87        char data[8193], progress[128];
  88        char abort_msg[] = "aborting due to possible repository "
  89                "corruption on the remote side.";
  90        int buffered = -1;
  91
  92        if (pipe(lp_pipe) < 0)
  93                die("git-upload-pack: unable to create pipe");
  94        pid_rev_list = fork();
  95        if (pid_rev_list < 0)
  96                die("git-upload-pack: unable to fork git-rev-list");
  97
  98        if (!pid_rev_list) {
  99                int i;
 100                int args;
 101                const char **argv;
 102                const char **p;
 103                char *buf;
 104
 105                if (create_full_pack) {
 106                        args = 10;
 107                        use_thin_pack = 0; /* no point doing it */
 108                }
 109                else
 110                        args = nr_has + nr_needs + 5;
 111                p = xmalloc(args * sizeof(char *));
 112                argv = (const char **) p;
 113                buf = xmalloc(args * 45);
 114
 115                dup2(lp_pipe[1], 1);
 116                close(0);
 117                close(lp_pipe[0]);
 118                close(lp_pipe[1]);
 119                *p++ = "rev-list";
 120                *p++ = use_thin_pack ? "--objects-edge" : "--objects";
 121                if (create_full_pack || MAX_NEEDS <= nr_needs)
 122                        *p++ = "--all";
 123                else {
 124                        for (i = 0; i < nr_needs; i++) {
 125                                *p++ = buf;
 126                                memcpy(buf, sha1_to_hex(needs_sha1[i]), 41);
 127                                buf += 41;
 128                        }
 129                }
 130                if (!create_full_pack)
 131                        for (i = 0; i < nr_has; i++) {
 132                                *p++ = buf;
 133                                *buf++ = '^';
 134                                memcpy(buf, sha1_to_hex(has_sha1[i]), 41);
 135                                buf += 41;
 136                        }
 137                *p++ = NULL;
 138                execv_git_cmd(argv);
 139                die("git-upload-pack: unable to exec git-rev-list");
 140        }
 141
 142        if (pipe(pu_pipe) < 0)
 143                die("git-upload-pack: unable to create pipe");
 144        if (pipe(pe_pipe) < 0)
 145                die("git-upload-pack: unable to create pipe");
 146        pid_pack_objects = fork();
 147        if (pid_pack_objects < 0) {
 148                /* daemon sets things up to ignore TERM */
 149                kill(pid_rev_list, SIGKILL);
 150                die("git-upload-pack: unable to fork git-pack-objects");
 151        }
 152        if (!pid_pack_objects) {
 153                dup2(lp_pipe[0], 0);
 154                dup2(pu_pipe[1], 1);
 155                dup2(pe_pipe[1], 2);
 156
 157                close(lp_pipe[0]);
 158                close(lp_pipe[1]);
 159                close(pu_pipe[0]);
 160                close(pu_pipe[1]);
 161                close(pe_pipe[0]);
 162                close(pe_pipe[1]);
 163                execl_git_cmd("pack-objects", "--stdout", "--progress", NULL);
 164                kill(pid_rev_list, SIGKILL);
 165                die("git-upload-pack: unable to exec git-pack-objects");
 166        }
 167
 168        close(lp_pipe[0]);
 169        close(lp_pipe[1]);
 170
 171        /* We read from pe_pipe[0] to capture stderr output for
 172         * progress bar, and pu_pipe[0] to capture the pack data.
 173         */
 174        close(pe_pipe[1]);
 175        close(pu_pipe[1]);
 176
 177        while (1) {
 178                const char *who;
 179                struct pollfd pfd[2];
 180                pid_t pid;
 181                int status;
 182                ssize_t sz;
 183                int pe, pu, pollsize;
 184
 185                pollsize = 0;
 186                pe = pu = -1;
 187
 188                if (0 <= pu_pipe[0]) {
 189                        pfd[pollsize].fd = pu_pipe[0];
 190                        pfd[pollsize].events = POLLIN;
 191                        pu = pollsize;
 192                        pollsize++;
 193                }
 194                if (0 <= pe_pipe[0]) {
 195                        pfd[pollsize].fd = pe_pipe[0];
 196                        pfd[pollsize].events = POLLIN;
 197                        pe = pollsize;
 198                        pollsize++;
 199                }
 200
 201                if (pollsize) {
 202                        if (poll(pfd, pollsize, -1) < 0) {
 203                                if (errno != EINTR) {
 204                                        error("poll failed, resuming: %s",
 205                                              strerror(errno));
 206                                        sleep(1);
 207                                }
 208                                continue;
 209                        }
 210                        if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
 211                                /* Data ready; we keep the last byte
 212                                 * to ourselves in case we detect
 213                                 * broken rev-list, so that we can
 214                                 * leave the stream corrupted.  This
 215                                 * is unfortunate -- unpack-objects
 216                                 * would happily accept a valid pack
 217                                 * data with trailing garbage, so
 218                                 * appending garbage after we pass all
 219                                 * the pack data is not good enough to
 220                                 * signal breakage to downstream.
 221                                 */
 222                                char *cp = data;
 223                                ssize_t outsz = 0;
 224                                if (0 <= buffered) {
 225                                        *cp++ = buffered;
 226                                        outsz++;
 227                                }
 228                                sz = read(pu_pipe[0], cp,
 229                                          sizeof(data) - outsz);
 230                                if (0 < sz)
 231                                                ;
 232                                else if (sz == 0) {
 233                                        close(pu_pipe[0]);
 234                                        pu_pipe[0] = -1;
 235                                }
 236                                else
 237                                        goto fail;
 238                                sz += outsz;
 239                                if (1 < sz) {
 240                                        buffered = data[sz-1] & 0xFF;
 241                                        sz--;
 242                                }
 243                                else
 244                                        buffered = -1;
 245                                sz = send_client_data(1, data, sz);
 246                                if (sz < 0)
 247                                        goto fail;
 248                        }
 249                        if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
 250                                /* Status ready; we ship that in the side-band
 251                                 * or dump to the standard error.
 252                                 */
 253                                sz = read(pe_pipe[0], progress,
 254                                          sizeof(progress));
 255                                if (0 < sz)
 256                                        send_client_data(2, progress, sz);
 257                                else if (sz == 0) {
 258                                        close(pe_pipe[0]);
 259                                        pe_pipe[0] = -1;
 260                                }
 261                                else
 262                                        goto fail;
 263                        }
 264                }
 265
 266                /* See if the children are still there */
 267                if (pid_rev_list || pid_pack_objects) {
 268                        pid = waitpid(-1, &status, WNOHANG);
 269                        if (!pid)
 270                                continue;
 271                        who = ((pid == pid_rev_list) ? "git-rev-list" :
 272                               (pid == pid_pack_objects) ? "git-pack-objects" :
 273                               NULL);
 274                        if (!who) {
 275                                if (pid < 0) {
 276                                        error("git-upload-pack: %s",
 277                                              strerror(errno));
 278                                        goto fail;
 279                                }
 280                                error("git-upload-pack: we weren't "
 281                                      "waiting for %d", pid);
 282                                continue;
 283                        }
 284                        if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) {
 285                                error("git-upload-pack: %s died with error.",
 286                                      who);
 287                                goto fail;
 288                        }
 289                        if (pid == pid_rev_list)
 290                                pid_rev_list = 0;
 291                        if (pid == pid_pack_objects)
 292                                pid_pack_objects = 0;
 293                        if (pid_rev_list || pid_pack_objects)
 294                                continue;
 295                }
 296
 297                /* both died happily */
 298                if (pollsize)
 299                        continue;
 300
 301                /* flush the data */
 302                if (0 <= buffered) {
 303                        data[0] = buffered;
 304                        sz = send_client_data(1, data, 1);
 305                        if (sz < 0)
 306                                goto fail;
 307                        fprintf(stderr, "flushed.\n");
 308                }
 309                send_client_data(1, NULL, 0);
 310                return;
 311        }
 312 fail:
 313        if (pid_pack_objects)
 314                kill(pid_pack_objects, SIGKILL);
 315        if (pid_rev_list)
 316                kill(pid_rev_list, SIGKILL);
 317        send_client_data(3, abort_msg, sizeof(abort_msg));
 318        die("git-upload-pack: %s", abort_msg);
 319}
 320
 321static int got_sha1(char *hex, unsigned char *sha1)
 322{
 323        if (get_sha1_hex(hex, sha1))
 324                die("git-upload-pack: expected SHA1 object, got '%s'", hex);
 325        if (!has_sha1_file(sha1))
 326                return 0;
 327        if (nr_has < MAX_HAS) {
 328                struct object *o = lookup_object(sha1);
 329                if (!(o && o->parsed))
 330                        o = parse_object(sha1);
 331                if (!o)
 332                        die("oops (%s)", sha1_to_hex(sha1));
 333                if (o->type == TYPE_COMMIT) {
 334                        struct commit_list *parents;
 335                        if (o->flags & THEY_HAVE)
 336                                return 0;
 337                        o->flags |= THEY_HAVE;
 338                        for (parents = ((struct commit*)o)->parents;
 339                             parents;
 340                             parents = parents->next)
 341                                parents->item->object.flags |= THEY_HAVE;
 342                }
 343                memcpy(has_sha1[nr_has++], sha1, 20);
 344        }
 345        return 1;
 346}
 347
 348static int get_common_commits(void)
 349{
 350        static char line[1000];
 351        unsigned char sha1[20], last_sha1[20];
 352        int len;
 353
 354        track_object_refs = 0;
 355        save_commit_buffer = 0;
 356
 357        for(;;) {
 358                len = packet_read_line(0, line, sizeof(line));
 359                reset_timeout();
 360
 361                if (!len) {
 362                        if (nr_has == 0 || multi_ack)
 363                                packet_write(1, "NAK\n");
 364                        continue;
 365                }
 366                len = strip(line, len);
 367                if (!strncmp(line, "have ", 5)) {
 368                        if (got_sha1(line+5, sha1) &&
 369                                        (multi_ack || nr_has == 1)) {
 370                                if (nr_has >= MAX_HAS)
 371                                        multi_ack = 0;
 372                                packet_write(1, "ACK %s%s\n",
 373                                        sha1_to_hex(sha1),
 374                                        multi_ack ?  " continue" : "");
 375                                if (multi_ack)
 376                                        memcpy(last_sha1, sha1, 20);
 377                        }
 378                        continue;
 379                }
 380                if (!strcmp(line, "done")) {
 381                        if (nr_has > 0) {
 382                                if (multi_ack)
 383                                        packet_write(1, "ACK %s\n",
 384                                                        sha1_to_hex(last_sha1));
 385                                return 0;
 386                        }
 387                        packet_write(1, "NAK\n");
 388                        return -1;
 389                }
 390                die("git-upload-pack: expected SHA1 list, got '%s'", line);
 391        }
 392}
 393
 394static int receive_needs(void)
 395{
 396        static char line[1000];
 397        int len, needs;
 398
 399        needs = 0;
 400        for (;;) {
 401                struct object *o;
 402                unsigned char dummy[20], *sha1_buf;
 403                len = packet_read_line(0, line, sizeof(line));
 404                reset_timeout();
 405                if (!len)
 406                        return needs;
 407
 408                sha1_buf = dummy;
 409                if (needs == MAX_NEEDS) {
 410                        fprintf(stderr,
 411                                "warning: supporting only a max of %d requests. "
 412                                "sending everything instead.\n",
 413                                MAX_NEEDS);
 414                }
 415                else if (needs < MAX_NEEDS)
 416                        sha1_buf = needs_sha1[needs];
 417
 418                if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf))
 419                        die("git-upload-pack: protocol error, "
 420                            "expected to get sha, not '%s'", line);
 421                if (strstr(line+45, "multi_ack"))
 422                        multi_ack = 1;
 423                if (strstr(line+45, "thin-pack"))
 424                        use_thin_pack = 1;
 425                if (strstr(line+45, "side-band"))
 426                        use_sideband = 1;
 427
 428                /* We have sent all our refs already, and the other end
 429                 * should have chosen out of them; otherwise they are
 430                 * asking for nonsense.
 431                 *
 432                 * Hmph.  We may later want to allow "want" line that
 433                 * asks for something like "master~10" (symbolic)...
 434                 * would it make sense?  I don't know.
 435                 */
 436                o = lookup_object(sha1_buf);
 437                if (!o || !(o->flags & OUR_REF))
 438                        die("git-upload-pack: not our ref %s", line+5);
 439                if (!(o->flags & WANTED)) {
 440                        o->flags |= WANTED;
 441                        needs++;
 442                }
 443        }
 444}
 445
 446static int send_ref(const char *refname, const unsigned char *sha1)
 447{
 448        static const char *capabilities = "multi_ack thin-pack side-band";
 449        struct object *o = parse_object(sha1);
 450
 451        if (!o)
 452                die("git-upload-pack: cannot find object %s:", sha1_to_hex(sha1));
 453
 454        if (capabilities)
 455                packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname,
 456                        0, capabilities);
 457        else
 458                packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname);
 459        capabilities = NULL;
 460        if (!(o->flags & OUR_REF)) {
 461                o->flags |= OUR_REF;
 462                nr_our_refs++;
 463        }
 464        if (o->type == TYPE_TAG) {
 465                o = deref_tag(o, refname, 0);
 466                packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
 467        }
 468        return 0;
 469}
 470
 471static int upload_pack(void)
 472{
 473        reset_timeout();
 474        head_ref(send_ref);
 475        for_each_ref(send_ref);
 476        packet_flush(1);
 477        nr_needs = receive_needs();
 478        if (!nr_needs)
 479                return 0;
 480        get_common_commits();
 481        create_pack_file();
 482        return 0;
 483}
 484
 485int main(int argc, char **argv)
 486{
 487        char *dir;
 488        int i;
 489        int strict = 0;
 490
 491        for (i = 1; i < argc; i++) {
 492                char *arg = argv[i];
 493
 494                if (arg[0] != '-')
 495                        break;
 496                if (!strcmp(arg, "--strict")) {
 497                        strict = 1;
 498                        continue;
 499                }
 500                if (!strncmp(arg, "--timeout=", 10)) {
 501                        timeout = atoi(arg+10);
 502                        continue;
 503                }
 504                if (!strcmp(arg, "--")) {
 505                        i++;
 506                        break;
 507                }
 508        }
 509        
 510        if (i != argc-1)
 511                usage(upload_pack_usage);
 512        dir = argv[i];
 513
 514        if (!enter_repo(dir, strict))
 515                die("'%s': unable to chdir or not a git archive", dir);
 516
 517        upload_pack();
 518        return 0;
 519}