Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * tar archive manipulation functions
3
 */
4
 
5
#include <u.h>
6
#include <libc.h>
7
#include <ctype.h>
8
#include "tar.h"
9
 
10
enum {
11
	Blocksxfr = 32,
12
};
13
 
14
/* exports */
15
char *thisnm, *lastnm;
16
 
17
/* private data */
18
static uvlong outoff = 0;		/* maintained by newarch, writetar */
19
 
20
unsigned
21
checksum(Hblock *hp)
22
{
23
	int i;
24
	uchar *cp, *csum, *end;
25
 
26
	i = ' ' * sizeof hp->chksum;	/* pretend blank chksum field */
27
	csum = (uchar *)hp->chksum;
28
	end = &hp->dummy[Tblock];
29
	/*
30
	 * Unixware gets this wrong; it adds *signed* chars.
31
	 *	i += (Uflag? *(schar *)cp: *cp);
32
	 */
33
	for (cp = hp->dummy; cp < csum; )
34
		i += *cp++;
35
	/* skip checksum field */
36
	for (cp += sizeof hp->chksum; cp < end; )
37
		i += *cp++;
38
	return i;
39
}
40
 
41
void
42
readtar(int in, char *buffer, long size)
43
{
44
	int i;
45
	unsigned bytes;
46
 
47
	bytes = i = readn(in, buffer, size);
48
	if (i <= 0)
49
		sysfatal("archive read error: %r");
50
	if (bytes % Tblock != 0)
51
		sysfatal("archive blocksize error");
52
	if (bytes != size) {
53
		/*
54
		 * buffering would be screwed up by only partially
55
		 * filling tbuf, yet this might be the last (short)
56
		 * record in a tar disk archive, so just zero the rest.
57
		 */
58
		fprint(2, "%s: warning: short archive block\n", argv0);
59
		memset(buffer + bytes, '\0', size - bytes);
60
	}
61
}
62
 
63
void
64
newarch(void)
65
{
66
	outoff = 0;
67
}
68
 
69
uvlong
70
writetar(int outf, char *buffer, ulong size)
71
{
72
	if (write(outf, buffer, size) < size) {
73
		fprint(2, "%s: archive write error: %r\n", argv0);
74
		fprint(2, "%s: archive seek offset: %llud\n", argv0, outoff);
75
		exits("write");
76
	}
77
	outoff += size;
78
	return outoff;
79
}
80
 
81
ulong
82
otoi(char *s)
83
{
84
	int c;
85
	ulong ul = 0;
86
 
87
	while (isascii(*s) && isspace(*s))
88
		s++;
89
	while ((c = *s++) >= '0' && c <= '7') {
90
		ul <<= 3;
91
		ul |= c - '0';
92
	}
93
	return ul;
94
}
95
 
96
int
97
getdir(Hblock *hp, int in, vlong *lenp)
98
{
99
	*lenp = 0;
100
	readtar(in, (char*)hp, Tblock);
101
	if (hp->name[0] == '\0') { /* zero block indicates end-of-archive */
102
		lastnm = strdup(thisnm);
103
		return 0;
104
	}
105
	*lenp = otoi(hp->size);
106
	if (otoi(hp->chksum) != checksum(hp))
107
		sysfatal("directory checksum error");
108
	if (lastnm != nil)
109
		free(lastnm);
110
	lastnm = thisnm;
111
	thisnm = strdup(hp->name);
112
	return 1;
113
}
114
 
115
uvlong 
116
passtar(Hblock *hp, int in, int outf, vlong len)
117
{
118
	ulong bytes;
119
	vlong off;
120
	uvlong blks;
121
	char bigbuf[Blocksxfr*Tblock];		/* 2*(8192 == MAXFDATA) */
122
 
123
	off = outoff;
124
	if (islink(hp->linkflag))
125
		return off;
126
	for (blks = TAPEBLKS((uvlong)len); blks >= Blocksxfr;
127
	    blks -= Blocksxfr) {
128
		readtar(in, bigbuf, sizeof bigbuf);
129
		off = writetar(outf, bigbuf, sizeof bigbuf);
130
	}
131
	if (blks > 0) {
132
		bytes = blks*Tblock;
133
		readtar(in, bigbuf, bytes);
134
		off = writetar(outf, bigbuf, bytes);
135
	}
136
	return off;
137
}
138
 
139
void
140
putempty(int out)
141
{
142
	static char buf[Tblock];
143
 
144
	writetar(out, buf, sizeof buf);
145
}
146
 
147
/* emit zero blocks at end */
148
int
149
closeout(int outf, char *, int prflag)
150
{
151
	if (outf < 0)
152
		return -1;
153
	putempty(outf);
154
	putempty(outf);
155
	if (lastnm && prflag)
156
		fprint(2, " %s\n", lastnm);
157
	close(outf);		/* guaranteed to succeed on plan 9 */
158
	return -1;
159
}