]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'js/maint-add-path-stat-pwd' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 16 Aug 2011 18:41:27 +0000 (11:41 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 16 Aug 2011 18:41:27 +0000 (11:41 -0700)
* js/maint-add-path-stat-pwd:
  get_pwd_cwd(): Do not trust st_dev/st_ino blindly

1  2 
abspath.c

diff --combined abspath.c
index 3005aedde68b48297aacd2082797b2e2f249b094,e7d22bf60be147c2fa6731834dcd42a132eadecd..f9494c49c17cf421a2efa7c6562bc84fcac014f6
+++ b/abspath.c
@@@ -1,45 -1,23 +1,45 @@@
  #include "cache.h"
  
 +/*
 + * Do not use this for inspecting *tracked* content.  When path is a
 + * symlink to a directory, we do not want to say it is a directory when
 + * dealing with tracked content in the working tree.
 + */
 +int is_directory(const char *path)
 +{
 +      struct stat st;
 +      return (!stat(path, &st) && S_ISDIR(st.st_mode));
 +}
 +
  /* We allow "recursive" symbolic links. Only within reason, though. */
  #define MAXDEPTH 5
  
 -const char *make_absolute_path(const char *path)
 +/*
 + * Use this to get the real path, i.e. resolve links. If you want an
 + * absolute path but don't mind links, use absolute_path.
 + *
 + * If path is our buffer, then return path, as it's already what the
 + * user wants.
 + */
 +const char *real_path(const char *path)
  {
        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
        char cwd[1024] = "";
 -      int buf_index = 1, len;
 +      int buf_index = 1;
  
        int depth = MAXDEPTH;
        char *last_elem = NULL;
        struct stat st;
  
 +      /* We've already done it */
 +      if (path == buf || path == next_buf)
 +              return path;
 +
        if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
                die ("Too long path: %.*s", 60, path);
  
        while (depth--) {
 -              if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
 +              if (!is_directory(buf)) {
                        char *last_slash = strrchr(buf, '/');
                        if (last_slash) {
                                *last_slash = '\0';
  
                if (*buf) {
                        if (!*cwd && !getcwd(cwd, sizeof(cwd)))
 -                              die ("Could not get current working directory");
 +                              die_errno ("Could not get current working directory");
  
                        if (chdir(buf))
 -                              die ("Could not switch to '%s'", buf);
 +                              die_errno ("Could not switch to '%s'", buf);
                }
                if (!getcwd(buf, PATH_MAX))
 -                      die ("Could not get current working directory");
 +                      die_errno ("Could not get current working directory");
  
                if (last_elem) {
 -                      int len = strlen(buf);
 +                      size_t len = strlen(buf);
                        if (len + strlen(last_elem) + 2 > PATH_MAX)
                                die ("Too long path name: '%s/%s'",
                                                buf, last_elem);
 -                      buf[len] = '/';
 -                      strcpy(buf + len + 1, last_elem);
 +                      if (len && buf[len-1] != '/')
 +                              buf[len++] = '/';
 +                      strcpy(buf + len, last_elem);
                        free(last_elem);
                        last_elem = NULL;
                }
  
                if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
 -                      len = readlink(buf, next_buf, PATH_MAX);
 +                      ssize_t len = readlink(buf, next_buf, PATH_MAX);
                        if (len < 0)
 -                              die ("Invalid symlink: %s", buf);
 +                              die_errno ("Invalid symlink '%s'", buf);
 +                      if (PATH_MAX <= len)
 +                              die("symbolic link too long: %s", buf);
                        next_buf[len] = '\0';
                        buf = next_buf;
                        buf_index = 1 - buf_index;
@@@ -87,7 -62,7 +87,7 @@@
        }
  
        if (*cwd && chdir(cwd))
 -              die ("Could not change back to '%s'", cwd);
 +              die_errno ("Could not change back to '%s'", cwd);
  
        return buf;
  }
@@@ -102,7 -77,8 +102,8 @@@ static const char *get_pwd_cwd(void
        pwd = getenv("PWD");
        if (pwd && strcmp(pwd, cwd)) {
                stat(cwd, &cwd_stat);
-               if (!stat(pwd, &pwd_stat) &&
+               if ((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) {
                        strlcpy(cwd, pwd, PATH_MAX);
        return cwd;
  }
  
 -const char *make_nonrelative_path(const char *path)
 +/*
 + * Use this to get an absolute path from a relative one. If you want
 + * to resolve links, you should use real_path.
 + *
 + * If the path is already absolute, then return path. As the user is
 + * never meant to free the return value, we're safe.
 + */
 +const char *absolute_path(const char *path)
  {
        static char buf[PATH_MAX + 1];
  
                if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
                        die("Too long path: %.*s", 60, path);
        } else {
 +              size_t len;
 +              const char *fmt;
                const char *cwd = get_pwd_cwd();
                if (!cwd)
 -                      die("Cannot determine the current working directory");
 -              if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
 +                      die_errno("Cannot determine the current working directory");
 +              len = strlen(cwd);
 +              fmt = (len > 0 && is_dir_sep(cwd[len-1])) ? "%s%s" : "%s/%s";
 +              if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX)
                        die("Too long path: %.*s", 60, path);
        }
        return buf;