Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Samba system utilities
4 : * Copyright (C) Andrew Tridgell 1992-1998
5 : * Copyright (C) Jeremy Allison 1998-2005
6 : * Copyright (C) Timur Bakeyev 2005
7 : * Copyright (C) Bjoern Jacke 2006-2007
8 : *
9 : * This program is free software; you can redistribute it and/or modify
10 : * it under the terms of the GNU General Public License as published by
11 : * the Free Software Foundation; either version 3 of the License, or
12 : * (at your option) any later version.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "replace.h"
24 : #include "system/filesys.h"
25 : #include "lib/util/sys_rw.h"
26 : #include <assert.h>
27 :
28 415312 : bool sys_valid_io_range(off_t offset, size_t length)
29 : {
30 295 : uint64_t last_byte_ofs;
31 :
32 415312 : if (offset < 0) {
33 60 : return false;
34 : }
35 :
36 295 : if (offset > INT64_MAX) {
37 : return false;
38 : }
39 :
40 415252 : if (length > UINT32_MAX) {
41 0 : return false;
42 : }
43 :
44 415252 : last_byte_ofs = (uint64_t)offset + (uint64_t)length;
45 415252 : if (last_byte_ofs > INT64_MAX) {
46 12 : return false;
47 : }
48 :
49 414945 : return true;
50 : }
51 :
52 25 : bool sys_io_ranges_overlap(size_t c1, off_t o1,
53 : size_t c2, off_t o2)
54 : {
55 25 : if (c1 == 0 || c2 == 0) {
56 0 : return false;
57 : }
58 22 : if (o2 < o1) {
59 : /*
60 : * o1
61 : * |····c1····|
62 : * o2
63 : * |····c2···| ?
64 : */
65 2 : return (o2 + c2 > o1);
66 : } else {
67 : /*
68 : * o1
69 : * |····c1···|
70 : * o2
71 : * |····c2····| ?
72 : */
73 20 : return (o1 + c1 > o2);
74 : }
75 : }
76 :
77 14 : off_t sys_block_align_truncate(off_t len, off_t align)
78 : {
79 14 : assert(align > 1);
80 14 : assert(((align - 1) & align) == 0);
81 14 : return len & (~align + 1);
82 : }
83 :
84 12 : off_t sys_block_align(off_t len, off_t align)
85 : {
86 12 : assert(align > 1);
87 12 : assert(((align - 1) & align) == 0);
88 12 : return (len + (align - 1)) & ~(align - 1);
89 : }
90 :
91 : /*******************************************************************
92 : A read wrapper that will deal with EINTR/EWOULDBLOCK
93 : ********************************************************************/
94 :
95 1587787 : ssize_t sys_read(int fd, void *buf, size_t count)
96 : {
97 18097 : ssize_t ret;
98 :
99 18097 : do {
100 1587788 : ret = read(fd, buf, count);
101 1587788 : } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
102 10 : errno == EWOULDBLOCK));
103 :
104 1587787 : return ret;
105 : }
106 :
107 : /**
108 : * read wrapper, void variant:
109 : * This is intended to be used as a void variant of
110 : * read in situations where the caller wants to ignore
111 : * the result. Hence not checking for EAGAIN|EWOULDBLOCK.
112 : */
113 0 : void sys_read_v(int fd, void *buf, size_t count)
114 : {
115 0 : ssize_t ret;
116 :
117 0 : do {
118 0 : ret = read(fd, buf, count);
119 0 : } while (ret == -1 && errno == EINTR);
120 0 : }
121 :
122 :
123 : /*******************************************************************
124 : A write wrapper that will deal with EINTR/EWOULDBLOCK.
125 : ********************************************************************/
126 :
127 3589 : ssize_t sys_write(int fd, const void *buf, size_t count)
128 : {
129 240 : ssize_t ret;
130 :
131 240 : do {
132 3589 : ret = write(fd, buf, count);
133 3589 : } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
134 0 : errno == EWOULDBLOCK));
135 :
136 3589 : return ret;
137 : }
138 :
139 : /**
140 : * write wrapper to deal with EINTR and friends.
141 : * void-variant that ignores the number of bytes written.
142 : * This is intended to be used as a void variant of
143 : * write in situations where the caller wants to ignore
144 : * the result. Hence not checking for EAGAIN|EWOULDBLOCK.
145 : */
146 26 : void sys_write_v(int fd, const void *buf, size_t count)
147 : {
148 10 : ssize_t ret;
149 :
150 10 : do {
151 26 : ret = write(fd, buf, count);
152 26 : } while (ret == -1 && errno == EINTR);
153 26 : }
154 :
155 :
156 : /*******************************************************************
157 : A writev wrapper that will deal with EINTR.
158 : ********************************************************************/
159 :
160 910842 : ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
161 : {
162 8179 : ssize_t ret;
163 :
164 8179 : do {
165 910842 : ret = writev(fd, iov, iovcnt);
166 910842 : } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
167 83 : errno == EWOULDBLOCK));
168 :
169 910842 : return ret;
170 : }
171 :
172 : /*******************************************************************
173 : A pread wrapper that will deal with EINTR
174 : ********************************************************************/
175 :
176 18921 : ssize_t sys_pread(int fd, void *buf, size_t count, off_t off)
177 : {
178 63 : ssize_t ret;
179 :
180 63 : do {
181 18921 : ret = pread(fd, buf, count, off);
182 18921 : } while (ret == -1 && errno == EINTR);
183 18921 : return ret;
184 : }
185 :
186 : /*******************************************************************
187 : A pread wrapper that will deal with EINTR and never return a short
188 : read unless pread returns zero meaning EOF.
189 : ********************************************************************/
190 :
191 18033 : ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off)
192 : {
193 18033 : ssize_t total_read = 0;
194 18033 : uint8_t *curr_buf = (uint8_t *)buf;
195 18033 : size_t curr_count = count;
196 18033 : off_t curr_off = off;
197 56 : bool ok;
198 :
199 18033 : ok = sys_valid_io_range(off, count);
200 18034 : if (!ok) {
201 0 : errno = EINVAL;
202 0 : return -1;
203 : }
204 :
205 34878 : while (curr_count != 0) {
206 18921 : ssize_t ret = sys_pread(fd,
207 : curr_buf,
208 : curr_count,
209 : curr_off);
210 :
211 18921 : if (ret == -1) {
212 0 : return -1;
213 : }
214 18921 : if (ret == 0) {
215 : /* EOF */
216 2062 : break;
217 : }
218 :
219 16844 : if (ret > curr_count) {
220 0 : errno = EIO;
221 0 : return -1;
222 : }
223 :
224 16844 : curr_buf += ret;
225 16844 : curr_count -= ret;
226 16844 : curr_off += ret;
227 :
228 16844 : total_read += ret;
229 : }
230 :
231 17978 : return total_read;
232 : }
233 :
234 : /*******************************************************************
235 : A write wrapper that will deal with EINTR
236 : ********************************************************************/
237 :
238 170111 : ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off)
239 : {
240 66 : ssize_t ret;
241 :
242 66 : do {
243 170111 : ret = pwrite(fd, buf, count, off);
244 170111 : } while (ret == -1 && errno == EINTR);
245 170111 : return ret;
246 : }
247 :
248 : /*******************************************************************
249 : A pwrite wrapper that will deal with EINTR and never allow a short
250 : write unless the file system returns an error.
251 : ********************************************************************/
252 :
253 170111 : ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off)
254 : {
255 170111 : ssize_t total_written = 0;
256 170111 : const uint8_t *curr_buf = (const uint8_t *)buf;
257 170111 : size_t curr_count = count;
258 170111 : off_t curr_off = off;
259 66 : bool ok;
260 :
261 170111 : ok = sys_valid_io_range(off, count);
262 170111 : if (!ok) {
263 0 : errno = EINVAL;
264 0 : return -1;
265 : }
266 :
267 340222 : while (curr_count != 0) {
268 170111 : ssize_t ret = sys_pwrite(fd,
269 : curr_buf,
270 : curr_count,
271 : curr_off);
272 :
273 170111 : if (ret == -1) {
274 0 : return -1;
275 : }
276 170111 : if (ret == 0) {
277 : /* Ensure we can never spin. */
278 0 : errno = ENOSPC;
279 0 : return -1;
280 : }
281 :
282 170111 : if (ret > curr_count) {
283 0 : errno = EIO;
284 0 : return -1;
285 : }
286 :
287 170111 : curr_buf += ret;
288 170111 : curr_count -= ret;
289 170111 : curr_off += ret;
290 :
291 170111 : total_written += ret;
292 : }
293 :
294 170045 : return total_written;
295 : }
|