diff options
Diffstat (limited to 'abspath.c')
-rw-r--r-- | abspath.c | 113 |
1 files changed, 85 insertions, 28 deletions
@@ -1,4 +1,6 @@ -#include "cache.h" +#include "git-compat-util.h" +#include "abspath.h" +#include "strbuf.h" /* * Do not use this for inspecting *tracked* content. When path is a @@ -67,19 +69,15 @@ static void get_root_part(struct strbuf *resolved, struct strbuf *remaining) #endif /* - * Return the real path (i.e., absolute path, with symlinks resolved - * and extra slashes removed) equivalent to the specified path. (If - * you want an absolute path but don't mind links, use - * absolute_path().) Places the resolved realpath in the provided strbuf. - * - * The directory part of path (i.e., everything up to the last - * dir_sep) must denote a valid, existing directory, but the last - * component need not exist. If die_on_error is set, then die with an - * informative error message if there is a problem. Otherwise, return - * NULL on errors (without generating any output). + * If set, any number of trailing components may be missing; otherwise, only one + * may be. */ -char *strbuf_realpath(struct strbuf *resolved, const char *path, - int die_on_error) +#define REALPATH_MANY_MISSING (1 << 0) +/* Should we die if there's an error? */ +#define REALPATH_DIE_ON_ERROR (1 << 1) + +static char *strbuf_realpath_1(struct strbuf *resolved, const char *path, + int flags) { struct strbuf remaining = STRBUF_INIT; struct strbuf next = STRBUF_INIT; @@ -89,7 +87,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path, struct stat st; if (!*path) { - if (die_on_error) + if (flags & REALPATH_DIE_ON_ERROR) die("The empty string is not a valid path"); else goto error_out; @@ -101,7 +99,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path, if (!resolved->len) { /* relative path; can use CWD as the initial resolved path */ if (strbuf_getcwd(resolved)) { - if (die_on_error) + if (flags & REALPATH_DIE_ON_ERROR) die_errno("unable to get current working directory"); else goto error_out; @@ -129,8 +127,9 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path, if (lstat(resolved->buf, &st)) { /* error out unless this was the last component */ - if (errno != ENOENT || remaining.len) { - if (die_on_error) + if (errno != ENOENT || + (!(flags & REALPATH_MANY_MISSING) && remaining.len)) { + if (flags & REALPATH_DIE_ON_ERROR) die_errno("Invalid path '%s'", resolved->buf); else @@ -143,7 +142,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path, if (num_symlinks++ > MAXSYMLINKS) { errno = ELOOP; - if (die_on_error) + if (flags & REALPATH_DIE_ON_ERROR) die("More than %d nested symlinks " "on path '%s'", MAXSYMLINKS, path); else @@ -153,7 +152,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path, len = strbuf_readlink(&symlink, resolved->buf, st.st_size); if (len < 0) { - if (die_on_error) + if (flags & REALPATH_DIE_ON_ERROR) die_errno("Invalid symlink '%s'", resolved->buf); else @@ -203,19 +202,34 @@ error_out: } /* - * Resolve `path` into an absolute, cleaned-up path. The return value - * comes from a shared buffer. + * Return the real path (i.e., absolute path, with symlinks resolved + * and extra slashes removed) equivalent to the specified path. (If + * you want an absolute path but don't mind links, use + * absolute_path().) Places the resolved realpath in the provided strbuf. + * + * The directory part of path (i.e., everything up to the last + * dir_sep) must denote a valid, existing directory, but the last + * component need not exist. If die_on_error is set, then die with an + * informative error message if there is a problem. Otherwise, return + * NULL on errors (without generating any output). */ -const char *real_path(const char *path) +char *strbuf_realpath(struct strbuf *resolved, const char *path, + int die_on_error) { - static struct strbuf realpath = STRBUF_INIT; - return strbuf_realpath(&realpath, path, 1); + return strbuf_realpath_1(resolved, path, + die_on_error ? REALPATH_DIE_ON_ERROR : 0); } -const char *real_path_if_valid(const char *path) +/* + * Just like strbuf_realpath, but allows an arbitrary number of path + * components to be missing. + */ +char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path, + int die_on_error) { - static struct strbuf realpath = STRBUF_INIT; - return strbuf_realpath(&realpath, path, 0); + return strbuf_realpath_1(resolved, path, + ((die_on_error ? REALPATH_DIE_ON_ERROR : 0) | + REALPATH_MANY_MISSING)); } char *real_pathdup(const char *path, int die_on_error) @@ -233,7 +247,7 @@ char *real_pathdup(const char *path, int die_on_error) /* * Use this to get an absolute path from a relative one. If you want - * to resolve links, you should use real_path. + * to resolve links, you should use strbuf_realpath. */ const char *absolute_path(const char *path) { @@ -268,3 +282,46 @@ char *prefix_filename(const char *pfx, const char *arg) #endif return strbuf_detach(&path, NULL); } + +char *prefix_filename_except_for_dash(const char *pfx, const char *arg) +{ + if (!strcmp(arg, "-")) + return xstrdup(arg); + return prefix_filename(pfx, arg); +} + +void strbuf_add_absolute_path(struct strbuf *sb, const char *path) +{ + if (!*path) + die("The empty string is not a valid path"); + if (!is_absolute_path(path)) { + struct stat cwd_stat, pwd_stat; + size_t orig_len = sb->len; + char *cwd = xgetcwd(); + char *pwd = getenv("PWD"); + if (pwd && strcmp(pwd, cwd) && + !stat(cwd, &cwd_stat) && + (cwd_stat.st_dev || cwd_stat.st_ino) && + !stat(pwd, &pwd_stat) && + pwd_stat.st_dev == cwd_stat.st_dev && + pwd_stat.st_ino == cwd_stat.st_ino) + strbuf_addstr(sb, pwd); + else + strbuf_addstr(sb, cwd); + if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1])) + strbuf_addch(sb, '/'); + free(cwd); + } + strbuf_addstr(sb, path); +} + +void strbuf_add_real_path(struct strbuf *sb, const char *path) +{ + if (sb->len) { + struct strbuf resolved = STRBUF_INIT; + strbuf_realpath(&resolved, path, 1); + strbuf_addbuf(sb, &resolved); + strbuf_release(&resolved); + } else + strbuf_realpath(sb, path, 1); +} |