diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2014-07-30 10:43:51 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-08-07 06:13:51 +0200 |
commit | 3cfa4bc00c61eca4c0986c793dd21b8b5271fd8f (patch) | |
tree | 01b10c6fa35134394d170696c5c14c67b20b87b3 /lib/libfile.c | |
parent | 2fd4f0fbe93ec7e6e10b3475257521dd8418f8e7 (diff) | |
download | barebox-3cfa4bc00c61eca4c0986c793dd21b8b5271fd8f.tar.gz barebox-3cfa4bc00c61eca4c0986c793dd21b8b5271fd8f.tar.xz |
move file helper functions to separate file
We have our file helper functions in several places. Move them
all to lib/libfile.c.
With this we no longer have file helpers in fs/fs.c which contains
the core fs functions and no functions in lib/libbb.c which are
not from busybox.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'lib/libfile.c')
-rw-r--r-- | lib/libfile.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/lib/libfile.c b/lib/libfile.c new file mode 100644 index 0000000000..b36537fae6 --- /dev/null +++ b/lib/libfile.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <common.h> +#include <fs.h> +#include <fcntl.h> +#include <malloc.h> +#include <libfile.h> +#include <progress.h> +#include <linux/stat.h> + +/* + * write_full - write to filedescriptor + * + * Like write, but guarantees to write the full buffer out, else + * it returns with an error. + */ +int write_full(int fd, void *buf, size_t size) +{ + size_t insize = size; + int now; + + while (size) { + now = write(fd, buf, size); + if (now <= 0) + return now; + size -= now; + buf += now; + } + + return insize; +} +EXPORT_SYMBOL(write_full); + +/* + * read_full - read from filedescriptor + * + * Like read, but this function only returns less bytes than + * requested when the end of file is reached. + */ +int read_full(int fd, void *buf, size_t size) +{ + size_t insize = size; + int now; + int total = 0; + + while (size) { + now = read(fd, buf, size); + if (now == 0) + return total; + if (now < 0) + return now; + total += now; + size -= now; + buf += now; + } + + return insize; +} +EXPORT_SYMBOL(read_full); + +/* + * read_file_line - read a line from a file + * + * Used to compose a filename from a printf format and to read a line from this + * file. All leading and trailing whitespaces (including line endings) are + * removed. The returned buffer must be freed with free(). This function is + * supposed for reading variable like content into a buffer, so files > 1024 + * bytes are ignored. + */ +char *read_file_line(const char *fmt, ...) +{ + va_list args; + char *filename; + char *buf, *line = NULL; + size_t size; + int ret; + struct stat s; + + va_start(args, fmt); + filename = vasprintf(fmt, args); + va_end(args); + + ret = stat(filename, &s); + if (ret) + goto out; + + if (s.st_size > 1024) + goto out; + + buf = read_file(filename, &size); + if (!buf) + goto out; + + line = strim(buf); + + line = xstrdup(line); + free(buf); +out: + free(filename); + return line; +} +EXPORT_SYMBOL_GPL(read_file_line); + +/** + * read_file - read a file to an allocated buffer + * @filename: The filename to read + * @size: After successful return contains the size of the file + * + * This function reads a file to an allocated buffer. + * Some TFTP servers do not transfer the size of a file. In this case + * a the file is first read to a temporary file. + * + * Return: The buffer conataining the file or NULL on failure + */ +void *read_file(const char *filename, size_t *size) +{ + int fd; + struct stat s; + void *buf = NULL; + const char *tmpfile = "/.read_file_tmp"; + int ret; + +again: + if (stat(filename, &s)) + return NULL; + + if (s.st_size == FILESIZE_MAX) { + ret = copy_file(filename, tmpfile, 0); + if (ret) + return NULL; + filename = tmpfile; + goto again; + } + + buf = xzalloc(s.st_size + 1); + + fd = open(filename, O_RDONLY); + if (fd < 0) + goto err_out; + + ret = read_full(fd, buf, s.st_size); + if (ret < 0) + goto err_out1; + + close(fd); + + if (size) + *size = s.st_size; + + if (filename == tmpfile) + unlink(tmpfile); + + return buf; + +err_out1: + close(fd); +err_out: + free(buf); + + if (filename == tmpfile) + unlink(tmpfile); + + return NULL; +} +EXPORT_SYMBOL(read_file); + +/** + * write_file - write a buffer to a file + * @filename: The filename to write + * @size: The size of the buffer + * + * Return: 0 for success or negative error value + */ +int write_file(const char *filename, void *buf, size_t size) +{ + int fd, ret; + + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT); + if (fd < 0) + return fd; + + ret = write_full(fd, buf, size); + + close(fd); + + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(write_file); + +/** + * copy_file - Copy a file + * @src: The source filename + * @dst: The destination filename + * @verbose: if true, show a progression bar + * + * Return: 0 for success or negative error code + */ +int copy_file(const char *src, const char *dst, int verbose) +{ + char *rw_buf = NULL; + int srcfd = 0, dstfd = 0; + int r, w; + int ret = 1; + void *buf; + int total = 0; + struct stat statbuf; + + rw_buf = xmalloc(RW_BUF_SIZE); + + srcfd = open(src, O_RDONLY); + if (srcfd < 0) { + printf("could not open %s: %s\n", src, errno_str()); + goto out; + } + + dstfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC); + if (dstfd < 0) { + printf("could not open %s: %s\n", dst, errno_str()); + goto out; + } + + if (verbose) { + if (stat(src, &statbuf) < 0) + statbuf.st_size = 0; + + init_progression_bar(statbuf.st_size); + } + + while (1) { + r = read(srcfd, rw_buf, RW_BUF_SIZE); + if (r < 0) { + perror("read"); + goto out; + } + if (!r) + break; + + buf = rw_buf; + while (r) { + w = write(dstfd, buf, r); + if (w < 0) { + perror("write"); + goto out; + } + buf += w; + r -= w; + total += w; + } + + if (verbose) { + if (statbuf.st_size && statbuf.st_size != FILESIZE_MAX) + show_progress(total); + else + show_progress(total / 16384); + } + } + + ret = 0; +out: + if (verbose) + putchar('\n'); + + free(rw_buf); + if (srcfd > 0) + close(srcfd); + if (dstfd > 0) + close(dstfd); + + return ret; +} +EXPORT_SYMBOL(copy_file); |