mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-12-21 23:29:16 +00:00
e72e1c891f
tar v2.0.1 binary distributed on the 'net that claimed to have fixed an unspecified bug in this version, but neither the sources nor the originator of that fix are available. It may be appropriate to completely replace this implementation.
243 lines
5.8 KiB
C
243 lines
5.8 KiB
C
/*
|
|
|
|
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 <types.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stddef.h>
|
|
#include <gsos.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#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;
|
|
}
|