1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 /*	Discipline to treat a contiguous segment of a stream as a stream
26 **	in its own right. The hard part in all this is to allow multiple
27 **	segments of the stream to be used as substreams at the same time.
28 **
29 **	Written by David G. Korn and Kiem-Phong Vo (03/18/1998)
30 */
31 
32 typedef struct _subfile_s
33 {
34 	Sfdisc_t	disc;	/* sfio discipline */
35 	Sfio_t*		parent;	/* parent stream */
36 	Sfoff_t		offset;	/* starting offset */
37 	Sfoff_t		extent;	/* size wanted */
38 	Sfoff_t		here;	/* current seek location */
39 } Subfile_t;
40 
41 #if __STD_C
streamio(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc,int type)42 static ssize_t streamio(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc, int type)
43 #else
44 static ssize_t streamio(f, buf, n, disc, type)
45 Sfio_t*		f;
46 Void_t*		buf;
47 size_t		n;
48 Sfdisc_t*	disc;
49 int		type;
50 #endif
51 {
52 	reg Subfile_t	*su;
53 	reg Sfoff_t	here, parent;
54 	reg ssize_t	io;
55 
56 	su = (Subfile_t*)disc;
57 
58 	/* read just what we need */
59 	if(su->extent >= 0 && (ssize_t)n > (io = (ssize_t)(su->extent - su->here)) )
60 		n = io;
61 	if(n <= 0)
62 		return n;
63 
64 	/* save current location in parent stream */
65 	parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
66 
67 	/* read data */
68 	here = su->here + su->offset;
69 	if(sfsk(f,here,SEEK_SET,disc) != here)
70 		io = 0;
71 	else
72 	{	if(type == SF_WRITE)
73 			io = sfwr(f,buf,n,disc);
74 		else	io = sfrd(f,buf,n,disc);
75 		if(io > 0)
76 			su->here += io;
77 	}
78 
79 	/* restore parent current position */
80 	sfsk(f,parent,SEEK_SET,disc);
81 
82 	return io;
83 }
84 
85 #if __STD_C
streamwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)86 static ssize_t streamwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
87 #else
88 static ssize_t streamwrite(f, buf, n, disc)
89 Sfio_t*		f;
90 Void_t*		buf;
91 size_t		n;
92 Sfdisc_t*	disc;
93 #endif
94 {
95 	return streamio(f,(Void_t*)buf,n,disc,SF_WRITE);
96 }
97 
98 #if __STD_C
streamread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)99 static ssize_t streamread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
100 #else
101 static ssize_t streamread(f, buf, n, disc)
102 Sfio_t*		f;
103 Void_t*		buf;
104 size_t		n;
105 Sfdisc_t*	disc;
106 #endif
107 {
108 	return streamio(f,buf,n,disc,SF_READ);
109 }
110 
111 #if __STD_C
streamseek(Sfio_t * f,Sfoff_t pos,int type,Sfdisc_t * disc)112 static Sfoff_t streamseek(Sfio_t* f, Sfoff_t pos, int type, Sfdisc_t* disc)
113 #else
114 static Sfoff_t streamseek(f, pos, type, disc)
115 Sfio_t*		f;
116 Sfoff_t		pos;
117 int		type;
118 Sfdisc_t*	disc;
119 #endif
120 {
121 	reg Subfile_t*	su;
122 	reg Sfoff_t	here, parent;
123 
124 	su = (Subfile_t*)disc;
125 
126 	switch(type)
127 	{
128 	case SEEK_SET:
129 		here = 0;
130 		break;
131 	case SEEK_CUR:
132 		here = su->here;
133 		break;
134 	case SEEK_END:
135 		if(su->extent >= 0)
136 			here = su->extent;
137 		else
138 		{	parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
139 			if((here = sfsk(f,(Sfoff_t)0,SEEK_END,disc)) < 0)
140 				return -1;
141 			else	here -= su->offset;
142 			sfsk(f,parent,SEEK_SET,disc);
143 		}
144 		break;
145 	default:
146 		return -1;
147 	}
148 
149 	pos += here;
150 	if(pos < 0 || (su->extent >= 0 && pos >= su->extent))
151 		return -1;
152 
153 	return (su->here = pos);
154 }
155 
156 #if __STD_C
streamexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)157 static int streamexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
158 #else
159 static int streamexcept(f, type, data, disc)
160 Sfio_t*		f;
161 int		type;
162 Void_t*		data;
163 Sfdisc_t*	disc;
164 #endif
165 {
166 	if(type == SF_FINAL || type == SF_DPOP)
167 		free(disc);
168 	return 0;
169 }
170 
171 #if __STD_C
sfdcsubstream(Sfio_t * f,Sfio_t * parent,Sfoff_t offset,Sfoff_t extent)172 Sfio_t* sfdcsubstream(Sfio_t* f, Sfio_t* parent, Sfoff_t offset, Sfoff_t extent)
173 #else
174 Sfio_t* sfdcsubstream(f, parent, offset, extent)
175 Sfio_t*	f;	/* stream */
176 Sfio_t*	parent;	/* parent stream */
177 Sfoff_t	offset;	/* offset in f */
178 Sfoff_t	extent;	/* desired size */
179 #endif
180 {
181 	reg Sfio_t*	sp;
182 	reg Subfile_t*	su;
183 	reg Sfoff_t	here;
184 
185 	/* establish that we can seek to offset */
186 	if((here = sfseek(parent,(Sfoff_t)0,SEEK_CUR)) < 0 || sfseek(parent,offset,SEEK_SET) < 0)
187 		return 0;
188 	else	sfseek(parent,here,SEEK_SET);
189 	sfpurge(parent);
190 
191 	if (!(sp = f) && !(sp = sfnew(NIL(Sfio_t*), NIL(Void_t*), (size_t)SF_UNBOUND, dup(sffileno(parent)), parent->flags)))
192 		return 0;
193 
194 	if(!(su = (Subfile_t*)malloc(sizeof(Subfile_t))))
195 	{	if(sp != f)
196 			sfclose(sp);
197 		return 0;
198 	}
199 	memset(su, 0, sizeof(*su));
200 
201 	su->disc.readf = streamread;
202 	su->disc.writef = streamwrite;
203 	su->disc.seekf = streamseek;
204 	su->disc.exceptf = streamexcept;
205 	su->parent = parent;
206 	su->offset = offset;
207 	su->extent = extent;
208 
209 	if(sfdisc(sp, (Sfdisc_t*)su) != (Sfdisc_t*)su)
210 	{	free(su);
211 		if(sp != f)
212 			sfclose(sp);
213 		return 0;
214 	}
215 
216 	return sp;
217 }
218