xref: /titanic_44/usr/src/lib/libast/common/disc/sfdcunion.c (revision 4a634bb80136cc001d14ab96addd9915105e5223)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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	"sfdchdr.h"
23 
24 
25 /*	Make a sequence of streams act like a single stream.
26 **	This is for reading only.
27 **
28 **	Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
29 */
30 
31 #define	UNSEEKABLE	1
32 
33 typedef struct _file_s
34 {	Sfio_t*	f;	/* the stream		*/
35 	Sfoff_t	lower;	/* its lowest end	*/
36 } File_t;
37 
38 typedef struct _union_s
39 {
40 	Sfdisc_t	disc;	/* discipline structure */
41 	short		type;	/* type of streams	*/
42 	short		c;	/* current stream	*/
43 	short		n;	/* number of streams	*/
44 	Sfoff_t		here;	/* current location	*/
45 	File_t		f[1];	/* array of streams	*/
46 } Union_t;
47 
48 #if __STD_C
49 static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
50 #else
51 static ssize_t unwrite(f, buf, n, disc)
52 Sfio_t*        f;      /* stream involved */
53 Void_t*        buf;    /* buffer to read into */
54 size_t         n;      /* number of bytes to read */
55 Sfdisc_t*      disc;   /* discipline */
56 #endif
57 {
58 	return -1;
59 }
60 
61 #if __STD_C
62 static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
63 #else
64 static ssize_t unread(f, buf, n, disc)
65 Sfio_t*        f;      /* stream involved */
66 Void_t*        buf;    /* buffer to read into */
67 size_t         n;      /* number of bytes to read */
68 Sfdisc_t*      disc;   /* discipline */
69 #endif
70 {
71 	reg Union_t*	un;
72 	reg ssize_t	r, m;
73 
74 	un = (Union_t*)disc;
75 	m = n;
76 	f = un->f[un->c].f;
77 	while(1)
78 	{	if((r = sfread(f,buf,m)) < 0 || (r == 0 && un->c == un->n-1) )
79 			break;
80 
81 		m -= r;
82 		un->here += r;
83 
84 		if(m == 0)
85 			break;
86 
87 		buf = (char*)buf + r;
88 		if(sfeof(f) && un->c < un->n-1)
89 			f = un->f[un->c += 1].f;
90 	}
91 	return n-m;
92 }
93 
94 #if __STD_C
95 static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
96 #else
97 static Sfoff_t unseek(f, addr, type, disc)
98 Sfio_t*        f;
99 Sfoff_t        addr;
100 int            type;
101 Sfdisc_t*      disc;
102 #endif
103 {
104 	reg Union_t*	un;
105 	reg int		i;
106 	reg Sfoff_t	extent, s;
107 
108 	un = (Union_t*)disc;
109 	if(un->type&UNSEEKABLE)
110 		return -1L;
111 
112 	if(type == 2)
113 	{	extent = 0;
114 		for(i = 0; i < un->n; ++i)
115 			extent += (sfsize(un->f[i].f) - un->f[i].lower);
116 		addr += extent;
117 	}
118 	else if(type == 1)
119 		addr += un->here;
120 
121 	if(addr < 0)
122 		return -1;
123 
124 	/* find the stream where the addr could be in */
125 	extent = 0;
126 	for(i = 0; i < un->n-1; ++i)
127 	{	s = sfsize(un->f[i].f) - un->f[i].lower;
128 		if(addr < extent + s)
129 			break;
130 		extent += s;
131 	}
132 
133 	s = (addr-extent) + un->f[i].lower;
134 	if(sfseek(un->f[i].f,s,0) != s)
135 		return -1;
136 
137 	un->c = i;
138 	un->here = addr;
139 
140 	for(i += 1; i < un->n; ++i)
141 		sfseek(un->f[i].f,un->f[i].lower,0);
142 
143 	return addr;
144 }
145 
146 /* on close, remove the discipline */
147 #if __STD_C
148 static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
149 #else
150 static int unexcept(f,type,data,disc)
151 Sfio_t*		f;
152 int		type;
153 Void_t*		data;
154 Sfdisc_t*	disc;
155 #endif
156 {
157 	if(type == SF_FINAL || type == SF_DPOP)
158 		free(disc);
159 
160 	return 0;
161 }
162 
163 #if __STD_C
164 int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
165 #else
166 int sfdcunion(f, array, n)
167 Sfio_t*		f;
168 Sfio_t**	array;
169 int		n;
170 #endif
171 {
172 	reg Union_t*	un;
173 	reg int		i;
174 
175 	if(n <= 0)
176 		return -1;
177 
178 	if(!(un = (Union_t*)malloc(sizeof(Union_t)+(n-1)*sizeof(File_t))) )
179 		return -1;
180 	memset(un, 0, sizeof(*un));
181 
182 	un->disc.readf = unread;
183 	un->disc.writef = unwrite;
184 	un->disc.seekf = unseek;
185 	un->disc.exceptf = unexcept;
186 	un->n = n;
187 
188 	for(i = 0; i < n; ++i)
189 	{	un->f[i].f = array[i];
190 		if(!(un->type&UNSEEKABLE))
191 		{	un->f[i].lower = sfseek(array[i],(Sfoff_t)0,1);
192 			if(un->f[i].lower < 0)
193 				un->type |= UNSEEKABLE;
194 		}
195 	}
196 
197 	if(sfdisc(f,(Sfdisc_t*)un) != (Sfdisc_t*)un)
198 	{	free(un);
199 		return -1;
200 	}
201 
202 	return 0;
203 }
204