summaryrefslogtreecommitdiff
path: root/sys/src/cmd/hgfs/zip.c
blob: 31ab65f6437ab6164492124659dd4dfbe22cac0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "dat.h"
#include "fns.h"

#include <flate.h>

struct zbuf {
	int	fd;
	int	len;

	uchar	*b, *p, *e;
};

static int
zwrite(void *a, void *p, int n)
{
	int *ofd = a;

	if(write(*ofd, p, n) != n)
		return -1;
	return n;
}

static int
zgetc(void *a)
{
	struct zbuf *z = a;
	int n;

	for(;;){
		if(z->p < z->e)
			return *z->p++;
		if(z->len <= 0)
			return -1;
		if((n = BUFSZ) > z->len)
			n = z->len;
		if((n = read(z->fd, z->p = z->b, n)) <= 0)
			return -1;
		z->len -= n;
		z->e = z->p + n;
	}
}

int
funzip(int ofd, int zfd, int len)
{
	uchar buf[BUFSZ];
	struct zbuf z;
	int wlen, n;
	uchar *p;

	if(len == 0)
		return 0;

	wlen = 0;
	if((n = BUFSZ) > len)
		n = len;
	if((n = read(zfd, p = buf, n)) <= 0)
		return -1;
	len -= n;
	switch(*p){
	default:
		return -1;
	case 'u':
		p++;
		n--;
		/* no break */
	case '\0':
		while((n > 0) && (write(ofd, p, n) == n)){
			wlen += n;
			if(len <= 0)
				break;
			if((n = BUFSZ) > len)
				n = len;
			if((n = read(zfd, p = buf, n)) <= 0)
				break;
			len -= n;
		}
		break;
	case 'x':
		if(n < 2)
			return -1;
		z.fd = zfd;
		z.len = len;
		z.b = buf;
		z.p = p + 2;
		z.e = p + n;
		if((wlen = inflate(&ofd, zwrite, &z, zgetc)) < 0){
			werrstr("%s", flateerr(wlen));
			return -1;
		}
		break;
	}
	return wlen;
}