home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
proglc
/
zoo141_c.lzh
/
ZOOPACK.C
< prev
Wrap
C/C++ Source or Header
|
1987-02-07
|
11KB
|
339 lines
/* zoopack.c */
/*
Copyright (C) 1986 Rahul Dhesi -- All rights reserved
*/
#include "options.h"
/* Packs an archive. The sequence is:
1. Copy all files from current archive to new one.
2. If the user didn't want a backup, delete the old archive
else rename it to same name with extension of .BAK.
3. Rename temporary archive to old name.
*/
/* define this to make packing noisless except for dots */
#define QUIETPACK 1
#include "portable.h"
#include <stdio.h>
#include "various.h"
#include "zoo.h"
#include "zoofns.h"
#include "errors.i"
#ifndef NOSIGNAL
#include <signal.h>
#endif
#ifdef FLAT
#include <types.h>
#include <stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#ifdef NOFCNTL
#include <file.h>
#else
#include <fcntl.h>
#endif
struct zoo_header zoo_header = {
TEXT,
ZOO_TAG,
(long) SIZ_ZOOH,
(long) (-SIZ_ZOOH),
MAJOR_VER,
MINOR_VER
};
char file_leader[] = FILE_LEADER;
extern int quiet;
int break_hit;
#ifdef LINT_ARGS
int ver_too_high (struct zoo_header *);
#else
int ver_too_high();
#endif
void zoopack(zoo_path, option)
char *zoo_path, *option;
{
char temp_file[PATHSIZE];
#ifndef NOSIGNAL
int (*oldsignal)();
#endif
register int zoo_han; /* handle for open archive */
register FILE *zoo_file; /* stream for open archive */
int new_han; /* handle of destination archive */
long next_ptr; /* pointer to within archive */
long new_dir_pos; /* ditto */
struct direntry direntry; /* directory entry */
struct zoo_header old_zoo_header; /* just for reading old header */
int status; /* error status */
int nobackup = 0; /* keep backup */
int force = 0; /* force overwrite of old backup */
int extcount = 0; /* how many files moved */
char backup_name[PATHSIZE]; /* name of backup */
int bad_header = 0; /* if archive has bad header */
int latest_date = 0; /* latest date on any file moved */
int latest_time = 0; /* ...likewise */
static char partial_msg[] =
"Partially packed archive left in %s.\n";
while (*option) {
switch (*option) {
case 'P': force++; break;
case 'E': nobackup++; break;
case 'q': quiet++; break;
default:
prterror ('f', inv_option, *option);
}
option++;
}
if (force == 1) /* force only if P was doubled */
force--;
/* Create a backup name by replacing any extension by backup extension. */
strcpy (backup_name, zoo_path);
{
char *temp;
if (temp = strrchr (backup_name,EXT_CH)) /* if dot found */
strcpy (temp, BACKUP_EXT); /* replace old extension */
else
strcat (backup_name, BACKUP_EXT); /* else just append */
}
/* Open original archive for read-only access */
if ((zoo_han = OPEN(zoo_path, F_READ)) == -1)
prterror ('f', could_not_open, zoo_path);
/* associate stream with handle. "r+" means read/write, must exist */
zoo_file = fdopen (zoo_han, "r+");
if (zoo_file == NULL)
prterror ('f', could_not_open, zoo_path);
/* Read the header of the old archive. */
frd_zooh(&old_zoo_header, zoo_file);
/* fread ((char *) &old_zoo_header, sizeof(old_zoo_header), 1, zoo_file); */
if ((old_zoo_header.zoo_start + old_zoo_header.zoo_minus) != 0L) {
prterror ('w', failed_consistency);
++bad_header; /* remember for future error message */
}
/* Refuse to pack it if its version number is higher than we can accept */
if (ver_too_high (&old_zoo_header))
prterror ('f', wrong_version, old_zoo_header.major_ver,
old_zoo_header.minor_ver);
fseek (zoo_file, old_zoo_header.zoo_start, 0); /* seek to where data begins */
/* Now see if the archive already exists with the backup extension. If so,
give an error message and abort. However, we skip this test if the user
specified overwriting the backup */
if (!force) {
if (exists (backup_name))
prterror ('f', "File %s already exists. Delete it or use PP option.\n",
backup_name);
}
/* Open the new archive by a temporary name. It is an error for it
to already exist */
strcpy(temp_file, "zXXXXXX");
mktemp(temp_file);
if (exists (temp_file))
prterror ('f', "%s already exists. Delete it and try again.\n",temp_file);
new_han = CREATE(temp_file, F_RDWR);
if (new_han == -1)
prterror ('f', "Could not create temporary file %s.\n", temp_file);
/* Write the header of the new archive, updated with our own data */
wr_zooh (&zoo_header, new_han);
/* write (new_han, (char *) &zoo_header, sizeof(zoo_header)); */
lseek (new_han, zoo_header.zoo_start, 0); /* position to add files */
/* Now we loop through the old archive's files and add each to the new
archive. The only changes needed are to update the .next and .offset
fields of the directory entry. */
while (1) {
frd_dir(&direntry, zoo_file);
/* fread ((char *) &direntry, sizeof (direntry), 1, zoo_file); */
if (direntry.zoo_tag != ZOO_TAG) {
long currpos, zoolength;
prterror ('F', bad_directory);
if (bad_header) { /* bad headers means don't save temp file */
close (new_han);
unlink (temp_file);
} else {
writenull (new_han, MAXDIRSIZE); /* write final null entry */
printf (partial_msg, temp_file);
if ((currpos = ftell (zoo_file)) != -1L)
if (fseek (zoo_file, 0L, 2) == 0)
if ((zoolength = ftell (zoo_file)) != -1L)
printf (cant_process, zoolength - currpos);
}
exit (1);
}
if (direntry.next == 0L) { /* END OF CHAIN */
break; /* EXIT on end of chain */
}
next_ptr = direntry.next; /* ptr to next dir entry */
if (!direntry.deleted) {
#ifdef QUIETPACK
/* nothing */
#else
prterror ('m', "%-14s -- ",
direntry.namlen > 0 ? direntry.lfname : direntry.fname);
#endif
if (lseek (zoo_han, direntry.offset, 0) == -1L) {
prterror ('f', "Could not seek to file data.\n");
} else {
extcount++; /* update count of files extracted */
/* write a directory entry for this file */
new_dir_pos = tell (new_han); /* new direntry pos in new archive */
/*
Write a null directory entry to preserve integrity in case of
program being interrupted. Note: I don't think it is
necessary to save direntry.next but I haven't checked.
Old code was:
writenull(new_han, SIZ_DIRL + direntry.var_dir_len);
*/
{
long oldnext;
oldnext = direntry.next;
direntry.next = 0L;
wr_dir(&direntry, new_han);
direntry.next = oldnext;
}
fseek (zoo_file, direntry.offset, 0); /* where to start copying */
lseek (zoo_han, direntry.offset, 0); /*DEBUG*/
/* Write file leader and remember position of new file data */
write (new_han, file_leader, SIZ_FLDR);
direntry.offset = tell(new_han);
status = getfile (zoo_han, new_han, direntry.size_now, 0);
/* if no error copy any comment attached to file */
if (status == 0 && direntry.cmt_size != 0) {
lseek (zoo_han, direntry.comment, 0); /* seek to old comment */
direntry.comment = tell (new_han); /* location of new comment */
status = getfile (zoo_han, new_han,
(long) direntry.cmt_size, 0);
}
if (status != 0) {
if (status == 1) {
memerr();
} else
if (status == 2 || status == 3) {
prterror ('F', disk_full);
printf (partial_msg, temp_file);
exit (1);
} else
prterror ('f', internal_error);
} else {
if (latest_date < direntry.date ||
(latest_date == direntry.date &&
latest_time < direntry.time)) {
latest_date = direntry.date;
latest_time = direntry.time;
}
}
direntry.next = tell (new_han);
lseek (new_han, new_dir_pos, 0); /* position to write direntry */
break_hit = 0;
#ifndef NOSIGNAL
oldsignal = signal (SIGINT, SIG_IGN);
if (oldsignal != SIG_IGN)
signal (SIGINT, handle_break);
#endif
if (wr_dir (&direntry, new_han) != -1 &&
write (new_han, file_leader, SIZ_FLDR) != -1) {
#ifdef QUIETPACK
/* prterror ('M', "."); */ ;
#else
prterror ('M', "moved\n");
#endif
} else
prterror ('f', "Write to temporary packed archive %s failed.\n", temp_file);
#ifndef NOSIGNAL
signal (SIGINT, oldsignal);
#endif
if (break_hit)
exit (1);
lseek (new_han, direntry.next, 0); /* back to end of new archive */
} /* end if (lseek ... */
} /* end if (!direntry.deleted) */
fseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */
} /* end while */
fclose (zoo_file);
/* write a final null entry */
writenull (new_han, MAXDIRSIZE);
#ifdef NIXTIME
close (new_han);
setutime (temp_file, latest_date, latest_time);
#else
settime (new_han, latest_date, latest_time); /* adjust its time */
close (new_han);
#endif
/* Important note: At this point, it is assumed that the archive was
packed and written to a new file without error. If control reaches
here without the new archive having been written properly, then
loss of data due to deletion of the original file could occur. In
other words, if something went wrong, execution MUST NOT reach here. */
if (extcount == 0) {
unlink (temp_file);
prterror ('m', "No files moved.\n");
} else {
char new_name[FNAMESIZE];
/* (a) if user requested, delete original, else rename it to
*.bak. (b) rename temp file to same base name as zoo_file. */
#ifdef QUIETPACK
/* prterror('M', "\n"); */
#endif
unlink (backup_name); /* remove any previous backup in any case */
if (nobackup)
unlink (zoo_path);
else
chname (backup_name, zoo_path);
basename (zoo_path, new_name);
if (chname (new_name, temp_file)) {
prterror ('w', "Renaming error. Packed archive is now in %s.\n", temp_file);
exit (1);
}
} /* end if */
} /* end zoopack() */
/* handle_break() */
/* Sets break_hit to 1 when called */
int handle_break()
{
#ifndef NOSIGNAL
signal (SIGINT, SIG_IGN); /* ignore future control ^Cs for now */
break_hit = 1;
#endif
}