xref: /plan9-contrib/sys/src/cmd/tarsplit/tarsub.c (revision ad6ca847b1a6a504acb0003cd6c5c6d92687369b)
14d2c0504SDavid du Colombier /*
24d2c0504SDavid du Colombier  * tar archive manipulation functions
34d2c0504SDavid du Colombier  */
44d2c0504SDavid du Colombier 
54d2c0504SDavid du Colombier #include <u.h>
64d2c0504SDavid du Colombier #include <libc.h>
74d2c0504SDavid du Colombier #include <ctype.h>
84d2c0504SDavid du Colombier #include "tar.h"
94d2c0504SDavid du Colombier 
104d2c0504SDavid du Colombier enum {
114d2c0504SDavid du Colombier 	Blocksxfr = 32,
124d2c0504SDavid du Colombier };
134d2c0504SDavid du Colombier 
144d2c0504SDavid du Colombier /* exports */
154d2c0504SDavid du Colombier char *thisnm, *lastnm;
164d2c0504SDavid du Colombier 
174d2c0504SDavid du Colombier /* private data */
184d2c0504SDavid du Colombier static uvlong outoff = 0;		/* maintained by newarch, writetar */
194d2c0504SDavid du Colombier 
204d2c0504SDavid du Colombier unsigned
checksum(Hblock * hp)214d2c0504SDavid du Colombier checksum(Hblock *hp)
224d2c0504SDavid du Colombier {
234d2c0504SDavid du Colombier 	int i;
244d2c0504SDavid du Colombier 	uchar *cp, *csum, *end;
254d2c0504SDavid du Colombier 
264d2c0504SDavid du Colombier 	i = ' ' * sizeof hp->chksum;	/* pretend blank chksum field */
274d2c0504SDavid du Colombier 	csum = (uchar *)hp->chksum;
284d2c0504SDavid du Colombier 	end = &hp->dummy[Tblock];
294d2c0504SDavid du Colombier 	/*
304d2c0504SDavid du Colombier 	 * Unixware gets this wrong; it adds *signed* chars.
314d2c0504SDavid du Colombier 	 *	i += (Uflag? *(schar *)cp: *cp);
324d2c0504SDavid du Colombier 	 */
334d2c0504SDavid du Colombier 	for (cp = hp->dummy; cp < csum; )
344d2c0504SDavid du Colombier 		i += *cp++;
354d2c0504SDavid du Colombier 	/* skip checksum field */
364d2c0504SDavid du Colombier 	for (cp += sizeof hp->chksum; cp < end; )
374d2c0504SDavid du Colombier 		i += *cp++;
384d2c0504SDavid du Colombier 	return i;
394d2c0504SDavid du Colombier }
404d2c0504SDavid du Colombier 
414d2c0504SDavid du Colombier void
readtar(int in,char * buffer,long size)424d2c0504SDavid du Colombier readtar(int in, char *buffer, long size)
434d2c0504SDavid du Colombier {
444d2c0504SDavid du Colombier 	int i;
454d2c0504SDavid du Colombier 	unsigned bytes;
464d2c0504SDavid du Colombier 
474d2c0504SDavid du Colombier 	bytes = i = readn(in, buffer, size);
484d2c0504SDavid du Colombier 	if (i <= 0)
494d2c0504SDavid du Colombier 		sysfatal("archive read error: %r");
504d2c0504SDavid du Colombier 	if (bytes % Tblock != 0)
514d2c0504SDavid du Colombier 		sysfatal("archive blocksize error");
524d2c0504SDavid du Colombier 	if (bytes != size) {
534d2c0504SDavid du Colombier 		/*
544d2c0504SDavid du Colombier 		 * buffering would be screwed up by only partially
554d2c0504SDavid du Colombier 		 * filling tbuf, yet this might be the last (short)
564d2c0504SDavid du Colombier 		 * record in a tar disk archive, so just zero the rest.
574d2c0504SDavid du Colombier 		 */
584d2c0504SDavid du Colombier 		fprint(2, "%s: warning: short archive block\n", argv0);
594d2c0504SDavid du Colombier 		memset(buffer + bytes, '\0', size - bytes);
604d2c0504SDavid du Colombier 	}
614d2c0504SDavid du Colombier }
624d2c0504SDavid du Colombier 
634d2c0504SDavid du Colombier void
newarch(void)644d2c0504SDavid du Colombier newarch(void)
654d2c0504SDavid du Colombier {
664d2c0504SDavid du Colombier 	outoff = 0;
674d2c0504SDavid du Colombier }
684d2c0504SDavid du Colombier 
694d2c0504SDavid du Colombier uvlong
writetar(int outf,char * buffer,ulong size)704d2c0504SDavid du Colombier writetar(int outf, char *buffer, ulong size)
714d2c0504SDavid du Colombier {
724d2c0504SDavid du Colombier 	if (write(outf, buffer, size) < size) {
734d2c0504SDavid du Colombier 		fprint(2, "%s: archive write error: %r\n", argv0);
744d2c0504SDavid du Colombier 		fprint(2, "%s: archive seek offset: %llud\n", argv0, outoff);
754d2c0504SDavid du Colombier 		exits("write");
764d2c0504SDavid du Colombier 	}
774d2c0504SDavid du Colombier 	outoff += size;
784d2c0504SDavid du Colombier 	return outoff;
794d2c0504SDavid du Colombier }
804d2c0504SDavid du Colombier 
814d2c0504SDavid du Colombier ulong
otoi(char * s)824d2c0504SDavid du Colombier otoi(char *s)
834d2c0504SDavid du Colombier {
844d2c0504SDavid du Colombier 	int c;
854d2c0504SDavid du Colombier 	ulong ul = 0;
864d2c0504SDavid du Colombier 
874d2c0504SDavid du Colombier 	while (isascii(*s) && isspace(*s))
884d2c0504SDavid du Colombier 		s++;
894d2c0504SDavid du Colombier 	while ((c = *s++) >= '0' && c <= '7') {
904d2c0504SDavid du Colombier 		ul <<= 3;
914d2c0504SDavid du Colombier 		ul |= c - '0';
924d2c0504SDavid du Colombier 	}
934d2c0504SDavid du Colombier 	return ul;
944d2c0504SDavid du Colombier }
954d2c0504SDavid du Colombier 
964d2c0504SDavid du Colombier int
getdir(Hblock * hp,int in,vlong * lenp)974d2c0504SDavid du Colombier getdir(Hblock *hp, int in, vlong *lenp)
984d2c0504SDavid du Colombier {
994d2c0504SDavid du Colombier 	*lenp = 0;
1004d2c0504SDavid du Colombier 	readtar(in, (char*)hp, Tblock);
1014d2c0504SDavid du Colombier 	if (hp->name[0] == '\0') { /* zero block indicates end-of-archive */
1024d2c0504SDavid du Colombier 		lastnm = strdup(thisnm);
1034d2c0504SDavid du Colombier 		return 0;
1044d2c0504SDavid du Colombier 	}
1054d2c0504SDavid du Colombier 	*lenp = otoi(hp->size);
1064d2c0504SDavid du Colombier 	if (otoi(hp->chksum) != checksum(hp))
1074d2c0504SDavid du Colombier 		sysfatal("directory checksum error");
1084d2c0504SDavid du Colombier 	if (lastnm != nil)
1094d2c0504SDavid du Colombier 		free(lastnm);
1104d2c0504SDavid du Colombier 	lastnm = thisnm;
1114d2c0504SDavid du Colombier 	thisnm = strdup(hp->name);
1124d2c0504SDavid du Colombier 	return 1;
1134d2c0504SDavid du Colombier }
1144d2c0504SDavid du Colombier 
115*ad6ca847SDavid du Colombier uvlong
passtar(Hblock * hp,int in,int outf,vlong len)1164d2c0504SDavid du Colombier passtar(Hblock *hp, int in, int outf, vlong len)
1174d2c0504SDavid du Colombier {
1184d2c0504SDavid du Colombier 	ulong bytes;
119*ad6ca847SDavid du Colombier 	vlong off;
1204d2c0504SDavid du Colombier 	uvlong blks;
1214d2c0504SDavid du Colombier 	char bigbuf[Blocksxfr*Tblock];		/* 2*(8192 == MAXFDATA) */
1224d2c0504SDavid du Colombier 
123*ad6ca847SDavid du Colombier 	off = outoff;
1244d2c0504SDavid du Colombier 	if (islink(hp->linkflag))
125*ad6ca847SDavid du Colombier 		return off;
1264d2c0504SDavid du Colombier 	for (blks = TAPEBLKS((uvlong)len); blks >= Blocksxfr;
1274d2c0504SDavid du Colombier 	    blks -= Blocksxfr) {
1284d2c0504SDavid du Colombier 		readtar(in, bigbuf, sizeof bigbuf);
129*ad6ca847SDavid du Colombier 		off = writetar(outf, bigbuf, sizeof bigbuf);
1304d2c0504SDavid du Colombier 	}
1314d2c0504SDavid du Colombier 	if (blks > 0) {
1324d2c0504SDavid du Colombier 		bytes = blks*Tblock;
1334d2c0504SDavid du Colombier 		readtar(in, bigbuf, bytes);
134*ad6ca847SDavid du Colombier 		off = writetar(outf, bigbuf, bytes);
1354d2c0504SDavid du Colombier 	}
136*ad6ca847SDavid du Colombier 	return off;
1374d2c0504SDavid du Colombier }
1384d2c0504SDavid du Colombier 
1394d2c0504SDavid du Colombier void
putempty(int out)1404d2c0504SDavid du Colombier putempty(int out)
1414d2c0504SDavid du Colombier {
1424d2c0504SDavid du Colombier 	static char buf[Tblock];
1434d2c0504SDavid du Colombier 
1444d2c0504SDavid du Colombier 	writetar(out, buf, sizeof buf);
1454d2c0504SDavid du Colombier }
1464d2c0504SDavid du Colombier 
1474d2c0504SDavid du Colombier /* emit zero blocks at end */
1484d2c0504SDavid du Colombier int
closeout(int outf,char *,int prflag)149*ad6ca847SDavid du Colombier closeout(int outf, char *, int prflag)
1504d2c0504SDavid du Colombier {
1514d2c0504SDavid du Colombier 	if (outf < 0)
1524d2c0504SDavid du Colombier 		return -1;
1534d2c0504SDavid du Colombier 	putempty(outf);
1544d2c0504SDavid du Colombier 	putempty(outf);
1554d2c0504SDavid du Colombier 	if (lastnm && prflag)
1564d2c0504SDavid du Colombier 		fprint(2, " %s\n", lastnm);
157*ad6ca847SDavid du Colombier 	close(outf);		/* guaranteed to succeed on plan 9 */
1584d2c0504SDavid du Colombier 	return -1;
1594d2c0504SDavid du Colombier }
160