From: Junio C Hamano Date: Wed, 18 Jan 2017 23:12:16 +0000 (-0800) Subject: Merge branch 'bw/realpath-wo-chdir' X-Git-Tag: v2.12.0-rc0~61 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/1c16df23b19e8d37d896e68c92d8341d6e60b4dc?ds=inline;hp=-c Merge branch 'bw/realpath-wo-chdir' The implementation of "real_path()" was to go there with chdir(2) and call getcwd(3), but this obviously wouldn't be usable in a threaded environment. Rewrite it to manually resolve relative paths including symbolic links in path components. * bw/realpath-wo-chdir: real_path: set errno when max number of symlinks is exceeded real_path: prevent redefinition of MAXSYMLINKS --- 1c16df23b19e8d37d896e68c92d8341d6e60b4dc diff --combined dir.c index 4ac63bc940,bfa8c8a9a5..65c3e681b8 --- a/dir.c +++ b/dir.c @@@ -16,6 -16,11 +16,6 @@@ #include "varint.h" #include "ewah/ewok.h" -struct path_simplify { - int len; - const char *path; -}; - /* * Tells read_directory_recursive how a file or directory should be treated. * Values are ordered by significance, e.g. if a directory contains both @@@ -45,7 -50,7 +45,7 @@@ struct cached_dir static enum path_treatment read_directory_recursive(struct dir_struct *dir, const char *path, int len, struct untracked_cache_dir *untracked, - int check_only, const struct path_simplify *simplify); + int check_only, const struct pathspec *pathspec); static int get_dtype(struct dirent *de, const char *path, int len); int fspathcmp(const char *a, const char *b) @@@ -174,21 -179,17 +174,21 @@@ char *common_prefix(const struct pathsp int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec) { - size_t len; + char *prefix; + size_t prefix_len; /* * Calculate common prefix for the pathspec, and * use that to optimize the directory walk */ - len = common_prefix_len(pathspec); + prefix = common_prefix(pathspec); + prefix_len = prefix ? strlen(prefix) : 0; /* Read the directory and prune it */ - read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec); - return len; + read_directory(dir, prefix, prefix_len, pathspec); + + free(prefix); + return prefix_len; } int within_depth(const char *name, int namelen, @@@ -1311,7 -1312,7 +1311,7 @@@ static enum exist_status directory_exis static enum path_treatment treat_directory(struct dir_struct *dir, struct untracked_cache_dir *untracked, const char *dirname, int len, int baselen, int exclude, - const struct path_simplify *simplify) + const struct pathspec *pathspec) { /* The "len-1" is to strip the final '/' */ switch (directory_exists_in_index(dirname, len-1)) { @@@ -1340,7 -1341,7 +1340,7 @@@ untracked = lookup_untracked(dir->untracked, untracked, dirname + baselen, len - baselen); return read_directory_recursive(dir, dirname, len, - untracked, 1, simplify); + untracked, 1, pathspec); } /* @@@ -1348,33 -1349,24 +1348,33 @@@ * reading - if the path cannot possibly be in the pathspec, * return true, and we'll skip it early. */ -static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify) +static int simplify_away(const char *path, int pathlen, + const struct pathspec *pathspec) { - if (simplify) { - for (;;) { - const char *match = simplify->path; - int len = simplify->len; + int i; - if (!match) - break; - if (len > pathlen) - len = pathlen; - if (!memcmp(path, match, len)) - return 0; - simplify++; - } - return 1; + if (!pathspec || !pathspec->nr) + return 0; + + GUARD_PATHSPEC(pathspec, + PATHSPEC_FROMTOP | + PATHSPEC_MAXDEPTH | + PATHSPEC_LITERAL | + PATHSPEC_GLOB | + PATHSPEC_ICASE | + PATHSPEC_EXCLUDE); + + for (i = 0; i < pathspec->nr; i++) { + const struct pathspec_item *item = &pathspec->items[i]; + int len = item->nowildcard_len; + + if (len > pathlen) + len = pathlen; + if (!ps_strncmp(item, item->match, path, len)) + return 0; } - return 0; + + return 1; } /* @@@ -1388,33 -1380,19 +1388,33 @@@ * 2. the path is a directory prefix of some element in the * pathspec */ -static int exclude_matches_pathspec(const char *path, int len, - const struct path_simplify *simplify) -{ - if (simplify) { - for (; simplify->path; simplify++) { - if (len == simplify->len - && !memcmp(path, simplify->path, len)) - return 1; - if (len < simplify->len - && simplify->path[len] == '/' - && !memcmp(path, simplify->path, len)) - return 1; - } +static int exclude_matches_pathspec(const char *path, int pathlen, + const struct pathspec *pathspec) +{ + int i; + + if (!pathspec || !pathspec->nr) + return 0; + + GUARD_PATHSPEC(pathspec, + PATHSPEC_FROMTOP | + PATHSPEC_MAXDEPTH | + PATHSPEC_LITERAL | + PATHSPEC_GLOB | + PATHSPEC_ICASE | + PATHSPEC_EXCLUDE); + + for (i = 0; i < pathspec->nr; i++) { + const struct pathspec_item *item = &pathspec->items[i]; + int len = item->nowildcard_len; + + if (len == pathlen && + !ps_strncmp(item, item->match, path, pathlen)) + return 1; + if (len > pathlen && + item->match[pathlen] == '/' && + !ps_strncmp(item, item->match, path, pathlen)) + return 1; } return 0; } @@@ -1482,7 -1460,7 +1482,7 @@@ static enum path_treatment treat_one_pa struct untracked_cache_dir *untracked, struct strbuf *path, int baselen, - const struct path_simplify *simplify, + const struct pathspec *pathspec, int dtype, struct dirent *de) { int exclude; @@@ -1534,7 -1512,7 +1534,7 @@@ case DT_DIR: strbuf_addch(path, '/'); return treat_directory(dir, untracked, path->buf, path->len, - baselen, exclude, simplify); + baselen, exclude, pathspec); case DT_REG: case DT_LNK: return exclude ? path_excluded : path_untracked; @@@ -1546,7 -1524,7 +1546,7 @@@ static enum path_treatment treat_path_f struct cached_dir *cdir, struct strbuf *path, int baselen, - const struct path_simplify *simplify) + const struct pathspec *pathspec) { strbuf_setlen(path, baselen); if (!cdir->ucd) { @@@ -1563,7 -1541,7 +1563,7 @@@ * with check_only set. */ return read_directory_recursive(dir, path->buf, path->len, - cdir->ucd, 1, simplify); + cdir->ucd, 1, pathspec); /* * We get path_recurse in the first run when * directory_exists_in_index() returns index_nonexistent. We @@@ -1578,23 -1556,23 +1578,23 @@@ static enum path_treatment treat_path(s struct cached_dir *cdir, struct strbuf *path, int baselen, - const struct path_simplify *simplify) + const struct pathspec *pathspec) { int dtype; struct dirent *de = cdir->de; if (!de) return treat_path_fast(dir, untracked, cdir, path, - baselen, simplify); + baselen, pathspec); if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_none; strbuf_setlen(path, baselen); strbuf_addstr(path, de->d_name); - if (simplify_away(path->buf, path->len, simplify)) + if (simplify_away(path->buf, path->len, pathspec)) return path_none; dtype = DTYPE(de); - return treat_one_path(dir, untracked, path, baselen, simplify, dtype, de); + return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de); } static void add_untracked(struct untracked_cache_dir *dir, const char *name) @@@ -1725,7 -1703,7 +1725,7 @@@ static void close_cached_dir(struct cac static enum path_treatment read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, struct untracked_cache_dir *untracked, int check_only, - const struct path_simplify *simplify) + const struct pathspec *pathspec) { struct cached_dir cdir; enum path_treatment state, subdir_state, dir_state = path_none; @@@ -1741,8 -1719,7 +1741,8 @@@ while (!read_cached_dir(&cdir)) { /* check how the file or directory should be treated */ - state = treat_path(dir, untracked, &cdir, &path, baselen, simplify); + state = treat_path(dir, untracked, &cdir, &path, + baselen, pathspec); if (state > dir_state) dir_state = state; @@@ -1754,9 -1731,8 +1754,9 @@@ path.buf + baselen, path.len - baselen); subdir_state = - read_directory_recursive(dir, path.buf, path.len, - ud, check_only, simplify); + read_directory_recursive(dir, path.buf, + path.len, ud, + check_only, pathspec); if (subdir_state > dir_state) dir_state = subdir_state; } @@@ -1780,7 -1756,7 +1780,7 @@@ else if ((dir->flags & DIR_SHOW_IGNORED_TOO) || ((dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path.buf, path.len, - simplify))) + pathspec))) dir_add_ignored(dir, path.buf, path.len); break; @@@ -1811,9 -1787,36 +1811,9 @@@ static int cmp_name(const void *p1, con return name_compare(e1->name, e1->len, e2->name, e2->len); } -static struct path_simplify *create_simplify(const char **pathspec) -{ - int nr, alloc = 0; - struct path_simplify *simplify = NULL; - - if (!pathspec) - return NULL; - - for (nr = 0 ; ; nr++) { - const char *match; - ALLOC_GROW(simplify, nr + 1, alloc); - match = *pathspec++; - if (!match) - break; - simplify[nr].path = match; - simplify[nr].len = simple_length(match); - } - simplify[nr].path = NULL; - simplify[nr].len = 0; - return simplify; -} - -static void free_simplify(struct path_simplify *simplify) -{ - free(simplify); -} - static int treat_leading_path(struct dir_struct *dir, const char *path, int len, - const struct path_simplify *simplify) + const struct pathspec *pathspec) { struct strbuf sb = STRBUF_INIT; int baselen, rc = 0; @@@ -1837,9 -1840,9 +1837,9 @@@ strbuf_add(&sb, path, baselen); if (!is_directory(sb.buf)) break; - if (simplify_away(sb.buf, sb.len, simplify)) + if (simplify_away(sb.buf, sb.len, pathspec)) break; - if (treat_one_path(dir, NULL, &sb, baselen, simplify, + if (treat_one_path(dir, NULL, &sb, baselen, pathspec, DT_DIR, NULL) == path_none) break; /* do not recurse into it */ if (len <= baselen) { @@@ -2007,14 -2010,33 +2007,14 @@@ static struct untracked_cache_dir *vali return root; } -int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec) +int read_directory(struct dir_struct *dir, const char *path, + int len, const struct pathspec *pathspec) { - struct path_simplify *simplify; struct untracked_cache_dir *untracked; - /* - * Check out create_simplify() - */ - if (pathspec) - GUARD_PATHSPEC(pathspec, - PATHSPEC_FROMTOP | - PATHSPEC_MAXDEPTH | - PATHSPEC_LITERAL | - PATHSPEC_GLOB | - PATHSPEC_ICASE | - PATHSPEC_EXCLUDE); - if (has_symlink_leading_path(path, len)) return dir->nr; - /* - * exclude patterns are treated like positive ones in - * create_simplify. Usually exclude patterns should be a - * subset of positive ones, which has no impacts on - * create_simplify(). - */ - simplify = create_simplify(pathspec ? pathspec->_raw : NULL); untracked = validate_untracked_cache(dir, len, pathspec); if (!untracked) /* @@@ -2022,8 -2044,9 +2022,8 @@@ * e.g. prep_exclude() */ dir->untracked = NULL; - if (!len || treat_leading_path(dir, path, len, simplify)) - read_directory_recursive(dir, path, len, untracked, 0, simplify); - free_simplify(simplify); + if (!len || treat_leading_path(dir, path, len, pathspec)) + read_directory_recursive(dir, path, len, untracked, 0, pathspec); QSORT(dir->entries, dir->nr, cmp_name); QSORT(dir->ignored, dir->ignored_nr, cmp_name); if (dir->untracked) { @@@ -2725,40 -2748,3 +2725,40 @@@ void untracked_cache_add_to_index(struc { untracked_cache_invalidate_path(istate, path); } + +/* Update gitfile and core.worktree setting to connect work tree and git dir */ +void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_) +{ + struct strbuf file_name = STRBUF_INIT; + struct strbuf rel_path = STRBUF_INIT; - char *git_dir = xstrdup(real_path(git_dir_)); - char *work_tree = xstrdup(real_path(work_tree_)); ++ char *git_dir = real_pathdup(git_dir_); ++ char *work_tree = real_pathdup(work_tree_); + + /* Update gitfile */ + strbuf_addf(&file_name, "%s/.git", work_tree); + write_file(file_name.buf, "gitdir: %s", + relative_path(git_dir, work_tree, &rel_path)); + + /* Update core.worktree setting */ + strbuf_reset(&file_name); + strbuf_addf(&file_name, "%s/config", git_dir); + git_config_set_in_file(file_name.buf, "core.worktree", + relative_path(work_tree, git_dir, &rel_path)); + + strbuf_release(&file_name); + strbuf_release(&rel_path); + free(work_tree); + free(git_dir); +} + +/* + * Migrate the git directory of the given path from old_git_dir to new_git_dir. + */ +void relocate_gitdir(const char *path, const char *old_git_dir, const char *new_git_dir) +{ + if (rename(old_git_dir, new_git_dir) < 0) + die_errno(_("could not migrate git directory from '%s' to '%s'"), + old_git_dir, new_git_dir); + + connect_work_tree_and_git_dir(path, new_git_dir); +}