setup.con commit Merge with master.kernel.org:/pub/scm/git/git.git (09dea56)
   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 it it looks like we're at the top
  77 * level git directory. We want to see a
  78 *
  79 *  - a HEAD symlink and a refs/ directory under ".git"
  80 *  - either a .git/objects/ directory _or_ the proper
  81 *    GIT_OBJECT_DIRECTORY environment variable
  82 */
  83static int is_toplevel_directory(void)
  84{
  85        struct stat st;
  86
  87        return  !lstat(".git/HEAD", &st) &&
  88                S_ISLNK(st.st_mode) &&
  89                !access(".git/refs/", X_OK) &&
  90                (getenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK));
  91}
  92
  93const char *setup_git_directory(void)
  94{
  95        static char cwd[PATH_MAX+1];
  96        int len, offset;
  97
  98        /*
  99         * If GIT_DIR is set explicitly, we're not going
 100         * to do any discovery
 101         */
 102        if (getenv(GIT_DIR_ENVIRONMENT))
 103                return NULL;
 104
 105        if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
 106                die("Unable to read current working directory");
 107
 108        offset = len = strlen(cwd);
 109        for (;;) {
 110                if (is_toplevel_directory())
 111                        break;
 112                chdir("..");
 113                do {
 114                        if (!offset)
 115                                die("Not a git repository");
 116                } while (cwd[--offset] != '/');
 117        }
 118
 119        if (offset == len)
 120                return NULL;
 121
 122        /* Make "offset" point to past the '/', and add a '/' at the end */
 123        offset++;
 124        cwd[len++] = '/';
 125        cwd[len] = 0;
 126        return cwd + offset;
 127}