summaryrefslogtreecommitdiffstats
path: root/lib/libfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libfile.c')
-rw-r--r--lib/libfile.c145
1 files changed, 103 insertions, 42 deletions
diff --git a/lib/libfile.c b/lib/libfile.c
index 3b7985fbca..67fc9cc7f3 100644
--- a/lib/libfile.c
+++ b/lib/libfile.c
@@ -33,10 +33,8 @@ int pwrite_full(int fd, const void *buf, size_t size, loff_t offset)
while (size) {
now = pwrite(fd, buf, size, offset);
- if (now == 0) {
- errno = ENOSPC;
- return -errno;
- }
+ if (now == 0)
+ return errno_set(-ENOSPC);
if (now < 0)
return now;
size -= now;
@@ -61,10 +59,8 @@ int write_full(int fd, const void *buf, size_t size)
while (size) {
now = write(fd, buf, size);
- if (now == 0) {
- errno = ENOSPC;
- return -errno;
- }
+ if (now == 0)
+ return errno_set(-ENOSPC);
if (now < 0)
return now;
size -= now;
@@ -191,6 +187,33 @@ out:
EXPORT_SYMBOL_GPL(read_file_line);
/**
+ * read_file_into_buf - read a file to an external buffer
+ * @filename: The filename to read
+ * @buf: The buffer to read into
+ * @size: The buffer size
+ *
+ * This function reads a file to an external buffer. At maximum @size
+ * bytes are read.
+ *
+ * Return: number of bytes read, or negative error code.
+ */
+ssize_t read_file_into_buf(const char *filename, void *buf, size_t size)
+{
+ int fd;
+ ssize_t ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ ret = read_full(fd, buf, size);
+
+ close(fd);
+
+ return ret;
+}
+
+/**
* read_file_2 - read a file to an allocated buffer
* @filename: The filename to read
* @size: After successful return contains the size of the file
@@ -212,11 +235,10 @@ EXPORT_SYMBOL_GPL(read_file_line);
int read_file_2(const char *filename, size_t *size, void **outbuf,
loff_t max_size)
{
- int fd;
struct stat s;
void *buf = NULL;
const char *tmpfile = "/.read_file_tmp";
- int ret;
+ ssize_t ret;
loff_t read_size;
again:
@@ -240,22 +262,13 @@ again:
/* ensure wchar_t nul termination */
buf = calloc(ALIGN(read_size, 2) + 2, 1);
if (!buf) {
- ret = -ENOMEM;
- errno = ENOMEM;
- goto err_out;
- }
-
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- ret = fd;
+ ret = errno_set(-ENOMEM);
goto err_out;
}
- ret = read_full(fd, buf, read_size);
+ ret = read_file_into_buf(filename, buf, read_size);
if (ret < 0)
- goto err_out1;
-
- close(fd);
+ goto err_out;
if (size)
*size = ret;
@@ -270,8 +283,6 @@ again:
return 0;
-err_out1:
- close(fd);
err_out:
free(buf);
@@ -307,6 +318,56 @@ void *read_file(const char *filename, size_t *size)
EXPORT_SYMBOL(read_file);
/**
+ * read_fd - read from a file descriptor to an allocated buffer
+ * @filename: The file descriptor to read
+ * @size: After successful return contains the size of the file
+ *
+ * This function reads a file descriptor from offset 0 until EOF to an
+ * allocated buffer.
+ *
+ * Return: On success, returns a nul-terminated buffer with the file's
+ * contents that should be deallocated with free().
+ * On error, NULL is returned and errno is set to an error code.
+ */
+void *read_fd(int fd, size_t *out_size)
+{
+ struct stat st;
+ ssize_t ret;
+ void *buf;
+
+ ret = fstat(fd, &st);
+ if (ret < 0)
+ return NULL;
+
+ if (st.st_size == FILE_SIZE_STREAM) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* For user convenience, we always nul-terminate the buffer in
+ * case it contains a string. As we don't want to assume the string
+ * to be either an array of char or wchar_t, we just unconditionally
+ * add 2 bytes as terminator. As the two byte terminator needs to be
+ * aligned, we just make it three bytes
+ */
+ buf = malloc(st.st_size + 3);
+ if (!buf)
+ return NULL;
+
+ ret = pread_full(fd, buf, st.st_size, 0);
+ if (ret < 0) {
+ free(buf);
+ return NULL;
+ }
+
+ memset(buf + st.st_size, '\0', 3);
+ *out_size = st.st_size;
+
+ return buf;
+}
+EXPORT_SYMBOL(read_fd);
+
+/**
* write_file - write a buffer to a file
* @filename: The filename to write
* @size: The size of the buffer
@@ -387,7 +448,7 @@ int copy_file(const char *src, const char *dst, int verbose)
srcfd = open(src, O_RDONLY);
if (srcfd < 0) {
- printf("could not open %s: %s\n", src, errno_str());
+ printf("could not open %s: %m\n", src);
ret = srcfd;
goto out;
}
@@ -396,7 +457,7 @@ int copy_file(const char *src, const char *dst, int verbose)
s = stat(dst, &dststat);
if (s && s != -ENOENT) {
- printf("could not stat %s: %s\n", dst, errno_str());
+ printf("could not stat %s: %m\n", dst);
ret = s;
goto out;
}
@@ -407,7 +468,7 @@ int copy_file(const char *src, const char *dst, int verbose)
dstfd = open(dst, mode);
if (dstfd < 0) {
- printf("could not open %s: %s\n", dst, errno_str());
+ printf("could not open %s: %m\n", dst);
ret = dstfd;
goto out;
}
@@ -542,8 +603,10 @@ int compare_file(const char *f1, const char *f2)
if (ret)
goto err_out2;
- if (s1.st_size != s2.st_size)
- return 1;
+ if (s1.st_size != s2.st_size) {
+ ret = 1;
+ goto err_out2;
+ }
buf1 = xmalloc(RW_BUF_SIZE);
buf2 = xmalloc(RW_BUF_SIZE);
@@ -587,17 +650,15 @@ err_out1:
* @pos: The position to lseek to
*
* Return: If successful this function returns a positive
- * filedescriptor number, otherwise -1 is returned
+ * filedescriptor number, otherwise a negative error code is returned
*/
int open_and_lseek(const char *filename, int mode, loff_t pos)
{
- int fd;
+ int fd, ret;
fd = open(filename, mode);
- if (fd < 0) {
- perror("open");
+ if (fd < 0)
return fd;
- }
if (!pos)
return fd;
@@ -605,26 +666,26 @@ int open_and_lseek(const char *filename, int mode, loff_t pos)
if (mode & (O_WRONLY | O_RDWR)) {
struct stat s;
- if (fstat(fd, &s)) {
- perror("fstat");
+ ret = fstat(fd, &s);
+ if (ret < 0)
goto out;
- }
- if (s.st_size < pos && ftruncate(fd, pos)) {
- perror("ftruncate");
- goto out;
+ if (s.st_size < pos) {
+ ret = ftruncate(fd, pos);
+ if (ret)
+ goto out;
}
}
if (lseek(fd, pos, SEEK_SET) != pos) {
- perror("lseek");
+ ret = -errno;
goto out;
}
return fd;
out:
close(fd);
- return -1;
+ return ret;
}
/**