abspath.con commit Merge branch 'ag/blame-encoding' (0eb5ebc)
   1#include "cache.h"
   2
   3/*
   4 * Do not use this for inspecting *tracked* content.  When path is a
   5 * symlink to a directory, we do not want to say it is a directory when
   6 * dealing with tracked content in the working tree.
   7 */
   8int is_directory(const char *path)
   9{
  10        struct stat st;
  11        return (!stat(path, &st) && S_ISDIR(st.st_mode));
  12}
  13
  14/* We allow "recursive" symbolic links. Only within reason, though. */
  15#define MAXDEPTH 5
  16
  17const char *make_absolute_path(const char *path)
  18{
  19        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
  20        char cwd[1024] = "";
  21        int buf_index = 1, len;
  22
  23        int depth = MAXDEPTH;
  24        char *last_elem = NULL;
  25        struct stat st;
  26
  27        if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
  28                die ("Too long path: %.*s", 60, path);
  29
  30        while (depth--) {
  31                if (!is_directory(buf)) {
  32                        char *last_slash = strrchr(buf, '/');
  33                        if (last_slash) {
  34                                *last_slash = '\0';
  35                                last_elem = xstrdup(last_slash + 1);
  36                        } else {
  37                                last_elem = xstrdup(buf);
  38                                *buf = '\0';
  39                        }
  40                }
  41
  42                if (*buf) {
  43                        if (!*cwd && !getcwd(cwd, sizeof(cwd)))
  44                                die ("Could not get current working directory");
  45
  46                        if (chdir(buf))
  47                                die ("Could not switch to '%s'", buf);
  48                }
  49                if (!getcwd(buf, PATH_MAX))
  50                        die ("Could not get current working directory");
  51
  52                if (last_elem) {
  53                        int len = strlen(buf);
  54                        if (len + strlen(last_elem) + 2 > PATH_MAX)
  55                                die ("Too long path name: '%s/%s'",
  56                                                buf, last_elem);
  57                        buf[len] = '/';
  58                        strcpy(buf + len + 1, last_elem);
  59                        free(last_elem);
  60                        last_elem = NULL;
  61                }
  62
  63                if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
  64                        len = readlink(buf, next_buf, PATH_MAX);
  65                        if (len < 0)
  66                                die ("Invalid symlink: %s", buf);
  67                        next_buf[len] = '\0';
  68                        buf = next_buf;
  69                        buf_index = 1 - buf_index;
  70                        next_buf = bufs[buf_index];
  71                } else
  72                        break;
  73        }
  74
  75        if (*cwd && chdir(cwd))
  76                die ("Could not change back to '%s'", cwd);
  77
  78        return buf;
  79}
  80
  81static const char *get_pwd_cwd(void)
  82{
  83        static char cwd[PATH_MAX + 1];
  84        char *pwd;
  85        struct stat cwd_stat, pwd_stat;
  86        if (getcwd(cwd, PATH_MAX) == NULL)
  87                return NULL;
  88        pwd = getenv("PWD");
  89        if (pwd && strcmp(pwd, cwd)) {
  90                stat(cwd, &cwd_stat);
  91                if (!stat(pwd, &pwd_stat) &&
  92                    pwd_stat.st_dev == cwd_stat.st_dev &&
  93                    pwd_stat.st_ino == cwd_stat.st_ino) {
  94                        strlcpy(cwd, pwd, PATH_MAX);
  95                }
  96        }
  97        return cwd;
  98}
  99
 100const char *make_nonrelative_path(const char *path)
 101{
 102        static char buf[PATH_MAX + 1];
 103
 104        if (is_absolute_path(path)) {
 105                if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
 106                        die("Too long path: %.*s", 60, path);
 107        } else {
 108                const char *cwd = get_pwd_cwd();
 109                if (!cwd)
 110                        die("Cannot determine the current working directory");
 111                if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
 112                        die("Too long path: %.*s", 60, path);
 113        }
 114        return buf;
 115}