| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 1 | /*	$OpenBSD: fvwrite.c,v 1.14 2005/08/08 08:05:36 espie Exp $ */ | 
|  | 2 | /*- | 
|  | 3 | * Copyright (c) 1990, 1993 | 
|  | 4 | *	The Regents of the University of California.  All rights reserved. | 
|  | 5 | * | 
|  | 6 | * This code is derived from software contributed to Berkeley by | 
|  | 7 | * Chris Torek. | 
|  | 8 | * | 
|  | 9 | * Redistribution and use in source and binary forms, with or without | 
|  | 10 | * modification, are permitted provided that the following conditions | 
|  | 11 | * are met: | 
|  | 12 | * 1. Redistributions of source code must retain the above copyright | 
|  | 13 | *    notice, this list of conditions and the following disclaimer. | 
|  | 14 | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | 15 | *    notice, this list of conditions and the following disclaimer in the | 
|  | 16 | *    documentation and/or other materials provided with the distribution. | 
|  | 17 | * 3. Neither the name of the University nor the names of its contributors | 
|  | 18 | *    may be used to endorse or promote products derived from this software | 
|  | 19 | *    without specific prior written permission. | 
|  | 20 | * | 
|  | 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 
|  | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | 24 | * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 
|  | 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
|  | 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
|  | 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
|  | 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
|  | 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | 31 | * SUCH DAMAGE. | 
|  | 32 | */ | 
|  | 33 |  | 
|  | 34 | #include <stdio.h> | 
|  | 35 | #include <stdlib.h> | 
|  | 36 | #include <string.h> | 
|  | 37 | #include <errno.h> | 
|  | 38 | #include "local.h" | 
|  | 39 | #include "fvwrite.h" | 
|  | 40 |  | 
|  | 41 | /* | 
|  | 42 | * Write some memory regions.  Return zero on success, EOF on error. | 
|  | 43 | * | 
|  | 44 | * This routine is large and unsightly, but most of the ugliness due | 
|  | 45 | * to the three different kinds of output buffering is handled here. | 
|  | 46 | */ | 
| Jim Huang | b486773 | 2010-10-15 00:50:45 +0800 | [diff] [blame] | 47 | __LIBC_HIDDEN__ int | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 48 | __sfvwrite(FILE *fp, struct __suio *uio) | 
|  | 49 | { | 
|  | 50 | size_t len; | 
| Glenn Kasten | 0946b1f | 2011-01-09 11:28:22 -0800 | [diff] [blame] | 51 | const char *p; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 52 | struct __siov *iov; | 
|  | 53 | int w, s; | 
|  | 54 | char *nl; | 
|  | 55 | int nlknown, nldist; | 
|  | 56 |  | 
|  | 57 | if ((len = uio->uio_resid) == 0) | 
|  | 58 | return (0); | 
|  | 59 | /* make sure we can write */ | 
|  | 60 | if (cantwrite(fp)) { | 
|  | 61 | errno = EBADF; | 
|  | 62 | return (EOF); | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | #define	MIN(a, b) ((a) < (b) ? (a) : (b)) | 
|  | 66 | #define	COPY(n)	  (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) | 
|  | 67 |  | 
|  | 68 | iov = uio->uio_iov; | 
|  | 69 | p = iov->iov_base; | 
|  | 70 | len = iov->iov_len; | 
|  | 71 | iov++; | 
|  | 72 | #define GETIOV(extra_work) \ | 
|  | 73 | while (len == 0) { \ | 
|  | 74 | extra_work; \ | 
|  | 75 | p = iov->iov_base; \ | 
|  | 76 | len = iov->iov_len; \ | 
|  | 77 | iov++; \ | 
|  | 78 | } | 
|  | 79 | if (fp->_flags & __SNBF) { | 
|  | 80 | /* | 
|  | 81 | * Unbuffered: write up to BUFSIZ bytes at a time. | 
|  | 82 | */ | 
|  | 83 | do { | 
|  | 84 | GETIOV(;); | 
|  | 85 | #if 1  /* BIONIC: don't limit to 1KB writes */ | 
| André Goddard Rosa | a910abc | 2010-01-30 22:46:25 -0200 | [diff] [blame] | 86 | w = (*fp->_write)(fp->_cookie, p, len); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 87 | #else | 
|  | 88 | w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ2)); | 
|  | 89 | #endif | 
|  | 90 | if (w <= 0) | 
|  | 91 | goto err; | 
|  | 92 | p += w; | 
|  | 93 | len -= w; | 
|  | 94 | } while ((uio->uio_resid -= w) != 0); | 
|  | 95 | } else if ((fp->_flags & __SLBF) == 0) { | 
|  | 96 | /* | 
|  | 97 | * Fully buffered: fill partially full buffer, if any, | 
|  | 98 | * and then flush.  If there is no partial buffer, write | 
|  | 99 | * one _bf._size byte chunk directly (without copying). | 
|  | 100 | * | 
|  | 101 | * String output is a special case: write as many bytes | 
|  | 102 | * as fit, but pretend we wrote everything.  This makes | 
|  | 103 | * snprintf() return the number of bytes needed, rather | 
|  | 104 | * than the number used, and avoids its write function | 
|  | 105 | * (so that the write function can be invalid). | 
|  | 106 | */ | 
|  | 107 | do { | 
|  | 108 | GETIOV(;); | 
|  | 109 | if ((fp->_flags & (__SALC | __SSTR)) == | 
|  | 110 | (__SALC | __SSTR) && fp->_w < (int)len) { | 
|  | 111 | size_t blen = fp->_p - fp->_bf._base; | 
|  | 112 | unsigned char *_base; | 
|  | 113 | int _size; | 
|  | 114 |  | 
|  | 115 | /* Allocate space exponentially. */ | 
|  | 116 | _size = fp->_bf._size; | 
|  | 117 | do { | 
|  | 118 | _size = (_size << 1) + 1; | 
|  | 119 | } while (_size < (int)(blen + len)); | 
|  | 120 | _base = realloc(fp->_bf._base, _size + 1); | 
|  | 121 | if (_base == NULL) | 
|  | 122 | goto err; | 
|  | 123 | fp->_w += _size - fp->_bf._size; | 
|  | 124 | fp->_bf._base = _base; | 
|  | 125 | fp->_bf._size = _size; | 
|  | 126 | fp->_p = _base + blen; | 
|  | 127 | } | 
|  | 128 | w = fp->_w; | 
|  | 129 | if (fp->_flags & __SSTR) { | 
|  | 130 | if ((int)len < w) | 
|  | 131 | w = len; | 
|  | 132 | COPY(w);	/* copy MIN(fp->_w,len), */ | 
|  | 133 | fp->_w -= w; | 
|  | 134 | fp->_p += w; | 
|  | 135 | w = len;	/* but pretend copied all */ | 
|  | 136 | } else if (fp->_p > fp->_bf._base && (int)len > w) { | 
|  | 137 | /* fill and flush */ | 
|  | 138 | COPY(w); | 
|  | 139 | /* fp->_w -= w; */ /* unneeded */ | 
|  | 140 | fp->_p += w; | 
|  | 141 | if (fflush(fp)) | 
|  | 142 | goto err; | 
|  | 143 | } else if ((int)len >= (w = fp->_bf._size)) { | 
|  | 144 | /* write directly */ | 
|  | 145 | w = (*fp->_write)(fp->_cookie, p, w); | 
|  | 146 | if (w <= 0) | 
|  | 147 | goto err; | 
|  | 148 | } else { | 
|  | 149 | /* fill and done */ | 
|  | 150 | w = len; | 
|  | 151 | COPY(w); | 
|  | 152 | fp->_w -= w; | 
|  | 153 | fp->_p += w; | 
|  | 154 | } | 
|  | 155 | p += w; | 
|  | 156 | len -= w; | 
|  | 157 | } while ((uio->uio_resid -= w) != 0); | 
|  | 158 | } else { | 
|  | 159 | /* | 
|  | 160 | * Line buffered: like fully buffered, but we | 
|  | 161 | * must check for newlines.  Compute the distance | 
|  | 162 | * to the first newline (including the newline), | 
|  | 163 | * or `infinity' if there is none, then pretend | 
|  | 164 | * that the amount to write is MIN(len,nldist). | 
|  | 165 | */ | 
|  | 166 | nlknown = 0; | 
|  | 167 | nldist = 0;	/* XXX just to keep gcc happy */ | 
|  | 168 | do { | 
|  | 169 | GETIOV(nlknown = 0); | 
|  | 170 | if (!nlknown) { | 
|  | 171 | nl = memchr((void *)p, '\n', len); | 
|  | 172 | nldist = nl ? nl + 1 - p : (int)len + 1; | 
|  | 173 | nlknown = 1; | 
|  | 174 | } | 
|  | 175 | s = MIN((int)len, nldist); | 
|  | 176 | w = fp->_w + fp->_bf._size; | 
|  | 177 | if (fp->_p > fp->_bf._base && s > w) { | 
|  | 178 | COPY(w); | 
|  | 179 | /* fp->_w -= w; */ | 
|  | 180 | fp->_p += w; | 
|  | 181 | if (fflush(fp)) | 
|  | 182 | goto err; | 
|  | 183 | } else if (s >= (w = fp->_bf._size)) { | 
|  | 184 | w = (*fp->_write)(fp->_cookie, p, w); | 
|  | 185 | if (w <= 0) | 
| André Goddard Rosa | a910abc | 2010-01-30 22:46:25 -0200 | [diff] [blame] | 186 | goto err; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 187 | } else { | 
|  | 188 | w = s; | 
|  | 189 | COPY(w); | 
|  | 190 | fp->_w -= w; | 
|  | 191 | fp->_p += w; | 
|  | 192 | } | 
|  | 193 | if ((nldist -= w) == 0) { | 
|  | 194 | /* copied the newline: flush and forget */ | 
|  | 195 | if (fflush(fp)) | 
|  | 196 | goto err; | 
|  | 197 | nlknown = 0; | 
|  | 198 | } | 
|  | 199 | p += w; | 
|  | 200 | len -= w; | 
|  | 201 | } while ((uio->uio_resid -= w) != 0); | 
|  | 202 | } | 
|  | 203 | return (0); | 
|  | 204 |  | 
|  | 205 | err: | 
|  | 206 | fp->_flags |= __SERR; | 
|  | 207 | return (EOF); | 
|  | 208 | } |