xref: /titanic_51/usr/src/lib/libast/common/disc/sfdcseekable.c (revision 4201a95e0468170d576f82c3aa63afecf718497a)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2009 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
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
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
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
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
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