receive-pack.con commit Add support for "forcing" a ref on the remote side (f65fdf0)
   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 is_all_zeroes(const char *hex)
 101{
 102        int i;
 103        for (i = 0; i < 40; i++)
 104                if (*hex++ != '0')
 105                        return 0;
 106        return 1;
 107}
 108
 109static int verify_old_ref(const char *name, char *hex_contents)
 110{
 111        int fd, ret;
 112        char buffer[60];
 113
 114        if (is_all_zeroes(hex_contents))
 115                return 0;
 116        fd = open(name, O_RDONLY);
 117        if (fd < 0)
 118                return -1;
 119        ret = read(fd, buffer, 40);
 120        close(fd);
 121        if (ret != 40)
 122                return -1;
 123        if (memcmp(buffer, hex_contents, 40))
 124                return -1;
 125        return 0;
 126}
 127
 128static void update(const char *name, unsigned char *old_sha1, unsigned char *new_sha1)
 129{
 130        char new_hex[60], *old_hex, *lock_name;
 131        int newfd, namelen, written;
 132
 133        namelen = strlen(name);
 134        lock_name = xmalloc(namelen + 10);
 135        memcpy(lock_name, name, namelen);
 136        memcpy(lock_name + namelen, ".lock", 6);
 137
 138        strcpy(new_hex, sha1_to_hex(new_sha1));
 139        old_hex = sha1_to_hex(old_sha1);
 140        if (!has_sha1_file(new_sha1))
 141                die("unpack should have generated %s, but I can't find it!", new_hex);
 142
 143        newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0644);
 144        if (newfd < 0)
 145                die("unable to create %s (%s)", lock_name, strerror(errno));
 146
 147        /* Write the ref with an ending '\n' */
 148        new_hex[40] = '\n';
 149        new_hex[41] = 0;
 150        written = write(newfd, new_hex, 41);
 151        /* Remove the '\n' again */
 152        new_hex[40] = 0;
 153
 154        close(newfd);
 155        if (written != 41) {
 156                unlink(lock_name);
 157                die("unable to write %s", lock_name);
 158        }
 159        if (verify_old_ref(name, old_hex) < 0) {
 160                unlink(lock_name);
 161                die("%s changed during push", name);
 162        }
 163        if (rename(lock_name, name) < 0) {
 164                unlink(lock_name);
 165                die("unable to replace %s", name);
 166        }
 167        fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 168}
 169
 170
 171/*
 172 * This gets called after(if) we've successfully
 173 * unpacked the data payload.
 174 */
 175static void execute_commands(void)
 176{
 177        struct command *cmd = commands;
 178
 179        while (cmd) {
 180                update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
 181                cmd = cmd->next;
 182        }
 183}
 184
 185static void read_head_info(void)
 186{
 187        struct command **p = &commands;
 188        for (;;) {
 189                static char line[1000];
 190                unsigned char old_sha1[20], new_sha1[20];
 191                struct command *cmd;
 192                int len;
 193
 194                len = packet_read_line(0, line, sizeof(line));
 195                if (!len)
 196                        break;
 197                if (line[len-1] == '\n')
 198                        line[--len] = 0;
 199                if (len < 83 ||
 200                    line[40] != ' ' ||
 201                    line[81] != ' ' ||
 202                    get_sha1_hex(line, old_sha1) ||
 203                    get_sha1_hex(line + 41, new_sha1))
 204                        die("protocol error: expected old/new/ref, got '%s'", line);
 205                cmd = xmalloc(sizeof(struct command) + len - 80);
 206                memcpy(cmd->old_sha1, old_sha1, 20);
 207                memcpy(cmd->new_sha1, new_sha1, 20);
 208                memcpy(cmd->ref_name, line + 82, len - 81);
 209                cmd->next = NULL;
 210                *p = cmd;
 211                p = &cmd->next;
 212        }
 213}
 214
 215static void unpack(void)
 216{
 217        pid_t pid = fork();
 218
 219        if (pid < 0)
 220                die("unpack fork failed");
 221        if (!pid) {
 222                execlp(unpacker, unpacker, NULL);
 223                die("unpack execute failed");
 224        }
 225
 226        for (;;) {
 227                int status, code;
 228                int retval = waitpid(pid, &status, 0);
 229
 230                if (retval < 0) {
 231                        if (errno == EINTR)
 232                                continue;
 233                        die("waitpid failed (%s)", strerror(retval));
 234                }
 235                if (retval != pid)
 236                        die("waitpid is confused");
 237                if (WIFSIGNALED(status))
 238                        die("%s died of signal %d", unpacker, WTERMSIG(status));
 239                if (!WIFEXITED(status))
 240                        die("%s died out of really strange complications", unpacker);
 241                code = WEXITSTATUS(status);
 242                if (code)
 243                        die("%s exited with error code %d", unpacker, code);
 244                return;
 245        }
 246}
 247
 248int main(int argc, char **argv)
 249{
 250        int i, nr_heads = 0;
 251        const char *dir = NULL;
 252        char **heads = NULL;
 253
 254        argv++;
 255        for (i = 1; i < argc; i++) {
 256                const char *arg = *argv++;
 257
 258                if (*arg == '-') {
 259                        if (!strncmp(arg, "--unpack=", 9)) {
 260                                unpacker = arg+9;
 261                                continue;
 262                        }
 263                        /* Do flag handling here */
 264                        usage(receive_pack_usage);
 265                }
 266                dir = arg;
 267                heads = argv;
 268                nr_heads = argc - i - 1;
 269                break;
 270        }
 271        if (!dir)
 272                usage(receive_pack_usage);
 273
 274        /* chdir to the directory. If that fails, try appending ".git" */
 275        if (chdir(dir) < 0) {
 276                static char path[PATH_MAX];
 277                snprintf(path, sizeof(path), "%s.git", dir);
 278                if (chdir(path) < 0)
 279                        die("unable to cd to %s", dir);
 280        }
 281
 282        /* If we have a ".git" directory, chdir to it */
 283        chdir(".git");
 284        setenv("GIT_DIR", ".", 1);
 285
 286        if (access("objects", X_OK) < 0 || access("refs/heads", X_OK) < 0)
 287                die("%s doesn't appear to be a git directory", dir);
 288        write_head_info("refs/", nr_heads, heads);
 289
 290        /* EOF */
 291        packet_flush(1);
 292
 293        read_head_info();
 294        if (commands) {
 295                unpack();
 296                execute_commands();
 297        }
 298        return 0;
 299}