1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2011 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #include "sfhdr.h" 23 24 /* Write data with discipline. 25 ** In the case of a string stream, this is used mainly to extend 26 ** the buffer. However, this is done here so that exception handling 27 ** is done uniformly across all stream types. 28 ** 29 ** Written by Kiem-Phong Vo. 30 */ 31 32 /* hole preserving writes */ 33 #if __STD_C 34 static ssize_t sfoutput(Sfio_t* f, char* buf, size_t n) 35 #else 36 static ssize_t sfoutput(f,buf,n) 37 Sfio_t* f; 38 char* buf; 39 size_t n; 40 #endif 41 { reg char *sp, *wbuf, *endbuf; 42 reg ssize_t s, w, wr; 43 44 s = w = 0; 45 wbuf = buf; 46 endbuf = buf+n; 47 while(n > 0) 48 { if((ssize_t)n < _Sfpage) /* no hole possible */ 49 { buf += n; 50 s = n = 0; 51 } 52 else while((ssize_t)n >= _Sfpage) 53 { /* see if a hole of 0's starts here */ 54 sp = buf+1; 55 if(buf[0] == 0 && buf[_Sfpage-1] == 0) 56 { /* check byte at a time until int-aligned */ 57 while(((ulong)sp)%sizeof(int)) 58 { if(*sp != 0) 59 goto chk_hole; 60 sp += 1; 61 } 62 63 /* check using int to speed up */ 64 while(sp < endbuf) 65 { if(*((int*)sp) != 0) 66 goto chk_hole; 67 sp += sizeof(int); 68 } 69 70 /* check the remaining bytes */ 71 if(sp > endbuf) 72 { sp -= sizeof(int); 73 while(sp < endbuf) 74 { if(*sp != 0) 75 goto chk_hole; 76 sp += 1; 77 } 78 } 79 } 80 81 chk_hole: 82 if((s = sp-buf) >= _Sfpage) /* found a hole */ 83 break; 84 85 /* skip a dirty page */ 86 n -= _Sfpage; 87 buf += _Sfpage; 88 } 89 90 /* write out current dirty pages */ 91 if(buf > wbuf) 92 { if((ssize_t)n < _Sfpage) 93 { buf = endbuf; 94 n = s = 0; 95 } 96 if((wr = syswritef(f->file,wbuf,buf-wbuf)) > 0) 97 { w += wr; 98 f->bits &= ~SF_HOLE; 99 } 100 if(wr != (buf-wbuf)) 101 break; 102 wbuf = buf; 103 } 104 105 /* seek to a rounded boundary within the hole */ 106 if(s >= _Sfpage) 107 { s = (s/_Sfpage)*_Sfpage; 108 if(SFSK(f,(Sfoff_t)s,SEEK_CUR,NIL(Sfdisc_t*)) < 0) 109 break; 110 w += s; 111 n -= s; 112 wbuf = (buf += s); 113 f->bits |= SF_HOLE; 114 115 if(n > 0) 116 { /* next page must be dirty */ 117 s = (ssize_t)n <= _Sfpage ? 1 : _Sfpage; 118 buf += s; 119 n -= s; 120 } 121 } 122 } 123 124 return w > 0 ? w : -1; 125 } 126 127 #if __STD_C 128 ssize_t sfwr(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc) 129 #else 130 ssize_t sfwr(f,buf,n,disc) 131 Sfio_t* f; 132 Void_t* buf; 133 size_t n; 134 Sfdisc_t* disc; 135 #endif 136 { 137 reg ssize_t w; 138 reg Sfdisc_t* dc; 139 reg int local, oerrno; 140 SFMTXDECL(f); 141 142 SFMTXENTER(f,(ssize_t)(-1)); 143 144 GETLOCAL(f,local); 145 if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */ 146 { if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0 ) 147 SFMTXRETURN(f, (ssize_t)(-1)); 148 if(f->next > f->data && SFSYNC(f) < 0 ) 149 SFMTXRETURN(f, (ssize_t)(-1)); 150 } 151 152 for(;;) 153 { /* stream locked by sfsetfd() */ 154 if(!(f->flags&SF_STRING) && f->file < 0) 155 SFMTXRETURN(f,(ssize_t)0); 156 157 /* clear current error states */ 158 f->flags &= ~(SF_EOF|SF_ERROR); 159 160 dc = disc; 161 if(f->flags&SF_STRING) /* just asking to extend buffer */ 162 w = n + (f->next - f->data); 163 else 164 { /* warn that a write is about to happen */ 165 SFDISC(f,dc,writef); 166 if(dc && dc->exceptf && (f->flags&SF_IOCHECK) ) 167 { reg int rv; 168 if(local) 169 SETLOCAL(f); 170 if((rv = _sfexcept(f,SF_WRITE,n,dc)) > 0) 171 n = rv; 172 else if(rv < 0) 173 { f->flags |= SF_ERROR; 174 SFMTXRETURN(f, rv); 175 } 176 } 177 178 if(f->extent >= 0) 179 { /* make sure we are at the right place to write */ 180 if(f->flags&SF_APPENDWR) 181 { if(f->here != f->extent || (f->flags&SF_SHARE)) 182 { f->here = SFSK(f,(Sfoff_t)0,SEEK_END,dc); 183 f->extent = f->here; 184 } 185 } 186 else if((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC)) 187 f->here = SFSK(f,f->here,SEEK_SET,dc); 188 } 189 190 oerrno = errno; 191 errno = 0; 192 193 if(dc && dc->writef) 194 { SFDCWR(f,buf,n,dc,w); 195 } 196 else if(SFISNULL(f)) 197 w = n; 198 else if(f->flags&SF_WHOLE) 199 goto do_write; 200 else if((ssize_t)n >= _Sfpage && 201 !(f->flags&(SF_SHARE|SF_APPENDWR)) && 202 f->here == f->extent && (f->here%_Sfpage) == 0) 203 { if((w = sfoutput(f,(char*)buf,n)) <= 0) 204 goto do_write; 205 } 206 else 207 { 208 do_write: 209 if((w = syswritef(f->file,buf,n)) > 0) 210 f->bits &= ~SF_HOLE; 211 } 212 213 if(errno == 0) 214 errno = oerrno; 215 216 if(w > 0) 217 { if(!(f->bits&SF_DCDOWN) ) 218 { if((f->flags&(SF_APPENDWR|SF_PUBLIC)) && f->extent >= 0 ) 219 f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc); 220 else f->here += w; 221 if(f->extent >= 0 && f->here > f->extent) 222 f->extent = f->here; 223 } 224 225 SFMTXRETURN(f, (ssize_t)w); 226 } 227 } 228 229 if(local) 230 SETLOCAL(f); 231 switch(_sfexcept(f,SF_WRITE,w,dc)) 232 { 233 case SF_ECONT : 234 goto do_continue; 235 case SF_EDONE : 236 w = local ? 0 : w; 237 SFMTXRETURN(f, (ssize_t)w); 238 case SF_EDISC : 239 if(!local && !(f->flags&SF_STRING)) 240 goto do_continue; 241 /* else fall thru */ 242 case SF_ESTACK : 243 SFMTXRETURN(f, (ssize_t)(-1)); 244 } 245 246 do_continue: 247 for(dc = f->disc; dc; dc = dc->disc) 248 if(dc == disc) 249 break; 250 disc = dc; 251 } 252 } 253