home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #3
/
amigamamagazinepolishissue1998.iso
/
ppc
/
lha_ppc
/
orig_src
/
lhadd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-08
|
14KB
|
624 lines
/*----------------------------------------------------------------------*/
/* LHarc Add Command */
/* This is part of LHarc UNIX Archiver Driver */
/* */
/* Copyright(C) MCMLXXXIX Yooichi.Tagawa */
/* */
/* V0.00 Original 1988.05.23 Y.Tagawa */
/* V1.00 Fixed 1989.09.22 Y.Tagawa */
/* V1.02 Bug fix 1990.01.19 Y.Tagawa */
/* V0.03 LHa for UNIX 1991.12.05 M.Oki */
/*----------------------------------------------------------------------*/
#include "lharc.h"
extern int encode_lzhuf ();
extern int encode_stored_crc ();
static char new_archive_name_buffer [ FILENAME_LENGTH ];
static char *new_archive_name;
FILE *temporary_fp = NULL;
/*----------------------------------------------------------------------*/
/* */
/*----------------------------------------------------------------------*/
static void
add_one (fp, nafp, hdr)
FILE *fp, *nafp;
LzHeader *hdr;
{
long header_pos, next_pos, org_pos, data_pos;
long v_original_size, v_packed_size;
reading_filename = hdr->name;
writting_filename = temporary_name;
if (!fp && generic_format) /* [generic] doesn't need directory info. */
return;
header_pos = ftell (nafp);
write_header (nafp, hdr); /* DUMMY */
if (hdr->original_size == 0) /* empty file or directory */
return; /* previous write_header is not DUMMY. (^_^) */
org_pos = ftell (fp);
data_pos = ftell (nafp);
hdr->crc = encode_lzhuf (fp, nafp, hdr->original_size,
&v_original_size, &v_packed_size, hdr->name, hdr->method);
if (v_packed_size < v_original_size)
{
next_pos = ftell (nafp);
}
else
{ /* retry by stored method */
fseek (fp, org_pos, SEEK_SET);
fseek (nafp, data_pos, SEEK_SET);
hdr->crc = encode_stored_crc (fp, nafp, hdr->original_size,
&v_original_size, &v_packed_size);
fflush (nafp);
next_pos = ftell (nafp);
#ifndef NOFTRUNCATE
ftruncate (fileno (nafp), next_pos);
#endif
bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
}
hdr->original_size = v_original_size;
hdr->packed_size = v_packed_size;
fseek (nafp, header_pos, SEEK_SET);
write_header (nafp, hdr);
fseek (nafp, next_pos, SEEK_SET);
}
FILE *
append_it (name, oafp, nafp)
char *name;
FILE *oafp, *nafp;
{
LzHeader ahdr, hdr;
FILE *fp;
long old_header;
int cmp;
int filec;
char **filev;
int i;
struct stat stbuf;
boolean directory;
if (stat (name, &stbuf) < 0)
{
error ("cannot access", name); /* See cleaning_files, Why? */
return oafp;
}
directory = is_directory (&stbuf);
init_header (name, &stbuf, &hdr);
if (!directory && !noexec)
fp = xfopen (name, READ_BINARY);
else
fp = NULL;
while (oafp)
{
old_header = ftell (oafp);
if (!get_header (oafp, &ahdr))
{
fclose (oafp);
oafp = NULL;
break;
}
else
{
cmp = STRING_COMPARE (ahdr.name, hdr.name);
if (cmp < 0)
{ /* SKIP */
/* copy old to new */
if (!noexec)
{
fseek (oafp, old_header, SEEK_SET);
copy_old_one (oafp, nafp, &ahdr);
}
else
fseek (oafp, ahdr.packed_size, SEEK_CUR);
}
else if (cmp == 0)
{ /* REPLACE */
/* drop old archive's */
fseek (oafp, ahdr.packed_size, SEEK_CUR);
break;
}
else /* cmp > 0, INSERT */
{
fseek (oafp, old_header, SEEK_SET);
break;
}
}
}
if (update_if_newer)
{
if (!oafp || /* not in archive */
cmp > 0 || /* // */
ahdr.unix_last_modified_stamp < /* newer than archive's */
hdr.unix_last_modified_stamp)
{
if (noexec)
printf ("ADD %s\n", name);
else
add_one (fp, nafp, &hdr);
}
else /* cmp == 0 */
{ /* copy old to new */
if (!noexec)
{
fseek (oafp, old_header, SEEK_SET);
copy_old_one (oafp, nafp, &ahdr);
}
}
}
else
{
if (!oafp || cmp > 0) /* not in archive or dropped */
{
if (noexec)
printf ("ADD %s\n", name);
else
add_one (fp, nafp, &hdr);
}
else /* cmp == 0 */ /* replace */
{
if (noexec)
printf ("REPLACE\n");
else
add_one (fp, nafp, &hdr);
}
}
if (!directory)
{
if (!noexec)
fclose (fp);
}
else
{ /* recurcive call */
if (find_files (name, &filec, &filev))
{
for (i = 0; i < filec; i ++)
oafp = append_it (filev[i], oafp, nafp);
free_files (filec, filev);
}
}
return oafp;
}
static void
find_update_files (oafp)
FILE *oafp; /* old archive */
{
char name[FILENAME_LENGTH];
struct string_pool sp;
LzHeader hdr;
long pos;
struct stat stbuf;
int len;
pos = ftell (oafp);
init_sp (&sp);
while (get_header (oafp, &hdr))
{
if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR)
{
if (stat (hdr.name, &stbuf) >= 0) /* exist ? */
add_sp (&sp, hdr.name, strlen (hdr.name) + 1);
}
else if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY)
{
strcpy (name, hdr.name);
len = strlen (name);
if (len > 0 && name[len - 1] == '/')
name[--len] = '\0'; /* strip tail '/' */
if (stat (name, &stbuf) >= 0) /* exist ? */
add_sp (&sp, name, len+1);
}
fseek (oafp, hdr.packed_size, SEEK_CUR);
}
fseek (oafp, pos, SEEK_SET);
finish_sp (&sp, &cmd_filec, &cmd_filev);
}
static void
delete (oafp, nafp)
FILE *oafp, *nafp;
{
LzHeader ahdr;
long old_header_pos;
old_header_pos = ftell (oafp);
while (get_header (oafp, &ahdr))
{
if (need_file (ahdr.name))
{ /* skip */
fseek (oafp, ahdr.packed_size, SEEK_CUR);
if (noexec)
printf ("DELETE %s\n", ahdr.name);
else if (verbose)
printf ("Delete %s\n", ahdr.name);
}
else
{ /* copy */
if (noexec)
{
fseek (oafp, ahdr.packed_size, SEEK_CUR);
}
else
{
fseek (oafp, old_header_pos, SEEK_SET);
copy_old_one (oafp, nafp, &ahdr);
}
}
old_header_pos = ftell (oafp);
}
return;
}
/*----------------------------------------------------------------------*/
/* */
/*----------------------------------------------------------------------*/
static FILE *
build_temporary_file ()
{
int old_umask;
FILE *afp;
build_temporary_name ();
signal (SIGINT, interrupt);
signal (SIGHUP, interrupt);
old_umask = umask (077);
afp = xfopen (temporary_name, WRITE_BINARY);
remove_temporary_at_error = TRUE;
temporary_fp = afp;
umask (old_umask);
return afp;
}
static void
build_backup_file ()
{
build_backup_name (backup_archive_name, archive_name);
if (!noexec)
{
signal (SIGINT, SIG_IGN);
signal (SIGHUP, SIG_IGN);
if (rename (archive_name, backup_archive_name) < 0)
fatal_error (archive_name);
recover_archive_when_interrupt = TRUE;
signal (SIGINT, interrupt);
signal (SIGHUP, interrupt);
}
}
static void
report_archive_name_if_different ()
{
if (!quiet && new_archive_name == new_archive_name_buffer)
{
/* warning at old archive is SFX */
printf ("New archive file is \"%s\"\n", new_archive_name);
}
}
#ifdef TMP_FILENAME_TEMPLATE
void
temporary_to_new_archive_file (new_archive_size)
long new_archive_size;
{
FILE *oafp, *nafp;
oafp = xfopen (temporary_name, READ_BINARY);
if (!strcmp(new_archive_name, "-"))
{
nafp = stdout;
writting_filename = "starndard output";
}
else
{
nafp = xfopen (new_archive_name, WRITE_BINARY);
writting_filename = archive_name;
}
reading_filename = temporary_name;
copyfile (oafp, nafp, new_archive_size, 0);
if (nafp != stdout) fclose (nafp);
fclose (oafp);
recover_archive_when_interrupt = FALSE;
unlink (temporary_name);
remove_temporary_at_error = FALSE;
}
#else
temporary_to_new_archive_file (new_archive_size)
long new_archive_size;
{
char *p;
p = (char *)rindex(new_archive_name,'/');
p = p ? p+1 : new_archive_name;
unlink ( new_archive_name );
if ( rename ( temporary_name , p )<0 ) {
fprintf(stderr, "Can't rename temporary_name '%s'\n", new_archive_name);
exit(1);
}
}
#endif
static void
set_archive_file_mode ()
{
int umask_value;
struct stat stbuf;
if (archive_file_gid < 0)
{
umask (umask_value = umask (0));
archive_file_mode = (~umask_value) & 0666; /* rw-rw-rw- */
if (stat (".", &stbuf) >= 0)
archive_file_gid = stbuf.st_gid;
}
if (archive_file_gid >= 0)
chown (new_archive_name, getuid (), archive_file_gid);
chmod (new_archive_name, archive_file_mode);
}
/*----------------------------------------------------------------------*/
/* REMOVE FILE/DIRECTORY */
/*----------------------------------------------------------------------*/
static void remove_files ();
static void
remove_one (name)
char *name;
{
struct stat stbuf;
int filec;
char **filev;
if (stat (name, &stbuf) < 0)
{
warning ("Cannot access", name);
}
else if (is_directory (&stbuf))
{
if (find_files (name, &filec, &filev))
{
remove_files (filec, filev);
free_files (filec, filev);
}
else
warning ("Cannot open directory", name);
if (noexec)
printf ("REMOVE DIRECTORY %s\n", name);
else if (rmdir (name) < 0)
warning ("Cannot remove directory", name);
else if (verbose)
printf ("Removed %s.\n", name);
}
else if (is_regularfile (&stbuf))
{
if (noexec)
printf ("REMOVE FILE %s.\n", name);
else if (unlink (name) < 0)
warning ("Cannot remove", name);
else if (verbose)
printf ("Removed %s.\n", name);
}
else
{
error ("Cannot remove (not a file or directory)", name);
}
}
static void
remove_files (filec, filev)
int filec;
char **filev;
{
int i;
for (i = 0; i < filec; i++)
remove_one (filev[i]);
}
/*----------------------------------------------------------------------*/
/* */
/*----------------------------------------------------------------------*/
void
cmd_add ()
{
LzHeader ahdr;
FILE *oafp, *nafp;
int i;
long old_header;
boolean old_archive_exist;
long new_archive_size;
/* exit if no operation */
if (!update_if_newer && cmd_filec == 0)
{
error ("No files given in argument, do nothing.", "");
return;
}
/* open old archive if exist */
if ((oafp = open_old_archive ()) == NULL)
old_archive_exist = FALSE;
else
old_archive_exist = TRUE;
if (update_if_newer && cmd_filec == 0 && !oafp)
fatal_error (archive_name); /* exit if cannot execute automatic update */
errno = 0;
if (new_archive && old_archive_exist)
{
fclose (oafp);
oafp = NULL;
}
if (oafp && archive_is_msdos_sfx1 (archive_name))
{
skip_msdos_sfx1_code (oafp);
build_standard_archive_name (new_archive_name_buffer, archive_name);
new_archive_name = new_archive_name_buffer;
}
else
{
new_archive_name = archive_name;
}
/* build temporary file */
if (!noexec)
nafp = build_temporary_file ();
/* find needed files when automatic update */
if (update_if_newer && cmd_filec == 0)
find_update_files (oafp);
/* build new archive file */
/* cleaning arguments */
cleaning_files (&cmd_filec, &cmd_filev);
if (cmd_filec == 0)
{
if (oafp)
fclose (oafp);
if (!noexec)
fclose (nafp);
return;
}
for (i = 0; i < cmd_filec; i ++)
oafp = append_it (cmd_filev[i], oafp, nafp);
if (oafp)
{
old_header = ftell (oafp);
while (get_header (oafp, &ahdr))
{
if (noexec)
fseek (oafp, ahdr.packed_size, SEEK_CUR);
else
{
fseek (oafp, old_header, SEEK_SET);
copy_old_one (oafp, nafp, &ahdr);
}
old_header = ftell (oafp);
}
fclose (oafp);
}
if (!noexec)
{
write_archive_tail (nafp);
new_archive_size = ftell (nafp);
fclose (nafp);
}
/* build backup archive file */
if (old_archive_exist)
build_backup_file ();
report_archive_name_if_different ();
/* copy temporary file to new archive file */
if (!noexec && (!strcmp(new_archive_name, "-") ||
rename (temporary_name, new_archive_name) < 0))
temporary_to_new_archive_file (new_archive_size);
/* set new archive file mode/group */
set_archive_file_mode ();
/* remove archived files */
if (delete_after_append)
remove_files (cmd_filec, cmd_filev);
return;
}
void
cmd_delete ()
{
FILE *oafp, *nafp;
long new_archive_size;
/* open old archive if exist */
if ((oafp = open_old_archive ()) == NULL)
fatal_error (archive_name);
errno = 0;
/* exit if no operation */
if (cmd_filec == 0)
{
fclose (oafp);
warning ("No files given in argument, do nothing.", "");
return;
}
if (archive_is_msdos_sfx1 (archive_name))
{
skip_msdos_sfx1_code (oafp);
build_standard_archive_name (new_archive_name_buffer, archive_name);
new_archive_name = new_archive_name_buffer;
}
else
{
new_archive_name = archive_name;
}
/* build temporary file */
if (!noexec)
nafp = build_temporary_file ();
/* build new archive file */
delete (oafp, nafp);
fclose (oafp);
if (!noexec)
{
write_archive_tail (nafp);
new_archive_size = ftell (nafp);
fclose (nafp);
}
/* build backup archive file */
build_backup_file ();
report_archive_name_if_different ();
/* copy temporary file to new archive file */
if (!noexec && rename (temporary_name, new_archive_name) < 0)
temporary_to_new_archive_file (new_archive_size);
/* set new archive file mode/group */
set_archive_file_mode ();
return;
}