1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
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 /* 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