home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
400-499
/
ff434.lzh
/
Backup
/
backup.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-18
|
33KB
|
1,655 lines
/*
* BACKUP.C
*
* (C)Copyright 1986-90, Matthew Dillon, All Rights Reserved.
* Permission is granted to distribute for non-profit only.
*
* Thanks to Jan Sven Trabandt for finding some major bugs!
*
* This program will backup a filesystem or directory, creating a single
* output file which can later be RESTORE'd from. It is a quick way to
* backup your work to a 'backup' disk.
*
* backup [options] path path path ... path [-ooutputfile]
*
* NOTE: if -o is not specified, not output file will be created
*
* NOTE: Any files/directories containing the keyword NOBACKUP in
* its comment field will not be backed up.
*
* options:
*
* -0 (Restore): Cause all restored files to be placed
* in the current (or -o) directory. No directory
* structure is restored at all
*
* -A ARCHIVE. Clear the archive bit on backed up files
*
* -U UPDATE. Backup only those files which have the archive bit
* cleared.
*
* -f[#KB] Floppy... actually, this option is used to force the backup
* program to automatically split up the backup files in #KB
* sections (default 800). I.E. -f with nothing else will
* use 800KB chunks. -f200 would use 200KB chunks, etc...
*
* PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
* AND RESTORE
*
* -Fvol example: -FDF0: -FDF1: This command specifies the ordering
* and number of (floppy) drives to backup to. This allows
* one to change floppies in one drive while it is backing up
* to another. It automatically cycles through the drives but
* you still must specify an initial output file (-ofile) to
* determine the base name for the files.
*
* This command also forces user prompting.
*
* PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
* AND RESTORE
*
* -b backup (default if executable name is 'backup')
*
* -r restore (default if executable nam is 'restore')
*
* -a append to the destination file.
*
* -c Compress files during backup
*
* -Cpat add file pattern to those which will not
* be compressed.
*
* -s Only display directories as we go along.
*
* -l/-t (either option) Causes a RESTORE to only LIST the files,
* not do an actual restore.
*
* -T (Restore) TIMESTAMP, COMMENT, AND PROTECTION BITS ONLY.
* NO files are created. It is assumed the files already
* exist. The timestamp and other fields are transfered
* from the backup file to the already-restored files (useful
* if the files were restored with a copy command that did
* non copy the timestamps. Even if the backup file is old,
* you can recover most of your time data).
*
* -S Silent. Don't display files or directories.
*
* -nKB Set buffer size to use, in KB.
*
* -v Verbose... Additionaly, display those files which will NOT
* be backed up.
*
* -pPAT only file-paths matching this pattern are backed up. You
* may specify more than one '-p' option.
*
* -dPAT file-paths matching this pattern are NOT backed up. you
* may specify more than one '-d' option.
*
* -ofile Output File
*
* -Ooffset Set Offset (manual recover on restore)
*
* ---------------------------------------------------------------------
*
* destination file format:
*
* HDR = <HDR><N.B><datestamp> -Backup Date
* VOL = <VOL><name_size.B><name> -VOLUME base
* DDS = <DDS><name_size.B><name> -down-directory
* END = <END><0.B> -up directory
* DAT = <DAT><N.B><datestamp> -datestamp for file
* PRO = <PRO><4.B><protection> -protection for file
* COM = <COM><N.B><comment> -comment for file
* FIL0= <FIL0><N.B><name><size.L><data> -uncompressed file
* FIL1= <FIL1><N.B><name><size.L><usize.L><data> -compressed form #1
* INC = <INC><12.B><ttlsize><strt><segsize> -next file is part of an
* incomplete file
*/
#include "defs.h"
#include <libraries/dos.h>
#include <libraries/dosextens.h>
ubyte Break;
ubyte Restore;
ubyte NoStructure;
ubyte ListOnly;
ubyte ShowFiles = 1;
ubyte ShowDirs = 1;
ubyte Verbose;
ubyte Archive;
ubyte Update;
ubyte Append;
ubyte Compress;
ubyte TimeStampOnly;
char *OutFile;
long BacBytes;
short BacCnt = 1;
short MyBreak;
char DirPath[256];
short DPLen;
char *BadFormat;
long BufSize = 65536;
long BufI;
ubyte *Buf;
long InBufSize = 8192;
long InBufI, InBufN;
ubyte *InBuf;
char Overide;
MLIST VList; /* Volume list (-F), of NODEs */
MLIST DList; /* Directory Stack */
MLIST CSList; /* compression patterns */
MLIST PSList; /* pick patterns */
MLIST DSList; /* don't pick patterns */
long CLen; /* Actual compressed file output length */
MLIST CList; /* List of memory buffers */
SCOMP *CWrite; /* Current memory buffer pointer */
extern void *GetHead(MLIST *);
extern void *GetTail(MLIST *);
extern void *GetSucc(MNODE *);
extern void *GetPred(MNODE *);
void AddPattern (MLIST *, char *);
void BackupFiles (int, char **);
void RestoreFiles(int, char **, long);
FIB *GetFileInfo(char *, long *);
void FreeFileInfo(FIB *, long);
void PushDir (char *, long);
int PopDirs (uword);
void BackupFlagHasFile(void);
long scan_directory(FIB *, long);
int mycheckbreak(void);
long scan_file (FIB *, long);
int match_file (char *);
void writeheaders(FIB *);
int newfile (void);
int read_file (short, char *, long, long);
int openoutput (char *, int, int);
void oputc (char);
void outlwatseek (long, long);
void owrite (void *, long);
void dumpoutput (void);
void dumpcrc (void);
void closeoutput (void);
long outbytes (void);
void outentry (ubyte, int, void *);
int openinput (char *, long);
void closeinput (void);
void seekinputend(void);
void setinputbound(long);
long oread (void *, long);
void AppendCrc (ubyte *, long);
int oreadchar (void);
void rollbackinput(void);
void mputc (char);
void mwrite (char *, long);
SCOMP *NewSComp (void);
void transfer0 (long);
void transfer1 (void);
int brk (void);
void UnCompressFile(long);
long CompressFile(char *, long);
int
brk()
{
MyBreak = 1;
return(0);
}
main(ac, av)
char **av;
{
register short i, notdone;
register char *str;
long manOffset = 0;
short xac = 0;
static char *Xav[256];
BadFormat = "Bad Format";
SetSignal(0, SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D);
onbreak(brk);
NewList(&VList);
NewList(&DList);
NewList(&CList);
NewList(&PSList);
NewList(&DSList);
NewList(&CSList);
AddPattern(&CSList, "*.Z");
AddPattern(&CSList, "*.ARC");
AddPattern(&CSList, "*.ZOO");
AddPattern(&CSList, "*.LZH");
for (str = av[0] + strlen(av[0]); str >= av[0] && *str != '/' && *str != ':'; --str);
++str;
if ((*str|0x20) == 'r')
Restore = 1;
if (ac == 1) {
printf("Backup/Restore V2.06, (c)Copyright 1988,1989 Matthew Dillon, All Rights Reserved\n", str);
printf("Backup/Restore is useful for HD backup and file transfers\n");
printf("%s -rbactlvASTU -d<pat> -p<pat> -f[#kb] -F<vol> -n<#kb> -ofile <file-dir-list>\n", str);
puts("\nread the docs for more info. Example for use w/ file transfer:");
puts("\t1> backup -c file/dir -oout.bak -create archive");
puts("\t1> restore -t out.bak -list archive");
puts("\t1> restore out.bak [-odest] -restore archive");
}
for (i = 1; i < ac; ++i) {
str = av[i];
if (*str != '-') {
if (xac == sizeof(Xav)/sizeof(Xav[0])) {
printf("Maximum %d files/dirs specifiable on command line\n", sizeof(Xav)/sizeof(Xav[0]));
exit(15);
}
Xav[xac++] = str;
continue;
}
notdone = 1;
++str;
while (notdone && *str) {
switch(*str) {
case '0':
NoStructure = 1;
break;
case 'r':
Restore = 1;
break;
case 'b':
Restore = 0;
break;
case 'a':
Append = 1;
break;
case 'c':
Compress = 1;
break;
case 'd':
AddPattern(&DSList, str + 1);
notdone = 0;
break;
case 'f':
BacBytes = 800 * 1024;
if (str[1] >= '0' && str[1] <= '9') {
BacBytes = atoi(str+1) * 1024;
notdone = 0;
}
break;
case 'F':
{ /* strlen(str+1)+1 */
char *name = (str[1]) ? str + 1 : av[++i];
NODE *node = malloc(sizeof(NODE) + strlen(name) + 1);
node->ln_Name = (char *)(node + 1);
strcpy((char *)(node + 1), name);
AddTail(&VList, node);
}
notdone = 0;
break;
case 'O':
{
char *name = (str[1]) ? str + 1 : av[++i];
manOffset = atoi(name);
}
Overide = 1;
notdone = 0;
break;
case 'n':
{
char *name = (str[1]) ? str + 1 : av[++i];
BufSize = atoi(name) * 1024;
}
if (BufSize <= 0)
BufSize = 65536;
notdone = 0;
break;
case 'o':
{
char *name = (str[1]) ? str + 1 : av[++i];
OutFile = name;
}
notdone = 0;
break;
case 'p':
{
char *name = (str[1]) ? str + 1 : av[++i];
AddPattern(&PSList, name);
}
notdone = 0;
break;
case 's':
ShowFiles = 0;
break;
case 't':
case 'l':
ListOnly = 1;
break;
case 'v':
Verbose= 1;
break;
case 'A':
Archive= 1;
break;
case 'C':
{
char *name = (str[1]) ? str + 1 : av[++i];
AddPattern(&CSList, name);
}
notdone = 0;
break;
case 'S':
ShowFiles = 0;
ShowDirs = 0;
break;
case 'T':
TimeStampOnly = 1;
break;
case 'U':
Update = 1;
break;
default:
puts("failure, backup w/ no args for help");
exit(20);
}
++str;
}
}
if (i > ac) {
puts("Expected argument to last option!");
exit(20);
}
Buf = malloc(BufSize);
if (Buf == NULL) {
printf("Unable to malloc %ld bytes\n", BufSize);
exit(20);
}
if (ListOnly)
InBufSize = 512; /* small buffer to avoid read overhead */
/* since we are skipping the meat */
InBuf = malloc(InBufSize);
if (InBuf == NULL) {
printf("Unable to malloc %ld bytes\n", InBufSize);
exit(20);
}
if (Restore)
RestoreFiles(xac, Xav, manOffset);
else
BackupFiles(xac, Xav);
return(0);
}
void
AddPattern(list, str)
MLIST *list;
char *str;
{
register NODE *node = malloc(sizeof(NODE));
AddTail(list, node);
node->ln_Name = str;
}
long SaveLock;
void
BackupFiles(ac, av)
char **av;
{
register short i;
register char *str, *ptr;
char notdone;
if (OutFile && openoutput(OutFile, Append, ((BacBytes)?1:0)) == 0)
exit(20);
if (OutFile) { /* write header */
DATESTAMP Date;
DateStamp(&Date);
outentry(XHDR, sizeof(DATESTAMP), &Date);
}
SaveLock = CurrentDir(DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
for (i = 0; i < ac; ++i) {
str = av[i];
/*
* Push DDS entries for each name segment of the path
*/
notdone = 1;
while (notdone) {
for (ptr = str; *ptr && *ptr != ':' && *ptr != '/'; ++ptr);
switch(*ptr) {
case '/': /* normal directory */
*ptr = 0;
PushDir(str, XDDS);
str = ptr + 1;
*ptr = '/';
break;
case ':': /* volume */
*ptr = 0;
PushDir(str, XVOL);
str = ptr + 1;
*ptr = ':';
break;
default: /* directory or file */
{
char *path = av[i];
FIB *fib;
long lock;
if (fib = GetFileInfo(path, &lock)) {
if (fib->fib_DirEntryType > 0) {
if (str[0])
PushDir(str, XDDS);
lock = scan_directory(fib, lock);
if (str[0])
PopDirs(1);
} else {
lock = scan_file(fib, lock);
}
FreeFileInfo(fib, lock);
} else {
printf("Unable to get info for %s\n", av[i]);
}
}
notdone = 0;
break;
}
}
PopDirs((uword)-1);
}
UnLock(CurrentDir(SaveLock));
if (OutFile)
closeoutput();
}
DATESTAMP Date;
ulong Crc; /* compare w/ */
ulong CrcGen;
ulong CrcSeek; /* (backup) where in file is CrcGen lw? */
char CrcEna;
char Comment[256];
char Scr[256];
long Protection;
long IncSize; /* Size of entire file */
long IncSeek; /* Seek offset into file */
long IncLen; /* # bytes in this segment */
void
RestoreFiles(ac, av, startoffset)
char **av;
long startoffset;
{
register short i;
register char *str;
char notdone;
char havedate;
char havecrc;
char havepro;
char havecom;
char haveinc;
long bytes;
long actual;
long baselock;
long lock;
PROC *proc = (PROC *)FindTask(NULL);
if (OutFile) {
lock = Lock(OutFile, SHARED_LOCK);
if (lock == NULL && (lock = CreateDir(OutFile))) {
UnLock(lock);
lock = Lock(OutFile, SHARED_LOCK);
}
} else {
lock = Lock("", SHARED_LOCK);
}
if (!lock) {
printf("Unable to lock/create %s\n", (OutFile) ? OutFile : "<currentdir>");
return;
}
baselock = lock;
SaveLock = CurrentDir(DupLock(baselock));
for (i = 0; i < ac; ++i) {
str = av[i];
lock = CurrentDir(SaveLock);
if (openinput(str, startoffset) == 0) {
startoffset = 0;
printf("Unable to open %s for input\n", str);
CurrentDir(lock);
continue;
}
startoffset = 0;
CurrentDir(lock);
lock = DupLock(baselock);
UnLock(CurrentDir(lock));
notdone = 1;
havedate = havecrc = havepro = havecom = haveinc = 0;
while (notdone) {
short c = oreadchar();
short l = oreadchar();
recover:
switch(c) {
case -1: /* EOF */
notdone = 0;
break;
case 0: /* NUL */
case 'z'&0x1F: /* ^Z */
if (Overide == 0)
notdone = 0;
break;
case XVOL:
case XDDS:
oread(Scr, l);
Scr[l] = 0;
/*
* In the replacement of the first
* argument case, we are already in
* the proper directory.
*/
if (EMPTYLIST(DList) && OutFile) {
register short j = strlen(OutFile);
UnLock(CurrentDir(DupLock(SaveLock)));
c = XDDS;
strcpy(Scr, OutFile);
if (j--) {
if (OutFile[j] == ':') {
Scr[j] = 0;
c = XVOL;
}
if (OutFile[j] == '/')
Scr[j] = 0;
}
}
PushDir(Scr, c);
if (ShowDirs)
printf("%-40s\n", DirPath);
if (ListOnly)
break;
if (NoStructure == 0) {
if (c == XVOL) {
lock = Lock(DirPath, SHARED_LOCK); /* DirPath incs ':' */
} else {
lock = Lock(Scr, SHARED_LOCK);
if (lock == NULL && (lock = CreateDir(Scr))) {
UnLock(lock);
lock = Lock(Scr, SHARED_LOCK);
}
}
}
{
SDIR *sd = GetTail(&DList);
sd->HaveFile = 1; /* don't remove dir */
}
if (NoStructure == 0) {
if (lock == NULL) {
printf("Unable to create directory %s\n", Scr);
notdone = 0;
} else {
UnLock(CurrentDir(lock));
}
}
break;
case XEND:
{
SDIR *sd = GetTail(&DList);
ubyte type;
c = 1;
if (!sd)
break;
type = sd->Type;
strcpy(Scr, sd->Element);
c = PopDirs(1);
if (ListOnly)
break;
if (type == XVOL) /* no parent directory */
break;
if (NoStructure == 0) {
lock = ParentDir(proc->pr_CurrentDir);
if (lock == NULL) {
puts("Unable to ParentDir!");
notdone = 0;
} else {
UnLock(CurrentDir(lock));
/*
if (c == 0)
DeleteFile(Scr);
*/
}
}
}
break;
case XCRC:
if (l != 4) {
puts(BadFormat);
notdone = SkipBad(&c, &l);
goto recover;
}
oread(&Crc, l);
havecrc = 1;
break;
case XDAT:
if (l != sizeof(DATESTAMP)) {
puts(BadFormat);
notdone = SkipBad(&c, &l);
goto recover;
}
oread(&Date, l);
havedate = 1;
break;
case XPRO:
if (l != 4) {
puts("Expected 4 bytes for protection");
notdone = SkipBad(&c, &l);
goto recover;
}
oread(&Protection, l);
havepro = 1;
break;
case XCOM:
oread(Comment, l);
Comment[l] = 0;
havecom = 1;
break;
case XFIL0:
case XFIL1:
if (!havepro)
Protection = 0;
if (!havecom)
Comment[0] = 0;
if (!havedate)
DateStamp(&Date);
if (!haveinc)
IncSize = 0;
oread(Scr, l);
Scr[l] = 0;
oread(&bytes, 4); /* length of file */
actual = bytes;
if (c == XFIL1) {
oread(&actual, 4);
bytes -= 4;
}
setinputbound(bytes);
{
short res = read_file(c, Scr, bytes, actual);
seekinputend();
if (res < 0)
goto bend;
}
if (ListOnly)
goto bend;
if (Archive)
SetProtection(Scr, Protection|FIBF_ARCHIVE);
else
SetProtection(Scr, Protection&~FIBF_ARCHIVE);
if (havecrc && Crc != CrcGen)
printf("WARNING, Crc failed! %s\n", Scr);
if (havedate)
setfiledate(Scr, &Date);
if (havecom && Comment[0])
SetComment(Scr, Comment);
bend:
havecom = havecrc = havedate = havepro = haveinc = 0;
break;
case XHDR:
if (l != sizeof(DATESTAMP)) {
puts("expected sizeof datestamp");
notdone = SkipBad(&c, &l);
goto recover;
}
oread(&Date, l);
printf(" ----- BACKUP ----- BACKUP DATE: %s\n", datetos(&Date, Scr, NULL));
break;
case XINC:
if (l != 12) {
puts("expected 12 bytes for XINC");
notdone = SkipBad(&c, &l);
goto recover;
}
oread(&IncSize, 4);
oread(&IncSeek, 4);
oread(&IncLen, 4);
haveinc = 1;
break;
default:
printf("Unknown Record Type: %02x\n", c);
notdone = SkipBad(&c, &l);
goto recover;
}
setinputbound(-1);
if (mycheckbreak()) {
Break = 1;
notdone = 0;
break;
}
}
if (Break)
break;
}
UnLock(baselock);
UnLock(CurrentDir(SaveLock));
}
SkipBad(pc, pl)
short *pc;
short *pl;
{
long skip = 0;
long offset = otellread();
short notdone = 1;
short c;
short l;
loop:
while ((c = oreadchar()) >= 0 && c != XDAT)
++skip;
if (c == XDAT) {
l = oreadchar();
++skip;
if (l != sizeof(DATESTAMP))
goto loop;
}
printf("Error at offset %d, skipping %d bytes", offset, skip);
if (c < 0) {
printf(" (EOF reached!)");
notdone = 0;
}
printf("\n");
*pc = c;
*pl = l;
return((int)notdone);
}
FIB *
GetFileInfo(path, plock)
char *path;
long *plock;
{
register long lock;
register FIB *fib;
*plock = NULL;
if (lock = Lock(path, SHARED_LOCK)) {
if (fib = malloc(sizeof(FIB))) {
if (Examine(lock, fib)) {
*plock = lock;
return(fib);
}
free(fib);
}
UnLock(lock);
}
return(NULL);
}
void
FreeFileInfo(fib, lock)
FIB *fib;
long lock;
{
if (fib)
free(fib);
if (lock)
UnLock(lock);
}
void
PushDir(element, type)
char *element;
{
register SDIR *sd = malloc(sizeof(SDIR));
register char *str = malloc(strlen(element)+1);
strcpy(str, element);
sd->Type = type;
sd->HaveFile = 0;
sd->Element = str;
AddTail(&DList, sd);
strcat(DirPath+DPLen, str);
if (type == XVOL)
strcat(DirPath+DPLen, ":");
else if (type == XDDS)
strcat(DirPath+DPLen, "/");
DPLen += strlen(DirPath+DPLen);
}
int
PopDirs(num)
uword num;
{
register SDIR *sd, *sp;
char lasthave = 0;
while (num && (sd = GetTail(&DList))) {
lasthave |= sd->HaveFile;
if (!Restore && sd->HaveFile) /* MUST write end-block */
outentry(XEND, 0, NULL);
if (sp = GetPred(sd))
sp->HaveFile |= sd->HaveFile;
Remove(sd);
DPLen -= strlen(sd->Element) + 1;
if (DPLen < 0) {
puts("DPLEN ERROR");
DPLen = 0;
}
DirPath[DPLen] = 0;
free(sd->Element);
free(sd);
--num;
}
return((int)lasthave);
}
void
BackupFlagHasFile()
{
register SDIR *sd;
SDIR *sdb = NULL;
for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
if (sd->HaveFile == 0)
sdb = sd;
}
for (sd = sdb; sd; sd = GetSucc(sd)) {
sd->HaveFile = 1;
outentry(sd->Type, strlen(sd->Element), sd->Element);
}
}
/*
* SCAN_DIRECTORY() (CORE OF BACKUP)
*/
long
scan_directory(dirfib, dirlock)
FIB *dirfib;
long dirlock;
{
register FIB *fib;
long lock;
long save = CurrentDir(dirlock);
if (Update == 0) /* force save entire tree */
BackupFlagHasFile();
while (ExNext(dirlock, dirfib) && (fib = GetFileInfo(dirfib->fib_FileName, &lock))) {
if (fib->fib_DirEntryType > 0) {
PushDir(fib->fib_FileName, XDDS);
if (ShowDirs)
printf("%-40s (DIR)\n", DirPath);
if (NoBack(fib) == 0)
lock = scan_directory(fib, lock);
PopDirs(1);
} else {
if (NoBack(fib) == 0)
lock = scan_file(fib, lock);
}
FreeFileInfo(fib, lock);
if (Break || mycheckbreak()) {
Break = 1;
break;
}
}
CurrentDir(save);
return(dirlock);
}
int
mycheckbreak()
{
if (MyBreak || (SetSignal(0, (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D))) {
puts(" ***** BREAK *****");
return(1);
}
return(0);
}
/*
* SCAN_FILE()
*
* If the file is accepted, write out pending directory entries, do
* compression if any, and write out the file.
*/
long
scan_file(fib, lock)
FIB *fib;
long lock;
{
long save;
char dbuf[32];
strcat(DirPath, fib->fib_FileName);
if (Update && (fib->fib_Protection & FIBF_ARCHIVE))
goto nomatch;
if (!match_file(DirPath))
goto nomatch;
if (ShowFiles)
printf("%-40s %6ld %s\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
BackupFlagHasFile();
if (OutFile) {
save = CurrentDir(lock);
if (openinput("", 0) == 0) {
CurrentDir(save);
printf("Unable to open %s\n", fib->fib_FileName);
goto nomatch;
}
if (Compress && CompressFile(fib->fib_FileName, fib->fib_Size)) {
if (OutFile && BacBytes && outbytes() + CLen > BacBytes) {
if (newfile() == 0)
goto skip1;
}
writeheaders(fib);
outentry(XFIL1, strlen(fib->fib_FileName), fib->fib_FileName);
CLen += 4;
owrite(&CLen, 4);
CLen -= 4;
owrite(&fib->fib_Size, 4);
transfer1();
} else {
if (OutFile && BacBytes && outbytes() + fib->fib_Size > BacBytes) {
if (newfile() == 0)
goto skip1;
}
if (Compress)
rollbackinput();
writeheaders(fib);
outentry(XFIL0, strlen(fib->fib_FileName), fib->fib_FileName);
owrite(&fib->fib_Size, 4);
transfer0(fib->fib_Size);
}
outlwatseek(CrcSeek, CrcGen);
skip1:
closeinput();
CurrentDir(save);
}
if (Break)
goto nomatch;
if (Archive && !(fib->fib_Protection & FIBF_ARCHIVE)) {
if (save = ParentDir(lock)) {
UnLock(lock);
save = CurrentDir(save);
SetProtection(fib->fib_FileName, fib->fib_Protection | FIBF_ARCHIVE);
lock = CurrentDir(save);
}
}
DirPath[DPLen] = 0;
return(lock);
nomatch:
if (Verbose)
printf("%-40s (NOT ACCEPTED)\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
DirPath[DPLen] = 0;
return(lock);
}
int
match_file(name)
char *name;
{
register NODE *node;
for (node = (NODE *)PSList.mlh_Head; node->ln_Succ; node = node->ln_Succ) {
if (WildCmp(node->ln_Name, name))
break;
}
if (node->ln_Succ == NULL && !EMPTYLIST(PSList))
return(0);
for (node = (NODE *)DSList.mlh_Head; node->ln_Succ; node = node->ln_Succ) {
if (WildCmp(node->ln_Name, name))
return(0);
}
return(1);
}
void
writeheaders(fib)
register FIB *fib;
{
long dummy = 0;
outentry(XDAT, sizeof(DATESTAMP), &fib->fib_Date);
outentry(XPRO, 4, &fib->fib_Protection);
if (fib->fib_Comment[0])
outentry(XCOM, strlen(fib->fib_Comment), fib->fib_Comment);
outentry(XCRC, 4, &dummy);
CrcSeek = outbytes() - 4;
}
/*
* (1) Write out XEND's to finish this archive,
* (2) Open a new output file
* (3) Write out XDDS's to build back to the current position
*/
int
newfile()
{
{
register SDIR *sd;
for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
if (sd->HaveFile)
outentry(XEND, 0, NULL);
}
}
++BacCnt;
if (OutFile && openoutput(OutFile, Append, 1) == 0) {
Break = 1;
return(0);
}
{
register SDIR *sd;
DATESTAMP Date;
DateStamp(&Date);
outentry(XHDR, sizeof(DATESTAMP), &Date);
for (sd = GetHead(&DList); sd; sd = GetSucc(sd)) {
if (sd->HaveFile)
outentry(sd->Type, strlen(sd->Element), sd->Element);
}
}
return(1);
}
int
read_file(type, fname, inbytes, outbytes)
short type;
char *fname;
long inbytes;
long outbytes;
{
char dbuf[32];
long save;
strcat(DirPath, fname);
if (!match_file(DirPath)) {
if (Verbose)
printf("%-40s (NOT ACCEPTED)\n", DirPath);
goto nomatch;
}
if (ShowFiles)
printf("%-40s %6ld %6ld %s %s\n", DirPath, inbytes, outbytes, datetos(&Date, dbuf, NULL), Comment);
if (ListOnly)
goto nomatch;
if (TimeStampOnly)
goto matchskip;
openoutput(fname, 0, 0);
switch(type) {
case XFIL0:
transfer0(inbytes);
break;
case XFIL1:
CrcGen = 0;
CrcEna = 1;
UnCompressFile(inbytes);
CrcEna = 0;
save = CrcGen;
transfer1(); /* ??? needed ??? */
CrcGen = save;
break;
}
closeoutput();
matchskip:
DirPath[DPLen] = 0;
return(1);
nomatch:
DirPath[DPLen] = 0;
return(-1);
}
/*
* FILE SUPPORT
*/
static int Infd = -1;
static int Outfd = -1;
static long OutBytes;
int
openoutput(name, append, enabtail)
char *name;
{
char *ptr = name;
static NODE *VNode; /* Volume node */
long lock;
extern int errno;
if (Outfd >= 0) {
dumpoutput();
close(Outfd);
Outfd = -1;
}
if (enabtail) {
if (VNode)
VNode = GetSucc(VNode);
if (!VNode)
VNode = GetHead(&VList);
if (VNode) {
ptr = malloc(strlen(VNode->ln_Name)+strlen(name)+8);
sprintf(ptr, "%s%s.%02ld", VNode->ln_Name, name, BacCnt);
} else {
ptr = malloc(strlen(name)+8);
sprintf(ptr, "%s.%02ld", name, BacCnt);
}
}
OutBytes = 0;
while (GetHead(&VList)) {
short c;
short d;
fprintf(stderr, "Ready for %s (y=go,n=abort) -", ptr);
fflush(stderr);
if ((c = getc(stdin)) == EOF) {
fprintf(stderr, "EOF, aborted\n");
c = 'n';
}
while ((d = getc(stdin)) != EOF && d != '\n');
if ((c|0x20) == 'y')
break;
if ((c|0x20) == 'n')
goto skip;
}
if (enabtail && SaveLock) /* original directory */
lock = CurrentDir(SaveLock);
if (append) {
Outfd = open(ptr, O_WRONLY|O_CREAT|O_APPEND);
if (Outfd >= 0) {
OutBytes = lseek(Outfd, 0L, 2);
/* lseek(Outfd, 0L, 0); */
}
} else {
Outfd = open(ptr, O_WRONLY|O_CREAT|O_TRUNC);
}
if (enabtail && SaveLock) /* back to before */
CurrentDir(lock);
if (Outfd < 0)
printf("Unable to open output file %s (%ld)\n", ptr, errno);
skip:
BufI = 0;
if (enabtail)
free(ptr);
return(Outfd >= 0);
}
void
oputc(v)
char v;
{
++OutBytes;
if (Outfd >= 0) {
if (BufI == BufSize)
dumpoutput();
Buf[BufI++] = v;
}
}
void
outlwatseek(pos, lw)
long pos;
long lw;
{
long index = BufI + pos - OutBytes; /* index into buffer */
if (index > BufI - 4) {
puts("SW ERROR");
return;
}
if (index >= 0) {
Buf[index+0] = lw >> 24;
Buf[index+1] = lw >> 16;
Buf[index+2] = lw >> 8;
Buf[index+3] = lw;
} else { /* uh oh */
if (Outfd >= 0) {
long old = lseek(Outfd, 0, 1); /* save current pos */
lseek(Outfd, pos, 0); /* seek back */
write(Outfd, (char *)&lw, 4); /* write data */
lseek(Outfd, old, 0); /* seek to end */
}
}
}
void
owrite(buf, n)
void *buf;
long n;
{
register long avail;
OutBytes += n;
if (Outfd >= 0) {
while (BufI + n > BufSize) {
avail = BufSize - BufI;
movmem(buf, Buf + BufI, avail);
n -= avail;
buf = (void *)((char *)buf + avail);
BufI = BufSize;
dumpoutput();
}
movmem(buf, Buf + BufI, n);
BufI += n;
}
}
void
dumpoutput()
{
if (Outfd >= 0 && BufI) {
write(Outfd, Buf, BufI);
BufI = 0;
}
}
void
closeoutput()
{
if (Outfd >= 0) {
dumpoutput();
close(Outfd);
Outfd = -1;
}
}
long
outbytes()
{
return(OutBytes);
}
/*
* <type><len><buf>
*/
void
outentry(type, len, buf)
ubyte type;
int len;
void *buf;
{
OutBytes += len + 2;
if (Outfd >= 0) {
if (BufI + len + 2 >= BufSize)
dumpoutput();
Buf[BufI+0] = type;
Buf[BufI+1] = len;
movmem(buf, Buf+BufI+2, len);
BufI += len + 2;
}
}
ulong OMax;
int
openinput(name, offset)
char *name;
long offset;
{
if (Infd >= 0)
close(Infd);
Infd = open(name, O_RDONLY);
InBufI = InBufN = 0;
OMax = -1;
if (Infd >= 0 && offset)
lseek(Infd, offset, 0);
return(Infd >= 0);
}
void
closeinput()
{
if (Infd >= 0)
close(Infd);
Infd = -1;
}
void
seekinputend()
{
register long inbuf = InBufI - InBufN;
register long forward = OMax;
if (forward > inbuf) {
lseek(Infd, forward - inbuf, 1);
OMax = InBufI = InBufN = 0;
return;
}
InBufN += forward;
}
void
setinputbound(max)
long max;
{
OMax = max;
}
long
oread(buf, n)
void *buf;
long n;
{
long x = 0;
long avail;
if (Infd < 0)
return(0);
if (n > OMax)
n = OMax;
while (n > (avail = InBufI - InBufN)) {
if (InBufN == -1)
return(0);
movmem(InBuf + InBufN, buf, avail);
AppendCrc(buf, avail);
OMax-= avail;
n -= avail;
buf = (void *)((char *)buf + avail);
x += avail;
InBufI = read(Infd, InBuf, InBufSize);
InBufN = 0;
if (InBufI <= 0) {
InBufI = 0;
return(x);
}
}
movmem(InBuf + InBufN, buf, n);
AppendCrc(buf, n);
InBufN += n;
x += n;
OMax -= n;
return(x);
}
long
otellread()
{
long pos = 0;
if (Infd >= 0)
pos = lseek(Infd, 0L, 1) - (InBufI - InBufN);
return(pos);
}
int
oreadchar()
{
if (!OMax || Infd < 0)
return(-1);
if (InBufN == InBufI) {
if (InBufN < 0)
return(EOF);
InBufI = read(Infd, InBuf, InBufSize);
InBufN = 0;
if (InBufI == 0) {
InBufN = InBufI = -1;
return(-1);
}
}
if (CrcEna)
CrcGen = (CrcGen << 3) ^ InBuf[InBufN] ^ (CrcGen >> 29);
return((int)InBuf[InBufN++]);
}
void
AppendCrc(buf, bytes)
register ubyte *buf;
register long bytes;
{
if (CrcEna) {
while (bytes--)
CrcGen = (CrcGen << 3) ^ *buf++ ^ (CrcGen >> 29);
}
}
void
rollbackinput()
{
if (Infd >= 0)
lseek(Infd, 0L, 0);
InBufI = InBufN = 0;
}
void
mputc(v)
char v;
{
register SCOMP *sc = CWrite;
++CLen;
if (sc->N == sc->Bytes) {
sc = GetSucc(sc);
if (sc == NULL);
sc = NewSComp();
if (sc == NULL) {
puts("SCOMP FAILED");
return;
}
sc->N = 0;
CWrite = sc;
}
((char *)(sc + 1))[sc->N++] = v;
}
void
mwrite(buf, n)
char *buf;
long n;
{
register SCOMP *sc = CWrite;
register long avail;
CLen += n;
while ((avail = sc->Bytes - sc->N) < n) {
movmem(buf, (char *)(sc + 1) + sc->N, avail);
buf += avail;
n -= avail;
sc->N = sc->Bytes;
sc = GetSucc(sc);
if (sc == NULL)
sc = NewSComp();
if (sc == NULL) {
puts("SCOMP FAILED");
return;
}
sc->N = 0;
}
movmem(buf, (char *)(sc + 1) + sc->N, n);
sc->N += n;
CWrite = sc;
}
SCOMP *
NewSComp()
{
register SCOMP *sc = malloc(sizeof(SCOMP) + 8192);
if (sc) {
sc->Bytes = 8192;
sc->N = 0;
AddTail(&CList, sc);
}
return(sc);
}
void
transfer0(n)
long n;
{
register long len;
if (Outfd < 0)
return;
CrcGen = 0;
CrcEna = 1;
for (len = BufSize - BufI; n; len = BufSize - BufI) {
if (len == 0) {
dumpoutput();
len = BufSize;
}
if (n < len)
len = n;
oread(Buf + BufI, len);
BufI += len;
n -= len;
OutBytes += len;
}
CrcEna = 0;
}
/*
* Compression Routines
*
* transfer1() : Backup: copy compression buffer to output file
*/
void
transfer1()
{
register long len;
register SCOMP *sc = GetHead(&CList);
register ubyte *ptr;
long n = CLen;
if (Outfd < 0)
return;
CrcGen = 0;
CrcEna = 1;
for (sc = GetHead(&CList); sc && n; sc = GetSucc(sc)) {
len = sc->Bytes;
ptr = (ubyte *)(sc + 1);
if (n < len)
len = n;
n -= len;
AppendCrc(ptr, len);
while (len > BufSize - BufI) {
movmem(ptr, Buf + BufI, BufSize - BufI);
ptr += BufSize - BufI;
len -= BufSize - BufI;
OutBytes += BufSize - BufI;
BufI = BufSize;
dumpoutput();
}
movmem(ptr, Buf + BufI, len);
BufI += len;
OutBytes += len;
}
CrcEna = 0;
if (n)
puts("Unexpected EOF in compression file");
}
/*
* NoBack() returns true if 'NOBACK' is found in the fib_Comment
* field.
*/
NoBack(fib)
FIB *fib;
{
char *str = fib->fib_Comment;
while (*str) {
if (*str == 'N' && strncmp(str, "NOBACK", 6) == 0)
return(1);
++str;
}
return(0);
}
/*
* quick hack to fix some macro bugs...
*/
long
CTOB(cptr)
void *cptr;
{
return((long)cptr >> 2);
}
void *
BTOC(bptr)
long bptr;
{
return((void *)(bptr << 2));
}
void *
GetHead(list)
MLIST *list;
{
MNODE *node = list->mlh_Head;
if (node->mln_Succ)
return(node);
return(NULL);
}
void *
GetTail(list)
MLIST *list;
{
MNODE *node = list->mlh_TailPred;
if (node->mln_Pred)
return(node);
return(NULL);
}
void *
GetSucc(node)
MNODE *node;
{
node = node->mln_Succ;
if (node->mln_Succ)
return(node);
return(NULL);
}
void *
GetPred(node)
MNODE *node;
{
node = node->mln_Pred;
if (node->mln_Pred)
return(node);
return(NULL);
}