2 * file_io.c - Helper functions for reading and writing to file descriptors.
6 * Copyright (C) 2013 Eric Biggers
8 * This file is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by the Free
10 * Software Foundation; either version 3 of the License, or (at your option) any
13 * This file is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this file; if not, see http://www.gnu.org/licenses/.
29 #include "wimlib/error.h"
30 #include "wimlib/file_io.h"
31 #include "wimlib/util.h"
32 #include "wimlib/win32.h" /* For pread(), pwrite() replacements */
35 * Wrapper around read() that checks for errors and keeps retrying until all
36 * requested bytes have been read or until end-of file has occurred.
39 * WIMLIB_ERR_SUCCESS (0)
40 * WIMLIB_ERR_READ (errno set)
41 * WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to EINVAL)
44 full_read(struct filedes *fd, void *buf, size_t count)
47 ssize_t ret = read(fd->fd, buf, count);
48 if (unlikely(ret <= 0)) {
51 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
55 return WIMLIB_ERR_READ;
65 pipe_read(struct filedes *fd, void *buf, size_t count, off_t offset)
69 /* Verify the offset. */
70 if (offset < fd->offset) {
71 ERROR("Can't seek backwards in pipe "
72 "(offset %"PRIu64" => %"PRIu64").\n"
73 " Make sure the WIM was captured as "
74 "pipable.", fd->offset, offset);
76 return WIMLIB_ERR_RESOURCE_ORDER;
79 /* Manually seek to the requested position. */
80 while (fd->offset != offset) {
81 size_t bytes_to_read = min(offset - fd->offset, BUFFER_SIZE);
82 u8 dummy[bytes_to_read];
84 ret = full_read(fd, dummy, bytes_to_read);
89 /* Do the actual read. */
90 return full_read(fd, buf, count);
94 * Wrapper around pread() that checks for errors and keeps retrying until all
95 * requested bytes have been read or until end-of file has occurred. This also
96 * transparently handle reading from pipe files, but the caller needs to be sure
97 * the requested offset is greater than or equal to the current offset, or else
98 * WIMLIB_ERR_RESOURCE_ORDER will be returned.
101 * WIMLIB_ERR_SUCCESS (0)
102 * WIMLIB_ERR_READ (errno set)
103 * WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to EINVAL)
104 * WIMLIB_ERR_RESOURCE_ORDER (errno set to ESPIPE)
107 full_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
113 ssize_t ret = pread(fd->fd, buf, count, offset);
114 if (unlikely(ret <= 0)) {
117 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
121 if (errno == ESPIPE) {
125 return WIMLIB_ERR_READ;
134 return pipe_read(fd, buf, count, offset);
138 * Wrapper around write() that checks for errors and keeps retrying until all
139 * requested bytes have been written.
142 * WIMLIB_ERR_SUCCESS (0)
143 * WIMLIB_ERR_WRITE (errno set)
146 full_write(struct filedes *fd, const void *buf, size_t count)
149 ssize_t ret = write(fd->fd, buf, count);
150 if (unlikely(ret < 0)) {
153 return WIMLIB_ERR_WRITE;
164 * Wrapper around pwrite() that checks for errors and keeps retrying until all
165 * requested bytes have been written.
168 * WIMLIB_ERR_SUCCESS (0)
169 * WIMLIB_ERR_WRITE (errno set)
172 full_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
175 ssize_t ret = pwrite(fd->fd, buf, count, offset);
176 if (unlikely(ret < 0)) {
179 return WIMLIB_ERR_WRITE;
188 off_t filedes_seek(struct filedes *fd, off_t offset)
194 if (fd->offset != offset) {
195 if (lseek(fd->fd, offset, SEEK_SET) == -1)
202 bool filedes_is_seekable(struct filedes *fd)
204 return !fd->is_pipe && lseek(fd->fd, 0, SEEK_CUR) != -1;