/* * Utilities for paths and pathnames */ #define USE_THE_REPOSITORY_VARIABLE #include "git-compat-util.h" #include "abspath.h" #include "environment.h" #include "gettext.h" #include "repository.h" #include "strbuf.h" #include "string-list.h" #include "dir.h" #include "worktree.h" #include "setup.h" #include "submodule-config.h" #include "path.h" #include "packfile.h" #include "object-store-ll.h" #include "lockfile.h" #include "exec-cmd.h" static int get_st_mode_bits(const char *path, int *mode) { … } struct strbuf *get_pathname(void) { … } static const char *cleanup_path(const char *path) { … } static void strbuf_cleanup_path(struct strbuf *sb) { … } static int dir_prefix(const char *buf, const char *dir) { … } /* $buf =~ m|$dir/+$file| but without regex */ static int is_dir_file(const char *buf, const char *dir, const char *file) { … } static void replace_dir(struct strbuf *buf, int len, const char *newdir) { … } struct common_dir { … }; static struct common_dir common_list[] = …; /* * A compressed trie. A trie node consists of zero or more characters that * are common to all elements with this prefix, optionally followed by some * children. If value is not NULL, the trie node is a terminal node. * * For example, consider the following set of strings: * abc * def * definite * definition * * The trie would look like: * root: len = 0, children a and d non-NULL, value = NULL. * a: len = 2, contents = bc, value = (data for "abc") * d: len = 2, contents = ef, children i non-NULL, value = (data for "def") * i: len = 3, contents = nit, children e and i non-NULL, value = NULL * e: len = 0, children all NULL, value = (data for "definite") * i: len = 2, contents = on, children all NULL, * value = (data for "definition") */ struct trie { … }; static struct trie *make_trie_node(const char *key, void *value) { … } /* * Add a key/value pair to a trie. The key is assumed to be \0-terminated. * If there was an existing value for this key, return it. */ static void *add_to_trie(struct trie *root, const char *key, void *value) { … } match_fn; /* * Search a trie for some key. Find the longest /-or-\0-terminated * prefix of the key for which the trie contains a value. If there is * no such prefix, return -1. Otherwise call fn with the unmatched * portion of the key and the found value. If fn returns 0 or * positive, then return its return value. If fn returns negative, * then call fn with the next-longest /-terminated prefix of the key * (i.e. a parent directory) for which the trie contains a value, and * handle its return value the same way. If there is no shorter * /-terminated prefix with a value left, then return the negative * return value of the most recent fn invocation. * * The key is partially normalized: consecutive slashes are skipped. * * For example, consider the trie containing only [logs, * logs/refs/bisect], both with values, but not logs/refs. * * | key | unmatched | prefix to node | return value | * |--------------------|----------------|------------------|--------------| * | a | not called | n/a | -1 | * | logstore | not called | n/a | -1 | * | logs | \0 | logs | as per fn | * | logs/ | / | logs | as per fn | * | logs/refs | /refs | logs | as per fn | * | logs/refs/ | /refs/ | logs | as per fn | * | logs/refs/b | /refs/b | logs | as per fn | * | logs/refs/bisected | /refs/bisected | logs | as per fn | * | logs/refs/bisect | \0 | logs/refs/bisect | as per fn | * | logs/refs/bisect/ | / | logs/refs/bisect | as per fn | * | logs/refs/bisect/a | /a | logs/refs/bisect | as per fn | * | (If fn in the previous line returns -1, then fn is called once more:) | * | logs/refs/bisect/a | /refs/bisect/a | logs | as per fn | * |--------------------|----------------|------------------|--------------| */ static int trie_find(struct trie *root, const char *key, match_fn fn, void *baton) { … } static struct trie common_trie; static int common_trie_done_setup; static void init_common_trie(void) { … } /* * Helper function for update_common_dir: returns 1 if the dir * prefix is common. */ static int check_common(const char *unmatched, void *value, void *baton UNUSED) { … } static void update_common_dir(struct strbuf *buf, int git_dir_len, const char *common_dir) { … } void report_linked_checkout_garbage(struct repository *r) { … } static void adjust_git_path(const struct repository *repo, struct strbuf *buf, int git_dir_len) { … } static void strbuf_worktree_gitdir(struct strbuf *buf, const struct repository *repo, const struct worktree *wt) { … } void repo_git_pathv(const struct repository *repo, const struct worktree *wt, struct strbuf *buf, const char *fmt, va_list args) { … } char *repo_git_path(const struct repository *repo, const char *fmt, ...) { … } void strbuf_repo_git_path(struct strbuf *sb, const struct repository *repo, const char *fmt, ...) { … } char *mkpathdup(const char *fmt, ...) { … } const char *mkpath(const char *fmt, ...) { … } const char *worktree_git_path(struct repository *r, const struct worktree *wt, const char *fmt, ...) { … } static void do_worktree_path(const struct repository *repo, struct strbuf *buf, const char *fmt, va_list args) { … } char *repo_worktree_path(const struct repository *repo, const char *fmt, ...) { … } void strbuf_repo_worktree_path(struct strbuf *sb, const struct repository *repo, const char *fmt, ...) { … } /* Returns 0 on success, negative on failure. */ static int do_submodule_path(struct strbuf *buf, const char *path, const char *fmt, va_list args) { … } char *git_pathdup_submodule(const char *path, const char *fmt, ...) { … } int strbuf_git_path_submodule(struct strbuf *buf, const char *path, const char *fmt, ...) { … } void repo_common_pathv(const struct repository *repo, struct strbuf *sb, const char *fmt, va_list args) { … } void strbuf_git_common_path(struct strbuf *sb, const struct repository *repo, const char *fmt, ...) { … } static struct passwd *getpw_str(const char *username, size_t len) { … } /* * Return a string with ~ and ~user expanded via getpw*. Returns NULL on getpw * failure or if path is NULL. * * If real_home is true, strbuf_realpath($HOME) is used in the `~/` expansion. * * If the path starts with `%(prefix)/`, the remainder is interpreted as * relative to where Git is installed, and expanded to the absolute path. */ char *interpolate_path(const char *path, int real_home) { … } /* * First, one directory to try is determined by the following algorithm. * * (0) If "strict" is given, the path is used as given and no DWIM is * done. Otherwise: * (1) "~/path" to mean path under the running user's home directory; * (2) "~user/path" to mean path under named user's home directory; * (3) "relative/path" to mean cwd relative directory; or * (4) "/absolute/path" to mean absolute directory. * * Unless "strict" is given, we check "%s/.git", "%s", "%s.git/.git", "%s.git" * in this order. We select the first one that is a valid git repository, and * chdir() to it. If none match, or we fail to chdir, we return NULL. * * If all goes well, we return the directory we used to chdir() (but * before ~user is expanded), avoiding getcwd() resolving symbolic * links. User relative paths are also returned as they are given, * except DWIM suffixing. */ const char *enter_repo(const char *path, int strict) { … } int calc_shared_perm(int mode) { … } int adjust_shared_perm(const char *path) { … } void safe_create_dir(const char *dir, int share) { … } static int have_same_root(const char *path1, const char *path2) { … } /* * Give path as relative to prefix. * * The strbuf may or may not be used, so do not assume it contains the * returned path. */ const char *relative_path(const char *in, const char *prefix, struct strbuf *sb) { … } /* * 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) { … } /* * It is okay if dst == src, but they should not overlap otherwise. * The "dst" buffer must be at least as long as "src"; normalizing may shrink * the size of the path, but will never grow it. * * Performs the following normalizations on src, storing the result in dst: * - Ensures that components are separated by '/' (Windows only) * - Squashes sequences of '/' except "//server/share" on Windows * - Removes "." components. * - Removes ".." components, and the components the precede them. * 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. * * prefix_len != NULL is for a specific case of prefix_pathspec(): * assume that src == dst and src[0..prefix_len-1] is already * normalized, any time "../" eats up to the prefix_len part, * prefix_len is reduced. In the end prefix_len is the remaining * prefix that has not been overridden by user pathspec. * * NEEDSWORK: This function doesn't perform normalization w.r.t. trailing '/'. * For everything but the root folder itself, the normalized path should not * end with a '/', then the callers need to be fixed up accordingly. * */ int normalize_path_copy_len(char *dst, const char *src, int *prefix_len) { … } int normalize_path_copy(char *dst, const char *src) { … } int strbuf_normalize_path(struct strbuf *src) { … } /* * path = Canonical absolute path * prefixes = string_list containing normalized, absolute paths without * trailing slashes (except for the root directory, which is denoted by "/"). * * Determines, for each path in prefixes, whether the "prefix" * 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 prefixes 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. */ int longest_ancestor_length(const char *path, struct string_list *prefixes) { … } /* strip arbitrary amount of directory separators at end of path */ static inline int chomp_trailing_dir_sep(const char *path, int len) { … } /* * If path ends with suffix (complete path components), returns the offset of * the last character in the path before the suffix (sans trailing directory * separators), and -1 otherwise. */ static ssize_t stripped_path_suffix_offset(const char *path, const char *suffix) { … } /* * Returns true if the path ends with components, considering only complete path * components, and false otherwise. */ int ends_with_path_components(const char *path, const char *components) { … } /* * 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 daemon_avoid_alias(const char *p) { … } /* * On NTFS, we need to be careful to disallow certain synonyms of the `.git/` * directory: * * - For historical reasons, file names that end in spaces or periods are * automatically trimmed. Therefore, `.git . . ./` is a valid way to refer * to `.git/`. * * - For other historical reasons, file names that do not conform to the 8.3 * format (up to eight characters for the basename, three for the file * extension, certain characters not allowed such as `+`, etc) are associated * with a so-called "short name", at least on the `C:` drive by default. * Which means that `git~1/` is a valid way to refer to `.git/`. * * Note: Technically, `.git/` could receive the short name `git~2` if the * short name `git~1` were already used. In Git, however, we guarantee that * `.git` is the first item in a directory, therefore it will be associated * with the short name `git~1` (unless short names are disabled). * * - For yet other historical reasons, NTFS supports so-called "Alternate Data * Streams", i.e. metadata associated with a given file, referred to via * `<filename>:<stream-name>:<stream-type>`. There exists a default stream * type for directories, allowing `.git/` to be accessed via * `.git::$INDEX_ALLOCATION/`. * * When this function returns 1, it indicates that the specified file/directory * name refers to a `.git` file or directory, or to any of these synonyms, and * Git should therefore not track it. * * For performance reasons, _all_ Alternate Data Streams of `.git/` are * forbidden, not just `::$INDEX_ALLOCATION`. * * This function is intended to be used by `git fsck` even on platforms where * the backslash is a regular filename character, therefore it needs to handle * backlash characters in the provided `name` specially: they are interpreted * as directory separators. */ int is_ntfs_dotgit(const char *name) { … } static int is_ntfs_dot_generic(const char *name, const char *dotgit_name, size_t len, const char *dotgit_ntfs_shortname_prefix) { … } /* * Inline helper to make sure compiler resolves strlen() on literals at * compile time. */ static inline int is_ntfs_dot_str(const char *name, const char *dotgit_name, const char *dotgit_ntfs_shortname_prefix) { … } int is_ntfs_dotgitmodules(const char *name) { … } int is_ntfs_dotgitignore(const char *name) { … } int is_ntfs_dotgitattributes(const char *name) { … } int is_ntfs_dotmailmap(const char *name) { … } int looks_like_command_line_option(const char *str) { … } char *xdg_config_home_for(const char *subdir, const char *filename) { … } char *xdg_config_home(const char *filename) { … } char *xdg_cache_home(const char *filename) { … } REPO_GIT_PATH_FUNC(…) … REPO_GIT_PATH_FUNC(…) … REPO_GIT_PATH_FUNC(…) … REPO_GIT_PATH_FUNC(…) … REPO_GIT_PATH_FUNC(…) … REPO_GIT_PATH_FUNC(…) … REPO_GIT_PATH_FUNC(…) …