xref: /onnv-gate/usr/src/lib/libast/common/disc/sfdcseekable.c (revision 12068:08a39a083754)
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	"sfdchdr.h"
234887Schin 
244887Schin /*	Discipline to make an unseekable read stream seekable
254887Schin **
264887Schin **	sfraise(f,SFSK_DISCARD,0) discards previous seek data
274887Schin **	but seeks from current offset on still allowed
284887Schin **
294887Schin **	Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
304887Schin */
314887Schin 
324887Schin typedef struct _skable_s
334887Schin {	Sfdisc_t	disc;	/* sfio discipline */
344887Schin 	Sfio_t*		shadow;	/* to shadow data */
354887Schin 	Sfoff_t		discard;/* sfseek(f,-1,SEEK_SET) discarded data */
364887Schin 	Sfoff_t		extent; /* shadow extent */
374887Schin 	int		eof;	/* if eof has been reached */
384887Schin } Seek_t;
394887Schin 
404887Schin #if __STD_C
skwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)414887Schin static ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
424887Schin #else
434887Schin static ssize_t skwrite(f, buf, n, disc)
444887Schin Sfio_t*		f;	/* stream involved */
454887Schin Void_t*		buf;	/* buffer to read into */
464887Schin size_t		n;	/* number of bytes to read */
474887Schin Sfdisc_t*	disc;	/* discipline */
484887Schin #endif
494887Schin {
504887Schin 	return (ssize_t)(-1);
514887Schin }
524887Schin 
534887Schin #if __STD_C
skread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)544887Schin static ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
554887Schin #else
564887Schin static ssize_t skread(f, buf, n, disc)
574887Schin Sfio_t*		f;	/* stream involved */
584887Schin Void_t*		buf;	/* buffer to read into */
594887Schin size_t		n;	/* number of bytes to read */
604887Schin Sfdisc_t*	disc;	/* discipline */
614887Schin #endif
624887Schin {
634887Schin 	Seek_t*		sk;
644887Schin 	Sfio_t*		sf;
654887Schin 	Sfoff_t		addr;
664887Schin 	ssize_t		r, w, p;
674887Schin 
684887Schin 	sk = (Seek_t*)disc;
694887Schin 	sf = sk->shadow;
704887Schin 	if(sk->eof)
714887Schin 		return sfread(sf,buf,n);
724887Schin 
734887Schin 	addr = sfseek(sf,(Sfoff_t)0,SEEK_CUR);
744887Schin 
754887Schin 	if(addr+n <= sk->extent)
764887Schin 		return sfread(sf,buf,n);
774887Schin 
784887Schin 	if((r = (ssize_t)(sk->extent-addr)) > 0)
794887Schin 	{	if((w = sfread(sf,buf,r)) != r)
804887Schin 			return w;
814887Schin 		buf = (char*)buf + r;
824887Schin 		n -= r;
834887Schin 	}
844887Schin 
854887Schin 	/* do a raw read */
864887Schin 	if((w = sfrd(f,buf,n,disc)) <= 0)
874887Schin 	{	sk->eof = 1;
884887Schin 		w = 0;
894887Schin 	}
904887Schin 	else
914887Schin 	{
924887Schin 		if((p = sfwrite(sf,buf,w)) != w)
934887Schin 			sk->eof = 1;
944887Schin 		if(p > 0)
954887Schin 			sk->extent += p;
964887Schin 	}
974887Schin 
984887Schin 	return r+w;
994887Schin }
1004887Schin 
1014887Schin #if __STD_C
skseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)1024887Schin static Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
1034887Schin #else
1044887Schin static Sfoff_t skseek(f, addr, type, disc)
1054887Schin Sfio_t*		f;
1064887Schin Sfoff_t		addr;
1074887Schin int		type;
1084887Schin Sfdisc_t*	disc;
1094887Schin #endif
1104887Schin {
1114887Schin 	Seek_t*		sk;
1124887Schin 	Sfio_t*		sf;
1134887Schin 	char		buf[SF_BUFSIZE];
1144887Schin 	ssize_t		r, w;
1154887Schin 
1164887Schin 	sk = (Seek_t*)disc;
1174887Schin 	sf = sk->shadow;
1184887Schin 
1194887Schin 	switch (type)
1204887Schin 	{
1214887Schin 	case SEEK_SET:
1224887Schin 		addr -= sk->discard;
1234887Schin 		break;
1244887Schin 	case SEEK_CUR:
1254887Schin 		addr += sftell(sf);
1264887Schin 		break;
1274887Schin 	case SEEK_END:
1284887Schin 		addr += sk->extent;
1294887Schin 		break;
1304887Schin 	default:
1314887Schin 		return -1;
1324887Schin 	}
1334887Schin 
1344887Schin 	if(addr < 0)
1354887Schin 		return (Sfoff_t)(-1);
1364887Schin 	else if(addr > sk->extent)
1374887Schin 	{	if(sk->eof)
1384887Schin 			return (Sfoff_t)(-1);
1394887Schin 
1404887Schin 		/* read enough to reach the seek point */
1414887Schin 		while(addr > sk->extent)
1424887Schin 		{	if(addr > sk->extent+sizeof(buf) )
1434887Schin 				w = sizeof(buf);
1444887Schin 			else	w = (int)(addr-sk->extent);
1454887Schin 			if((r = sfrd(f,buf,w,disc)) <= 0)
1464887Schin 				w = r-1;
1474887Schin 			else if((w = sfwrite(sf,buf,r)) > 0)
1484887Schin 				sk->extent += w;
1494887Schin 			if(w != r)
1504887Schin 			{	sk->eof = 1;
1514887Schin 				break;
1524887Schin 			}
1534887Schin 		}
1544887Schin 
1554887Schin 		if(addr > sk->extent)
1564887Schin 			return (Sfoff_t)(-1);
1574887Schin 	}
1584887Schin 
1594887Schin 	return sfseek(sf,addr,SEEK_SET) + sk->discard;
1604887Schin }
1614887Schin 
1624887Schin /* on close, remove the discipline */
1634887Schin #if __STD_C
skexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)1644887Schin static int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
1654887Schin #else
1664887Schin static int skexcept(f,type,data,disc)
1674887Schin Sfio_t*		f;
1684887Schin int		type;
1694887Schin Void_t*		data;
1704887Schin Sfdisc_t*	disc;
1714887Schin #endif
1724887Schin {
1734887Schin 	Seek_t*		sk;
1744887Schin 
1754887Schin 	sk = (Seek_t*)disc;
1764887Schin 
1774887Schin 	switch (type)
1784887Schin 	{
1794887Schin 	case SF_FINAL:
1804887Schin 	case SF_DPOP:
1814887Schin 		sfclose(sk->shadow);
1824887Schin 		free(disc);
1834887Schin 		break;
1844887Schin 	case SFSK_DISCARD:
1854887Schin 		sk->eof = 0;
1864887Schin 		sk->discard += sk->extent;
1874887Schin 		sk->extent = 0;
1884887Schin 		sfseek(sk->shadow,(Sfoff_t)0,SEEK_SET);
1894887Schin 		break;
1904887Schin 	}
1914887Schin 	return 0;
1924887Schin }
1934887Schin 
1944887Schin #if __STD_C
sfdcseekable(Sfio_t * f)1954887Schin int sfdcseekable(Sfio_t* f)
1964887Schin #else
1974887Schin int sfdcseekable(f)
1984887Schin Sfio_t*	f;
1994887Schin #endif
2004887Schin {
2014887Schin 	reg Seek_t*	sk;
2024887Schin 
2034887Schin 	/* see if already seekable */
2044887Schin 	if(sfseek(f,(Sfoff_t)0,SEEK_CUR) >= 0)
2054887Schin 		return 0;
2064887Schin 
2074887Schin 	if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) )
2084887Schin 		return -1;
2094887Schin 	memset(sk, 0, sizeof(*sk));
2104887Schin 
2114887Schin 	sk->disc.readf = skread;
2124887Schin 	sk->disc.writef = skwrite;
2134887Schin 	sk->disc.seekf = skseek;
2144887Schin 	sk->disc.exceptf = skexcept;
2154887Schin 	sk->shadow = sftmp(SF_BUFSIZE);
2164887Schin 	sk->discard = 0;
2174887Schin 	sk->extent = 0;
2184887Schin 	sk->eof = 0;
2194887Schin 
2204887Schin 	if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk)
2214887Schin 	{	sfclose(sk->shadow);
2224887Schin 		free(sk);
2234887Schin 		return -1;
2244887Schin 	}
2254887Schin 
2264887Schin 	return 0;
2274887Schin }
228