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