xref: /onnv-gate/usr/src/lib/libast/common/disc/sfdcunion.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 
254887Schin /*	Make a sequence of streams act like a single stream.
264887Schin **	This is for reading only.
274887Schin **
284887Schin **	Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
294887Schin */
304887Schin 
314887Schin #define	UNSEEKABLE	1
324887Schin 
334887Schin typedef struct _file_s
344887Schin {	Sfio_t*	f;	/* the stream		*/
354887Schin 	Sfoff_t	lower;	/* its lowest end	*/
364887Schin } File_t;
374887Schin 
384887Schin typedef struct _union_s
394887Schin {
404887Schin 	Sfdisc_t	disc;	/* discipline structure */
414887Schin 	short		type;	/* type of streams	*/
424887Schin 	short		c;	/* current stream	*/
434887Schin 	short		n;	/* number of streams	*/
444887Schin 	Sfoff_t		here;	/* current location	*/
454887Schin 	File_t		f[1];	/* array of streams	*/
464887Schin } Union_t;
474887Schin 
484887Schin #if __STD_C
unwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)494887Schin static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
504887Schin #else
514887Schin static ssize_t unwrite(f, buf, n, disc)
524887Schin Sfio_t*        f;      /* stream involved */
534887Schin Void_t*        buf;    /* buffer to read into */
544887Schin size_t         n;      /* number of bytes to read */
554887Schin Sfdisc_t*      disc;   /* discipline */
564887Schin #endif
574887Schin {
584887Schin 	return -1;
594887Schin }
604887Schin 
614887Schin #if __STD_C
unread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)624887Schin static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
634887Schin #else
644887Schin static ssize_t unread(f, buf, n, disc)
654887Schin Sfio_t*        f;      /* stream involved */
664887Schin Void_t*        buf;    /* buffer to read into */
674887Schin size_t         n;      /* number of bytes to read */
684887Schin Sfdisc_t*      disc;   /* discipline */
694887Schin #endif
704887Schin {
714887Schin 	reg Union_t*	un;
724887Schin 	reg ssize_t	r, m;
734887Schin 
744887Schin 	un = (Union_t*)disc;
754887Schin 	m = n;
764887Schin 	f = un->f[un->c].f;
774887Schin 	while(1)
784887Schin 	{	if((r = sfread(f,buf,m)) < 0 || (r == 0 && un->c == un->n-1) )
794887Schin 			break;
804887Schin 
814887Schin 		m -= r;
824887Schin 		un->here += r;
834887Schin 
844887Schin 		if(m == 0)
854887Schin 			break;
864887Schin 
874887Schin 		buf = (char*)buf + r;
884887Schin 		if(sfeof(f) && un->c < un->n-1)
894887Schin 			f = un->f[un->c += 1].f;
904887Schin 	}
914887Schin 	return n-m;
924887Schin }
934887Schin 
944887Schin #if __STD_C
unseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)954887Schin static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
964887Schin #else
974887Schin static Sfoff_t unseek(f, addr, type, disc)
984887Schin Sfio_t*        f;
994887Schin Sfoff_t        addr;
1004887Schin int            type;
1014887Schin Sfdisc_t*      disc;
1024887Schin #endif
1034887Schin {
1044887Schin 	reg Union_t*	un;
1054887Schin 	reg int		i;
1064887Schin 	reg Sfoff_t	extent, s;
1074887Schin 
1084887Schin 	un = (Union_t*)disc;
1094887Schin 	if(un->type&UNSEEKABLE)
1104887Schin 		return -1L;
1114887Schin 
1124887Schin 	if(type == 2)
1134887Schin 	{	extent = 0;
1144887Schin 		for(i = 0; i < un->n; ++i)
1154887Schin 			extent += (sfsize(un->f[i].f) - un->f[i].lower);
1164887Schin 		addr += extent;
1174887Schin 	}
1184887Schin 	else if(type == 1)
1194887Schin 		addr += un->here;
1204887Schin 
1214887Schin 	if(addr < 0)
1224887Schin 		return -1;
1234887Schin 
1244887Schin 	/* find the stream where the addr could be in */
1254887Schin 	extent = 0;
1264887Schin 	for(i = 0; i < un->n-1; ++i)
1274887Schin 	{	s = sfsize(un->f[i].f) - un->f[i].lower;
1284887Schin 		if(addr < extent + s)
1294887Schin 			break;
1304887Schin 		extent += s;
1314887Schin 	}
1324887Schin 
1334887Schin 	s = (addr-extent) + un->f[i].lower;
1344887Schin 	if(sfseek(un->f[i].f,s,0) != s)
1354887Schin 		return -1;
1364887Schin 
1374887Schin 	un->c = i;
1384887Schin 	un->here = addr;
1394887Schin 
1404887Schin 	for(i += 1; i < un->n; ++i)
1414887Schin 		sfseek(un->f[i].f,un->f[i].lower,0);
1424887Schin 
1434887Schin 	return addr;
1444887Schin }
1454887Schin 
1464887Schin /* on close, remove the discipline */
1474887Schin #if __STD_C
unexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)1484887Schin static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
1494887Schin #else
1504887Schin static int unexcept(f,type,data,disc)
1514887Schin Sfio_t*		f;
1524887Schin int		type;
1534887Schin Void_t*		data;
1544887Schin Sfdisc_t*	disc;
1554887Schin #endif
1564887Schin {
1574887Schin 	if(type == SF_FINAL || type == SF_DPOP)
1584887Schin 		free(disc);
1594887Schin 
1604887Schin 	return 0;
1614887Schin }
1624887Schin 
1634887Schin #if __STD_C
sfdcunion(Sfio_t * f,Sfio_t ** array,int n)1644887Schin int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
1654887Schin #else
1664887Schin int sfdcunion(f, array, n)
1674887Schin Sfio_t*		f;
1684887Schin Sfio_t**	array;
1694887Schin int		n;
1704887Schin #endif
1714887Schin {
1724887Schin 	reg Union_t*	un;
1734887Schin 	reg int		i;
1744887Schin 
1754887Schin 	if(n <= 0)
1764887Schin 		return -1;
1774887Schin 
1784887Schin 	if(!(un = (Union_t*)malloc(sizeof(Union_t)+(n-1)*sizeof(File_t))) )
1794887Schin 		return -1;
1804887Schin 	memset(un, 0, sizeof(*un));
1814887Schin 
1824887Schin 	un->disc.readf = unread;
1834887Schin 	un->disc.writef = unwrite;
1844887Schin 	un->disc.seekf = unseek;
1854887Schin 	un->disc.exceptf = unexcept;
1864887Schin 	un->n = n;
1874887Schin 
1884887Schin 	for(i = 0; i < n; ++i)
1894887Schin 	{	un->f[i].f = array[i];
1904887Schin 		if(!(un->type&UNSEEKABLE))
1914887Schin 		{	un->f[i].lower = sfseek(array[i],(Sfoff_t)0,1);
1924887Schin 			if(un->f[i].lower < 0)
1934887Schin 				un->type |= UNSEEKABLE;
1944887Schin 		}
1954887Schin 	}
1964887Schin 
1974887Schin 	if(sfdisc(f,(Sfdisc_t*)un) != (Sfdisc_t*)un)
1984887Schin 	{	free(un);
1994887Schin 		return -1;
2004887Schin 	}
2014887Schin 
2024887Schin 	return 0;
2034887Schin }
204