clone-pack.con commit clone-pack: new option --keep tells it not to explode the pack. (64c381b)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include <sys/wait.h>
   5
   6static int quiet;
   7static int keep_pack;
   8static const char clone_pack_usage[] =
   9"git-clone-pack [-q] [--keep] [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
  10static const char *exec = "git-upload-pack";
  11
  12static void clone_handshake(int fd[2], struct ref *ref)
  13{
  14        unsigned char sha1[20];
  15
  16        while (ref) {
  17                packet_write(fd[1], "want %s\n", sha1_to_hex(ref->old_sha1));
  18                ref = ref->next;
  19        }
  20        packet_flush(fd[1]);
  21
  22        /* We don't have nuttin' */
  23        packet_write(fd[1], "done\n");
  24        if (get_ack(fd[0], sha1))
  25                error("Huh! git-clone-pack got positive ack for %s", sha1_to_hex(sha1));
  26}
  27
  28static int is_master(struct ref *ref)
  29{
  30        return !strcmp(ref->name, "refs/heads/master");
  31}
  32
  33static void write_one_ref(struct ref *ref)
  34{
  35        char *path = git_path("%s", ref->name);
  36        int fd;
  37        char *hex;
  38
  39        if (safe_create_leading_directories(path))
  40                die("unable to create leading directory for %s", ref->name);
  41        fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);
  42        if (fd < 0)
  43                die("unable to create ref %s", ref->name);
  44        hex = sha1_to_hex(ref->old_sha1);
  45        hex[40] = '\n';
  46        if (write(fd, hex, 41) != 41)
  47                die("unable to write ref %s", ref->name);
  48        close(fd);
  49}
  50
  51static void write_refs(struct ref *ref)
  52{
  53        struct ref *head = NULL, *head_ptr, *master_ref;
  54        char *head_path;
  55
  56        /* Upload-pack must report HEAD first */
  57        if (!strcmp(ref->name, "HEAD")) {
  58                head = ref;
  59                ref = ref->next;
  60        }
  61        head_ptr = NULL;
  62        master_ref = NULL;
  63        while (ref) {
  64                if (is_master(ref))
  65                        master_ref = ref;
  66                if (head &&
  67                    !memcmp(ref->old_sha1, head->old_sha1, 20) &&
  68                    !strncmp(ref->name, "refs/heads/",11) &&
  69                    (!head_ptr || ref == master_ref))
  70                        head_ptr = ref;
  71
  72                write_one_ref(ref);
  73                ref = ref->next;
  74        }
  75        if (!head) {
  76                fprintf(stderr, "No HEAD in remote.\n");
  77                return;
  78        }
  79
  80        head_path = strdup(git_path("HEAD"));
  81        if (!head_ptr) {
  82                /*
  83                 * If we had a master ref, and it wasn't HEAD, we need to undo the
  84                 * symlink, and write a standalone HEAD. Give a warning, because that's
  85                 * really really wrong.
  86                 */
  87                if (master_ref) {
  88                        error("HEAD doesn't point to any refs! Making standalone HEAD");
  89                        unlink(head_path);
  90                }
  91                write_one_ref(head);
  92                free(head_path);
  93                return;
  94        }
  95
  96        /* We reset to the master branch if it's available */
  97        if (master_ref)
  98                return;
  99
 100        fprintf(stderr, "Setting HEAD to %s\n", head_ptr->name);
 101
 102        /*
 103         * Uhhuh. Other end didn't have master. We start HEAD off with
 104         * the first branch with the same value.
 105         */
 106        if (create_symref(head_path, head_ptr->name) < 0)
 107                die("unable to link HEAD to %s", head_ptr->name);
 108        free(head_path);
 109}
 110
 111static int clone_by_unpack(int fd[2])
 112{
 113        int status;
 114        pid_t pid;
 115
 116        pid = fork();
 117        if (pid < 0)
 118                die("git-clone-pack: unable to fork off git-unpack-objects");
 119        if (!pid) {
 120                dup2(fd[0], 0);
 121                close(fd[0]);
 122                close(fd[1]);
 123                execlp("git-unpack-objects", "git-unpack-objects",
 124                        quiet ? "-q" : NULL, NULL);
 125                die("git-unpack-objects exec failed");
 126        }
 127        close(fd[0]);
 128        close(fd[1]);
 129        while (waitpid(pid, &status, 0) < 0) {
 130                if (errno != EINTR)
 131                        die("waiting for git-unpack-objects: %s", strerror(errno));
 132        }
 133        if (WIFEXITED(status)) {
 134                int code = WEXITSTATUS(status);
 135                if (code)
 136                        die("git-unpack-objects died with error code %d", code);
 137                return 0;
 138        }
 139        if (WIFSIGNALED(status)) {
 140                int sig = WTERMSIG(status);
 141                die("git-unpack-objects died of signal %d", sig);
 142        }
 143        die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
 144}
 145
 146static int finish_pack(const char *pack_tmp_name)
 147{
 148        int pipe_fd[2];
 149        pid_t pid;
 150        char idx[PATH_MAX];
 151        char final[PATH_MAX];
 152        char hash[41];
 153        unsigned char sha1[20];
 154        char *cp;
 155        int err = 0;
 156
 157        if (pipe(pipe_fd) < 0)
 158                die("git-clone-pack: unable to set up pipe");
 159
 160        strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
 161        cp = strrchr(idx, '/');
 162        memcpy(cp, "/pidx", 5);
 163
 164        pid = fork();
 165        if (pid < 0)
 166                die("git-clone-pack: unable to fork off git-index-pack");
 167        if (!pid) {
 168                close(0);
 169                dup2(pipe_fd[1], 1);
 170                close(pipe_fd[0]);
 171                close(pipe_fd[1]);
 172                execlp("git-index-pack","git-index-pack",
 173                       "-o", idx, pack_tmp_name, NULL);
 174                error("cannot exec git-index-pack <%s> <%s>",
 175                      idx, pack_tmp_name);
 176                exit(1);
 177        }
 178        close(pipe_fd[1]);
 179        if (read(pipe_fd[0], hash, 40) != 40) {
 180                error("git-clone-pack: unable to read from git-index-pack");
 181                err = 1;
 182        }
 183        close(pipe_fd[0]);
 184
 185        for (;;) {
 186                int status, code;
 187                int retval = waitpid(pid, &status, 0);
 188
 189                if (retval < 0) {
 190                        if (errno == EINTR)
 191                                continue;
 192                        error("waitpid failed (%s)", strerror(retval));
 193                        goto error_die;
 194                }
 195                if (WIFSIGNALED(status)) {
 196                        int sig = WTERMSIG(status);
 197                        error("git-index-pack died of signal %d", sig);
 198                        goto error_die;
 199                }
 200                if (!WIFEXITED(status)) {
 201                        error("git-index-pack died of unnatural causes %d",
 202                              status);
 203                        goto error_die;
 204                }
 205                code = WEXITSTATUS(status);
 206                if (code) {
 207                        error("git-index-pack died with error code %d", code);
 208                        goto error_die;
 209                }
 210                if (err)
 211                        goto error_die;
 212                break;
 213        }
 214        hash[40] = 0;
 215        if (get_sha1_hex(hash, sha1)) {
 216                error("git-index-pack reported nonsense '%s'", hash);
 217                goto error_die;
 218        }
 219        /* Now we have pack in pack_tmp_name[], and
 220         * idx in idx[]; rename them to their final names.
 221         */
 222        snprintf(final, sizeof(final),
 223                 "%s/pack/pack-%s.pack", get_object_directory(), hash);
 224        move_temp_to_file(pack_tmp_name, final);
 225        chmod(final, 0444);
 226        snprintf(final, sizeof(final),
 227                 "%s/pack/pack-%s.idx", get_object_directory(), hash);
 228        move_temp_to_file(idx, final);
 229        chmod(final, 0444);
 230        return 0;
 231
 232 error_die:
 233        unlink(idx);
 234        unlink(pack_tmp_name);
 235        exit(1);
 236}
 237
 238static int clone_without_unpack(int fd[2])
 239{
 240        char tmpfile[PATH_MAX];
 241        int ofd, ifd;
 242
 243        ifd = fd[0];
 244        snprintf(tmpfile, sizeof(tmpfile),
 245                 "%s/pack-XXXXXX", get_object_directory());
 246        ofd = mkstemp(tmpfile);
 247        if (ofd < 0)
 248                return error("unable to create temporary file %s", tmpfile);
 249
 250        while (1) {
 251                char buf[8192];
 252                ssize_t sz, wsz, pos;
 253                sz = read(ifd, buf, sizeof(buf));
 254                if (sz == 0)
 255                        break;
 256                if (sz < 0) {
 257                        error("error reading pack (%s)", strerror(errno));
 258                        close(ofd);
 259                        unlink(tmpfile);
 260                        return -1;
 261                }
 262                pos = 0;
 263                while (pos < sz) {
 264                        wsz = write(ofd, buf + pos, sz - pos);
 265                        if (wsz < 0) {
 266                                error("error writing pack (%s)",
 267                                      strerror(errno));
 268                                close(ofd);
 269                                unlink(tmpfile);
 270                                return -1;
 271                        }
 272                        pos += wsz;
 273                }
 274        }
 275        close(ofd);
 276        return finish_pack(tmpfile);
 277}
 278
 279static int clone_pack(int fd[2], int nr_match, char **match)
 280{
 281        struct ref *refs;
 282        int status;
 283
 284        get_remote_heads(fd[0], &refs, nr_match, match);
 285        if (!refs) {
 286                packet_flush(fd[1]);
 287                die("no matching remote head");
 288        }
 289        clone_handshake(fd, refs);
 290
 291        if (keep_pack)
 292                status = clone_without_unpack(fd);
 293        else
 294                status = clone_by_unpack(fd);
 295
 296        if (!status)
 297                write_refs(refs);
 298        return status;
 299}
 300
 301static int clone_options(const char *var, const char *value)
 302{
 303        if (!strcmp("clone.keeppack", var)) {
 304                keep_pack = git_config_bool(var, value);
 305                return 0;
 306        }
 307        if (!strcmp("clone.quiet", var)) {
 308                quiet = git_config_bool(var, value);
 309                return 0;
 310        }
 311        /*
 312         * Put other local option parsing for this program
 313         * here ...
 314         */
 315
 316        /* Fall back on the default ones */
 317        return git_default_config(var, value);
 318}
 319
 320int main(int argc, char **argv)
 321{
 322        int i, ret, nr_heads;
 323        char *dest = NULL, **heads;
 324        int fd[2];
 325        pid_t pid;
 326
 327        git_config(clone_options);
 328        nr_heads = 0;
 329        heads = NULL;
 330        for (i = 1; i < argc; i++) {
 331                char *arg = argv[i];
 332
 333                if (*arg == '-') {
 334                        if (!strcmp("-q", arg)) {
 335                                quiet = 1;
 336                                continue;
 337                        }
 338                        if (!strncmp("--exec=", arg, 7)) {
 339                                exec = arg + 7;
 340                                continue;
 341                        }
 342                        if (!strcmp("--keep", arg)) {
 343                                keep_pack = 1;
 344                                continue;
 345                        }
 346                        usage(clone_pack_usage);
 347                }
 348                dest = arg;
 349                heads = argv + i + 1;
 350                nr_heads = argc - i - 1;
 351                break;
 352        }
 353        if (!dest)
 354                usage(clone_pack_usage);
 355        pid = git_connect(fd, dest, exec);
 356        if (pid < 0)
 357                return 1;
 358        ret = clone_pack(fd, nr_heads, heads);
 359        close(fd[0]);
 360        close(fd[1]);
 361        finish_connect(pid);
 362        return ret;
 363}