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 /* Internal function to do a hard read. 25 ** This knows about discipline and memory mapping, peek read. 26 ** 27 ** Written by Kiem-Phong Vo. 28 */ 29 30 /* synchronize unseekable write streams */ 31 #if __STD_C 32 static void _sfwrsync(void) 33 #else 34 static void _sfwrsync() 35 #endif 36 { reg Sfpool_t* p; 37 reg Sfio_t* f; 38 reg int n; 39 40 /* sync all pool heads */ 41 for(p = _Sfpool.next; p; p = p->next) 42 { if(p->n_sf <= 0) 43 continue; 44 f = p->sf[0]; 45 if(!SFFROZEN(f) && f->next > f->data && 46 (f->mode&SF_WRITE) && f->extent < 0 ) 47 (void)_sfflsbuf(f,-1); 48 } 49 50 /* and all the ones in the discrete pool */ 51 for(n = 0; n < _Sfpool.n_sf; ++n) 52 { f = _Sfpool.sf[n]; 53 54 if(!SFFROZEN(f) && f->next > f->data && 55 (f->mode&SF_WRITE) && f->extent < 0 ) 56 (void)_sfflsbuf(f,-1); 57 } 58 } 59 60 #if __STD_C 61 ssize_t sfrd(reg Sfio_t* f, reg Void_t* buf, reg size_t n, Sfdisc_t* disc) 62 #else 63 ssize_t sfrd(f,buf,n,disc) 64 reg Sfio_t* f; 65 reg Void_t* buf; 66 reg size_t n; 67 Sfdisc_t* disc; 68 #endif 69 { 70 Sfoff_t r; 71 reg Sfdisc_t* dc; 72 reg int local, rcrv, dosync, oerrno; 73 74 SFMTXSTART(f,-1); 75 76 GETLOCAL(f,local); 77 if((rcrv = f->mode & (SF_RC|SF_RV)) ) 78 f->mode &= ~(SF_RC|SF_RV); 79 f->bits &= ~SF_JUSTSEEK; 80 81 if(f->mode&SF_PKRD) 82 SFMTXRETURN(f, -1); 83 84 if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */ 85 { if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0) 86 SFMTXRETURN(f, -1); 87 if(f->next < f->endb) 88 { if(SFSYNC(f) < 0) 89 SFMTXRETURN(f, -1); 90 if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) ) 91 { f->endb = f->next = f->endr = f->data; 92 f->mode &= ~SF_SYNCED; 93 } 94 #ifdef MAP_TYPE 95 if((f->bits&SF_MMAP) && f->data) 96 { SFMUNMAP(f, f->data, f->endb-f->data); 97 f->data = NIL(uchar*); 98 } 99 #endif 100 f->next = f->endb = f->endr = f->endw = f->data; 101 } 102 } 103 104 for(dosync = 0;;) 105 { /* stream locked by sfsetfd() */ 106 if(!(f->flags&SF_STRING) && f->file < 0) 107 SFMTXRETURN(f, 0); 108 109 f->flags &= ~(SF_EOF|SF_ERROR); 110 111 dc = disc; 112 if(f->flags&SF_STRING) 113 { if((r = (f->data+f->extent) - f->next) < 0) 114 r = 0; 115 if(r <= 0) 116 goto do_except; 117 SFMTXRETURN(f, (ssize_t)r); 118 } 119 120 /* warn that a read is about to happen */ 121 SFDISC(f,dc,readf); 122 if(dc && dc->exceptf && (f->flags&SF_IOCHECK) ) 123 { reg int rv; 124 if(local) 125 SETLOCAL(f); 126 if((rv = _sfexcept(f,SF_READ,n,dc)) > 0) 127 n = rv; 128 else if(rv < 0) 129 { f->flags |= SF_ERROR; 130 SFMTXRETURN(f, (ssize_t)rv); 131 } 132 } 133 134 #ifdef MAP_TYPE 135 if(f->bits&SF_MMAP) 136 { reg ssize_t a, round; 137 sfstat_t st; 138 139 /* determine if we have to copy data to buffer */ 140 if((uchar*)buf >= f->data && (uchar*)buf <= f->endb) 141 { n += f->endb - f->next; 142 buf = NIL(char*); 143 } 144 145 /* actual seek location */ 146 if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) && 147 (r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here) 148 f->here = r; 149 else f->here -= f->endb-f->next; 150 151 /* before mapping, make sure we have data to map */ 152 if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n) 153 { if((r = sysfstatf(f->file,&st)) < 0) 154 goto do_except; 155 if((r = (f->extent = st.st_size) - f->here) <= 0 ) 156 { r = 0; /* eof */ 157 goto do_except; 158 } 159 } 160 161 /* make sure current position is page aligned */ 162 if((a = (size_t)(f->here%_Sfpage)) != 0) 163 { f->here -= a; 164 r += a; 165 } 166 167 /* map minimal requirement */ 168 if(r > (round = (1 + (n+a)/f->size)*f->size) ) 169 r = round; 170 171 if(f->data) 172 SFMUNMAP(f, f->data, f->endb-f->data); 173 174 for(;;) 175 { f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r, 176 (PROT_READ|PROT_WRITE), 177 MAP_PRIVATE, 178 f->file, (sfoff_t)f->here); 179 if(f->data && (caddr_t)f->data != (caddr_t)(-1)) 180 break; 181 else 182 { f->data = NIL(uchar*); 183 if((r >>= 1) < (_Sfpage*SF_NMAP) || 184 (errno != EAGAIN && errno != ENOMEM) ) 185 break; 186 } 187 } 188 189 if(f->data) 190 { if(f->bits&SF_SEQUENTIAL) 191 SFMMSEQON(f,f->data,r); 192 f->next = f->data+a; 193 f->endr = f->endb = f->data+r; 194 f->endw = f->data; 195 f->here += r; 196 197 /* make known our seek location */ 198 (void)SFSK(f,f->here,SEEK_SET,dc); 199 200 if(buf) 201 { if(n > (size_t)(r-a)) 202 n = (ssize_t)(r-a); 203 memcpy(buf,f->next,n); 204 f->next += n; 205 } 206 else n = f->endb - f->next; 207 208 SFMTXRETURN(f, n); 209 } 210 else 211 { r = -1; 212 f->here += a; 213 214 /* reset seek pointer to its physical location */ 215 (void)SFSK(f,f->here,SEEK_SET,dc); 216 217 /* make a buffer */ 218 (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND); 219 220 if(!buf) 221 { buf = (Void_t*)f->data; 222 n = f->size; 223 } 224 } 225 } 226 #endif 227 228 /* sync unseekable write streams to prevent deadlock */ 229 if(!dosync && f->extent < 0) 230 { dosync = 1; 231 _sfwrsync(); 232 } 233 234 /* make sure file pointer is right */ 235 if(f->extent >= 0 && (f->flags&SF_SHARE) ) 236 { if(!(f->flags&SF_PUBLIC) ) 237 f->here = SFSK(f,f->here,SEEK_SET,dc); 238 else f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc); 239 } 240 241 oerrno = errno; 242 errno = 0; 243 244 if(dc && dc->readf) 245 { int share = f->flags&SF_SHARE; 246 247 if(rcrv) /* pass on rcrv for possible continuations */ 248 f->mode |= rcrv; 249 /* tell readf that no peeking necessary */ 250 else f->flags &= ~SF_SHARE; 251 252 SFDCRD(f,buf,n,dc,r); 253 254 /* reset flags */ 255 if(rcrv) 256 f->mode &= ~rcrv; 257 else f->flags |= share; 258 } 259 else if(SFISNULL(f)) 260 r = 0; 261 else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv) 262 { /* try peek read */ 263 r = sfpkrd(f->file, (char*)buf, n, 264 (rcrv&SF_RC) ? (int)f->getr : -1, 265 -1L, (rcrv&SF_RV) ? 1 : 0); 266 if(r > 0) 267 { if(rcrv&SF_RV) 268 f->mode |= SF_PKRD; 269 else f->mode |= SF_RC; 270 } 271 } 272 else r = sysreadf(f->file,buf,n); 273 274 if(errno == 0 ) 275 errno = oerrno; 276 277 if(r > 0 ) 278 { if(!(f->bits&SF_DCDOWN) ) /* not a continuation call */ 279 { if(!(f->mode&SF_PKRD) ) 280 { f->here += r; 281 if(f->extent >= 0 && f->extent < f->here) 282 f->extent = f->here; 283 } 284 if((uchar*)buf >= f->data && 285 (uchar*)buf < f->data+f->size) 286 f->endb = f->endr = ((uchar*)buf) + r; 287 } 288 289 SFMTXRETURN(f, (ssize_t)r); 290 } 291 292 do_except: 293 if(local) 294 SETLOCAL(f); 295 switch(_sfexcept(f,SF_READ,(ssize_t)r,dc)) 296 { 297 case SF_ECONT : 298 goto do_continue; 299 case SF_EDONE : 300 n = local ? 0 : (ssize_t)r; 301 SFMTXRETURN(f,n); 302 case SF_EDISC : 303 if(!local && !(f->flags&SF_STRING)) 304 goto do_continue; 305 /* else fall thru */ 306 case SF_ESTACK : 307 SFMTXRETURN(f, -1); 308 } 309 310 do_continue: 311 for(dc = f->disc; dc; dc = dc->disc) 312 if(dc == disc) 313 break; 314 disc = dc; 315 } 316 } 317