Annotation of src/usr.bin/ar/archive.c, Revision 1.1
1.1 ! deraadt 1: /* $NetBSD: archive.c,v 1.7 1995/03/26 03:27:46 glass Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 1990, 1993, 1994
! 5: * The Regents of the University of California. All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to Berkeley by
! 8: * Hugh Smith at The University of Guelph.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the University of
! 21: * California, Berkeley and its contributors.
! 22: * 4. Neither the name of the University nor the names of its contributors
! 23: * may be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 36: * SUCH DAMAGE.
! 37: */
! 38:
! 39: #ifndef lint
! 40: #if 0
! 41: static char sccsid[] = "@(#)archive.c 8.3 (Berkeley) 4/2/94";
! 42: #else
! 43: static char rcsid[] = "$NetBSD: archive.c,v 1.7 1995/03/26 03:27:46 glass Exp $";
! 44: #endif
! 45: #endif /* not lint */
! 46:
! 47: #include <sys/param.h>
! 48: #include <sys/stat.h>
! 49:
! 50: #include <ar.h>
! 51: #include <dirent.h>
! 52: #include <err.h>
! 53: #include <errno.h>
! 54: #include <fcntl.h>
! 55: #include <stdio.h>
! 56: #include <stdlib.h>
! 57: #include <string.h>
! 58: #include <unistd.h>
! 59:
! 60: #include "archive.h"
! 61: #include "extern.h"
! 62:
! 63: typedef struct ar_hdr HDR;
! 64: static char hb[sizeof(HDR) + 1]; /* real header */
! 65:
! 66: int
! 67: open_archive(mode)
! 68: int mode;
! 69: {
! 70: int created, fd, nr;
! 71: char buf[SARMAG];
! 72:
! 73: created = 0;
! 74: if (mode & O_CREAT) {
! 75: mode |= O_EXCL;
! 76: if ((fd = open(archive, mode, DEFFILEMODE)) >= 0) {
! 77: /* POSIX.2 puts create message on stderr. */
! 78: if (!(options & AR_C))
! 79: warnx("creating archive %s", archive);
! 80: created = 1;
! 81: goto opened;
! 82: }
! 83: if (errno != EEXIST)
! 84: error(archive);
! 85: mode &= ~O_EXCL;
! 86: }
! 87: if ((fd = open(archive, mode, DEFFILEMODE)) < 0)
! 88: error(archive);
! 89:
! 90: /*
! 91: * Attempt to place a lock on the opened file - if we get an
! 92: * error then someone is already working on this library (or
! 93: * it's going across NFS).
! 94: */
! 95: opened: if (flock(fd, LOCK_EX|LOCK_NB) && errno != EOPNOTSUPP)
! 96: error(archive);
! 97:
! 98: /*
! 99: * If not created, O_RDONLY|O_RDWR indicates that it has to be
! 100: * in archive format.
! 101: */
! 102: if (!created &&
! 103: ((mode & O_ACCMODE) == O_RDONLY || (mode & O_ACCMODE) == O_RDWR)) {
! 104: if ((nr = read(fd, buf, SARMAG) != SARMAG)) {
! 105: if (nr >= 0)
! 106: badfmt();
! 107: error(archive);
! 108: } else if (bcmp(buf, ARMAG, SARMAG))
! 109: badfmt();
! 110: } else if (write(fd, ARMAG, SARMAG) != SARMAG)
! 111: error(archive);
! 112: return (fd);
! 113: }
! 114:
! 115: void
! 116: close_archive(fd)
! 117: int fd;
! 118: {
! 119:
! 120: (void)close(fd); /* Implicit unlock. */
! 121: }
! 122:
! 123: /* Convert ar header field to an integer. */
! 124: #define AR_ATOI(from, to, len, base) { \
! 125: memmove(buf, from, len); \
! 126: buf[len] = '\0'; \
! 127: to = strtol(buf, (char **)NULL, base); \
! 128: }
! 129:
! 130: /*
! 131: * get_arobj --
! 132: * read the archive header for this member
! 133: */
! 134: int
! 135: get_arobj(fd)
! 136: int fd;
! 137: {
! 138: struct ar_hdr *hdr;
! 139: int len, nr;
! 140: char *p, buf[20];
! 141:
! 142: nr = read(fd, hb, sizeof(HDR));
! 143: if (nr != sizeof(HDR)) {
! 144: if (!nr)
! 145: return (0);
! 146: if (nr < 0)
! 147: error(archive);
! 148: badfmt();
! 149: }
! 150:
! 151: hdr = (struct ar_hdr *)hb;
! 152: if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
! 153: badfmt();
! 154:
! 155: /* Convert the header into the internal format. */
! 156: #define DECIMAL 10
! 157: #define OCTAL 8
! 158:
! 159: AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), DECIMAL);
! 160: AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), DECIMAL);
! 161: AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), DECIMAL);
! 162: AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), OCTAL);
! 163: AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), DECIMAL);
! 164:
! 165: /* Leading spaces should never happen. */
! 166: if (hdr->ar_name[0] == ' ')
! 167: badfmt();
! 168:
! 169: /*
! 170: * Long name support. Set the "real" size of the file, and the
! 171: * long name flag/size.
! 172: */
! 173: if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) {
! 174: chdr.lname = len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1);
! 175: if (len <= 0 || len > MAXNAMLEN)
! 176: badfmt();
! 177: nr = read(fd, chdr.name, len);
! 178: if (nr != len) {
! 179: if (nr < 0)
! 180: error(archive);
! 181: badfmt();
! 182: }
! 183: chdr.name[len] = 0;
! 184: chdr.size -= len;
! 185: } else {
! 186: chdr.lname = 0;
! 187: memmove(chdr.name, hdr->ar_name, sizeof(hdr->ar_name));
! 188:
! 189: /* Strip trailing spaces, null terminate. */
! 190: for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
! 191: *++p = '\0';
! 192: }
! 193: return (1);
! 194: }
! 195:
! 196: static int already_written;
! 197:
! 198: /*
! 199: * put_arobj --
! 200: * Write an archive member to a file.
! 201: */
! 202: void
! 203: put_arobj(cfp, sb)
! 204: CF *cfp;
! 205: struct stat *sb;
! 206: {
! 207: int lname;
! 208: char *name;
! 209: struct ar_hdr *hdr;
! 210: off_t size;
! 211:
! 212: /*
! 213: * If passed an sb structure, reading a file from disk. Get stat(2)
! 214: * information, build a name and construct a header. (Files are named
! 215: * by their last component in the archive.) If not, then just write
! 216: * the last header read.
! 217: */
! 218: if (sb) {
! 219: name = rname(cfp->rname);
! 220: (void)fstat(cfp->rfd, sb);
! 221:
! 222: /*
! 223: * If not truncating names and the name is too long or contains
! 224: * a space, use extended format 1.
! 225: */
! 226: lname = strlen(name);
! 227: if (options & AR_TR) {
! 228: if (lname > OLDARMAXNAME) {
! 229: (void)fflush(stdout);
! 230: warnx("warning: %s truncated to %.*s",
! 231: name, OLDARMAXNAME, name);
! 232: (void)fflush(stderr);
! 233: }
! 234: (void)sprintf(hb, HDR3, name, sb->st_mtimespec.ts_sec,
! 235: sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
! 236: ARFMAG);
! 237: lname = 0;
! 238: } else if (lname > sizeof(hdr->ar_name) || strchr(name, ' '))
! 239: (void)sprintf(hb, HDR1, AR_EFMT1, lname,
! 240: sb->st_mtimespec.ts_sec, sb->st_uid, sb->st_gid,
! 241: sb->st_mode, sb->st_size + lname, ARFMAG);
! 242: else {
! 243: lname = 0;
! 244: (void)sprintf(hb, HDR2, name, sb->st_mtimespec.ts_sec,
! 245: sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
! 246: ARFMAG);
! 247: }
! 248: size = sb->st_size;
! 249: } else {
! 250: lname = chdr.lname;
! 251: name = chdr.name;
! 252: size = chdr.size;
! 253: }
! 254:
! 255: if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR))
! 256: error(cfp->wname);
! 257: if (lname) {
! 258: if (write(cfp->wfd, name, lname) != lname)
! 259: error(cfp->wname);
! 260: already_written = lname;
! 261: }
! 262: copy_ar(cfp, size);
! 263: already_written = 0;
! 264: }
! 265:
! 266: /*
! 267: * copy_ar --
! 268: * Copy size bytes from one file to another - taking care to handle the
! 269: * extra byte (for odd size files) when reading archives and writing an
! 270: * extra byte if necessary when adding files to archive. The length of
! 271: * the object is the long name plus the object itself; the variable
! 272: * already_written gets set if a long name was written.
! 273: *
! 274: * The padding is really unnecessary, and is almost certainly a remnant
! 275: * of early archive formats where the header included binary data which
! 276: * a PDP-11 required to start on an even byte boundary. (Or, perhaps,
! 277: * because 16-bit word addressed copies were faster?) Anyhow, it should
! 278: * have been ripped out long ago.
! 279: */
! 280: void
! 281: copy_ar(cfp, size)
! 282: CF *cfp;
! 283: off_t size;
! 284: {
! 285: static char pad = '\n';
! 286: off_t sz;
! 287: int from, nr, nw, off, to;
! 288: char buf[8*1024];
! 289:
! 290: if (!(sz = size))
! 291: return;
! 292:
! 293: from = cfp->rfd;
! 294: to = cfp->wfd;
! 295: sz = size;
! 296: while (sz && (nr = read(from, buf, MIN(sz, sizeof(buf)))) > 0) {
! 297: sz -= nr;
! 298: for (off = 0; off < nr; nr -= off, off += nw)
! 299: if ((nw = write(to, buf + off, nr)) < 0)
! 300: error(cfp->wname);
! 301: }
! 302: if (sz) {
! 303: if (nr == 0)
! 304: badfmt();
! 305: error(cfp->rname);
! 306: }
! 307:
! 308: if (cfp->flags & RPAD && (size + chdr.lname) & 1 &&
! 309: (nr = read(from, buf, 1)) != 1) {
! 310: if (nr == 0)
! 311: badfmt();
! 312: error(cfp->rname);
! 313: }
! 314: if (cfp->flags & WPAD && (size + already_written) & 1 &&
! 315: write(to, &pad, 1) != 1)
! 316: error(cfp->wname);
! 317: }
! 318:
! 319: /*
! 320: * skip_arobj -
! 321: * Skip over an object -- taking care to skip the pad bytes.
! 322: */
! 323: void
! 324: skip_arobj(fd)
! 325: int fd;
! 326: {
! 327: off_t len;
! 328:
! 329: len = chdr.size + (chdr.size + chdr.lname & 1);
! 330: if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
! 331: error(archive);
! 332: }