author | Junio C Hamano <gitster@pobox.com> | |
Mon, 7 Jul 2008 09:17:23 +0000 (02:17 -0700) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Mon, 7 Jul 2008 09:17:23 +0000 (02:17 -0700) |
* dr/ceiling:
Eliminate an unnecessary chdir("..")
Add support for GIT_CEILING_DIRECTORIES
Fold test-absolute-path into test-path-utils
Implement normalize_absolute_path
Conflicts:
cache.h
setup.c
Eliminate an unnecessary chdir("..")
Add support for GIT_CEILING_DIRECTORIES
Fold test-absolute-path into test-path-utils
Implement normalize_absolute_path
Conflicts:
cache.h
setup.c
1 | 2 | |||
---|---|---|---|---|
.gitignore | patch | | diff1 | | diff2 | | blob | history |
Documentation/git.txt | patch | | diff1 | | diff2 | | blob | history |
Makefile | patch | | diff1 | | diff2 | | blob | history |
cache.h | patch | | diff1 | | diff2 | | blob | history |
path.c | patch | | diff1 | | diff2 | | blob | history |
setup.c | patch | | diff1 | | diff2 | | blob | history |
t/test-lib.sh | patch | | diff1 | | diff2 | | blob | history |
diff --cc .gitignore
Simple merge
diff --cc Documentation/git.txt
Simple merge
diff --cc Makefile
Simple merge
diff --cc cache.h
index 96c43884cccd1c5703aedd88d48bb145c5d6c07d,833f4cd982e419902c0376b0e5917e272640336e..0d8eddac778ace8e4b5f58459f508ac1192dbcff
+++ b/cache.h
#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
#define CONFIG_ENVIRONMENT "GIT_CONFIG"
-#define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL"
#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
+ #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
char *enter_repo(char *path, int strict);
static inline int is_absolute_path(const char *path)
{
- return path[0] == '/';
+ return path[0] == '/' || has_dos_drive_prefix(path);
}
const char *make_absolute_path(const char *path);
+const char *make_nonrelative_path(const char *path);
+const char *make_relative_path(const char *abs, const char *base);
+ int normalize_absolute_path(char *buf, const char *path);
+ int longest_ancestor_length(const char *path, const char *prefix_list);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
diff --cc path.c
index 496123ca552a3aad32b009c668962045ec78d218,0c4330486bb83b38c14a356cebb488f4419b93fb..598325598bba8685d18d24c6331562cdf63fc05f
+++ b/path.c
return 0;
}
-/* We allow "recursive" symbolic links. Only within reason, though. */
-#define MAXDEPTH 5
-
-const char *make_absolute_path(const char *path)
+static const char *get_pwd_cwd(void)
{
- static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
- char cwd[1024] = "";
- int buf_index = 1, len;
-
- int depth = MAXDEPTH;
- char *last_elem = NULL;
- struct stat st;
-
- if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
- die ("Too long path: %.*s", 60, path);
-
- while (depth--) {
- if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
- char *last_slash = strrchr(buf, '/');
- if (last_slash) {
- *last_slash = '\0';
- last_elem = xstrdup(last_slash + 1);
- } else {
- last_elem = xstrdup(buf);
- *buf = '\0';
- }
+ static char cwd[PATH_MAX + 1];
+ char *pwd;
+ struct stat cwd_stat, pwd_stat;
+ if (getcwd(cwd, PATH_MAX) == NULL)
+ return NULL;
+ pwd = getenv("PWD");
+ if (pwd && strcmp(pwd, cwd)) {
+ stat(cwd, &cwd_stat);
+ if (!stat(pwd, &pwd_stat) &&
+ pwd_stat.st_dev == cwd_stat.st_dev &&
+ pwd_stat.st_ino == cwd_stat.st_ino) {
+ strlcpy(cwd, pwd, PATH_MAX);
}
+ }
+ return cwd;
+}
- if (*buf) {
- if (!*cwd && !getcwd(cwd, sizeof(cwd)))
- die ("Could not get current working directory");
-
- if (chdir(buf))
- die ("Could not switch to '%s'", buf);
- }
- if (!getcwd(buf, PATH_MAX))
- die ("Could not get current working directory");
-
- if (last_elem) {
- int len = strlen(buf);
- if (len + strlen(last_elem) + 2 > PATH_MAX)
- die ("Too long path name: '%s/%s'",
- buf, last_elem);
- buf[len] = '/';
- strcpy(buf + len + 1, last_elem);
- free(last_elem);
- last_elem = NULL;
- }
+const char *make_nonrelative_path(const char *path)
+{
+ static char buf[PATH_MAX + 1];
- if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
- len = readlink(buf, next_buf, PATH_MAX);
- if (len < 0)
- die ("Invalid symlink: %s", buf);
- next_buf[len] = '\0';
- buf = next_buf;
- buf_index = 1 - buf_index;
- next_buf = bufs[buf_index];
- } else
- break;
+ if (is_absolute_path(path)) {
+ if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+ die ("Too long path: %.*s", 60, path);
+ } else {
+ const char *cwd = get_pwd_cwd();
+ if (!cwd)
+ die("Cannot determine the current working directory");
+ if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
+ die ("Too long path: %.*s", 60, path);
}
+ return buf;
+}
- if (*cwd && chdir(cwd))
- die ("Could not change back to '%s'", cwd);
-
+const char *make_relative_path(const char *abs, const char *base)
+{
+ static char buf[PATH_MAX + 1];
+ int baselen;
+ if (!base)
+ return abs;
+ baselen = strlen(base);
+ if (prefixcmp(abs, base))
+ return abs;
+ if (abs[baselen] == '/')
+ baselen++;
+ else if (base[baselen - 1] != '/')
+ return abs;
+ strcpy(buf, abs + baselen);
return buf;
}
+
+ /*
+ * path = absolute path
+ * buf = buffer of at least max(2, strlen(path)+1) bytes
+ * It is okay if buf == path, but they should not overlap otherwise.
+ *
+ * Performs the following normalizations on path, storing the result in buf:
+ * - Removes trailing slashes.
+ * - Removes empty components.
+ * - Removes "." components.
+ * - Removes ".." components, and the components the precede them.
+ * "" and paths that contain only slashes are normalized to "/".
+ * Returns the length of the output.
+ *
+ * Note that this function is purely textual. It does not follow symlinks,
+ * verify the existence of the path, or make any system calls.
+ */
+ int normalize_absolute_path(char *buf, const char *path)
+ {
+ const char *comp_start = path, *comp_end = path;
+ char *dst = buf;
+ int comp_len;
+ assert(buf);
+ assert(path);
+
+ while (*comp_start) {
+ assert(*comp_start == '/');
+ while (*++comp_end && *comp_end != '/')
+ ; /* nothing */
+ comp_len = comp_end - comp_start;
+
+ if (!strncmp("/", comp_start, comp_len) ||
+ !strncmp("/.", comp_start, comp_len))
+ goto next;
+
+ if (!strncmp("/..", comp_start, comp_len)) {
+ while (dst > buf && *--dst != '/')
+ ; /* nothing */
+ goto next;
+ }
+
+ memcpy(dst, comp_start, comp_len);
+ dst += comp_len;
+ next:
+ comp_start = comp_end;
+ }
+
+ if (dst == buf)
+ *dst++ = '/';
+
+ *dst = '\0';
+ return dst - buf;
+ }
+
+ /*
+ * path = Canonical absolute path
+ * prefix_list = Colon-separated list of absolute paths
+ *
+ * Determines, for each path in parent_list, whether the "prefix" really
+ * is an ancestor directory of path. Returns the length of the longest
+ * ancestor directory, excluding any trailing slashes, or -1 if no prefix
+ * is an ancestor. (Note that this means 0 is returned if prefix_list is
+ * "/".) "/foo" is not considered an ancestor of "/foobar". Directories
+ * are not considered to be their own ancestors. path must be in a
+ * canonical form: empty components, or "." or ".." components are not
+ * allowed. prefix_list may be null, which is like "".
+ */
+ int longest_ancestor_length(const char *path, const char *prefix_list)
+ {
+ char buf[PATH_MAX+1];
+ const char *ceil, *colon;
+ int len, max_len = -1;
+
+ if (prefix_list == NULL || !strcmp(path, "/"))
+ return -1;
+
+ for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
+ for (colon = ceil; *colon && *colon != ':'; colon++);
+ len = colon - ceil;
+ if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
+ continue;
+ strlcpy(buf, ceil, len+1);
+ len = normalize_absolute_path(buf, buf);
+ /* Strip "trailing slashes" from "/". */
+ if (len == 1)
+ len = 0;
+
+ if (!strncmp(path, buf, len) &&
+ path[len] == '/' &&
+ len > max_len) {
+ max_len = len;
+ }
+ }
+
+ return max_len;
+ }
diff --cc setup.c
index cc3fb380c1f3471f0371ba54ca2f338f90a8d4fc,045ca20b32f4b512e175601fb371ac54dfce8cee..6cf909463d4ad3681a2f35269db9dc944f4389c2
+++ b/setup.c
if (!getcwd(cwd, sizeof(cwd)-1))
die("Unable to read current working directory");
- if (has_dos_drive_prefix(cwd))
- minoffset = 2;
+
+ ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
++ if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
++ ceil_offset = 1;
/*
* Test in the following order (relative to the cwd):
diff --cc t/test-lib.sh
Simple merge