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