1 : #define VSTR_SC_POSIX_C
2 : /*
3 : * Copyright (C) 2002, 2003, 2004 James Antill
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 : *
19 : * email: james@and.org
20 : */
21 : /* functions which are shortcuts */
22 : #include "main.h"
23 :
24 : #if !(USE_FD_CLOSE_CHECK) /* hack to test code path on close error */
25 : # define VSTR__POSIX_OPEN3(x, y, z) open64(x, y, z)
26 : # define VSTR__POSIX_CLOSE(x) close(x)
27 : #else
28 : /* this is all non threadsafe ... */
29 : # define VSTR__POSIX_OPEN3(x, y, z) vstr__sc_posix_open(x, y, z)
30 : # define VSTR__POSIX_CLOSE(x) vstr__sc_posix_close(x)
31 : static int vstr__sc_posix_open(const char *pathname, int flags,
32 : VSTR_AUTOCONF_mode_t mode)
33 15527 : {
34 15527 : int ret = open64(pathname, flags, mode);
35 :
36 15527 : ASSERT((ret == -1) || ++vstr__options.fd_count);
37 :
38 15527 : return (ret);
39 : }
40 :
41 : static int vstr__sc_posix_close(int fd)
42 15522 : {
43 15522 : int ret = close(fd);
44 :
45 15522 : ASSERT(vstr__options.fd_count-- > 0);
46 :
47 15522 : if ((ret != -1) &&
48 : vstr__options.fd_close_fail_num && !--vstr__options.fd_close_fail_num)
49 : {
50 4 : errno = EIO;
51 4 : return (-1);
52 : }
53 :
54 15518 : return (ret);
55 : }
56 : #endif
57 :
58 : #define VSTR__POSIX_OPEN1(x) \
59 : VSTR__POSIX_OPEN3(x, O_RDONLY | O_NOCTTY | O_NONBLOCK, 0)
60 :
61 : #ifndef HAVE_MMAP
62 : # define VSTR__SC_ENOSYS(x) \
63 : if (err) \
64 : { \
65 : errno = ENOSYS; \
66 : *err = (x); \
67 : } \
68 : \
69 : return (FALSE)
70 : #else
71 : static void vstr__sc_ref_munmap(Vstr_ref *passed_ref)
72 1841 : { /* debugging is all non threadsafe ... */
73 1841 : Vstr__sc_mmap_ref *mmap_ref = (Vstr__sc_mmap_ref *)passed_ref;
74 :
75 1841 : munmap(mmap_ref->ref.ptr, mmap_ref->mmap_len); /* this _can't_ be -1 */
76 :
77 1841 : VSTR__F(mmap_ref);
78 :
79 461 : ASSERT(vstr__options.mmap_count-- > 0);
80 : }
81 : #endif
82 :
83 : static int vstr__sc_get_size(size_t base_len,
84 : int fd, size_t *len, VSTR_AUTOCONF_off64_t off,
85 : unsigned int *err,
86 : unsigned int err_fstat, unsigned int err_size)
87 : VSTR__COMPILE_ATTR_NONNULL_A();
88 : static int vstr__sc_get_size(size_t base_len,
89 : int fd, size_t *len, VSTR_AUTOCONF_off64_t off,
90 : unsigned int *err,
91 : unsigned int err_fstat, unsigned int err_size)
92 80452 : {
93 80452 : struct stat64 stat_buf;
94 :
95 80452 : ASSERT(len && err);
96 :
97 80452 : if (*len)
98 18526 : return (TRUE);
99 :
100 61926 : if (fstat64(fd, &stat_buf) == -1)
101 : {
102 12 : *err = err_fstat;
103 12 : return (FALSE);
104 : }
105 :
106 61914 : if (stat_buf.st_size <= off)
107 : {
108 4 : *err = err_fstat;
109 4 : errno = ENOSPC;
110 4 : return (FALSE);
111 : }
112 :
113 61910 : *len = (stat_buf.st_size - off);
114 61910 : if (*len > (SIZE_MAX - base_len))
115 : {
116 61728 : *err = err_size;
117 61728 : errno = EFBIG;
118 61728 : return (FALSE);
119 : }
120 :
121 182 : return (TRUE);
122 : }
123 :
124 :
125 : #ifndef HAVE_MMAP
126 : int vstr_sc_mmap_fd(Vstr_base *VSTR__ATTR_UNUSED(base),
127 : size_t VSTR__ATTR_UNUSED(pos),
128 : int VSTR__ATTR_UNUSED(fd),
129 : VSTR_AUTOCONF_off64_t VSTR__ATTR_UNUSED(off),
130 : size_t VSTR__ATTR_UNUSED(len),
131 : unsigned int *err)
132 : { VSTR__SC_ENOSYS(VSTR_TYPE_SC_MMAP_FD_ERR_MMAP_ERRNO); }
133 : #else
134 : int vstr_sc_mmap_fd(Vstr_base *base, size_t pos, int fd,
135 : VSTR_AUTOCONF_off64_t off, size_t len, unsigned int *err)
136 32727 : {
137 32727 : unsigned int dummy_err;
138 32727 : void *addr = NULL;
139 32727 : Vstr__sc_mmap_ref *mmap_ref = NULL;
140 :
141 32727 : assert(off >= 0); /* off is offset from the start of the file,
142 : * not as in seek */
143 :
144 32727 : if (!err)
145 1704 : err = &dummy_err;
146 32727 : *err = 0;
147 :
148 32727 : ASSERT_GOTO(base && (pos <= base->len), inval_args);
149 :
150 32727 : if (!vstr__sc_get_size(base->len, fd, &len, off, err,
151 : VSTR_TYPE_SC_MMAP_FD_ERR_FSTAT_ERRNO,
152 : VSTR_TYPE_SC_MMAP_FD_ERR_TOO_LARGE))
153 30872 : return (FALSE);
154 :
155 1855 : addr = mmap64(NULL, len, PROT_READ, MAP_PRIVATE, fd, off);
156 1855 : if (addr == MAP_FAILED)
157 : {
158 12 : *err = VSTR_TYPE_SC_MMAP_FD_ERR_MMAP_ERRNO;
159 12 : return (FALSE);
160 : }
161 :
162 1843 : if (!(mmap_ref = VSTR__MK(sizeof(Vstr__sc_mmap_ref))))
163 1 : goto malloc_mmap_ref_failed;
164 1842 : mmap_ref->mmap_len = len;
165 1842 : mmap_ref->ref.func = vstr__sc_ref_munmap;
166 1842 : mmap_ref->ref.ptr = (void *)addr;
167 1842 : mmap_ref->ref.ref = 0;
168 :
169 1842 : if (!vstr_add_ref(base, pos, &mmap_ref->ref, 0, len))
170 1 : goto add_ref_failed;
171 :
172 1841 : ASSERT(++vstr__options.mmap_count);
173 :
174 1841 : return (TRUE);
175 :
176 : add_ref_failed:
177 1 : VSTR__F(mmap_ref);
178 : malloc_mmap_ref_failed:
179 2 : munmap(addr, len);
180 2 : *err = VSTR_TYPE_SC_MMAP_FILE_ERR_MEM;
181 2 : errno = ENOMEM;
182 2 : base->conf->malloc_bad = TRUE;
183 :
184 2 : return (FALSE);
185 :
186 : inval_args:
187 8184 : *err = VSTR_TYPE_SC_MMAP_FD_ERR_MMAP_ERRNO;
188 8184 : errno = EINVAL;
189 8184 : return (FALSE);
190 : }
191 : #endif
192 :
193 : #ifndef HAVE_MMAP
194 : int vstr_sc_mmap_file(Vstr_base *VSTR__ATTR_UNUSED(base),
195 : size_t VSTR__ATTR_UNUSED(pos),
196 : const char *VSTR__ATTR_UNUSED(filename),
197 : VSTR_AUTOCONF_off64_t VSTR__ATTR_UNUSED(off),
198 : size_t VSTR__ATTR_UNUSED(len),
199 : unsigned int *err)
200 : { VSTR__SC_ENOSYS(VSTR_TYPE_SC_MMAP_FD_ERR_MMAP_ERRNO); }
201 : #else
202 : int vstr_sc_mmap_file(Vstr_base *base, size_t pos, const char *filename,
203 : VSTR_AUTOCONF_off64_t off, size_t len,
204 : unsigned int *err)
205 31019 : {
206 31019 : int fd = -1;
207 31019 : unsigned int dummy_err;
208 31019 : int ret = 0;
209 31019 : int saved_errno = 0;
210 :
211 31019 : if (!err)
212 12 : err = &dummy_err;
213 31019 : *err = 0;
214 :
215 31019 : if ((fd = VSTR__POSIX_OPEN1(filename)) == -1)
216 : {
217 4 : *err = VSTR_TYPE_SC_MMAP_FILE_ERR_OPEN_ERRNO;
218 4 : return (FALSE);
219 : }
220 :
221 31015 : ret = vstr_sc_mmap_fd(base, pos, fd, off, len, err);
222 :
223 31015 : if (*err)
224 30870 : saved_errno = errno;
225 :
226 31015 : if ((VSTR__POSIX_CLOSE(fd) == -1) && !*err)
227 : {
228 1 : *err = VSTR_TYPE_SC_MMAP_FILE_ERR_CLOSE_ERRNO;
229 1 : return (FALSE);
230 : }
231 :
232 31014 : if (*err)
233 30870 : errno = saved_errno;
234 :
235 31014 : return (ret);
236 : }
237 : #endif
238 :
239 : static int vstr__sc_read_slow_len_fd(Vstr_base *base, size_t pos, int fd,
240 : size_t len, unsigned int *err)
241 32 : {
242 32 : size_t orig_pos = pos;
243 32 : ssize_t bytes = -1;
244 32 : unsigned int num = 0;
245 32 : Vstr_ref *ref = NULL;
246 :
247 32 : ASSERT_GOTO(base && (pos <= base->len), inval_args);
248 :
249 32 : if (pos && !vstr__add_setup_pos(base, &pos, &num, NULL))
250 1 : goto mem_fail;
251 31 : pos = orig_pos;
252 :
253 31 : if (!(ref = vstr_ref_make_malloc(len)))
254 2 : goto mem_fail;
255 :
256 29 : if (!vstr_cntl_conf(base->conf, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_REF,
257 : 1, UINT_MAX))
258 1 : goto mem_ref_fail;
259 :
260 28 : do
261 : {
262 28 : bytes = read(fd, ref->ptr, len);
263 28 : } while ((bytes == -1) && (errno == EINTR));
264 :
265 28 : if (bytes == -1)
266 : {
267 4 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
268 4 : goto mem_ref_fail;
269 : }
270 24 : if (!bytes)
271 : {
272 4 : *err = VSTR_TYPE_SC_READ_FD_ERR_EOF;
273 4 : errno = ENOSPC;
274 4 : goto mem_ref_fail;
275 : }
276 :
277 20 : num = vstr_add_ref(base, pos, ref, 0, bytes); /* must work */
278 20 : ASSERT(num);
279 :
280 20 : vstr_ref_del(ref);
281 :
282 20 : return (TRUE);
283 :
284 : mem_ref_fail:
285 9 : assert(ref);
286 9 : vstr_ref_del(ref);
287 :
288 : mem_fail:
289 12 : if (!*err)
290 : {
291 4 : *err = VSTR_TYPE_SC_READ_FD_ERR_MEM;
292 4 : errno = ENOMEM;
293 : }
294 :
295 12 : return (FALSE);
296 :
297 : inval_args:
298 11 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
299 11 : errno = EINVAL;
300 11 : return (FALSE);
301 : }
302 :
303 : static int vstr__sc_read_fast_iov_fd(Vstr_base *base, size_t pos, int fd,
304 : struct iovec *iovs, unsigned int num,
305 : unsigned int *err)
306 70786 : {
307 70786 : ssize_t bytes = -1;
308 :
309 70786 : if (num > UIO_MAXIOV)
310 4 : num = UIO_MAXIOV;
311 :
312 70786 : do
313 : {
314 70786 : bytes = readv(fd, iovs, num);
315 70786 : } while ((bytes == -1) && (errno == EINTR));
316 :
317 70786 : if (bytes == -1)
318 : {
319 6828 : vstr_add_iovec_buf_end(base, pos, 0);
320 6828 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
321 6828 : return (FALSE);
322 : }
323 :
324 63958 : vstr_add_iovec_buf_end(base, pos, (size_t)bytes);
325 :
326 63958 : if (!bytes)
327 : {
328 2155 : *err = VSTR_TYPE_SC_READ_FD_ERR_EOF;
329 2155 : errno = ENOSPC;
330 2155 : return (FALSE);
331 : }
332 :
333 61803 : return (TRUE);
334 : }
335 :
336 : int vstr_sc_read_iov_fd(Vstr_base *base, size_t pos, int fd,
337 : unsigned int min, unsigned int max,
338 : unsigned int *err)
339 53976 : {
340 53976 : struct iovec *iovs = NULL;
341 53976 : unsigned int num = 0;
342 53976 : unsigned int dummy_err;
343 :
344 53976 : if (!err)
345 8 : err = &dummy_err;
346 53976 : *err = 0;
347 :
348 53976 : assert(max >= min);
349 :
350 53976 : ASSERT_GOTO(base && (pos <= base->len), inval_args);
351 :
352 53976 : if (!min)
353 4 : return (TRUE);
354 :
355 53972 : if (!base->cache_available)
356 18 : return (vstr__sc_read_slow_len_fd(base, pos, fd,
357 : min * base->conf->buf_sz, err));
358 :
359 : /* use iovec internal add -- much quicker, one syscall no double copy */
360 53954 : if (!vstr_add_iovec_buf_beg(base, pos, min, max, &iovs, &num))
361 : {
362 1 : *err = VSTR_TYPE_SC_READ_FD_ERR_MEM;
363 1 : errno = ENOMEM;
364 1 : return (FALSE);
365 : }
366 :
367 53953 : return (vstr__sc_read_fast_iov_fd(base, pos, fd, iovs, num, err));
368 :
369 : inval_args:
370 19292 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
371 19292 : errno = EINVAL;
372 19292 : return (FALSE);
373 : }
374 :
375 : #define IOV_SZ(iovs, num) \
376 : (iovs[0].iov_len + ((num > 1) ? iovs[num - 1].iov_len : 0) + \
377 : ((num > 2) ? ((num - 2) * base->conf->buf_sz) : 0))
378 :
379 : static int vstr__sc_read_len_fd(Vstr_base *base, size_t pos, int fd,
380 : size_t len, unsigned int *err)
381 16849 : {
382 16849 : struct iovec *iovs = NULL;
383 16849 : unsigned int num = 0;
384 16849 : unsigned int ios = 0;
385 :
386 16849 : if (!base->cache_available)
387 14 : return (vstr__sc_read_slow_len_fd(base, pos, fd, len, err));
388 :
389 : /* guess at 2 over size, as we usually lose some in the division
390 : * and we can lose a lot on iovs[0] */
391 16835 : ios = len / base->conf->buf_sz;
392 16835 : ios += 2;
393 16835 : if (!vstr_add_iovec_buf_beg(base, pos, ios, ios, &iovs, &num))
394 : {
395 2 : *err = VSTR_TYPE_SC_READ_FD_ERR_MEM;
396 2 : errno = ENOMEM;
397 2 : return (FALSE);
398 : }
399 :
400 : /* fixup iovs for exact size of len, if bigger */
401 42077 : assert(num && ((num == 1) || (iovs[num - 1].iov_len == base->conf->buf_sz)));
402 :
403 42077 : assert(IOV_SZ(iovs, num) >= len);
404 50499 : while (IOV_SZ(iovs, num) > len)
405 : {
406 33666 : size_t tmp = 0;
407 :
408 33666 : tmp = (IOV_SZ(iovs, num) - len);
409 33666 : if (tmp >= iovs[num - 1].iov_len)
410 : {
411 16833 : --num;
412 16833 : continue;
413 : }
414 :
415 16833 : iovs[num - 1].iov_len -= tmp;
416 16833 : assert(IOV_SZ(iovs, num) == len);
417 : }
418 16833 : assert(IOV_SZ(iovs, num) == len);
419 :
420 16833 : return (vstr__sc_read_fast_iov_fd(base, pos, fd, iovs, num, err));
421 : }
422 : #undef IOV_SZ
423 :
424 : int vstr_sc_read_len_fd(Vstr_base *base, size_t pos, int fd,
425 : size_t len, unsigned int *err)
426 16758 : {
427 16758 : unsigned int dummy_err;
428 16758 : const size_t off = 0;
429 :
430 16758 : if (!err)
431 8 : err = &dummy_err;
432 16758 : *err = 0;
433 :
434 16758 : ASSERT_GOTO(base && (pos <= base->len), inval_args);
435 :
436 16758 : if (!vstr__sc_get_size(base->len, fd, &len, off, err,
437 : VSTR_TYPE_SC_READ_FD_ERR_FSTAT_ERRNO,
438 : VSTR_TYPE_SC_READ_FD_ERR_TOO_LARGE))
439 4 : return (FALSE);
440 :
441 16754 : return (vstr__sc_read_len_fd(base, pos, fd, len, err));
442 :
443 : inval_args:
444 4193 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
445 4193 : errno = EINVAL;
446 4193 : return (FALSE);
447 : }
448 :
449 : int vstr_sc_read_iov_file(Vstr_base *base, size_t pos,
450 : const char *filename, VSTR_AUTOCONF_off64_t off,
451 : unsigned int min, unsigned int max,
452 : unsigned int *err)
453 50 : {
454 50 : int fd = -1;
455 50 : unsigned int dummy_err;
456 50 : int ret = 0;
457 50 : int saved_errno = 0;
458 :
459 50 : if (!err)
460 17 : err = &dummy_err;
461 50 : *err = 0;
462 :
463 50 : ASSERT_GOTO(base && (pos <= base->len), inval_args);
464 :
465 32 : if ((fd = VSTR__POSIX_OPEN1(filename)) == -1)
466 : {
467 4 : *err = VSTR_TYPE_SC_READ_FILE_ERR_OPEN_ERRNO;
468 4 : return (FALSE);
469 : }
470 :
471 28 : if (off && (lseek64(fd, off, SEEK_SET) == -1))
472 4 : *err = VSTR_TYPE_SC_READ_FILE_ERR_SEEK_ERRNO;
473 :
474 28 : if (!*err)
475 : {
476 24 : size_t orig_pos = pos;
477 24 : size_t orig_len = base->len;
478 :
479 60 : while (!*err && min)
480 : {
481 36 : unsigned int num = base->num;
482 36 : size_t tmp = base->len;
483 :
484 36 : ret = vstr_sc_read_iov_fd(base, pos, fd, min, max, err);
485 :
486 36 : num = base->num - num;
487 36 : if (num > min) num = min;
488 :
489 36 : min -= num;
490 36 : max -= num;
491 36 : pos += base->len - tmp;
492 : }
493 24 : if (*err) /* shouldn't change errno */
494 : {
495 3 : ASSERT((saved_errno = errno));
496 3 : vstr_del(base, orig_pos, base->len - orig_len);
497 21 : ASSERT( saved_errno == errno);
498 : }
499 : }
500 :
501 28 : if (*err)
502 7 : saved_errno = errno;
503 :
504 28 : if ((VSTR__POSIX_CLOSE(fd) == -1) && !*err)
505 : {
506 1 : *err = VSTR_TYPE_SC_READ_FILE_ERR_CLOSE_ERRNO;
507 1 : return (FALSE);
508 : }
509 :
510 27 : if (*err)
511 7 : errno = saved_errno;
512 :
513 27 : return (ret);
514 :
515 : inval_args:
516 29 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
517 29 : errno = EINVAL;
518 29 : return (FALSE);
519 : }
520 :
521 : int vstr_sc_read_len_file(Vstr_base *base, size_t pos,
522 : const char *filename,
523 : VSTR_AUTOCONF_off64_t off, size_t len,
524 : unsigned int *err)
525 30993 : {
526 30993 : int fd = -1;
527 30993 : unsigned int dummy_err;
528 30993 : int ret = FALSE;
529 30993 : int saved_errno = 0;
530 :
531 30993 : if (!err)
532 83 : err = &dummy_err;
533 30993 : *err = 0;
534 :
535 30993 : ASSERT_GOTO(base && (pos <= base->len), inval_args);
536 :
537 30975 : if ((fd = VSTR__POSIX_OPEN1(filename)) == -1)
538 : {
539 8 : *err = VSTR_TYPE_SC_READ_FILE_ERR_OPEN_ERRNO;
540 8 : return (FALSE);
541 : }
542 :
543 30967 : if (vstr__sc_get_size(base->len, fd, &len, off, err,
544 : VSTR_TYPE_SC_READ_FILE_ERR_FSTAT_ERRNO,
545 : VSTR_TYPE_SC_READ_FILE_ERR_TOO_LARGE))
546 : {
547 99 : if (off && (lseek64(fd, off, SEEK_SET) == -1))
548 4 : *err = VSTR_TYPE_SC_READ_FILE_ERR_SEEK_ERRNO;
549 : }
550 :
551 30967 : if (!*err)
552 : {
553 95 : size_t orig_pos = pos;
554 95 : size_t orig_len = base->len;
555 :
556 190 : while (!*err && len)
557 : {
558 95 : size_t tmp = base->len;
559 :
560 95 : ret = vstr__sc_read_len_fd(base, pos, fd, len, err);
561 95 : len -= base->len - tmp;
562 95 : pos += base->len - tmp;
563 : }
564 :
565 95 : if (*err)
566 : {
567 4 : ASSERT((saved_errno = errno));
568 4 : vstr_del(base, orig_pos, base->len - orig_len);
569 23227 : ASSERT( saved_errno == errno);
570 : }
571 : }
572 :
573 30967 : if (*err)
574 30876 : saved_errno = errno;
575 :
576 30967 : if ((VSTR__POSIX_CLOSE(fd) == -1) && !*err)
577 : {
578 1 : *err = VSTR_TYPE_SC_READ_FILE_ERR_CLOSE_ERRNO;
579 1 : return (FALSE);
580 : }
581 :
582 30966 : if (*err)
583 30876 : errno = saved_errno;
584 :
585 30966 : return (ret);
586 :
587 : inval_args:
588 7764 : *err = VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO;
589 7764 : errno = EINVAL;
590 7764 : return (FALSE);
591 : }
592 :
593 : int vstr_sc_write_fd(Vstr_base *base, size_t pos, size_t len, int fd,
594 : unsigned int *err)
595 97092 : {
596 97092 : unsigned int dummy_err;
597 :
598 97092 : if (!err)
599 56556 : err = &dummy_err;
600 97092 : *err = 0;
601 :
602 97092 : ASSERT_GOTO(base && pos && (((pos <= base->len) &&
603 : (vstr_sc_poslast(pos, len) <= base->len)) ||
604 : !len), inval_args);
605 :
606 97083 : if (!len)
607 934 : return (TRUE);
608 :
609 176223 : while (len)
610 : {
611 96194 : struct iovec cpy_vec[VSTR__SC_VEC_SZ];
612 96194 : size_t sz = VSTR__SC_VEC_SZ;
613 96194 : struct iovec *vec;
614 96194 : unsigned int num = 0;
615 96194 : size_t clen = 0;
616 96194 : ssize_t bytes = 0;
617 :
618 96194 : if ((pos == 1) && (len == base->len) && base->cache_available)
619 : {
620 96169 : if (!(clen = vstr_export_iovec_ptr_all(base, &vec, &num)))
621 : {
622 1 : *err = VSTR_TYPE_SC_WRITE_FD_ERR_MEM;
623 1 : errno = ENOMEM;
624 1 : return (FALSE);
625 : }
626 : }
627 : else
628 : { /* could opt. anything with cache_avail ... but probably not worth it */
629 25 : vec = cpy_vec;
630 25 : clen = vstr_export_iovec_cpy_ptr(base, pos, len, vec, sz, &num);
631 : }
632 :
633 96193 : if (num > UIO_MAXIOV)
634 : {
635 28 : unsigned int scan = num;
636 :
637 404 : while (scan-- > UIO_MAXIOV)
638 376 : clen -= vec[scan].iov_len;
639 28 : num = UIO_MAXIOV;
640 : }
641 :
642 : /* Linux just gives EINVAL on size > SSIZE_MAX */
643 96193 : if (clen > SSIZE_MAX)
644 : {
645 4 : unsigned int scan = num;
646 :
647 7 : ASSERT(VSTR_MAX_NODE_ALL <= SSIZE_MAX);
648 :
649 8 : while (clen > SSIZE_MAX)
650 : {
651 4 : ASSERT(scan >= 1);
652 4 : clen -= vec[--scan].iov_len;
653 : }
654 :
655 4 : num = scan;
656 : }
657 :
658 96193 : do
659 : {
660 96193 : bytes = writev(fd, vec, num);
661 96193 : } while ((bytes == -1) && (errno == EINTR));
662 :
663 96193 : if (bytes == -1)
664 : {
665 15564 : *err = VSTR_TYPE_SC_WRITE_FD_ERR_WRITE_ERRNO;
666 15564 : return (FALSE);
667 : }
668 :
669 80629 : ASSERT((size_t)bytes <= len);
670 :
671 80629 : vstr_del(base, pos, bytes);
672 :
673 80629 : ASSERT((size_t)bytes <= clen);
674 80629 : if (clen != (size_t)bytes)
675 555 : break;
676 :
677 80074 : len -= bytes;
678 : }
679 :
680 80584 : return (TRUE);
681 :
682 : inval_args:
683 25252 : *err = VSTR_TYPE_SC_WRITE_FD_ERR_WRITE_ERRNO;
684 25252 : errno = EINVAL;
685 25252 : return (FALSE);
686 : }
687 :
688 : int vstr_sc_write_file(Vstr_base *base, size_t pos, size_t len,
689 : const char *filename, int open_flags,
690 : VSTR_AUTOCONF_mode_t mode,
691 : VSTR_AUTOCONF_off64_t off, unsigned int *err)
692 53 : {
693 53 : int fd = -1;
694 53 : unsigned int dummy_err;
695 53 : int ret = 0;
696 53 : int saved_errno = 0;
697 :
698 53 : if (!err)
699 36 : err = &dummy_err;
700 53 : *err = 0;
701 :
702 53 : ASSERT_GOTO(base && pos && (((pos <= base->len) &&
703 : (vstr_sc_poslast(pos, len) <= base->len)) ||
704 : !len), inval_args);
705 :
706 53 : if (!len)
707 4 : return (TRUE);
708 :
709 49 : if (!open_flags) /* O_RDONLY isn't valid, for obvious reasons */
710 5 : open_flags = (O_WRONLY | O_CREAT | O_EXCL | O_NONBLOCK);
711 :
712 49 : if ((fd = VSTR__POSIX_OPEN3(filename, open_flags, mode)) == -1)
713 : {
714 4 : *err = VSTR_TYPE_SC_WRITE_FILE_ERR_OPEN_ERRNO;
715 4 : return (FALSE);
716 : }
717 :
718 45 : if (off && (lseek64(fd, off, SEEK_SET) == -1))
719 4 : *err = VSTR_TYPE_SC_WRITE_FILE_ERR_SEEK_ERRNO;
720 :
721 86 : while (!*err && len)
722 : {
723 41 : size_t tmp = base->len;
724 :
725 41 : ret = vstr_sc_write_fd(base, pos, len, fd, err);
726 41 : len -= tmp - base->len;
727 : }
728 :
729 45 : if (*err)
730 9 : saved_errno = errno;
731 :
732 45 : if ((VSTR__POSIX_CLOSE(fd) == -1) && !*err)
733 : {
734 1 : *err = VSTR_TYPE_SC_WRITE_FILE_ERR_CLOSE_ERRNO;
735 1 : return (FALSE);
736 : }
737 :
738 44 : if (*err)
739 9 : errno = saved_errno;
740 :
741 44 : return (ret);
742 :
743 : inval_args:
744 14 : *err = VSTR_TYPE_SC_WRITE_FD_ERR_WRITE_ERRNO;
745 14 : errno = EINVAL;
746 14 : return (FALSE);
747 : }
748 :
749 : static int vstr__sc_fmt_add_cb_ipv4_ptr(Vstr_base *base, size_t pos,
750 : Vstr_fmt_spec *spec)
751 129 : {
752 129 : struct in_addr *ipv4 = VSTR_FMT_CB_ARG_PTR(spec, 0);
753 129 : size_t obj_len = 0;
754 129 : char buf[1024];
755 129 : const char *ptr = NULL;
756 :
757 129 : assert(ipv4);
758 129 : assert(sizeof(buf) >= INET_ADDRSTRLEN);
759 :
760 129 : ptr = inet_ntop(AF_INET, ipv4, buf, sizeof(buf));
761 129 : if (!ptr) ptr = "0.0.0.0";
762 :
763 129 : obj_len = strlen(ptr);
764 :
765 129 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &obj_len,
766 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
767 29 : return (FALSE);
768 :
769 100 : if (!vstr_add_buf(base, pos, ptr, obj_len))
770 6 : return (FALSE);
771 :
772 94 : if (!vstr_sc_fmt_cb_end(base, pos, spec, obj_len))
773 30 : return (FALSE);
774 :
775 64 : return (TRUE);
776 : }
777 :
778 : static int vstr__sc_fmt_add_cb_ipv6_ptr(Vstr_base *base, size_t pos,
779 : Vstr_fmt_spec *spec)
780 129 : {
781 129 : struct in6_addr *ipv6 = VSTR_FMT_CB_ARG_PTR(spec, 0);
782 129 : size_t obj_len = 0;
783 129 : char buf[1024];
784 129 : const char *ptr = NULL;
785 :
786 129 : assert(ipv6);
787 129 : assert(sizeof(buf) >= INET6_ADDRSTRLEN);
788 :
789 129 : ptr = inet_ntop(AF_INET6, ipv6, buf, sizeof(buf));
790 129 : if (!ptr) ptr = "::";
791 :
792 129 : obj_len = strlen(ptr);
793 :
794 129 : if (!vstr_sc_fmt_cb_beg(base, &pos, spec, &obj_len,
795 : VSTR_FLAG_SC_FMT_CB_BEG_OBJ_STR))
796 22 : return (FALSE);
797 :
798 107 : if (!vstr_add_buf(base, pos, ptr, obj_len))
799 13 : return (FALSE);
800 :
801 94 : if (!vstr_sc_fmt_cb_end(base, pos, spec, obj_len))
802 30 : return (FALSE);
803 :
804 64 : return (TRUE);
805 : }
806 :
807 : int vstr_sc_fmt_add_ipv4_ptr(Vstr_conf *conf, const char *name)
808 4169 : {
809 4169 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ipv4_ptr,
810 : VSTR_TYPE_FMT_PTR_VOID,
811 : VSTR_TYPE_FMT_END));
812 : }
813 :
814 : int vstr_sc_fmt_add_ipv6_ptr(Vstr_conf *conf, const char *name)
815 4071 : {
816 4071 : return (vstr_fmt_add(conf, name, vstr__sc_fmt_add_cb_ipv6_ptr,
817 : VSTR_TYPE_FMT_PTR_VOID,
818 : VSTR_TYPE_FMT_END));
819 : }
820 :
821 : #define VSTR__SC_FMT_ADD(x, n, nchk) \
822 : if (ret && \
823 : !VSTR_SC_FMT_ADD(conf, vstr_sc_fmt_add_ ## x, "{" n, nchk, "}")) \
824 : ret = FALSE
825 :
826 : int vstr__sc_fmt_add_posix(Vstr_conf *conf)
827 601 : {
828 601 : int ret = TRUE;
829 :
830 601 : VSTR__SC_FMT_ADD(ipv4_ptr, "ipv4.p", "p");
831 601 : VSTR__SC_FMT_ADD(ipv6_ptr, "ipv6.p", "p");
832 :
833 601 : return (ret);
834 : }
|