| 1 | #include "cache.h" |
| 2 | |
| 3 | const char **get_pathspec(const char *prefix, char **pathspec) |
| 4 | { |
| 5 | char *entry = *pathspec; |
| 6 | char **p; |
| 7 | int prefixlen; |
| 8 | |
| 9 | if (!prefix) { |
| 10 | char **p; |
| 11 | if (!entry) |
| 12 | return NULL; |
| 13 | p = pathspec; |
| 14 | do { |
| 15 | if (*entry != '.') |
| 16 | continue; |
| 17 | /* fixup ? */ |
| 18 | } while ((entry = *++p) != NULL); |
| 19 | return (const char **) pathspec; |
| 20 | } |
| 21 | |
| 22 | if (!entry) { |
| 23 | static const char *spec[2]; |
| 24 | spec[0] = prefix; |
| 25 | spec[1] = NULL; |
| 26 | return spec; |
| 27 | } |
| 28 | |
| 29 | /* Otherwise we have to re-write the entries.. */ |
| 30 | prefixlen = strlen(prefix); |
| 31 | p = pathspec; |
| 32 | do { |
| 33 | int speclen, len = prefixlen; |
| 34 | char *n; |
| 35 | |
| 36 | for (;;) { |
| 37 | if (!strcmp(entry, ".")) { |
| 38 | entry++; |
| 39 | break; |
| 40 | } |
| 41 | if (!strncmp(entry, "./", 2)) { |
| 42 | entry += 2; |
| 43 | continue; |
| 44 | } |
| 45 | if (!strncmp(entry, "../", 3)) { |
| 46 | do { |
| 47 | if (!len) |
| 48 | die("'%s' is outside repository", *p); |
| 49 | len--; |
| 50 | } while (len && prefix[len-1] != '/'); |
| 51 | entry += 3; |
| 52 | continue; |
| 53 | } |
| 54 | break; |
| 55 | } |
| 56 | speclen = strlen(entry); |
| 57 | n = xmalloc(speclen + len + 1); |
| 58 | |
| 59 | memcpy(n, prefix, len); |
| 60 | memcpy(n + len, entry, speclen+1); |
| 61 | *p = n; |
| 62 | } while ((entry = *++p) != NULL); |
| 63 | return (const char **) pathspec; |
| 64 | } |
| 65 | |
| 66 | const char *setup_git_directory(void) |
| 67 | { |
| 68 | static char cwd[PATH_MAX+1]; |
| 69 | int len, offset; |
| 70 | |
| 71 | /* |
| 72 | * If GIT_DIR is set explicitly, we're not going |
| 73 | * to do any discovery |
| 74 | */ |
| 75 | if (gitenv(GIT_DIR_ENVIRONMENT)) |
| 76 | return NULL; |
| 77 | |
| 78 | if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/') |
| 79 | die("Unable to read current working directory"); |
| 80 | |
| 81 | offset = len = strlen(cwd); |
| 82 | for (;;) { |
| 83 | /* |
| 84 | * We always want to see a .git/refs/ subdirectory |
| 85 | */ |
| 86 | if (!access(".git/refs/", X_OK)) { |
| 87 | /* |
| 88 | * Then we need either a GIT_OBJECT_DIRECTORY define |
| 89 | * or a .git/objects/ directory |
| 90 | */ |
| 91 | if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK)) |
| 92 | break; |
| 93 | } |
| 94 | chdir(".."); |
| 95 | do { |
| 96 | if (!offset) |
| 97 | die("Not a git repository"); |
| 98 | } while (cwd[--offset] != '/'); |
| 99 | } |
| 100 | |
| 101 | if (offset == len) |
| 102 | return NULL; |
| 103 | |
| 104 | /* Make "offset" point to past the '/', and add a '/' at the end */ |
| 105 | offset++; |
| 106 | cwd[len++] = '/'; |
| 107 | cwd[len] = 0; |
| 108 | return cwd + offset; |
| 109 | } |