Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[pandora-kernel.git] / tools / perf / util / path.c
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
15 static char bad_path[] = "/bad-path/";
16 /*
17  * Two hacks:
18  */
19
20 static const char *get_perf_dir(void)
21 {
22         return ".";
23 }
24
25 size_t strlcpy(char *dest, const char *src, size_t size)
26 {
27         size_t ret = strlen(src);
28
29         if (size) {
30                 size_t len = (ret >= size) ? size - 1 : ret;
31                 memcpy(dest, src, len);
32                 dest[len] = '\0';
33         }
34         return ret;
35 }
36
37
38 static char *get_pathname(void)
39 {
40         static char pathname_array[4][PATH_MAX];
41         static int idx;
42
43         return pathname_array[3 & ++idx];
44 }
45
46 static char *cleanup_path(char *path)
47 {
48         /* Clean it up */
49         if (!memcmp(path, "./", 2)) {
50                 path += 2;
51                 while (*path == '/')
52                         path++;
53         }
54         return path;
55 }
56
57 static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
58 {
59         const char *perf_dir = get_perf_dir();
60         size_t len;
61
62         len = strlen(perf_dir);
63         if (n < len + 1)
64                 goto bad;
65         memcpy(buf, perf_dir, len);
66         if (len && !is_dir_sep(perf_dir[len-1]))
67                 buf[len++] = '/';
68         len += vsnprintf(buf + len, n - len, fmt, args);
69         if (len >= n)
70                 goto bad;
71         return cleanup_path(buf);
72 bad:
73         strlcpy(buf, bad_path, n);
74         return buf;
75 }
76
77 char *perf_pathdup(const char *fmt, ...)
78 {
79         char path[PATH_MAX];
80         va_list args;
81         va_start(args, fmt);
82         (void)perf_vsnpath(path, sizeof(path), fmt, args);
83         va_end(args);
84         return xstrdup(path);
85 }
86
87 char *mkpath(const char *fmt, ...)
88 {
89         va_list args;
90         unsigned len;
91         char *pathname = get_pathname();
92
93         va_start(args, fmt);
94         len = vsnprintf(pathname, PATH_MAX, fmt, args);
95         va_end(args);
96         if (len >= PATH_MAX)
97                 return bad_path;
98         return cleanup_path(pathname);
99 }
100
101 char *perf_path(const char *fmt, ...)
102 {
103         const char *perf_dir = get_perf_dir();
104         char *pathname = get_pathname();
105         va_list args;
106         unsigned len;
107
108         len = strlen(perf_dir);
109         if (len > PATH_MAX-100)
110                 return bad_path;
111         memcpy(pathname, perf_dir, len);
112         if (len && perf_dir[len-1] != '/')
113                 pathname[len++] = '/';
114         va_start(args, fmt);
115         len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
116         va_end(args);
117         if (len >= PATH_MAX)
118                 return bad_path;
119         return cleanup_path(pathname);
120 }
121
122 /* strip arbitrary amount of directory separators at end of path */
123 static inline int chomp_trailing_dir_sep(const char *path, int len)
124 {
125         while (len && is_dir_sep(path[len - 1]))
126                 len--;
127         return len;
128 }
129
130 /*
131  * If path ends with suffix (complete path components), returns the
132  * part before suffix (sans trailing directory separators).
133  * Otherwise returns NULL.
134  */
135 char *strip_path_suffix(const char *path, const char *suffix)
136 {
137         int path_len = strlen(path), suffix_len = strlen(suffix);
138
139         while (suffix_len) {
140                 if (!path_len)
141                         return NULL;
142
143                 if (is_dir_sep(path[path_len - 1])) {
144                         if (!is_dir_sep(suffix[suffix_len - 1]))
145                                 return NULL;
146                         path_len = chomp_trailing_dir_sep(path, path_len);
147                         suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
148                 }
149                 else if (path[--path_len] != suffix[--suffix_len])
150                         return NULL;
151         }
152
153         if (path_len && !is_dir_sep(path[path_len - 1]))
154                 return NULL;
155         return strndup(path, chomp_trailing_dir_sep(path, path_len));
156 }