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