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