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