1 /***********************************************************************
2 *                                                                      *
3 *              This software is part of the zlib package               *
4 *       Copyright (c) 1995-2009 Jean-loup Gailly and Mark Adler        *
5 *                                                                      *
6 * This software is provided 'as-is', without any express or implied    *
7 * warranty. In no event will the authors be held liable for any        *
8 * damages arising from the use of this software.                       *
9 *                                                                      *
10 * Permission is granted to anyone to use this software for any         *
11 * purpose, including commercial applications, and to alter it and      *
12 * redistribute it freely, subject to the following restrictions:       *
13 *                                                                      *
14 *  1. The origin of this software must not be misrepresented;          *
15 *     you must not claim that you wrote the original software. If      *
16 *     you use this software in a product, an acknowledgment in the     *
17 *     product documentation would be appreciated but is not            *
18 *     required.                                                        *
19 *                                                                      *
20 *  2. Altered source versions must be plainly marked as such,          *
21 *     and must not be misrepresented as being the original             *
22 *     software.                                                        *
23 *                                                                      *
24 *  3. This notice may not be removed or altered from any source        *
25 *     distribution.                                                    *
26 *                                                                      *
27 * This software is provided "as-is", without any express or implied    *
28 * warranty. In no event will the authors be held liable for any damages*
29 * arising from the use of this software.                               *
30 *                                                                      *
31 * Permission is granted to anyone to use this software for any purpose,*
32 * including commercial applications, and to alter it and redistribute i*
33 * freely, subject to the following restrictions:                       *
34 *                                                                      *
35 * 1. The origin of this software must not be misrepresented; you must n*
36 *    claim that you wrote the original software. If you use this softwa*
37 *    in a product, an acknowledgment in the product documentation would*
38 *    be appreciated but is not required.                               *
39 *                                                                      *
40 * 2. Altered source versions must be plainly marked as such, and must n*
41 *    be misrepresented as being the original software.                 *
42 *                                                                      *
43 * 3. This notice may not be removed or altered from any source         *
44 *    distribution.                                                     *
45 *                                                                      *
46 *                           Jean-loup Gailly                           *
47 *                              Mark Adler                              *
48 *                                                                      *
49 ***********************************************************************/
50 #pragma prototyped
51 
52 /*
53  * sfio gzip discipline
54  *
55  * handles { gzip compress vczip } on input
56  * handles { gzip compress } on output
57  */
58 
59 #include <sfio_t.h>
60 #include <ast.h>
61 #include <zlib.h>
62 #include <sfdcgzip.h>
63 
64 #ifdef z_off64_t
65 #undef	z_off_t
66 #define z_off_t		z_off64_t
67 #undef	gzsync
68 #define gzsync		gzsync64
69 #endif
70 
71 typedef struct
72 {
73 	Sfdisc_t	disc;		/* sfio discipline		*/
74 	gzFile*		gz;		/* gz handle			*/
75 	Sfio_t*		op;		/* original stream		*/
76 } Sfgzip_t;
77 
78 /*
79  * gzip exception handler
80  * free on close
81  */
82 
83 static int
sfgzexcept(Sfio_t * sp,int op,void * val,Sfdisc_t * dp)84 sfgzexcept(Sfio_t* sp, int op, void* val, Sfdisc_t* dp)
85 {
86 	register Sfgzip_t*	gz = (Sfgzip_t*)dp;
87 	int			f;
88 	int			r;
89 
90 	NoP(sp);
91 #if 0
92 	{
93 		static char	aha[] = "AHA sfdcgzip event 0\n";
94 		static int	init;
95 
96 		if (!init)
97 			init = getenv("SFGZ_DEBUG") ? 1 : -1;
98 		if (init > 0)
99 		{
100 			aha[sizeof(aha) - 3] = '0' + op;
101 			write(2, aha, sizeof(aha) - 1);
102 		}
103 	}
104 #endif
105 	switch (op)
106 	{
107 	case SF_ATEXIT:
108 		sfdisc(sp, SF_POPDISC);
109 		return 0;
110 	case SF_CLOSING:
111 	case SF_DPOP:
112 	case SF_FINAL:
113 		if (gz->gz)
114 		{
115 			SFDCNEXT(sp, f);
116 			if (r = gzclose(gz->gz) ? -1 : 0)
117 				sp->_flags |= SF_ERROR;
118 			gz->gz = 0;
119 			SFDCPREV(sp, f);
120 		}
121 		else
122 			r = 0;
123 		if (gz->op)
124 		{
125 			sfclose(gz->op);
126 			gz->op = 0;
127 		}
128 		if (op != SF_CLOSING)
129 			free(dp);
130 		return r;
131 	case SF_DBUFFER:
132 		return 1;
133 	case SF_SYNC:
134 		if (!val && gzsync(gz->gz, (z_off_t)(-1)) < 0)
135 			sp->_flags |= SF_ERROR;
136 		return 0;
137 	case SFGZ_HANDLE:
138 		return (*((gzFile**)val) = gz->gz) ? 1 : -1;
139 	case SFGZ_GETPOS:
140 		return (*((Sfoff_t*)val) = gzsync(gz->gz, (z_off_t)(-1))) < 0 ? -1 : 0;
141 	case SFGZ_SETPOS:
142 		return gzsync(gz->gz, (z_off_t)(*((Sfoff_t*)val))) < 0 ? -1 : 0;
143 	}
144 	return 0;
145 }
146 
147 /*
148  * sfio gzip discipline seek
149  */
150 
151 static Sfoff_t
sfgzseek(Sfio_t * fp,Sfoff_t off,int op,Sfdisc_t * dp)152 sfgzseek(Sfio_t* fp, Sfoff_t off, int op, Sfdisc_t* dp)
153 {
154 	return sfsk(fp, off, op, dp);
155 }
156 
157 /*
158  * sfio gzip discipline read
159  */
160 
161 static ssize_t
sfgzread(Sfio_t * fp,Void_t * buf,size_t size,Sfdisc_t * dp)162 sfgzread(Sfio_t* fp, Void_t* buf, size_t size, Sfdisc_t* dp)
163 {
164 	register Sfgzip_t*	gz = (Sfgzip_t*)dp;
165 
166 	return gzread(gz->gz, buf, size);
167 }
168 
169 /*
170  * sfio gzip discipline write
171  */
172 
173 static ssize_t
sfgzwrite(Sfio_t * fp,const Void_t * buf,size_t size,Sfdisc_t * dp)174 sfgzwrite(Sfio_t* fp, const Void_t* buf, size_t size, Sfdisc_t* dp)
175 {
176 	register Sfgzip_t*	gz = (Sfgzip_t*)dp;
177 
178 	return gzwrite(gz->gz, (void*)buf, size);
179 }
180 
181 /*
182  * create and push the sfio gzip discipline
183  *
184  * (flags&SFGZ_VERIFY) return
185  *	>0	is a { g:gzip c:compress v:vczip } file
186  *	 0	not a { gzip compress vczip } file
187  *	<0	error
188  * otherwise return
189  *	>0	discipline pushed { g:gzip c:compress v:vczip }
190  *	 0	discipline not needed
191  *	<0	error
192  */
193 
194 #undef	PRIVATE
195 #define PRIVATE	0
196 
197 int
sfdcgzip(Sfio_t * sp,int flags)198 sfdcgzip(Sfio_t* sp, int flags)
199 {
200 	char*		m;
201 	Sfgzip_t*	gz;
202 	int		fd;
203 	int		rd;
204 	size_t		z;
205 	char		mode[10];
206 
207 	rd = sfset(sp, 0, 0) & SF_READ;
208 	if (rd)
209 	{
210 		register unsigned char*	s;
211 		register int		n;
212 		register int		r;
213 
214 		/*
215 		 * peek the first 4 bytes to verify the magic
216 		 *
217 		 *	0x1f8b....	sfdcgzip	gzip
218 		 *	0x1f9d....	sfdclzw		compress
219 		 *	0xd6c3c4d8	sfpopen		vcunzip
220 		 */
221 
222 #if PRIVATE
223 		if (!(n = sfset(sp, 0, 0) & SF_SHARE))
224 			sfset(sp, SF_SHARE, 1);
225 #endif
226 		s = (unsigned char*)sfreserve(sp, 4, SF_LOCKR);
227 #if PRIVATE
228 		if (!n)
229 			sfset(sp, SF_SHARE, 0);
230 #endif
231 		if (!s)
232 			return -1;
233 		n = 0;
234 		if (s[0] == 0x1f)
235 		{
236 			if (s[1] == 0x8b)
237 				n = 'g';
238 			else if (s[1] == 0x9d)
239 				n = 'c';
240 		}
241 		else if (s[0] == 0xd6 && s[1] == 0xc3 && s[2] == 0xc4 && s[3] == 0xd8)
242 			n = 'v';
243 		sfread(sp, s, 0);
244 		if (!n)
245 			return 0;
246 		if (flags & SFGZ_VERIFY)
247 			return n != 0;
248 		switch (n)
249 		{
250 		case 'c':
251 			return (r = sfdclzw(sp, flags)) > 0 ? 'c' : r;
252 		case 'v':
253 			r = 0;
254 			n = dup(0);
255 			close(0);
256 			if (dup(sffileno(sp)) || !sfpopen(sp, "vcunzip", "r"))
257 				r = -1;
258 			close(0);
259 			if (n > 0 && dup(n))
260 				r = -1;
261 			close(n);
262 			return r > 0 ? 'v' : r;
263 		}
264 	}
265 	else if (flags & SFGZ_VERIFY)
266 		return -1;
267 	if (!(gz = newof(0, Sfgzip_t, 1, 0)))
268 		return -1;
269 	gz->disc.exceptf = sfgzexcept;
270 	if (rd)
271 		gz->disc.readf = sfgzread;
272 	else
273 		gz->disc.writef = sfgzwrite;
274 	gz->disc.seekf = sfgzseek;
275 	m = mode;
276 	*m++ = rd ? 'r' : 'w';
277 	*m++ = 'b';
278 	if (flags & SFGZ_NOCRC)
279 		*m++ = 'n';
280 	*m++ = 'o';
281 	if ((flags &= 0xf) > 0 && flags <= 9)
282 		*m++ = '0' + flags;
283 	*m = 0;
284 #if PRIVATE
285 	sfset(sp, SF_SHARE|SF_PUBLIC, 0);
286 #endif
287 	if (!rd)
288 	{
289 		m = 0;
290 		z = 0;
291 	}
292 	else if (!(z = sfreserve(sp, 0, -1) ? (size_t)sfvalue(sp) : 0))
293 		m = 0;
294 	else if (m = sfreserve(sp, z, 0))
295 		z = (size_t)sfvalue(sp);
296 	else
297 		z = 0;
298 	fd = sffileno(sp);
299 	if (rd && (gz->op = sfopen(NiL, "/dev/null", "r")))
300 		sfswap(sp, gz->op);
301 	if (!(gz->gz = gzbopen(fd, mode, m, z)) || sfdisc(sp, &gz->disc) != &gz->disc)
302 	{
303 		free(gz);
304 		return -1;
305 	}
306 #if PRIVATE
307 #if 0
308 {
309 	char*	v;
310 	long	n;
311 
312 	if ((v = getenv("SFGZ_sfdcgzip_bufsize")) || (v = getenv("SFGZ_bufsize")))
313 	{
314 		if ((n = strtol(v, NiL, 0)) > 0)
315 			sfsetbuf(sp, NiL, n);
316 	}
317 	else
318 		sfsetbuf(sp, NiL, SF_BUFSIZE);
319 }
320 #else
321 	sfsetbuf(sp, NiL, SF_BUFSIZE);
322 #endif
323 #endif
324 	if (!rd)
325 		sfset(sp, SF_IOCHECK, 1);
326 	return 'g';
327 }
328 
329 #if __OBSOLETE__ < 19990717
330 
331 #if defined(__EXPORT__)
332 #define extern	__EXPORT__
333 #endif
334 
335 extern int
sfgzip(Sfio_t * sp)336 sfgzip(Sfio_t* sp)
337 {
338 	return sfdcgzip(sp, 0);
339 }
340 
341 #undef	extern
342 
343 #endif
344