1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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, reg char* buf, reg size_t n) 32 #else 33 static ssize_t sfoutput(f,buf,n) 34 Sfio_t* f; 35 reg char* buf; 36 reg 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(reg Sfio_t* f, reg const Void_t* buf, reg size_t n, reg Sfdisc_t* disc) 126 #else 127 ssize_t sfwr(f,buf,n,disc) 128 reg Sfio_t* f; 129 reg Void_t* buf; 130 reg size_t n; 131 reg Sfdisc_t* disc; 132 #endif 133 { 134 reg ssize_t w; 135 reg Sfdisc_t* dc; 136 reg int local, oerrno; 137 138 SFMTXSTART(f,(ssize_t)(-1)); 139 140 GETLOCAL(f,local); 141 if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */ 142 { if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0 ) 143 SFMTXRETURN(f, (ssize_t)(-1)); 144 if(f->next > f->data && SFSYNC(f) < 0 ) 145 SFMTXRETURN(f, (ssize_t)(-1)); 146 } 147 148 for(;;) 149 { /* stream locked by sfsetfd() */ 150 if(!(f->flags&SF_STRING) && f->file < 0) 151 SFMTXRETURN(f,(ssize_t)0); 152 153 /* clear current error states */ 154 f->flags &= ~(SF_EOF|SF_ERROR); 155 156 dc = disc; 157 if(f->flags&SF_STRING) /* total required buffer */ 158 w = n + (f->next - f->data); 159 else 160 { /* warn that a write is about to happen */ 161 SFDISC(f,dc,writef); 162 if(dc && dc->exceptf && (f->flags&SF_IOCHECK) ) 163 { reg int rv; 164 if(local) 165 SETLOCAL(f); 166 if((rv = _sfexcept(f,SF_WRITE,n,dc)) > 0) 167 n = rv; 168 else if(rv < 0) 169 { f->flags |= SF_ERROR; 170 SFMTXRETURN(f, rv); 171 } 172 } 173 174 if(f->extent >= 0) 175 { /* make sure we are at the right place to write */ 176 if(f->flags&SF_APPENDWR) 177 { if(f->here != f->extent || (f->flags&SF_SHARE)) 178 { f->here = SFSK(f,(Sfoff_t)0,SEEK_END,dc); 179 f->extent = f->here; 180 } 181 } 182 else if((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC)) 183 f->here = SFSK(f,f->here,SEEK_SET,dc); 184 } 185 186 oerrno = errno; 187 errno = 0; 188 189 if(dc && dc->writef) 190 { SFDCWR(f,buf,n,dc,w); 191 } 192 else if(SFISNULL(f)) 193 w = n; 194 else if(f->flags&SF_WHOLE) 195 goto do_write; 196 else if((ssize_t)n >= _Sfpage && 197 !(f->flags&(SF_SHARE|SF_APPENDWR)) && 198 f->here == f->extent && (f->here%_Sfpage) == 0) 199 { if((w = sfoutput(f,(char*)buf,n)) <= 0) 200 goto do_write; 201 } 202 else 203 { 204 do_write: 205 if((w = syswritef(f->file,buf,n)) > 0) 206 f->bits &= ~SF_HOLE; 207 } 208 209 if(errno == 0) 210 errno = oerrno; 211 212 if(w > 0) 213 { if(!(f->bits&SF_DCDOWN) ) 214 { if((f->flags&(SF_APPENDWR|SF_PUBLIC)) && f->extent >= 0 ) 215 f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc); 216 else f->here += w; 217 if(f->extent >= 0 && f->here > f->extent) 218 f->extent = f->here; 219 } 220 221 SFMTXRETURN(f, (ssize_t)w); 222 } 223 } 224 225 if(local) 226 SETLOCAL(f); 227 switch(_sfexcept(f,SF_WRITE,w,dc)) 228 { 229 case SF_ECONT : 230 goto do_continue; 231 case SF_EDONE : 232 w = local ? 0 : w; 233 SFMTXRETURN(f, (ssize_t)w); 234 case SF_EDISC : 235 if(!local && !(f->flags&SF_STRING)) 236 goto do_continue; 237 /* else fall thru */ 238 case SF_ESTACK : 239 SFMTXRETURN(f, (ssize_t)(-1)); 240 } 241 242 do_continue: 243 for(dc = f->disc; dc; dc = dc->disc) 244 if(dc == disc) 245 break; 246 disc = dc; 247 } 248 } 249