diff options
Diffstat (limited to 'tools/perf/util/util.c')
| -rw-r--r-- | tools/perf/util/util.c | 94 | 
1 files changed, 94 insertions, 0 deletions
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c new file mode 100644 index 00000000000..f9b890fde68 --- /dev/null +++ b/tools/perf/util/util.c @@ -0,0 +1,94 @@ +#include "util.h" +#include <sys/mman.h> + +int mkdir_p(char *path, mode_t mode) +{ +	struct stat st; +	int err; +	char *d = path; + +	if (*d != '/') +		return -1; + +	if (stat(path, &st) == 0) +		return 0; + +	while (*++d == '/'); + +	while ((d = strchr(d, '/'))) { +		*d = '\0'; +		err = stat(path, &st) && mkdir(path, mode); +		*d++ = '/'; +		if (err) +			return -1; +		while (*d == '/') +			++d; +	} +	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; +} + +static int slow_copyfile(const char *from, const char *to) +{ +	int err = 0; +	char *line = NULL; +	size_t n; +	FILE *from_fp = fopen(from, "r"), *to_fp; + +	if (from_fp == NULL) +		goto out; + +	to_fp = fopen(to, "w"); +	if (to_fp == NULL) +		goto out_fclose_from; + +	while (getline(&line, &n, from_fp) > 0) +		if (fputs(line, to_fp) == EOF) +			goto out_fclose_to; +	err = 0; +out_fclose_to: +	fclose(to_fp); +	free(line); +out_fclose_from: +	fclose(from_fp); +out: +	return err; +} + +int copyfile(const char *from, const char *to) +{ +	int fromfd, tofd; +	struct stat st; +	void *addr; +	int err = -1; + +	if (stat(from, &st)) +		goto out; + +	if (st.st_size == 0) /* /proc? do it slowly... */ +		return slow_copyfile(from, to); + +	fromfd = open(from, O_RDONLY); +	if (fromfd < 0) +		goto out; + +	tofd = creat(to, 0755); +	if (tofd < 0) +		goto out_close_from; + +	addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0); +	if (addr == MAP_FAILED) +		goto out_close_to; + +	if (write(tofd, addr, st.st_size) == st.st_size) +		err = 0; + +	munmap(addr, st.st_size); +out_close_to: +	close(tofd); +	if (err) +		unlink(to); +out_close_from: +	close(fromfd); +out: +	return err; +}  |