/* * tarsplit [-d] [-p pfx] [-s size] - split a tar archive into independent * tar archives under some size */ #include #include #include #include "tar.h" enum { Stdin, Endsize = 2 * Tblock, /* size of zero blocks at archive end */ }; /* private data */ static char *filenm; static char *prefix = "ts."; static vlong size = 512*1024*1024; /* fits on a CD with room to spare */ static int opennext(int out, char *prefix) { static int filenum = 0; if (out >= 0) { fprint(2, "%s: opennext called with file open\n", argv0); exits("open botch"); } free(filenm); filenm = smprint("%s%.5d", prefix, filenum++); fprint(2, "%s: %s ...", filenm, thisnm); out = create(filenm, OWRITE, 0666); if (out < 0) sysfatal("%s: %r", filenm); newarch(); return out; } static int split(int in, int out, char * /* inname */) { vlong len, membsz; uvlong outoff = 0; static Hblock hdr; Hblock *hp = &hdr; while (getdir(hp, in, &len)) { membsz = Tblock + ROUNDUP((uvlong)len, Tblock); if (outoff + membsz + Endsize > size) { /* won't fit? */ out = closeout(out, filenm, 1); if (membsz + Endsize > size) sysfatal("archive member %s (%,lld) + overhead " "exceeds size limit %,lld", hp->name, len, size); } if (out < 0) out = opennext(out, prefix); /* write directory block */ writetar(out, (char *)hp, Tblock); outoff = passtar(hp, in, out, len); } return out; } void usage(void) { fprint(2, "usage: %s [-p pfx] [-s size] [file]...\n", argv0); exits("usage"); } void main(int argc, char **argv) { int out = -1; ARGBEGIN { case 'p': prefix = EARGF(usage()); break; case 's': size = atoll(EARGF(usage())); if (size < Tblock + Endsize) sysfatal("implausible max size of %lld bytes", size); break; default: usage(); } ARGEND if (argc <= 0) out = split(Stdin, out, "/fd/0"); else for (; argc-- > 0; argv++) { int in = open(argv[0], OREAD); if (in < 0) sysfatal("%s: %r", argv[0]); out = split(in, out, argv[0]); close(in); } closeout(out, filenm, 1); exits(0); }