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: }

Defined functions

Defined variables

already_written defined in line 188; used 3 times
hb defined in line 57; used 6 times
sccsid defined in line 38; never used

Defined typedef's

HDR defined in line 56; used 5 times

Defined macros

AR_ATOI defined in line 116; used 5 times
DECIMAL defined in line 148; used 4 times
OCTAL defined in line 149; used 1 times
Last modified: 1993-09-25
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4274
Valid CSS Valid XHTML 1.0 Strict