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 */
39 /* Wrapper around read() that checks for errors keeps retrying until all
40 * requested bytes have been read or until end-of file has occurred.
43 * WIMLIB_ERR_SUCCESS (0)
44 * WIMLIB_ERR_READ (errno set)
45 * WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
48 full_read(struct filedes *fd, void *buf, size_t count)
51 size_t bytes_remaining;
53 for (bytes_remaining = count;
55 bytes_remaining -= bytes_read, buf += bytes_read)
57 bytes_read = read(fd->fd, buf, bytes_remaining);
58 if (unlikely(bytes_read <= 0)) {
59 if (bytes_read == 0) {
61 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
62 } else if (errno == EINTR) {
65 return WIMLIB_ERR_READ;
69 count -= bytes_remaining;
75 pipe_read(struct filedes *fd, void *buf, size_t count, off_t offset)
79 /* Verify the offset. */
80 if (offset < fd->offset) {
81 ERROR("Can't seek backwards in pipe "
82 "(offset %"PRIu64" => %"PRIu64").\n"
83 " Make sure the WIM was captured as "
84 "pipable.", fd->offset, offset);
86 return WIMLIB_ERR_RESOURCE_ORDER;
89 /* Manually seek to the requested position. */
90 while (fd->offset != offset) {
91 size_t bytes_to_read = min(offset - fd->offset, BUFFER_SIZE);
92 u8 dummy[bytes_to_read];
94 ret = full_read(fd, dummy, bytes_to_read);
99 /* Do the actual read. */
100 return full_read(fd, buf, count);
103 /* Wrapper around pread() that checks for errors and keeps retrying until all
104 * requested bytes have been read or until end-of file has occurred. This also
105 * transparently handle reading from pipe files, but the caller needs to be sure
106 * the requested offset is greater than or equal to the current offset, or else
107 * WIMLIB_ERR_RESOURCE_ORDER will be returned.
110 * WIMLIB_ERR_SUCCESS (0)
111 * WIMLIB_ERR_READ (errno set)
112 * WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
113 * WIMLIB_ERR_RESOURCE_ORDER (errno set to ESPIPE)
116 full_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
119 size_t bytes_remaining;
124 for (bytes_remaining = count;
125 bytes_remaining != 0;
126 bytes_remaining -= bytes_read, buf += bytes_read,
127 offset += bytes_read)
129 bytes_read = pread(fd->fd, buf, bytes_remaining, offset);
130 if (unlikely(bytes_read <= 0)) {
131 if (bytes_read == 0) {
133 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
134 } else if (errno == EINTR) {
136 } else if (errno == ESPIPE) {
140 return WIMLIB_ERR_READ;
147 return pipe_read(fd, buf, count, offset);
150 /* Wrapper around write() that checks for errors and keeps retrying until all
151 * requested bytes have been written.
154 * WIMLIB_ERR_SUCCESS (0)
155 * WIMLIB_ERR_WRITE (errno set)
158 full_write(struct filedes *fd, const void *buf, size_t count)
160 ssize_t bytes_written;
161 size_t bytes_remaining;
163 for (bytes_remaining = count;
164 bytes_remaining != 0;
165 bytes_remaining -= bytes_written, buf += bytes_written)
167 bytes_written = write(fd->fd, buf, bytes_remaining);
168 if (unlikely(bytes_written < 0)) {
171 return WIMLIB_ERR_WRITE;
179 /* Wrapper around pwrite() that checks for errors and keeps retrying until all
180 * requested bytes have been written.
183 * WIMLIB_ERR_SUCCESS (0)
184 * WIMLIB_ERR_WRITE (errno set)
187 full_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
189 ssize_t bytes_written;
190 size_t bytes_remaining;
192 for (bytes_remaining = count;
193 bytes_remaining != 0;
194 bytes_remaining -= bytes_written, buf += bytes_written,
195 offset += bytes_written)
197 bytes_written = pwrite(fd->fd, buf, bytes_remaining, offset);
198 if (unlikely(bytes_written < 0)) {
201 return WIMLIB_ERR_WRITE;
208 raw_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
210 return pread(fd->fd, buf, count, offset);
214 raw_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
216 return pwrite(fd->fd, buf, count, offset);
219 off_t filedes_seek(struct filedes *fd, off_t offset)
225 if (fd->offset != offset) {
226 if (lseek(fd->fd, offset, SEEK_SET) == -1)
233 bool filedes_is_seekable(struct filedes *fd)
235 return !fd->is_pipe && lseek(fd->fd, 0, SEEK_CUR) != -1;