diff --git a/bin/tar/Makefile b/bin/tar/Makefile new file mode 100644 index 0000000..349b4d3 --- /dev/null +++ b/bin/tar/Makefile @@ -0,0 +1,5 @@ +tar.a: tar.c + compile tar.c keep=tar + +tar: tar.a + link tar keep=tar diff --git a/bin/tar/tar.c b/bin/tar/tar.c new file mode 100644 index 0000000..032d2ea --- /dev/null +++ b/bin/tar/tar.c @@ -0,0 +1,242 @@ +/* + + tar.c - a GS version of the venerable Unix tape archive + utility. + + 7/12/93 - changed to use read/write instead of fread/fwrite. + Some performance improvement. + Copyright 1991-1993 Procyon Enterprises, Inc. + This code and the executable derived from it are hereby + put in the public domain. + +*/ + +#pragma stacksize 1024 +#pragma optimize 9 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TBLOCK 512 +#define NAMSIZ 100 + +union hblock { + char dummy[TBLOCK]; + struct header { + char name[NAMSIZ]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[NAMSIZ]; + FileInfoRecGS fInfo; + } dbuf; +}; + +byte buffer[1024]; +char filename[255]; +int tarfile; + +int optVerbose, optFile, optExtract, + optTest; + +/* pull a file out of the archive one block at a time */ + +GSString255Ptr MakeGSString1(char *s) +{ +GSString255Ptr n; + n = malloc(sizeof(GSString255)); + strcpy((char *) n->text,s); + n->length = strlen(s); + return n; +} + +static char fixed[NAMSIZ]; +char *fixName(char *n) +{ +int i,j; + + for (i = 0, j = 0; n[i] != 0;) { + if (n[i] == '/') { + fixed[j++] = '/'; + while (n[i] == '/') i++; + } + else fixed[j++] = n[i++]; + } + fixed[j] = 0; + return fixed; +} + +int extractFile(char *name, longword blocks, longword length) +{ +word excess; +int got,get,i,e; +int output; +char *d,dirName[256]; +CreateRecGS c; +FileInfoRecGS inf; + + if (optVerbose) printf("extracting %s (%ld blocks)\n",name, blocks); + blocks = length / 1024; + excess = length % 1024; + if (excess) blocks++; + + for (i = 0; i < strlen(name); i++) + if (!( isalnum(name[i]) || (name[i] == '.') || (name[i] == '/') )) + name[i] = '.'; + + if (name[0] == '/') { + fprintf(stderr, "Can't extract to a volume name!\n"); + exit(1); + } + d = name; + while ((d = strchr(d, '/')) != NULL) { + + strncpy(dirName, name, d-name); + dirName[(int) (d-name)] = '\0'; + + inf.pCount = 3; + inf.pathname = MakeGSString1(dirName); + GetFileInfoGS(&inf); + if (e = toolerror()) { + switch (e) { + case 0x46: + case 0x44: break; + default: fprintf(stderr, "error statting file %s (%x)\n", + dirName,e); + exit(1); break; + } + } + else if (inf.fileType != 0x0F) { + fprintf(stderr, "can't overwrite file %s\n", dirName); + exit(1); + } + + if (e) { + c.pCount = 3; + c.pathname = inf.pathname; + c.access = 0xC3; + c.fileType = 0x0F; + CreateGS(&c); + if (e = toolerror()) { + fprintf(stderr, "fatal GS/OS error %x\n",e); + exit(1); + } + } + free(inf.pathname); + while (*d == '/') d++; + } + + if (!blocks) return 0; + name=fixName(name); + output = open(name, O_WRONLY|O_CREAT,0666); + for (i = 0; i < blocks; i++) { + if ((i == blocks-1) && excess) get = excess; + else get = 1024; + got = read(tarfile, buffer, (size_t) get); + if (got != get) { fprintf(stderr, "read error\n"); exit(1); } + + if (write(output, buffer, (size_t) got) < get) + { fprintf(stderr, "write error\n"); exit(1); } + } + close(output); +} + +int testFile(char *name, longword blocks, longword length) +{ + printf("%s (%ld blocks)\n",name, blocks); +} + +void usage(void) +{ + fprintf(stderr,"Usage: tar -options [archive]\n" + " options: t - list files in archive (test)\n" + " x - extract files from archive\n" + " f - use file [archive] instead of tape\n" + " v - verbose mode\n"); + exit(1); +} + +void parseOpts(char *opts) +{ +char *i = opts; + + while (*i != '\0') { + switch (*i) { + case 'x': if (optTest) usage(); + optExtract = 1; break; + case 't': if (optExtract) usage(); + optTest = 1; break; + case 'f': optFile = 1; break; + case 'v': optVerbose = 1; break; + default: usage(); + } + i++; + } +} + +int main(int argc, char *argv[]) +{ +longword block; +longword size; +longword fileBlocks; +word got; +int SessionPB = 0; +int err; + + block = 0; + optVerbose = optFile = optExtract = optTest = 0; + + if (argc == 1) usage(); + if (argv[1][0] == '-') parseOpts(&argv[1][1]); + else parseOpts(argv[1]); + + if (optFile) tarfile = open(argv[2], O_RDONLY); + else { fprintf(stderr, "no SCSI tape found\n"); exit(1); } + + if (tarfile == 0) { + perror("Couldn't open archive"); + exit(1); + } + + if (!(optExtract || optTest)) usage(); + BeginSession(&SessionPB); + + do { + if (lseek(tarfile, (long) block*512, SEEK_SET) == -1) { + err = errno; + fprintf(stderr, "Seek error(%s)- aborting\n",strerror(err)); + exit(1); + } + got = read(tarfile, buffer, (size_t) 512); + if (!buffer[0]) break; + if (got == 0) { fprintf(stderr, "Read error- aborting\n"); exit(1); } + if (got == 512) { + sscanf(buffer+0174, "%lo", &size); + + fileBlocks = (size / 512); + if (size % 512) fileBlocks++; + + block += fileBlocks + 1; + strcpy(filename, (char *) buffer); /* copy the filename for future + reeference */ + if (optExtract) extractFile(filename, fileBlocks, size); + else if (optTest) testFile(filename, fileBlocks, size); + + buffer[0] = 0; + } + } while (got == 512); + close(tarfile); + EndSession(&SessionPB); + return 0; +}