]> wimlib.net Git - wimlib/blob - src/file_io.c
Use explicit casting in ctype macros
[wimlib] / src / file_io.c
1 /*
2  * file_io.c - Helper functions for reading and writing to file descriptors.
3  */
4
5 /*
6  * Copyright (C) 2013 Eric Biggers
7  *
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
11  * later version.
12  *
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
16  * details.
17  *
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/.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <errno.h>
27 #include <unistd.h>
28
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 */
33
34 /* Wrapper around read() that checks for errors keeps retrying until all
35  * requested bytes have been read or until end-of file has occurred.
36  *
37  * Return values:
38  *      WIMLIB_ERR_SUCCESS                      (0)
39  *      WIMLIB_ERR_READ                         (errno set)
40  *      WIMLIB_ERR_UNEXPECTED_END_OF_FILE       (errno set to 0)
41  */
42 int
43 full_read(struct filedes *fd, void *buf, size_t count)
44 {
45         ssize_t bytes_read;
46         size_t bytes_remaining;
47
48         for (bytes_remaining = count;
49              bytes_remaining != 0;
50              bytes_remaining -= bytes_read, buf += bytes_read)
51         {
52                 bytes_read = read(fd->fd, buf, bytes_remaining);
53                 if (unlikely(bytes_read <= 0)) {
54                         if (bytes_read == 0) {
55                                 errno = 0;
56                                 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
57                         } else if (errno == EINTR) {
58                                 continue;
59                         } else {
60                                 return WIMLIB_ERR_READ;
61                         }
62                 }
63         }
64         count -= bytes_remaining;
65         fd->offset += count;
66         return 0;
67 }
68
69 static int
70 pipe_read(struct filedes *fd, void *buf, size_t count, off_t offset)
71 {
72         int ret;
73
74         /* Verify the offset.  */
75         if (offset < fd->offset) {
76                 ERROR("Can't seek backwards in pipe "
77                       "(offset %"PRIu64" => %"PRIu64").\n"
78                       "        Make sure the WIM was captured as "
79                       "pipable.", fd->offset, offset);
80                 errno = ESPIPE;
81                 return WIMLIB_ERR_RESOURCE_ORDER;
82         }
83
84         /* Manually seek to the requested position.  */
85         while (fd->offset != offset) {
86                 size_t bytes_to_read = min(offset - fd->offset, BUFFER_SIZE);
87                 u8 dummy[bytes_to_read];
88
89                 ret = full_read(fd, dummy, bytes_to_read);
90                 if (ret)
91                         return ret;
92         }
93
94         /* Do the actual read.  */
95         return full_read(fd, buf, count);
96 }
97
98 /* Wrapper around pread() that checks for errors and keeps retrying until all
99  * requested bytes have been read or until end-of file has occurred.  This also
100  * transparently handle reading from pipe files, but the caller needs to be sure
101  * the requested offset is greater than or equal to the current offset, or else
102  * WIMLIB_ERR_RESOURCE_ORDER will be returned.
103  *
104  * Return values:
105  *      WIMLIB_ERR_SUCCESS                      (0)
106  *      WIMLIB_ERR_READ                         (errno set)
107  *      WIMLIB_ERR_UNEXPECTED_END_OF_FILE       (errno set to 0)
108  *      WIMLIB_ERR_RESOURCE_ORDER               (errno set to ESPIPE)
109  */
110 int
111 full_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
112 {
113         ssize_t bytes_read;
114         size_t bytes_remaining;
115
116         if (fd->is_pipe)
117                 goto is_pipe;
118
119         for (bytes_remaining = count;
120              bytes_remaining != 0;
121              bytes_remaining -= bytes_read, buf += bytes_read,
122                 offset += bytes_read)
123         {
124                 bytes_read = pread(fd->fd, buf, bytes_remaining, offset);
125                 if (unlikely(bytes_read <= 0)) {
126                         if (bytes_read == 0) {
127                                 errno = 0;
128                                 return WIMLIB_ERR_UNEXPECTED_END_OF_FILE;
129                         } else if (errno == EINTR) {
130                                 continue;
131                         } else if (errno == ESPIPE) {
132                                 fd->is_pipe = 1;
133                                 goto is_pipe;
134                         } else {
135                                 return WIMLIB_ERR_READ;
136                         }
137                 }
138         }
139         return 0;
140
141 is_pipe:
142         return pipe_read(fd, buf, count, offset);
143 }
144
145 /* Wrapper around write() that checks for errors and keeps retrying until all
146  * requested bytes have been written.
147  *
148  * Return values:
149  *      WIMLIB_ERR_SUCCESS                      (0)
150  *      WIMLIB_ERR_WRITE                        (errno set)
151  */
152 int
153 full_write(struct filedes *fd, const void *buf, size_t count)
154 {
155         ssize_t bytes_written;
156         size_t bytes_remaining;
157
158         for (bytes_remaining = count;
159              bytes_remaining != 0;
160              bytes_remaining -= bytes_written, buf += bytes_written)
161         {
162                 bytes_written = write(fd->fd, buf, bytes_remaining);
163                 if (unlikely(bytes_written < 0)) {
164                         if (errno == EINTR)
165                                 continue;
166                         return WIMLIB_ERR_WRITE;
167                 }
168         }
169         fd->offset += count;
170         return 0;
171 }
172
173
174 /* Wrapper around pwrite() that checks for errors and keeps retrying until all
175  * requested bytes have been written.
176  *
177  * Return values:
178  *      WIMLIB_ERR_SUCCESS      (0)
179  *      WIMLIB_ERR_WRITE        (errno set)
180  * */
181 int
182 full_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
183 {
184         ssize_t bytes_written;
185         size_t bytes_remaining;
186
187         for (bytes_remaining = count;
188              bytes_remaining != 0;
189              bytes_remaining -= bytes_written, buf += bytes_written,
190                 offset += bytes_written)
191         {
192                 bytes_written = pwrite(fd->fd, buf, bytes_remaining, offset);
193                 if (unlikely(bytes_written < 0)) {
194                         if (errno == EINTR)
195                                 continue;
196                         return WIMLIB_ERR_WRITE;
197                 }
198         }
199         return 0;
200 }
201
202 ssize_t
203 raw_pread(struct filedes *fd, void *buf, size_t count, off_t offset)
204 {
205         return pread(fd->fd, buf, count, offset);
206 }
207
208 ssize_t
209 raw_pwrite(struct filedes *fd, const void *buf, size_t count, off_t offset)
210 {
211         return pwrite(fd->fd, buf, count, offset);
212 }
213
214 off_t filedes_seek(struct filedes *fd, off_t offset)
215 {
216         if (fd->is_pipe) {
217                 errno = ESPIPE;
218                 return -1;
219         }
220         if (fd->offset != offset) {
221                 if (lseek(fd->fd, offset, SEEK_SET) == -1)
222                         return -1;
223                 fd->offset = offset;
224         }
225         return offset;
226 }
227
228 bool filedes_is_seekable(struct filedes *fd)
229 {
230         return !fd->is_pipe && lseek(fd->fd, 0, SEEK_CUR) != -1;
231 }