18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * I'm tired of doing "vsnprintf()" etc just to open a
48c2ecf20Sopenharmony_ci * file, so here's a "return static buffer with printf"
58c2ecf20Sopenharmony_ci * interface for paths.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * It's obviously not thread-safe. Sue me. But it's quite
88c2ecf20Sopenharmony_ci * useful for doing things like
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *   f = open(mkpath("%s/%s.perf", base, name), O_RDONLY);
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * which is what it's designed for.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci#include "path.h"
158c2ecf20Sopenharmony_ci#include "cache.h"
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <limits.h>
188c2ecf20Sopenharmony_ci#include <stdio.h>
198c2ecf20Sopenharmony_ci#include <string.h>
208c2ecf20Sopenharmony_ci#include <sys/types.h>
218c2ecf20Sopenharmony_ci#include <sys/stat.h>
228c2ecf20Sopenharmony_ci#include <dirent.h>
238c2ecf20Sopenharmony_ci#include <unistd.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic char bad_path[] = "/bad-path/";
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * One hack:
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic char *get_pathname(void)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	static char pathname_array[4][PATH_MAX];
328c2ecf20Sopenharmony_ci	static int idx;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return pathname_array[3 & ++idx];
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic char *cleanup_path(char *path)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	/* Clean it up */
408c2ecf20Sopenharmony_ci	if (!memcmp(path, "./", 2)) {
418c2ecf20Sopenharmony_ci		path += 2;
428c2ecf20Sopenharmony_ci		while (*path == '/')
438c2ecf20Sopenharmony_ci			path++;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci	return path;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cichar *mkpath(const char *fmt, ...)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	va_list args;
518c2ecf20Sopenharmony_ci	unsigned len;
528c2ecf20Sopenharmony_ci	char *pathname = get_pathname();
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	va_start(args, fmt);
558c2ecf20Sopenharmony_ci	len = vsnprintf(pathname, PATH_MAX, fmt, args);
568c2ecf20Sopenharmony_ci	va_end(args);
578c2ecf20Sopenharmony_ci	if (len >= PATH_MAX)
588c2ecf20Sopenharmony_ci		return bad_path;
598c2ecf20Sopenharmony_ci	return cleanup_path(pathname);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ciint path__join(char *bf, size_t size, const char *path1, const char *path2)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciint path__join3(char *bf, size_t size, const char *path1, const char *path2, const char *path3)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%s%s%s%s%s", path1, path1[0] ? "/" : "",
708c2ecf20Sopenharmony_ci			 path2, path2[0] ? "/" : "", path3);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cibool is_regular_file(const char *file)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct stat st;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (stat(file, &st))
788c2ecf20Sopenharmony_ci		return false;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return S_ISREG(st.st_mode);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
848c2ecf20Sopenharmony_cibool is_directory(const char *base_path, const struct dirent *dent)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	char path[PATH_MAX];
878c2ecf20Sopenharmony_ci	struct stat st;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	sprintf(path, "%s/%s", base_path, dent->d_name);
908c2ecf20Sopenharmony_ci	if (stat(path, &st))
918c2ecf20Sopenharmony_ci		return false;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return S_ISDIR(st.st_mode);
948c2ecf20Sopenharmony_ci}
95