summaryrefslogtreecommitdiff
path: root/usr.bin/ar
diff options
context:
space:
mode:
authorBruce Evans <bde@FreeBSD.org>1997-07-06 06:54:14 +0000
committerBruce Evans <bde@FreeBSD.org>1997-07-06 06:54:14 +0000
commitc44252b6e8da46f58fd1882b9e7305a0f9114c16 (patch)
tree29fcabeee2a8db74f376eb75e7c13a0f440c6ce9 /usr.bin/ar
parent616fc29f94872d4d502f3d8631885d52a9167322 (diff)
Notes
Diffstat (limited to 'usr.bin/ar')
-rw-r--r--usr.bin/ar/ar.1320
-rw-r--r--usr.bin/ar/ar.5.5146
-rw-r--r--usr.bin/ar/archive.c326
-rw-r--r--usr.bin/ar/misc.c149
-rw-r--r--usr.bin/ar/replace.c178
5 files changed, 1119 insertions, 0 deletions
diff --git a/usr.bin/ar/ar.1 b/usr.bin/ar/ar.1
new file mode 100644
index 000000000000..fd5ce4f717c9
--- /dev/null
+++ b/usr.bin/ar/ar.1
@@ -0,0 +1,320 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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
+.\" are met:
+.\" 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
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ar.1 8.4 (Berkeley) 4/28/95
+.\"
+.Dd "April 28, 1995"
+.Dt AR 1
+.Os
+.Sh NAME
+.Nm ar
+.Nd create and maintain library archives
+.Sh SYNOPSIS
+.Nm ar
+.Fl d
+.Op Fl \Tv
+.Ar archive file ...
+.Nm ar
+.Fl m
+.Op Fl \Tv
+.Ar archive file ...
+.Nm ar
+.Fl m
+.Op Fl abiTv
+.Ar position archive file ...
+.Nm ar
+.Fl p
+.Op Fl \Tv
+.Ar archive
+.Op Ar file ...
+.Nm ar
+.Fl q
+.Op Fl cTv
+.Ar archive file ...
+.Nm ar
+.Fl r
+.Op Fl cuTv
+.Ar archive file ...
+.Nm ar
+.Fl r
+.Op Fl abciuTv
+.Ar position archive file ...
+.Nm ar
+.Fl t
+.Op Fl \Tv
+.Ar archive
+.Op Ar file ...
+.Nm ar
+.Fl x
+.Op Fl ouTv
+.Ar archive
+.Op Ar file ...
+.Sh DESCRIPTION
+The
+.Nm ar
+utility creates and maintains groups of files combined into an archive.
+Once an archive has been created, new files can be added and existing
+files can be extracted, deleted, or replaced.
+.Pp
+Files are named in the archive by a single component, i.e., if a file
+referenced by a path containing a slash (``/'') is archived it will be
+named by the last component of that path.
+When matching paths listed on the command line against file names stored
+in the archive, only the last component of the path will be compared.
+.Pp
+All informational and error messages use the path listed on the command
+line, if any was specified; otherwise the name in the archive is used.
+If multiple files in the archive have the same name, and paths are listed
+on the command line to ``select'' archive files for an operation, only the
+.Em first
+file with a matching name will be selected.
+.Pp
+The normal use of
+.Nm ar
+is for the creation and maintenance of libraries suitable for use with
+the loader (see
+.Xr ld 1 ),
+although it is not restricted to this purpose.
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+A positioning modifier used with the options
+.Fl r
+and
+.Fl m .
+The files are entered or moved
+.Em after
+the archive member
+.Ar position ,
+which must be specified.
+.It Fl b
+A positioning modifier used with the options
+.Fl r
+and
+.Fl m .
+The files are entered or moved
+.Em before
+the archive member
+.Ar position ,
+which must be specified.
+.It Fl c
+Whenever an archive is created, an informational message to that effect
+is written to standard error.
+If the
+.Fl c
+option is specified,
+.Nm ar
+creates the archive silently.
+.It Fl d
+Delete the specified archive files.
+.It Fl i
+Identical to the
+.Fl b
+option.
+.It Fl m
+Move the specified archive files within the archive.
+If one of the options
+.Fl a ,
+.Fl b
+or
+.Fl i
+is specified, the files are moved before or after the
+.Ar position
+file in the archive.
+If none of those options are specified, the files are moved
+to the end of the archive.
+.It Fl o
+Set the access and modification times of extracted files to the
+modification time of the file when it was entered into the archive.
+This will fail if the user is not the owner of the extracted file
+or the super-user.
+.It Fl p
+Write the contents of the specified archive files to the standard output.
+If no files are specified, the contents of all the files in the archive
+are written in the order they appear in the archive.
+.It Fl q
+(Quickly) append the specified files to the archive.
+If the archive does not exist a new archive file is created.
+Much faster than the
+.Fl r
+option, when creating a large archive
+piece-by-piece, as no checking is done to see if the files already
+exist in the archive.
+.It Fl r
+Replace or add the specified files to the archive.
+If the archive does not exist a new archive file is created.
+Files that replace existing files do not change the order of the files
+within the archive.
+New files are appended to the archive unless one of the options
+.Fl a ,
+.Fl b
+or
+.Fl i
+is specified.
+.It Fl T
+Select and/or name archive members using only the first fifteen characters
+of the archive member or command line file name.
+The historic archive format had sixteen bytes for the name, but some
+historic archiver and loader implementations were unable to handle names
+that used the entire space.
+This means that file names that are not unique in their first fifteen
+characters can subsequently be confused.
+A warning message is printed to the standard error output if any file
+names are truncated.
+(See
+.Xr ar 5
+for more information.)
+.It Fl t
+List the specified files in the order in which they appear in the archive,
+each on a separate line.
+If no files are specified, all files in the archive are listed.
+.It Fl u
+Update files.
+When used with the
+.Fl r
+option, files in the archive will be replaced
+only if the disk file has a newer modification time than the file in
+the archive.
+When used with the
+.Fl x
+option, files in the archive will be extracted
+only if the archive file has a newer modification time than the file
+on disk.
+.It Fl v
+Provide verbose output.
+When used with the
+.Fl d ,
+.Fl m ,
+.Fl q
+or
+.Fl x
+options,
+.Nm ar
+gives a file-by-file description of the archive modification.
+This description consists of three, white-space separated fields: the
+option letter, a dash (``-'') and the file name.
+When used with the
+.Fl r
+option,
+.Nm ar
+displays the description as above, but the initial letter is an ``a'' if
+the file is added to the archive and an ``r'' if the file replaces a file
+already in the archive.
+.Pp
+When used with the
+.Fl p
+option,
+the name of each printed file,
+enclosed in less-than (``<'') and greater-than (``>'') characters,
+is written to the standard output before
+the contents of the file;
+it is preceded by a single newline character, and
+followed by two newline characters.
+.Pp
+When used with the
+.Fl t
+option,
+.Nm ar
+displays an ``ls -l'' style listing of information about the members of
+the archive.
+This listing consists of eight, white-space separated fields:
+the file permissions (see
+.Xr strmode 3 ),
+the decimal user and group ID's separated by a single slash (``/''),
+the file size (in bytes), the file modification time (in the
+.Xr date 1
+format ``%b %e %H:%M %Y''), and the name of the file.
+.It Fl x
+Extract the specified archive members into the files named by the command
+line arguments.
+If no members are specified, all the members of the archive are extracted into
+the current directory.
+.Pp
+If the file does not exist, it is created; if it does exist, the owner
+and group will be unchanged.
+The file access and modification times are the time of the extraction
+(but see the
+.Fl o
+option).
+The file permissions will be set to those of the file when it was entered
+into the archive; this will fail if the user is not the owner of the
+extracted file or the super-user.
+.El
+.Pp
+The
+.Nm ar
+utility exits 0 on success, and >0 if an error occurs.
+.Sh ENVIRONMENT
+.Bl -tag -width indent -compact
+.It Ev TMPDIR
+The pathname of the directory to use when creating temporary files.
+.El
+.Sh FILES
+.Bl -tag -width indent -compact
+.It Pa /tmp
+default temporary file directory
+.It Pa ar.XXXXXX
+temporary file names
+.El
+.Sh COMPATIBILITY
+By default,
+.Nm ar
+writes archives that may be incompatible with historic archives, as
+the format used for storing archive members with names longer than
+fifteen characters has changed.
+This implementation of
+.Nm ar
+is backward compatible with previous versions of
+.Nm ar
+in that it can read and write (using the
+.Fl T
+option) historic archives.
+The
+.Fl T
+option is provided for compatibility only, and will be deleted
+in a future release.
+See
+.Xr ar 5
+for more information.
+.SH STANDARDS
+The
+.Nm ar
+utility is expected to offer a superset of the
+.St -p1003.2
+functionality.
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr ranlib 1 ,
+.Xr strmode 3 ,
+.Xr ar 5
diff --git a/usr.bin/ar/ar.5.5 b/usr.bin/ar/ar.5.5
new file mode 100644
index 000000000000..2ab5b2d99851
--- /dev/null
+++ b/usr.bin/ar/ar.5.5
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ar.5.5 8.2 (Berkeley) 6/1/94
+.\"
+.Dd June 1, 1994
+.Dt AR 5
+.Os
+.Sh NAME
+.Nm ar
+.Nd archive (library) file format
+.Sh SYNOPSIS
+.Fd #include <ar.h>
+.Sh DESCRIPTION
+The archive command
+.Nm ar
+combines several files into one.
+Archives are mainly used as libraries of object files intended to be
+loaded using the link-editor
+.Xr ld 1 .
+.Pp
+A file created with
+.Nm ar
+begins with the ``magic'' string "!<arch>\en".
+The rest of the archive is made up of objects, each of which is composed
+of a header for a file, a possible file name, and the file contents.
+The header is portable between machine architectures, and, if the file
+contents are printable, the archive is itself printable.
+.Pp
+The header is made up of six variable length
+.Tn ASCII
+fields, followed by a
+two character trailer.
+The fields are the object name (16 characters), the file last modification
+time (12 characters), the user and group id's (each 6 characters), the file
+mode (8 characters) and the file size (10 characters).
+All numeric fields are in decimal, except for the file mode which is in
+octal.
+.Pp
+The modification time is the file
+.Fa st_mtime
+field, i.e.,
+.Dv CUT
+seconds since
+the epoch.
+The user and group id's are the file
+.Fa st_uid
+and
+.Fa st_gid
+fields.
+The file mode is the file
+.Fa st_mode
+field.
+The file size is the file
+.Fa st_size
+field.
+The two-byte trailer is the string "\`\en".
+.Pp
+Only the name field has any provision for overflow.
+If any file name is more than 16 characters in length or contains an
+embedded space, the string "#1/" followed by the
+.Tn ASCII
+length of the
+name is written in the name field.
+The file size (stored in the archive header) is incremented by the length
+of the name.
+The name is then written immediately following the archive header.
+.Pp
+Any unused characters in any of these fields are written as space
+characters.
+If any fields are their particular maximum number of characters in
+length, there will be no separation between the fields.
+.Pp
+Objects in the archive are always an even number of bytes long; files
+which are an odd number of bytes long are padded with a newline (``\en'')
+character, although the size in the header does not reflect this.
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr stat 2
+.Sh HISTORY
+There have been at least four
+.Nm ar
+formats.
+The first was denoted by the leading ``magic'' number 0177555 (stored as
+type int).
+These archives were almost certainly created on a 16-bit machine, and
+contain headers made up of five fields.
+The fields are the object name (8 characters), the file last modification
+time (type long), the user id (type char), the file mode (type char) and
+the file size (type unsigned int).
+Files were padded to an even number of bytes.
+.Pp
+The second was denoted by the leading ``magic'' number 0177545 (stored as
+type int).
+These archives may have been created on either 16 or 32-bit machines, and
+contain headers made up of six fields.
+The fields are the object name (14 characters), the file last modification
+time (type long), the user and group id's (each type char), the file mode
+(type int) and the file size (type long).
+Files were padded to an even number of bytes.
+For more information on converting from this format see
+.Xr arcv 8 .
+.ne 1i
+.Pp
+The current archive format (without support for long character names and
+names with embedded spaces) was introduced in
+.Bx 4.0 .
+The headers were the same as the current format, with the exception that
+names longer than 16 characters were truncated, and names with embedded
+spaces (and often trailing spaces) were not supported.
+It has been extended for these reasons,
+as described above.
+This format first appeared in 4.4BSD.
+.Sh COMPATIBILITY
+No archive format is currently specified by any standard.
+.At V
+has historically distributed archives in a different format from
+all of the above.
diff --git a/usr.bin/ar/archive.c b/usr.bin/ar/archive.c
new file mode 100644
index 000000000000..9dd6b2077f5a
--- /dev/null
+++ b/usr.bin/ar/archive.c
@@ -0,0 +1,326 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+ * are met:
+ * 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
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)archive.c 8.4 (Berkeley) 4/27/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ar.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "extern.h"
+
+typedef struct ar_hdr HDR;
+static char hb[sizeof(HDR) + 1]; /* real header */
+
+int
+open_archive(mode)
+ int mode;
+{
+ int created, fd, nr;
+ char buf[SARMAG];
+
+ created = 0;
+ if (mode & O_CREAT) {
+ mode |= O_EXCL;
+ if ((fd = open(archive, mode, DEFFILEMODE)) >= 0) {
+ /* POSIX.2 puts create message on stderr. */
+ if (!(options & AR_C))
+ warnx("creating archive %s", archive);
+ created = 1;
+ goto opened;
+ }
+ if (errno != EEXIST)
+ error(archive);
+ mode &= ~O_EXCL;
+ }
+ if ((fd = open(archive, mode, DEFFILEMODE)) < 0)
+ error(archive);
+
+ /*
+ * 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)
+ error(archive);
+
+ /*
+ * If not created, O_RDONLY|O_RDWR indicates that it has to be
+ * in archive format.
+ */
+ if (!created &&
+ ((mode & O_ACCMODE) == O_RDONLY || (mode & O_ACCMODE) == O_RDWR)) {
+ if ((nr = read(fd, buf, SARMAG) != SARMAG)) {
+ if (nr >= 0)
+ badfmt();
+ error(archive);
+ } else if (bcmp(buf, ARMAG, SARMAG))
+ badfmt();
+ } else if (write(fd, ARMAG, SARMAG) != SARMAG)
+ error(archive);
+ return (fd);
+}
+
+void
+close_archive(fd)
+ int fd;
+{
+
+ (void)close(fd); /* Implicit unlock. */
+}
+
+/* Convert ar header field to an integer. */
+#define AR_ATOI(from, to, len, base) { \
+ memmove(buf, from, len); \
+ buf[len] = '\0'; \
+ to = strtol(buf, (char **)NULL, base); \
+}
+
+/*
+ * get_arobj --
+ * read the archive header for this member
+ */
+int
+get_arobj(fd)
+ int fd;
+{
+ struct ar_hdr *hdr;
+ int len, nr;
+ char *p, buf[20];
+
+ nr = read(fd, hb, sizeof(HDR));
+ if (nr != sizeof(HDR)) {
+ if (!nr)
+ return (0);
+ if (nr < 0)
+ error(archive);
+ badfmt();
+ }
+
+ hdr = (struct ar_hdr *)hb;
+ if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
+ badfmt();
+
+ /* Convert the header into the internal format. */
+#define DECIMAL 10
+#define OCTAL 8
+
+ 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] == ' ')
+ badfmt();
+
+ /*
+ * Long name support. Set the "real" size of the file, and the
+ * long name flag/size.
+ */
+ 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)
+ badfmt();
+ nr = read(fd, chdr.name, len);
+ if (nr != len) {
+ if (nr < 0)
+ error(archive);
+ badfmt();
+ }
+ chdr.name[len] = 0;
+ chdr.size -= len;
+ } else {
+ chdr.lname = 0;
+ memmove(chdr.name, hdr->ar_name, sizeof(hdr->ar_name));
+
+ /* Strip trailing spaces, null terminate. */
+ for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
+ *++p = '\0';
+ }
+ return (1);
+}
+
+static int already_written;
+
+/*
+ * put_arobj --
+ * Write an archive member to a file.
+ */
+void
+put_arobj(cfp, sb)
+ CF *cfp;
+ struct stat *sb;
+{
+ int lname;
+ char *name;
+ struct ar_hdr *hdr;
+ off_t size;
+
+ /*
+ * 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
+ * the last header read.
+ */
+ if (sb) {
+ 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.
+ */
+ lname = strlen(name);
+ if (options & AR_TR) {
+ if (lname > OLDARMAXNAME) {
+ (void)fflush(stdout);
+ warnx("warning: %s truncated to %.*s",
+ name, OLDARMAXNAME, name);
+ (void)fflush(stderr);
+ }
+ (void)sprintf(hb, HDR3, name, sb->st_mtimespec.ts_sec,
+ sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
+ ARFMAG);
+ lname = 0;
+ } else if (lname > sizeof(hdr->ar_name) || strchr(name, ' '))
+ (void)sprintf(hb, HDR1, AR_EFMT1, lname,
+ sb->st_mtimespec.ts_sec, sb->st_uid, sb->st_gid,
+ sb->st_mode, sb->st_size + lname, ARFMAG);
+ else {
+ lname = 0;
+ (void)sprintf(hb, HDR2, name, sb->st_mtimespec.ts_sec,
+ sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
+ ARFMAG);
+ }
+ size = sb->st_size;
+ } else {
+ lname = chdr.lname;
+ name = chdr.name;
+ size = chdr.size;
+ }
+
+ if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR))
+ error(cfp->wname);
+ if (lname) {
+ if (write(cfp->wfd, name, lname) != lname)
+ error(cfp->wname);
+ already_written = lname;
+ }
+ copy_ar(cfp, size);
+ already_written = 0;
+}
+
+/*
+ * copy_ar --
+ * 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.
+ */
+void
+copy_ar(cfp, size)
+ CF *cfp;
+ off_t size;
+{
+ static char pad = '\n';
+ off_t sz;
+ int from, nr, nw, off, to;
+ char buf[8*1024];
+
+ if (!(sz = size))
+ return;
+
+ from = cfp->rfd;
+ to = cfp->wfd;
+ sz = size;
+ while (sz && (nr = read(from, buf, MIN(sz, sizeof(buf)))) > 0) {
+ sz -= nr;
+ for (off = 0; off < nr; nr -= off, off += nw)
+ if ((nw = write(to, buf + off, nr)) < 0)
+ error(cfp->wname);
+ }
+ if (sz) {
+ if (nr == 0)
+ badfmt();
+ error(cfp->rname);
+ }
+
+ if (cfp->flags & RPAD && (size + chdr.lname) & 1 &&
+ (nr = read(from, buf, 1)) != 1) {
+ if (nr == 0)
+ badfmt();
+ error(cfp->rname);
+ }
+ if (cfp->flags & WPAD && (size + already_written) & 1 &&
+ write(to, &pad, 1) != 1)
+ error(cfp->wname);
+}
+
+/*
+ * skip_arobj -
+ * Skip over an object -- taking care to skip the pad bytes.
+ */
+void
+skip_arobj(fd)
+ int fd;
+{
+ off_t len;
+
+ len = chdr.size + (chdr.size + chdr.lname & 1);
+ if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
+ error(archive);
+}
diff --git a/usr.bin/ar/misc.c b/usr.bin/ar/misc.c
new file mode 100644
index 000000000000..f9c0d14578c8
--- /dev/null
+++ b/usr.bin/ar/misc.c
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+ * are met:
+ * 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
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)misc.c 8.4 (Berkeley) 4/27/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "extern.h"
+#include "pathnames.h"
+
+char *tname = "temporary file"; /* temporary file "name" */
+
+int
+tmp()
+{
+ extern char *envtmp;
+ sigset_t set, oset;
+ static int first;
+ int fd;
+ char path[MAXPATHLEN];
+
+ if (!first && !envtmp) {
+ envtmp = getenv("TMPDIR");
+ first = 1;
+ }
+
+ if (envtmp)
+ (void)sprintf(path, "%s/%s", envtmp, _NAME_ARTMP);
+ else
+ strcpy(path, _PATH_ARTMP);
+
+ sigfillset(&set);
+ (void)sigprocmask(SIG_BLOCK, &set, &oset);
+ if ((fd = mkstemp(path)) == -1)
+ error(tname);
+ (void)unlink(path);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ return (fd);
+}
+
+/*
+ * files --
+ * See if the current file matches any file in the argument list; if it
+ * does, remove it from the argument list.
+ */
+char *
+files(argv)
+ char **argv;
+{
+ char **list, *p;
+
+ for (list = argv; *list; ++list)
+ if (compare(*list)) {
+ p = *list;
+ for (; list[0] = list[1]; ++list)
+ continue;
+ return (p);
+ }
+ return (NULL);
+}
+
+void
+orphans(argv)
+ char **argv;
+{
+
+ for (; *argv; ++argv)
+ warnx("%s: not found in archive", *argv);
+}
+
+char *
+rname(path)
+ char *path;
+{
+ char *ind;
+
+ return ((ind = strrchr(path, '/')) ? ind + 1 : path);
+}
+
+int
+compare(dest)
+ char *dest;
+{
+
+ if (options & AR_TR)
+ return (!strncmp(chdr.name, rname(dest), OLDARMAXNAME));
+ return (!strcmp(chdr.name, rname(dest)));
+}
+
+void
+badfmt()
+{
+
+ errno = EFTYPE;
+ err(1, "%s", archive);
+}
+
+void
+error(name)
+ char *name;
+{
+
+ err(1, "%s", name);
+}
diff --git a/usr.bin/ar/replace.c b/usr.bin/ar/replace.c
new file mode 100644
index 000000000000..4500b9077f66
--- /dev/null
+++ b/usr.bin/ar/replace.c
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+ * are met:
+ * 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
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)replace.c 8.4 (Berkeley) 4/27/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ar.h>
+#include <dirent.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "archive.h"
+#include "extern.h"
+
+/*
+ * replace --
+ * Replace or add named members to archive. Entries already in the
+ * archive are swapped in place. Others are added before or after
+ * the key entry, based on the a, b and i options. If the u option
+ * is specified, modification dates select for replacement.
+ */
+int
+replace(argv)
+ char **argv;
+{
+ char *file;
+ int afd, curfd, errflg, exists, mods, sfd, tfd1, tfd2;
+ struct stat sb;
+ CF cf;
+ off_t size, tsize;
+
+ errflg = 0;
+ /*
+ * If doesn't exist, simply append to the archive. There's
+ * a race here, but it's pretty short, and not worth fixing.
+ */
+ exists = !stat(archive, &sb);
+ afd = open_archive(O_CREAT|O_RDWR);
+
+ if (!exists) {
+ tfd1 = -1;
+ tfd2 = tmp();
+ goto append;
+ }
+
+ tfd1 = tmp(); /* Files before key file. */
+ tfd2 = tmp(); /* Files after key file. */
+
+ /*
+ * Break archive into two parts -- entries before and after the key
+ * entry. If positioning before the key, place the key at the
+ * beginning of the after key entries and if positioning after the
+ * key, place the key at the end of the before key entries. Put it
+ * all back together at the end.
+ */
+ mods = (options & (AR_A|AR_B));
+ for (curfd = tfd1; get_arobj(afd);) {
+ if (*argv && (file = files(argv))) {
+ if ((sfd = open(file, O_RDONLY)) < 0) {
+ errflg = 1;
+ warn("%s", file);
+ goto useold;
+ }
+ (void)fstat(sfd, &sb);
+ if (options & AR_U && sb.st_mtime <= chdr.date) {
+ (void)close(sfd);
+ goto useold;
+ }
+
+ if (options & AR_V)
+ (void)printf("r - %s\n", file);
+
+ /* Read from disk, write to an archive; pad on write */
+ SETCF(sfd, file, curfd, tname, WPAD);
+ put_arobj(&cf, &sb);
+ (void)close(sfd);
+ skip_arobj(afd);
+ continue;
+ }
+
+ if (mods && compare(posname)) {
+ mods = 0;
+ if (options & AR_B)
+ curfd = tfd2;
+ /* Read and write to an archive; pad on both. */
+ SETCF(afd, archive, curfd, tname, RPAD|WPAD);
+ put_arobj(&cf, (struct stat *)NULL);
+ if (options & AR_A)
+ curfd = tfd2;
+ } else {
+ /* Read and write to an archive; pad on both. */
+useold: SETCF(afd, archive, curfd, tname, RPAD|WPAD);
+ put_arobj(&cf, (struct stat *)NULL);
+ }
+ }
+
+ if (mods) {
+ warnx("%s: archive member not found", posarg);
+ close_archive(afd);
+ return (1);
+ }
+
+ /* Append any left-over arguments to the end of the after file. */
+append: while (file = *argv++) {
+ if (options & AR_V)
+ (void)printf("a - %s\n", file);
+ if ((sfd = open(file, O_RDONLY)) < 0) {
+ errflg = 1;
+ warn("%s", file);
+ continue;
+ }
+ (void)fstat(sfd, &sb);
+ /* Read from disk, write to an archive; pad on write. */
+ SETCF(sfd, file,
+ options & (AR_A|AR_B) ? tfd1 : tfd2, tname, WPAD);
+ put_arobj(&cf, &sb);
+ (void)close(sfd);
+ }
+
+ (void)lseek(afd, (off_t)SARMAG, SEEK_SET);
+
+ SETCF(tfd1, tname, afd, archive, NOPAD);
+ if (tfd1 != -1) {
+ tsize = size = lseek(tfd1, (off_t)0, SEEK_CUR);
+ (void)lseek(tfd1, (off_t)0, SEEK_SET);
+ copy_ar(&cf, size);
+ } else
+ tsize = 0;
+
+ tsize += size = lseek(tfd2, (off_t)0, SEEK_CUR);
+ (void)lseek(tfd2, (off_t)0, SEEK_SET);
+ cf.rfd = tfd2;
+ copy_ar(&cf, size);
+
+ (void)ftruncate(afd, tsize + SARMAG);
+ close_archive(afd);
+ return (errflg);
+}