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