receive-pack.con commit git-send-pack: actually send the object pack (94fdb7a)
   1#include "cache.h"
   2#include "pkt-line.h"
   3#include <sys/wait.h>
   4
   5static const char receive_pack_usage[] = "git-receive-pack [--unpack=executable] <git-dir> [heads]";
   6
   7static const char *unpacker = "git-unpack-objects";
   8
   9static int path_match(const char *path, int nr, char **match)
  10{
  11        int i;
  12        int pathlen = strlen(path);
  13
  14        for (i = 0; i < nr; i++) {
  15                char *s = match[i];
  16                int len = strlen(s);
  17
  18                if (!len || len > pathlen)
  19                        continue;
  20                if (memcmp(path + pathlen - len, s, len))
  21                        continue;
  22                if (pathlen > len && path[pathlen - len - 1] != '/')
  23                        continue;
  24                *s = 0;
  25                return 1;
  26        }
  27        return 0;
  28}
  29
  30static void show_ref(const char *path, unsigned char *sha1)
  31{
  32        packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
  33}
  34
  35static int read_ref(const char *path, unsigned char *sha1)
  36{
  37        int ret = -1;
  38        int fd = open(path, O_RDONLY);
  39
  40        if (fd >= 0) {
  41                char buffer[60];
  42                if (read(fd, buffer, sizeof(buffer)) >= 40)
  43                        ret = get_sha1_hex(buffer, sha1);
  44                close(fd);
  45        }
  46        return ret;
  47}
  48
  49static void write_head_info(const char *base, int nr, char **match)
  50{
  51        DIR *dir = opendir(base);
  52
  53        if (dir) {
  54                struct dirent *de;
  55                int baselen = strlen(base);
  56                char *path = xmalloc(baselen + 257);
  57                memcpy(path, base, baselen);
  58
  59                while ((de = readdir(dir)) != NULL) {
  60                        char sha1[20];
  61                        struct stat st;
  62                        int namelen;
  63
  64                        if (de->d_name[0] == '.')
  65                                continue;
  66                        namelen = strlen(de->d_name);
  67                        if (namelen > 255)
  68                                continue;
  69                        memcpy(path + baselen, de->d_name, namelen+1);
  70                        if (lstat(path, &st) < 0)
  71                                continue;
  72                        if (S_ISDIR(st.st_mode)) {
  73                                path[baselen + namelen] = '/';
  74                                path[baselen + namelen + 1] = 0;
  75                                write_head_info(path, nr, match);
  76                                continue;
  77                        }
  78                        if (read_ref(path, sha1) < 0)
  79                                continue;
  80                        if (!has_sha1_file(sha1))
  81                                continue;
  82                        if (nr && !path_match(path, nr, match))
  83                                continue;
  84                        show_ref(path, sha1);
  85                }
  86                free(path);
  87                closedir(dir);
  88        }
  89}
  90
  91struct command {
  92        struct command *next;
  93        unsigned char old_sha1[20];
  94        unsigned char new_sha1[20];
  95        char ref_name[0];
  96};
  97
  98struct command *commands = NULL;
  99
 100static int verify_old_ref(const char *name, char *hex_contents)
 101{
 102        int fd, ret;
 103        char buffer[60];
 104
 105        fd = open(name, O_RDONLY);
 106        if (fd < 0)
 107                return -1;
 108        ret = read(fd, buffer, 40);
 109        close(fd);
 110        if (ret != 40)
 111                return -1;
 112        if (memcmp(buffer, hex_contents, 40))
 113                return -1;
 114        return 0;
 115}
 116
 117static void update(const char *name, unsigned char *old_sha1, unsigned char *new_sha1)
 118{
 119        char new_hex[60], *old_hex, *lock_name;
 120        int newfd, namelen, written;
 121
 122        namelen = strlen(name);
 123        lock_name = xmalloc(namelen + 10);
 124        memcpy(lock_name, name, namelen);
 125        memcpy(lock_name + namelen, ".lock", 6);
 126
 127        strcpy(new_hex, sha1_to_hex(new_sha1));
 128        new_hex[40] = '\n';
 129        new_hex[41] = 0;
 130        old_hex = sha1_to_hex(old_sha1);
 131        if (!has_sha1_file(new_sha1))
 132                die("unpack should have generated %s, but I can't find it!", new_hex);
 133
 134        newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0644);
 135        if (newfd < 0)
 136                die("unable to create %s (%s)", lock_name, strerror(errno));
 137        written = write(newfd, new_hex, 41);
 138        close(newfd);
 139        if (written != 41) {
 140                unlink(lock_name);
 141                die("unable to write %s", lock_name);
 142        }
 143        if (verify_old_ref(name, old_hex) < 0) {
 144                unlink(lock_name);
 145                die("%s changed during push", name);
 146        }
 147        if (rename(lock_name, name) < 0) {
 148                unlink(lock_name);
 149                die("unable to replace %s", name);
 150        }
 151        fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 152}
 153
 154
 155/*
 156 * This gets called after(if) we've successfully
 157 * unpacked the data payload.
 158 */
 159static void execute_commands(void)
 160{
 161        struct command *cmd = commands;
 162
 163        while (cmd) {
 164                update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
 165                cmd = cmd->next;
 166        }
 167}
 168
 169static void read_head_info(void)
 170{
 171        struct command **p = &commands;
 172        for (;;) {
 173                static char line[1000];
 174                unsigned char old_sha1[20], new_sha1[20];
 175                struct command *cmd;
 176                int len;
 177
 178                len = packet_read_line(0, line, sizeof(line));
 179                if (!len)
 180                        break;
 181                if (line[len-1] == '\n')
 182                        line[--len] = 0;
 183                if (len < 83 ||
 184                    line[40] != ' ' ||
 185                    line[81] != ' ' ||
 186                    get_sha1_hex(line, old_sha1) ||
 187                    get_sha1_hex(line + 41, new_sha1))
 188                        die("protocol error: expected old/new/ref, got '%s'", line);
 189                cmd = xmalloc(sizeof(struct command) + len - 80);
 190                memcpy(cmd->old_sha1, old_sha1, 20);
 191                memcpy(cmd->new_sha1, new_sha1, 20);
 192                memcpy(cmd->ref_name, line + 82, len - 81);
 193                cmd->next = NULL;
 194                *p = cmd;
 195                p = &cmd->next;
 196        }
 197}
 198
 199static void unpack(void)
 200{
 201        pid_t pid = fork();
 202
 203        if (pid < 0)
 204                die("unpack fork failed");
 205        if (!pid) {
 206                execlp(unpacker, unpacker, NULL);
 207                die("unpack execute failed");
 208        }
 209
 210        for (;;) {
 211                int status, code;
 212                int retval = waitpid(pid, &status, 0);
 213
 214                if (retval < 0) {
 215                        if (errno == EINTR)
 216                                continue;
 217                        die("waitpid failed (%s)", strerror(retval));
 218                }
 219                if (retval != pid)
 220                        die("waitpid is confused");
 221                if (WIFSIGNALED(status))
 222                        die("%s died of signal %d", unpacker, WTERMSIG(status));
 223                if (!WIFEXITED(status))
 224                        die("%s died out of really strange complications", unpacker);
 225                code = WEXITSTATUS(status);
 226                if (code)
 227                        die("%s exited with error code %d", unpacker, code);
 228                return;
 229        }
 230}
 231
 232int main(int argc, char **argv)
 233{
 234        int i, nr_heads = 0;
 235        const char *dir = NULL;
 236        char **heads = NULL;
 237
 238        argv++;
 239        for (i = 1; i < argc; i++) {
 240                const char *arg = *argv++;
 241
 242                if (*arg == '-') {
 243                        if (!strncmp(arg, "--unpack=", 9)) {
 244                                unpacker = arg+9;
 245                                continue;
 246                        }
 247                        /* Do flag handling here */
 248                        usage(receive_pack_usage);
 249                }
 250                dir = arg;
 251                heads = argv;
 252                nr_heads = argc - i - 1;
 253                break;
 254        }
 255        if (!dir)
 256                usage(receive_pack_usage);
 257
 258        /* chdir to the directory. If that fails, try appending ".git" */
 259        if (chdir(dir) < 0) {
 260                static char path[PATH_MAX];
 261                snprintf(path, sizeof(path), "%s.git", dir);
 262                if (chdir(path) < 0)
 263                        die("unable to cd to %s", dir);
 264        }
 265
 266        /* If we have a ".git" directory, chdir to it */
 267        chdir(".git");
 268        setenv("GIT_DIR", ".", 1);
 269
 270        if (access("objects", X_OK) < 0 || access("refs/heads", X_OK) < 0)
 271                die("%s doesn't appear to be a git directory", dir);
 272        write_head_info("refs/", nr_heads, heads);
 273
 274        /* EOF */
 275        packet_flush(1);
 276
 277        read_head_info();
 278        if (commands) {
 279                unpack();
 280                execute_commands();
 281        }
 282        return 0;
 283}