Annotation of src/usr.bin/ar/archive.c, Revision 1.1.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: }