Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 1 | #include "cache.h" |
| 2 | |
Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 3 | const char *prefix_path(const char *prefix, int len, const char *path) |
Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 4 | { |
Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 5 | const char *orig = path; |
Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 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 | |
Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 50 | const char **get_pathspec(const char *prefix, const char **pathspec) |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 51 | { |
Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 52 | const char *entry = *pathspec; |
| 53 | const char **p; |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 54 | int prefixlen; |
| 55 | |
Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 56 | if (!prefix && !entry) |
| 57 | return NULL; |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 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.. */ |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 67 | p = pathspec; |
Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 68 | prefixlen = prefix ? strlen(prefix) : 0; |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 69 | do { |
Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 70 | *p = prefix_path(prefix, prefixlen, entry); |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 71 | } while ((entry = *++p) != NULL); |
| 72 | return (const char **) pathspec; |
| 73 | } |
| 74 | |
Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 75 | /* |
| 76 | * Test it it looks like we're at the top |
| 77 | * level git directory. We want to see a |
| 78 | * |
Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 79 | * - either a .git/objects/ directory _or_ the proper |
| 80 | * GIT_OBJECT_DIRECTORY environment variable |
Junio C Hamano | 8098a17 | 2005-09-30 21:26:57 | [diff] [blame] | 81 | * - a refs/ directory under ".git" |
| 82 | * - either a HEAD symlink or a HEAD file that is formatted as |
| 83 | * a proper "ref:". |
Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 84 | */ |
| 85 | static int is_toplevel_directory(void) |
| 86 | { |
Junio C Hamano | 8098a17 | 2005-09-30 21:26:57 | [diff] [blame] | 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; |
Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 93 | } |
| 94 | |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 95 | const char *setup_git_directory(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 |
| 103 | */ |
Junio C Hamano | a9ab586 | 2005-09-09 21:48:54 | [diff] [blame] | 104 | if (getenv(GIT_DIR_ENVIRONMENT)) |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 105 | return NULL; |
| 106 | |
| 107 | if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/') |
| 108 | die("Unable to read current working directory"); |
| 109 | |
| 110 | offset = len = strlen(cwd); |
| 111 | for (;;) { |
Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 112 | if (is_toplevel_directory()) |
| 113 | break; |
Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 114 | chdir(".."); |
| 115 | do { |
| 116 | if (!offset) |
| 117 | die("Not a git repository"); |
| 118 | } while (cwd[--offset] != '/'); |
| 119 | } |
| 120 | |
| 121 | if (offset == len) |
| 122 | return NULL; |
| 123 | |
| 124 | /* Make "offset" point to past the '/', and add a '/' at the end */ |
| 125 | offset++; |
| 126 | cwd[len++] = '/'; |
| 127 | cwd[len] = 0; |
| 128 | return cwd + offset; |
| 129 | } |