xref: /original-bsd/usr.bin/ar/archive.c (revision 054717d4)
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
12 static char sccsid[] = "@(#)archive.c	5.1 (Berkeley) 01/17/91";
13 #endif /* not lint */
14 
15 #include <sys/param.h>
16 #include <sys/errno.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <dirent.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ar.h>
25 #include "archive.h"
26 
27 extern char *archive;			/* archive name */
28 
29 open_archive(mode)
30 	int mode;
31 {
32 	int created, fd, nr;
33 	char buf[SARMAG];
34 
35 	created = 0;
36 	if (mode & O_CREAT) {
37 		mode |= O_EXCL;
38 		if ((fd = open(archive, mode, DEFFILEMODE)) >= 0) {
39 			/* POSIX.2 puts create message on stderr. */
40 			if (!(options & AR_C))
41 				(void)fprintf(stderr,
42 				    "ar: creating archive %s.\n", archive);
43 			created = 1;
44 			goto opened;
45 		}
46 		if (errno != EEXIST)
47 			error(archive);
48 		mode &= ~O_EXCL;
49 	}
50 	if ((fd = open(archive, mode, DEFFILEMODE)) < 0)
51 		error(archive);
52 
53 	/*
54 	 * Attempt to place a lock on the opened file - if we get an
55 	 * error then someone is already working on this library.
56 	 */
57 opened:	if (flock(fd, LOCK_EX|LOCK_NB))
58 		error(archive);
59 
60 	/*
61 	 * If not created, O_RDONLY|O_RDWR indicates that it has to be
62 	 * in archive format.
63 	 */
64 	if (!created &&
65 	    ((mode & O_ACCMODE) == O_RDONLY || (mode & O_ACCMODE) == O_RDWR)) {
66 		if ((nr = read(fd, buf, SARMAG) != SARMAG)) {
67 			if (nr >= 0)
68 				badfmt();
69 			error(archive);
70 		} else if (bcmp(buf, ARMAG, SARMAG))
71 			badfmt();
72 	} else if (write(fd, ARMAG, SARMAG) != SARMAG)
73 		error(archive);
74 	return(fd);
75 }
76 
77 close_archive(fd)
78 	int fd;
79 {
80 	(void)flock(fd, LOCK_UN);
81 	(void)close(fd);
82 }
83 
84 /*
85  * copyfile --
86  *	Copy size bytes from one file to another - taking care to handle the
87  *	extra byte (for odd size files) when reading archives and tmpfiles
88  *	and writing an extra byte if necessary when adding files to archive.
89  *
90  *	The padding is really unnecessary, and is almost certainly a remnant
91  *	of early archive formats where the header included binary data which
92  *	a PDP-11 required to start on an even byte boundary.  It should have
93  *	been ripped out when the format changed.
94  */
95 copyfile(cfp, size)
96 	CF *cfp;
97 	register off_t size;
98 {
99 	register int from, nr, nw, off, to;
100 	char pad, buf[8*1024];
101 
102 	if (!size)
103 		return;
104 
105 	pad = size & 1;
106 	from = cfp->rfd;
107 	to = cfp->wfd;
108 	while (size &&
109 	    (nr = read(from, buf, MIN(size, sizeof(buf)))) > 0) {
110 		size -= nr;
111 		for (off = 0; off < nr; nr -= off, off += nw)
112 			if ((nw = write(to, buf + off, nr)) < 0)
113 				error(cfp->wname);
114 	}
115 	if (size) {
116 		if (nr == 0)
117 			badfmt();
118 		error(cfp->rname);
119 	}
120 
121 	if (pad) {
122 		if (cfp->flags & RPAD && (nr = read(from, buf, 1)) != 1) {
123 			if (nr == 0)
124 				badfmt();
125 			error(cfp->rname);
126 		}
127 		if (cfp->flags & WPAD) {
128 			pad = '\n';
129 			if (write(to, &pad, 1) != 1)
130 				error(cfp->wname);
131 		}
132 	}
133 }
134