|
Packit |
992a25 |
/***********************************************************************
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* This software is part of the ast package *
|
|
Packit |
992a25 |
* Copyright (c) 1985-2011 AT&T Intellectual Property *
|
|
Packit |
992a25 |
* and is licensed under the *
|
|
Packit |
992a25 |
* Eclipse Public License, Version 1.0 *
|
|
Packit |
992a25 |
* by AT&T Intellectual Property *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* A copy of the License is available at *
|
|
Packit |
992a25 |
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
Packit |
992a25 |
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* Information and Software Systems Research *
|
|
Packit |
992a25 |
* AT&T Research *
|
|
Packit |
992a25 |
* Florham Park NJ *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* Glenn Fowler <gsf@research.att.com> *
|
|
Packit |
992a25 |
* David Korn <dgk@research.att.com> *
|
|
Packit |
992a25 |
* Phong Vo <kpv@research.att.com> *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
***********************************************************************/
|
|
Packit |
992a25 |
#include "sfhdr.h"
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* Internal function to do a hard read.
|
|
Packit |
992a25 |
** This knows about discipline and memory mapping, peek read.
|
|
Packit |
992a25 |
**
|
|
Packit |
992a25 |
** Written by Kiem-Phong Vo.
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* synchronize unseekable write streams */
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
static void _sfwrsync(void)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
static void _sfwrsync()
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{ reg Sfpool_t* p;
|
|
Packit |
992a25 |
reg Sfio_t* f;
|
|
Packit |
992a25 |
reg int n;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* sync all pool heads */
|
|
Packit |
992a25 |
for(p = _Sfpool.next; p; p = p->next)
|
|
Packit |
992a25 |
{ if(p->n_sf <= 0)
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
f = p->sf[0];
|
|
Packit |
992a25 |
if(!SFFROZEN(f) && f->next > f->data &&
|
|
Packit |
992a25 |
(f->mode&SF_WRITE) && f->extent < 0 )
|
|
Packit |
992a25 |
(void)_sfflsbuf(f,-1);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* and all the ones in the discrete pool */
|
|
Packit |
992a25 |
for(n = 0; n < _Sfpool.n_sf; ++n)
|
|
Packit |
992a25 |
{ f = _Sfpool.sf[n];
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(!SFFROZEN(f) && f->next > f->data &&
|
|
Packit |
992a25 |
(f->mode&SF_WRITE) && f->extent < 0 )
|
|
Packit |
992a25 |
(void)_sfflsbuf(f,-1);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
ssize_t sfrd(f,buf,n,disc)
|
|
Packit |
992a25 |
Sfio_t* f;
|
|
Packit |
992a25 |
Void_t* buf;
|
|
Packit |
992a25 |
size_t n;
|
|
Packit |
992a25 |
Sfdisc_t* disc;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
Sfoff_t r;
|
|
Packit |
992a25 |
reg Sfdisc_t* dc;
|
|
Packit |
992a25 |
reg int local, rcrv, dosync, oerrno;
|
|
Packit |
992a25 |
SFMTXDECL(f);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
SFMTXENTER(f,-1);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
GETLOCAL(f,local);
|
|
Packit |
992a25 |
if((rcrv = f->mode & (SF_RC|SF_RV)) )
|
|
Packit |
992a25 |
f->mode &= ~(SF_RC|SF_RV);
|
|
Packit |
992a25 |
f->bits &= ~SF_JUSTSEEK;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(f->mode&SF_PKRD)
|
|
Packit |
992a25 |
SFMTXRETURN(f, -1);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
|
|
Packit |
992a25 |
{ if(f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
|
|
Packit |
992a25 |
SFMTXRETURN(f, -1);
|
|
Packit |
992a25 |
if(f->next < f->endb)
|
|
Packit |
992a25 |
{ if(SFSYNC(f) < 0)
|
|
Packit |
992a25 |
SFMTXRETURN(f, -1);
|
|
Packit |
992a25 |
if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
|
|
Packit |
992a25 |
{ f->endb = f->next = f->endr = f->data;
|
|
Packit |
992a25 |
f->mode &= ~SF_SYNCED;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#ifdef MAP_TYPE
|
|
Packit |
992a25 |
if((f->bits&SF_MMAP) && f->data)
|
|
Packit |
992a25 |
{ SFMUNMAP(f, f->data, f->endb-f->data);
|
|
Packit |
992a25 |
f->data = NIL(uchar*);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
f->next = f->endb = f->endr = f->endw = f->data;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
for(dosync = 0;;)
|
|
Packit |
992a25 |
{ /* stream locked by sfsetfd() */
|
|
Packit |
992a25 |
if(!(f->flags&SF_STRING) && f->file < 0)
|
|
Packit |
992a25 |
SFMTXRETURN(f, 0);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
f->flags &= ~(SF_EOF|SF_ERROR);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
dc = disc;
|
|
Packit |
992a25 |
if(f->flags&SF_STRING)
|
|
Packit |
992a25 |
{ if((r = (f->data+f->extent) - f->next) < 0)
|
|
Packit |
992a25 |
r = 0;
|
|
Packit |
992a25 |
if(r <= 0)
|
|
Packit |
992a25 |
goto do_except;
|
|
Packit |
992a25 |
SFMTXRETURN(f, (ssize_t)r);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* warn that a read is about to happen */
|
|
Packit |
992a25 |
SFDISC(f,dc,readf);
|
|
Packit |
992a25 |
if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
|
|
Packit |
992a25 |
{ reg int rv;
|
|
Packit |
992a25 |
if(local)
|
|
Packit |
992a25 |
SETLOCAL(f);
|
|
Packit |
992a25 |
if((rv = _sfexcept(f,SF_READ,n,dc)) > 0)
|
|
Packit |
992a25 |
n = rv;
|
|
Packit |
992a25 |
else if(rv < 0)
|
|
Packit |
992a25 |
{ f->flags |= SF_ERROR;
|
|
Packit |
992a25 |
SFMTXRETURN(f, (ssize_t)rv);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#ifdef MAP_TYPE
|
|
Packit |
992a25 |
if(f->bits&SF_MMAP)
|
|
Packit |
992a25 |
{ reg ssize_t a, round;
|
|
Packit |
992a25 |
sfstat_t st;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* determine if we have to copy data to buffer */
|
|
Packit |
992a25 |
if((uchar*)buf >= f->data && (uchar*)buf <= f->endb)
|
|
Packit |
992a25 |
{ n += f->endb - f->next;
|
|
Packit |
992a25 |
buf = NIL(char*);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* actual seek location */
|
|
Packit |
992a25 |
if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
|
|
Packit |
992a25 |
(r = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc)) != f->here)
|
|
Packit |
992a25 |
f->here = r;
|
|
Packit |
992a25 |
else f->here -= f->endb-f->next;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* before mapping, make sure we have data to map */
|
|
Packit |
992a25 |
if((f->flags&SF_SHARE) || (size_t)(r = f->extent-f->here) < n)
|
|
Packit |
992a25 |
{ if((r = sysfstatf(f->file,&st)) < 0)
|
|
Packit |
992a25 |
goto do_except;
|
|
Packit |
992a25 |
if((r = (f->extent = st.st_size) - f->here) <= 0 )
|
|
Packit |
992a25 |
{ r = 0; /* eof */
|
|
Packit |
992a25 |
goto do_except;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* make sure current position is page aligned */
|
|
Packit |
992a25 |
if((a = (size_t)(f->here%_Sfpage)) != 0)
|
|
Packit |
992a25 |
{ f->here -= a;
|
|
Packit |
992a25 |
r += a;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* map minimal requirement */
|
|
Packit |
992a25 |
if(r > (round = (1 + (n+a)/f->size)*f->size) )
|
|
Packit |
992a25 |
r = round;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(f->data)
|
|
Packit |
992a25 |
SFMUNMAP(f, f->data, f->endb-f->data);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
for(;;)
|
|
Packit |
992a25 |
{ f->data = (uchar*) sysmmapf((caddr_t)0, (size_t)r,
|
|
Packit |
992a25 |
(PROT_READ|PROT_WRITE),
|
|
Packit |
992a25 |
MAP_PRIVATE,
|
|
Packit |
992a25 |
f->file, (sfoff_t)f->here);
|
|
Packit |
992a25 |
if(f->data && (caddr_t)f->data != (caddr_t)(-1))
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
{ f->data = NIL(uchar*);
|
|
Packit |
992a25 |
if((r >>= 1) < (_Sfpage*SF_NMAP) ||
|
|
Packit |
992a25 |
(errno != EAGAIN && errno != ENOMEM) )
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(f->data)
|
|
Packit |
992a25 |
{ if(f->bits&SF_SEQUENTIAL)
|
|
Packit |
992a25 |
SFMMSEQON(f,f->data,r);
|
|
Packit |
992a25 |
f->next = f->data+a;
|
|
Packit |
992a25 |
f->endr = f->endb = f->data+r;
|
|
Packit |
992a25 |
f->endw = f->data;
|
|
Packit |
992a25 |
f->here += r;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* make known our seek location */
|
|
Packit |
992a25 |
(void)SFSK(f,f->here,SEEK_SET,dc);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(buf)
|
|
Packit |
992a25 |
{ if(n > (size_t)(r-a))
|
|
Packit |
992a25 |
n = (ssize_t)(r-a);
|
|
Packit |
992a25 |
memcpy(buf,f->next,n);
|
|
Packit |
992a25 |
f->next += n;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else n = f->endb - f->next;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
SFMTXRETURN(f, n);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
{ r = -1;
|
|
Packit |
992a25 |
f->here += a;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* reset seek pointer to its physical location */
|
|
Packit |
992a25 |
(void)SFSK(f,f->here,SEEK_SET,dc);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* make a buffer */
|
|
Packit |
992a25 |
(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(!buf)
|
|
Packit |
992a25 |
{ buf = (Void_t*)f->data;
|
|
Packit |
992a25 |
n = f->size;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* sync unseekable write streams to prevent deadlock */
|
|
Packit |
992a25 |
if(!dosync && f->extent < 0)
|
|
Packit |
992a25 |
{ dosync = 1;
|
|
Packit |
992a25 |
_sfwrsync();
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* make sure file pointer is right */
|
|
Packit |
992a25 |
if(f->extent >= 0 && (f->flags&SF_SHARE) )
|
|
Packit |
992a25 |
{ if(!(f->flags&SF_PUBLIC) )
|
|
Packit |
992a25 |
f->here = SFSK(f,f->here,SEEK_SET,dc);
|
|
Packit |
992a25 |
else f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
oerrno = errno;
|
|
Packit |
992a25 |
errno = 0;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(dc && dc->readf)
|
|
Packit |
992a25 |
{ int share = f->flags&SF_SHARE;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(rcrv) /* pass on rcrv for possible continuations */
|
|
Packit |
992a25 |
f->mode |= rcrv;
|
|
Packit |
992a25 |
/* tell readf that no peeking necessary */
|
|
Packit |
992a25 |
else f->flags &= ~SF_SHARE;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
SFDCRD(f,buf,n,dc,r);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* reset flags */
|
|
Packit |
992a25 |
if(rcrv)
|
|
Packit |
992a25 |
f->mode &= ~rcrv;
|
|
Packit |
992a25 |
else f->flags |= share;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else if(SFISNULL(f))
|
|
Packit |
992a25 |
r = 0;
|
|
Packit |
992a25 |
else if(f->extent < 0 && (f->flags&SF_SHARE) && rcrv)
|
|
Packit |
992a25 |
{ /* try peek read */
|
|
Packit |
992a25 |
r = sfpkrd(f->file, (char*)buf, n,
|
|
Packit |
992a25 |
(rcrv&SF_RC) ? (int)f->getr : -1,
|
|
Packit |
992a25 |
-1L, (rcrv&SF_RV) ? 1 : 0);
|
|
Packit |
992a25 |
if(r > 0)
|
|
Packit |
992a25 |
{ if(rcrv&SF_RV)
|
|
Packit |
992a25 |
f->mode |= SF_PKRD;
|
|
Packit |
992a25 |
else f->mode |= SF_RC;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else r = sysreadf(f->file,buf,n);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(errno == 0 )
|
|
Packit |
992a25 |
errno = oerrno;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(r > 0 )
|
|
Packit |
992a25 |
{ if(!(f->bits&SF_DCDOWN) ) /* not a continuation call */
|
|
Packit |
992a25 |
{ if(!(f->mode&SF_PKRD) )
|
|
Packit |
992a25 |
{ f->here += r;
|
|
Packit |
992a25 |
if(f->extent >= 0 && f->extent < f->here)
|
|
Packit |
992a25 |
f->extent = f->here;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if((uchar*)buf >= f->data &&
|
|
Packit |
992a25 |
(uchar*)buf < f->data+f->size)
|
|
Packit |
992a25 |
f->endb = f->endr = ((uchar*)buf) + r;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
SFMTXRETURN(f, (ssize_t)r);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
do_except:
|
|
Packit |
992a25 |
if(local)
|
|
Packit |
992a25 |
SETLOCAL(f);
|
|
Packit |
992a25 |
switch(_sfexcept(f,SF_READ,(ssize_t)r,dc))
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
case SF_ECONT :
|
|
Packit |
992a25 |
goto do_continue;
|
|
Packit |
992a25 |
case SF_EDONE :
|
|
Packit |
992a25 |
n = local ? 0 : (ssize_t)r;
|
|
Packit |
992a25 |
SFMTXRETURN(f,n);
|
|
Packit |
992a25 |
case SF_EDISC :
|
|
Packit |
992a25 |
if(!local && !(f->flags&SF_STRING))
|
|
Packit |
992a25 |
goto do_continue;
|
|
Packit |
992a25 |
/* else fall thru */
|
|
Packit |
992a25 |
case SF_ESTACK :
|
|
Packit |
992a25 |
SFMTXRETURN(f, -1);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
do_continue:
|
|
Packit |
992a25 |
for(dc = f->disc; dc; dc = dc->disc)
|
|
Packit |
992a25 |
if(dc == disc)
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
disc = dc;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|