From 7627943a1bb0cda6f37b66381a62facf9e200285 Mon Sep 17 00:00:00 2001 From: Matthias Lederhofer Date: Thu, 28 Jun 2007 16:15:25 +0200 Subject: getenv/setenv: use constants if available There were places using "GIT_DIR" instead of GIT_DIR_ENVIRONMENT and "GIT_CONFIG" instead of CONFIG_ENVIRONMENT. This makes it easier to find all places touching an environment variable using git grep or similar tools. Signed-off-by: Matthias Lederhofer Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 6395cf2309..c4ce96236a 100644 --- a/path.c +++ b/path.c @@ -252,7 +252,7 @@ char *enter_repo(char *path, int strict) if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 && validate_headref("HEAD") == 0) { - setenv("GIT_DIR", ".", 1); + setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format(); return path; } -- cgit v1.2.3 From e7a7be8831b159b9a7331b34c3ec6915d4a72190 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 25 Jul 2007 21:34:53 -0700 Subject: git_mkstemp(): be careful not to overflow the path buffer. If user's TMPDIR is insanely long, return negative after setting errno to ENAMETOOLONG, pretending that the underlying mkstemp() choked on a temporary file path that is too long. Signed-off-by: Junio C Hamano --- path.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index c4ce96236a..dfff41f626 100644 --- a/path.c +++ b/path.c @@ -71,21 +71,17 @@ char *git_path(const char *fmt, ...) /* git_mkstemp() - create tmp file honoring TMPDIR variable */ int git_mkstemp(char *path, size_t len, const char *template) { - char *env, *pch = path; - - if ((env = getenv("TMPDIR")) == NULL) { - strcpy(pch, "/tmp/"); - len -= 5; - pch += 5; - } else { - size_t n = snprintf(pch, len, "%s/", env); - - len -= n; - pch += n; + const char *tmp; + size_t n; + + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = "/tmp"; + n = snprintf(path, len, "%s/%s", tmp, template); + if (len <= n) { + errno = ENAMETOOLONG; + return -1; } - - strlcpy(pch, template, len); - return mkstemp(path); } -- cgit v1.2.3 From e5392c51469c25851f9c6e53165d75fc61901768 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 1 Aug 2007 01:28:59 +0100 Subject: Add is_absolute_path() and make_absolute_path() This patch adds convenience functions to work with absolute paths. The function is_absolute_path() should help the efforts to integrate the MinGW fork. Note that make_absolute_path() returns a pointer to a static buffer. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- path.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index dfff41f626..42609524a5 100644 --- a/path.c +++ b/path.c @@ -288,3 +288,68 @@ int adjust_shared_perm(const char *path) return -2; return 0; } + +/* We allow "recursive" symbolic links. Only within reason, though. */ +#define MAXDEPTH 5 + +const char *make_absolute_path(const char *path) +{ + 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); + } + + 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; + } + + 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 (*cwd && chdir(cwd)) + die ("Could not change back to '%s'", cwd); + + return buf; +} -- cgit v1.2.3 From e371a4c648e72673fcfdf0b45192857dd149e2f5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 2 Mar 2008 07:40:33 +0000 Subject: Fix make_absolute_path() for parameters without a slash When passing "xyz" to make_absolute_path(), make_absolute_path() erroneously tried to chdir("xyz"), and then append "/xyz". Instead, skip the chdir() completely when no slash was found. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- path.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 42609524a5..af2716199b 100644 --- a/path.c +++ b/path.c @@ -311,8 +311,10 @@ const char *make_absolute_path(const char *path) if (last_slash) { *last_slash = '\0'; last_elem = xstrdup(last_slash + 1); - } else + } else { last_elem = xstrdup(buf); + *buf = '\0'; + } } if (*buf) { -- cgit v1.2.3 From 81a24b52c164b96d37c8c50799a624e2e8ce8a57 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 5 Mar 2008 00:15:39 +0100 Subject: Do not use GUID on dir in git init --shared=all on FreeBSD It does not allow changing the bit to a non-root user. This fixes t1301-shared-repo.sh on the platform. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index af2716199b..f4ed979997 100644 --- a/path.c +++ b/path.c @@ -283,7 +283,7 @@ int adjust_shared_perm(const char *path) ? (S_IXGRP|S_IXOTH) : 0)); if (S_ISDIR(mode)) - mode |= S_ISGID; + mode |= FORCE_DIR_SET_GID; if ((mode & st.st_mode) != mode && chmod(path, mode) < 0) return -2; return 0; -- cgit v1.2.3 From 06cbe8550324e0fd2290839bf3b9a92aa53b70ab Mon Sep 17 00:00:00 2001 From: Heikki Orsila Date: Wed, 16 Apr 2008 11:34:24 +0300 Subject: Make core.sharedRepository more generic git init --shared=0xxx, where '0xxx' is an octal number, will create a repository with file modes set to '0xxx'. Users with a safe umask value (0077) can use this option to force file modes. For example, '0640' is a group-readable but not group-writable regardless of user's umask value. Values compatible with old Git versions are written as they were before, for compatibility reasons. That is, "1" for "group" and "2" for "everybody". "git config core.sharedRepository 0xxx" is also handled. Signed-off-by: Heikki Orsila Signed-off-by: Junio C Hamano --- path.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index f4ed979997..2ae7cd9975 100644 --- a/path.c +++ b/path.c @@ -266,24 +266,25 @@ int adjust_shared_perm(const char *path) if (lstat(path, &st) < 0) return -1; mode = st.st_mode; - if (mode & S_IRUSR) - mode |= (shared_repository == PERM_GROUP - ? S_IRGRP - : (shared_repository == PERM_EVERYBODY - ? (S_IRGRP|S_IROTH) - : 0)); - - if (mode & S_IWUSR) - mode |= S_IWGRP; - - if (mode & S_IXUSR) - mode |= (shared_repository == PERM_GROUP - ? S_IXGRP - : (shared_repository == PERM_EVERYBODY - ? (S_IXGRP|S_IXOTH) - : 0)); - if (S_ISDIR(mode)) + + if (shared_repository) { + int tweak = shared_repository; + if (!(mode & S_IWUSR)) + tweak &= ~0222; + mode = (mode & ~0777) | tweak; + } else { + /* Preserve old PERM_UMASK behaviour */ + if (mode & S_IWUSR) + mode |= S_IWGRP; + } + + if (S_ISDIR(mode)) { mode |= FORCE_DIR_SET_GID; + + /* Copy read bits to execute bits */ + mode |= (shared_repository & 0444) >> 2; + } + if ((mode & st.st_mode) != mode && chmod(path, mode) < 0) return -2; return 0; -- cgit v1.2.3 From 0104ca09e3abf48ab26fd0599c4b686fcff60ffc Mon Sep 17 00:00:00 2001 From: Heikki Orsila Date: Sun, 27 Apr 2008 21:21:58 +0300 Subject: Make read_in_full() and write_in_full() consistent with xread() and xwrite() xread() and xwrite() return ssize_t values as their native POSIX counterparts read(2) and write(2). To be consistent, read_in_full() and write_in_full() should also return ssize_t values. Signed-off-by: Junio C Hamano --- path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 2ae7cd9975..b7c24a2aac 100644 --- a/path.c +++ b/path.c @@ -91,7 +91,8 @@ int validate_headref(const char *path) struct stat st; char *buf, buffer[256]; unsigned char sha1[20]; - int len, fd; + int fd; + ssize_t len; if (lstat(path, &st) < 0) return -1; -- cgit v1.2.3 From ae299be0e5e610027e6492d48d70c1cbb0e9edd8 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Mon, 19 May 2008 23:48:54 -0700 Subject: Implement normalize_absolute_path normalize_absolute_path removes several oddities form absolute paths, giving nice clean paths like "/dir/sub1/sub2". Also add a test case for this utility, based on a new test program (in the style of test-sha1). Signed-off-by: David Reiss Signed-off-by: Junio C Hamano --- path.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index b7c24a2aac..7175a06ed8 100644 --- a/path.c +++ b/path.c @@ -357,3 +357,56 @@ const char *make_absolute_path(const char *path) 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; +} -- cgit v1.2.3 From 0454dd93bfb2334355ec62fff670d8c6cb3570a1 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Mon, 19 May 2008 23:49:26 -0700 Subject: Add support for GIT_CEILING_DIRECTORIES Make git recognize a new environment variable that prevents it from chdir'ing up into specified directories when looking for a GIT_DIR. Useful for avoiding slow network directories. For example, I use git in an environment where homedirs are automounted and "ls /home/nonexistent" takes about 9 seconds. Setting GIT_CEILING_DIRS="/home" allows "git help -a" (for bash completion) and "git symbolic-ref" (for my shell prompt) to run in a reasonable time. Signed-off-by: David Reiss Signed-off-by: Junio C Hamano --- path.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 7175a06ed8..0c4330486b 100644 --- a/path.c +++ b/path.c @@ -410,3 +410,46 @@ int normalize_absolute_path(char *buf, const char *path) *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; +} -- cgit v1.2.3 From 1b9a9467f8b9a8da2fe58d10ae16779492aa7737 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 5 Jun 2008 23:15:19 -0400 Subject: Use nonrelative paths instead of absolute paths for cloned repositories Particularly for the "alternates" file, if one will be created, we want a path that doesn't depend on the current directory, but we want to retain any symlinks in the path as given and any in the user's view of the current directory when the path was given. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- path.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index b7c24a2aac..4945f2abc5 100644 --- a/path.c +++ b/path.c @@ -291,6 +291,42 @@ int adjust_shared_perm(const char *path) return 0; } +static const char *get_pwd_cwd(void) +{ + 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; +} + +const char *make_nonrelative_path(const char *path) +{ + static char buf[PATH_MAX + 1]; + + if (path[0] == '/') { + 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; +} + /* We allow "recursive" symbolic links. Only within reason, though. */ #define MAXDEPTH 5 -- cgit v1.2.3 From e048a49f96172aecec96a5821a2177cbd49a24ed Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 8 Jun 2008 16:34:40 +0200 Subject: make_nonrelative_path: Use is_absolute_path() This helps porting to Windows. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 4945f2abc5..7a35a26a16 100644 --- a/path.c +++ b/path.c @@ -314,7 +314,7 @@ const char *make_nonrelative_path(const char *path) { static char buf[PATH_MAX + 1]; - if (path[0] == '/') { + if (is_absolute_path(path)) { if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die ("Too long path: %.*s", 60, path); } else { -- cgit v1.2.3 From 044bbbcb63281dfdb78344ada2c44c96122dc822 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 Jun 2008 12:34:06 -0700 Subject: Make git_dir a path relative to work_tree in setup_work_tree() Once we find the absolute paths for git_dir and work_tree, we can make git_dir a relative path since we know pwd will be work_tree. This should save the kernel some time traversing the path to work_tree all the time if git_dir is inside work_tree. Daniel's patch didn't apply for me as-is, so I recreated it with some differences, and here are the numbers from ten runs each. There is some IO for me - probably due to more-or-less random flushing of the journal - so the variation is bigger than I'd like, but whatever: Before: real 0m8.135s real 0m7.933s real 0m8.080s real 0m7.954s real 0m7.949s real 0m8.112s real 0m7.934s real 0m8.059s real 0m7.979s real 0m8.038s After: real 0m7.685s real 0m7.968s real 0m7.703s real 0m7.850s real 0m7.995s real 0m7.817s real 0m7.963s real 0m7.955s real 0m7.848s real 0m7.969s Now, going by "best of ten" (on the assumption that the longer numbers are all due to IO), I'm saying a 7.933s -> 7.685s reduction, and it does seem to be outside of the noise (ie the "after" case never broke 8s, while the "before" case did so half the time). So looks like about 3% to me. Doing it for a slightly smaller test-case (just the "arch" subdirectory) gets more stable numbers probably due to not filling the journal with metadata updates, so we have: Before: real 0m1.633s real 0m1.633s real 0m1.633s real 0m1.632s real 0m1.632s real 0m1.630s real 0m1.634s real 0m1.631s real 0m1.632s real 0m1.632s After: real 0m1.610s real 0m1.609s real 0m1.610s real 0m1.608s real 0m1.607s real 0m1.610s real 0m1.609s real 0m1.611s real 0m1.608s real 0m1.611s where I'ld just take the averages and say 1.632 vs 1.610, which is just over 1% peformance improvement. So it's not in the noise, but it's not as big as I initially thought and measured. (That said, it obviously depends on how deep the working directory path is too, and whether it is behind NFS or something else that might need to cause more work to look up). Signed-off-by: Junio C Hamano --- path.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 7a35a26a16..6e3df18499 100644 --- a/path.c +++ b/path.c @@ -330,6 +330,23 @@ const char *make_nonrelative_path(const char *path) /* We allow "recursive" symbolic links. Only within reason, though. */ #define MAXDEPTH 5 +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; +} + const char *make_absolute_path(const char *path) { static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; -- cgit v1.2.3 From 5b8e6f85f971dba8eeac048e7821978bbca14121 Mon Sep 17 00:00:00 2001 From: Dmitry Potapov Date: Sat, 28 Jun 2008 00:46:42 +0400 Subject: shrink git-shell by avoiding redundant dependencies A lot of modules that have nothing to do with git-shell functionality were linked in, bloating git-shell more than 8 times. This patch cuts off redundant dependencies by: 1. providing stubs for three functions that make no sense for git-shell; 2. moving quote_path_fully from environment.c to quote.c to make the later self sufficient; 3. moving make_absolute_path into a new separate file. The following numbers have been received with the default optimization settings on master using GCC 4.1.2: Before: text data bss dec hex filename 143915 1348 93168 238431 3a35f git-shell After: text data bss dec hex filename 17670 788 8232 26690 6842 git-shell Signed-off-by: Junio C Hamano --- path.c | 67 ------------------------------------------------------------------ 1 file changed, 67 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 6e3df18499..496123ca55 100644 --- a/path.c +++ b/path.c @@ -327,9 +327,6 @@ const char *make_nonrelative_path(const char *path) return buf; } -/* We allow "recursive" symbolic links. Only within reason, though. */ -#define MAXDEPTH 5 - const char *make_relative_path(const char *abs, const char *base) { static char buf[PATH_MAX + 1]; @@ -346,67 +343,3 @@ const char *make_relative_path(const char *abs, const char *base) strcpy(buf, abs + baselen); return buf; } - -const char *make_absolute_path(const char *path) -{ - 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'; - } - } - - 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; - } - - 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 (*cwd && chdir(cwd)) - die ("Could not change back to '%s'", cwd); - - return buf; -} -- cgit v1.2.3 From 8c6202d8696d2e3ae016042acd05f6a82763a5e3 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sat, 12 Jul 2008 03:15:03 +0200 Subject: Fix backwards-incompatible handling of core.sharedRepository 06cbe85 (Make core.sharedRepository more generic, 2008-04-16) broke the traditional setting of core.sharedRepository to true, which was to make the repository group writable: with umask 022, it would clear the permission bits for 'other'. (umask 002 did not exhibit this behaviour since pre-chmod() check in adjust_shared_perm() fails in that case.) The call to adjust_shared_perm() should only loosen the permission. If the user has umask like 022 or 002 that allow others to read, the resulting files should be made readable and writable by group, without restricting the readability by others. This patch fixes the adjust_shared_perm() mode tweak based on Junio's suggestion and adds the appropriate tests to t/t1301-shared-repo.sh. Cc: Heikki Orsila Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 6e3df18499..c1d567996d 100644 --- a/path.c +++ b/path.c @@ -272,7 +272,7 @@ int adjust_shared_perm(const char *path) int tweak = shared_repository; if (!(mode & S_IWUSR)) tweak &= ~0222; - mode = (mode & ~0777) | tweak; + mode |= tweak; } else { /* Preserve old PERM_UMASK behaviour */ if (mode & S_IWUSR) -- cgit v1.2.3 From 10c4c881c4d2cb0ece0508e7142e189e68445257 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:55 +0200 Subject: Allow add_path() to add non-existent directories to the path This function had used make_absolute_path(); but this function dies if the directory that contains the entry whose relative path was supplied in the argument does not exist. This is a problem if the argument is, for example, "../libexec/git-core", and that "../libexec" does not exist. Since the resolution of symbolic links is not required for elements in PATH, we can fall back to using make_nonrelative_path(), which simply prepends $PWD to the path. We have to move make_nonrelative_path() alongside make_absolute_path() in abspath.c so that git-shell can be linked. See 5b8e6f85f. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 504eae061f..9df447bd6d 100644 --- a/path.c +++ b/path.c @@ -291,42 +291,6 @@ int adjust_shared_perm(const char *path) return 0; } -static const char *get_pwd_cwd(void) -{ - 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; -} - -const char *make_nonrelative_path(const char *path) -{ - static char buf[PATH_MAX + 1]; - - 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; -} - const char *make_relative_path(const char *abs, const char *base) { static char buf[PATH_MAX + 1]; -- cgit v1.2.3 From 2860b57a87ba7e544d472701c83019d7624e6a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 10 Aug 2008 22:26:23 +0700 Subject: Fix typo in comments of longest_ancestor_length() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 9df447bd6d..76e8872622 100644 --- a/path.c +++ b/path.c @@ -365,7 +365,7 @@ int normalize_absolute_path(char *buf, const char *path) * path = Canonical absolute path * prefix_list = Colon-separated list of absolute paths * - * Determines, for each path in parent_list, whether the "prefix" really + * Determines, for each path in prefix_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 -- cgit v1.2.3 From 108bebeab31881654b7b0f1b5b393a6655d74d3f Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Sun, 26 Oct 2008 22:59:13 +0100 Subject: Add mksnpath which allows you to specify the output buffer This is just vsnprintf's but additionally calls cleanup_path() on the result. To be used as alternatives to mkpath() where the buffer for the created path may not be reused by subsequent calls of the same formatting function. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- path.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 76e8872622..8b64878c21 100644 --- a/path.c +++ b/path.c @@ -32,6 +32,21 @@ static char *cleanup_path(char *path) return path; } +char *mksnpath(char *buf, size_t n, const char *fmt, ...) +{ + va_list args; + unsigned len; + + va_start(args, fmt); + len = vsnprintf(buf, n, fmt, args); + va_end(args); + if (len >= n) { + snprintf(buf, n, bad_path); + return buf; + } + return cleanup_path(buf); +} + char *mkpath(const char *fmt, ...) { va_list args; -- cgit v1.2.3 From fe2d7776d5191896e361973f478ca078fa95b324 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Mon, 27 Oct 2008 10:22:21 +0100 Subject: Add git_snpath: a .git path formatting routine with output buffer The function's purpose is to replace git_path where the buffer of formatted path may not be reused by subsequent calls of the function or will be copied anyway. Signed-off-by: Junio C Hamano --- path.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 8b64878c21..85ab28a0f1 100644 --- a/path.c +++ b/path.c @@ -47,6 +47,29 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) return cleanup_path(buf); } +char *git_snpath(char *buf, size_t n, const char *fmt, ...) +{ + const char *git_dir = get_git_dir(); + va_list args; + size_t len; + + len = strlen(git_dir); + if (n < len + 1) + goto bad; + memcpy(buf, git_dir, len); + if (len && !is_dir_sep(git_dir[len-1])) + buf[len++] = '/'; + va_start(args, fmt); + len += vsnprintf(buf + len, n - len, fmt, args); + va_end(args); + if (len >= n) + goto bad; + return cleanup_path(buf); +bad: + snprintf(buf, n, bad_path); + return buf; +} + char *mkpath(const char *fmt, ...) { va_list args; -- cgit v1.2.3 From aba13e7c0566f578f866504bfcb388a72f7e5079 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Mon, 27 Oct 2008 11:17:51 +0100 Subject: git_pathdup: returns xstrdup-ed copy of the formatted path Signed-off-by: Junio C Hamano --- path.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 85ab28a0f1..092ce57190 100644 --- a/path.c +++ b/path.c @@ -47,10 +47,9 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) return cleanup_path(buf); } -char *git_snpath(char *buf, size_t n, const char *fmt, ...) +static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args) { const char *git_dir = get_git_dir(); - va_list args; size_t len; len = strlen(git_dir); @@ -59,9 +58,7 @@ char *git_snpath(char *buf, size_t n, const char *fmt, ...) memcpy(buf, git_dir, len); if (len && !is_dir_sep(git_dir[len-1])) buf[len++] = '/'; - va_start(args, fmt); len += vsnprintf(buf + len, n - len, fmt, args); - va_end(args); if (len >= n) goto bad; return cleanup_path(buf); @@ -70,6 +67,25 @@ bad: return buf; } +char *git_snpath(char *buf, size_t n, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + (void)git_vsnpath(buf, n, fmt, args); + va_end(args); + return buf; +} + +char *git_pathdup(const char *fmt, ...) +{ + char path[PATH_MAX]; + va_list args; + va_start(args, fmt); + (void)git_vsnpath(path, sizeof(path), fmt, args); + va_end(args); + return xstrdup(path); +} + char *mkpath(const char *fmt, ...) { va_list args; -- cgit v1.2.3 From 1442171bc913a9cddae5c6ad0d0a4be3a1ca86e8 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 23 Oct 2008 04:32:23 +0000 Subject: fix overlapping memcpy in normalize_absolute_path The comments for normalize_absolute_path explicitly claim that the source and destination buffers may be the same (though they may not otherwise overlap). Thus the call to memcpy may involve copying overlapping data, and memmove should be used instead. This fixes a valgrind error in t1504. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'path.c') diff --git a/path.c b/path.c index 76e8872622..c1cb54b7b8 100644 --- a/path.c +++ b/path.c @@ -348,7 +348,7 @@ int normalize_absolute_path(char *buf, const char *path) goto next; } - memcpy(dst, comp_start, comp_len); + memmove(dst, comp_start, comp_len); dst += comp_len; next: comp_start = comp_end; -- cgit v1.2.3 From 9db56f71b91153f4076a796c80c61f00edd8b700 Mon Sep 17 00:00:00 2001 From: Daniel Lowe Date: Mon, 10 Nov 2008 16:07:52 -0500 Subject: Fix non-literal format in printf-style calls These were found using gcc 4.3.2-1ubuntu11 with the warning: warning: format not a string literal and no format arguments Incorporated suggestions from Brandon Casey . Signed-off-by: Junio C Hamano --- path.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index eb24017535..a074aea649 100644 --- a/path.c +++ b/path.c @@ -41,7 +41,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) len = vsnprintf(buf, n, fmt, args); va_end(args); if (len >= n) { - snprintf(buf, n, bad_path); + strlcpy(buf, bad_path, n); return buf; } return cleanup_path(buf); @@ -63,7 +63,7 @@ static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args) goto bad; return cleanup_path(buf); bad: - snprintf(buf, n, bad_path); + strlcpy(buf, bad_path, n); return buf; } -- cgit v1.2.3 From b229d18a809c169314b7f0d048dc5a7632e8f916 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 29 Jan 2009 03:30:16 -0500 Subject: validate_headref: tighten ref-matching to just branches When we are trying to determine whether a directory contains a git repository, one of the tests we do is to check whether HEAD is either a symlink or a symref into the "refs/" hierarchy, or a detached HEAD. We can tighten this a little more, though: a non-detached HEAD should always point to a branch (since checking out anything else should result in detachment), so it is safe to check for "refs/heads/". Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- path.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index a074aea649..108d9e9599 100644 --- a/path.c +++ b/path.c @@ -154,7 +154,7 @@ int validate_headref(const char *path) /* Make sure it is a "refs/.." symlink */ if (S_ISLNK(st.st_mode)) { len = readlink(path, buffer, sizeof(buffer)-1); - if (len >= 5 && !memcmp("refs/", buffer, 5)) + if (len >= 11 && !memcmp("refs/heads/", buffer, 11)) return 0; return -1; } @@ -178,7 +178,7 @@ int validate_headref(const char *path) len -= 4; while (len && isspace(*buf)) buf++, len--; - if (len >= 5 && !memcmp("refs/", buf, 5)) + if (len >= 11 && !memcmp("refs/heads/", buf, 11)) return 0; } -- cgit v1.2.3 From f3cad0ad82e24966bf7bcc8a47670c54c30e4b18 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 7 Feb 2009 16:08:28 +0100 Subject: Move sanitary_path_copy() to path.c and rename it to normalize_path_copy() This function and normalize_absolute_path() do almost the same thing. The former already works on Windows, but the latter crashes. In subsequent changes we will remove normalize_absolute_path(). Here we make the replacement function reusable. On the way we rename it to reflect that it does some path normalization. Apart from that this is only moving around code. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index a074aea649..820eab5ac3 100644 --- a/path.c +++ b/path.c @@ -415,6 +415,92 @@ int normalize_absolute_path(char *buf, const char *path) return dst - buf; } +int normalize_path_copy(char *dst, const char *src) +{ + char *dst0; + + if (has_dos_drive_prefix(src)) { + *dst++ = *src++; + *dst++ = *src++; + } + dst0 = dst; + + if (is_dir_sep(*src)) { + *dst++ = '/'; + while (is_dir_sep(*src)) + src++; + } + + for (;;) { + char c = *src; + + /* + * A path component that begins with . could be + * special: + * (1) "." and ends -- ignore and terminate. + * (2) "./" -- ignore them, eat slash and continue. + * (3) ".." and ends -- strip one and terminate. + * (4) "../" -- strip one, eat slash and continue. + */ + if (c == '.') { + if (!src[1]) { + /* (1) */ + src++; + } else if (is_dir_sep(src[1])) { + /* (2) */ + src += 2; + while (is_dir_sep(*src)) + src++; + continue; + } else if (src[1] == '.') { + if (!src[2]) { + /* (3) */ + src += 2; + goto up_one; + } else if (is_dir_sep(src[2])) { + /* (4) */ + src += 3; + while (is_dir_sep(*src)) + src++; + goto up_one; + } + } + } + + /* copy up to the next '/', and eat all '/' */ + while ((c = *src++) != '\0' && !is_dir_sep(c)) + *dst++ = c; + if (is_dir_sep(c)) { + *dst++ = '/'; + while (is_dir_sep(c)) + c = *src++; + src--; + } else if (!c) + break; + continue; + + up_one: + /* + * dst0..dst is prefix portion, and dst[-1] is '/'; + * go up one level. + */ + dst -= 2; /* go past trailing '/' if any */ + if (dst < dst0) + return -1; + while (1) { + if (dst <= dst0) + break; + c = *dst--; + if (c == '/') { /* MinGW: cannot be '\\' anymore */ + dst += 2; + break; + } + } + } + *dst = '\0'; + return 0; +} + /* * path = Canonical absolute path * prefix_list = Colon-separated list of absolute paths -- cgit v1.2.3 From 43a7ddb55d82d5c6f0c4d2cbe408a1df71d58ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 7 Feb 2009 16:08:29 +0100 Subject: Fix GIT_CEILING_DIRECTORIES on Windows Using git with GIT_CEILING_DIRECTORIES crashed on Windows due to a failed assertion in normalize_absolute_path(): This function expects absolute paths to start with a slash, while on Windows they can start with a drive letter or a backslash. This fixes it by using the alternative, normalize_path_copy() instead, which can handle Windows-style paths just fine. Secondly, the portability macro PATH_SEP is used instead of expecting colons to be used as path list delimiter. The test script t1504 is also changed to help MSYS's bash recognize some program arguments as path list. (MSYS's bash must translate POSIX-style path lists to Windows-style path lists, and the heuristic did not catch some cases.) Signed-off-by: Rene Scharfe Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 820eab5ac3..79c5c104c3 100644 --- a/path.c +++ b/path.c @@ -524,15 +524,16 @@ int longest_ancestor_length(const char *path, const char *prefix_list) return -1; for (colon = ceil = prefix_list; *colon; ceil = colon+1) { - for (colon = ceil; *colon && *colon != ':'; colon++); + for (colon = ceil; *colon && *colon != PATH_SEP; 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 (normalize_path_copy(buf, buf) < 0) + continue; + len = strlen(buf); + if (len > 0 && buf[len-1] == '/') + buf[--len] = '\0'; if (!strncmp(path, buf, len) && path[len] == '/' && -- cgit v1.2.3 From f42302b49333d035a323f5d80fb9562d375b17f1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 7 Feb 2009 16:08:30 +0100 Subject: Test and fix normalize_path_copy() This changes the test-path-utils utility to invoke normalize_path_copy() instead of normalize_absolute_path() because the latter is about to be removed. The test cases in t0060 are adjusted in two regards: - normalize_path_copy() more often leaves a trailing slash in the result. This has no negative side effects because the new user of this function, longest_ancester_length(), already accounts for this behavior. - The function can fail. The tests uncover a flaw in normalize_path_copy(): If there are sufficiently many '..' path components so that the root is reached, such as in "/d1/s1/../../d2", then the leading slash was lost. This manifested itself that (assuming there is a repository at /tmp/foo) $ git add /d1/../tmp/foo/some-file reported 'pathspec is outside repository'. This is now fixed. Moreover, the test case descriptions of t0060 now include the test data and expected outcome. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 79c5c104c3..6b7be5b869 100644 --- a/path.c +++ b/path.c @@ -484,18 +484,12 @@ int normalize_path_copy(char *dst, const char *src) * dst0..dst is prefix portion, and dst[-1] is '/'; * go up one level. */ - dst -= 2; /* go past trailing '/' if any */ - if (dst < dst0) + dst--; /* go to trailing '/' */ + if (dst <= dst0) return -1; - while (1) { - if (dst <= dst0) - break; - c = *dst--; - if (c == '/') { /* MinGW: cannot be '\\' anymore */ - dst += 2; - break; - } - } + /* Windows: dst[-1] cannot be backslash anymore */ + while (dst0 < dst && dst[-1] != '/') + dst--; } *dst = '\0'; return 0; -- cgit v1.2.3 From f2a782b8ba189b5ed51d18aa3eb93a670c220018 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 7 Feb 2009 16:08:31 +0100 Subject: Remove unused normalize_absolute_path() This function is now superseded by normalize_path_copy(). Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 51 ++++++--------------------------------------------- 1 file changed, 6 insertions(+), 45 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 6b7be5b869..4b9107fed1 100644 --- a/path.c +++ b/path.c @@ -363,58 +363,19 @@ const char *make_relative_path(const char *abs, const char *base) } /* - * 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. + * It is okay if dst == src, but they should not overlap otherwise. * - * Performs the following normalizations on path, storing the result in buf: - * - Removes trailing slashes. - * - Removes empty components. + * Performs the following normalizations on src, storing the result in dst: + * - Ensures that components are separated by '/' (Windows only) + * - Squashes sequences of '/'. * - 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. + * Returns failure (non-zero) if a ".." component appears as first path + * component anytime during the normalization. Otherwise, returns success (0). * * 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; - } - - memmove(dst, comp_start, comp_len); - dst += comp_len; - next: - comp_start = comp_end; - } - - if (dst == buf) - *dst++ = '/'; - - *dst = '\0'; - return dst - buf; -} - int normalize_path_copy(char *dst, const char *src) { char *dst0; -- cgit v1.2.3 From 222b1673860bba6c75895ce3e2d1467fb878fa2a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 12 Feb 2009 13:02:09 -0800 Subject: Revert "validate_headref: tighten ref-matching to just branches" This reverts commit b229d18a809c169314b7f0d048dc5a7632e8f916, at least until we figure out how to work better with TopGit that points HEAD to refs/top-bases/ hierarchy. --- path.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index dd22370e8e..4b9107fed1 100644 --- a/path.c +++ b/path.c @@ -154,7 +154,7 @@ int validate_headref(const char *path) /* Make sure it is a "refs/.." symlink */ if (S_ISLNK(st.st_mode)) { len = readlink(path, buffer, sizeof(buffer)-1); - if (len >= 11 && !memcmp("refs/heads/", buffer, 11)) + if (len >= 5 && !memcmp("refs/", buffer, 5)) return 0; return -1; } @@ -178,7 +178,7 @@ int validate_headref(const char *path) len -= 4; while (len && isspace(*buf)) buf++, len--; - if (len >= 11 && !memcmp("refs/heads/", buf, 11)) + if (len >= 5 && !memcmp("refs/", buf, 5)) return 0; } -- cgit v1.2.3 From 4fcc86b07db26da17f17af0fd777cab78fcaaf4c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:10:49 +0100 Subject: Introduce the function strip_path_suffix() The function strip_path_suffix() will try to strip a given suffix from a given path. The suffix must start at a directory boundary (i.e. "core" is not a path suffix of "libexec/git-core", but "git-core" is). Arbitrary runs of directory separators ("slashes") are assumed identical. Example: strip_path_suffix("C:\\msysgit/\\libexec\\git-core", "libexec///git-core", &prefix) will set prefix to "C:\\msysgit" and return 0. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt Signed-off-by: Junio C Hamano --- path.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 4b9107fed1..e332b504a6 100644 --- a/path.c +++ b/path.c @@ -499,3 +499,39 @@ int longest_ancestor_length(const char *path, const char *prefix_list) return max_len; } + +/* strip arbitrary amount of directory separators at end of path */ +static inline int chomp_trailing_dir_sep(const char *path, int len) +{ + while (len && is_dir_sep(path[len - 1])) + len--; + return len; +} + +/* + * If path ends with suffix (complete path components), returns the + * part before suffix (sans trailing directory separators). + * Otherwise returns NULL. + */ +char *strip_path_suffix(const char *path, const char *suffix) +{ + int path_len = strlen(path), suffix_len = strlen(suffix); + + while (suffix_len) { + if (!path_len) + return NULL; + + if (is_dir_sep(path[path_len - 1])) { + if (!is_dir_sep(suffix[suffix_len - 1])) + return NULL; + path_len = chomp_trailing_dir_sep(path, path_len); + suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); + } + else if (path[--path_len] != suffix[--suffix_len]) + return NULL; + } + + if (path_len && !is_dir_sep(path[path_len - 1])) + return NULL; + return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); +} -- cgit v1.2.3 From 5a688fe4706462dfa0a7932ef0c82c335c47e9ab Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 25 Mar 2009 16:19:36 -0700 Subject: "core.sharedrepository = 0mode" should set, not loosen This fixes the behaviour of octal notation to how it is defined in the documentation, while keeping the traditional "loosen only" semantics intact for "group" and "everybody". Three main points of this patch are: - For an explicit octal notation, the internal shared_repository variable is set to a negative value, so that we can tell "group" (which is to "OR" in 0660) and 0660 (which is to "SET" to 0660); - git-init did not set shared_repository variable early enough to affect the initial creation of many files, notably copied templates and the configuration. We set it very early when a command-line option specifies a custom value. - Many codepaths create files inside $GIT_DIR by various ways that all involve mkstemp(), and then call move_temp_to_file() to rename it to its final destination. We can add adjust_shared_perm() call here; for the traditional "loosen-only", this would be a no-op for many codepaths because the mode is already loose enough, but with the new behaviour it makes a difference. Signed-off-by: Junio C Hamano --- path.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index e332b504a6..42898e0fb1 100644 --- a/path.c +++ b/path.c @@ -314,33 +314,39 @@ char *enter_repo(char *path, int strict) int adjust_shared_perm(const char *path) { struct stat st; - int mode; + int mode, tweak, shared; if (!shared_repository) return 0; if (lstat(path, &st) < 0) return -1; mode = st.st_mode; - - if (shared_repository) { - int tweak = shared_repository; - if (!(mode & S_IWUSR)) - tweak &= ~0222; + if (shared_repository < 0) + shared = -shared_repository; + else + shared = shared_repository; + tweak = shared; + + if (!(mode & S_IWUSR)) + tweak &= ~0222; + if (mode & S_IXUSR) + /* Copy read bits to execute bits */ + tweak |= (tweak & 0444) >> 2; + if (shared_repository < 0) + mode = (mode & ~0777) | tweak; + else mode |= tweak; - } else { - /* Preserve old PERM_UMASK behaviour */ - if (mode & S_IWUSR) - mode |= S_IWGRP; - } if (S_ISDIR(mode)) { - mode |= FORCE_DIR_SET_GID; - /* Copy read bits to execute bits */ - mode |= (shared_repository & 0444) >> 2; + mode |= (shared & 0444) >> 2; + mode |= FORCE_DIR_SET_GID; } - if ((mode & st.st_mode) != mode && chmod(path, mode) < 0) + if (((shared_repository < 0 + ? (st.st_mode & (FORCE_DIR_SET_GID | 0777)) + : (st.st_mode & mode)) != mode) && + chmod(path, mode) < 0) return -2; return 0; } -- cgit v1.2.3 From 17e61b82887fb71800b0fcd39ffe89ddf4d2492e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 27 Mar 2009 23:21:00 -0700 Subject: set_shared_perm(): sometimes we know what the final mode bits should look like adjust_shared_perm() first obtains the mode bits from lstat(2), expecting to find what the result of applying user's umask is, and then tweaks it as necessary. When the file to be adjusted is created with mkstemp(3), however, the mode thusly obtained does not have anything to do with user's umask, and we would need to start from 0444 in such a case and there is no point running lstat(2) for such a path. This introduces a new API set_shared_perm() to bypass the lstat(2) and instead force setting the mode bits to the desired value directly. adjust_shared_perm() becomes a thin wrapper to the function. Signed-off-by: Junio C Hamano --- path.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'path.c') diff --git a/path.c b/path.c index 42898e0fb1..8a0a6741fd 100644 --- a/path.c +++ b/path.c @@ -311,16 +311,23 @@ char *enter_repo(char *path, int strict) return NULL; } -int adjust_shared_perm(const char *path) +int set_shared_perm(const char *path, int mode) { struct stat st; - int mode, tweak, shared; + int tweak, shared, orig_mode; - if (!shared_repository) + if (!shared_repository) { + if (mode) + return chmod(path, mode & ~S_IFMT); return 0; - if (lstat(path, &st) < 0) - return -1; - mode = st.st_mode; + } + if (!mode) { + if (lstat(path, &st) < 0) + return -1; + mode = st.st_mode; + orig_mode = mode; + } else + orig_mode = 0; if (shared_repository < 0) shared = -shared_repository; else @@ -344,9 +351,9 @@ int adjust_shared_perm(const char *path) } if (((shared_repository < 0 - ? (st.st_mode & (FORCE_DIR_SET_GID | 0777)) - : (st.st_mode & mode)) != mode) && - chmod(path, mode) < 0) + ? (orig_mode & (FORCE_DIR_SET_GID | 0777)) + : (orig_mode & mode)) != mode) && + chmod(path, (mode & ~S_IFMT)) < 0) return -2; return 0; } -- cgit v1.2.3 From 003b33a8ad686ee4a0d0b36635bfd6aba940b24a Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Sun, 31 May 2009 01:35:52 -0700 Subject: diff: generate pretty filenames in prep_temp_blob() Naturally, prep_temp_blob() did not care about filenames. As a result, GIT_EXTERNAL_DIFF and textconv generated filenames such as ".diff_XXXXXX". This modifies prep_temp_blob() to generate user-friendly filenames when creating temporary files. Diffing "name.ext" now generates "XXXXXX_name.ext". Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano --- path.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'path.c') diff --git a/path.c b/path.c index 8a0a6741fd..047fdb0a1f 100644 --- a/path.c +++ b/path.c @@ -139,6 +139,22 @@ int git_mkstemp(char *path, size_t len, const char *template) return mkstemp(path); } +/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */ +int git_mkstemps(char *path, size_t len, const char *template, int suffix_len) +{ + const char *tmp; + size_t n; + + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = "/tmp"; + n = snprintf(path, len, "%s/%s", tmp, template); + if (len <= n) { + errno = ENAMETOOLONG; + return -1; + } + return mkstemps(path, suffix_len); +} int validate_headref(const char *path) { -- cgit v1.2.3