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