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

Reply via email to