1*86470930SIngo Molnar /* 2*86470930SIngo Molnar * I'm tired of doing "vsnprintf()" etc just to open a 3*86470930SIngo Molnar * file, so here's a "return static buffer with printf" 4*86470930SIngo Molnar * interface for paths. 5*86470930SIngo Molnar * 6*86470930SIngo Molnar * It's obviously not thread-safe. Sue me. But it's quite 7*86470930SIngo Molnar * useful for doing things like 8*86470930SIngo Molnar * 9*86470930SIngo Molnar * f = open(mkpath("%s/%s.perf", base, name), O_RDONLY); 10*86470930SIngo Molnar * 11*86470930SIngo Molnar * which is what it's designed for. 12*86470930SIngo Molnar */ 13*86470930SIngo Molnar #include "cache.h" 14*86470930SIngo Molnar 15*86470930SIngo Molnar static char bad_path[] = "/bad-path/"; 16*86470930SIngo Molnar /* 17*86470930SIngo Molnar * Two hacks: 18*86470930SIngo Molnar */ 19*86470930SIngo Molnar 20*86470930SIngo Molnar static char *get_perf_dir(void) 21*86470930SIngo Molnar { 22*86470930SIngo Molnar return "."; 23*86470930SIngo Molnar } 24*86470930SIngo Molnar 25*86470930SIngo Molnar size_t strlcpy(char *dest, const char *src, size_t size) 26*86470930SIngo Molnar { 27*86470930SIngo Molnar size_t ret = strlen(src); 28*86470930SIngo Molnar 29*86470930SIngo Molnar if (size) { 30*86470930SIngo Molnar size_t len = (ret >= size) ? size - 1 : ret; 31*86470930SIngo Molnar memcpy(dest, src, len); 32*86470930SIngo Molnar dest[len] = '\0'; 33*86470930SIngo Molnar } 34*86470930SIngo Molnar return ret; 35*86470930SIngo Molnar } 36*86470930SIngo Molnar 37*86470930SIngo Molnar 38*86470930SIngo Molnar static char *get_pathname(void) 39*86470930SIngo Molnar { 40*86470930SIngo Molnar static char pathname_array[4][PATH_MAX]; 41*86470930SIngo Molnar static int index; 42*86470930SIngo Molnar return pathname_array[3 & ++index]; 43*86470930SIngo Molnar } 44*86470930SIngo Molnar 45*86470930SIngo Molnar static char *cleanup_path(char *path) 46*86470930SIngo Molnar { 47*86470930SIngo Molnar /* Clean it up */ 48*86470930SIngo Molnar if (!memcmp(path, "./", 2)) { 49*86470930SIngo Molnar path += 2; 50*86470930SIngo Molnar while (*path == '/') 51*86470930SIngo Molnar path++; 52*86470930SIngo Molnar } 53*86470930SIngo Molnar return path; 54*86470930SIngo Molnar } 55*86470930SIngo Molnar 56*86470930SIngo Molnar char *mksnpath(char *buf, size_t n, const char *fmt, ...) 57*86470930SIngo Molnar { 58*86470930SIngo Molnar va_list args; 59*86470930SIngo Molnar unsigned len; 60*86470930SIngo Molnar 61*86470930SIngo Molnar va_start(args, fmt); 62*86470930SIngo Molnar len = vsnprintf(buf, n, fmt, args); 63*86470930SIngo Molnar va_end(args); 64*86470930SIngo Molnar if (len >= n) { 65*86470930SIngo Molnar strlcpy(buf, bad_path, n); 66*86470930SIngo Molnar return buf; 67*86470930SIngo Molnar } 68*86470930SIngo Molnar return cleanup_path(buf); 69*86470930SIngo Molnar } 70*86470930SIngo Molnar 71*86470930SIngo Molnar static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args) 72*86470930SIngo Molnar { 73*86470930SIngo Molnar const char *perf_dir = get_perf_dir(); 74*86470930SIngo Molnar size_t len; 75*86470930SIngo Molnar 76*86470930SIngo Molnar len = strlen(perf_dir); 77*86470930SIngo Molnar if (n < len + 1) 78*86470930SIngo Molnar goto bad; 79*86470930SIngo Molnar memcpy(buf, perf_dir, len); 80*86470930SIngo Molnar if (len && !is_dir_sep(perf_dir[len-1])) 81*86470930SIngo Molnar buf[len++] = '/'; 82*86470930SIngo Molnar len += vsnprintf(buf + len, n - len, fmt, args); 83*86470930SIngo Molnar if (len >= n) 84*86470930SIngo Molnar goto bad; 85*86470930SIngo Molnar return cleanup_path(buf); 86*86470930SIngo Molnar bad: 87*86470930SIngo Molnar strlcpy(buf, bad_path, n); 88*86470930SIngo Molnar return buf; 89*86470930SIngo Molnar } 90*86470930SIngo Molnar 91*86470930SIngo Molnar char *perf_snpath(char *buf, size_t n, const char *fmt, ...) 92*86470930SIngo Molnar { 93*86470930SIngo Molnar va_list args; 94*86470930SIngo Molnar va_start(args, fmt); 95*86470930SIngo Molnar (void)perf_vsnpath(buf, n, fmt, args); 96*86470930SIngo Molnar va_end(args); 97*86470930SIngo Molnar return buf; 98*86470930SIngo Molnar } 99*86470930SIngo Molnar 100*86470930SIngo Molnar char *perf_pathdup(const char *fmt, ...) 101*86470930SIngo Molnar { 102*86470930SIngo Molnar char path[PATH_MAX]; 103*86470930SIngo Molnar va_list args; 104*86470930SIngo Molnar va_start(args, fmt); 105*86470930SIngo Molnar (void)perf_vsnpath(path, sizeof(path), fmt, args); 106*86470930SIngo Molnar va_end(args); 107*86470930SIngo Molnar return xstrdup(path); 108*86470930SIngo Molnar } 109*86470930SIngo Molnar 110*86470930SIngo Molnar char *mkpath(const char *fmt, ...) 111*86470930SIngo Molnar { 112*86470930SIngo Molnar va_list args; 113*86470930SIngo Molnar unsigned len; 114*86470930SIngo Molnar char *pathname = get_pathname(); 115*86470930SIngo Molnar 116*86470930SIngo Molnar va_start(args, fmt); 117*86470930SIngo Molnar len = vsnprintf(pathname, PATH_MAX, fmt, args); 118*86470930SIngo Molnar va_end(args); 119*86470930SIngo Molnar if (len >= PATH_MAX) 120*86470930SIngo Molnar return bad_path; 121*86470930SIngo Molnar return cleanup_path(pathname); 122*86470930SIngo Molnar } 123*86470930SIngo Molnar 124*86470930SIngo Molnar char *perf_path(const char *fmt, ...) 125*86470930SIngo Molnar { 126*86470930SIngo Molnar const char *perf_dir = get_perf_dir(); 127*86470930SIngo Molnar char *pathname = get_pathname(); 128*86470930SIngo Molnar va_list args; 129*86470930SIngo Molnar unsigned len; 130*86470930SIngo Molnar 131*86470930SIngo Molnar len = strlen(perf_dir); 132*86470930SIngo Molnar if (len > PATH_MAX-100) 133*86470930SIngo Molnar return bad_path; 134*86470930SIngo Molnar memcpy(pathname, perf_dir, len); 135*86470930SIngo Molnar if (len && perf_dir[len-1] != '/') 136*86470930SIngo Molnar pathname[len++] = '/'; 137*86470930SIngo Molnar va_start(args, fmt); 138*86470930SIngo Molnar len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); 139*86470930SIngo Molnar va_end(args); 140*86470930SIngo Molnar if (len >= PATH_MAX) 141*86470930SIngo Molnar return bad_path; 142*86470930SIngo Molnar return cleanup_path(pathname); 143*86470930SIngo Molnar } 144*86470930SIngo Molnar 145*86470930SIngo Molnar 146*86470930SIngo Molnar /* perf_mkstemp() - create tmp file honoring TMPDIR variable */ 147*86470930SIngo Molnar int perf_mkstemp(char *path, size_t len, const char *template) 148*86470930SIngo Molnar { 149*86470930SIngo Molnar const char *tmp; 150*86470930SIngo Molnar size_t n; 151*86470930SIngo Molnar 152*86470930SIngo Molnar tmp = getenv("TMPDIR"); 153*86470930SIngo Molnar if (!tmp) 154*86470930SIngo Molnar tmp = "/tmp"; 155*86470930SIngo Molnar n = snprintf(path, len, "%s/%s", tmp, template); 156*86470930SIngo Molnar if (len <= n) { 157*86470930SIngo Molnar errno = ENAMETOOLONG; 158*86470930SIngo Molnar return -1; 159*86470930SIngo Molnar } 160*86470930SIngo Molnar return mkstemp(path); 161*86470930SIngo Molnar } 162*86470930SIngo Molnar 163*86470930SIngo Molnar 164*86470930SIngo Molnar const char *make_relative_path(const char *abs, const char *base) 165*86470930SIngo Molnar { 166*86470930SIngo Molnar static char buf[PATH_MAX + 1]; 167*86470930SIngo Molnar int baselen; 168*86470930SIngo Molnar if (!base) 169*86470930SIngo Molnar return abs; 170*86470930SIngo Molnar baselen = strlen(base); 171*86470930SIngo Molnar if (prefixcmp(abs, base)) 172*86470930SIngo Molnar return abs; 173*86470930SIngo Molnar if (abs[baselen] == '/') 174*86470930SIngo Molnar baselen++; 175*86470930SIngo Molnar else if (base[baselen - 1] != '/') 176*86470930SIngo Molnar return abs; 177*86470930SIngo Molnar strcpy(buf, abs + baselen); 178*86470930SIngo Molnar return buf; 179*86470930SIngo Molnar } 180*86470930SIngo Molnar 181*86470930SIngo Molnar /* 182*86470930SIngo Molnar * It is okay if dst == src, but they should not overlap otherwise. 183*86470930SIngo Molnar * 184*86470930SIngo Molnar * Performs the following normalizations on src, storing the result in dst: 185*86470930SIngo Molnar * - Ensures that components are separated by '/' (Windows only) 186*86470930SIngo Molnar * - Squashes sequences of '/'. 187*86470930SIngo Molnar * - Removes "." components. 188*86470930SIngo Molnar * - Removes ".." components, and the components the precede them. 189*86470930SIngo Molnar * Returns failure (non-zero) if a ".." component appears as first path 190*86470930SIngo Molnar * component anytime during the normalization. Otherwise, returns success (0). 191*86470930SIngo Molnar * 192*86470930SIngo Molnar * Note that this function is purely textual. It does not follow symlinks, 193*86470930SIngo Molnar * verify the existence of the path, or make any system calls. 194*86470930SIngo Molnar */ 195*86470930SIngo Molnar int normalize_path_copy(char *dst, const char *src) 196*86470930SIngo Molnar { 197*86470930SIngo Molnar char *dst0; 198*86470930SIngo Molnar 199*86470930SIngo Molnar if (has_dos_drive_prefix(src)) { 200*86470930SIngo Molnar *dst++ = *src++; 201*86470930SIngo Molnar *dst++ = *src++; 202*86470930SIngo Molnar } 203*86470930SIngo Molnar dst0 = dst; 204*86470930SIngo Molnar 205*86470930SIngo Molnar if (is_dir_sep(*src)) { 206*86470930SIngo Molnar *dst++ = '/'; 207*86470930SIngo Molnar while (is_dir_sep(*src)) 208*86470930SIngo Molnar src++; 209*86470930SIngo Molnar } 210*86470930SIngo Molnar 211*86470930SIngo Molnar for (;;) { 212*86470930SIngo Molnar char c = *src; 213*86470930SIngo Molnar 214*86470930SIngo Molnar /* 215*86470930SIngo Molnar * A path component that begins with . could be 216*86470930SIngo Molnar * special: 217*86470930SIngo Molnar * (1) "." and ends -- ignore and terminate. 218*86470930SIngo Molnar * (2) "./" -- ignore them, eat slash and continue. 219*86470930SIngo Molnar * (3) ".." and ends -- strip one and terminate. 220*86470930SIngo Molnar * (4) "../" -- strip one, eat slash and continue. 221*86470930SIngo Molnar */ 222*86470930SIngo Molnar if (c == '.') { 223*86470930SIngo Molnar if (!src[1]) { 224*86470930SIngo Molnar /* (1) */ 225*86470930SIngo Molnar src++; 226*86470930SIngo Molnar } else if (is_dir_sep(src[1])) { 227*86470930SIngo Molnar /* (2) */ 228*86470930SIngo Molnar src += 2; 229*86470930SIngo Molnar while (is_dir_sep(*src)) 230*86470930SIngo Molnar src++; 231*86470930SIngo Molnar continue; 232*86470930SIngo Molnar } else if (src[1] == '.') { 233*86470930SIngo Molnar if (!src[2]) { 234*86470930SIngo Molnar /* (3) */ 235*86470930SIngo Molnar src += 2; 236*86470930SIngo Molnar goto up_one; 237*86470930SIngo Molnar } else if (is_dir_sep(src[2])) { 238*86470930SIngo Molnar /* (4) */ 239*86470930SIngo Molnar src += 3; 240*86470930SIngo Molnar while (is_dir_sep(*src)) 241*86470930SIngo Molnar src++; 242*86470930SIngo Molnar goto up_one; 243*86470930SIngo Molnar } 244*86470930SIngo Molnar } 245*86470930SIngo Molnar } 246*86470930SIngo Molnar 247*86470930SIngo Molnar /* copy up to the next '/', and eat all '/' */ 248*86470930SIngo Molnar while ((c = *src++) != '\0' && !is_dir_sep(c)) 249*86470930SIngo Molnar *dst++ = c; 250*86470930SIngo Molnar if (is_dir_sep(c)) { 251*86470930SIngo Molnar *dst++ = '/'; 252*86470930SIngo Molnar while (is_dir_sep(c)) 253*86470930SIngo Molnar c = *src++; 254*86470930SIngo Molnar src--; 255*86470930SIngo Molnar } else if (!c) 256*86470930SIngo Molnar break; 257*86470930SIngo Molnar continue; 258*86470930SIngo Molnar 259*86470930SIngo Molnar up_one: 260*86470930SIngo Molnar /* 261*86470930SIngo Molnar * dst0..dst is prefix portion, and dst[-1] is '/'; 262*86470930SIngo Molnar * go up one level. 263*86470930SIngo Molnar */ 264*86470930SIngo Molnar dst--; /* go to trailing '/' */ 265*86470930SIngo Molnar if (dst <= dst0) 266*86470930SIngo Molnar return -1; 267*86470930SIngo Molnar /* Windows: dst[-1] cannot be backslash anymore */ 268*86470930SIngo Molnar while (dst0 < dst && dst[-1] != '/') 269*86470930SIngo Molnar dst--; 270*86470930SIngo Molnar } 271*86470930SIngo Molnar *dst = '\0'; 272*86470930SIngo Molnar return 0; 273*86470930SIngo Molnar } 274*86470930SIngo Molnar 275*86470930SIngo Molnar /* 276*86470930SIngo Molnar * path = Canonical absolute path 277*86470930SIngo Molnar * prefix_list = Colon-separated list of absolute paths 278*86470930SIngo Molnar * 279*86470930SIngo Molnar * Determines, for each path in prefix_list, whether the "prefix" really 280*86470930SIngo Molnar * is an ancestor directory of path. Returns the length of the longest 281*86470930SIngo Molnar * ancestor directory, excluding any trailing slashes, or -1 if no prefix 282*86470930SIngo Molnar * is an ancestor. (Note that this means 0 is returned if prefix_list is 283*86470930SIngo Molnar * "/".) "/foo" is not considered an ancestor of "/foobar". Directories 284*86470930SIngo Molnar * are not considered to be their own ancestors. path must be in a 285*86470930SIngo Molnar * canonical form: empty components, or "." or ".." components are not 286*86470930SIngo Molnar * allowed. prefix_list may be null, which is like "". 287*86470930SIngo Molnar */ 288*86470930SIngo Molnar int longest_ancestor_length(const char *path, const char *prefix_list) 289*86470930SIngo Molnar { 290*86470930SIngo Molnar char buf[PATH_MAX+1]; 291*86470930SIngo Molnar const char *ceil, *colon; 292*86470930SIngo Molnar int len, max_len = -1; 293*86470930SIngo Molnar 294*86470930SIngo Molnar if (prefix_list == NULL || !strcmp(path, "/")) 295*86470930SIngo Molnar return -1; 296*86470930SIngo Molnar 297*86470930SIngo Molnar for (colon = ceil = prefix_list; *colon; ceil = colon+1) { 298*86470930SIngo Molnar for (colon = ceil; *colon && *colon != PATH_SEP; colon++); 299*86470930SIngo Molnar len = colon - ceil; 300*86470930SIngo Molnar if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil)) 301*86470930SIngo Molnar continue; 302*86470930SIngo Molnar strlcpy(buf, ceil, len+1); 303*86470930SIngo Molnar if (normalize_path_copy(buf, buf) < 0) 304*86470930SIngo Molnar continue; 305*86470930SIngo Molnar len = strlen(buf); 306*86470930SIngo Molnar if (len > 0 && buf[len-1] == '/') 307*86470930SIngo Molnar buf[--len] = '\0'; 308*86470930SIngo Molnar 309*86470930SIngo Molnar if (!strncmp(path, buf, len) && 310*86470930SIngo Molnar path[len] == '/' && 311*86470930SIngo Molnar len > max_len) { 312*86470930SIngo Molnar max_len = len; 313*86470930SIngo Molnar } 314*86470930SIngo Molnar } 315*86470930SIngo Molnar 316*86470930SIngo Molnar return max_len; 317*86470930SIngo Molnar } 318*86470930SIngo Molnar 319*86470930SIngo Molnar /* strip arbitrary amount of directory separators at end of path */ 320*86470930SIngo Molnar static inline int chomp_trailing_dir_sep(const char *path, int len) 321*86470930SIngo Molnar { 322*86470930SIngo Molnar while (len && is_dir_sep(path[len - 1])) 323*86470930SIngo Molnar len--; 324*86470930SIngo Molnar return len; 325*86470930SIngo Molnar } 326*86470930SIngo Molnar 327*86470930SIngo Molnar /* 328*86470930SIngo Molnar * If path ends with suffix (complete path components), returns the 329*86470930SIngo Molnar * part before suffix (sans trailing directory separators). 330*86470930SIngo Molnar * Otherwise returns NULL. 331*86470930SIngo Molnar */ 332*86470930SIngo Molnar char *strip_path_suffix(const char *path, const char *suffix) 333*86470930SIngo Molnar { 334*86470930SIngo Molnar int path_len = strlen(path), suffix_len = strlen(suffix); 335*86470930SIngo Molnar 336*86470930SIngo Molnar while (suffix_len) { 337*86470930SIngo Molnar if (!path_len) 338*86470930SIngo Molnar return NULL; 339*86470930SIngo Molnar 340*86470930SIngo Molnar if (is_dir_sep(path[path_len - 1])) { 341*86470930SIngo Molnar if (!is_dir_sep(suffix[suffix_len - 1])) 342*86470930SIngo Molnar return NULL; 343*86470930SIngo Molnar path_len = chomp_trailing_dir_sep(path, path_len); 344*86470930SIngo Molnar suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); 345*86470930SIngo Molnar } 346*86470930SIngo Molnar else if (path[--path_len] != suffix[--suffix_len]) 347*86470930SIngo Molnar return NULL; 348*86470930SIngo Molnar } 349*86470930SIngo Molnar 350*86470930SIngo Molnar if (path_len && !is_dir_sep(path[path_len - 1])) 351*86470930SIngo Molnar return NULL; 352*86470930SIngo Molnar return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); 353*86470930SIngo Molnar } 354