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 /* Discipline to make an unseekable read stream seekable
25 **
26 ** sfraise(f,SFSK_DISCARD,0) discards previous seek data
27 ** but seeks from current offset on still allowed
28 **
29 ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
30 */
31
32 typedef struct _skable_s
33 { Sfdisc_t disc; /* sfio discipline */
34 Sfio_t* shadow; /* to shadow data */
35 Sfoff_t discard;/* sfseek(f,-1,SEEK_SET) discarded data */
36 Sfoff_t extent; /* shadow extent */
37 int eof; /* if eof has been reached */
38 } Seek_t;
39
40 #if __STD_C
skwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)41 static ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
42 #else
43 static ssize_t skwrite(f, buf, n, disc)
44 Sfio_t* f; /* stream involved */
45 Void_t* buf; /* buffer to read into */
46 size_t n; /* number of bytes to read */
47 Sfdisc_t* disc; /* discipline */
48 #endif
49 {
50 return (ssize_t)(-1);
51 }
52
53 #if __STD_C
skread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)54 static ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
55 #else
56 static ssize_t skread(f, buf, n, disc)
57 Sfio_t* f; /* stream involved */
58 Void_t* buf; /* buffer to read into */
59 size_t n; /* number of bytes to read */
60 Sfdisc_t* disc; /* discipline */
61 #endif
62 {
63 Seek_t* sk;
64 Sfio_t* sf;
65 Sfoff_t addr;
66 ssize_t r, w, p;
67
68 sk = (Seek_t*)disc;
69 sf = sk->shadow;
70 if(sk->eof)
71 return sfread(sf,buf,n);
72
73 addr = sfseek(sf,(Sfoff_t)0,SEEK_CUR);
74
75 if(addr+n <= sk->extent)
76 return sfread(sf,buf,n);
77
78 if((r = (ssize_t)(sk->extent-addr)) > 0)
79 { if((w = sfread(sf,buf,r)) != r)
80 return w;
81 buf = (char*)buf + r;
82 n -= r;
83 }
84
85 /* do a raw read */
86 if((w = sfrd(f,buf,n,disc)) <= 0)
87 { sk->eof = 1;
88 w = 0;
89 }
90 else
91 {
92 if((p = sfwrite(sf,buf,w)) != w)
93 sk->eof = 1;
94 if(p > 0)
95 sk->extent += p;
96 }
97
98 return r+w;
99 }
100
101 #if __STD_C
skseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)102 static Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
103 #else
104 static Sfoff_t skseek(f, addr, type, disc)
105 Sfio_t* f;
106 Sfoff_t addr;
107 int type;
108 Sfdisc_t* disc;
109 #endif
110 {
111 Seek_t* sk;
112 Sfio_t* sf;
113 char buf[SF_BUFSIZE];
114 ssize_t r, w;
115
116 sk = (Seek_t*)disc;
117 sf = sk->shadow;
118
119 switch (type)
120 {
121 case SEEK_SET:
122 addr -= sk->discard;
123 break;
124 case SEEK_CUR:
125 addr += sftell(sf);
126 break;
127 case SEEK_END:
128 addr += sk->extent;
129 break;
130 default:
131 return -1;
132 }
133
134 if(addr < 0)
135 return (Sfoff_t)(-1);
136 else if(addr > sk->extent)
137 { if(sk->eof)
138 return (Sfoff_t)(-1);
139
140 /* read enough to reach the seek point */
141 while(addr > sk->extent)
142 { if(addr > sk->extent+sizeof(buf) )
143 w = sizeof(buf);
144 else w = (int)(addr-sk->extent);
145 if((r = sfrd(f,buf,w,disc)) <= 0)
146 w = r-1;
147 else if((w = sfwrite(sf,buf,r)) > 0)
148 sk->extent += w;
149 if(w != r)
150 { sk->eof = 1;
151 break;
152 }
153 }
154
155 if(addr > sk->extent)
156 return (Sfoff_t)(-1);
157 }
158
159 return sfseek(sf,addr,SEEK_SET) + sk->discard;
160 }
161
162 /* on close, remove the discipline */
163 #if __STD_C
skexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)164 static int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
165 #else
166 static int skexcept(f,type,data,disc)
167 Sfio_t* f;
168 int type;
169 Void_t* data;
170 Sfdisc_t* disc;
171 #endif
172 {
173 Seek_t* sk;
174
175 sk = (Seek_t*)disc;
176
177 switch (type)
178 {
179 case SF_FINAL:
180 case SF_DPOP:
181 sfclose(sk->shadow);
182 free(disc);
183 break;
184 case SFSK_DISCARD:
185 sk->eof = 0;
186 sk->discard += sk->extent;
187 sk->extent = 0;
188 sfseek(sk->shadow,(Sfoff_t)0,SEEK_SET);
189 break;
190 }
191 return 0;
192 }
193
194 #if __STD_C
sfdcseekable(Sfio_t * f)195 int sfdcseekable(Sfio_t* f)
196 #else
197 int sfdcseekable(f)
198 Sfio_t* f;
199 #endif
200 {
201 reg Seek_t* sk;
202
203 /* see if already seekable */
204 if(sfseek(f,(Sfoff_t)0,SEEK_CUR) >= 0)
205 return 0;
206
207 if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) )
208 return -1;
209 memset(sk, 0, sizeof(*sk));
210
211 sk->disc.readf = skread;
212 sk->disc.writef = skwrite;
213 sk->disc.seekf = skseek;
214 sk->disc.exceptf = skexcept;
215 sk->shadow = sftmp(SF_BUFSIZE);
216 sk->discard = 0;
217 sk->extent = 0;
218 sk->eof = 0;
219
220 if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk)
221 { sfclose(sk->shadow);
222 free(sk);
223 return -1;
224 }
225
226 return 0;
227 }
228