setup.con commit git-mv: quote $src in regexp properly. (90109b3)
   1#include "cache.h"
   2
   3const char *prefix_path(const char *prefix, int len, const char *path)
   4{
   5        const char *orig = path;
   6        for (;;) {
   7                char c;
   8                if (*path != '.')
   9                        break;
  10                c = path[1];
  11                /* "." */
  12                if (!c) {
  13                        path++;
  14                        break;
  15                }
  16                /* "./" */
  17                if (c == '/') {
  18                        path += 2;
  19                        continue;
  20                }
  21                if (c != '.')
  22                        break;
  23                c = path[2];
  24                if (!c)
  25                        path += 2;
  26                else if (c == '/')
  27                        path += 3;
  28                else
  29                        break;
  30                /* ".." and "../" */
  31                /* Remove last component of the prefix */
  32                do {
  33                        if (!len)
  34                                die("'%s' is outside repository", orig);
  35                        len--;
  36                } while (len && prefix[len-1] != '/');
  37                continue;
  38        }
  39        if (len) {
  40                int speclen = strlen(path);
  41                char *n = xmalloc(speclen + len + 1);
  42        
  43                memcpy(n, prefix, len);
  44                memcpy(n + len, path, speclen+1);
  45                path = n;
  46        }
  47        return path;
  48}
  49
  50const char **get_pathspec(const char *prefix, const char **pathspec)
  51{
  52        const char *entry = *pathspec;
  53        const char **p;
  54        int prefixlen;
  55
  56        if (!prefix && !entry)
  57                return NULL;
  58
  59        if (!entry) {
  60                static const char *spec[2];
  61                spec[0] = prefix;
  62                spec[1] = NULL;
  63                return spec;
  64        }
  65
  66        /* Otherwise we have to re-write the entries.. */
  67        p = pathspec;
  68        prefixlen = prefix ? strlen(prefix) : 0;
  69        do {
  70                *p = prefix_path(prefix, prefixlen, entry);
  71        } while ((entry = *++p) != NULL);
  72        return (const char **) pathspec;
  73}
  74
  75/*
  76 * Test if it looks like we're at the top level git directory.
  77 * We want to see:
  78 *
  79 *  - either a .git/objects/ directory _or_ the proper
  80 *    GIT_OBJECT_DIRECTORY environment variable
  81 *  - a refs/ directory under ".git"
  82 *  - either a HEAD symlink or a HEAD file that is formatted as
  83 *    a proper "ref:".
  84 */
  85static int is_toplevel_directory(void)
  86{
  87        if (access(".git/refs/", X_OK) ||
  88            access(getenv(DB_ENVIRONMENT) ?
  89                   getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) ||
  90            validate_symref(".git/HEAD"))
  91                return 0;
  92        return 1;
  93}
  94
  95static const char *setup_git_directory_1(void)
  96{
  97        static char cwd[PATH_MAX+1];
  98        int len, offset;
  99
 100        /*
 101         * If GIT_DIR is set explicitly, we're not going
 102         * to do any discovery, but we still do repository
 103         * validation.
 104         */
 105        if (getenv(GIT_DIR_ENVIRONMENT)) {
 106                char path[PATH_MAX];
 107                int len = strlen(getenv(GIT_DIR_ENVIRONMENT));
 108                if (sizeof(path) - 40 < len)
 109                        die("'$%s' too big", GIT_DIR_ENVIRONMENT);
 110                memcpy(path, getenv(GIT_DIR_ENVIRONMENT), len);
 111                
 112                strcpy(path + len, "/refs");
 113                if (access(path, X_OK))
 114                        goto bad_dir_environ;
 115                strcpy(path + len, "/HEAD");
 116                if (validate_symref(path))
 117                        goto bad_dir_environ;
 118                if (getenv(DB_ENVIRONMENT)) {
 119                        if (access(DB_ENVIRONMENT, X_OK))
 120                                goto bad_dir_environ;
 121                }
 122                else {
 123                        strcpy(path + len, "/objects");
 124                        if (access(path, X_OK))
 125                                goto bad_dir_environ;
 126                }
 127                return NULL;
 128        bad_dir_environ:
 129                path[len] = 0;
 130                die("Not a git repository: '%s'", path);
 131        }
 132
 133        if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
 134                die("Unable to read current working directory");
 135
 136        offset = len = strlen(cwd);
 137        for (;;) {
 138                if (is_toplevel_directory())
 139                        break;
 140                chdir("..");
 141                do {
 142                        if (!offset)
 143                                die("Not a git repository");
 144                } while (cwd[--offset] != '/');
 145        }
 146
 147        if (offset == len)
 148                return NULL;
 149
 150        /* Make "offset" point to past the '/', and add a '/' at the end */
 151        offset++;
 152        cwd[len++] = '/';
 153        cwd[len] = 0;
 154        return cwd + offset;
 155}
 156
 157int check_repository_format_version(const char *var, const char *value)
 158{
 159       if (strcmp(var, "core.repositoryformatversion") == 0)
 160               repository_format_version = git_config_int(var, value);
 161       return 0;
 162}
 163
 164int check_repository_format(void)
 165{
 166        git_config(check_repository_format_version);
 167        if (GIT_REPO_VERSION < repository_format_version)
 168                die ("Expected git repo version <= %d, found %d",
 169                     GIT_REPO_VERSION, repository_format_version);
 170        return 0;
 171}
 172
 173const char *setup_git_directory(void)
 174{
 175        const char *retval = setup_git_directory_1();
 176        check_repository_format();
 177        return retval;
 178}