mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-12-22 14:30:29 +00:00
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;
|
||
|
}
|