removed COMPAT_43 flag. the code was removed in df.c version 5.21.
[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
4e6c9859 12static char sccsid[] = "@(#)archive.c 8.1 (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;
57565f06
RC
106 register char *p;
107 char buf[20];
11dc4a38
KB
108
109 nr = read(fd, hb, sizeof(HDR));
110 if (nr != sizeof(HDR)) {
111 if (!nr)
112 return(0);
113 if (nr < 0)
114 error(archive);
115 badfmt();
116 }
117
118 hdr = (struct ar_hdr *)hb;
119 if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
120 badfmt();
121
122 /* Convert the header into the internal format. */
123#define DECIMAL 10
124#define OCTAL 8
125
126 AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), DECIMAL);
127 AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), DECIMAL);
128 AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), DECIMAL);
129 AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), OCTAL);
130 AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), DECIMAL);
131
132 /* Leading spaces should never happen. */
133 if (hdr->ar_name[0] == ' ')
134 badfmt();
135
136 /*
137 * Long name support. Set the "real" size of the file, and the
138 * long name flag/size.
139 */
140 if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) {
141 chdr.lname = len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1);
142 if (len <= 0 || len > MAXNAMLEN)
143 badfmt();
144 nr = read(fd, chdr.name, len);
145 if (nr != len) {
146 if (nr < 0)
147 error(archive);
148 badfmt();
149 }
150 chdr.name[len] = 0;
151 chdr.size -= len;
152 } else {
153 chdr.lname = 0;
154 bcopy(hdr->ar_name, chdr.name, sizeof(hdr->ar_name));
155
156 /* Strip trailing spaces, null terminate. */
157 for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
158 *++p = '\0';
159 }
160 return(1);
161}
162
163static int already_written;
164
165/*
ce478bb7 166 * put_arobj --
11dc4a38
KB
167 * Write an archive member to a file.
168 */
ce478bb7 169put_arobj(cfp, sb)
11dc4a38
KB
170 CF *cfp;
171 struct stat *sb;
172{
173 register int lname;
174 register char *name;
175 struct ar_hdr *hdr;
176 off_t size;
11dc4a38
KB
177
178 /*
179 * If passed an sb structure, reading a file from disk. Get stat(2)
180 * information, build a name and construct a header. (Files are named
181 * by their last component in the archive.) If not, then just write
182 * the last header read.
183 */
184 if (sb) {
185 name = rname(cfp->rname);
186 (void)fstat(cfp->rfd, sb);
187
616b39cf
KB
188 /*
189 * If not truncating names and the name is too long or contains
190 * a space, use extended format 1.
191 */
192 lname = strlen(name);
4f81e05f 193 if (options & AR_TR) {
5504c5d3 194 if (lname > OLDARMAXNAME) {
a862a678
KB
195 (void)fflush(stdout);
196 (void)fprintf(stderr,
616b39cf 197 "ar: warning: %s truncated to %.*s\n",
5504c5d3 198 name, OLDARMAXNAME, name);
616b39cf
KB
199 (void)fflush(stderr);
200 }
6a8fdfdd
KB
201 (void)sprintf(hb, HDR3, name, sb->st_mtimespec.ts_sec,
202 sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
203 ARFMAG);
5504c5d3
KB
204 lname = 0;
205 } else if (lname > sizeof(hdr->ar_name) || index(name, ' '))
6a8fdfdd
KB
206 (void)sprintf(hb, HDR1, AR_EFMT1, lname,
207 sb->st_mtimespec.ts_sec, sb->st_uid, sb->st_gid,
208 sb->st_mode, sb->st_size + lname, ARFMAG);
5504c5d3 209 else {
11dc4a38 210 lname = 0;
6a8fdfdd
KB
211 (void)sprintf(hb, HDR2, name, sb->st_mtimespec.ts_sec,
212 sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size,
213 ARFMAG);
11dc4a38
KB
214 }
215 size = sb->st_size;
216 } else {
217 lname = chdr.lname;
218 name = chdr.name;
219 size = chdr.size;
220 }
221
222 if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR))
223 error(cfp->wname);
224 if (lname) {
225 if (write(cfp->wfd, name, lname) != lname)
226 error(cfp->wname);
227 already_written = lname;
228 }
ce478bb7 229 copy_ar(cfp, size);
11dc4a38
KB
230 already_written = 0;
231}
232
6276da5a 233/*
ce478bb7 234 * copy_ar --
6276da5a 235 * Copy size bytes from one file to another - taking care to handle the
11dc4a38
KB
236 * extra byte (for odd size files) when reading archives and writing an
237 * extra byte if necessary when adding files to archive. The length of
238 * the object is the long name plus the object itself; the variable
239 * already_written gets set if a long name was written.
6276da5a
KB
240 *
241 * The padding is really unnecessary, and is almost certainly a remnant
242 * of early archive formats where the header included binary data which
11dc4a38
KB
243 * a PDP-11 required to start on an even byte boundary. (Or, perhaps,
244 * because 16-bit word addressed copies were faster?) Anyhow, it should
245 * have been ripped out long ago.
6276da5a 246 */
ce478bb7 247copy_ar(cfp, size)
6276da5a 248 CF *cfp;
11dc4a38 249 off_t size;
6276da5a 250{
11dc4a38
KB
251 static char pad = '\n';
252 register off_t sz;
6276da5a 253 register int from, nr, nw, off, to;
11dc4a38 254 char buf[8*1024];
6276da5a 255
11dc4a38 256 if (!(sz = size))
6276da5a
KB
257 return;
258
6276da5a
KB
259 from = cfp->rfd;
260 to = cfp->wfd;
11dc4a38
KB
261 sz = size;
262 while (sz && (nr = read(from, buf, MIN(sz, sizeof(buf)))) > 0) {
263 sz -= nr;
6276da5a
KB
264 for (off = 0; off < nr; nr -= off, off += nw)
265 if ((nw = write(to, buf + off, nr)) < 0)
266 error(cfp->wname);
267 }
11dc4a38 268 if (sz) {
6276da5a
KB
269 if (nr == 0)
270 badfmt();
271 error(cfp->rname);
272 }
273
11dc4a38
KB
274 if (cfp->flags & RPAD && size & 1 && (nr = read(from, buf, 1)) != 1) {
275 if (nr == 0)
276 badfmt();
277 error(cfp->rname);
6276da5a 278 }
11dc4a38
KB
279 if (cfp->flags & WPAD && (size + already_written) & 1 &&
280 write(to, &pad, 1) != 1)
281 error(cfp->wname);
282}
283
284/*
ce478bb7 285 * skip_arobj -
11dc4a38
KB
286 * Skip over an object -- taking care to skip the pad bytes.
287 */
a862a678 288void
ce478bb7 289skip_arobj(fd)
11dc4a38
KB
290 int fd;
291{
292 off_t len;
293
294 len = chdr.size + (chdr.size + chdr.lname & 1);
295 if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
296 error(archive);
6276da5a 297}