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