xref: /openbmc/linux/tools/perf/util/data.c (revision e55c8aba)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
26a4d98d7SJiri Olsa #include <linux/compiler.h>
36a4d98d7SJiri Olsa #include <linux/kernel.h>
48520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
57f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
665691e9fSAdrian Hunter #include <linux/err.h>
76a4d98d7SJiri Olsa #include <sys/types.h>
86a4d98d7SJiri Olsa #include <sys/stat.h>
9a43783aeSArnaldo Carvalho de Melo #include <errno.h>
10c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h>
116a4d98d7SJiri Olsa #include <unistd.h>
126a4d98d7SJiri Olsa #include <string.h>
1314552063SJiri Olsa #include <asm/bug.h>
14eb617670SJiri Olsa #include <dirent.h>
156a4d98d7SJiri Olsa 
166a4d98d7SJiri Olsa #include "data.h"
17fb71c86cSArnaldo Carvalho de Melo #include "util.h" // rm_rf_perf_data()
1884f5d36fSJiri Olsa #include "debug.h"
19258031c0SJiri Olsa #include "header.h"
20fb71c86cSArnaldo Carvalho de Melo #include <internal/lib.h>
216a4d98d7SJiri Olsa 
close_dir(struct perf_data_file * files,int nr)2214552063SJiri Olsa static void close_dir(struct perf_data_file *files, int nr)
2314552063SJiri Olsa {
24d4b3eedcSRiccardo Mancini 	while (--nr >= 0) {
2514552063SJiri Olsa 		close(files[nr].fd);
26d8f9da24SArnaldo Carvalho de Melo 		zfree(&files[nr].path);
2714552063SJiri Olsa 	}
2814552063SJiri Olsa 	free(files);
2914552063SJiri Olsa }
3014552063SJiri Olsa 
perf_data__close_dir(struct perf_data * data)3114552063SJiri Olsa void perf_data__close_dir(struct perf_data *data)
3214552063SJiri Olsa {
3314552063SJiri Olsa 	close_dir(data->dir.files, data->dir.nr);
3414552063SJiri Olsa }
3514552063SJiri Olsa 
perf_data__create_dir(struct perf_data * data,int nr)3614552063SJiri Olsa int perf_data__create_dir(struct perf_data *data, int nr)
3714552063SJiri Olsa {
3814552063SJiri Olsa 	struct perf_data_file *files = NULL;
39f2211881SZhen Lei 	int i, ret;
4014552063SJiri Olsa 
41ec65def1SJiri Olsa 	if (WARN_ON(!data->is_dir))
42ec65def1SJiri Olsa 		return -EINVAL;
43ec65def1SJiri Olsa 
4414552063SJiri Olsa 	files = zalloc(nr * sizeof(*files));
4514552063SJiri Olsa 	if (!files)
4614552063SJiri Olsa 		return -ENOMEM;
4714552063SJiri Olsa 
4814552063SJiri Olsa 	for (i = 0; i < nr; i++) {
4914552063SJiri Olsa 		struct perf_data_file *file = &files[i];
5014552063SJiri Olsa 
51f2211881SZhen Lei 		ret = asprintf(&file->path, "%s/data.%d", data->path, i);
5265e7c963SAlexey Bayduraev 		if (ret < 0) {
5365e7c963SAlexey Bayduraev 			ret = -ENOMEM;
5414552063SJiri Olsa 			goto out_err;
5565e7c963SAlexey Bayduraev 		}
5614552063SJiri Olsa 
5714552063SJiri Olsa 		ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
5865e7c963SAlexey Bayduraev 		if (ret < 0) {
5965e7c963SAlexey Bayduraev 			ret = -errno;
6014552063SJiri Olsa 			goto out_err;
6165e7c963SAlexey Bayduraev 		}
6214552063SJiri Olsa 
6314552063SJiri Olsa 		file->fd = ret;
6414552063SJiri Olsa 	}
6514552063SJiri Olsa 
6669560e36SAlexey Bayduraev 	data->dir.version = PERF_DIR_VERSION;
6769560e36SAlexey Bayduraev 	data->dir.files   = files;
6869560e36SAlexey Bayduraev 	data->dir.nr      = nr;
6914552063SJiri Olsa 	return 0;
7014552063SJiri Olsa 
7114552063SJiri Olsa out_err:
7214552063SJiri Olsa 	close_dir(files, i);
7314552063SJiri Olsa 	return ret;
7414552063SJiri Olsa }
7514552063SJiri Olsa 
perf_data__open_dir(struct perf_data * data)76eb617670SJiri Olsa int perf_data__open_dir(struct perf_data *data)
77eb617670SJiri Olsa {
78eb617670SJiri Olsa 	struct perf_data_file *files = NULL;
79eb617670SJiri Olsa 	struct dirent *dent;
80eb617670SJiri Olsa 	int ret = -1;
81eb617670SJiri Olsa 	DIR *dir;
82eb617670SJiri Olsa 	int nr = 0;
83eb617670SJiri Olsa 
8446e201efSAdrian Hunter 	/*
8546e201efSAdrian Hunter 	 * Directory containing a single regular perf data file which is already
8646e201efSAdrian Hunter 	 * open, means there is nothing more to do here.
8746e201efSAdrian Hunter 	 */
8846e201efSAdrian Hunter 	if (perf_data__is_single_file(data))
8946e201efSAdrian Hunter 		return 0;
9046e201efSAdrian Hunter 
91ec65def1SJiri Olsa 	if (WARN_ON(!data->is_dir))
92ec65def1SJiri Olsa 		return -EINVAL;
93ec65def1SJiri Olsa 
94258031c0SJiri Olsa 	/* The version is provided by DIR_FORMAT feature. */
95258031c0SJiri Olsa 	if (WARN_ON(data->dir.version != PERF_DIR_VERSION))
96258031c0SJiri Olsa 		return -1;
97258031c0SJiri Olsa 
98eb617670SJiri Olsa 	dir = opendir(data->path);
99eb617670SJiri Olsa 	if (!dir)
100eb617670SJiri Olsa 		return -EINVAL;
101eb617670SJiri Olsa 
102eb617670SJiri Olsa 	while ((dent = readdir(dir)) != NULL) {
103eb617670SJiri Olsa 		struct perf_data_file *file;
104eb617670SJiri Olsa 		char path[PATH_MAX];
105eb617670SJiri Olsa 		struct stat st;
106eb617670SJiri Olsa 
107eb617670SJiri Olsa 		snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name);
108eb617670SJiri Olsa 		if (stat(path, &st))
109eb617670SJiri Olsa 			continue;
110eb617670SJiri Olsa 
111490e6db0SAdrian Hunter 		if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data.", 5))
112eb617670SJiri Olsa 			continue;
113eb617670SJiri Olsa 
114eb617670SJiri Olsa 		ret = -ENOMEM;
115eb617670SJiri Olsa 
116eb617670SJiri Olsa 		file = realloc(files, (nr + 1) * sizeof(*files));
117eb617670SJiri Olsa 		if (!file)
118eb617670SJiri Olsa 			goto out_err;
119eb617670SJiri Olsa 
120eb617670SJiri Olsa 		files = file;
121eb617670SJiri Olsa 		file = &files[nr++];
122eb617670SJiri Olsa 
123eb617670SJiri Olsa 		file->path = strdup(path);
124eb617670SJiri Olsa 		if (!file->path)
125eb617670SJiri Olsa 			goto out_err;
126eb617670SJiri Olsa 
127eb617670SJiri Olsa 		ret = open(file->path, O_RDONLY);
128eb617670SJiri Olsa 		if (ret < 0)
129eb617670SJiri Olsa 			goto out_err;
130eb617670SJiri Olsa 
131eb617670SJiri Olsa 		file->fd = ret;
132eb617670SJiri Olsa 		file->size = st.st_size;
133eb617670SJiri Olsa 	}
134eb617670SJiri Olsa 
135*0a6564ebSMiaoqian Lin 	closedir(dir);
136eb617670SJiri Olsa 	if (!files)
137eb617670SJiri Olsa 		return -EINVAL;
138eb617670SJiri Olsa 
139eb617670SJiri Olsa 	data->dir.files = files;
140eb617670SJiri Olsa 	data->dir.nr    = nr;
141eb617670SJiri Olsa 	return 0;
142eb617670SJiri Olsa 
143eb617670SJiri Olsa out_err:
144*0a6564ebSMiaoqian Lin 	closedir(dir);
145eb617670SJiri Olsa 	close_dir(files, nr);
146eb617670SJiri Olsa 	return ret;
147eb617670SJiri Olsa }
148eb617670SJiri Olsa 
perf_data__update_dir(struct perf_data * data)149e8be1357SJiri Olsa int perf_data__update_dir(struct perf_data *data)
150e8be1357SJiri Olsa {
151e8be1357SJiri Olsa 	int i;
152e8be1357SJiri Olsa 
153e8be1357SJiri Olsa 	if (WARN_ON(!data->is_dir))
154e8be1357SJiri Olsa 		return -EINVAL;
155e8be1357SJiri Olsa 
156e8be1357SJiri Olsa 	for (i = 0; i < data->dir.nr; i++) {
157e8be1357SJiri Olsa 		struct perf_data_file *file = &data->dir.files[i];
158e8be1357SJiri Olsa 		struct stat st;
159e8be1357SJiri Olsa 
160e8be1357SJiri Olsa 		if (fstat(file->fd, &st))
161e8be1357SJiri Olsa 			return -1;
162e8be1357SJiri Olsa 
163e8be1357SJiri Olsa 		file->size = st.st_size;
164e8be1357SJiri Olsa 	}
165e8be1357SJiri Olsa 
166e8be1357SJiri Olsa 	return 0;
167e8be1357SJiri Olsa }
168e8be1357SJiri Olsa 
check_pipe(struct perf_data * data)1698ceb41d7SJiri Olsa static bool check_pipe(struct perf_data *data)
1706a4d98d7SJiri Olsa {
1716a4d98d7SJiri Olsa 	struct stat st;
1726a4d98d7SJiri Olsa 	bool is_pipe = false;
1738ceb41d7SJiri Olsa 	int fd = perf_data__is_read(data) ?
1746a4d98d7SJiri Olsa 		 STDIN_FILENO : STDOUT_FILENO;
1756a4d98d7SJiri Olsa 
1762d4f2799SJiri Olsa 	if (!data->path) {
1776a4d98d7SJiri Olsa 		if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
1786a4d98d7SJiri Olsa 			is_pipe = true;
1796a4d98d7SJiri Olsa 	} else {
1802d4f2799SJiri Olsa 		if (!strcmp(data->path, "-"))
1816a4d98d7SJiri Olsa 			is_pipe = true;
1826a4d98d7SJiri Olsa 	}
1836a4d98d7SJiri Olsa 
18460136667SNamhyung Kim 	if (is_pipe) {
18560136667SNamhyung Kim 		if (data->use_stdio) {
18660136667SNamhyung Kim 			const char *mode;
18760136667SNamhyung Kim 
18860136667SNamhyung Kim 			mode = perf_data__is_read(data) ? "r" : "w";
18960136667SNamhyung Kim 			data->file.fptr = fdopen(fd, mode);
19060136667SNamhyung Kim 
19160136667SNamhyung Kim 			if (data->file.fptr == NULL) {
192eae8ad80SJiri Olsa 				data->file.fd = fd;
19360136667SNamhyung Kim 				data->use_stdio = false;
19460136667SNamhyung Kim 			}
19560136667SNamhyung Kim 		} else {
19660136667SNamhyung Kim 			data->file.fd = fd;
19760136667SNamhyung Kim 		}
19860136667SNamhyung Kim 	}
1996a4d98d7SJiri Olsa 
2008ceb41d7SJiri Olsa 	return data->is_pipe = is_pipe;
2016a4d98d7SJiri Olsa }
2026a4d98d7SJiri Olsa 
check_backup(struct perf_data * data)2038ceb41d7SJiri Olsa static int check_backup(struct perf_data *data)
2046a4d98d7SJiri Olsa {
2056a4d98d7SJiri Olsa 	struct stat st;
2066a4d98d7SJiri Olsa 
2075021fc4eSJiri Olsa 	if (perf_data__is_read(data))
2085021fc4eSJiri Olsa 		return 0;
2095021fc4eSJiri Olsa 
2102d4f2799SJiri Olsa 	if (!stat(data->path, &st) && st.st_size) {
2116a4d98d7SJiri Olsa 		char oldname[PATH_MAX];
212ccb7a71dSJiri Olsa 		int ret;
213ccb7a71dSJiri Olsa 
2146a4d98d7SJiri Olsa 		snprintf(oldname, sizeof(oldname), "%s.old",
2152d4f2799SJiri Olsa 			 data->path);
216ccb7a71dSJiri Olsa 
217ccb7a71dSJiri Olsa 		ret = rm_rf_perf_data(oldname);
218ccb7a71dSJiri Olsa 		if (ret) {
219ccb7a71dSJiri Olsa 			pr_err("Can't remove old data: %s (%s)\n",
220ccb7a71dSJiri Olsa 			       ret == -2 ?
221ccb7a71dSJiri Olsa 			       "Unknown file found" : strerror(errno),
222ccb7a71dSJiri Olsa 			       oldname);
223ccb7a71dSJiri Olsa 			return -1;
224ccb7a71dSJiri Olsa 		}
225ccb7a71dSJiri Olsa 
226ccb7a71dSJiri Olsa 		if (rename(data->path, oldname)) {
227ccb7a71dSJiri Olsa 			pr_err("Can't move data: %s (%s to %s)\n",
228ccb7a71dSJiri Olsa 			       strerror(errno),
229ccb7a71dSJiri Olsa 			       data->path, oldname);
230ccb7a71dSJiri Olsa 			return -1;
231ccb7a71dSJiri Olsa 		}
2326a4d98d7SJiri Olsa 	}
2336a4d98d7SJiri Olsa 
2346a4d98d7SJiri Olsa 	return 0;
2356a4d98d7SJiri Olsa }
2366a4d98d7SJiri Olsa 
is_dir(struct perf_data * data)237ec65def1SJiri Olsa static bool is_dir(struct perf_data *data)
238ec65def1SJiri Olsa {
239ec65def1SJiri Olsa 	struct stat st;
240ec65def1SJiri Olsa 
241ec65def1SJiri Olsa 	if (stat(data->path, &st))
242ec65def1SJiri Olsa 		return false;
243ec65def1SJiri Olsa 
244ec65def1SJiri Olsa 	return (st.st_mode & S_IFMT) == S_IFDIR;
245ec65def1SJiri Olsa }
246ec65def1SJiri Olsa 
open_file_read(struct perf_data * data)2478ceb41d7SJiri Olsa static int open_file_read(struct perf_data *data)
2486a4d98d7SJiri Olsa {
2492a525f6aSAdrian Hunter 	int flags = data->in_place_update ? O_RDWR : O_RDONLY;
2506a4d98d7SJiri Olsa 	struct stat st;
2516a4d98d7SJiri Olsa 	int fd;
2526e81c74cSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
2536a4d98d7SJiri Olsa 
2542a525f6aSAdrian Hunter 	fd = open(data->file.path, flags);
2556a4d98d7SJiri Olsa 	if (fd < 0) {
2566a4d98d7SJiri Olsa 		int err = errno;
2576a4d98d7SJiri Olsa 
258eae8ad80SJiri Olsa 		pr_err("failed to open %s: %s", data->file.path,
259c8b5f2c9SArnaldo Carvalho de Melo 			str_error_r(err, sbuf, sizeof(sbuf)));
260eae8ad80SJiri Olsa 		if (err == ENOENT && !strcmp(data->file.path, "perf.data"))
2616a4d98d7SJiri Olsa 			pr_err("  (try 'perf record' first)");
2626a4d98d7SJiri Olsa 		pr_err("\n");
2636a4d98d7SJiri Olsa 		return -err;
2646a4d98d7SJiri Olsa 	}
2656a4d98d7SJiri Olsa 
2666a4d98d7SJiri Olsa 	if (fstat(fd, &st) < 0)
2676a4d98d7SJiri Olsa 		goto out_close;
2686a4d98d7SJiri Olsa 
2698ceb41d7SJiri Olsa 	if (!data->force && st.st_uid && (st.st_uid != geteuid())) {
270071266bfSArnaldo Carvalho de Melo 		pr_err("File %s not owned by current user or root (use -f to override)\n",
271eae8ad80SJiri Olsa 		       data->file.path);
2726a4d98d7SJiri Olsa 		goto out_close;
2736a4d98d7SJiri Olsa 	}
2746a4d98d7SJiri Olsa 
2756a4d98d7SJiri Olsa 	if (!st.st_size) {
2768ceb41d7SJiri Olsa 		pr_info("zero-sized data (%s), nothing to do!\n",
277eae8ad80SJiri Olsa 			data->file.path);
2786a4d98d7SJiri Olsa 		goto out_close;
2796a4d98d7SJiri Olsa 	}
2806a4d98d7SJiri Olsa 
28145112e89SJiri Olsa 	data->file.size = st.st_size;
2826a4d98d7SJiri Olsa 	return fd;
2836a4d98d7SJiri Olsa 
2846a4d98d7SJiri Olsa  out_close:
2856a4d98d7SJiri Olsa 	close(fd);
2866a4d98d7SJiri Olsa 	return -1;
2876a4d98d7SJiri Olsa }
2886a4d98d7SJiri Olsa 
open_file_write(struct perf_data * data)2898ceb41d7SJiri Olsa static int open_file_write(struct perf_data *data)
2906a4d98d7SJiri Olsa {
291ffa91880SAdrien BAK 	int fd;
2926e81c74cSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
293ffa91880SAdrien BAK 
294eae8ad80SJiri Olsa 	fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
295cd6379ebSJiri Olsa 		  S_IRUSR|S_IWUSR);
296ffa91880SAdrien BAK 
297ffa91880SAdrien BAK 	if (fd < 0)
298eae8ad80SJiri Olsa 		pr_err("failed to open %s : %s\n", data->file.path,
299c8b5f2c9SArnaldo Carvalho de Melo 			str_error_r(errno, sbuf, sizeof(sbuf)));
300ffa91880SAdrien BAK 
301ffa91880SAdrien BAK 	return fd;
3026a4d98d7SJiri Olsa }
3036a4d98d7SJiri Olsa 
open_file(struct perf_data * data)3048ceb41d7SJiri Olsa static int open_file(struct perf_data *data)
3056a4d98d7SJiri Olsa {
3066a4d98d7SJiri Olsa 	int fd;
3076a4d98d7SJiri Olsa 
3088ceb41d7SJiri Olsa 	fd = perf_data__is_read(data) ?
3098ceb41d7SJiri Olsa 	     open_file_read(data) : open_file_write(data);
3106a4d98d7SJiri Olsa 
3112d4f2799SJiri Olsa 	if (fd < 0) {
312b8f7d86bSJiri Olsa 		zfree(&data->file.path);
3132d4f2799SJiri Olsa 		return -1;
3142d4f2799SJiri Olsa 	}
3152d4f2799SJiri Olsa 
316eae8ad80SJiri Olsa 	data->file.fd = fd;
3172d4f2799SJiri Olsa 	return 0;
3182d4f2799SJiri Olsa }
3192d4f2799SJiri Olsa 
open_file_dup(struct perf_data * data)3202d4f2799SJiri Olsa static int open_file_dup(struct perf_data *data)
3212d4f2799SJiri Olsa {
3222d4f2799SJiri Olsa 	data->file.path = strdup(data->path);
3232d4f2799SJiri Olsa 	if (!data->file.path)
3242d4f2799SJiri Olsa 		return -ENOMEM;
3252d4f2799SJiri Olsa 
3262d4f2799SJiri Olsa 	return open_file(data);
3276a4d98d7SJiri Olsa }
3286a4d98d7SJiri Olsa 
open_dir(struct perf_data * data)329ec65def1SJiri Olsa static int open_dir(struct perf_data *data)
330ec65def1SJiri Olsa {
331ec65def1SJiri Olsa 	int ret;
332ec65def1SJiri Olsa 
333ec65def1SJiri Olsa 	/*
334ec65def1SJiri Olsa 	 * So far we open only the header, so we can read the data version and
335ec65def1SJiri Olsa 	 * layout.
336ec65def1SJiri Olsa 	 */
3379b70b9dbSAdrian Hunter 	if (asprintf(&data->file.path, "%s/data", data->path) < 0)
338ec65def1SJiri Olsa 		return -1;
339ec65def1SJiri Olsa 
340ec65def1SJiri Olsa 	if (perf_data__is_write(data) &&
341ec65def1SJiri Olsa 	    mkdir(data->path, S_IRWXU) < 0)
342ec65def1SJiri Olsa 		return -1;
343ec65def1SJiri Olsa 
344ec65def1SJiri Olsa 	ret = open_file(data);
345ec65def1SJiri Olsa 
346ec65def1SJiri Olsa 	/* Cleanup whatever we managed to create so far. */
347ec65def1SJiri Olsa 	if (ret && perf_data__is_write(data))
348ec65def1SJiri Olsa 		rm_rf_perf_data(data->path);
349ec65def1SJiri Olsa 
350ec65def1SJiri Olsa 	return ret;
351ec65def1SJiri Olsa }
352ec65def1SJiri Olsa 
perf_data__open(struct perf_data * data)3538ceb41d7SJiri Olsa int perf_data__open(struct perf_data *data)
3546a4d98d7SJiri Olsa {
3558ceb41d7SJiri Olsa 	if (check_pipe(data))
3566a4d98d7SJiri Olsa 		return 0;
3576a4d98d7SJiri Olsa 
35860136667SNamhyung Kim 	/* currently it allows stdio for pipe only */
35960136667SNamhyung Kim 	data->use_stdio = false;
36060136667SNamhyung Kim 
3612d4f2799SJiri Olsa 	if (!data->path)
3622d4f2799SJiri Olsa 		data->path = "perf.data";
3636a4d98d7SJiri Olsa 
3645021fc4eSJiri Olsa 	if (check_backup(data))
3655021fc4eSJiri Olsa 		return -1;
3665021fc4eSJiri Olsa 
367ec65def1SJiri Olsa 	if (perf_data__is_read(data))
368ec65def1SJiri Olsa 		data->is_dir = is_dir(data);
369ec65def1SJiri Olsa 
370ec65def1SJiri Olsa 	return perf_data__is_dir(data) ?
371ec65def1SJiri Olsa 	       open_dir(data) : open_file_dup(data);
3726a4d98d7SJiri Olsa }
3736a4d98d7SJiri Olsa 
perf_data__close(struct perf_data * data)3748ceb41d7SJiri Olsa void perf_data__close(struct perf_data *data)
3756a4d98d7SJiri Olsa {
376ec65def1SJiri Olsa 	if (perf_data__is_dir(data))
377ec65def1SJiri Olsa 		perf_data__close_dir(data);
378ec65def1SJiri Olsa 
379b8f7d86bSJiri Olsa 	zfree(&data->file.path);
38060136667SNamhyung Kim 
38160136667SNamhyung Kim 	if (data->use_stdio)
38260136667SNamhyung Kim 		fclose(data->file.fptr);
38360136667SNamhyung Kim 	else
384eae8ad80SJiri Olsa 		close(data->file.fd);
3856a4d98d7SJiri Olsa }
3866f9a317fSJiri Olsa 
perf_data__read(struct perf_data * data,void * buf,size_t size)38760136667SNamhyung Kim ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size)
38860136667SNamhyung Kim {
38960136667SNamhyung Kim 	if (data->use_stdio) {
39060136667SNamhyung Kim 		if (fread(buf, size, 1, data->file.fptr) == 1)
39160136667SNamhyung Kim 			return size;
39260136667SNamhyung Kim 		return feof(data->file.fptr) ? 0 : -1;
39360136667SNamhyung Kim 	}
39460136667SNamhyung Kim 	return readn(data->file.fd, buf, size);
39560136667SNamhyung Kim }
39660136667SNamhyung Kim 
perf_data_file__write(struct perf_data_file * file,void * buf,size_t size)397e268687bSJiri Olsa ssize_t perf_data_file__write(struct perf_data_file *file,
398e268687bSJiri Olsa 			      void *buf, size_t size)
399e268687bSJiri Olsa {
400e268687bSJiri Olsa 	return writen(file->fd, buf, size);
401e268687bSJiri Olsa }
402e268687bSJiri Olsa 
perf_data__write(struct perf_data * data,void * buf,size_t size)4038ceb41d7SJiri Olsa ssize_t perf_data__write(struct perf_data *data,
4046f9a317fSJiri Olsa 			      void *buf, size_t size)
4056f9a317fSJiri Olsa {
40660136667SNamhyung Kim 	if (data->use_stdio) {
40760136667SNamhyung Kim 		if (fwrite(buf, size, 1, data->file.fptr) == 1)
40860136667SNamhyung Kim 			return size;
40960136667SNamhyung Kim 		return -1;
41060136667SNamhyung Kim 	}
411e268687bSJiri Olsa 	return perf_data_file__write(&data->file, buf, size);
4126f9a317fSJiri Olsa }
413040f9915SWang Nan 
perf_data__switch(struct perf_data * data,const char * postfix,size_t pos,bool at_exit,char ** new_filepath)4148ceb41d7SJiri Olsa int perf_data__switch(struct perf_data *data,
415040f9915SWang Nan 			   const char *postfix,
41603724b2eSAndi Kleen 			   size_t pos, bool at_exit,
41703724b2eSAndi Kleen 			   char **new_filepath)
418040f9915SWang Nan {
419040f9915SWang Nan 	int ret;
420040f9915SWang Nan 
4218ceb41d7SJiri Olsa 	if (perf_data__is_read(data))
422040f9915SWang Nan 		return -EINVAL;
423040f9915SWang Nan 
42403724b2eSAndi Kleen 	if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
425040f9915SWang Nan 		return -ENOMEM;
426040f9915SWang Nan 
427040f9915SWang Nan 	/*
428040f9915SWang Nan 	 * Only fire a warning, don't return error, continue fill
429040f9915SWang Nan 	 * original file.
430040f9915SWang Nan 	 */
43103724b2eSAndi Kleen 	if (rename(data->path, *new_filepath))
43203724b2eSAndi Kleen 		pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
433040f9915SWang Nan 
434040f9915SWang Nan 	if (!at_exit) {
435eae8ad80SJiri Olsa 		close(data->file.fd);
4368ceb41d7SJiri Olsa 		ret = perf_data__open(data);
437040f9915SWang Nan 		if (ret < 0)
438040f9915SWang Nan 			goto out;
439040f9915SWang Nan 
440eae8ad80SJiri Olsa 		if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
441040f9915SWang Nan 			ret = -errno;
442040f9915SWang Nan 			pr_debug("Failed to lseek to %zu: %s",
443040f9915SWang Nan 				 pos, strerror(errno));
444040f9915SWang Nan 			goto out;
445040f9915SWang Nan 		}
446040f9915SWang Nan 	}
447eae8ad80SJiri Olsa 	ret = data->file.fd;
448040f9915SWang Nan out:
449040f9915SWang Nan 	return ret;
450040f9915SWang Nan }
45129583c17SJiri Olsa 
perf_data__size(struct perf_data * data)45229583c17SJiri Olsa unsigned long perf_data__size(struct perf_data *data)
45329583c17SJiri Olsa {
45429583c17SJiri Olsa 	u64 size = data->file.size;
45529583c17SJiri Olsa 	int i;
45629583c17SJiri Olsa 
45746e201efSAdrian Hunter 	if (perf_data__is_single_file(data))
45829583c17SJiri Olsa 		return size;
45929583c17SJiri Olsa 
46029583c17SJiri Olsa 	for (i = 0; i < data->dir.nr; i++) {
46129583c17SJiri Olsa 		struct perf_data_file *file = &data->dir.files[i];
46229583c17SJiri Olsa 
46329583c17SJiri Olsa 		size += file->size;
46429583c17SJiri Olsa 	}
46529583c17SJiri Olsa 
46629583c17SJiri Olsa 	return size;
46729583c17SJiri Olsa }
468eeb399b5SAdrian Hunter 
perf_data__make_kcore_dir(struct perf_data * data,char * buf,size_t buf_sz)469eeb399b5SAdrian Hunter int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz)
470eeb399b5SAdrian Hunter {
471eeb399b5SAdrian Hunter 	int ret;
472eeb399b5SAdrian Hunter 
473eeb399b5SAdrian Hunter 	if (!data->is_dir)
474eeb399b5SAdrian Hunter 		return -1;
475eeb399b5SAdrian Hunter 
476eeb399b5SAdrian Hunter 	ret = snprintf(buf, buf_sz, "%s/kcore_dir", data->path);
477eeb399b5SAdrian Hunter 	if (ret < 0 || (size_t)ret >= buf_sz)
478eeb399b5SAdrian Hunter 		return -1;
479eeb399b5SAdrian Hunter 
480eeb399b5SAdrian Hunter 	return mkdir(buf, S_IRWXU);
481eeb399b5SAdrian Hunter }
482eeb399b5SAdrian Hunter 
has_kcore_dir(const char * path)483a4455e00SAdrian Hunter bool has_kcore_dir(const char *path)
484a4455e00SAdrian Hunter {
48565691e9fSAdrian Hunter 	struct dirent *d = ERR_PTR(-EINVAL);
48665691e9fSAdrian Hunter 	const char *name = "kcore_dir";
48765691e9fSAdrian Hunter 	DIR *dir = opendir(path);
48865691e9fSAdrian Hunter 	size_t n = strlen(name);
48965691e9fSAdrian Hunter 	bool result = false;
490a4455e00SAdrian Hunter 
49165691e9fSAdrian Hunter 	if (dir) {
49265691e9fSAdrian Hunter 		while (d && !result) {
49365691e9fSAdrian Hunter 			d = readdir(dir);
49465691e9fSAdrian Hunter 			result = d ? strncmp(d->d_name, name, n) : false;
49565691e9fSAdrian Hunter 		}
49665691e9fSAdrian Hunter 		closedir(dir);
49765691e9fSAdrian Hunter 	}
498a4455e00SAdrian Hunter 
49965691e9fSAdrian Hunter 	return result;
500a4455e00SAdrian Hunter }
501a4455e00SAdrian Hunter 
perf_data__kallsyms_name(struct perf_data * data)502eeb399b5SAdrian Hunter char *perf_data__kallsyms_name(struct perf_data *data)
503eeb399b5SAdrian Hunter {
504eeb399b5SAdrian Hunter 	char *kallsyms_name;
505eeb399b5SAdrian Hunter 	struct stat st;
506eeb399b5SAdrian Hunter 
507eeb399b5SAdrian Hunter 	if (!data->is_dir)
508eeb399b5SAdrian Hunter 		return NULL;
509eeb399b5SAdrian Hunter 
510eeb399b5SAdrian Hunter 	if (asprintf(&kallsyms_name, "%s/kcore_dir/kallsyms", data->path) < 0)
511eeb399b5SAdrian Hunter 		return NULL;
512eeb399b5SAdrian Hunter 
513eeb399b5SAdrian Hunter 	if (stat(kallsyms_name, &st)) {
514eeb399b5SAdrian Hunter 		free(kallsyms_name);
515eeb399b5SAdrian Hunter 		return NULL;
516eeb399b5SAdrian Hunter 	}
517eeb399b5SAdrian Hunter 
518eeb399b5SAdrian Hunter 	return kallsyms_name;
519eeb399b5SAdrian Hunter }
520058f1511SJiri Olsa 
perf_data__guest_kallsyms_name(struct perf_data * data,pid_t machine_pid)521a5367ecbSAdrian Hunter char *perf_data__guest_kallsyms_name(struct perf_data *data, pid_t machine_pid)
522a5367ecbSAdrian Hunter {
523a5367ecbSAdrian Hunter 	char *kallsyms_name;
524a5367ecbSAdrian Hunter 	struct stat st;
525a5367ecbSAdrian Hunter 
526a5367ecbSAdrian Hunter 	if (!data->is_dir)
527a5367ecbSAdrian Hunter 		return NULL;
528a5367ecbSAdrian Hunter 
529a5367ecbSAdrian Hunter 	if (asprintf(&kallsyms_name, "%s/kcore_dir__%d/kallsyms", data->path, machine_pid) < 0)
530a5367ecbSAdrian Hunter 		return NULL;
531a5367ecbSAdrian Hunter 
532a5367ecbSAdrian Hunter 	if (stat(kallsyms_name, &st)) {
533a5367ecbSAdrian Hunter 		free(kallsyms_name);
534a5367ecbSAdrian Hunter 		return NULL;
535a5367ecbSAdrian Hunter 	}
536a5367ecbSAdrian Hunter 
537a5367ecbSAdrian Hunter 	return kallsyms_name;
538a5367ecbSAdrian Hunter }
539a5367ecbSAdrian Hunter 
is_perf_data(const char * path)540058f1511SJiri Olsa bool is_perf_data(const char *path)
541058f1511SJiri Olsa {
542058f1511SJiri Olsa 	bool ret = false;
543058f1511SJiri Olsa 	FILE *file;
544058f1511SJiri Olsa 	u64 magic;
545058f1511SJiri Olsa 
546058f1511SJiri Olsa 	file = fopen(path, "r");
547058f1511SJiri Olsa 	if (!file)
548058f1511SJiri Olsa 		return false;
549058f1511SJiri Olsa 
550058f1511SJiri Olsa 	if (fread(&magic, 1, 8, file) < 8)
551058f1511SJiri Olsa 		goto out;
552058f1511SJiri Olsa 
553058f1511SJiri Olsa 	ret = is_perf_magic(magic);
554058f1511SJiri Olsa out:
555058f1511SJiri Olsa 	fclose(file);
556058f1511SJiri Olsa 	return ret;
557058f1511SJiri Olsa }
558