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