Skip to content
This repository
tag: v1.7.12.4
Fetching contributors…

Cannot retrieve contributors at this time

file 169 lines (152 sloc) 4.279 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
#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

/*
* 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;

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 (!is_directory(buf)) {
char *last_slash = find_last_dir_sep(buf);
if (last_slash) {
*last_slash = '\0';
last_elem = xstrdup(last_slash + 1);
} else {
last_elem = xstrdup(buf);
*buf = '\0';
}
}

if (*buf) {
if (!*cwd && !getcwd(cwd, sizeof(cwd)))
die_errno ("Could not get current working directory");

if (chdir(buf))
die_errno ("Could not switch to '%s'", buf);
}
if (!getcwd(buf, PATH_MAX))
die_errno ("Could not get current working directory");

if (last_elem) {
size_t len = strlen(buf);
if (len + strlen(last_elem) + 2 > PATH_MAX)
die ("Too long path name: '%s/%s'",
buf, last_elem);
if (len && !is_dir_sep(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)) {
ssize_t len = readlink(buf, next_buf, PATH_MAX);
if (len < 0)
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;
next_buf = bufs[buf_index];
} else
break;
}

if (*cwd && chdir(cwd))
die_errno ("Could not change back to '%s'", cwd);

return buf;
}

static const char *get_pwd_cwd(void)
{
static char cwd[PATH_MAX + 1];
char *pwd;
struct stat cwd_stat, pwd_stat;
if (getcwd(cwd, PATH_MAX) == NULL)
return NULL;
pwd = getenv("PWD");
if (pwd && strcmp(pwd, cwd)) {
stat(cwd, &cwd_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;
}

/*
* 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 (is_absolute_path(path)) {
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_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;
}

/*
* Unlike prefix_path, this should be used if the named file does
* not have to interact with index entry; i.e. name of a random file
* on the filesystem.
*/
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
{
static char path[PATH_MAX];
#ifndef WIN32
if (!pfx_len || is_absolute_path(arg))
return arg;
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
#else
char *p;
/* don't add prefix to absolute paths, but still replace '\' by '/' */
if (is_absolute_path(arg))
pfx_len = 0;
else if (pfx_len)
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
for (p = path + pfx_len; *p; p++)
if (*p == '\\')
*p = '/';
#endif
return path;
}
Something went wrong with that request. Please try again.