| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 1 | #include "cache.h" |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 2 | #include "dir.h" |
| 3 | |
| 4 | static int inside_git_dir = -1; |
| 5 | static int inside_work_tree = -1; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 6 | |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 7 | static int sanitary_path_copy(char *dst, const char *src) |
| 8 | { |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 9 | char *dst0; |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 10 | |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 11 | if (has_dos_drive_prefix(src)) { |
| 12 | *dst++ = *src++; |
| 13 | *dst++ = *src++; |
| 14 | } |
| 15 | dst0 = dst; |
| 16 | |
| 17 | if (is_dir_sep(*src)) { |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 18 | *dst++ = '/'; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 19 | while (is_dir_sep(*src)) |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 20 | src++; |
| 21 | } |
| 22 | |
| 23 | for (;;) { |
| 24 | char c = *src; |
| 25 | |
| 26 | /* |
| 27 | * A path component that begins with . could be |
| 28 | * special: |
| 29 | * (1) "." and ends -- ignore and terminate. |
| 30 | * (2) "./" -- ignore them, eat slash and continue. |
| 31 | * (3) ".." and ends -- strip one and terminate. |
| 32 | * (4) "../" -- strip one, eat slash and continue. |
| 33 | */ |
| 34 | if (c == '.') { |
| Johannes Sixt | 4cd148d | 2008-03-01 20:11:14 | [diff] [blame] | 35 | if (!src[1]) { |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 36 | /* (1) */ |
| 37 | src++; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 38 | } else if (is_dir_sep(src[1])) { |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 39 | /* (2) */ |
| 40 | src += 2; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 41 | while (is_dir_sep(*src)) |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 42 | src++; |
| 43 | continue; |
| Johannes Sixt | 4cd148d | 2008-03-01 20:11:14 | [diff] [blame] | 44 | } else if (src[1] == '.') { |
| 45 | if (!src[2]) { |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 46 | /* (3) */ |
| 47 | src += 2; |
| 48 | goto up_one; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 49 | } else if (is_dir_sep(src[2])) { |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 50 | /* (4) */ |
| 51 | src += 3; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 52 | while (is_dir_sep(*src)) |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 53 | src++; |
| 54 | goto up_one; |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | /* copy up to the next '/', and eat all '/' */ |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 60 | while ((c = *src++) != '\0' && !is_dir_sep(c)) |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 61 | *dst++ = c; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 62 | if (is_dir_sep(c)) { |
| 63 | *dst++ = '/'; |
| 64 | while (is_dir_sep(c)) |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 65 | c = *src++; |
| 66 | src--; |
| 67 | } else if (!c) |
| 68 | break; |
| 69 | continue; |
| 70 | |
| 71 | up_one: |
| 72 | /* |
| 73 | * dst0..dst is prefix portion, and dst[-1] is '/'; |
| 74 | * go up one level. |
| 75 | */ |
| 76 | dst -= 2; /* go past trailing '/' if any */ |
| 77 | if (dst < dst0) |
| 78 | return -1; |
| 79 | while (1) { |
| 80 | if (dst <= dst0) |
| 81 | break; |
| 82 | c = *dst--; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 83 | if (c == '/') { /* MinGW: cannot be '\\' anymore */ |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 84 | dst += 2; |
| 85 | break; |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | *dst = '\0'; |
| 90 | return 0; |
| 91 | } |
| 92 | |
| Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 93 | const char *prefix_path(const char *prefix, int len, const char *path) |
| Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 94 | { |
| Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 95 | const char *orig = path; |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 96 | char *sanitized = xmalloc(len + strlen(path) + 1); |
| Johannes Sixt | 9a13ba1 | 2008-02-19 21:29:40 | [diff] [blame] | 97 | if (is_absolute_path(orig)) |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 98 | strcpy(sanitized, path); |
| 99 | else { |
| 100 | if (len) |
| 101 | memcpy(sanitized, prefix, len); |
| 102 | strcpy(sanitized + len, path); |
| Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 103 | } |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 104 | if (sanitary_path_copy(sanitized, sanitized)) |
| 105 | goto error_out; |
| Johannes Sixt | 9a13ba1 | 2008-02-19 21:29:40 | [diff] [blame] | 106 | if (is_absolute_path(orig)) { |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 107 | const char *work_tree = get_git_work_tree(); |
| 108 | size_t len = strlen(work_tree); |
| 109 | size_t total = strlen(sanitized) + 1; |
| 110 | if (strncmp(sanitized, work_tree, len) || |
| 111 | (sanitized[len] != '\0' && sanitized[len] != '/')) { |
| 112 | error_out: |
| Dmitry Potapov | 62525ef | 2008-10-05 00:40:36 | [diff] [blame] | 113 | die("'%s' is outside repository", orig); |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 114 | } |
| 115 | if (sanitized[len] == '/') |
| 116 | len++; |
| 117 | memmove(sanitized, sanitized + len, total - len); |
| Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 118 | } |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 119 | return sanitized; |
| Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 120 | } |
| 121 | |
| Junio C Hamano | a6080a0 | 2007-06-07 07:04:01 | [diff] [blame] | 122 | /* |
| Junio C Hamano | 4ca0660 | 2005-11-26 07:14:15 | [diff] [blame] | 123 | * Unlike prefix_path, this should be used if the named file does |
| 124 | * not have to interact with index entry; i.e. name of a random file |
| 125 | * on the filesystem. |
| 126 | */ |
| 127 | const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) |
| 128 | { |
| 129 | static char path[PATH_MAX]; |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 130 | #ifndef __MINGW32__ |
| Steffen Prohaska | ecf4831 | 2007-11-25 22:29:03 | [diff] [blame] | 131 | if (!pfx || !*pfx || is_absolute_path(arg)) |
| Junio C Hamano | 4ca0660 | 2005-11-26 07:14:15 | [diff] [blame] | 132 | return arg; |
| 133 | memcpy(path, pfx, pfx_len); |
| 134 | strcpy(path + pfx_len, arg); |
| Johannes Sixt | 25fe217 | 2008-03-05 20:51:27 | [diff] [blame] | 135 | #else |
| 136 | char *p; |
| 137 | /* don't add prefix to absolute paths, but still replace '\' by '/' */ |
| 138 | if (is_absolute_path(arg)) |
| 139 | pfx_len = 0; |
| 140 | else |
| 141 | memcpy(path, pfx, pfx_len); |
| 142 | strcpy(path + pfx_len, arg); |
| 143 | for (p = path + pfx_len; *p; p++) |
| 144 | if (*p == '\\') |
| 145 | *p = '/'; |
| 146 | #endif |
| Junio C Hamano | 4ca0660 | 2005-11-26 07:14:15 | [diff] [blame] | 147 | return path; |
| 148 | } |
| 149 | |
| Linus Torvalds | e23d0b4 | 2006-04-26 17:15:54 | [diff] [blame] | 150 | /* |
| 151 | * Verify a filename that we got as an argument for a pathspec |
| 152 | * entry. Note that a filename that begins with "-" never verifies |
| 153 | * as true, because even if such a filename were to exist, we want |
| 154 | * it to be preceded by the "--" marker (or we want the user to |
| 155 | * use a format like "./-filename") |
| 156 | */ |
| 157 | void verify_filename(const char *prefix, const char *arg) |
| 158 | { |
| 159 | const char *name; |
| 160 | struct stat st; |
| 161 | |
| 162 | if (*arg == '-') |
| 163 | die("bad flag '%s' used after filename", arg); |
| 164 | name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg; |
| 165 | if (!lstat(name, &st)) |
| 166 | return; |
| 167 | if (errno == ENOENT) |
| Junio C Hamano | ea92f41 | 2006-04-26 22:09:27 | [diff] [blame] | 168 | die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" |
| 169 | "Use '--' to separate paths from revisions", arg); |
| Linus Torvalds | e23d0b4 | 2006-04-26 17:15:54 | [diff] [blame] | 170 | die("'%s': %s", arg, strerror(errno)); |
| 171 | } |
| 172 | |
| Junio C Hamano | ea92f41 | 2006-04-26 22:09:27 | [diff] [blame] | 173 | /* |
| 174 | * Opposite of the above: the command line did not have -- marker |
| 175 | * and we parsed the arg as a refname. It should not be interpretable |
| 176 | * as a filename. |
| 177 | */ |
| 178 | void verify_non_filename(const char *prefix, const char *arg) |
| 179 | { |
| 180 | const char *name; |
| 181 | struct stat st; |
| 182 | |
| Matthias Lederhofer | 7ae3df8 | 2007-06-03 14:48:16 | [diff] [blame] | 183 | if (!is_inside_work_tree() || is_inside_git_dir()) |
| Johannes Schindelin | 6802563 | 2007-01-20 02:09:34 | [diff] [blame] | 184 | return; |
| Junio C Hamano | ea92f41 | 2006-04-26 22:09:27 | [diff] [blame] | 185 | if (*arg == '-') |
| 186 | return; /* flag */ |
| 187 | name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg; |
| 188 | if (!lstat(name, &st)) |
| 189 | die("ambiguous argument '%s': both revision and filename\n" |
| 190 | "Use '--' to separate filenames from revisions", arg); |
| Junio C Hamano | 33a798c | 2007-08-06 07:20:06 | [diff] [blame] | 191 | if (errno != ENOENT && errno != ENOTDIR) |
| Junio C Hamano | ea92f41 | 2006-04-26 22:09:27 | [diff] [blame] | 192 | die("'%s': %s", arg, strerror(errno)); |
| 193 | } |
| 194 | |
| Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 195 | const char **get_pathspec(const char *prefix, const char **pathspec) |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 196 | { |
| Junio C Hamano | 6b5ee13 | 2005-09-21 07:00:47 | [diff] [blame] | 197 | const char *entry = *pathspec; |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 198 | const char **src, **dst; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 199 | int prefixlen; |
| 200 | |
| Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 201 | if (!prefix && !entry) |
| 202 | return NULL; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 203 | |
| 204 | if (!entry) { |
| 205 | static const char *spec[2]; |
| 206 | spec[0] = prefix; |
| 207 | spec[1] = NULL; |
| 208 | return spec; |
| 209 | } |
| 210 | |
| 211 | /* Otherwise we have to re-write the entries.. */ |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 212 | src = pathspec; |
| 213 | dst = pathspec; |
| Linus Torvalds | f332726 | 2005-08-17 03:44:32 | [diff] [blame] | 214 | prefixlen = prefix ? strlen(prefix) : 0; |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 215 | while (*src) { |
| 216 | const char *p = prefix_path(prefix, prefixlen, *src); |
| Dmitry Potapov | 62525ef | 2008-10-05 00:40:36 | [diff] [blame] | 217 | *(dst++) = p; |
| Junio C Hamano | d089eba | 2008-01-29 06:44:27 | [diff] [blame] | 218 | src++; |
| 219 | } |
| 220 | *dst = NULL; |
| 221 | if (!*pathspec) |
| 222 | return NULL; |
| 223 | return pathspec; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 224 | } |
| 225 | |
| Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 226 | /* |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 227 | * Test if it looks like we're at a git directory. |
| Junio C Hamano | 5e7bfe2 | 2005-11-25 23:43:41 | [diff] [blame] | 228 | * We want to see: |
| Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 229 | * |
| Jim Meyering | 790296f | 2008-01-03 14:18:07 | [diff] [blame] | 230 | * - either an objects/ directory _or_ the proper |
| Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 231 | * GIT_OBJECT_DIRECTORY environment variable |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 232 | * - a refs/ directory |
| Junio C Hamano | 8098a17 | 2005-09-30 21:26:57 | [diff] [blame] | 233 | * - either a HEAD symlink or a HEAD file that is formatted as |
| Junio C Hamano | c847f53 | 2007-01-02 07:31:08 | [diff] [blame] | 234 | * a proper "ref:", or a regular file HEAD that has a properly |
| 235 | * formatted sha1 object name. |
| Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 236 | */ |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 237 | static int is_git_directory(const char *suspect) |
| Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 238 | { |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 239 | char path[PATH_MAX]; |
| 240 | size_t len = strlen(suspect); |
| 241 | |
| 242 | strcpy(path, suspect); |
| 243 | if (getenv(DB_ENVIRONMENT)) { |
| 244 | if (access(getenv(DB_ENVIRONMENT), X_OK)) |
| 245 | return 0; |
| 246 | } |
| 247 | else { |
| 248 | strcpy(path + len, "/objects"); |
| 249 | if (access(path, X_OK)) |
| 250 | return 0; |
| 251 | } |
| 252 | |
| 253 | strcpy(path + len, "/refs"); |
| 254 | if (access(path, X_OK)) |
| Junio C Hamano | 8098a17 | 2005-09-30 21:26:57 | [diff] [blame] | 255 | return 0; |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 256 | |
| 257 | strcpy(path + len, "/HEAD"); |
| Junio C Hamano | c847f53 | 2007-01-02 07:31:08 | [diff] [blame] | 258 | if (validate_headref(path)) |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 259 | return 0; |
| 260 | |
| Junio C Hamano | 8098a17 | 2005-09-30 21:26:57 | [diff] [blame] | 261 | return 1; |
| Linus Torvalds | 5f5608b | 2005-08-27 20:54:42 | [diff] [blame] | 262 | } |
| 263 | |
| Johannes Schindelin | 6802563 | 2007-01-20 02:09:34 | [diff] [blame] | 264 | int is_inside_git_dir(void) |
| 265 | { |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 266 | if (inside_git_dir < 0) |
| 267 | inside_git_dir = is_inside_dir(get_git_dir()); |
| 268 | return inside_git_dir; |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 269 | } |
| Johannes Schindelin | 6802563 | 2007-01-20 02:09:34 | [diff] [blame] | 270 | |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 271 | int is_inside_work_tree(void) |
| 272 | { |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 273 | if (inside_work_tree < 0) |
| 274 | inside_work_tree = is_inside_dir(get_git_work_tree()); |
| 275 | return inside_work_tree; |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 276 | } |
| 277 | |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 278 | /* |
| Johannes Schindelin | 7efeb8f | 2007-08-05 13:12:53 | [diff] [blame] | 279 | * set_work_tree() is only ever called if you set GIT_DIR explicitely. |
| 280 | * The old behaviour (which we retain here) is to set the work tree root |
| 281 | * to the cwd, unless overridden by the config, the command line, or |
| 282 | * GIT_WORK_TREE. |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 283 | */ |
| Johannes Schindelin | 7efeb8f | 2007-08-05 13:12:53 | [diff] [blame] | 284 | static const char *set_work_tree(const char *dir) |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 285 | { |
| Johannes Schindelin | 7efeb8f | 2007-08-05 13:12:53 | [diff] [blame] | 286 | char buffer[PATH_MAX + 1]; |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 287 | |
| Johannes Schindelin | 7efeb8f | 2007-08-05 13:12:53 | [diff] [blame] | 288 | if (!getcwd(buffer, sizeof(buffer))) |
| 289 | die ("Could not get the current working directory"); |
| 290 | git_work_tree_cfg = xstrdup(buffer); |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 291 | inside_work_tree = 1; |
| 292 | |
| Johannes Schindelin | 7efeb8f | 2007-08-05 13:12:53 | [diff] [blame] | 293 | return NULL; |
| Johannes Schindelin | 6802563 | 2007-01-20 02:09:34 | [diff] [blame] | 294 | } |
| 295 | |
| Junio C Hamano | f3fa183 | 2007-11-08 23:35:32 | [diff] [blame] | 296 | void setup_work_tree(void) |
| 297 | { |
| Johannes Schindelin | 354e653 | 2007-11-09 11:34:07 | [diff] [blame] | 298 | const char *work_tree, *git_dir; |
| 299 | static int initialized = 0; |
| 300 | |
| 301 | if (initialized) |
| 302 | return; |
| 303 | work_tree = get_git_work_tree(); |
| 304 | git_dir = get_git_dir(); |
| Mike Hommey | 59f0f2f | 2007-11-03 11:23:11 | [diff] [blame] | 305 | if (!is_absolute_path(git_dir)) |
| Linus Torvalds | 044bbbc | 2008-06-19 19:34:06 | [diff] [blame] | 306 | git_dir = make_absolute_path(git_dir); |
| Mike Hommey | 59f0f2f | 2007-11-03 11:23:11 | [diff] [blame] | 307 | if (!work_tree || chdir(work_tree)) |
| 308 | die("This operation must be run in a work tree"); |
| Linus Torvalds | 044bbbc | 2008-06-19 19:34:06 | [diff] [blame] | 309 | set_git_dir(make_relative_path(git_dir, work_tree)); |
| Johannes Schindelin | 354e653 | 2007-11-09 11:34:07 | [diff] [blame] | 310 | initialized = 1; |
| Mike Hommey | 59f0f2f | 2007-11-03 11:23:11 | [diff] [blame] | 311 | } |
| 312 | |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 313 | static int check_repository_format_gently(int *nongit_ok) |
| 314 | { |
| Johannes Schindelin | ef90d6d | 2008-05-14 17:46:53 | [diff] [blame] | 315 | git_config(check_repository_format_version, NULL); |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 316 | if (GIT_REPO_VERSION < repository_format_version) { |
| 317 | if (!nongit_ok) |
| 318 | die ("Expected git repo version <= %d, found %d", |
| 319 | GIT_REPO_VERSION, repository_format_version); |
| 320 | warning("Expected git repo version <= %d, found %d", |
| 321 | GIT_REPO_VERSION, repository_format_version); |
| 322 | warning("Please upgrade Git"); |
| 323 | *nongit_ok = -1; |
| 324 | return -1; |
| 325 | } |
| 326 | return 0; |
| 327 | } |
| 328 | |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 329 | /* |
| Lars Hjemli | b44ebb1 | 2008-02-20 22:13:13 | [diff] [blame] | 330 | * Try to read the location of the git directory from the .git file, |
| 331 | * return path to git directory if found. |
| 332 | */ |
| 333 | const char *read_gitfile_gently(const char *path) |
| 334 | { |
| 335 | char *buf; |
| 336 | struct stat st; |
| 337 | int fd; |
| 338 | size_t len; |
| 339 | |
| 340 | if (stat(path, &st)) |
| 341 | return NULL; |
| 342 | if (!S_ISREG(st.st_mode)) |
| 343 | return NULL; |
| 344 | fd = open(path, O_RDONLY); |
| 345 | if (fd < 0) |
| 346 | die("Error opening %s: %s", path, strerror(errno)); |
| 347 | buf = xmalloc(st.st_size + 1); |
| 348 | len = read_in_full(fd, buf, st.st_size); |
| 349 | close(fd); |
| 350 | if (len != st.st_size) |
| 351 | die("Error reading %s", path); |
| 352 | buf[len] = '\0'; |
| 353 | if (prefixcmp(buf, "gitdir: ")) |
| 354 | die("Invalid gitfile format: %s", path); |
| 355 | while (buf[len - 1] == '\n' || buf[len - 1] == '\r') |
| 356 | len--; |
| 357 | if (len < 9) |
| 358 | die("No path in gitfile: %s", path); |
| 359 | buf[len] = '\0'; |
| 360 | if (!is_git_directory(buf + 8)) |
| 361 | die("Not a git repository: %s", buf + 8); |
| 362 | path = make_absolute_path(buf + 8); |
| 363 | free(buf); |
| 364 | return path; |
| 365 | } |
| 366 | |
| 367 | /* |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 368 | * We cannot decide in this function whether we are in the work tree or |
| 369 | * not, since the config can only be read _after_ this function was called. |
| 370 | */ |
| Junio C Hamano | 4ca0660 | 2005-11-26 07:14:15 | [diff] [blame] | 371 | const char *setup_git_directory_gently(int *nongit_ok) |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 372 | { |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 373 | const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); |
| David Reiss | 0454dd9 | 2008-05-20 06:49:26 | [diff] [blame] | 374 | const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT); |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 375 | static char cwd[PATH_MAX+1]; |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 376 | const char *gitdirenv; |
| Lars Hjemli | b44ebb1 | 2008-02-20 22:13:13 | [diff] [blame] | 377 | const char *gitfile_dir; |
| David Reiss | 0454dd9 | 2008-05-20 06:49:26 | [diff] [blame] | 378 | int len, offset, ceil_offset; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 379 | |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 380 | /* |
| SZEDER Gábor | af05d67 | 2008-03-25 21:06:26 | [diff] [blame] | 381 | * Let's assume that we are in a git repository. |
| 382 | * If it turns out later that we are somewhere else, the value will be |
| 383 | * updated accordingly. |
| 384 | */ |
| 385 | if (nongit_ok) |
| 386 | *nongit_ok = 0; |
| 387 | |
| 388 | /* |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 389 | * If GIT_DIR is set explicitly, we're not going |
| 390 | * to do any discovery, but we still do repository |
| 391 | * validation. |
| 392 | */ |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 393 | gitdirenv = getenv(GIT_DIR_ENVIRONMENT); |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 394 | if (gitdirenv) { |
| 395 | if (PATH_MAX - 40 < strlen(gitdirenv)) |
| 396 | die("'$%s' too big", GIT_DIR_ENVIRONMENT); |
| 397 | if (is_git_directory(gitdirenv)) { |
| Johannes Schindelin | dd5c8af | 2007-10-16 23:37:36 | [diff] [blame] | 398 | static char buffer[1024 + 1]; |
| 399 | const char *retval; |
| 400 | |
| Nguyễn Thái Ngọc Duy | 138dd1e | 2007-11-29 12:21:39 | [diff] [blame] | 401 | if (!work_tree_env) { |
| 402 | retval = set_work_tree(gitdirenv); |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 403 | /* config may override worktree */ |
| 404 | if (check_repository_format_gently(nongit_ok)) |
| 405 | return NULL; |
| Nguyễn Thái Ngọc Duy | 138dd1e | 2007-11-29 12:21:39 | [diff] [blame] | 406 | return retval; |
| 407 | } |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 408 | if (check_repository_format_gently(nongit_ok)) |
| 409 | return NULL; |
| Johannes Schindelin | dd5c8af | 2007-10-16 23:37:36 | [diff] [blame] | 410 | retval = get_relative_cwd(buffer, sizeof(buffer) - 1, |
| 411 | get_git_work_tree()); |
| 412 | if (!retval || !*retval) |
| 413 | return NULL; |
| 414 | set_git_dir(make_absolute_path(gitdirenv)); |
| 415 | if (chdir(work_tree_env) < 0) |
| 416 | die ("Could not chdir to %s", work_tree_env); |
| 417 | strcat(buffer, "/"); |
| 418 | return retval; |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 419 | } |
| Johannes Schindelin | 3a3c3fc | 2006-08-04 15:46:19 | [diff] [blame] | 420 | if (nongit_ok) { |
| Matthias Lederhofer | 41e95f6 | 2006-07-30 01:30:29 | [diff] [blame] | 421 | *nongit_ok = 1; |
| 422 | return NULL; |
| 423 | } |
| Shawn O. Pearce | ad1a382 | 2006-12-31 04:30:19 | [diff] [blame] | 424 | die("Not a git repository: '%s'", gitdirenv); |
| Junio C Hamano | 5e7bfe2 | 2005-11-25 23:43:41 | [diff] [blame] | 425 | } |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 426 | |
| Junio C Hamano | f66a4d6 | 2007-07-04 19:45:42 | [diff] [blame] | 427 | if (!getcwd(cwd, sizeof(cwd)-1)) |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 428 | die("Unable to read current working directory"); |
| 429 | |
| David Reiss | 0454dd9 | 2008-05-20 06:49:26 | [diff] [blame] | 430 | ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); |
| Junio C Hamano | 17d778e | 2008-07-07 09:17:23 | [diff] [blame] | 431 | if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) |
| 432 | ceil_offset = 1; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 433 | |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 434 | /* |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 435 | * Test in the following order (relative to the cwd): |
| Lars Hjemli | b44ebb1 | 2008-02-20 22:13:13 | [diff] [blame] | 436 | * - .git (file containing "gitdir: <path>") |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 437 | * - .git/ |
| 438 | * - ./ (bare) |
| Lars Hjemli | b44ebb1 | 2008-02-20 22:13:13 | [diff] [blame] | 439 | * - ../.git |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 440 | * - ../.git/ |
| 441 | * - ../ (bare) |
| 442 | * - ../../.git/ |
| 443 | * etc. |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 444 | */ |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 445 | offset = len = strlen(cwd); |
| 446 | for (;;) { |
| Lars Hjemli | b44ebb1 | 2008-02-20 22:13:13 | [diff] [blame] | 447 | gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); |
| 448 | if (gitfile_dir) { |
| 449 | if (set_git_dir(gitfile_dir)) |
| 450 | die("Repository setup failed"); |
| 451 | break; |
| 452 | } |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 453 | if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) |
| 454 | break; |
| 455 | if (is_git_directory(".")) { |
| 456 | inside_git_dir = 1; |
| 457 | if (!work_tree_env) |
| 458 | inside_work_tree = 0; |
| 459 | setenv(GIT_DIR_ENVIRONMENT, ".", 1); |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 460 | check_repository_format_gently(nongit_ok); |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 461 | return NULL; |
| 462 | } |
| David Reiss | 0454dd9 | 2008-05-20 06:49:26 | [diff] [blame] | 463 | while (--offset > ceil_offset && cwd[offset] != '/'); |
| 464 | if (offset <= ceil_offset) { |
| 465 | if (nongit_ok) { |
| 466 | if (chdir(cwd)) |
| 467 | die("Cannot come back to cwd"); |
| 468 | *nongit_ok = 1; |
| 469 | return NULL; |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 470 | } |
| Richard Hartmann | f66bc5f | 2008-12-21 23:17:32 | [diff] [blame] | 471 | die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); |
| David Reiss | 0454dd9 | 2008-05-20 06:49:26 | [diff] [blame] | 472 | } |
| Alex Riesen | 7be77de | 2008-12-05 00:36:46 | [diff] [blame] | 473 | if (chdir("..")) |
| 474 | die("Cannot change to %s/..: %s", cwd, strerror(errno)); |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 475 | } |
| 476 | |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 477 | inside_git_dir = 0; |
| 478 | if (!work_tree_env) |
| 479 | inside_work_tree = 1; |
| 480 | git_work_tree_cfg = xstrndup(cwd, offset); |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 481 | if (check_repository_format_gently(nongit_ok)) |
| 482 | return NULL; |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 483 | if (offset == len) |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 484 | return NULL; |
| Matthias Lederhofer | 892c41b | 2007-06-06 07:10:42 | [diff] [blame] | 485 | |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 486 | /* Make "offset" point to past the '/', and add a '/' at the end */ |
| 487 | offset++; |
| 488 | cwd[len++] = '/'; |
| 489 | cwd[len] = 0; |
| 490 | return cwd + offset; |
| Linus Torvalds | d288a70 | 2005-08-17 01:06:34 | [diff] [blame] | 491 | } |
| Junio C Hamano | 5e7bfe2 | 2005-11-25 23:43:41 | [diff] [blame] | 492 | |
| Junio C Hamano | 94df250 | 2006-06-10 06:09:49 | [diff] [blame] | 493 | int git_config_perm(const char *var, const char *value) |
| 494 | { |
| Heikki Orsila | 06cbe85 | 2008-04-16 08:34:24 | [diff] [blame] | 495 | int i; |
| 496 | char *endptr; |
| 497 | |
| 498 | if (value == NULL) |
| 499 | return PERM_GROUP; |
| 500 | |
| 501 | if (!strcmp(value, "umask")) |
| 502 | return PERM_UMASK; |
| 503 | if (!strcmp(value, "group")) |
| 504 | return PERM_GROUP; |
| 505 | if (!strcmp(value, "all") || |
| 506 | !strcmp(value, "world") || |
| 507 | !strcmp(value, "everybody")) |
| 508 | return PERM_EVERYBODY; |
| 509 | |
| 510 | /* Parse octal numbers */ |
| 511 | i = strtol(value, &endptr, 8); |
| 512 | |
| 513 | /* If not an octal number, maybe true/false? */ |
| 514 | if (*endptr != 0) |
| 515 | return git_config_bool(var, value) ? PERM_GROUP : PERM_UMASK; |
| 516 | |
| 517 | /* |
| 518 | * Treat values 0, 1 and 2 as compatibility cases, otherwise it is |
| 519 | * a chmod value. |
| 520 | */ |
| 521 | switch (i) { |
| 522 | case PERM_UMASK: /* 0 */ |
| 523 | return PERM_UMASK; |
| 524 | case OLD_PERM_GROUP: /* 1 */ |
| 525 | return PERM_GROUP; |
| 526 | case OLD_PERM_EVERYBODY: /* 2 */ |
| 527 | return PERM_EVERYBODY; |
| Junio C Hamano | 94df250 | 2006-06-10 06:09:49 | [diff] [blame] | 528 | } |
| Heikki Orsila | 06cbe85 | 2008-04-16 08:34:24 | [diff] [blame] | 529 | |
| 530 | /* A filemode value was given: 0xxx */ |
| 531 | |
| 532 | if ((i & 0600) != 0600) |
| 533 | die("Problem with core.sharedRepository filemode value " |
| 534 | "(0%.3o).\nThe owner of files must always have " |
| 535 | "read and write permissions.", i); |
| 536 | |
| 537 | /* |
| 538 | * Mask filemode value. Others can not get write permission. |
| 539 | * x flags for directories are handled separately. |
| 540 | */ |
| 541 | return i & 0666; |
| Junio C Hamano | 94df250 | 2006-06-10 06:09:49 | [diff] [blame] | 542 | } |
| 543 | |
| Johannes Schindelin | ef90d6d | 2008-05-14 17:46:53 | [diff] [blame] | 544 | int check_repository_format_version(const char *var, const char *value, void *cb) |
| Junio C Hamano | ab9cb76 | 2005-11-25 23:59:09 | [diff] [blame] | 545 | { |
| Johannes Schindelin | 299726d | 2007-07-29 23:24:38 | [diff] [blame] | 546 | if (strcmp(var, "core.repositoryformatversion") == 0) |
| 547 | repository_format_version = git_config_int(var, value); |
| Johannes Schindelin | 457f06d | 2005-12-22 22:13:56 | [diff] [blame] | 548 | else if (strcmp(var, "core.sharedrepository") == 0) |
| Junio C Hamano | 94df250 | 2006-06-10 06:09:49 | [diff] [blame] | 549 | shared_repository = git_config_perm(var, value); |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 550 | else if (strcmp(var, "core.bare") == 0) { |
| 551 | is_bare_repository_cfg = git_config_bool(var, value); |
| 552 | if (is_bare_repository_cfg == 1) |
| 553 | inside_work_tree = -1; |
| 554 | } else if (strcmp(var, "core.worktree") == 0) { |
| Junio C Hamano | 180483c | 2008-02-11 19:00:32 | [diff] [blame] | 555 | if (!value) |
| 556 | return config_error_nonbool(var); |
| Jim Meyering | 8e0f700 | 2008-01-31 17:26:32 | [diff] [blame] | 557 | free(git_work_tree_cfg); |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 558 | git_work_tree_cfg = xstrdup(value); |
| 559 | inside_work_tree = -1; |
| 560 | } |
| Johannes Schindelin | 299726d | 2007-07-29 23:24:38 | [diff] [blame] | 561 | return 0; |
| Junio C Hamano | ab9cb76 | 2005-11-25 23:59:09 | [diff] [blame] | 562 | } |
| 563 | |
| 564 | int check_repository_format(void) |
| 565 | { |
| Nguyễn Thái Ngọc Duy | 9459aa7 | 2007-12-05 13:33:32 | [diff] [blame] | 566 | return check_repository_format_gently(NULL); |
| Junio C Hamano | ab9cb76 | 2005-11-25 23:59:09 | [diff] [blame] | 567 | } |
| 568 | |
| Junio C Hamano | 5e7bfe2 | 2005-11-25 23:43:41 | [diff] [blame] | 569 | const char *setup_git_directory(void) |
| 570 | { |
| Junio C Hamano | 4ca0660 | 2005-11-26 07:14:15 | [diff] [blame] | 571 | const char *retval = setup_git_directory_gently(NULL); |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 572 | |
| 573 | /* If the work tree is not the default one, recompute prefix */ |
| 574 | if (inside_work_tree < 0) { |
| 575 | static char buffer[PATH_MAX + 1]; |
| 576 | char *rel; |
| 577 | if (retval && chdir(retval)) |
| 578 | die ("Could not jump back into original cwd"); |
| 579 | rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree()); |
| Nguyễn Thái Ngọc Duy | bb52863 | 2008-08-30 09:15:32 | [diff] [blame] | 580 | if (rel && *rel && chdir(get_git_work_tree())) |
| 581 | die ("Could not jump to working directory"); |
| Johannes Schindelin | e90fdc3 | 2007-08-01 00:30:14 | [diff] [blame] | 582 | return rel && *rel ? strcat(rel, "/") : NULL; |
| 583 | } |
| 584 | |
| Junio C Hamano | 5e7bfe2 | 2005-11-25 23:43:41 | [diff] [blame] | 585 | return retval; |
| 586 | } |