1991-09-24 12:03:40 +08:00
|
|
|
|
/* Library function for scanning an archive file.
|
2016-02-29 01:55:20 +08:00
|
|
|
|
Copyright (C) 1987-2016 Free Software Foundation, Inc.
|
2006-02-12 03:02:21 +08:00
|
|
|
|
This file is part of GNU Make.
|
|
|
|
|
|
|
|
|
|
GNU Make 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
|
2007-07-05 03:35:15 +08:00
|
|
|
|
Foundation; either version 3 of the License, or (at your option) any later
|
|
|
|
|
version.
|
2006-02-12 03:02:21 +08:00
|
|
|
|
|
|
|
|
|
GNU Make 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
|
2007-07-05 03:35:15 +08:00
|
|
|
|
this program. If not, see <http://www.gnu.org/licenses/>. */
|
1992-06-11 12:58:10 +08:00
|
|
|
|
|
2013-01-21 00:01:01 +08:00
|
|
|
|
#include "makeint.h"
|
1993-04-13 04:52:46 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
#ifdef TEST
|
|
|
|
|
/* Hack, the real error() routine eventually pulls in die from main.c */
|
|
|
|
|
#define error(a, b, c, d)
|
|
|
|
|
#endif
|
|
|
|
|
|
1993-04-13 04:52:46 +08:00
|
|
|
|
#ifdef HAVE_FCNTL_H
|
1992-06-11 12:58:10 +08:00
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <sys/file.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#ifndef NO_ARCHIVES
|
2006-11-19 04:53:44 +08:00
|
|
|
|
|
1997-08-28 04:30:54 +08:00
|
|
|
|
#ifdef VMS
|
|
|
|
|
#include <lbrdef.h>
|
|
|
|
|
#include <mhddef.h>
|
|
|
|
|
#include <credef.h>
|
|
|
|
|
#include <descrip.h>
|
|
|
|
|
#include <ctype.h>
|
2014-09-05 03:04:52 +08:00
|
|
|
|
#include <ssdef.h>
|
|
|
|
|
#include <stsdef.h>
|
|
|
|
|
#include <rmsdef.h>
|
|
|
|
|
|
2014-09-12 11:39:34 +08:00
|
|
|
|
/* This symbol should be present in lbrdef.h. */
|
|
|
|
|
#ifndef LBR$_HDRTRUNC
|
|
|
|
|
#pragma extern_model save
|
|
|
|
|
#pragma extern_model globalvalue
|
|
|
|
|
extern unsigned int LBR$_HDRTRUNC;
|
|
|
|
|
#pragma extern_model restore
|
|
|
|
|
#endif
|
|
|
|
|
|
1997-08-28 04:30:54 +08:00
|
|
|
|
#include <unixlib.h>
|
|
|
|
|
#include <lbr$routines.h>
|
2014-09-12 11:39:34 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
const char *
|
|
|
|
|
vmsify (const char *name, int type);
|
|
|
|
|
|
|
|
|
|
/* Time conversion from VMS to Unix
|
|
|
|
|
Conversion from local time (stored in library) to GMT (needed for gmake)
|
|
|
|
|
Note: The tm_gmtoff element is a VMS extension to the ANSI standard. */
|
|
|
|
|
static time_t
|
|
|
|
|
vms_time_to_unix(void *vms_time)
|
|
|
|
|
{
|
|
|
|
|
struct tm *tmp;
|
|
|
|
|
time_t unix_time;
|
|
|
|
|
|
|
|
|
|
unix_time = decc$fix_time(vms_time);
|
|
|
|
|
tmp = localtime(&unix_time);
|
|
|
|
|
unix_time -= tmp->tm_gmtoff;
|
|
|
|
|
|
|
|
|
|
return unix_time;
|
|
|
|
|
}
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* VMS library routines need static variables for callback */
|
|
|
|
|
static void *VMS_lib_idx;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
static const void *VMS_saved_arg;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
|
|
|
|
static long int (*VMS_function) ();
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
static long int VMS_function_ret;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a callback procedure for lib$get_index */
|
1997-08-28 04:30:54 +08:00
|
|
|
|
static int
|
2014-09-05 03:04:52 +08:00
|
|
|
|
VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa)
|
1997-08-28 04:30:54 +08:00
|
|
|
|
{
|
|
|
|
|
int status, i;
|
2014-09-05 03:04:52 +08:00
|
|
|
|
const int truncated = 0; /* Member name may be truncated */
|
|
|
|
|
time_t member_date; /* Member date */
|
|
|
|
|
char *filename;
|
|
|
|
|
unsigned int buffer_length; /* Actual buffer length */
|
|
|
|
|
|
|
|
|
|
/* Unused constants - Make does not actually use most of these */
|
|
|
|
|
const int file_desc = -1; /* archive file descriptor for reading the data */
|
|
|
|
|
const int header_position = 0; /* Header position */
|
|
|
|
|
const int data_position = 0; /* Data position in file */
|
|
|
|
|
const int data_size = 0; /* Data size */
|
|
|
|
|
const int uid = 0; /* member gid */
|
|
|
|
|
const int gid = 0; /* member gid */
|
|
|
|
|
const int mode = 0; /* member protection mode */
|
|
|
|
|
/* End of unused constants */
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
|
|
|
|
static struct dsc$descriptor_s bufdesc =
|
|
|
|
|
{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* Only need the module definition */
|
1997-08-28 04:30:54 +08:00
|
|
|
|
struct mhddef *mhd;
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* If a previous callback is non-zero, just return that status */
|
|
|
|
|
if (VMS_function_ret)
|
|
|
|
|
{
|
|
|
|
|
return SS$_NORMAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* lbr_set_module returns more than just the module header. So allocate
|
|
|
|
|
a buffer which is big enough: the maximum LBR$C_MAXHDRSIZ. That's at
|
|
|
|
|
least bigger than the size of struct mhddef.
|
|
|
|
|
If the request is too small, a buffer truncated warning is issued so
|
|
|
|
|
it can be reissued with a larger buffer.
|
|
|
|
|
We do not care if the buffer is truncated, so that is still a success. */
|
|
|
|
|
mhd = xmalloc(LBR$C_MAXHDRSIZ);
|
|
|
|
|
bufdesc.dsc$a_pointer = (char *) mhd;
|
|
|
|
|
bufdesc.dsc$w_length = LBR$C_MAXHDRSIZ;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
status = lbr$set_module(&VMS_lib_idx, rfa, &bufdesc, &buffer_length, 0);
|
|
|
|
|
|
|
|
|
|
if ((status != LBR$_HDRTRUNC) && !$VMS_STATUS_SUCCESS(status))
|
1997-08-28 04:30:54 +08:00
|
|
|
|
{
|
2014-09-05 03:04:52 +08:00
|
|
|
|
ON(error, NILF,
|
2013-11-24 11:23:52 +08:00
|
|
|
|
_("lbr$set_module() failed to extract module info, status = %d"),
|
|
|
|
|
status);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
lbr$close(&VMS_lib_idx);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
return status;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
#ifdef TEST
|
|
|
|
|
/* When testing this code, it is useful to know the length returned */
|
|
|
|
|
printf("Input length = %d, actual = %d\n",
|
|
|
|
|
bufdesc.dsc$w_length, buffer_length);
|
2000-01-22 13:43:03 +08:00
|
|
|
|
#endif
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* Conversion from VMS time to C time.
|
|
|
|
|
VMS defectlet - mhddef is sub-optimal, for the time, it has a 32 bit
|
|
|
|
|
longword, mhd$l_datim, and a 32 bit fill instead of two longwords, or
|
|
|
|
|
equivalent. */
|
|
|
|
|
member_date = vms_time_to_unix(&mhd->mhd$l_datim);
|
|
|
|
|
free(mhd);
|
|
|
|
|
|
|
|
|
|
/* Here we have a problem. The module name on VMS does not have
|
|
|
|
|
a file type, but the filename pattern in the "VMS_saved_arg"
|
|
|
|
|
may have one.
|
|
|
|
|
But only the method being called knows how to interpret the
|
|
|
|
|
filename pattern.
|
|
|
|
|
There are currently two different formats being used.
|
|
|
|
|
This means that we need a VMS specific code in those methods
|
|
|
|
|
to handle it. */
|
|
|
|
|
filename = xmalloc(module->dsc$w_length + 1);
|
|
|
|
|
|
|
|
|
|
/* TODO: We may need an option to preserve the case of the module
|
|
|
|
|
For now force the module name to lower case */
|
1997-08-28 04:30:54 +08:00
|
|
|
|
for (i = 0; i < module->dsc$w_length; i++)
|
2014-09-05 03:04:52 +08:00
|
|
|
|
filename[i] = _tolower((unsigned char )module->dsc$a_pointer[i]);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
|
|
|
|
filename[i] = '\0';
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
VMS_function_ret = (*VMS_function)(file_desc, filename, truncated,
|
|
|
|
|
header_position, data_position, data_size, member_date, uid, gid, mode,
|
|
|
|
|
VMS_saved_arg);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
free(filename);
|
|
|
|
|
return SS$_NORMAL;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
|
1997-08-28 04:30:54 +08:00
|
|
|
|
/* Takes three arguments ARCHIVE, FUNCTION and ARG.
|
|
|
|
|
|
|
|
|
|
Open the archive named ARCHIVE, find its members one by one,
|
|
|
|
|
and for each one call FUNCTION with the following arguments:
|
|
|
|
|
archive file descriptor for reading the data,
|
|
|
|
|
member name,
|
|
|
|
|
member name might be truncated flag,
|
|
|
|
|
member header position in file,
|
|
|
|
|
member data position in file,
|
|
|
|
|
member data size,
|
|
|
|
|
member date,
|
|
|
|
|
member uid,
|
|
|
|
|
member gid,
|
|
|
|
|
member protection mode,
|
|
|
|
|
ARG.
|
|
|
|
|
|
|
|
|
|
NOTE: on VMS systems, only name, date, and arg are meaningful!
|
|
|
|
|
|
|
|
|
|
The descriptor is poised to read the data of the member
|
|
|
|
|
when FUNCTION is called. It does not matter how much
|
|
|
|
|
data FUNCTION reads.
|
|
|
|
|
|
|
|
|
|
If FUNCTION returns nonzero, we immediately return
|
|
|
|
|
what FUNCTION returned.
|
|
|
|
|
|
|
|
|
|
Returns -1 if archive does not exist,
|
|
|
|
|
Returns -2 if archive has invalid format.
|
|
|
|
|
Returns 0 if have scanned successfully. */
|
|
|
|
|
|
|
|
|
|
long int
|
2013-11-24 11:23:52 +08:00
|
|
|
|
ar_scan (const char *archive, ar_member_func_t function, const void *varg)
|
1997-08-28 04:30:54 +08:00
|
|
|
|
{
|
2014-09-05 03:04:52 +08:00
|
|
|
|
char *vms_archive;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
|
|
|
|
static struct dsc$descriptor_s libdesc =
|
|
|
|
|
{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
const unsigned long func = LBR$C_READ;
|
|
|
|
|
const unsigned long type = LBR$C_TYP_UNK;
|
|
|
|
|
const unsigned long index = 1;
|
|
|
|
|
unsigned long lib_idx;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
int status;
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
VMS_saved_arg = varg;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* Null archive string can show up in test and cause an access violation */
|
|
|
|
|
if (archive == NULL)
|
1997-08-28 04:30:54 +08:00
|
|
|
|
{
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* Null filenames do not exist */
|
|
|
|
|
return -1;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* archive path name must be in VMS format */
|
|
|
|
|
vms_archive = (char *) vmsify(archive, 0);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
status = lbr$ini_control(&VMS_lib_idx, &func, &type, 0);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
if (!$VMS_STATUS_SUCCESS(status))
|
1997-08-28 04:30:54 +08:00
|
|
|
|
{
|
2014-09-05 03:04:52 +08:00
|
|
|
|
ON(error, NILF, _("lbr$ini_control() failed with status = %d"), status);
|
|
|
|
|
return -2;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
libdesc.dsc$a_pointer = vms_archive;
|
|
|
|
|
libdesc.dsc$w_length = strlen(vms_archive);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
status = lbr$open(&VMS_lib_idx, &libdesc, 0, NULL, 0, NULL, 0);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
if (!$VMS_STATUS_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* TODO: A library format failure could mean that this is a file
|
|
|
|
|
generated by the GNU AR utility and in that case, we need to
|
|
|
|
|
take the UNIX codepath. This will also take a change to the
|
|
|
|
|
GNV AR wrapper program. */
|
|
|
|
|
|
|
|
|
|
switch (status)
|
|
|
|
|
{
|
|
|
|
|
case RMS$_FNF:
|
|
|
|
|
/* Archive does not exist */
|
|
|
|
|
return -1;
|
|
|
|
|
default:
|
|
|
|
|
#ifndef TEST
|
|
|
|
|
OSN(error, NILF,
|
|
|
|
|
_("unable to open library '%s' to lookup member status %d"),
|
|
|
|
|
archive, status);
|
|
|
|
|
#endif
|
|
|
|
|
/* For library format errors, specification says to return -2 */
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
|
|
|
|
VMS_function = function;
|
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* Clear the return status, as we are supposed to stop calling the
|
|
|
|
|
callback function if it becomes non-zero, and this is a static
|
|
|
|
|
variable. */
|
|
|
|
|
VMS_function_ret = 0;
|
|
|
|
|
|
|
|
|
|
status = lbr$get_index(&VMS_lib_idx, &index, VMS_get_member_info, NULL, 0);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
lbr$close(&VMS_lib_idx);
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* Unless a failure occurred in the lbr$ routines, return the
|
|
|
|
|
the status from the 'function' routine. */
|
|
|
|
|
if ($VMS_STATUS_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
return VMS_function_ret;
|
|
|
|
|
}
|
1997-08-28 04:30:54 +08:00
|
|
|
|
|
2014-09-05 03:04:52 +08:00
|
|
|
|
/* This must be something wrong with the library and an error
|
|
|
|
|
message should already have been printed. */
|
|
|
|
|
return -2;
|
1997-08-28 04:30:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* !VMS */
|
|
|
|
|
|
1993-12-17 07:24:39 +08:00
|
|
|
|
/* SCO Unix's compiler defines both of these. */
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#ifdef M_UNIX
|
|
|
|
|
#undef M_XENIX
|
1993-12-17 07:24:39 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
1991-09-24 12:03:40 +08:00
|
|
|
|
/* On the sun386i and in System V rel 3, ar.h defines two different archive
|
|
|
|
|
formats depending upon whether you have defined PORTAR (normal) or PORT5AR
|
|
|
|
|
(System V Release 1). There is no default, one or the other must be defined
|
|
|
|
|
to have a nonzero value. */
|
|
|
|
|
|
1992-06-12 06:30:17 +08:00
|
|
|
|
#if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#undef PORTAR
|
1993-12-17 07:24:39 +08:00
|
|
|
|
#ifdef M_XENIX
|
|
|
|
|
/* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
|
|
|
|
|
PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
|
|
|
|
|
right one. */
|
|
|
|
|
#define PORTAR 0
|
|
|
|
|
#else
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#define PORTAR 1
|
|
|
|
|
#endif
|
1993-12-17 07:24:39 +08:00
|
|
|
|
#endif
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1999-02-22 15:23:30 +08:00
|
|
|
|
/* On AIX, define these symbols to be sure to get both archive formats.
|
|
|
|
|
AIX 4.3 introduced the "big" archive format to support 64-bit object
|
|
|
|
|
files, so on AIX 4.3 systems we need to support both the "normal" and
|
|
|
|
|
"big" archive formats. An archive's format is indicated in the
|
|
|
|
|
"fl_magic" field of the "FL_HDR" structure. For a normal archive,
|
|
|
|
|
this field will be the string defined by the AIAMAG symbol. For a
|
|
|
|
|
"big" archive, it will be the string defined by the AIAMAGBIG symbol
|
|
|
|
|
(at least on AIX it works this way).
|
|
|
|
|
|
|
|
|
|
Note: we'll define these symbols regardless of which AIX version
|
|
|
|
|
we're compiling on, but this is okay since we'll use the new symbols
|
|
|
|
|
only if they're present. */
|
|
|
|
|
#ifdef _AIX
|
|
|
|
|
# define __AR_SMALL__
|
|
|
|
|
# define __AR_BIG__
|
|
|
|
|
#endif
|
|
|
|
|
|
1999-07-07 05:09:32 +08:00
|
|
|
|
#ifndef WINDOWS32
|
2014-02-03 22:28:40 +08:00
|
|
|
|
# if !defined (__ANDROID__) && !defined (__BEOS__)
|
2000-04-22 10:11:17 +08:00
|
|
|
|
# include <ar.h>
|
|
|
|
|
# else
|
2014-02-03 22:28:40 +08:00
|
|
|
|
/* These platforms don't have <ar.h> but have archives in the same format
|
2000-04-22 10:11:17 +08:00
|
|
|
|
* as many other Unices. This was taken from GNU binutils for BeOS.
|
|
|
|
|
*/
|
2013-05-17 14:29:46 +08:00
|
|
|
|
# define ARMAG "!<arch>\n" /* String that begins an archive file. */
|
|
|
|
|
# define SARMAG 8 /* Size of that string. */
|
|
|
|
|
# define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
|
2000-04-22 10:11:17 +08:00
|
|
|
|
struct ar_hdr
|
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
char ar_name[16]; /* Member file name, sometimes / terminated. */
|
|
|
|
|
char ar_date[12]; /* File date, decimal seconds since Epoch. */
|
|
|
|
|
char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
|
|
|
|
|
char ar_mode[8]; /* File mode, in ASCII octal. */
|
|
|
|
|
char ar_size[10]; /* File size, in ASCII decimal. */
|
|
|
|
|
char ar_fmag[2]; /* Always contains ARFMAG. */
|
2000-04-22 10:11:17 +08:00
|
|
|
|
};
|
|
|
|
|
# endif
|
2010-07-06 02:32:03 +08:00
|
|
|
|
# define TOCHAR(_m) (_m)
|
1999-07-07 05:09:32 +08:00
|
|
|
|
#else
|
|
|
|
|
/* These should allow us to read Windows (VC++) libraries (according to Frank
|
|
|
|
|
* Libbrecht <frankl@abzx.belgium.hp.com>)
|
|
|
|
|
*/
|
|
|
|
|
# include <windows.h>
|
|
|
|
|
# include <windef.h>
|
|
|
|
|
# include <io.h>
|
|
|
|
|
# define ARMAG IMAGE_ARCHIVE_START
|
|
|
|
|
# define SARMAG IMAGE_ARCHIVE_START_SIZE
|
|
|
|
|
# define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
|
|
|
|
|
# define ar_name Name
|
|
|
|
|
# define ar_mode Mode
|
|
|
|
|
# define ar_size Size
|
|
|
|
|
# define ar_date Date
|
|
|
|
|
# define ar_uid UserID
|
|
|
|
|
# define ar_gid GroupID
|
2010-07-06 02:32:03 +08:00
|
|
|
|
/* In Windows the member names have type BYTE so we must cast them. */
|
|
|
|
|
# define TOCHAR(_m) ((char *)(_m))
|
1999-07-07 05:09:32 +08:00
|
|
|
|
#endif
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1992-06-03 09:07:39 +08:00
|
|
|
|
/* Cray's <ar.h> apparently defines this. */
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#ifndef AR_HDR_SIZE
|
|
|
|
|
# define AR_HDR_SIZE (sizeof (struct ar_hdr))
|
1992-06-03 09:07:39 +08:00
|
|
|
|
#endif
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
|
|
|
|
/* Takes three arguments ARCHIVE, FUNCTION and ARG.
|
|
|
|
|
|
|
|
|
|
Open the archive named ARCHIVE, find its members one by one,
|
|
|
|
|
and for each one call FUNCTION with the following arguments:
|
|
|
|
|
archive file descriptor for reading the data,
|
|
|
|
|
member name,
|
1993-04-30 09:08:30 +08:00
|
|
|
|
member name might be truncated flag,
|
1991-09-24 12:03:40 +08:00
|
|
|
|
member header position in file,
|
|
|
|
|
member data position in file,
|
|
|
|
|
member data size,
|
|
|
|
|
member date,
|
|
|
|
|
member uid,
|
|
|
|
|
member gid,
|
|
|
|
|
member protection mode,
|
|
|
|
|
ARG.
|
|
|
|
|
|
|
|
|
|
The descriptor is poised to read the data of the member
|
|
|
|
|
when FUNCTION is called. It does not matter how much
|
|
|
|
|
data FUNCTION reads.
|
|
|
|
|
|
|
|
|
|
If FUNCTION returns nonzero, we immediately return
|
|
|
|
|
what FUNCTION returned.
|
|
|
|
|
|
|
|
|
|
Returns -1 if archive does not exist,
|
|
|
|
|
Returns -2 if archive has invalid format.
|
|
|
|
|
Returns 0 if have scanned successfully. */
|
|
|
|
|
|
|
|
|
|
long int
|
2006-11-19 04:53:44 +08:00
|
|
|
|
ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
|
|
|
|
#ifdef AIAMAG
|
|
|
|
|
FL_HDR fl_header;
|
2013-07-22 05:52:13 +08:00
|
|
|
|
# ifdef AIAMAGBIG
|
1999-02-22 15:23:30 +08:00
|
|
|
|
int big_archive = 0;
|
|
|
|
|
FL_HDR_BIG fl_header_big;
|
2013-07-22 05:52:13 +08:00
|
|
|
|
# endif
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#endif
|
1993-04-27 04:43:32 +08:00
|
|
|
|
char *namemap = 0;
|
2006-11-19 04:53:44 +08:00
|
|
|
|
int desc = open (archive, O_RDONLY, 0);
|
1991-09-24 12:03:40 +08:00
|
|
|
|
if (desc < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
#ifdef SARMAG
|
|
|
|
|
{
|
|
|
|
|
char buf[SARMAG];
|
2016-03-06 04:21:59 +08:00
|
|
|
|
int nread;
|
|
|
|
|
EINTRLOOP (nread, read (desc, buf, SARMAG));
|
2006-04-10 06:09:24 +08:00
|
|
|
|
if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
#ifdef AIAMAG
|
|
|
|
|
{
|
2016-03-06 04:21:59 +08:00
|
|
|
|
int nread;
|
|
|
|
|
EINTRLOOP (nread, read (desc, &fl_header, FL_HSZ));
|
1999-02-22 15:23:30 +08:00
|
|
|
|
if (nread != FL_HSZ)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
}
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#ifdef AIAMAGBIG
|
|
|
|
|
/* If this is a "big" archive, then set the flag and
|
|
|
|
|
re-read the header into the "big" structure. */
|
2006-04-10 06:09:24 +08:00
|
|
|
|
if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
|
1999-02-22 15:23:30 +08:00
|
|
|
|
{
|
2016-03-06 04:21:59 +08:00
|
|
|
|
off_t o;
|
|
|
|
|
|
2013-05-17 14:29:46 +08:00
|
|
|
|
big_archive = 1;
|
|
|
|
|
|
|
|
|
|
/* seek back to beginning of archive */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (o, lseek (desc, 0, 0));
|
|
|
|
|
if (o < 0)
|
2013-05-17 14:29:46 +08:00
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* re-read the header into the "big" structure */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, &fl_header_big, FL_HSZ_BIG));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (nread != FL_HSZ_BIG)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
1999-02-22 15:23:30 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
/* Check to make sure this is a "normal" archive. */
|
2006-04-10 06:09:24 +08:00
|
|
|
|
if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
|
2013-05-17 14:29:46 +08:00
|
|
|
|
{
|
1999-02-22 15:23:30 +08:00
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
2013-05-17 14:29:46 +08:00
|
|
|
|
}
|
1991-09-24 12:03:40 +08:00
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
{
|
|
|
|
|
#ifndef M_XENIX
|
|
|
|
|
int buf;
|
|
|
|
|
#else
|
|
|
|
|
unsigned short int buf;
|
|
|
|
|
#endif
|
2016-03-06 04:21:59 +08:00
|
|
|
|
int nread;
|
|
|
|
|
EINTRLOOP (nread, read (desc, &buf, sizeof (buf)));
|
1991-09-24 12:03:40 +08:00
|
|
|
|
if (nread != sizeof (buf) || buf != ARMAG)
|
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Now find the members one by one. */
|
|
|
|
|
{
|
|
|
|
|
#ifdef SARMAG
|
|
|
|
|
register long int member_offset = SARMAG;
|
|
|
|
|
#else
|
|
|
|
|
#ifdef AIAMAG
|
|
|
|
|
long int member_offset;
|
|
|
|
|
long int last_member_offset;
|
|
|
|
|
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#ifdef AIAMAGBIG
|
|
|
|
|
if ( big_archive )
|
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
|
|
|
|
|
sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
|
1999-02-22 15:23:30 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
|
|
|
|
|
sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
|
1999-02-22 15:23:30 +08:00
|
|
|
|
}
|
1995-08-11 07:09:46 +08:00
|
|
|
|
|
|
|
|
|
if (member_offset == 0)
|
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
/* Empty archive. */
|
|
|
|
|
close (desc);
|
|
|
|
|
return 0;
|
1995-08-11 07:09:46 +08:00
|
|
|
|
}
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#else
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#ifndef M_XENIX
|
1991-09-24 12:03:40 +08:00
|
|
|
|
register long int member_offset = sizeof (int);
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#else /* Xenix. */
|
1991-09-24 12:03:40 +08:00
|
|
|
|
register long int member_offset = sizeof (unsigned short int);
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#endif /* Not Xenix. */
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
2013-05-17 14:29:46 +08:00
|
|
|
|
register int nread;
|
|
|
|
|
struct ar_hdr member_header;
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#ifdef AIAMAGBIG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
struct ar_hdr_big member_header_big;
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#endif
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#ifdef AIAMAG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
char name[256];
|
|
|
|
|
int name_len;
|
|
|
|
|
long int dateval;
|
|
|
|
|
int uidval, gidval;
|
|
|
|
|
long int data_offset;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#else
|
2013-05-17 14:29:46 +08:00
|
|
|
|
char namebuf[sizeof member_header.ar_name + 1];
|
|
|
|
|
char *name;
|
|
|
|
|
int is_namemap; /* Nonzero if this entry maps long names. */
|
2013-07-22 05:52:13 +08:00
|
|
|
|
int long_name = 0;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#endif
|
2013-05-17 14:29:46 +08:00
|
|
|
|
long int eltsize;
|
|
|
|
|
int eltmode;
|
|
|
|
|
long int fnval;
|
2016-03-06 04:21:59 +08:00
|
|
|
|
off_t o;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (o, lseek (desc, member_offset, 0));
|
|
|
|
|
if (o < 0)
|
2013-05-17 14:29:46 +08:00
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
|
|
|
|
#ifdef AIAMAG
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#ifdef AIAMAGBIG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (big_archive)
|
|
|
|
|
{
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, &member_header_big,
|
|
|
|
|
AR_MEMHDR_SZ(member_header_big)));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
|
|
|
|
|
if (nread != AR_MEMHDR_SZ(member_header_big))
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sscanf (member_header_big.ar_namlen, "%4d", &name_len);
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, name, name_len));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
|
|
|
|
|
if (nread != name_len)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name[name_len] = 0;
|
|
|
|
|
|
|
|
|
|
sscanf (member_header_big.ar_date, "%12ld", &dateval);
|
|
|
|
|
sscanf (member_header_big.ar_uid, "%12d", &uidval);
|
|
|
|
|
sscanf (member_header_big.ar_gid, "%12d", &gidval);
|
|
|
|
|
sscanf (member_header_big.ar_mode, "%12o", &eltmode);
|
|
|
|
|
sscanf (member_header_big.ar_size, "%20ld", &eltsize);
|
|
|
|
|
|
|
|
|
|
data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
|
|
|
|
|
+ name_len + 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#endif
|
2013-05-17 14:29:46 +08:00
|
|
|
|
{
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, &member_header,
|
|
|
|
|
AR_MEMHDR_SZ(member_header)));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
|
|
|
|
|
if (nread != AR_MEMHDR_SZ(member_header))
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sscanf (member_header.ar_namlen, "%4d", &name_len);
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, name, name_len));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
|
|
|
|
|
if (nread != name_len)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name[name_len] = 0;
|
|
|
|
|
|
|
|
|
|
sscanf (member_header.ar_date, "%12ld", &dateval);
|
|
|
|
|
sscanf (member_header.ar_uid, "%12d", &uidval);
|
|
|
|
|
sscanf (member_header.ar_gid, "%12d", &gidval);
|
|
|
|
|
sscanf (member_header.ar_mode, "%12o", &eltmode);
|
|
|
|
|
sscanf (member_header.ar_size, "%12ld", &eltsize);
|
|
|
|
|
|
|
|
|
|
data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
|
|
|
|
|
+ name_len + 2);
|
|
|
|
|
}
|
|
|
|
|
data_offset += data_offset % 2;
|
|
|
|
|
|
|
|
|
|
fnval =
|
|
|
|
|
(*function) (desc, name, 0,
|
|
|
|
|
member_offset, data_offset, eltsize,
|
|
|
|
|
dateval, uidval, gidval,
|
|
|
|
|
eltmode, arg);
|
|
|
|
|
|
|
|
|
|
#else /* Not AIAMAG. */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, &member_header, AR_HDR_SIZE));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (nread == 0)
|
|
|
|
|
/* No data left means end of file; that is OK. */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (nread != AR_HDR_SIZE
|
1999-07-22 12:31:11 +08:00
|
|
|
|
#if defined(ARFMAG) || defined(ARFZMAG)
|
2013-05-17 14:29:46 +08:00
|
|
|
|
|| (
|
1999-07-22 12:31:11 +08:00
|
|
|
|
# ifdef ARFMAG
|
2006-04-10 06:09:24 +08:00
|
|
|
|
memcmp (member_header.ar_fmag, ARFMAG, 2)
|
1999-07-22 12:31:11 +08:00
|
|
|
|
# else
|
|
|
|
|
1
|
|
|
|
|
# endif
|
|
|
|
|
&&
|
|
|
|
|
# ifdef ARFZMAG
|
2006-04-10 06:09:24 +08:00
|
|
|
|
memcmp (member_header.ar_fmag, ARFZMAG, 2)
|
1999-07-22 12:31:11 +08:00
|
|
|
|
# else
|
|
|
|
|
1
|
|
|
|
|
# endif
|
|
|
|
|
)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#endif
|
2013-05-17 14:29:46 +08:00
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = namebuf;
|
|
|
|
|
memcpy (name, member_header.ar_name, sizeof member_header.ar_name);
|
|
|
|
|
{
|
|
|
|
|
register char *p = name + sizeof member_header.ar_name;
|
|
|
|
|
do
|
|
|
|
|
*p = '\0';
|
|
|
|
|
while (p > name && *--p == ' ');
|
1993-04-27 04:43:32 +08:00
|
|
|
|
|
|
|
|
|
#ifndef AIAMAG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
/* If the member name is "//" or "ARFILENAMES/" this may be
|
|
|
|
|
a list of file name mappings. The maximum file name
|
|
|
|
|
length supported by the standard archive format is 14
|
|
|
|
|
characters. This member will actually always be the
|
|
|
|
|
first or second entry in the archive, but we don't check
|
|
|
|
|
that. */
|
|
|
|
|
is_namemap = (!strcmp (name, "//")
|
|
|
|
|
|| !strcmp (name, "ARFILENAMES/"));
|
|
|
|
|
#endif /* Not AIAMAG. */
|
|
|
|
|
/* On some systems, there is a slash after each member name. */
|
|
|
|
|
if (*p == '/')
|
|
|
|
|
*p = '\0';
|
1993-04-27 04:43:32 +08:00
|
|
|
|
|
|
|
|
|
#ifndef AIAMAG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
/* If the member name starts with a space or a slash, this
|
|
|
|
|
is an index into the file name mappings (used by GNU ar).
|
|
|
|
|
Otherwise if the member name looks like #1/NUMBER the
|
|
|
|
|
real member name appears in the element data (used by
|
|
|
|
|
4.4BSD). */
|
|
|
|
|
if (! is_namemap
|
|
|
|
|
&& (name[0] == ' ' || name[0] == '/')
|
|
|
|
|
&& namemap != 0)
|
|
|
|
|
{
|
|
|
|
|
name = namemap + atoi (name + 1);
|
|
|
|
|
long_name = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (name[0] == '#'
|
|
|
|
|
&& name[1] == '1'
|
|
|
|
|
&& name[2] == '/')
|
|
|
|
|
{
|
|
|
|
|
int namesize = atoi (name + 3);
|
|
|
|
|
|
|
|
|
|
name = alloca (namesize + 1);
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, name, namesize));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (nread != namesize)
|
|
|
|
|
{
|
|
|
|
|
close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
name[namesize] = '\0';
|
|
|
|
|
|
|
|
|
|
long_name = 1;
|
|
|
|
|
}
|
1993-04-27 04:43:32 +08:00
|
|
|
|
#endif /* Not AIAMAG. */
|
2013-05-17 14:29:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef M_XENIX
|
|
|
|
|
sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode);
|
|
|
|
|
eltsize = atol (TOCHAR (member_header.ar_size));
|
|
|
|
|
#else /* Xenix. */
|
|
|
|
|
eltmode = (unsigned short int) member_header.ar_mode;
|
|
|
|
|
eltsize = member_header.ar_size;
|
|
|
|
|
#endif /* Not Xenix. */
|
|
|
|
|
|
|
|
|
|
fnval =
|
|
|
|
|
(*function) (desc, name, ! long_name, member_offset,
|
|
|
|
|
member_offset + AR_HDR_SIZE, eltsize,
|
|
|
|
|
#ifndef M_XENIX
|
|
|
|
|
atol (TOCHAR (member_header.ar_date)),
|
|
|
|
|
atoi (TOCHAR (member_header.ar_uid)),
|
|
|
|
|
atoi (TOCHAR (member_header.ar_gid)),
|
|
|
|
|
#else /* Xenix. */
|
|
|
|
|
member_header.ar_date,
|
|
|
|
|
member_header.ar_uid,
|
|
|
|
|
member_header.ar_gid,
|
|
|
|
|
#endif /* Not Xenix. */
|
|
|
|
|
eltmode, arg);
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1992-06-12 06:30:17 +08:00
|
|
|
|
#endif /* AIAMAG. */
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (fnval)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return fnval;
|
|
|
|
|
}
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
|
|
|
|
#ifdef AIAMAG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (member_offset == last_member_offset)
|
|
|
|
|
/* End of the chain. */
|
|
|
|
|
break;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#ifdef AIAMAGBIG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (big_archive)
|
2007-07-05 03:35:15 +08:00
|
|
|
|
sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
|
2013-05-17 14:29:46 +08:00
|
|
|
|
else
|
1999-02-22 15:23:30 +08:00
|
|
|
|
#endif
|
2013-05-17 14:29:46 +08:00
|
|
|
|
sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (lseek (desc, member_offset, 0) != member_offset)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#else
|
1993-04-27 04:43:32 +08:00
|
|
|
|
|
2013-05-17 14:29:46 +08:00
|
|
|
|
/* If this member maps archive names, we must read it in. The
|
|
|
|
|
name map will always precede any members whose names must
|
|
|
|
|
be mapped. */
|
|
|
|
|
if (is_namemap)
|
|
|
|
|
{
|
|
|
|
|
char *clear;
|
|
|
|
|
char *limit;
|
|
|
|
|
|
|
|
|
|
namemap = alloca (eltsize);
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (nread, read (desc, namemap, eltsize));
|
2013-05-17 14:29:46 +08:00
|
|
|
|
if (nread != eltsize)
|
|
|
|
|
{
|
|
|
|
|
(void) close (desc);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The names are separated by newlines. Some formats have
|
|
|
|
|
a trailing slash. Null terminate the strings for
|
|
|
|
|
convenience. */
|
|
|
|
|
limit = namemap + eltsize;
|
|
|
|
|
for (clear = namemap; clear < limit; clear++)
|
|
|
|
|
{
|
|
|
|
|
if (*clear == '\n')
|
|
|
|
|
{
|
|
|
|
|
*clear = '\0';
|
|
|
|
|
if (clear[-1] == '/')
|
|
|
|
|
clear[-1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_namemap = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
member_offset += AR_HDR_SIZE + eltsize;
|
|
|
|
|
if (member_offset % 2 != 0)
|
|
|
|
|
member_offset++;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close (desc);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1997-08-28 04:30:54 +08:00
|
|
|
|
#endif /* !VMS */
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1993-04-30 09:08:30 +08:00
|
|
|
|
/* Return nonzero iff NAME matches MEM.
|
|
|
|
|
If TRUNCATED is nonzero, MEM may be truncated to
|
|
|
|
|
sizeof (struct ar_hdr.ar_name) - 1. */
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
|
|
|
|
int
|
2006-11-19 04:53:44 +08:00
|
|
|
|
ar_name_equal (const char *name, const char *mem, int truncated)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
2006-11-19 04:53:44 +08:00
|
|
|
|
const char *p;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
1999-10-15 15:00:58 +08:00
|
|
|
|
p = strrchr (name, '/');
|
1991-09-24 12:03:40 +08:00
|
|
|
|
if (p != 0)
|
|
|
|
|
name = p + 1;
|
|
|
|
|
|
1997-08-28 04:30:54 +08:00
|
|
|
|
#ifndef VMS
|
1993-04-30 09:08:30 +08:00
|
|
|
|
if (truncated)
|
|
|
|
|
{
|
1993-05-04 05:03:37 +08:00
|
|
|
|
#ifdef AIAMAG
|
|
|
|
|
/* TRUNCATED should never be set on this system. */
|
|
|
|
|
abort ();
|
|
|
|
|
#else
|
1993-04-30 09:08:30 +08:00
|
|
|
|
struct ar_hdr hdr;
|
1995-01-08 00:55:30 +08:00
|
|
|
|
#if !defined (__hpux) && !defined (cray)
|
2013-05-17 14:29:46 +08:00
|
|
|
|
return strneq (name, mem, sizeof (hdr.ar_name) - 1);
|
1994-02-17 05:32:01 +08:00
|
|
|
|
#else
|
2013-05-17 14:29:46 +08:00
|
|
|
|
return strneq (name, mem, sizeof (hdr.ar_name) - 2);
|
1995-01-08 00:55:30 +08:00
|
|
|
|
#endif /* !__hpux && !cray */
|
1998-07-31 04:54:47 +08:00
|
|
|
|
#endif /* !AIAMAG */
|
1993-04-30 09:08:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
1991-09-24 12:03:40 +08:00
|
|
|
|
return !strcmp (name, mem);
|
2014-09-05 03:04:52 +08:00
|
|
|
|
#else
|
|
|
|
|
/* VMS members do not have suffixes, but the filenames usually
|
|
|
|
|
have.
|
|
|
|
|
Do we need to strip VMS disk/directory format paths?
|
|
|
|
|
|
|
|
|
|
Most VMS compilers etc. by default are case insensitive
|
|
|
|
|
but produce uppercase external names, incl. module names.
|
|
|
|
|
However the VMS librarian (ar) and the linker by default
|
|
|
|
|
are case sensitive: they take what they get, usually
|
|
|
|
|
uppercase names. So for the non-default settings of the
|
|
|
|
|
compilers etc. there is a need to have a case sensitive
|
|
|
|
|
mode. */
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
len = strlen(mem);
|
|
|
|
|
int match;
|
|
|
|
|
char *dot;
|
|
|
|
|
if ((dot=strrchr(name,'.')))
|
|
|
|
|
match = (len == dot - name) && !strncasecmp(name, mem, len);
|
|
|
|
|
else
|
|
|
|
|
match = !strcasecmp (name, mem);
|
|
|
|
|
return match;
|
|
|
|
|
}
|
|
|
|
|
#endif /* !VMS */
|
1991-09-24 12:03:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
1997-08-28 04:30:54 +08:00
|
|
|
|
#ifndef VMS
|
1991-09-24 12:03:40 +08:00
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
static long int
|
2006-11-19 04:53:44 +08:00
|
|
|
|
ar_member_pos (int desc UNUSED, const char *mem, int truncated,
|
2013-05-17 14:29:46 +08:00
|
|
|
|
long int hdrpos, long int datapos UNUSED, long int size UNUSED,
|
2004-02-24 21:50:19 +08:00
|
|
|
|
long int date UNUSED, int uid UNUSED, int gid UNUSED,
|
2006-11-19 04:53:44 +08:00
|
|
|
|
int mode UNUSED, const void *name)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
1993-04-30 09:08:30 +08:00
|
|
|
|
if (!ar_name_equal (name, mem, truncated))
|
1991-09-24 12:03:40 +08:00
|
|
|
|
return 0;
|
|
|
|
|
return hdrpos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set date of member MEMNAME in archive ARNAME to current time.
|
|
|
|
|
Returns 0 if successful,
|
|
|
|
|
-1 if file ARNAME does not exist,
|
|
|
|
|
-2 if not a valid archive,
|
|
|
|
|
-3 if other random system call error (including file read-only),
|
|
|
|
|
1 if valid but member MEMNAME does not exist. */
|
|
|
|
|
|
|
|
|
|
int
|
2006-11-19 04:53:44 +08:00
|
|
|
|
ar_member_touch (const char *arname, const char *memname)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
2006-11-19 04:53:44 +08:00
|
|
|
|
long int pos = ar_scan (arname, ar_member_pos, memname);
|
2004-02-24 21:50:19 +08:00
|
|
|
|
int fd;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
struct ar_hdr ar_hdr;
|
2016-03-06 04:21:59 +08:00
|
|
|
|
off_t o;
|
|
|
|
|
int r;
|
2004-02-24 21:50:19 +08:00
|
|
|
|
unsigned int ui;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
|
|
if (pos < 0)
|
|
|
|
|
return (int) pos;
|
|
|
|
|
if (!pos)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (fd, open (arname, O_RDWR, 0666));
|
1991-09-24 12:03:40 +08:00
|
|
|
|
if (fd < 0)
|
|
|
|
|
return -3;
|
|
|
|
|
/* Read in this member's header */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (o, lseek (fd, pos, 0));
|
|
|
|
|
if (o < 0)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
goto lose;
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (r, read (fd, &ar_hdr, AR_HDR_SIZE));
|
|
|
|
|
if (r != AR_HDR_SIZE)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
goto lose;
|
|
|
|
|
/* Write back the header, thus touching the archive file. */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (o, lseek (fd, pos, 0));
|
|
|
|
|
if (o < 0)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
goto lose;
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
|
|
|
|
|
if (r != AR_HDR_SIZE)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
goto lose;
|
|
|
|
|
/* The file's mtime is the time we we want. */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (r, fstat (fd, &statbuf));
|
|
|
|
|
if (r < 0)
|
2001-06-01 11:56:50 +08:00
|
|
|
|
goto lose;
|
1999-07-24 06:46:47 +08:00
|
|
|
|
#if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
/* Advance member's time to that time */
|
2004-02-24 21:50:19 +08:00
|
|
|
|
for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
|
|
|
|
|
ar_hdr.ar_date[ui] = ' ';
|
2016-03-06 04:21:59 +08:00
|
|
|
|
sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime);
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#ifdef AIAMAG
|
2013-05-17 14:29:46 +08:00
|
|
|
|
ar_hdr.ar_date[strlen (ar_hdr.ar_date)] = ' ';
|
1991-09-24 12:03:40 +08:00
|
|
|
|
#endif
|
|
|
|
|
#else
|
|
|
|
|
ar_hdr.ar_date = statbuf.st_mtime;
|
|
|
|
|
#endif
|
|
|
|
|
/* Write back this member's header */
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (o, lseek (fd, pos, 0));
|
|
|
|
|
if (o < 0)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
goto lose;
|
2016-03-06 04:21:59 +08:00
|
|
|
|
EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
|
|
|
|
|
if (r != AR_HDR_SIZE)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
goto lose;
|
|
|
|
|
close (fd);
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
lose:
|
2016-03-06 04:21:59 +08:00
|
|
|
|
r = errno;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
close (fd);
|
2016-03-06 04:21:59 +08:00
|
|
|
|
errno = r;
|
1991-09-24 12:03:40 +08:00
|
|
|
|
return -3;
|
|
|
|
|
}
|
1997-08-28 04:30:54 +08:00
|
|
|
|
#endif
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
|
|
|
|
#ifdef TEST
|
|
|
|
|
|
|
|
|
|
long int
|
2006-11-19 04:53:44 +08:00
|
|
|
|
describe_member (int desc, const char *name, int truncated,
|
2013-05-17 14:29:46 +08:00
|
|
|
|
long int hdrpos, long int datapos, long int size,
|
2006-11-19 04:53:44 +08:00
|
|
|
|
long int date, int uid, int gid, int mode, const void *arg)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
|
|
|
|
extern char *ctime ();
|
|
|
|
|
|
2012-03-04 08:24:20 +08:00
|
|
|
|
printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"),
|
2013-05-17 14:29:46 +08:00
|
|
|
|
name, truncated ? _(" (name might be truncated)") : "",
|
|
|
|
|
size, hdrpos, datapos);
|
1999-07-28 14:23:37 +08:00
|
|
|
|
printf (_(" Date %s"), ctime (&date));
|
|
|
|
|
printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
|
1991-09-24 12:03:40 +08:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-15 05:54:04 +08:00
|
|
|
|
int
|
|
|
|
|
main (int argc, char **argv)
|
1991-09-24 12:03:40 +08:00
|
|
|
|
{
|
2006-11-19 04:53:44 +08:00
|
|
|
|
ar_scan (argv[1], describe_member, NULL);
|
1991-09-24 12:03:40 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-17 14:29:46 +08:00
|
|
|
|
#endif /* TEST. */
|
|
|
|
|
#endif /* NO_ARCHIVES. */
|