* 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.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)archive.c 8.2 (Berkeley) %G%";
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. */
warnx("creating archive %s", 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) { \
memmove(buf, from, len); \
to = strtol(buf, (char **)NULL, base); \
* read the archive header for this member
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
);
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
);
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
) {
warnx("warning: %s truncated to %.*s\n",
name
, OLDARMAXNAME
, name
);
(void)sprintf(hb
, HDR3
, name
, sb
->st_mtimespec
.ts_sec
,
sb
->st_uid
, sb
->st_gid
, sb
->st_mode
, sb
->st_size
,
} 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
);
(void)sprintf(hb
, HDR2
, name
, sb
->st_mtimespec
.ts_sec
,
sb
->st_uid
, sb
->st_gid
, sb
->st_mode
, sb
->st_size
,
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.
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)