home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Garbo
/
Garbo.cdr
/
mac
/
source
/
tarsrc.sit
/
extract.c
< prev
next >
Wrap
Text File
|
1989-09-14
|
8KB
|
361 lines
/*
* Macintosh Tar
*
* Modified by Craig Ruff for use on the Macintosh.
*/
/*
* Extract files from a tar archive.
*
* Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
*
* @(#) extract.c 1.17 86/10/29 Public Domain - gnu
*/
#include "tar.h"
extern union record *head; /* Points to current tape header */
extern struct stat {
long st_size;
long st_mtime;
} hstat; /* Fake stat struct for compat. */
Boolean ExtractArchive();
extern void PrintHeader();
extern Boolean SkipFile();
int MakeDirs(); /* Makes required directories */
/*
* Extract - extract the entire archive
*/
Extract() {
Point where;
SFReply reply;
/*
* Use the standard file dialog to select the archive.
*/
where.h = where.v = 75;
SFGetFile(where, "\pTar Archive:", nil, -1, nil, nil, &reply);
if (!reply.good)
return;
/*
* Remember the VRefNum and Name for OpenArchive.
* Find out where to put the extracted files.
*/
arVRefNum = reply.vRefNum;
arName = reply.fName;
if (GetDir("\pExtraction Directory:", true) == false)
return;
/*
* Extract and print the files as found in the archive.
*/
if (WindInit())
return;
TextFace(underline);
WPrintf(header);
TextFace(0);
ReadAnd(ExtractArchive);
CloseArchive();
WindEnd(autoPage);
}
/*
* Extract a file from the archive.
*/
Boolean
ExtractArchive()
{
register char *data;
register char *p;
union record *rec;
int i, namelen;
Boolean errFound = false;
long check, written;
long size;
OSErr err;
char macName[256];
HParamBlockRec dpb;
HParamBlockRec fpb;
char *routine = "\pExtractArchive";
SaveRec(&head); /* Make sure it sticks around */
UseRec(head); /* And go past it in the archive */
DecodeHeader(head, &hstat, 1); /* Snarf fields */
/* Print the record from 'head' and 'hstat' */
PrintHeader();
switch (head->header.linkflag) {
default:
WPrintf("Unknown file type %d for %s",
head->header.linkflag, head->header.name);
break;
case LF_OLDNORMAL:
case LF_NORMAL:
/*
* Appears to be a file.
* See if it's really a directory.
*/
namelen = strlen(head->header.name) - 1;
if (head->header.name[namelen] == '/')
goto really_dir;
FixName(head->header.name, macName);
again_file:
fpb.fileParam.ioCompletion = nil;
fpb.fileParam.ioNamePtr = macName;
fpb.fileParam.ioVRefNum = dirVRefNum;
fpb.fileParam.ioFVersNum = 0;
fpb.fileParam.ioDirID = 0;
err = PBHCreate(&fpb, false);
if (err == noErr) {
fpb.fileParam.ioCompletion = nil;
fpb.fileParam.ioNamePtr = macName;
fpb.fileParam.ioVRefNum = dirVRefNum;
fpb.fileParam.ioDirID = 0;
fpb.fileParam.ioFVersNum = 0;
fpb.fileParam.ioFDirIndex = 0;
if (PBHGetFInfo(&fpb, false)) {
OSAlert(routine, "\pPBHGetFInfo", macName,
fpb.fileParam.ioResult);
goto doNext;
}
strncpy(&fpb.fileParam.ioFlFndrInfo.fdCreator,
fdCreator, 4);
strncpy(&fpb.fileParam.ioFlFndrInfo.fdType, fdType, 4);
fpb.fileParam.ioCompletion = nil;
fpb.fileParam.ioNamePtr = macName;
fpb.fileParam.ioVRefNum = dirVRefNum;
fpb.fileParam.ioDirID = 0;
fpb.fileParam.ioFVersNum = 0;
if (PBHSetFInfo(&fpb, false)) {
OSAlert(routine, "\pPBHSetFInfo", macName,
fpb.fileParam.ioResult);
goto doNext;
}
fpb.ioParam.ioPermssn = fsWrPerm;
fpb.ioParam.ioMisc = nil;
err = PBHOpen(&fpb, false);
}
if (err != noErr) {
if (MakeDirs(macName))
goto again_file;
PgmAlert(routine, "\pCould not make file", macName);
errFound = SkipFile((long)hstat.st_size);
break;
}
/*
* Note that this only extracts data forks!
*/
for (size = hstat.st_size;
size > 0;
size -= written) {
/*
* Locate data, determine max length
* writeable, write it, record that
* we have used the data, then check
* if the write worked.
*/
if ((rec = FindRec()) == nil)
return(true);
data = rec->charptr;
written = EndOfRecs()->charptr - data;
if (written > size)
written = size;
/*
* Convert newlines to return for Mac compatability.
*/
if (cvtNl) {
for (i = written, p = data; --i >= 0; p++)
if (*p == LF)
*p = RETURN;
}
check = written;
fpb.ioParam.ioBuffer = data;
fpb.ioParam.ioReqCount = check;
fpb.ioParam.ioPosMode = fsAtMark;
fpb.ioParam.ioPosOffset = 0;
err = PBWrite((ParmBlkPtr) &fpb, false);
if (err != noErr) {
OSAlert(routine, "\pPBWrite", macName, err);
goto doNext;
}
check = fpb.ioParam.ioActCount;
/*
* The following is in violation of strict
* typing, since the arg to userec
* should be a struct rec *. FIXME.
*/
UseRec(data + written - 1);
if (check == written)
continue;
/*
* Error in writing to file.
* Print it, skip to next file in archive.
*/
PgmAlert(routine, "\pWrite short", macName);
doNext:
PBClose((ParmBlkPtr) &fpb, false);
errFound = SkipFile((long)(size - written));
goto quit;
}
PBClose((ParmBlkPtr) &fpb, false);
quit:
break;
case LF_DIR:
/* Check for trailing / */
namelen = strlen(head->header.name)-1;
really_dir:
while (namelen && head->header.name[namelen] == '/')
head->header.name[namelen--] = '\0'; /* Zap / */
FixName(head->header.name, macName);
/* FALL THROUGH */
again_dir:
dpb.fileParam.ioCompletion = nil;
dpb.fileParam.ioNamePtr = macName;
dpb.fileParam.ioVRefNum = dirVRefNum;
dpb.fileParam.ioFVersNum = 0;
dpb.fileParam.ioDirID = 0;
err = PBDirCreate(&dpb, false);
if ((err != noErr) && (err != dupFNErr)) {
if (MakeDirs(macName))
goto again_dir;
PgmAlert(routine, "\pCould not make directory", macName);
}
break;
}
/* We don't need to save it any longer. */
SaveRec((union record **) 0);
return(errFound);
}
/*
* After a file/link/symlink/dir creation has failed, see if
* it's because some required directory was not present, and if
* so, create all required dirs.
*/
int
MakeDirs(pathname)
char *pathname;
{
int madeone = 0; /* Did we do anything yet? */
int i, savedLen;
OSErr err;
HParamBlockRec pb;
savedLen = pathname[0] & 0xff;
/*
* skip initial ':'
*
* Note that the directory name has already been converted to Mac style.
*/
for (i = 2; i < savedLen; i++) {
while ((i < savedLen) && (pathname[i] != ':'))
i++;
if (i == savedLen)
break;
pathname[0] = i++ - 1;
pb.fileParam.ioCompletion = nil;
pb.fileParam.ioNamePtr = pathname;
pb.fileParam.ioVRefNum = dirVRefNum;
pb.fileParam.ioFVersNum = 0;
pb.fileParam.ioDirID = 0;
err = PBDirCreate(&pb, false);
if (err == dupFNErr) {
continue;
} else if (err != noErr) {
OSAlert("\pMakeDirs", "\pPBDirCreate", pathname,
pb.fileParam.ioResult);
return(0);
} else {
madeone++; /* Remember if we made one */
continue;
}
}
pathname[0] = savedLen;
return(madeone); /* Tell them to retry if we made one */
}
/*
* FixName - convert to a Mac style pathname
*
* Conversions:
* . -> (Stay at this directory level)
* .. -> :: (Up a directory level)
* .xxxx -> _xxxx (Don't get in trouble with device names)
* xx:xx -> xx/xx (Don't get in trouble with directory delims)
*/
FixName(tar, mac)
register char *tar;
char *mac;
{
char *end = tar + strlen(tar);
register char *p = mac + 1;
register char *next;
for (next = tar; tar < end; next++) {
/*
* Swallow up all contiguous '/' characters.
*/
while (*next && (*next == '/'))
next++;
/*
* Find the entire name up until the next '/'.
*/
tar = next;
while (*next && (*next != '/'))
next++;
*next = 0;
*p++ = ':';
if (*tar == '.')
switch (*(tar + 1)) {
case '\0':
p--;
continue;
case '.':
if (*(tar + 2) == 0)
continue;
/* else FALL THROUGH */
default:
*tar = '_';
}
while (tar < next) {
if (*tar == ':')
*tar = '/';
*p++ = *tar++;
}
}
*mac = p - mac - 1;
}