Commit | Line | Data |
---|---|---|
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 | 12 | static 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 |
31 | typedef struct ar_hdr HDR; |
32 | static char hb[sizeof(HDR) + 1]; /* real header */ | |
33 | ||
706c0358 | 34 | int |
6276da5a KB |
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)) | |
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 | 63 | opened: 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 | 83 | void |
6276da5a KB |
84 | close_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 | 102 | int |
ce478bb7 | 103 | get_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 | ||
164 | static int already_written; | |
165 | ||
166 | /* | |
ce478bb7 | 167 | * put_arobj -- |
11dc4a38 KB |
168 | * Write an archive member to a file. |
169 | */ | |
706c0358 | 170 | void |
ce478bb7 | 171 | put_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 | 248 | void |
ce478bb7 | 249 | copy_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 | 290 | void |
ce478bb7 | 291 | skip_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 | } |