924 lines
17 KiB
C
924 lines
17 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
/* ar - archiver Author: Michiel Huisjes */
|
|
/* Made into arch/aal by Ceriel Jacobs
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
* Usage: [arch|aal] [qdprtx][vlcu] archive [file] ...
|
|
* possible key
|
|
* d: delete
|
|
* p: print named files
|
|
* q: append
|
|
* r: replace (append when not in archive)
|
|
* t: print contents of archive
|
|
* x: extract
|
|
* possible args
|
|
* c: don't give "create" message
|
|
* u: replace only if dated later than member in archive
|
|
* v: verbose
|
|
#ifdef DISTRIBUTION
|
|
* D: make distribution: use distr_time, uid=2, gid=2, mode=0644
|
|
#endif
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <signal.h>
|
|
#include "print.h"
|
|
#include "system.h"
|
|
#include "object.h"
|
|
#include "arch.h"
|
|
#include "ranlib.h"
|
|
|
|
/* UNIX specific */
|
|
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
|
|
#ifndef unix
|
|
#define unix
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef unix
|
|
#include <unistd.h>
|
|
#else
|
|
#define getuid() 0
|
|
#define getgid() 0
|
|
#endif
|
|
|
|
#ifdef AAL
|
|
#include "out.h"
|
|
#define MAGIC_NUMBER AALMAG
|
|
long offset;
|
|
struct ranlib *tab;
|
|
unsigned int tnum = 0;
|
|
char *tstrtab;
|
|
unsigned int tssiz = 0;
|
|
unsigned int tabsz, strtabsz;
|
|
#else
|
|
#define MAGIC_NUMBER ARMAG
|
|
#endif
|
|
|
|
#define odd(nr) (nr & 01)
|
|
#define even(nr) (odd(nr) ? nr + 1 : nr)
|
|
|
|
typedef char BOOL;
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
|
|
#define READ 0
|
|
#define APPEND 2
|
|
#define CREATE 1
|
|
|
|
#define MEMBER struct ar_hdr
|
|
|
|
#define NIL_PTR ((char *) 0)
|
|
#define NIL_MEM ((MEMBER *) 0)
|
|
#define NIL_LONG ((long *) 0)
|
|
|
|
#define IO_SIZE (10 * 1024)
|
|
|
|
#define equal(str1, str2) (!strncmp((str1), (str2), AR_NAME_MAX))
|
|
|
|
BOOL verbose;
|
|
BOOL app_fl;
|
|
BOOL ex_fl;
|
|
BOOL show_fl;
|
|
/* print files found in archive. */
|
|
BOOL pr_fl;
|
|
BOOL u_fl;
|
|
BOOL rep_fl;
|
|
BOOL del_fl;
|
|
BOOL nocr_fl;
|
|
BOOL local_fl;
|
|
#ifdef DISTRIBUTION
|
|
BOOL distr_fl;
|
|
time_t distr_time;
|
|
#endif
|
|
|
|
#ifndef S_ISUID
|
|
#define S_ISUID 0
|
|
#endif
|
|
#ifndef S_ISGID
|
|
#define S_ISGID 0
|
|
#endif
|
|
|
|
#define MODE_COUNT 11
|
|
|
|
char io_buffer[IO_SIZE];
|
|
|
|
char *progname;
|
|
|
|
char temp_buf[L_tmpnam];
|
|
char *temp_arch = &temp_buf[0];
|
|
|
|
void do_object(FILE* f, long size);
|
|
void do_names(struct outhead *headp);
|
|
void enter_name(struct outname *namep);
|
|
void write_symdef(FILE *ar);
|
|
|
|
void error(BOOL quit, char *str1, char *str2);
|
|
FILE* open_archive(char *name, int mode);
|
|
void
|
|
catch(int param);
|
|
MEMBER *get_member(FILE*);
|
|
void get(int argc, char *argv[]);
|
|
void add(char *name, FILE* ar, FILE* dst, char *mess);
|
|
void extract(FILE* ar, MEMBER *member);
|
|
void copy_member(MEMBER *member, FILE* from, FILE* to, BOOL extracting);
|
|
char *get_mode(int mode);
|
|
void wr_fatal(void);
|
|
void rd_fatal(void);
|
|
void mwrite(FILE* f, void* address, size_t bytes);
|
|
void show(char *s, char *name);
|
|
|
|
/* Conversion utilities. */
|
|
static mode_t ar2mode(short mode);
|
|
static short mode2ar(mode_t mode);
|
|
|
|
/** Maps an AR mode to the current system mode. */
|
|
struct modemap
|
|
{
|
|
short ar_mode;
|
|
mode_t mode;
|
|
};
|
|
|
|
/** Mapping table to map an AR mode to a system mode. */
|
|
static const struct modemap armodes[MODE_COUNT] =
|
|
{
|
|
{ AR_IRUSR, S_IRUSR },
|
|
{ AR_IWUSR, S_IWUSR },
|
|
{ AR_IXUSR, S_IXUSR },
|
|
|
|
{ AR_IRGRP, S_IRGRP },
|
|
{ AR_IWGRP, S_IWGRP },
|
|
{ AR_IXGRP, S_IXGRP },
|
|
|
|
{ AR_IROTH, S_IROTH },
|
|
{ AR_IWOTH, S_IWOTH },
|
|
{ AR_IXOTH, S_IXOTH },
|
|
|
|
{ AR_ISUID, S_ISUID },
|
|
{ AR_ISGID, S_ISGID } };
|
|
|
|
/** Convert an "ar" mode to a system specific
|
|
* mode.
|
|
*/
|
|
static mode_t ar2mode(short mode)
|
|
{
|
|
int i;
|
|
mode_t result = 0;
|
|
for (i = 0; i < MODE_COUNT; i++)
|
|
{
|
|
if (mode & armodes[i].ar_mode)
|
|
{
|
|
result = result | armodes[i].mode;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** Convert a system specified mode to
|
|
* an ar compatible mode.
|
|
*/
|
|
static short mode2ar(mode_t mode)
|
|
{
|
|
int i;
|
|
short result = 0;
|
|
for (i = 0; i < MODE_COUNT; i++)
|
|
{
|
|
if (mode & armodes[i].mode)
|
|
{
|
|
result = result | armodes[i].ar_mode;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
error(TRUE, "usage: %s [qdprtxl][vc] archive [file] ...\n", progname);
|
|
}
|
|
|
|
/*VARARGS2*/
|
|
void error(BOOL quit, char *str1, char *str2)
|
|
{
|
|
char errbuf[256];
|
|
|
|
sprint(errbuf, str1, str2);
|
|
fwrite(errbuf, strlen(errbuf), 1, stderr);
|
|
if (quit)
|
|
{
|
|
remove(temp_arch);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/** Opens the specified archive. */
|
|
FILE* open_archive(char *name, int mode)
|
|
{
|
|
unsigned short magic = 0;
|
|
FILE* file = NULL;
|
|
|
|
if (mode == CREATE)
|
|
{
|
|
file = fopen(name, "wb+");
|
|
if (file == NULL)
|
|
error(TRUE, "cannot create %s\n", name);
|
|
magic = MAGIC_NUMBER;
|
|
wr_int2(file, magic);
|
|
return file;
|
|
}
|
|
|
|
file = fopen(name, "rb");
|
|
if (file == NULL)
|
|
{
|
|
/* mode APPEND and files does not exist. */
|
|
if (mode == APPEND)
|
|
{
|
|
fclose(open_archive(name, CREATE));
|
|
if (!nocr_fl)
|
|
error(FALSE, "creating %s\n", name);
|
|
return open_archive(name, APPEND);
|
|
}
|
|
error(TRUE, "cannot open %s\n", name);
|
|
}
|
|
else
|
|
/* file already exists, simply open it for appending */
|
|
{
|
|
if (mode == APPEND)
|
|
{
|
|
fclose(file);
|
|
file = fopen(name, "a+b");
|
|
}
|
|
}
|
|
fseek(file, 0, SEEK_SET);
|
|
magic = rd_unsigned2(file);
|
|
if (magic != AALMAG && magic != ARMAG)
|
|
error(TRUE, "%s is not in ar format\n", name);
|
|
|
|
return file;
|
|
}
|
|
|
|
void
|
|
catch(int param)
|
|
{
|
|
remove(temp_arch);
|
|
exit(2);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
register char *ptr;
|
|
int needs_arg = 0;
|
|
|
|
progname = argv[0];
|
|
|
|
if (argc < 3)
|
|
usage();
|
|
|
|
for (ptr = argv[1]; *ptr; ptr++)
|
|
{
|
|
switch (*ptr)
|
|
{
|
|
case 't':
|
|
show_fl = TRUE;
|
|
break;
|
|
case 'v':
|
|
verbose = TRUE;
|
|
break;
|
|
case 'x':
|
|
ex_fl = TRUE;
|
|
break;
|
|
case 'q':
|
|
needs_arg = 1;
|
|
app_fl = TRUE;
|
|
break;
|
|
case 'c':
|
|
nocr_fl = TRUE;
|
|
break;
|
|
case 'u':
|
|
u_fl = TRUE;
|
|
break;
|
|
case 'p':
|
|
needs_arg = 1;
|
|
pr_fl = TRUE;
|
|
break;
|
|
case 'd':
|
|
needs_arg = 1;
|
|
del_fl = TRUE;
|
|
break;
|
|
case 'r':
|
|
needs_arg = 1;
|
|
rep_fl = TRUE;
|
|
break;
|
|
#ifdef DISTRIBUTION
|
|
case 'D' :
|
|
distr_fl = TRUE;
|
|
break;
|
|
#endif
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
|
|
if (needs_arg && argc <= 3)
|
|
usage();
|
|
#ifdef DISTRIBUTION
|
|
if (distr_fl)
|
|
{
|
|
static struct stat statbuf;
|
|
|
|
stat(progname, &statbuf);
|
|
distr_time = statbuf.st_mtime;
|
|
}
|
|
#endif
|
|
if (sys_tmpnam(temp_arch) == NULL)
|
|
{
|
|
error(TRUE, "Cannot create a temporary filename\n", NULL);
|
|
}
|
|
|
|
if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1)
|
|
usage();
|
|
|
|
if (u_fl && !rep_fl)
|
|
usage();
|
|
|
|
if (rep_fl || del_fl
|
|
#ifdef AAL
|
|
|| app_fl
|
|
#endif
|
|
)
|
|
{
|
|
/*fclose(mkstemp(temp_arch));*/
|
|
}
|
|
#ifdef AAL
|
|
tab = (struct ranlib *) malloc(512 * sizeof(struct ranlib));
|
|
tstrtab = malloc(4096);
|
|
if (!tab || !tstrtab)
|
|
error(TRUE, "Out of core\n", NULL);
|
|
tabsz = 512;
|
|
strtabsz = 4096;
|
|
#endif
|
|
|
|
signal(SIGINT,
|
|
catch);
|
|
get(argc, argv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Read next member of in the archive file "f". */
|
|
MEMBER *get_member(FILE *f)
|
|
{
|
|
static MEMBER member;
|
|
|
|
again:
|
|
if (rd_arhdr(f, &member) == 0)
|
|
return NIL_MEM;
|
|
if (member.ar_size < 0)
|
|
{
|
|
error(TRUE, "archive has member with negative size\n",NULL);
|
|
}
|
|
if (equal(SYMDEF, member.ar_name))
|
|
{
|
|
fseek(f, member.ar_size, SEEK_CUR);
|
|
goto again;
|
|
}
|
|
return &member;
|
|
}
|
|
|
|
void get(int argc, char *argv[])
|
|
{
|
|
register MEMBER *member;
|
|
FILE *ar_f;
|
|
int i = 0;
|
|
char buffer[FILENAME_MAX];
|
|
size_t read_chars;
|
|
FILE* temp_fd;
|
|
|
|
ar_f = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND);
|
|
if (rep_fl || del_fl
|
|
#ifdef AAL
|
|
|| app_fl
|
|
#endif
|
|
)
|
|
temp_fd = open_archive(temp_arch, CREATE);
|
|
while ((member = get_member(ar_f)) != NIL_MEM)
|
|
{
|
|
if (argc > 3)
|
|
{
|
|
for (i = 3; i < argc; i++)
|
|
{
|
|
sys_basename(argv[i],buffer);
|
|
if (equal(buffer, member->ar_name))
|
|
break;
|
|
}
|
|
if (i == argc || app_fl)
|
|
{
|
|
if (rep_fl || del_fl
|
|
#ifdef AAL
|
|
|| app_fl
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef AAL
|
|
if (i != argc)
|
|
{
|
|
print("%s: already in archive\n", argv[i]);
|
|
argv[i] = "";
|
|
}
|
|
#endif
|
|
wr_arhdr(temp_fd, member);
|
|
copy_member(member, ar_f, temp_fd, FALSE);
|
|
}
|
|
else
|
|
{
|
|
#ifndef AAL
|
|
if (app_fl && i != argc)
|
|
{
|
|
print("%s: already in archive\n", argv[i]);
|
|
argv[i] = "";
|
|
}
|
|
#endif
|
|
fseek(ar_f, even(member->ar_size),SEEK_CUR);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if (ex_fl || pr_fl)
|
|
extract(ar_f,member);
|
|
else
|
|
{
|
|
if (rep_fl)
|
|
add(argv[i], ar_f, temp_fd, "r - %s\n");
|
|
else if (show_fl)
|
|
{
|
|
char buf[sizeof(member->ar_name) + 2];
|
|
register char *p = buf, *q = member->ar_name;
|
|
|
|
while (q <= &member->ar_name[sizeof(member->ar_name)-1] && *q)
|
|
{
|
|
*p++ = *q++;
|
|
}
|
|
*p++ = '\n';
|
|
*p = '\0';
|
|
if (verbose)
|
|
{
|
|
char *mode = get_mode(member->ar_mode);
|
|
char *date = ctime(&(member->ar_date));
|
|
|
|
*(date + 16) = '\0';
|
|
*(date + 24) = '\0';
|
|
|
|
print("%s%3u/%u%7ld %s %s %s",
|
|
mode,
|
|
(unsigned) (member->ar_uid & 0377),
|
|
(unsigned) (member->ar_gid & 0377),
|
|
member->ar_size,
|
|
date+4,
|
|
date+20,
|
|
buf);
|
|
}
|
|
else print(buf);
|
|
}
|
|
else if (del_fl)
|
|
{
|
|
show("d - %s\n", member->ar_name);
|
|
}
|
|
fseek(ar_f, even(member->ar_size), SEEK_CUR);
|
|
}
|
|
argv[i] = "";
|
|
}
|
|
|
|
if (argc > 3)
|
|
{
|
|
for (i = 3; i < argc; i++)
|
|
if (argv[i][0] != '\0')
|
|
{
|
|
#ifndef AAL
|
|
if (app_fl)
|
|
add(argv[i], ar_f, "a - %s\n");
|
|
else
|
|
#endif
|
|
if (rep_fl
|
|
#ifdef AAL
|
|
|| app_fl
|
|
#endif
|
|
)
|
|
add(argv[i], ar_f, temp_fd, "a - %s\n");
|
|
else
|
|
{
|
|
print("%s: not found\n", argv[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rep_fl || del_fl
|
|
#ifdef AAL
|
|
|| app_fl
|
|
#endif
|
|
)
|
|
{
|
|
signal(SIGINT, SIG_IGN);
|
|
fclose(ar_f);
|
|
fclose(temp_fd);
|
|
ar_f = open_archive(argv[2], CREATE);
|
|
temp_fd = open_archive(temp_arch, APPEND);
|
|
#ifdef AAL
|
|
write_symdef(ar_f);
|
|
#endif
|
|
while ((read_chars = fread(io_buffer, 1, IO_SIZE, temp_fd)) > 0)
|
|
mwrite(ar_f, io_buffer, read_chars);
|
|
fclose(temp_fd);
|
|
remove(temp_arch);
|
|
}
|
|
fclose(ar_f);
|
|
}
|
|
|
|
/** Add an entry into the archive.
|
|
*
|
|
* @param[in] name path specification of the file to add.
|
|
* @param[in] ar Original ar file for update.
|
|
* @param[in] dst Archive name that will have its file added.
|
|
*
|
|
*/
|
|
void add(char *name, FILE* ar, FILE* dst, char *mess)
|
|
{
|
|
static MEMBER member;
|
|
size_t read_chars;
|
|
struct stat status;
|
|
char buffer[FILENAME_MAX];
|
|
FILE* src_fd = NULL;
|
|
|
|
if (stat(name, &status) < 0)
|
|
{
|
|
error(FALSE, "cannot find %s\n", name);
|
|
return;
|
|
}
|
|
else if (S_ISDIR(status.st_mode))
|
|
{
|
|
error(FALSE, "%s is a directory (ignored)\n", name);
|
|
return;
|
|
}
|
|
else if (u_fl && status.st_mtime <= member.ar_date)
|
|
{
|
|
wr_arhdr(dst, &member);
|
|
copy_member(&member, ar, dst, FALSE);
|
|
return;
|
|
}
|
|
else if ((src_fd = fopen(name, "rb")) == NULL)
|
|
{
|
|
error(FALSE, "cannot open %s\n", name);
|
|
return;
|
|
}
|
|
|
|
sys_basename(name, buffer);
|
|
strncpy (member.ar_name, buffer, sizeof(member.ar_name));
|
|
member.ar_uid = status.st_uid;
|
|
member.ar_gid = status.st_gid;
|
|
member.ar_mode = mode2ar(status.st_mode);
|
|
member.ar_date = status.st_mtime;
|
|
member.ar_size = status.st_size;
|
|
#ifdef DISTRIBUTION
|
|
if (distr_fl)
|
|
{
|
|
member.ar_uid = 2;
|
|
member.ar_gid = 2;
|
|
member.ar_mode = AR_IUSR | AR_IWUSR | AR_IRGRP | AR_IROTH;
|
|
member.ar_date = distr_time;
|
|
}
|
|
#endif
|
|
wr_arhdr(dst, &member);
|
|
#ifdef AAL
|
|
do_object(src_fd, member.ar_size);
|
|
fseek(src_fd, 0L, SEEK_SET);
|
|
offset += AR_TOTAL + even(member.ar_size);
|
|
#endif
|
|
while (status.st_size > 0)
|
|
{
|
|
size_t x = IO_SIZE;
|
|
|
|
read_chars = x;
|
|
if (status.st_size < x)
|
|
{
|
|
x = status.st_size;
|
|
read_chars = x;
|
|
status.st_size = 0;
|
|
x = even(x);
|
|
}
|
|
else status.st_size -= x;
|
|
if (fread(io_buffer, 1, read_chars, src_fd) != read_chars)
|
|
{
|
|
error(FALSE,"%s seems to shrink\n", name);
|
|
break;
|
|
}
|
|
mwrite(dst, io_buffer, x);
|
|
}
|
|
|
|
if (verbose)
|
|
show(mess, member.ar_name);
|
|
fclose(src_fd);
|
|
}
|
|
|
|
/** Extract an archive entry pointed to by member to
|
|
* either standard output or to a file.
|
|
*
|
|
*/
|
|
void extract(FILE* ar, MEMBER *member)
|
|
{
|
|
FILE* file = stdout;
|
|
char buf[sizeof(member->ar_name) + 1];
|
|
|
|
strncpy(buf, member->ar_name, sizeof(member->ar_name));
|
|
buf[sizeof(member->ar_name)] = 0;
|
|
if (pr_fl == FALSE)
|
|
{
|
|
file = fopen(buf, "wb");
|
|
if (file == NULL)
|
|
{
|
|
error(FALSE, "cannot create %s\n", buf);
|
|
file = NULL;
|
|
}
|
|
};
|
|
|
|
if (verbose)
|
|
{
|
|
if (pr_fl == FALSE)
|
|
show("x - %s\n", buf);
|
|
else
|
|
show("\n<%s>\n\n", buf);
|
|
}
|
|
|
|
copy_member(member, ar, file, TRUE);
|
|
|
|
if (file != NULL)
|
|
fclose(file);
|
|
if (pr_fl == FALSE)
|
|
chmod(buf, ar2mode(member->ar_mode));
|
|
}
|
|
|
|
void copy_member(MEMBER *member, FILE* from, FILE* to, BOOL extracting)
|
|
{
|
|
size_t rest;
|
|
long mem_size = member->ar_size;
|
|
BOOL is_odd = odd(mem_size) ? TRUE : FALSE;
|
|
|
|
#ifdef AAL
|
|
if (!extracting)
|
|
{
|
|
long pos = ftell(from);
|
|
|
|
do_object(from, mem_size);
|
|
offset += AR_TOTAL + even(mem_size);
|
|
fseek(from, pos, SEEK_SET);
|
|
}
|
|
#endif
|
|
do
|
|
{
|
|
rest = mem_size > (size_t) IO_SIZE ? IO_SIZE : (size_t) mem_size;
|
|
if (fread(io_buffer, 1, rest, from) != rest)
|
|
{
|
|
char buf[sizeof(member->ar_name) + 1];
|
|
|
|
strncpy(buf, member->ar_name, sizeof(member->ar_name));
|
|
buf[sizeof(member->ar_name)] = 0;
|
|
error(TRUE, "read error on %s\n", buf);
|
|
}
|
|
if (to != NULL)
|
|
mwrite(to, io_buffer, rest);
|
|
mem_size -= (long) rest;
|
|
} while (mem_size > 0L);
|
|
|
|
if (is_odd)
|
|
{
|
|
fseek(from, 1L, SEEK_CUR);
|
|
if ((to != NULL) && (extracting == FALSE))
|
|
fseek(to, 1L, SEEK_CUR);
|
|
}
|
|
}
|
|
|
|
char *get_mode(int mode)
|
|
{
|
|
static char mode_buf[11];
|
|
register int tmp = mode;
|
|
int i;
|
|
|
|
mode_buf[9] = ' ';
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
mode_buf[i * 3] = (tmp & AR_IRUSR) ? 'r' : '-';
|
|
mode_buf[i * 3 + 1] = (tmp & AR_IWUSR) ? 'w' : '-';
|
|
mode_buf[i * 3 + 2] = (tmp & AR_IXUSR) ? 'x' : '-';
|
|
tmp <<= 3;
|
|
}
|
|
if (mode & AR_ISUID)
|
|
mode_buf[2] = 's';
|
|
if (mode & AR_ISGID)
|
|
mode_buf[5] = 's';
|
|
return mode_buf;
|
|
}
|
|
|
|
void wr_fatal(void)
|
|
{
|
|
error(TRUE, "write error\n", NULL);
|
|
}
|
|
|
|
void rd_fatal(void)
|
|
{
|
|
error(TRUE, "read error\n", NULL);
|
|
}
|
|
|
|
void mwrite(FILE* f, void* address, size_t bytes)
|
|
{
|
|
if (fwrite(address, 1, bytes, f) != bytes)
|
|
error(TRUE, "write error\n", NULL);
|
|
}
|
|
|
|
void show(char *s, char *name)
|
|
{
|
|
MEMBER x;
|
|
char buf[sizeof(x.ar_name) + 1];
|
|
register char *p = buf, *q = name;
|
|
|
|
while (q <= &name[sizeof(x.ar_name) - 1] && *q)
|
|
*p++ = *q++;
|
|
*p++ = '\0';
|
|
print(s, buf);
|
|
}
|
|
|
|
#ifdef AAL
|
|
/*
|
|
* Write out the ranlib table: first 4 bytes telling how many ranlib structs
|
|
* there are, followed by the ranlib structs,
|
|
* then 4 bytes giving the size of the string table, followed by the string
|
|
* table itself.
|
|
*/
|
|
void write_symdef(FILE *ar)
|
|
{
|
|
register struct ranlib *ran;
|
|
register int i;
|
|
register long delta;
|
|
time_t time_value;
|
|
MEMBER arbuf;
|
|
|
|
if (!tnum)
|
|
return;
|
|
if (odd(tssiz))
|
|
tstrtab[tssiz++] = '\0';
|
|
for (i = 0; i < sizeof(arbuf.ar_name); i++)
|
|
arbuf.ar_name[i] = '\0';
|
|
strcpy(arbuf.ar_name, SYMDEF);
|
|
arbuf.ar_size = 4 + 2 * 4 * (long) tnum + 4 + (long) tssiz;
|
|
time(&time_value);
|
|
arbuf.ar_date = (long) time_value;
|
|
arbuf.ar_uid = getuid();
|
|
arbuf.ar_gid = getgid();
|
|
arbuf.ar_mode = AR_IRUSR | AR_IRGRP | AR_IROTH;
|
|
#ifdef DISTRIBUTION
|
|
if (distr_fl)
|
|
{
|
|
arbuf.ar_uid = 2;
|
|
arbuf.ar_gid = 2;
|
|
arbuf.ar_date = distr_time;
|
|
}
|
|
#endif
|
|
wr_arhdr(ar, &arbuf);
|
|
wr_long(ar, (long) tnum);
|
|
/*
|
|
* Account for the space occupied by the magic number
|
|
* and the ranlib table.
|
|
*/
|
|
delta = 2 + AR_TOTAL + arbuf.ar_size;
|
|
for (ran = tab; ran < &tab[tnum]; ran++)
|
|
{
|
|
ran->ran_pos += delta;
|
|
}
|
|
|
|
wr_ranlib(ar, tab, (long) tnum);
|
|
wr_long(ar, (long) tssiz);
|
|
wr_bytes(ar, tstrtab, (long) tssiz);
|
|
}
|
|
|
|
/*
|
|
* Return whether the bytes in `buf' form a good object header.
|
|
* The header is put in `headp'.
|
|
*/
|
|
int is_outhead(struct outhead *headp)
|
|
{
|
|
return !BADMAGIC(*headp) && headp->oh_nname != 0;
|
|
}
|
|
|
|
void do_object(FILE* f, long size)
|
|
{
|
|
struct outhead headbuf;
|
|
|
|
if (size < SZ_HEAD)
|
|
{
|
|
/* It can't be an object file. */
|
|
return;
|
|
}
|
|
/*
|
|
* Read a header to see if it is an object file.
|
|
*/
|
|
if (!rd_fdopen(f))
|
|
{
|
|
rd_fatal();
|
|
}
|
|
rd_ohead(&headbuf);
|
|
if (!is_outhead(&headbuf))
|
|
{
|
|
return;
|
|
}
|
|
do_names(&headbuf);
|
|
}
|
|
|
|
/*
|
|
* First skip the names and read in the string table, then seek back to the
|
|
* name table and read and write the names one by one. Update the ranlib table
|
|
* accordingly.
|
|
*/
|
|
void do_names(struct outhead *headp)
|
|
{
|
|
register char *strings = NULL;
|
|
register int nnames = headp->oh_nname;
|
|
#define NNAMES 100
|
|
struct outname namebuf[NNAMES];
|
|
long xxx = OFF_CHAR(*headp);
|
|
|
|
if ( (headp->oh_nchar != (unsigned int) headp->oh_nchar)
|
|
|| ((strings = malloc((unsigned int) headp->oh_nchar))) == NULL)
|
|
{
|
|
error(TRUE, "string table too big\n", NULL);
|
|
}
|
|
rd_string(strings, headp->oh_nchar);
|
|
while (nnames)
|
|
{
|
|
int i = nnames >= NNAMES ? NNAMES : nnames;
|
|
register struct outname *p = namebuf;
|
|
|
|
nnames -= i;
|
|
rd_name(namebuf, i);
|
|
while (i--)
|
|
{
|
|
long off = p->on_foff - xxx;
|
|
if (p->on_foff == (long) 0)
|
|
{
|
|
p++;
|
|
continue; /* An unrecognizable name. */
|
|
}
|
|
p->on_mptr = strings + off;
|
|
/*
|
|
* Only enter names that are exported and are really
|
|
* defined. Also enter common names. Note, that
|
|
* this might cause problems when the name is really
|
|
* defined in a later file, with a value != 0.
|
|
* However, this problem also exists on the Unix
|
|
* ranlib archives.
|
|
*/
|
|
if ((p->on_type & S_EXT) && (p->on_type & S_TYP) != S_UND)
|
|
enter_name(p);
|
|
p++;
|
|
}
|
|
}
|
|
free(strings);
|
|
}
|
|
|
|
void enter_name(struct outname *namep)
|
|
{
|
|
register char *cp;
|
|
|
|
if (tnum >= tabsz)
|
|
{
|
|
tab = (struct ranlib *) realloc((char *) tab,
|
|
(tabsz += 512) * sizeof(struct ranlib));
|
|
if (!tab)
|
|
error(TRUE, "Out of core\n", NULL);
|
|
}
|
|
tab[tnum].ran_off = tssiz;
|
|
tab[tnum].ran_pos = offset;
|
|
|
|
for (cp = namep->on_mptr;; cp++)
|
|
{
|
|
if (tssiz >= strtabsz)
|
|
{
|
|
tstrtab = realloc(tstrtab, (strtabsz += 4096));
|
|
if (!tstrtab)
|
|
error(TRUE, "string table overflow\n", NULL);
|
|
}
|
|
tstrtab[tssiz++] = *cp;
|
|
if (!*cp)
|
|
break;
|
|
}
|
|
tnum++;
|
|
}
|
|
#endif /* AAL */
|