Changes in v3:
* Rewrite of `strip_last_component()` as the v2 verison didn't properly handle
inputs like '/foo'. Thanks to Johannes for pointing this out and suggesting
a solution.
* Small style changes
* Revert the call in `get_common_dir_noenv()` to maintain proper functionality.
Brandon Williams (4):
real_path: resolve symlinks by hand
real_path: convert real_path_internal to strbuf_realpath
real_path: create real_pathdup
real_path: have callers use real_pathdup and strbuf_realpath
abspath.c | 222 ++++++++++++++++++++++++++++++++++++------------------
builtin/init-db.c | 6 +-
cache.h | 3 +
environment.c | 2 +-
setup.c | 13 ++--
sha1_file.c | 2 +-
submodule.c | 2 +-
transport.c | 2 +-
worktree.c | 2 +-
9 files changed, 169 insertions(+), 85 deletions(-)
--- interdiff from v2
diff --git a/abspath.c b/abspath.c
index df37356..79ee310 100644
--- a/abspath.c
+++ b/abspath.c
@@ -14,10 +14,17 @@ int is_directory(const char *path)
/* removes the last path component from 'path' except if 'path' is root */
static void strip_last_component(struct strbuf *path)
{
- if (path->len > offset_1st_component(path->buf)) {
- char *last_slash = find_last_dir_sep(path->buf);
- strbuf_setlen(path, last_slash - path->buf);
- }
+ size_t offset = offset_1st_component(path->buf);
+ size_t len = path->len;
+
+ /* Find start of the last component */
+ while (offset < len && !is_dir_sep(path->buf[len - 1]))
+ len--;
+ /* Skip sequences of multiple path-separators */
+ while (offset < len && is_dir_sep(path->buf[len - 1]))
+ len--;
+
+ strbuf_setlen(path, len);
}
/* get (and remove) the next component in 'remaining' and place it in 'next' */
@@ -112,7 +119,7 @@ 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 (errno != ENOENT || remaining.len) {
if (die_on_error)
die_errno("Invalid path '%s'",
resolved->buf);
@@ -203,7 +210,7 @@ char *real_pathdup(const char *path)
struct strbuf realpath = STRBUF_INIT;
char *retval = NULL;
- if(strbuf_realpath(&realpath, path, 0))
+ if (strbuf_realpath(&realpath, path, 0))
retval = strbuf_detach(&realpath, NULL);
strbuf_release(&realpath);
diff --git a/setup.c b/setup.c
index 0d9fdd0..1b534a7 100644
--- a/setup.c
+++ b/setup.c
@@ -254,7 +254,7 @@ int get_common_dir_noenv(struct strbuf *sb, const char
*gitdir)
if (!is_absolute_path(data.buf))
strbuf_addf(&path, "%s/", gitdir);
strbuf_addbuf(&path, &data);
- strbuf_realpath(sb, path.buf, 1);
+ strbuf_addstr(sb, real_path(path.buf));
ret = 1;
} else {
strbuf_addstr(sb, gitdir);
--
2.8.0.rc3.226.g39d4020