prettyness police
[unix-history] / usr / src / usr.bin / ar / archive.c
CommitLineData
6276da5a 1/*-
4e6c9859
KB
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
6276da5a
KB
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
706c0358 12static char sccsid[] = "@(#)archive.c 8.2 (Berkeley) %G%";
6276da5a
KB
13#endif /* not lint */
14
15#include <sys/param.h>
6276da5a 16#include <sys/stat.h>
706c0358 17
6276da5a 18#include <ar.h>
706c0358
JSP
19#include <dirent.h>
20#include <err.h>
21#include <errno.h>
22#include <fcntl.h>
11dc4a38 23#include <stdio.h>
a862a678
KB
24#include <stdlib.h>
25#include <string.h>
706c0358
JSP
26#include <unistd.h>
27
6276da5a 28#include "archive.h"
a862a678 29#include "extern.h"
6276da5a 30
11dc4a38
KB
31typedef struct ar_hdr HDR;
32static char hb[sizeof(HDR) + 1]; /* real header */
33
706c0358 34int
6276da5a
KB
35open_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))
706c0358 47 warnx("creating archive %s", archive);
6276da5a
KB
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
11dc4a38
KB
60 * error then someone is already working on this library (or
61 * it's going across NFS).
6276da5a 62 */
11dc4a38 63opened: if (flock(fd, LOCK_EX|LOCK_NB) && errno != EOPNOTSUPP)
6276da5a
KB
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);
706c0358 80 return (fd);
6276da5a
KB
81}
82
a862a678 83void
6276da5a
KB
84close_archive(fd)
85 int fd;
86{
706c0358 87
a862a678 88 (void)close(fd); /* Implicit unlock. */
6276da5a
KB
89}
90
11dc4a38
KB
91/* Convert ar header field to an integer. */
92#define AR_ATOI(from, to, len, base) { \
706c0358 93 memmove(buf, from, len); \
11dc4a38
KB
94 buf[len] = '\0'; \
95 to = strtol(buf, (char **)NULL, base); \
96}
97
98/*
ce478bb7 99 * get_arobj --
11dc4a38
KB
100 * read the archive header for this member
101 */
706c0358 102int
ce478bb7 103get_arobj(fd)
11dc4a38
KB
104 int fd;
105{
106 struct ar_hdr *hdr;
706c0358
JSP
107 int len, nr;
108 char *p, buf[20];
11dc4a38
KB
109
110 nr = read(fd, hb, sizeof(HDR));
111 if (nr != sizeof(HDR)) {
112 if (!nr)
706c0358 113 return (0);
11dc4a38
KB
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;
706c0358 155 memmove(chdr.name, hdr->ar_name, sizeof(hdr->ar_name));
11dc4a38
KB
156
157 /* Strip trailing spaces, null terminate. */
158 for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
159 *++p = '\0';
160 }
706c0358 161 return (1);
11dc4a38
KB
162}
163
164static int already_written;
165
166/*
ce478bb7 167 * put_arobj --
11dc4a38
KB
168 * Write an archive member to a file.
169 */
706c0358 170void
ce478bb7 171put_arobj(cfp, sb)
11dc4a38
KB
172 CF *cfp;
173 struct stat *sb;
174{
706c0358
JSP
175 int lname;
176 char *name;
11dc4a38
KB
177 struct ar_hdr *hdr;
178 off_t size;
11dc4a38
KB
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
616b39cf
KB
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);
4f81e05f 195 if (options & AR_TR) {
5504c5d3 196 if (lname > OLDARMAXNAME) {
a862a678 197 (void)fflush(stdout);
706c0358 198 warnx("warning: %s truncated to %.*s\n",
5504c5d3 199 name, OLDARMAXNAME, name);
616b39cf
KB
200 (void)fflush(stderr);
201 }
6a8fdfdd
KB
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);
5504c5d3 205 lname = 0;
706c0358 206 } else if (lname > sizeof(hdr->ar_name) || strchr(name, ' '))
6a8fdfdd
KB
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);
5504c5d3 210 else {
11dc4a38 211 lname = 0;
6a8fdfdd
KB
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);
11dc4a38
KB
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 }
ce478bb7 230 copy_ar(cfp, size);
11dc4a38
KB
231 already_written = 0;
232}
233
6276da5a 234/*
ce478bb7 235 * copy_ar --
6276da5a 236 * Copy size bytes from one file to another - taking care to handle the
11dc4a38
KB
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.
6276da5a
KB
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
11dc4a38
KB
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.
6276da5a 247 */
706c0358 248void
ce478bb7 249copy_ar(cfp, size)
6276da5a 250 CF *cfp;
11dc4a38 251 off_t size;
6276da5a 252{
11dc4a38 253 static char pad = '\n';
706c0358
JSP
254 off_t sz;
255 int from, nr, nw, off, to;
11dc4a38 256 char buf[8*1024];
6276da5a 257
11dc4a38 258 if (!(sz = size))
6276da5a
KB
259 return;
260
6276da5a
KB
261 from = cfp->rfd;
262 to = cfp->wfd;
11dc4a38
KB
263 sz = size;
264 while (sz && (nr = read(from, buf, MIN(sz, sizeof(buf)))) > 0) {
265 sz -= nr;
6276da5a
KB
266 for (off = 0; off < nr; nr -= off, off += nw)
267 if ((nw = write(to, buf + off, nr)) < 0)
268 error(cfp->wname);
269 }
11dc4a38 270 if (sz) {
6276da5a
KB
271 if (nr == 0)
272 badfmt();
273 error(cfp->rname);
274 }
275
11dc4a38
KB
276 if (cfp->flags & RPAD && size & 1 && (nr = read(from, buf, 1)) != 1) {
277 if (nr == 0)
278 badfmt();
279 error(cfp->rname);
6276da5a 280 }
11dc4a38
KB
281 if (cfp->flags & WPAD && (size + already_written) & 1 &&
282 write(to, &pad, 1) != 1)
283 error(cfp->wname);
284}
285
286/*
ce478bb7 287 * skip_arobj -
11dc4a38
KB
288 * Skip over an object -- taking care to skip the pad bytes.
289 */
a862a678 290void
ce478bb7 291skip_arobj(fd)
11dc4a38
KB
292 int fd;
293{
294 off_t len;
295
296 len = chdr.size + (chdr.size + chdr.lname & 1);
297 if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
298 error(archive);
6276da5a 299}