2 * file_io.c - Helper functions for reading and writing to file descriptors.
6 * Copyright (C) 2013 Eric Biggers
8 * This file is part of wimlib, a library for working with WIM files.
10 * wimlib is free software; you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option)
15 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with wimlib; if not, see http://www.gnu.org/licenses/.
28 #include "wimlib/error.h"
29 #include "wimlib/file_io.h"
30 #include "wimlib/util.h"
32 # include "wimlib/win32.h" /* For pread(), pwrite() replacements */
34 # include <sys/uio.h> /* for writev() and `struct iovec' */
41 /* Wrapper around read() that checks for errors keeps retrying until all
42 * requested bytes have been read or until end-of file has occurred.
45 * WIMLIB_ERR_SUCCESS (0)
46 * WIMLIB_ERR_READ (errno set)
47 * WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
50 full_read(struct filedes *fd, void *buf, size_t count)
53 size_t bytes_remaining;
55 for (bytes_remaining = count;
57 bytes_remaining -= bytes_read, buf += bytes_read)
59 bytes_read = read(fd->fd, buf, bytes_remaining);
60 if (unlikely(bytes_read <= 0)) {
61 if (bytes_read == 0) {
63 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
64 } else if (errno == EINTR) {
67 return WIMLIB_ERR_READ;
71 count -= bytes_remaining;
77 pipe_read(struct filedes *fd, void *buf, size_t count, off_t offset)
81 /* Verify the offset. */
82 if (offset < fd->offset) {
83 ERROR("Can't seek backwards in pipe "
84 "(offset %"PRIu64" => %"PRIu64").\n"
85 " Make sure the WIM was captured as "
86 "pipable.", fd->offset, offset);
88 return WIMLIB_ERR_RESOURCE_ORDER;
91 /* Manually seek to the requested position. */
92 while (fd->offset != offset) {
93 size_t bytes_to_read = min(offset - fd->offset, BUFFER_SIZE);
94 u8 dummy[bytes_to_read];
96 ret = full_read(fd, dummy, bytes_to_read);
101 /* Do the actual read. */
102 return full_read(fd, buf, count);
105 /* Wrapper around pread() that checks for errors and keeps retrying until all
106 * requested bytes have been read or until end-of file has occurred. This also
107 * transparently handle reading from pipe files, but the caller needs to be sure
108 * the requested offset is greater than or equal to the current offset, or else
109 * WIMLIB_ERR_RESOURCE_ORDER will be returned.
112 * WIMLIB_ERR_SUCCESS (0)
113 * WIMLIB_ERR_READ (errno set)
114 * WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
115 * WIMLIB_ERR_RESOURCE_ORDER (errno set to ESPIPE)
118 full_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
121 size_t bytes_remaining;
126 for (bytes_remaining = count;
127 bytes_remaining != 0;
128 bytes_remaining -= bytes_read, buf += bytes_read,
129 offset += bytes_read)
131 bytes_read = pread(fd->fd, buf, bytes_remaining, offset);
132 if (unlikely(bytes_read <= 0)) {
133 if (bytes_read == 0) {
135 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
136 } else if (errno == EINTR) {
138 } else if (errno == ESPIPE) {
142 return WIMLIB_ERR_READ;
149 return pipe_read(fd, buf, count, offset);
152 /* Wrapper around write() that checks for errors and keeps retrying until all
153 * requested bytes have been written.
156 * WIMLIB_ERR_SUCCESS (0)
157 * WIMLIB_ERR_WRITE (errno set)
160 full_write(struct filedes *fd, const void *buf, size_t count)
162 ssize_t bytes_written;
163 size_t bytes_remaining;
165 for (bytes_remaining = count;
166 bytes_remaining != 0;
167 bytes_remaining -= bytes_written, buf += bytes_written)
169 bytes_written = write(fd->fd, buf, bytes_remaining);
170 if (unlikely(bytes_written < 0)) {
173 return WIMLIB_ERR_WRITE;
181 /* Wrapper around pwrite() that checks for errors and keeps retrying until all
182 * requested bytes have been written.
185 * WIMLIB_ERR_SUCCESS (0)
186 * WIMLIB_ERR_WRITE (errno set)
189 full_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
191 ssize_t bytes_written;
192 size_t bytes_remaining;
194 for (bytes_remaining = count;
195 bytes_remaining != 0;
196 bytes_remaining -= bytes_written, buf += bytes_written,
197 offset += bytes_written)
199 bytes_written = pwrite(fd->fd, buf, bytes_remaining, offset);
200 if (unlikely(bytes_written < 0)) {
203 return WIMLIB_ERR_WRITE;
210 /* Wrapper around writev() that checks for errors and keep retrying until all
211 * requested bytes have been written.
214 * WIMLIB_ERR_SUCCESS (0)
215 * WIMLIB_ERR_WRITE (errno set)
218 full_writev(struct filedes *fd, struct iovec *iov, int iovcnt)
220 size_t total_bytes_written = 0;
222 ssize_t bytes_written;
224 bytes_written = writev(fd->fd, iov, iovcnt);
225 if (unlikely(bytes_written < 0)) {
228 return WIMLIB_ERR_WRITE;
230 total_bytes_written += bytes_written;
231 while (bytes_written) {
232 if (bytes_written >= iov[0].iov_len) {
233 bytes_written -= iov[0].iov_len;
237 iov[0].iov_base += bytes_written;
238 iov[0].iov_len -= bytes_written;
243 fd->offset += total_bytes_written;
249 raw_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
251 return pread(fd->fd, buf, count, offset);
255 raw_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
257 return pwrite(fd->fd, buf, count, offset);
260 off_t filedes_seek(struct filedes *fd, off_t offset)
266 if (fd->offset != offset) {
267 if (lseek(fd->fd, offset, SEEK_SET) == -1)
274 bool filedes_is_seekable(struct filedes *fd)
276 return !fd->is_pipe && lseek(fd->fd, 0, SEEK_CUR) != -1;