^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * I'm tired of doing "vsnprintf()" etc just to open a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * file, so here's a "return static buffer with printf"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * interface for paths.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * It's obviously not thread-safe. Sue me. But it's quite
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * useful for doing things like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * f = open(mkpath("%s/%s.perf", base, name), O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * which is what it's designed for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "path.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "cache.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <dirent.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static char bad_path[] = "/bad-path/";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * One hack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static char *get_pathname(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static char pathname_array[4][PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return pathname_array[3 & ++idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static char *cleanup_path(char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* Clean it up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!memcmp(path, "./", 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) path += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) while (*path == '/')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) path++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) char *mkpath(const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) va_list args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) char *pathname = get_pathname();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) va_start(args, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) len = vsnprintf(pathname, PATH_MAX, fmt, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) va_end(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (len >= PATH_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return bad_path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return cleanup_path(pathname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int path__join(char *bf, size_t size, const char *path1, const char *path2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int path__join3(char *bf, size_t size, const char *path1, const char *path2, const char *path3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return scnprintf(bf, size, "%s%s%s%s%s", path1, path1[0] ? "/" : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) path2, path2[0] ? "/" : "", path3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) bool is_regular_file(const char *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct stat st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (stat(file, &st))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return S_ISREG(st.st_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) bool is_directory(const char *base_path, const struct dirent *dent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct stat st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) sprintf(path, "%s/%s", base_path, dent->d_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (stat(path, &st))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return S_ISDIR(st.st_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }