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