18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/compiler.h>
38c2ecf20Sopenharmony_ci#include <linux/kernel.h>
48c2ecf20Sopenharmony_ci#include <linux/string.h>
58c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
68c2ecf20Sopenharmony_ci#include <sys/types.h>
78c2ecf20Sopenharmony_ci#include <sys/stat.h>
88c2ecf20Sopenharmony_ci#include <errno.h>
98c2ecf20Sopenharmony_ci#include <fcntl.h>
108c2ecf20Sopenharmony_ci#include <unistd.h>
118c2ecf20Sopenharmony_ci#include <string.h>
128c2ecf20Sopenharmony_ci#include <asm/bug.h>
138c2ecf20Sopenharmony_ci#include <dirent.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "data.h"
168c2ecf20Sopenharmony_ci#include "util.h" // rm_rf_perf_data()
178c2ecf20Sopenharmony_ci#include "debug.h"
188c2ecf20Sopenharmony_ci#include "header.h"
198c2ecf20Sopenharmony_ci#include <internal/lib.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic void close_dir(struct perf_data_file *files, int nr)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	while (--nr >= 0) {
248c2ecf20Sopenharmony_ci		close(files[nr].fd);
258c2ecf20Sopenharmony_ci		zfree(&files[nr].path);
268c2ecf20Sopenharmony_ci	}
278c2ecf20Sopenharmony_ci	free(files);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_civoid perf_data__close_dir(struct perf_data *data)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	close_dir(data->dir.files, data->dir.nr);
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciint perf_data__create_dir(struct perf_data *data, int nr)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct perf_data_file *files = NULL;
388c2ecf20Sopenharmony_ci	int i, ret;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (WARN_ON(!data->is_dir))
418c2ecf20Sopenharmony_ci		return -EINVAL;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	files = zalloc(nr * sizeof(*files));
448c2ecf20Sopenharmony_ci	if (!files)
458c2ecf20Sopenharmony_ci		return -ENOMEM;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
488c2ecf20Sopenharmony_ci		struct perf_data_file *file = &files[i];
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		ret = asprintf(&file->path, "%s/data.%d", data->path, i);
518c2ecf20Sopenharmony_ci		if (ret < 0)
528c2ecf20Sopenharmony_ci			goto out_err;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
558c2ecf20Sopenharmony_ci		if (ret < 0)
568c2ecf20Sopenharmony_ci			goto out_err;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		file->fd = ret;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	data->dir.version = PERF_DIR_VERSION;
628c2ecf20Sopenharmony_ci	data->dir.files   = files;
638c2ecf20Sopenharmony_ci	data->dir.nr      = nr;
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciout_err:
678c2ecf20Sopenharmony_ci	close_dir(files, i);
688c2ecf20Sopenharmony_ci	return ret;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciint perf_data__open_dir(struct perf_data *data)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct perf_data_file *files = NULL;
748c2ecf20Sopenharmony_ci	struct dirent *dent;
758c2ecf20Sopenharmony_ci	int ret = -1;
768c2ecf20Sopenharmony_ci	DIR *dir;
778c2ecf20Sopenharmony_ci	int nr = 0;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/*
808c2ecf20Sopenharmony_ci	 * Directory containing a single regular perf data file which is already
818c2ecf20Sopenharmony_ci	 * open, means there is nothing more to do here.
828c2ecf20Sopenharmony_ci	 */
838c2ecf20Sopenharmony_ci	if (perf_data__is_single_file(data))
848c2ecf20Sopenharmony_ci		return 0;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (WARN_ON(!data->is_dir))
878c2ecf20Sopenharmony_ci		return -EINVAL;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* The version is provided by DIR_FORMAT feature. */
908c2ecf20Sopenharmony_ci	if (WARN_ON(data->dir.version != PERF_DIR_VERSION))
918c2ecf20Sopenharmony_ci		return -1;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	dir = opendir(data->path);
948c2ecf20Sopenharmony_ci	if (!dir)
958c2ecf20Sopenharmony_ci		return -EINVAL;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	while ((dent = readdir(dir)) != NULL) {
988c2ecf20Sopenharmony_ci		struct perf_data_file *file;
998c2ecf20Sopenharmony_ci		char path[PATH_MAX];
1008c2ecf20Sopenharmony_ci		struct stat st;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
1038c2ecf20Sopenharmony_ci		if (stat(path, &st))
1048c2ecf20Sopenharmony_ci			continue;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data.", 5))
1078c2ecf20Sopenharmony_ci			continue;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		file = realloc(files, (nr + 1) * sizeof(*files));
1128c2ecf20Sopenharmony_ci		if (!file)
1138c2ecf20Sopenharmony_ci			goto out_err;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci		files = file;
1168c2ecf20Sopenharmony_ci		file = &files[nr++];
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		file->path = strdup(path);
1198c2ecf20Sopenharmony_ci		if (!file->path)
1208c2ecf20Sopenharmony_ci			goto out_err;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		ret = open(file->path, O_RDONLY);
1238c2ecf20Sopenharmony_ci		if (ret < 0)
1248c2ecf20Sopenharmony_ci			goto out_err;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		file->fd = ret;
1278c2ecf20Sopenharmony_ci		file->size = st.st_size;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	closedir(dir);
1318c2ecf20Sopenharmony_ci	if (!files)
1328c2ecf20Sopenharmony_ci		return -EINVAL;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	data->dir.files = files;
1358c2ecf20Sopenharmony_ci	data->dir.nr    = nr;
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ciout_err:
1398c2ecf20Sopenharmony_ci	closedir(dir);
1408c2ecf20Sopenharmony_ci	close_dir(files, nr);
1418c2ecf20Sopenharmony_ci	return ret;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciint perf_data__update_dir(struct perf_data *data)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	int i;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (WARN_ON(!data->is_dir))
1498c2ecf20Sopenharmony_ci		return -EINVAL;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	for (i = 0; i < data->dir.nr; i++) {
1528c2ecf20Sopenharmony_ci		struct perf_data_file *file = &data->dir.files[i];
1538c2ecf20Sopenharmony_ci		struct stat st;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		if (fstat(file->fd, &st))
1568c2ecf20Sopenharmony_ci			return -1;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		file->size = st.st_size;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic bool check_pipe(struct perf_data *data)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct stat st;
1678c2ecf20Sopenharmony_ci	bool is_pipe = false;
1688c2ecf20Sopenharmony_ci	int fd = perf_data__is_read(data) ?
1698c2ecf20Sopenharmony_ci		 STDIN_FILENO : STDOUT_FILENO;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (!data->path) {
1728c2ecf20Sopenharmony_ci		if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
1738c2ecf20Sopenharmony_ci			is_pipe = true;
1748c2ecf20Sopenharmony_ci	} else {
1758c2ecf20Sopenharmony_ci		if (!strcmp(data->path, "-"))
1768c2ecf20Sopenharmony_ci			is_pipe = true;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (is_pipe)
1808c2ecf20Sopenharmony_ci		data->file.fd = fd;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return data->is_pipe = is_pipe;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int check_backup(struct perf_data *data)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct stat st;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (perf_data__is_read(data))
1908c2ecf20Sopenharmony_ci		return 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (!stat(data->path, &st) && st.st_size) {
1938c2ecf20Sopenharmony_ci		char oldname[PATH_MAX];
1948c2ecf20Sopenharmony_ci		int ret;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		snprintf(oldname, sizeof(oldname), "%s.old",
1978c2ecf20Sopenharmony_ci			 data->path);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		ret = rm_rf_perf_data(oldname);
2008c2ecf20Sopenharmony_ci		if (ret) {
2018c2ecf20Sopenharmony_ci			pr_err("Can't remove old data: %s (%s)\n",
2028c2ecf20Sopenharmony_ci			       ret == -2 ?
2038c2ecf20Sopenharmony_ci			       "Unknown file found" : strerror(errno),
2048c2ecf20Sopenharmony_ci			       oldname);
2058c2ecf20Sopenharmony_ci			return -1;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		if (rename(data->path, oldname)) {
2098c2ecf20Sopenharmony_ci			pr_err("Can't move data: %s (%s to %s)\n",
2108c2ecf20Sopenharmony_ci			       strerror(errno),
2118c2ecf20Sopenharmony_ci			       data->path, oldname);
2128c2ecf20Sopenharmony_ci			return -1;
2138c2ecf20Sopenharmony_ci		}
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	return 0;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic bool is_dir(struct perf_data *data)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct stat st;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (stat(data->path, &st))
2248c2ecf20Sopenharmony_ci		return false;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return (st.st_mode & S_IFMT) == S_IFDIR;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int open_file_read(struct perf_data *data)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct stat st;
2328c2ecf20Sopenharmony_ci	int fd;
2338c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	fd = open(data->file.path, O_RDONLY);
2368c2ecf20Sopenharmony_ci	if (fd < 0) {
2378c2ecf20Sopenharmony_ci		int err = errno;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		pr_err("failed to open %s: %s", data->file.path,
2408c2ecf20Sopenharmony_ci			str_error_r(err, sbuf, sizeof(sbuf)));
2418c2ecf20Sopenharmony_ci		if (err == ENOENT && !strcmp(data->file.path, "perf.data"))
2428c2ecf20Sopenharmony_ci			pr_err("  (try 'perf record' first)");
2438c2ecf20Sopenharmony_ci		pr_err("\n");
2448c2ecf20Sopenharmony_ci		return -err;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (fstat(fd, &st) < 0)
2488c2ecf20Sopenharmony_ci		goto out_close;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!data->force && st.st_uid && (st.st_uid != geteuid())) {
2518c2ecf20Sopenharmony_ci		pr_err("File %s not owned by current user or root (use -f to override)\n",
2528c2ecf20Sopenharmony_ci		       data->file.path);
2538c2ecf20Sopenharmony_ci		goto out_close;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (!st.st_size) {
2578c2ecf20Sopenharmony_ci		pr_info("zero-sized data (%s), nothing to do!\n",
2588c2ecf20Sopenharmony_ci			data->file.path);
2598c2ecf20Sopenharmony_ci		goto out_close;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	data->file.size = st.st_size;
2638c2ecf20Sopenharmony_ci	return fd;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci out_close:
2668c2ecf20Sopenharmony_ci	close(fd);
2678c2ecf20Sopenharmony_ci	return -1;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int open_file_write(struct perf_data *data)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	int fd;
2738c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
2768c2ecf20Sopenharmony_ci		  S_IRUSR|S_IWUSR);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (fd < 0)
2798c2ecf20Sopenharmony_ci		pr_err("failed to open %s : %s\n", data->file.path,
2808c2ecf20Sopenharmony_ci			str_error_r(errno, sbuf, sizeof(sbuf)));
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return fd;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int open_file(struct perf_data *data)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	int fd;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	fd = perf_data__is_read(data) ?
2908c2ecf20Sopenharmony_ci	     open_file_read(data) : open_file_write(data);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (fd < 0) {
2938c2ecf20Sopenharmony_ci		zfree(&data->file.path);
2948c2ecf20Sopenharmony_ci		return -1;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	data->file.fd = fd;
2988c2ecf20Sopenharmony_ci	return 0;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic int open_file_dup(struct perf_data *data)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	data->file.path = strdup(data->path);
3048c2ecf20Sopenharmony_ci	if (!data->file.path)
3058c2ecf20Sopenharmony_ci		return -ENOMEM;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return open_file(data);
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic int open_dir(struct perf_data *data)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	int ret;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/*
3158c2ecf20Sopenharmony_ci	 * So far we open only the header, so we can read the data version and
3168c2ecf20Sopenharmony_ci	 * layout.
3178c2ecf20Sopenharmony_ci	 */
3188c2ecf20Sopenharmony_ci	if (asprintf(&data->file.path, "%s/data", data->path) < 0)
3198c2ecf20Sopenharmony_ci		return -1;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (perf_data__is_write(data) &&
3228c2ecf20Sopenharmony_ci	    mkdir(data->path, S_IRWXU) < 0)
3238c2ecf20Sopenharmony_ci		return -1;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	ret = open_file(data);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Cleanup whatever we managed to create so far. */
3288c2ecf20Sopenharmony_ci	if (ret && perf_data__is_write(data))
3298c2ecf20Sopenharmony_ci		rm_rf_perf_data(data->path);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return ret;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ciint perf_data__open(struct perf_data *data)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	if (check_pipe(data))
3378c2ecf20Sopenharmony_ci		return 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (!data->path)
3408c2ecf20Sopenharmony_ci		data->path = "perf.data";
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (check_backup(data))
3438c2ecf20Sopenharmony_ci		return -1;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (perf_data__is_read(data))
3468c2ecf20Sopenharmony_ci		data->is_dir = is_dir(data);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return perf_data__is_dir(data) ?
3498c2ecf20Sopenharmony_ci	       open_dir(data) : open_file_dup(data);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_civoid perf_data__close(struct perf_data *data)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	if (perf_data__is_dir(data))
3558c2ecf20Sopenharmony_ci		perf_data__close_dir(data);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	zfree(&data->file.path);
3588c2ecf20Sopenharmony_ci	close(data->file.fd);
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cissize_t perf_data_file__write(struct perf_data_file *file,
3628c2ecf20Sopenharmony_ci			      void *buf, size_t size)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	return writen(file->fd, buf, size);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cissize_t perf_data__write(struct perf_data *data,
3688c2ecf20Sopenharmony_ci			      void *buf, size_t size)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	return perf_data_file__write(&data->file, buf, size);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ciint perf_data__switch(struct perf_data *data,
3748c2ecf20Sopenharmony_ci			   const char *postfix,
3758c2ecf20Sopenharmony_ci			   size_t pos, bool at_exit,
3768c2ecf20Sopenharmony_ci			   char **new_filepath)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	int ret;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (check_pipe(data))
3818c2ecf20Sopenharmony_ci		return -EINVAL;
3828c2ecf20Sopenharmony_ci	if (perf_data__is_read(data))
3838c2ecf20Sopenharmony_ci		return -EINVAL;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
3868c2ecf20Sopenharmony_ci		return -ENOMEM;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/*
3898c2ecf20Sopenharmony_ci	 * Only fire a warning, don't return error, continue fill
3908c2ecf20Sopenharmony_ci	 * original file.
3918c2ecf20Sopenharmony_ci	 */
3928c2ecf20Sopenharmony_ci	if (rename(data->path, *new_filepath))
3938c2ecf20Sopenharmony_ci		pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (!at_exit) {
3968c2ecf20Sopenharmony_ci		close(data->file.fd);
3978c2ecf20Sopenharmony_ci		ret = perf_data__open(data);
3988c2ecf20Sopenharmony_ci		if (ret < 0)
3998c2ecf20Sopenharmony_ci			goto out;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
4028c2ecf20Sopenharmony_ci			ret = -errno;
4038c2ecf20Sopenharmony_ci			pr_debug("Failed to lseek to %zu: %s",
4048c2ecf20Sopenharmony_ci				 pos, strerror(errno));
4058c2ecf20Sopenharmony_ci			goto out;
4068c2ecf20Sopenharmony_ci		}
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci	ret = data->file.fd;
4098c2ecf20Sopenharmony_ciout:
4108c2ecf20Sopenharmony_ci	return ret;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ciunsigned long perf_data__size(struct perf_data *data)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	u64 size = data->file.size;
4168c2ecf20Sopenharmony_ci	int i;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (perf_data__is_single_file(data))
4198c2ecf20Sopenharmony_ci		return size;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	for (i = 0; i < data->dir.nr; i++) {
4228c2ecf20Sopenharmony_ci		struct perf_data_file *file = &data->dir.files[i];
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		size += file->size;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return size;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ciint perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	int ret;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (!data->is_dir)
4358c2ecf20Sopenharmony_ci		return -1;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	ret = snprintf(buf, buf_sz, "%s/kcore_dir", data->path);
4388c2ecf20Sopenharmony_ci	if (ret < 0 || (size_t)ret >= buf_sz)
4398c2ecf20Sopenharmony_ci		return -1;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return mkdir(buf, S_IRWXU);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cichar *perf_data__kallsyms_name(struct perf_data *data)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	char *kallsyms_name;
4478c2ecf20Sopenharmony_ci	struct stat st;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (!data->is_dir)
4508c2ecf20Sopenharmony_ci		return NULL;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (asprintf(&kallsyms_name, "%s/kcore_dir/kallsyms", data->path) < 0)
4538c2ecf20Sopenharmony_ci		return NULL;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (stat(kallsyms_name, &st)) {
4568c2ecf20Sopenharmony_ci		free(kallsyms_name);
4578c2ecf20Sopenharmony_ci		return NULL;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return kallsyms_name;
4618c2ecf20Sopenharmony_ci}
462