1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * I'm tired of doing "vsnprintf()" etc just to open a 3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * file, so here's a "return static buffer with printf" 4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * interface for paths. 5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * It's obviously not thread-safe. Sue me. But it's quite 7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * useful for doing things like 8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * f = open(mkpath("%s/%s.perf", base, name), O_RDONLY); 10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * which is what it's designed for. 12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "cache.h" 14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char bad_path[] = "/bad-path/"; 16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Two hacks: 18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic const char *get_perf_dir(void) 21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return "."; 23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#ifndef HAVE_STRLCPY 26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengsize_t strlcpy(char *dest, const char *src, size_t size) 27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t ret = strlen(src); 29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (size) { 31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t len = (ret >= size) ? size - 1 : ret; 32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memcpy(dest, src, len); 33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dest[len] = '\0'; 34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#endif 38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char *get_pathname(void) 40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng static char pathname_array[4][PATH_MAX]; 42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng static int idx; 43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return pathname_array[3 & ++idx]; 45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char *cleanup_path(char *path) 48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Clean it up */ 50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!memcmp(path, "./", 2)) { 51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng path += 2; 52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (*path == '/') 53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng path++; 54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return path; 56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args) 59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *perf_dir = get_perf_dir(); 61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t len; 62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len = strlen(perf_dir); 64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (n < len + 1) 65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto bad; 66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memcpy(buf, perf_dir, len); 67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (len && !is_dir_sep(perf_dir[len-1])) 68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng buf[len++] = '/'; 69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len += vsnprintf(buf + len, n - len, fmt, args); 70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (len >= n) 71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto bad; 72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return cleanup_path(buf); 73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbad: 74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng strlcpy(buf, bad_path, n); 75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return buf; 76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengchar *perf_pathdup(const char *fmt, ...) 79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char path[PATH_MAX]; 81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_list args; 82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_start(args, fmt); 83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (void)perf_vsnpath(path, sizeof(path), fmt, args); 84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_end(args); 85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return xstrdup(path); 86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengchar *mkpath(const char *fmt, ...) 89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_list args; 91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned len; 92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *pathname = get_pathname(); 93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_start(args, fmt); 95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len = vsnprintf(pathname, PATH_MAX, fmt, args); 96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_end(args); 97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (len >= PATH_MAX) 98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return bad_path; 99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return cleanup_path(pathname); 100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengchar *perf_path(const char *fmt, ...) 103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *perf_dir = get_perf_dir(); 105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *pathname = get_pathname(); 106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_list args; 107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned len; 108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len = strlen(perf_dir); 110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (len > PATH_MAX-100) 111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return bad_path; 112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memcpy(pathname, perf_dir, len); 113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (len && perf_dir[len-1] != '/') 114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pathname[len++] = '/'; 115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_start(args, fmt); 116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); 117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng va_end(args); 118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (len >= PATH_MAX) 119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return bad_path; 120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return cleanup_path(pathname); 121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* strip arbitrary amount of directory separators at end of path */ 124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline int chomp_trailing_dir_sep(const char *path, int len) 125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (len && is_dir_sep(path[len - 1])) 127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len--; 128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return len; 129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * If path ends with suffix (complete path components), returns the 133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * part before suffix (sans trailing directory separators). 134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Otherwise returns NULL. 135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengchar *strip_path_suffix(const char *path, const char *suffix) 137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int path_len = strlen(path), suffix_len = strlen(suffix); 139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (suffix_len) { 141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!path_len) 142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (is_dir_sep(path[path_len - 1])) { 145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!is_dir_sep(suffix[suffix_len - 1])) 146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng path_len = chomp_trailing_dir_sep(path, path_len); 148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); 149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else if (path[--path_len] != suffix[--suffix_len]) 151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (path_len && !is_dir_sep(path[path_len - 1])) 155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return strndup(path, chomp_trailing_dir_sep(path, path_len)); 157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 158