diff options
Diffstat (limited to 'path.c')
-rw-r--r-- | path.c | 94 |
1 files changed, 76 insertions, 18 deletions
@@ -148,10 +148,12 @@ void home_config_paths(char **global, char **xdg, char *file) *global = mkpathdup("%s/.gitconfig", home); } - if (!xdg_home) - *xdg = NULL; - else - *xdg = mkpathdup("%s/git/%s", xdg_home, file); + if (xdg) { + if (!xdg_home) + *xdg = NULL; + else + *xdg = mkpathdup("%s/git/%s", xdg_home, file); + } free(to_free); } @@ -249,9 +251,7 @@ int validate_headref(const char *path) static struct passwd *getpw_str(const char *username, size_t len) { struct passwd *pw; - char *username_z = xmalloc(len + 1); - memcpy(username_z, username, len); - username_z[len] = '\0'; + char *username_z = xmemdupz(username, len); pw = getpwnam(username_z); free(username_z); return pw; @@ -265,28 +265,28 @@ static struct passwd *getpw_str(const char *username, size_t len) char *expand_user_path(const char *path) { struct strbuf user_path = STRBUF_INIT; - const char *first_slash = strchrnul(path, '/'); const char *to_copy = path; if (path == NULL) goto return_null; if (path[0] == '~') { + const char *first_slash = strchrnul(path, '/'); const char *username = path + 1; size_t username_len = first_slash - username; if (username_len == 0) { const char *home = getenv("HOME"); if (!home) goto return_null; - strbuf_add(&user_path, home, strlen(home)); + strbuf_addstr(&user_path, home); } else { struct passwd *pw = getpw_str(username, username_len); if (!pw) goto return_null; - strbuf_add(&user_path, pw->pw_dir, strlen(pw->pw_dir)); + strbuf_addstr(&user_path, pw->pw_dir); } to_copy = first_slash; } - strbuf_add(&user_path, to_copy, strlen(to_copy)); + strbuf_addstr(&user_path, to_copy); return strbuf_detach(&user_path, NULL); return_null: strbuf_release(&user_path); @@ -434,6 +434,16 @@ int adjust_shared_perm(const char *path) return 0; } +static int have_same_root(const char *path1, const char *path2) +{ + int is_abs1, is_abs2; + + is_abs1 = is_absolute_path(path1); + is_abs2 = is_absolute_path(path2); + return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) || + (!is_abs1 && !is_abs2); +} + /* * Give path as relative to prefix. * @@ -454,6 +464,16 @@ const char *relative_path(const char *in, const char *prefix, else if (!prefix_len) return in; + if (have_same_root(in, prefix)) { + /* bypass dos_drive, for "c:" is identical to "C:" */ + if (has_dos_drive_prefix(in)) { + i = 2; + j = 2; + } + } else { + return in; + } + while (i < prefix_len && j < in_len && prefix[i] == in[j]) { if (is_dir_sep(prefix[i])) { while (is_dir_sep(prefix[i])) @@ -531,6 +551,51 @@ const char *relative_path(const char *in, const char *prefix, } /* + * A simpler implementation of relative_path + * + * Get relative path by removing "prefix" from "in". This function + * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter + * to increase performance when traversing the path to work_tree. + */ +const char *remove_leading_path(const char *in, const char *prefix) +{ + static char buf[PATH_MAX + 1]; + int i = 0, j = 0; + + if (!prefix || !prefix[0]) + return in; + while (prefix[i]) { + if (is_dir_sep(prefix[i])) { + if (!is_dir_sep(in[j])) + return in; + while (is_dir_sep(prefix[i])) + i++; + while (is_dir_sep(in[j])) + j++; + continue; + } else if (in[j] != prefix[i]) { + return in; + } + i++; + j++; + } + if ( + /* "/foo" is a prefix of "/foo" */ + in[j] && + /* "/foo" is not a prefix of "/foobar" */ + !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j]) + ) + return in; + while (is_dir_sep(in[j])) + j++; + if (!in[j]) + strcpy(buf, "."); + else + strcpy(buf, in + j); + return buf; +} + +/* * It is okay if dst == src, but they should not overlap otherwise. * * Performs the following normalizations on src, storing the result in dst: @@ -758,10 +823,3 @@ int daemon_avoid_alias(const char *p) } } } - -int offset_1st_component(const char *path) -{ - if (has_dos_drive_prefix(path)) - return 2 + is_dir_sep(path[2]); - return is_dir_sep(path[0]); -} |