14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #include "sfhdr.h"
234887Schin
244887Schin /* Internal function to do a hard read.
254887Schin ** This knows about discipline and memory mapping, peek read.
264887Schin **
274887Schin ** Written by Kiem-Phong Vo.
284887Schin */
294887Schin
304887Schin /* synchronize unseekable write streams */
314887Schin #if __STD_C
_sfwrsync(void)324887Schin static void _sfwrsync(void)
334887Schin #else
344887Schin static void _sfwrsync()
354887Schin #endif
364887Schin { reg Sfpool_t* p;
374887Schin reg Sfio_t* f;
384887Schin reg int n;
394887Schin
404887Schin /* sync all pool heads */
414887Schin for(p = _Sfpool.next; p; p = p->next)
424887Schin { if(p->n_sf <= 0)
434887Schin continue;
444887Schin f = p->sf[0];
454887Schin if(!SFFROZEN(f) && f->next > f->data &&
464887Schin (f->mode&SF_WRITE) && f->extent < 0 )
474887Schin (void)_sfflsbuf(f,-1);
484887Schin }
494887Schin
504887Schin /* and all the ones in the discrete pool */
514887Schin for(n = 0; n < _Sfpool.n_sf; ++n)
524887Schin { f = _Sfpool.sf[n];
534887Schin
544887Schin if(!SFFROZEN(f) && f->next > f->data &&
554887Schin (f->mode&SF_WRITE) && f->extent < 0 )
564887Schin (void)_sfflsbuf(f,-1);
574887Schin }
584887Schin }
594887Schin
604887Schin #if __STD_C
sfrd(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)618462SApril.Chin@Sun.COM ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
624887Schin #else
634887Schin ssize_t sfrd(f,buf,n,disc)
648462SApril.Chin@Sun.COM Sfio_t* f;
658462SApril.Chin@Sun.COM Void_t* buf;
668462SApril.Chin@Sun.COM size_t n;
674887Schin Sfdisc_t* disc;
684887Schin #endif
694887Schin {
704887Schin Sfoff_t r;
714887Schin reg Sfdisc_t* dc;
724887Schin reg int local, rcrv, dosync, oerrno;
738462SApril.Chin@Sun.COM SFMTXDECL(f);
744887Schin
758462SApril.Chin@Sun.COM SFMTXENTER(f,-1);
764887Schin
774887Schin GETLOCAL(f,local);
784887Schin if((rcrv = f->mode & (SF_RC|SF_RV)) )
794887Schin f->mode &= ~(SF_RC|SF_RV);
804887Schin f->bits &= ~SF_JUSTSEEK;
814887Schin
824887Schin if(f->mode&SF_PKRD)
834887Schin SFMTXRETURN(f, -1);
844887Schin
854887Schin if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
864887Schin { if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
874887Schin SFMTXRETURN(f, -1);
884887Schin if(f->next < f->endb)
894887Schin { if(SFSYNC(f) < 0)
904887Schin SFMTXRETURN(f, -1);
914887Schin if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
924887Schin { f->endb = f->next = f->endr = f->data;
934887Schin f->mode &= ~SF_SYNCED;
944887Schin }
954887Schin #ifdef MAP_TYPE
964887Schin if((f->bits&SF_MMAP) && f->data)
974887Schin { SFMUNMAP(f, f->data, f->endb-f->data);
984887Schin f->data = NIL(uchar*);
994887Schin }
1004887Schin #endif
1014887Schin f->next = f->endb = f->endr = f->endw = f->data;
1024887Schin }
1034887Schin }
1044887Schin
1054887Schin for(dosync = 0;;)
1064887Schin { /* stream locked by sfsetfd() */
1074887Schin if(!(f->flags&SF_STRING) && f->file < 0)
1084887Schin SFMTXRETURN(f, 0);
1094887Schin
1104887Schin f->flags &= ~(SF_EOF|SF_ERROR);
1114887Schin
1124887Schin dc = disc;
1134887Schin if(f->flags&SF_STRING)
1144887Schin { if((r = (f->data+f->extent) - f->next) < 0)
1154887Schin r = 0;
1164887Schin if(r <= 0)
1174887Schin goto do_except;
1184887Schin SFMTXRETURN(f, (ssize_t)r);
1194887Schin }
1204887Schin
1214887Schin /* warn that a read is about to happen */
1224887Schin SFDISC(f,dc,readf);
1234887Schin if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
1244887Schin { reg int rv;
1254887Schin if(local)
1264887Schin SETLOCAL(f);
1274887Schin if((rv = _sfexcept(f,SF_READ,n,dc)) > 0)
1284887Schin n = rv;
1294887Schin else if(rv < 0)
1304887Schin { f->flags |= SF_ERROR;
1314887Schin SFMTXRETURN(f, (ssize_t)rv);
1324887Schin }
1334887Schin }
1344887Schin
1354887Schin #ifdef MAP_TYPE
1364887Schin if(f->bits&SF_MMAP)
1374887Schin { reg ssize_t a, round;
1384887Schin sfstat_t st;
1394887Schin
1404887Schin /* determine if we have to copy data to buffer */
1414887Schin if((uchar*)buf >= f->data && (uchar*)buf <= f->endb)
1424887Schin { n += f->endb - f->next;
1434887Schin buf = NIL(char*);
1444887Schin }
1454887Schin
1464887Schin /* actual seek location */
1474887Schin if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
1484887Schin (r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here)
1494887Schin f->here = r;
1504887Schin else f->here -= f->endb-f->next;
1514887Schin
1524887Schin /* before mapping, make sure we have data to map */
1534887Schin if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n)
1544887Schin { if((r = sysfstatf(f->file,&st)) < 0)
1554887Schin goto do_except;
1564887Schin if((r = (f->extent = st.st_size) - f->here) <= 0 )
1574887Schin { r = 0; /* eof */
1584887Schin goto do_except;
1594887Schin }
1604887Schin }
1614887Schin
1624887Schin /* make sure current position is page aligned */
1634887Schin if((a = (size_t)(f->here%_Sfpage)) != 0)
1644887Schin { f->here -= a;
1654887Schin r += a;
1664887Schin }
1674887Schin
1684887Schin /* map minimal requirement */
1694887Schin if(r > (round = (1 + (n+a)/f->size)*f->size) )
1704887Schin r = round;
1714887Schin
1724887Schin if(f->data)
1734887Schin SFMUNMAP(f, f->data, f->endb-f->data);
1744887Schin
1754887Schin for(;;)
1764887Schin { f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r,
1774887Schin (PROT_READ|PROT_WRITE),
1784887Schin MAP_PRIVATE,
1794887Schin f->file, (sfoff_t)f->here);
1804887Schin if(f->data && (caddr_t)f->data != (caddr_t)(-1))
1814887Schin break;
1824887Schin else
1834887Schin { f->data = NIL(uchar*);
1844887Schin if((r >>= 1) < (_Sfpage*SF_NMAP) ||
1854887Schin (errno != EAGAIN && errno != ENOMEM) )
1864887Schin break;
1874887Schin }
1884887Schin }
1894887Schin
1904887Schin if(f->data)
1914887Schin { if(f->bits&SF_SEQUENTIAL)
1924887Schin SFMMSEQON(f,f->data,r);
1934887Schin f->next = f->data+a;
1944887Schin f->endr = f->endb = f->data+r;
1954887Schin f->endw = f->data;
1964887Schin f->here += r;
1974887Schin
1984887Schin /* make known our seek location */
1994887Schin (void)SFSK(f,f->here,SEEK_SET,dc);
2004887Schin
2014887Schin if(buf)
2024887Schin { if(n > (size_t)(r-a))
2034887Schin n = (ssize_t)(r-a);
2044887Schin memcpy(buf,f->next,n);
2054887Schin f->next += n;
2064887Schin }
2074887Schin else n = f->endb - f->next;
2084887Schin
2094887Schin SFMTXRETURN(f, n);
2104887Schin }
2114887Schin else
2124887Schin { r = -1;
2134887Schin f->here += a;
2144887Schin
2154887Schin /* reset seek pointer to its physical location */
2164887Schin (void)SFSK(f,f->here,SEEK_SET,dc);
2174887Schin
2184887Schin /* make a buffer */
2194887Schin (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
2204887Schin
2214887Schin if(!buf)
2224887Schin { buf = (Void_t*)f->data;
2234887Schin n = f->size;
2244887Schin }
2254887Schin }
2264887Schin }
2274887Schin #endif
2284887Schin
2294887Schin /* sync unseekable write streams to prevent deadlock */
2304887Schin if(!dosync && f->extent < 0)
2314887Schin { dosync = 1;
2324887Schin _sfwrsync();
2334887Schin }
2344887Schin
2354887Schin /* make sure file pointer is right */
2364887Schin if(f->extent >= 0 && (f->flags&SF_SHARE) )
2374887Schin { if(!(f->flags&SF_PUBLIC) )
2384887Schin f->here = SFSK(f,f->here,SEEK_SET,dc);
2394887Schin else f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
2404887Schin }
2414887Schin
2424887Schin oerrno = errno;
2434887Schin errno = 0;
2444887Schin
2454887Schin if(dc && dc->readf)
2464887Schin { int share = f->flags&SF_SHARE;
2474887Schin
2484887Schin if(rcrv) /* pass on rcrv for possible continuations */
2494887Schin f->mode |= rcrv;
2504887Schin /* tell readf that no peeking necessary */
2514887Schin else f->flags &= ~SF_SHARE;
2524887Schin
2534887Schin SFDCRD(f,buf,n,dc,r);
2544887Schin
2554887Schin /* reset flags */
2564887Schin if(rcrv)
2574887Schin f->mode &= ~rcrv;
2584887Schin else f->flags |= share;
2594887Schin }
2604887Schin else if(SFISNULL(f))
2614887Schin r = 0;
2624887Schin else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv)
2634887Schin { /* try peek read */
2644887Schin r = sfpkrd(f->file, (char*)buf, n,
2654887Schin (rcrv&SF_RC) ? (int)f->getr : -1,
2664887Schin -1L, (rcrv&SF_RV) ? 1 : 0);
2674887Schin if(r > 0)
2684887Schin { if(rcrv&SF_RV)
2694887Schin f->mode |= SF_PKRD;
2704887Schin else f->mode |= SF_RC;
2714887Schin }
2724887Schin }
2734887Schin else r = sysreadf(f->file,buf,n);
2744887Schin
2754887Schin if(errno == 0 )
2764887Schin errno = oerrno;
2774887Schin
2784887Schin if(r > 0 )
2794887Schin { if(!(f->bits&SF_DCDOWN) ) /* not a continuation call */
2804887Schin { if(!(f->mode&SF_PKRD) )
2814887Schin { f->here += r;
2824887Schin if(f->extent >= 0 && f->extent < f->here)
2834887Schin f->extent = f->here;
2844887Schin }
2854887Schin if((uchar*)buf >= f->data &&
2864887Schin (uchar*)buf < f->data+f->size)
2874887Schin f->endb = f->endr = ((uchar*)buf) + r;
2884887Schin }
2894887Schin
2904887Schin SFMTXRETURN(f, (ssize_t)r);
2914887Schin }
2924887Schin
2934887Schin do_except:
2944887Schin if(local)
2954887Schin SETLOCAL(f);
2964887Schin switch(_sfexcept(f,SF_READ,(ssize_t)r,dc))
2974887Schin {
2984887Schin case SF_ECONT :
2994887Schin goto do_continue;
3004887Schin case SF_EDONE :
3014887Schin n = local ? 0 : (ssize_t)r;
3024887Schin SFMTXRETURN(f,n);
3034887Schin case SF_EDISC :
3044887Schin if(!local && !(f->flags&SF_STRING))
3054887Schin goto do_continue;
3064887Schin /* else fall thru */
3074887Schin case SF_ESTACK :
3084887Schin SFMTXRETURN(f, -1);
3094887Schin }
3104887Schin
3114887Schin do_continue:
3124887Schin for(dc = f->disc; dc; dc = dc->disc)
3134887Schin if(dc == disc)
3144887Schin break;
3154887Schin disc = dc;
3164887Schin }
3174887Schin }
318