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