* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)archive.c 5.7 (Berkeley) 3/21/91";
extern CHDR chdr
; /* converted header */
extern char *archive
; /* archive name */
typedef struct ar_hdr HDR
;
static char hb
[sizeof(HDR
) + 1]; /* real header */
if ((fd
= open(archive
, mode
, DEFFILEMODE
)) >= 0) {
/* POSIX.2 puts create message on stderr. */
"ar: creating archive %s.\n", archive
);
if ((fd
= open(archive
, mode
, DEFFILEMODE
)) < 0)
* Attempt to place a lock on the opened file - if we get an
* error then someone is already working on this library (or
* it's going across NFS).
opened
: if (flock(fd
, LOCK_EX
|LOCK_NB
) && errno
!= EOPNOTSUPP
)
* If not created, O_RDONLY|O_RDWR indicates that it has to be
((mode
& O_ACCMODE
) == O_RDONLY
|| (mode
& O_ACCMODE
) == O_RDWR
)) {
if ((nr
= read(fd
, buf
, SARMAG
) != SARMAG
)) {
} else if (bcmp(buf
, ARMAG
, SARMAG
))
} else if (write(fd
, ARMAG
, SARMAG
) != SARMAG
)
(void)close(fd
); /* Implicit unlock. */
/* Convert ar header field to an integer. */
#define AR_ATOI(from, to, len, base) { \
to = strtol(buf, (char **)NULL, base); \
* read the archive header for this member
register char *p
, buf
[20];
nr
= read(fd
, hb
, sizeof(HDR
));
hdr
= (struct ar_hdr
*)hb
;
if (strncmp(hdr
->ar_fmag
, ARFMAG
, sizeof(ARFMAG
) - 1))
/* Convert the header into the internal format. */
AR_ATOI(hdr
->ar_date
, chdr
.date
, sizeof(hdr
->ar_date
), DECIMAL
);
AR_ATOI(hdr
->ar_uid
, chdr
.uid
, sizeof(hdr
->ar_uid
), DECIMAL
);
AR_ATOI(hdr
->ar_gid
, chdr
.gid
, sizeof(hdr
->ar_gid
), DECIMAL
);
AR_ATOI(hdr
->ar_mode
, chdr
.mode
, sizeof(hdr
->ar_mode
), OCTAL
);
AR_ATOI(hdr
->ar_size
, chdr
.size
, sizeof(hdr
->ar_size
), DECIMAL
);
/* Leading spaces should never happen. */
if (hdr
->ar_name
[0] == ' ')
* Long name support. Set the "real" size of the file, and the
if (!bcmp(hdr
->ar_name
, AR_EFMT1
, sizeof(AR_EFMT1
) - 1)) {
chdr
.lname
= len
= atoi(hdr
->ar_name
+ sizeof(AR_EFMT1
) - 1);
if (len
<= 0 || len
> MAXNAMLEN
)
nr
= read(fd
, chdr
.name
, len
);
bcopy(hdr
->ar_name
, chdr
.name
, sizeof(hdr
->ar_name
));
/* Strip trailing spaces, null terminate. */
for (p
= chdr
.name
+ sizeof(hdr
->ar_name
) - 1; *p
== ' '; --p
);
static int already_written
;
* Write an archive member to a file.
* If passed an sb structure, reading a file from disk. Get stat(2)
* information, build a name and construct a header. (Files are named
* by their last component in the archive.) If not, then just write
name
= rname(cfp
->rname
);
(void)fstat(cfp
->rfd
, sb
);
* If not truncating names and the name is too long or contains
* a space, use extended format 1.
if (lname
> OLDARMAXNAME
) {
"ar: warning: %s truncated to %.*s\n",
name
, OLDARMAXNAME
, name
);
(void)sprintf(hb
, HDR3
, name
, sb
->st_mtime
, sb
->st_uid
,
sb
->st_gid
, sb
->st_mode
, sb
->st_size
, ARFMAG
);
} else if (lname
> sizeof(hdr
->ar_name
) || index(name
, ' '))
(void)sprintf(hb
, HDR1
, AR_EFMT1
, lname
, sb
->st_mtime
,
sb
->st_uid
, sb
->st_gid
, sb
->st_mode
,
sb
->st_size
+ lname
, ARFMAG
);
(void)sprintf(hb
, HDR2
, name
, sb
->st_mtime
, sb
->st_uid
,
sb
->st_gid
, sb
->st_mode
, sb
->st_size
, ARFMAG
);
if (write(cfp
->wfd
, hb
, sizeof(HDR
)) != sizeof(HDR
))
if (write(cfp
->wfd
, name
, lname
) != lname
)
* Copy size bytes from one file to another - taking care to handle the
* extra byte (for odd size files) when reading archives and writing an
* extra byte if necessary when adding files to archive. The length of
* the object is the long name plus the object itself; the variable
* already_written gets set if a long name was written.
* The padding is really unnecessary, and is almost certainly a remnant
* of early archive formats where the header included binary data which
* a PDP-11 required to start on an even byte boundary. (Or, perhaps,
* because 16-bit word addressed copies were faster?) Anyhow, it should
* have been ripped out long ago.
register int from
, nr
, nw
, off
, to
;
while (sz
&& (nr
= read(from
, buf
, MIN(sz
, sizeof(buf
)))) > 0) {
for (off
= 0; off
< nr
; nr
-= off
, off
+= nw
)
if ((nw
= write(to
, buf
+ off
, nr
)) < 0)
if (cfp
->flags
& RPAD
&& size
& 1 && (nr
= read(from
, buf
, 1)) != 1) {
if (cfp
->flags
& WPAD
&& (size
+ already_written
) & 1 &&
* Skip over an object -- taking care to skip the pad bytes.
len
= chdr
.size
+ (chdr
.size
+ chdr
.lname
& 1);
if (lseek(fd
, len
, SEEK_CUR
) == (off_t
)-1)