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