home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
binutils-1.8.x-src.lha
/
GNU
/
src
/
amiga
/
binutils-1.8.x
/
ar.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-21
|
47KB
|
2,003 lines
/* ar.c - Archive modify and extract.
Copyright (C) 1988 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <ar.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#if !defined(A_OUT) && !defined(MACH_O)
#define A_OUT
#endif
#ifdef A_OUT
#ifdef COFF_ENCAPSULATE
#include "a.out.encap.h"
#else
#include <a.out.h>
#endif
#endif
#ifdef MACH_O
#ifndef A_OUT
#include <nlist.h>
#endif
#include <sys/loader.h>
#endif
#ifdef USG
#include <time.h>
#include <fcntl.h>
#else
#include <sys/file.h>
#include <sys/time.h>
#endif
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
# ifdef sparc
# include <alloca.h>
# else
char *alloca ();
# endif
#endif
#ifdef USG
#define bcopy(source, dest, size) memcpy((dest), (source), (size))
#define bcmp(a, b, size) memcmp((a), (b), (size))
#define bzero(s, size) memset((s), 0, (size))
#endif
/* Locking is normally disabled because fcntl hangs on the Sun
and it isn't supported properly across NFS anyway. */
#ifdef LOCKS
/* You might need to compile with -I/usr/include/sys if your fcntl.h
isn't in /usr/include (which is where it should be according to POSIX). */
#include <fcntl.h>
#endif
/* This structure is used internally to represent the info
on a member of an archive. This is to make it easier to change format. */
struct member_desc
{
/* Name of member. */
char *name;
/* The following fields are stored in the member header as decimal or octal
numerals, but in this structure they are stored as machine numbers. */
int mode; /* Protection mode from member header. */
long int date; /* Last modify date as stored in member header. */
unsigned int size; /* Bytes of member's data, from member header. */
int uid, gid; /* UID and GID fields copied from member header. */
unsigned int offset;/* Offset in archive of the header of this member. */
unsigned int data_offset;/* Offset of first data byte of the member. */
/* The next field does not describe where the member was in the
old archive, but rather where it will be in the modified archive.
It is set up by write_archive. */
unsigned int new_offset; /* Offset of this member in new archive */
/* Symdef data for member. Used only for files being inserted. */
struct symdef *symdefs;
unsigned int nsymdefs; /* Number of entries of symdef data. */
unsigned int string_size; /* Size of strings needed by symdef data. */
};
/* Each symbol is recorded by something like this. */
struct symdef
{
union
{
unsigned long int stringoffset;
char *name;
} s;
unsigned long int offset;
};
/* Nonzero means it's the name of an existing member;
position new or moved files with respect to this one. */
char *posname;
/* How to use `posname':
POS_BEFORE means position before that member.
POS_AFTER means position after that member.
POS_DEFAULT if position by default; then `posname' should also be zero. */
enum { POS_DEFAULT, POS_BEFORE, POS_AFTER } postype;
/* Nonzero means describe each action performed. */
int verbose;
/* Nonzero means don't warn about creating the archive file if necessary. */
int silent_create;
/* Nonzero means don't replace existing members whose
dates are more recent than the corresponding files. */
int newer_only;
/* Nonzero means preserve dates of members when extracting them. */
int preserve_dates;
/* Operation to be performed. */
#define DELETE 1
#define REPLACE 2
#define PRINT_TABLE 3
#define PRINT_FILES 4
#define EXTRACT 5
#define MOVE 6
#define QUICK_APPEND 7
int operation;
/* Name of archive file. */
char *archive;
/* Descriptor on which we have locked the original archive file,
or -1 if this has not been done. */
int lock_indesc;
/* Pointer to tail of `argv', at first subfile name argument,
or zero if no such were specified. */
char **files;
/* Nonzero means write a __.SYMDEF member into the modified archive. */
int symdef_flag;
/* Nonzero means __.SYMDEF member exists in old archive. */
int symdef_exists;
/* Nonzero means don't update __.SYMDEF unless the flag was given. */
int ignore_symdef;
/* Total number of symdef entries we will have. */
unsigned long int nsymdefs;
/* Symdef data from old archive (set up only if we need it) */
struct symdef *old_symdefs;
/* Number of symdefs in remaining in old_symdefs. */
unsigned int num_old_symdefs;
/* Number of symdefs old_symdefs had when it was read in. */
unsigned long int original_num_symdefs;
/* String table from old __.SYMDEF member. */
char *old_strings;
/* Size of old_strings */
unsigned long int old_strings_size;
/* String table to be written into __.SYMDEF member. */
char *new_strings;
/* Size of new_strings */
unsigned long int new_strings_size;
/* An archive map is a chain of these structures.
Each structure describes one member of the archive.
The chain is in the same order as the members are. */
struct mapelt
{
struct member_desc info;
struct mapelt *next;
};
struct mapelt *maplast;
/* If nonzero, this is the map-element for the __.SYMDEF member
and we should update the time of that member just before finishing. */
struct mapelt *symdef_mapelt;
/* Header that we wrote for the __.SYMDEF member. */
struct ar_hdr symdef_header;
char *xmalloc (), *xrealloc ();
void free ();
void add_to_map (), delete_from_map ();
int insert_in_map ();
void print_descr ();
char *concat ();
void scan ();
void extract_members ();
void extract_member ();
void print_contents ();
void write_symdef_member ();
void read_old_symdefs ();
void two_operations ();
void usage (), fatal (), error (), error_with_file ();
void perror_with_name (), pfatal_with_name ();
void write_archive ();
void touch_symdef_member ();
void update_symdefs ();
void delete_members (), move_members (), replace_members ();
void quick_append ();
/* Output BYTES of data at BUF to the descriptor DESC.
FILE is the name of the file (for error messages). */
void
mywrite (desc, buf, bytes, file)
int desc;
char *buf;
int bytes;
char *file;
{
register int val;
while (bytes > 0)
{
val = write (desc, buf, bytes);
if (val <= 0)
perror_with_name (file);
buf += val;
bytes -= val;
}
}
int
main (argc, argv)
int argc;
char **argv;
{
int i;
operation = 0;
verbose = 0;
newer_only = 0;
silent_create = 0;
posname = 0;
postype = POS_DEFAULT;
preserve_dates = 0;
symdef_flag = 0;
symdef_exists = 0;
ignore_symdef = 0;
symdef_mapelt = 0;
files = 0;
lock_indesc = -1;
if (argc < 2)
usage ("too few command arguments", 0);
{
char *key = argv[1];
char *p = key;
char c;
while (c = *p++)
{
switch (c)
{
case 'a':
postype = POS_AFTER;
break;
case 'b':
postype = POS_BEFORE;
break;
case 'c':
silent_create = 1;
break;
case 'd':
if (operation)
two_operations ();
operation = DELETE;
break;
case 'i':
postype = POS_BEFORE;
break;
case 'l':
break;
case 'm':
if (operation)
two_operations ();
operation = MOVE;
break;
case 'o':
preserve_dates = 1;
break;
case 'p':
if (operation)
two_operations ();
operation = PRINT_FILES;
break;
case 'q':
if (operation)
two_operations ();
operation = QUICK_APPEND;
break;
case 'r':
if (operation)