setup.con commit Merge with master to get diff fixes. (6680153)
   1#include "cache.h"
   2
   3static char *prefix_path(const char *prefix, int len, char *path)
   4{
   5        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, char **pathspec)
  51{
  52        char *entry = *pathspec;
  53        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
  75const char *setup_git_directory(void)
  76{
  77        static char cwd[PATH_MAX+1];
  78        int len, offset;
  79
  80        /*
  81         * If GIT_DIR is set explicitly, we're not going
  82         * to do any discovery
  83         */
  84        if (gitenv(GIT_DIR_ENVIRONMENT))
  85                return NULL;
  86
  87        if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
  88                die("Unable to read current working directory");
  89
  90        offset = len = strlen(cwd);
  91        for (;;) {
  92                /*
  93                 * We always want to see a .git/refs/ subdirectory
  94                 */
  95                if (!access(".git/refs/", X_OK)) {
  96                        /*
  97                         * Then we need either a GIT_OBJECT_DIRECTORY define
  98                         * or a .git/objects/ directory
  99                         */
 100                        if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
 101                                break;
 102                }
 103                chdir("..");
 104                do {
 105                        if (!offset)
 106                                die("Not a git repository");
 107                } while (cwd[--offset] != '/');
 108        }
 109
 110        if (offset == len)
 111                return NULL;
 112
 113        /* Make "offset" point to past the '/', and add a '/' at the end */
 114        offset++;
 115        cwd[len++] = '/';
 116        cwd[len] = 0;
 117        return cwd + offset;
 118}