xref: /plan9/sys/src/cmd/ar.c (revision 25fc69938fdecc61cd09e795cbe2d2f72f1082b1)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * ar - portable (ascii) format version
33e12c5d1SDavid du Colombier  */
43e12c5d1SDavid du Colombier #include <u.h>
53e12c5d1SDavid du Colombier #include <libc.h>
63e12c5d1SDavid du Colombier #include <bio.h>
7219b2ee8SDavid du Colombier #include <mach.h>
83e12c5d1SDavid du Colombier #include <ar.h>
93e12c5d1SDavid du Colombier 
10bd389b36SDavid du Colombier /*
11bd389b36SDavid du Colombier  *	The algorithm uses up to 3 temp files.  The "pivot member" is the
12219b2ee8SDavid du Colombier  *	archive member specified by and a, b, or i option.  The temp files are
13219b2ee8SDavid du Colombier  *	astart - contains existing members up to and including the pivot member.
14219b2ee8SDavid du Colombier  *	amiddle - contains new files moved or inserted behind the pivot.
15219b2ee8SDavid du Colombier  *	aend - contains the existing members that follow the pivot member.
16219b2ee8SDavid du Colombier  *	When all members have been processed, function 'install' streams the
17219b2ee8SDavid du Colombier  * 	temp files, in order, back into the archive.
18bd389b36SDavid du Colombier  */
19bd389b36SDavid du Colombier 
20219b2ee8SDavid du Colombier typedef struct	Arsymref
21219b2ee8SDavid du Colombier {
22219b2ee8SDavid du Colombier 	char	*name;
23219b2ee8SDavid du Colombier 	int	type;
24219b2ee8SDavid du Colombier 	int	len;
254de34a7eSDavid du Colombier 	vlong	offset;
26219b2ee8SDavid du Colombier 	struct	Arsymref *next;
27219b2ee8SDavid du Colombier } Arsymref;
28219b2ee8SDavid du Colombier 
29bd389b36SDavid du Colombier typedef struct	Armember	/* Temp file entry - one per archive member */
303e12c5d1SDavid du Colombier {
31bd389b36SDavid du Colombier 	struct Armember	*next;
32bd389b36SDavid du Colombier 	struct ar_hdr	hdr;
33bd389b36SDavid du Colombier 	long		size;
34bd389b36SDavid du Colombier 	long		date;
35bd389b36SDavid du Colombier 	void		*member;
36bd389b36SDavid du Colombier } Armember;
373e12c5d1SDavid du Colombier 
38bd389b36SDavid du Colombier typedef	struct Arfile		/* Temp file control block - one per tempfile */
39bd389b36SDavid du Colombier {
40bd389b36SDavid du Colombier 	int	paged;		/* set when some data paged to disk */
41bd389b36SDavid du Colombier 	char	*fname;		/* paging file name */
42bd389b36SDavid du Colombier 	int	fd;		/* paging file descriptor */
434de34a7eSDavid du Colombier 	vlong	size;
44bd389b36SDavid du Colombier 	Armember *head;		/* head of member chain */
45bd389b36SDavid du Colombier 	Armember *tail;		/* tail of member chain */
46219b2ee8SDavid du Colombier 	Arsymref *sym;		/* head of defined symbol chain */
47bd389b36SDavid du Colombier } Arfile;
48219b2ee8SDavid du Colombier 
497dd7cddfSDavid du Colombier typedef struct Hashchain
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier 	char	*name;
527dd7cddfSDavid du Colombier 	struct Hashchain *next;
537dd7cddfSDavid du Colombier } Hashchain;
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier #define	NHASH	1024
567dd7cddfSDavid du Colombier 
57219b2ee8SDavid du Colombier /*
58219b2ee8SDavid du Colombier  *	macro to portably read/write archive header.
59219b2ee8SDavid du Colombier  *	'cmd' is read/write/Bread/Bwrite, etc.
60219b2ee8SDavid du Colombier  */
61219b2ee8SDavid du Colombier #define	HEADER_IO(cmd, f, h)	cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
62219b2ee8SDavid du Colombier 				|| cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
63219b2ee8SDavid du Colombier 				|| cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
64219b2ee8SDavid du Colombier 				|| cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
65219b2ee8SDavid du Colombier 				|| cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
66219b2ee8SDavid du Colombier 				|| cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
67219b2ee8SDavid du Colombier 				|| cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
68219b2ee8SDavid du Colombier 
69bd389b36SDavid du Colombier 		/* constants and flags */
70bd389b36SDavid du Colombier char	*man =		"mrxtdpq";
71bd389b36SDavid du Colombier char	*opt =		"uvnbailo";
72bd389b36SDavid du Colombier char	artemp[] =	"/tmp/vXXXXX";
73bd389b36SDavid du Colombier char	movtemp[] =	"/tmp/v1XXXXX";
74bd389b36SDavid du Colombier char	tailtemp[] =	"/tmp/v2XXXXX";
75219b2ee8SDavid du Colombier char	symdef[] =	"__.SYMDEF";
763e12c5d1SDavid du Colombier 
77bd389b36SDavid du Colombier int	aflag;				/* command line flags */
78bd389b36SDavid du Colombier int	bflag;
79bd389b36SDavid du Colombier int	cflag;
80bd389b36SDavid du Colombier int	oflag;
81bd389b36SDavid du Colombier int	uflag;
82bd389b36SDavid du Colombier int	vflag;
833e12c5d1SDavid du Colombier 
84bd389b36SDavid du Colombier Arfile *astart, *amiddle, *aend;	/* Temp file control block pointers */
85219b2ee8SDavid du Colombier int	allobj = 1;			/* set when all members are object files of the same type */
86219b2ee8SDavid du Colombier int	symdefsize;			/* size of symdef file */
877dd7cddfSDavid du Colombier int	dupfound;			/* flag for duplicate symbol */
887dd7cddfSDavid du Colombier Hashchain	*hash[NHASH];		/* hash table of text symbols */
89bd389b36SDavid du Colombier 
90bd389b36SDavid du Colombier #define	ARNAMESIZE	sizeof(astart->tail->hdr.name)
91bd389b36SDavid du Colombier 
92bd389b36SDavid du Colombier char	poname[ARNAMESIZE+1];		/* name of pivot member */
93bd389b36SDavid du Colombier char	*file;				/* current file or member being worked on */
943e12c5d1SDavid du Colombier Biobuf	bout;
95219b2ee8SDavid du Colombier Biobuf bar;
963e12c5d1SDavid du Colombier 
97219b2ee8SDavid du Colombier void	arcopy(Biobuf*, Arfile*, Armember*);
98bd389b36SDavid du Colombier int	arcreate(char*);
99bd389b36SDavid du Colombier void	arfree(Arfile*);
100bd389b36SDavid du Colombier void	arinsert(Arfile*, Armember*);
101bd389b36SDavid du Colombier char	*armalloc(int);
102219b2ee8SDavid du Colombier void	armove(Biobuf*, Arfile*, Armember*);
103219b2ee8SDavid du Colombier void	arread(Biobuf*, Armember*, int);
104bd389b36SDavid du Colombier void	arstream(int, Arfile*);
105bd389b36SDavid du Colombier int	arwrite(int, Armember*);
106bd389b36SDavid du Colombier int	bamatch(char*, char*);
1077dd7cddfSDavid du Colombier int	duplicate(char*);
108219b2ee8SDavid du Colombier Armember *getdir(Biobuf*);
109bd389b36SDavid du Colombier int	getspace(void);
1107dd7cddfSDavid du Colombier void	install(char*, Arfile*, Arfile*, Arfile*, int);
111bd389b36SDavid du Colombier void	longt(Armember*);
112bd389b36SDavid du Colombier int	match(int, char**);
113bd389b36SDavid du Colombier void	mesg(int, char*);
114bd389b36SDavid du Colombier Arfile	*newtempfile(char*);
115bd389b36SDavid du Colombier Armember *newmember(void);
116219b2ee8SDavid du Colombier void	objsym(Sym*, void*);
117bd389b36SDavid du Colombier int	openar(char*, int, int);
118bd389b36SDavid du Colombier int	page(Arfile*);
119bd389b36SDavid du Colombier void	pmode(long);
120219b2ee8SDavid du Colombier void	rl(int);
1214de34a7eSDavid du Colombier void	scanobj(Biobuf*, Arfile*, long);
122bd389b36SDavid du Colombier void	select(int*, long);
123bd389b36SDavid du Colombier void	setcom(void(*)(char*, int, char**));
1244de34a7eSDavid du Colombier void	skip(Biobuf*, vlong);
1257dd7cddfSDavid du Colombier int	symcomp(void*, void*);
126bd389b36SDavid du Colombier void	trim(char*, char*, int);
1273e12c5d1SDavid du Colombier void	usage(void);
1283e12c5d1SDavid du Colombier void	wrerr(void);
1294de34a7eSDavid du Colombier void	wrsym(Biobuf*, long, Arsymref*);
1303e12c5d1SDavid du Colombier 
131bd389b36SDavid du Colombier void	rcmd(char*, int, char**);		/* command processing */
132bd389b36SDavid du Colombier void	dcmd(char*, int, char**);
133bd389b36SDavid du Colombier void	xcmd(char*, int, char**);
134bd389b36SDavid du Colombier void	tcmd(char*, int, char**);
135bd389b36SDavid du Colombier void	pcmd(char*, int, char**);
136bd389b36SDavid du Colombier void	mcmd(char*, int, char**);
137bd389b36SDavid du Colombier void	qcmd(char*, int, char**);
138bd389b36SDavid du Colombier void	(*comfun)(char*, int, char**);
139bd389b36SDavid du Colombier 
1403e12c5d1SDavid du Colombier void
main(int argc,char * argv[])1413e12c5d1SDavid du Colombier main(int argc, char *argv[])
1423e12c5d1SDavid du Colombier {
1433e12c5d1SDavid du Colombier 	char *cp;
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
1463e12c5d1SDavid du Colombier 	if(argc < 3)
1473e12c5d1SDavid du Colombier 		usage();
148bd389b36SDavid du Colombier 	for (cp = argv[1]; *cp; cp++) {
1493e12c5d1SDavid du Colombier 		switch(*cp) {
150bd389b36SDavid du Colombier 		case 'a':	aflag = 1;	break;
151bd389b36SDavid du Colombier 		case 'b':	bflag = 1;	break;
152bd389b36SDavid du Colombier 		case 'c':	cflag = 1;	break;
153bd389b36SDavid du Colombier 		case 'd':	setcom(dcmd);	break;
154bd389b36SDavid du Colombier 		case 'i':	bflag = 1;	break;
1553e12c5d1SDavid du Colombier 		case 'l':
156bd389b36SDavid du Colombier 				strcpy(artemp, "vXXXXX");
157bd389b36SDavid du Colombier 				strcpy(movtemp, "v1XXXXX");
158bd389b36SDavid du Colombier 				strcpy(tailtemp, "v2XXXXX");
159bd389b36SDavid du Colombier 				break;
160bd389b36SDavid du Colombier 		case 'm':	setcom(mcmd);	break;
161bd389b36SDavid du Colombier 		case 'o':	oflag = 1;	break;
162bd389b36SDavid du Colombier 		case 'p':	setcom(pcmd);	break;
163bd389b36SDavid du Colombier 		case 'q':	setcom(qcmd);	break;
164bd389b36SDavid du Colombier 		case 'r':	setcom(rcmd);	break;
165bd389b36SDavid du Colombier 		case 't':	setcom(tcmd);	break;
166bd389b36SDavid du Colombier 		case 'u':	uflag = 1;	break;
167bd389b36SDavid du Colombier 		case 'v':	vflag = 1;	break;
168bd389b36SDavid du Colombier 		case 'x':	setcom(xcmd);	break;
1693e12c5d1SDavid du Colombier 		default:
1703e12c5d1SDavid du Colombier 			fprint(2, "ar: bad option `%c'\n", *cp);
171bd389b36SDavid du Colombier 			exits("error");
1723e12c5d1SDavid du Colombier 		}
1733e12c5d1SDavid du Colombier 	}
174bd389b36SDavid du Colombier 	if (aflag && bflag) {
175bd389b36SDavid du Colombier 		fprint(2, "ar: only one of 'a' and 'b' can be specified\n");
176bd389b36SDavid du Colombier 		usage();
177bd389b36SDavid du Colombier 	}
178bd389b36SDavid du Colombier 	if(aflag || bflag) {
179bd389b36SDavid du Colombier 		trim(argv[2], poname, sizeof(poname));
1803e12c5d1SDavid du Colombier 		argv++;
1813e12c5d1SDavid du Colombier 		argc--;
1823e12c5d1SDavid du Colombier 		if(argc < 3)
1833e12c5d1SDavid du Colombier 			usage();
1843e12c5d1SDavid du Colombier 	}
1853e12c5d1SDavid du Colombier 	if(comfun == 0) {
186bd389b36SDavid du Colombier 		if(uflag == 0) {
1873e12c5d1SDavid du Colombier 			fprint(2, "ar: one of [%s] must be specified\n", man);
188bd389b36SDavid du Colombier 			usage();
1893e12c5d1SDavid du Colombier 		}
1903e12c5d1SDavid du Colombier 		setcom(rcmd);
1913e12c5d1SDavid du Colombier 	}
192bd389b36SDavid du Colombier 	cp = argv[2];
193bd389b36SDavid du Colombier 	argc -= 3;
194bd389b36SDavid du Colombier 	argv += 3;
195bd389b36SDavid du Colombier 	(*comfun)(cp, argc, argv);	/* do the command */
196bd389b36SDavid du Colombier 	cp = 0;
197bd389b36SDavid du Colombier 	while (argc--) {
198bd389b36SDavid du Colombier 		if (*argv) {
199bd389b36SDavid du Colombier 			fprint(2, "ar: %s not found\n", *argv);
200bd389b36SDavid du Colombier 			cp = "error";
2013e12c5d1SDavid du Colombier 		}
202bd389b36SDavid du Colombier 		argv++;
203bd389b36SDavid du Colombier 	}
204bd389b36SDavid du Colombier 	exits(cp);
205bd389b36SDavid du Colombier }
206bd389b36SDavid du Colombier /*
207bd389b36SDavid du Colombier  *	select a command
208bd389b36SDavid du Colombier  */
2093e12c5d1SDavid du Colombier void
setcom(void (* fun)(char *,int,char **))210bd389b36SDavid du Colombier setcom(void (*fun)(char *, int, char**))
2113e12c5d1SDavid du Colombier {
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier 	if(comfun != 0) {
2143e12c5d1SDavid du Colombier 		fprint(2, "ar: only one of [%s] allowed\n", man);
215bd389b36SDavid du Colombier 		usage();
2163e12c5d1SDavid du Colombier 	}
2173e12c5d1SDavid du Colombier 	comfun = fun;
2183e12c5d1SDavid du Colombier }
219bd389b36SDavid du Colombier /*
220bd389b36SDavid du Colombier  *	perform the 'r' and 'u' commands
221bd389b36SDavid du Colombier  */
2223e12c5d1SDavid du Colombier void
rcmd(char * arname,int count,char ** files)223bd389b36SDavid du Colombier rcmd(char *arname, int count, char **files)
2243e12c5d1SDavid du Colombier {
225219b2ee8SDavid du Colombier 	int fd;
2269a747e4fSDavid du Colombier 	int i;
227bd389b36SDavid du Colombier 	Arfile *ap;
228bd389b36SDavid du Colombier 	Armember *bp;
2299a747e4fSDavid du Colombier 	Dir *d;
230219b2ee8SDavid du Colombier 	Biobuf *bfile;
2313e12c5d1SDavid du Colombier 
232bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 1);
233219b2ee8SDavid du Colombier 	if (fd >= 0) {
234219b2ee8SDavid du Colombier 		Binit(&bar, fd, OREAD);
235219b2ee8SDavid du Colombier 		Bseek(&bar,seek(fd,0,1), 1);
236219b2ee8SDavid du Colombier 	}
237bd389b36SDavid du Colombier 	astart = newtempfile(artemp);
238bd389b36SDavid du Colombier 	ap = astart;
239bd389b36SDavid du Colombier 	aend = 0;
240219b2ee8SDavid du Colombier 	for(i = 0; fd >= 0; i++) {
241219b2ee8SDavid du Colombier 		bp = getdir(&bar);
242bd389b36SDavid du Colombier 		if (!bp)
243bd389b36SDavid du Colombier 			break;
244bd389b36SDavid du Colombier 		if (bamatch(file, poname)) {		/* check for pivot */
245bd389b36SDavid du Colombier 			aend = newtempfile(tailtemp);
246bd389b36SDavid du Colombier 			ap = aend;
247bd389b36SDavid du Colombier 		}
248219b2ee8SDavid du Colombier 			/* pitch symdef file */
249219b2ee8SDavid du Colombier 		if (i == 0 && strcmp(file, symdef) == 0) {
250219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
251219b2ee8SDavid du Colombier 			continue;
252219b2ee8SDavid du Colombier 		}
253219b2ee8SDavid du Colombier 		if (count && !match(count, files)) {
254219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
255219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
256219b2ee8SDavid du Colombier 			continue;
257219b2ee8SDavid du Colombier 		}
258219b2ee8SDavid du Colombier 		bfile = Bopen(file, OREAD);
259219b2ee8SDavid du Colombier 		if (!bfile) {
260bd389b36SDavid du Colombier 			if (count != 0)
2613e12c5d1SDavid du Colombier 				fprint(2, "ar: cannot open %s\n", file);
262219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
263219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
264219b2ee8SDavid du Colombier 			continue;
265219b2ee8SDavid du Colombier 		}
2669a747e4fSDavid du Colombier 		d = dirfstat(Bfildes(bfile));
2679a747e4fSDavid du Colombier 		if(d == nil)
2689a747e4fSDavid du Colombier 			fprint(2, "ar: cannot stat %s: %r\n", file);
2699a747e4fSDavid du Colombier 		if (uflag && (d==nil || d->mtime <= bp->date)) {
270219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
271219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
272219b2ee8SDavid du Colombier 			Bterm(bfile);
2739a747e4fSDavid du Colombier 			free(d);
274219b2ee8SDavid du Colombier 			continue;
2753e12c5d1SDavid du Colombier 		}
276bd389b36SDavid du Colombier 		mesg('r', file);
277219b2ee8SDavid du Colombier 		skip(&bar, bp->size);
2789a747e4fSDavid du Colombier 		scanobj(bfile, ap, d->length);
2799a747e4fSDavid du Colombier 		free(d);
280219b2ee8SDavid du Colombier 		armove(bfile, ap, bp);
281219b2ee8SDavid du Colombier 		Bterm(bfile);
2823e12c5d1SDavid du Colombier 	}
2837dd7cddfSDavid du Colombier 	if(fd >= 0)
284bd389b36SDavid du Colombier 		close(fd);
285bd389b36SDavid du Colombier 		/* copy in remaining files named on command line */
286bd389b36SDavid du Colombier 	for (i = 0; i < count; i++) {
287bd389b36SDavid du Colombier 		file = files[i];
2883e12c5d1SDavid du Colombier 		if(file == 0)
2893e12c5d1SDavid du Colombier 			continue;
290bd389b36SDavid du Colombier 		files[i] = 0;
291219b2ee8SDavid du Colombier 		bfile = Bopen(file, OREAD);
292219b2ee8SDavid du Colombier 		if (!bfile)
2933e12c5d1SDavid du Colombier 			fprint(2, "ar: %s cannot open\n", file);
294bd389b36SDavid du Colombier 		else {
295bd389b36SDavid du Colombier 			mesg('a', file);
2969a747e4fSDavid du Colombier 			d = dirfstat(Bfildes(bfile));
2979a747e4fSDavid du Colombier 			if (d == nil)
298219b2ee8SDavid du Colombier 				fprint(2, "can't stat %s\n", file);
299219b2ee8SDavid du Colombier 			else {
3009a747e4fSDavid du Colombier 				scanobj(bfile, astart, d->length);
301219b2ee8SDavid du Colombier 				armove(bfile, astart, newmember());
3029a747e4fSDavid du Colombier 				free(d);
303219b2ee8SDavid du Colombier 			}
304219b2ee8SDavid du Colombier 			Bterm(bfile);
3053e12c5d1SDavid du Colombier 		}
3063e12c5d1SDavid du Colombier 	}
3077dd7cddfSDavid du Colombier 	if(fd < 0 && !cflag)
3087dd7cddfSDavid du Colombier 		install(arname, astart, 0, aend, 1);	/* issue 'creating' msg */
3097dd7cddfSDavid du Colombier 	else
3107dd7cddfSDavid du Colombier 		install(arname, astart, 0, aend, 0);
311bd389b36SDavid du Colombier }
312219b2ee8SDavid du Colombier 
313bd389b36SDavid du Colombier void
dcmd(char * arname,int count,char ** files)314bd389b36SDavid du Colombier dcmd(char *arname, int count, char **files)
315bd389b36SDavid du Colombier {
316bd389b36SDavid du Colombier 	Armember *bp;
317219b2ee8SDavid du Colombier 	int fd, i;
318bd389b36SDavid du Colombier 
319bd389b36SDavid du Colombier 	if (!count)
320bd389b36SDavid du Colombier 		return;
321bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 0);
322219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
323219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
324bd389b36SDavid du Colombier 	astart = newtempfile(artemp);
325219b2ee8SDavid du Colombier 	for (i = 0; bp = getdir(&bar); i++) {
326bd389b36SDavid du Colombier 		if(match(count, files)) {
327bd389b36SDavid du Colombier 			mesg('d', file);
328219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
329219b2ee8SDavid du Colombier 			if (strcmp(file, symdef) == 0)
330219b2ee8SDavid du Colombier 				allobj = 0;
331219b2ee8SDavid du Colombier 		} else if (i == 0 && strcmp(file, symdef) == 0)
332219b2ee8SDavid du Colombier 				skip(&bar, bp->size);
333219b2ee8SDavid du Colombier 		else {
334219b2ee8SDavid du Colombier 			scanobj(&bar, astart, bp->size);
335219b2ee8SDavid du Colombier 			arcopy(&bar, astart, bp);
336bd389b36SDavid du Colombier 		}
337219b2ee8SDavid du Colombier 	}
338219b2ee8SDavid du Colombier 	close(fd);
3397dd7cddfSDavid du Colombier 	install(arname, astart, 0, 0, 0);
3403e12c5d1SDavid du Colombier }
3413e12c5d1SDavid du Colombier 
3423e12c5d1SDavid du Colombier void
xcmd(char * arname,int count,char ** files)343bd389b36SDavid du Colombier xcmd(char *arname, int count, char **files)
3443e12c5d1SDavid du Colombier {
345bd389b36SDavid du Colombier 	int fd, f, mode, i;
346bd389b36SDavid du Colombier 	Armember *bp;
347d3c05884SDavid du Colombier 	Dir dx;
3483e12c5d1SDavid du Colombier 
349bd389b36SDavid du Colombier 	fd = openar(arname, OREAD, 0);
350219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
351219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
352bd389b36SDavid du Colombier 	i = 0;
353219b2ee8SDavid du Colombier 	while (bp = getdir(&bar)) {
354bd389b36SDavid du Colombier 		if(count == 0 || match(count, files)) {
355bd389b36SDavid du Colombier 			mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
356bd389b36SDavid du Colombier 			f = create(file, OWRITE, mode);
357bd389b36SDavid du Colombier 			if(f < 0) {
358bd389b36SDavid du Colombier 				fprint(2, "ar: %s cannot create\n", file);
359219b2ee8SDavid du Colombier 				skip(&bar, bp->size);
360bd389b36SDavid du Colombier 			} else {
361bd389b36SDavid du Colombier 				mesg('x', file);
362219b2ee8SDavid du Colombier 				arcopy(&bar, 0, bp);
363bd389b36SDavid du Colombier 				if (write(f, bp->member, bp->size) < 0)
3643e12c5d1SDavid du Colombier 					wrerr();
365bd389b36SDavid du Colombier 				if(oflag) {
366d3c05884SDavid du Colombier 					nulldir(&dx);
367d3c05884SDavid du Colombier 					dx.atime = bp->date;
368d3c05884SDavid du Colombier 					dx.mtime = bp->date;
369d3c05884SDavid du Colombier 					if(dirwstat(file, &dx) < 0)
370bd389b36SDavid du Colombier 						perror(file);
371bd389b36SDavid du Colombier 				}
372bd389b36SDavid du Colombier 				free(bp->member);
373bd389b36SDavid du Colombier 				close(f);
374bd389b36SDavid du Colombier 			}
375bd389b36SDavid du Colombier 			free(bp);
376bd389b36SDavid du Colombier 			if (count && ++i >= count)
377bd389b36SDavid du Colombier 				break;
378bd389b36SDavid du Colombier 		} else {
379219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
380bd389b36SDavid du Colombier 			free(bp);
381bd389b36SDavid du Colombier 		}
382bd389b36SDavid du Colombier 	}
383bd389b36SDavid du Colombier 	close(fd);
384bd389b36SDavid du Colombier }
385bd389b36SDavid du Colombier void
pcmd(char * arname,int count,char ** files)386bd389b36SDavid du Colombier pcmd(char *arname, int count, char **files)
387bd389b36SDavid du Colombier {
388bd389b36SDavid du Colombier 	int fd;
389bd389b36SDavid du Colombier 	Armember *bp;
3903e12c5d1SDavid du Colombier 
391bd389b36SDavid du Colombier 	fd = openar(arname, OREAD, 0);
392219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
393219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
394219b2ee8SDavid du Colombier 	while(bp = getdir(&bar)) {
395bd389b36SDavid du Colombier 		if(count == 0 || match(count, files)) {
396bd389b36SDavid du Colombier 			if(vflag)
397bd389b36SDavid du Colombier 				print("\n<%s>\n\n", file);
398219b2ee8SDavid du Colombier 			arcopy(&bar, 0, bp);
399bd389b36SDavid du Colombier 			if (write(1, bp->member, bp->size) < 0)
400bd389b36SDavid du Colombier 				wrerr();
401bd389b36SDavid du Colombier 		} else
402219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
403bd389b36SDavid du Colombier 		free(bp);
404bd389b36SDavid du Colombier 	}
405bd389b36SDavid du Colombier 	close(fd);
406bd389b36SDavid du Colombier }
407bd389b36SDavid du Colombier void
mcmd(char * arname,int count,char ** files)408bd389b36SDavid du Colombier mcmd(char *arname, int count, char **files)
409bd389b36SDavid du Colombier {
410219b2ee8SDavid du Colombier 	int fd, i;
411bd389b36SDavid du Colombier 	Arfile *ap;
412bd389b36SDavid du Colombier 	Armember *bp;
413bd389b36SDavid du Colombier 
414bd389b36SDavid du Colombier 	if (count == 0)
415bd389b36SDavid du Colombier 		return;
416bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 0);
417219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
418219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
419bd389b36SDavid du Colombier 	astart = newtempfile(artemp);
420bd389b36SDavid du Colombier 	amiddle = newtempfile(movtemp);
421bd389b36SDavid du Colombier 	aend = 0;
422bd389b36SDavid du Colombier 	ap = astart;
423219b2ee8SDavid du Colombier 	for (i = 0; bp = getdir(&bar); i++) {
424bd389b36SDavid du Colombier 		if (bamatch(file, poname)) {
425bd389b36SDavid du Colombier 			aend = newtempfile(tailtemp);
426bd389b36SDavid du Colombier 			ap = aend;
427bd389b36SDavid du Colombier 		}
428bd389b36SDavid du Colombier 		if(match(count, files)) {
429bd389b36SDavid du Colombier 			mesg('m', file);
430219b2ee8SDavid du Colombier 			scanobj(&bar, amiddle, bp->size);
431219b2ee8SDavid du Colombier 			arcopy(&bar, amiddle, bp);
432bd389b36SDavid du Colombier 		} else
433219b2ee8SDavid du Colombier 			/*
434219b2ee8SDavid du Colombier 			 * pitch the symdef file if it is at the beginning
435219b2ee8SDavid du Colombier 			 * of the archive and we aren't inserting in front
436219b2ee8SDavid du Colombier 			 * of it (ap == astart).
437219b2ee8SDavid du Colombier 			 */
438219b2ee8SDavid du Colombier 		if (ap == astart && i == 0 && strcmp(file, symdef) == 0)
439219b2ee8SDavid du Colombier 			skip(&bar, bp->size);
440219b2ee8SDavid du Colombier 		else {
441219b2ee8SDavid du Colombier 			scanobj(&bar, ap, bp->size);
442219b2ee8SDavid du Colombier 			arcopy(&bar, ap, bp);
443219b2ee8SDavid du Colombier 		}
444bd389b36SDavid du Colombier 	}
445bd389b36SDavid du Colombier 	close(fd);
446bd389b36SDavid du Colombier 	if (poname[0] && aend == 0)
447bd389b36SDavid du Colombier 		fprint(2, "ar: %s not found - files moved to end.\n", poname);
4487dd7cddfSDavid du Colombier 	install(arname, astart, amiddle, aend, 0);
449bd389b36SDavid du Colombier }
450bd389b36SDavid du Colombier void
tcmd(char * arname,int count,char ** files)451bd389b36SDavid du Colombier tcmd(char *arname, int count, char **files)
452bd389b36SDavid du Colombier {
453bd389b36SDavid du Colombier 	int fd;
454bd389b36SDavid du Colombier 	Armember *bp;
455bd389b36SDavid du Colombier 	char name[ARNAMESIZE+1];
456bd389b36SDavid du Colombier 
457bd389b36SDavid du Colombier 	fd = openar(arname, OREAD, 0);
458219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
459219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
460219b2ee8SDavid du Colombier 	while(bp = getdir(&bar)) {
461bd389b36SDavid du Colombier 		if(count == 0 || match(count, files)) {
462bd389b36SDavid du Colombier 			if(vflag)
463bd389b36SDavid du Colombier 				longt(bp);
464219b2ee8SDavid du Colombier 			trim(file, name, ARNAMESIZE);
465bd389b36SDavid du Colombier 			Bprint(&bout, "%s\n", name);
466bd389b36SDavid du Colombier 		}
467219b2ee8SDavid du Colombier 		skip(&bar, bp->size);
468bd389b36SDavid du Colombier 		free(bp);
469bd389b36SDavid du Colombier 	}
470bd389b36SDavid du Colombier 	close(fd);
471bd389b36SDavid du Colombier }
472bd389b36SDavid du Colombier void
qcmd(char * arname,int count,char ** files)473bd389b36SDavid du Colombier qcmd(char *arname, int count, char **files)
474bd389b36SDavid du Colombier {
475219b2ee8SDavid du Colombier 	int fd, i;
476bd389b36SDavid du Colombier 	Armember *bp;
477219b2ee8SDavid du Colombier 	Biobuf *bfile;
478bd389b36SDavid du Colombier 
479bd389b36SDavid du Colombier 	if(aflag || bflag) {
480bd389b36SDavid du Colombier 		fprint(2, "ar: abi not allowed with q\n");
481bd389b36SDavid du Colombier 		exits("error");
482bd389b36SDavid du Colombier 	}
483bd389b36SDavid du Colombier 	fd = openar(arname, ORDWR, 1);
484bd389b36SDavid du Colombier 	if (fd < 0) {
485bd389b36SDavid du Colombier 		if(!cflag)
486bd389b36SDavid du Colombier 			fprint(2, "ar: creating %s\n", arname);
487bd389b36SDavid du Colombier 		fd = arcreate(arname);
488bd389b36SDavid du Colombier 	}
489219b2ee8SDavid du Colombier 	Binit(&bar, fd, OREAD);
490219b2ee8SDavid du Colombier 	Bseek(&bar,seek(fd,0,1), 1);
491bd389b36SDavid du Colombier 	/* leave note group behind when writing archive; i.e. sidestep interrupts */
492bd389b36SDavid du Colombier 	rfork(RFNOTEG);
493219b2ee8SDavid du Colombier 	Bseek(&bar, 0, 2);
494bd389b36SDavid du Colombier 	bp = newmember();
495bd389b36SDavid du Colombier 	for(i=0; i<count && files[i]; i++) {
496bd389b36SDavid du Colombier 		file = files[i];
497bd389b36SDavid du Colombier 		files[i] = 0;
498219b2ee8SDavid du Colombier 		bfile = Bopen(file, OREAD);
499219b2ee8SDavid du Colombier 		if(!bfile)
500bd389b36SDavid du Colombier 			fprint(2, "ar: %s cannot open\n", file);
501bd389b36SDavid du Colombier 		else {
502bd389b36SDavid du Colombier 			mesg('q', file);
503219b2ee8SDavid du Colombier 			armove(bfile, 0, bp);
504bd389b36SDavid du Colombier 			if (!arwrite(fd, bp))
505bd389b36SDavid du Colombier 				wrerr();
506bd389b36SDavid du Colombier 			free(bp->member);
507bd389b36SDavid du Colombier 			bp->member = 0;
508219b2ee8SDavid du Colombier 			Bterm(bfile);
509bd389b36SDavid du Colombier 		}
510bd389b36SDavid du Colombier 	}
511bd389b36SDavid du Colombier 	free(bp);
512bd389b36SDavid du Colombier 	close(fd);
513bd389b36SDavid du Colombier }
514219b2ee8SDavid du Colombier 
515219b2ee8SDavid du Colombier /*
516219b2ee8SDavid du Colombier  *	extract the symbol references from an object file
517219b2ee8SDavid du Colombier  */
518219b2ee8SDavid du Colombier void
scanobj(Biobuf * b,Arfile * ap,long size)5194de34a7eSDavid du Colombier scanobj(Biobuf *b, Arfile *ap, long size)
520219b2ee8SDavid du Colombier {
521219b2ee8SDavid du Colombier 	int obj;
5224de34a7eSDavid du Colombier 	vlong offset;
5239a747e4fSDavid du Colombier 	Dir *d;
524219b2ee8SDavid du Colombier 	static int lastobj = -1;
525219b2ee8SDavid du Colombier 
526219b2ee8SDavid du Colombier 	if (!allobj)			/* non-object file encountered */
527219b2ee8SDavid du Colombier 		return;
5287dd7cddfSDavid du Colombier 	offset = Boffset(b);
529219b2ee8SDavid du Colombier 	obj = objtype(b, 0);
530219b2ee8SDavid du Colombier 	if (obj < 0) {			/* not an object file */
531219b2ee8SDavid du Colombier 		allobj = 0;
5329a747e4fSDavid du Colombier 		d = dirfstat(Bfildes(b));
5339a747e4fSDavid du Colombier 		if (d != nil && d->length == 0)
5347dd7cddfSDavid du Colombier 			fprint(2, "ar: zero length file %s\n", file);
5359a747e4fSDavid du Colombier 		free(d);
536219b2ee8SDavid du Colombier 		Bseek(b, offset, 0);
537219b2ee8SDavid du Colombier 		return;
538219b2ee8SDavid du Colombier 	}
539219b2ee8SDavid du Colombier 	if (lastobj >= 0 && obj != lastobj) {
540219b2ee8SDavid du Colombier 		fprint(2, "ar: inconsistent object file %s\n", file);
541219b2ee8SDavid du Colombier 		allobj = 0;
542219b2ee8SDavid du Colombier 		Bseek(b, offset, 0);
543219b2ee8SDavid du Colombier 		return;
544219b2ee8SDavid du Colombier 	}
545219b2ee8SDavid du Colombier 	lastobj = obj;
546219b2ee8SDavid du Colombier 	if (!readar(b, obj, offset+size, 0)) {
547219b2ee8SDavid du Colombier 		fprint(2, "ar: invalid symbol reference in file %s\n", file);
548219b2ee8SDavid du Colombier 		allobj = 0;
549219b2ee8SDavid du Colombier 		Bseek(b, offset, 0);
550219b2ee8SDavid du Colombier 		return;
551219b2ee8SDavid du Colombier 	}
552219b2ee8SDavid du Colombier 	Bseek(b, offset, 0);
553219b2ee8SDavid du Colombier 	objtraverse(objsym, ap);
554219b2ee8SDavid du Colombier }
555219b2ee8SDavid du Colombier 
556219b2ee8SDavid du Colombier /*
557219b2ee8SDavid du Colombier  *	add text and data symbols to the symbol list
558219b2ee8SDavid du Colombier  */
559219b2ee8SDavid du Colombier void
objsym(Sym * s,void * p)560219b2ee8SDavid du Colombier objsym(Sym *s, void *p)
561219b2ee8SDavid du Colombier {
562219b2ee8SDavid du Colombier 	int n;
563219b2ee8SDavid du Colombier 	Arsymref *as;
564219b2ee8SDavid du Colombier 	Arfile *ap;
565219b2ee8SDavid du Colombier 
566219b2ee8SDavid du Colombier 	if (s->type != 'T' &&  s->type != 'D')
567219b2ee8SDavid du Colombier 		return;
568219b2ee8SDavid du Colombier 	ap = (Arfile*)p;
569219b2ee8SDavid du Colombier 	as = (Arsymref*)armalloc(sizeof(Arsymref));
570219b2ee8SDavid du Colombier 	as->offset = ap->size;
571219b2ee8SDavid du Colombier 	n = strlen(s->name);
572219b2ee8SDavid du Colombier 	as->name = armalloc(n+1);
573219b2ee8SDavid du Colombier 	strcpy(as->name, s->name);
5747dd7cddfSDavid du Colombier 	if(s->type == 'T' && duplicate(as->name)) {
5757dd7cddfSDavid du Colombier 		dupfound = 1;
5767dd7cddfSDavid du Colombier 		fprint(2, "duplicate text symbol: %s\n", as->name);
5777dd7cddfSDavid du Colombier 		free(as->name);
5787dd7cddfSDavid du Colombier 		free(as);
5797dd7cddfSDavid du Colombier 		return;
5807dd7cddfSDavid du Colombier 	}
581219b2ee8SDavid du Colombier 	as->type = s->type;
582219b2ee8SDavid du Colombier 	symdefsize += 4+(n+1)+1;
583219b2ee8SDavid du Colombier 	as->len = n;
584219b2ee8SDavid du Colombier 	as->next = ap->sym;
585219b2ee8SDavid du Colombier 	ap->sym = as;
586219b2ee8SDavid du Colombier }
587219b2ee8SDavid du Colombier 
588bd389b36SDavid du Colombier /*
5897dd7cddfSDavid du Colombier  *	Check the symbol table for duplicate text symbols
5907dd7cddfSDavid du Colombier  */
5917dd7cddfSDavid du Colombier int
duplicate(char * name)5927dd7cddfSDavid du Colombier duplicate(char *name)
5937dd7cddfSDavid du Colombier {
5947dd7cddfSDavid du Colombier 	Hashchain *p;
5957dd7cddfSDavid du Colombier 	char *cp;
5967dd7cddfSDavid du Colombier 	int h;
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier 	h = 0;
5997dd7cddfSDavid du Colombier 	for(cp = name; *cp; h += *cp++)
6007dd7cddfSDavid du Colombier 		h *= 1119;
6017dd7cddfSDavid du Colombier 	if(h < 0)
6027dd7cddfSDavid du Colombier 		h = ~h;
6037dd7cddfSDavid du Colombier 	h %= NHASH;
6047dd7cddfSDavid du Colombier 
6057dd7cddfSDavid du Colombier 	for(p = hash[h]; p; p = p->next)
6067dd7cddfSDavid du Colombier 		if(strcmp(p->name, name) == 0)
6077dd7cddfSDavid du Colombier 			return 1;
6087dd7cddfSDavid du Colombier 	p = (Hashchain*) armalloc(sizeof(Hashchain));
6097dd7cddfSDavid du Colombier 	p->next = hash[h];
6107dd7cddfSDavid du Colombier 	p->name = name;
6117dd7cddfSDavid du Colombier 	hash[h] = p;
6127dd7cddfSDavid du Colombier 	return 0;
6137dd7cddfSDavid du Colombier }
6147dd7cddfSDavid du Colombier 
6157dd7cddfSDavid du Colombier /*
616bd389b36SDavid du Colombier  *	open an archive and validate its header
617bd389b36SDavid du Colombier  */
6183e12c5d1SDavid du Colombier int
openar(char * arname,int mode,int errok)619bd389b36SDavid du Colombier openar(char *arname, int mode, int errok)
6203e12c5d1SDavid du Colombier {
621bd389b36SDavid du Colombier 	int fd;
6223e12c5d1SDavid du Colombier 	char mbuf[SARMAG];
6233e12c5d1SDavid du Colombier 
624bd389b36SDavid du Colombier 	fd = open(arname, mode);
625bd389b36SDavid du Colombier 	if(fd >= 0){
626bd389b36SDavid du Colombier 		if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
627bd389b36SDavid du Colombier 			fprint(2, "ar: %s not in archive format\n", arname);
628bd389b36SDavid du Colombier 			exits("error");
6293e12c5d1SDavid du Colombier 		}
630bd389b36SDavid du Colombier 	}else if(!errok){
631bd389b36SDavid du Colombier 		fprint(2, "ar: cannot open %s: %r\n", arname);
632bd389b36SDavid du Colombier 		exits("error");
633bd389b36SDavid du Colombier 	}
634bd389b36SDavid du Colombier 	return fd;
635bd389b36SDavid du Colombier }
6364de34a7eSDavid du Colombier 
637bd389b36SDavid du Colombier /*
638bd389b36SDavid du Colombier  *	create an archive and set its header
639bd389b36SDavid du Colombier  */
640bd389b36SDavid du Colombier int
arcreate(char * arname)641bd389b36SDavid du Colombier arcreate(char *arname)
642bd389b36SDavid du Colombier {
643bd389b36SDavid du Colombier 	int fd;
644bd389b36SDavid du Colombier 
645bd389b36SDavid du Colombier 	fd = create(arname, OWRITE, 0664);
646bd389b36SDavid du Colombier 	if(fd < 0){
647bd389b36SDavid du Colombier 		fprint(2, "ar: cannot create %s: %r\n", arname);
648bd389b36SDavid du Colombier 		exits("error");
649bd389b36SDavid du Colombier 	}
650bd389b36SDavid du Colombier 	if(write(fd, ARMAG, SARMAG) != SARMAG)
651bd389b36SDavid du Colombier 		wrerr();
652bd389b36SDavid du Colombier 	return fd;
653bd389b36SDavid du Colombier }
6544de34a7eSDavid du Colombier 
655bd389b36SDavid du Colombier /*
656bd389b36SDavid du Colombier  *		error handling
657bd389b36SDavid du Colombier  */
658bd389b36SDavid du Colombier void
wrerr(void)659bd389b36SDavid du Colombier wrerr(void)
660bd389b36SDavid du Colombier {
661bd389b36SDavid du Colombier 	perror("ar: write error");
662bd389b36SDavid du Colombier 	exits("error");
6633e12c5d1SDavid du Colombier }
6643e12c5d1SDavid du Colombier 
6653e12c5d1SDavid du Colombier void
rderr(void)666bd389b36SDavid du Colombier rderr(void)
6673e12c5d1SDavid du Colombier {
668bd389b36SDavid du Colombier 	perror("ar: read error");
669bd389b36SDavid du Colombier 	exits("error");
670bd389b36SDavid du Colombier }
6713e12c5d1SDavid du Colombier 
672bd389b36SDavid du Colombier void
phaseerr(int offset)673bd389b36SDavid du Colombier phaseerr(int offset)
674bd389b36SDavid du Colombier {
675bd389b36SDavid du Colombier 	fprint(2, "ar: phase error at offset %d\n", offset);
676bd389b36SDavid du Colombier 	exits("error");
6773e12c5d1SDavid du Colombier }
6783e12c5d1SDavid du Colombier 
6793e12c5d1SDavid du Colombier void
usage(void)6803e12c5d1SDavid du Colombier usage(void)
6813e12c5d1SDavid du Colombier {
682bd389b36SDavid du Colombier 	fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man);
683bd389b36SDavid du Colombier 	exits("error");
6843e12c5d1SDavid du Colombier }
6854de34a7eSDavid du Colombier 
6863e12c5d1SDavid du Colombier /*
687bd389b36SDavid du Colombier  *	read the header for the next archive member
6883e12c5d1SDavid du Colombier  */
689bd389b36SDavid du Colombier Armember *
getdir(Biobuf * b)690219b2ee8SDavid du Colombier getdir(Biobuf *b)
6913e12c5d1SDavid du Colombier {
692bd389b36SDavid du Colombier 	Armember *bp;
6933e12c5d1SDavid du Colombier 	char *cp;
694bd389b36SDavid du Colombier 	static char name[ARNAMESIZE+1];
6953e12c5d1SDavid du Colombier 
696bd389b36SDavid du Colombier 	bp = newmember();
697219b2ee8SDavid du Colombier 	if(HEADER_IO(Bread, b, bp->hdr)) {
698bd389b36SDavid du Colombier 		free(bp);
699bd389b36SDavid du Colombier 		return 0;
7003e12c5d1SDavid du Colombier 	}
701*25fc6993SDavid du Colombier 	if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)) != 0)
7027dd7cddfSDavid du Colombier 		phaseerr(Boffset(b));
703bd389b36SDavid du Colombier 	strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
704bd389b36SDavid du Colombier 	cp = name+sizeof(name)-1;
705*25fc6993SDavid du Colombier 	*cp = '\0';
706*25fc6993SDavid du Colombier 	/* skip trailing spaces and (gnu-produced) slashes */
707*25fc6993SDavid du Colombier 	while(*--cp == ' ' || *cp == '/')
7083e12c5d1SDavid du Colombier 		;
7093e12c5d1SDavid du Colombier 	cp[1] = '\0';
7103e12c5d1SDavid du Colombier 	file = name;
7114de34a7eSDavid du Colombier 	bp->date = strtol(bp->hdr.date, 0, 0);
7124de34a7eSDavid du Colombier 	bp->size = strtol(bp->hdr.size, 0, 0);
713bd389b36SDavid du Colombier 	return bp;
7143e12c5d1SDavid du Colombier }
7154de34a7eSDavid du Colombier 
716bd389b36SDavid du Colombier /*
717bd389b36SDavid du Colombier  *	Copy the file referenced by fd to the temp file
718bd389b36SDavid du Colombier  */
719bd389b36SDavid du Colombier void
armove(Biobuf * b,Arfile * ap,Armember * bp)720219b2ee8SDavid du Colombier armove(Biobuf *b, Arfile *ap, Armember *bp)
721bd389b36SDavid du Colombier {
722bd389b36SDavid du Colombier 	char *cp;
7239a747e4fSDavid du Colombier 	Dir *d;
7243e12c5d1SDavid du Colombier 
7259a747e4fSDavid du Colombier 	d = dirfstat(Bfildes(b));
7269a747e4fSDavid du Colombier 	if (d == nil) {
727bd389b36SDavid du Colombier 		fprint(2, "ar: cannot stat %s\n", file);
728bd389b36SDavid du Colombier 		return;
729bd389b36SDavid du Colombier 	}
730bd389b36SDavid du Colombier 	trim(file, bp->hdr.name, sizeof(bp->hdr.name));
731bd389b36SDavid du Colombier 	for (cp = strchr(bp->hdr.name, 0);		/* blank pad on right */
732bd389b36SDavid du Colombier 		cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
733bd389b36SDavid du Colombier 			*cp = ' ';
7349a747e4fSDavid du Colombier 	sprint(bp->hdr.date, "%-12ld", d->mtime);
735bd389b36SDavid du Colombier 	sprint(bp->hdr.uid, "%-6d", 0);
736bd389b36SDavid du Colombier 	sprint(bp->hdr.gid, "%-6d", 0);
7379a747e4fSDavid du Colombier 	sprint(bp->hdr.mode, "%-8lo", d->mode);
7389a747e4fSDavid du Colombier 	sprint(bp->hdr.size, "%-10lld", d->length);
739bd389b36SDavid du Colombier 	strncpy(bp->hdr.fmag, ARFMAG, 2);
7409a747e4fSDavid du Colombier 	bp->size = d->length;
741219b2ee8SDavid du Colombier 	arread(b, bp, bp->size);
7429a747e4fSDavid du Colombier 	if (d->length&0x01)
7439a747e4fSDavid du Colombier 		d->length++;
744219b2ee8SDavid du Colombier 	if (ap) {
745bd389b36SDavid du Colombier 		arinsert(ap, bp);
7469a747e4fSDavid du Colombier 		ap->size += d->length+SAR_HDR;
747219b2ee8SDavid du Colombier 	}
7489a747e4fSDavid du Colombier 	free(d);
749bd389b36SDavid du Colombier }
7504de34a7eSDavid du Colombier 
751bd389b36SDavid du Colombier /*
752bd389b36SDavid du Colombier  *	Copy the archive member at the current offset into the temp file.
753bd389b36SDavid du Colombier  */
754bd389b36SDavid du Colombier void
arcopy(Biobuf * b,Arfile * ap,Armember * bp)755219b2ee8SDavid du Colombier arcopy(Biobuf *b, Arfile *ap, Armember *bp)
756bd389b36SDavid du Colombier {
7574de34a7eSDavid du Colombier 	long n;
7583e12c5d1SDavid du Colombier 
759bd389b36SDavid du Colombier 	n = bp->size;
760bd389b36SDavid du Colombier 	if (n & 01)
761bd389b36SDavid du Colombier 		n++;
762219b2ee8SDavid du Colombier 	arread(b, bp, n);
763219b2ee8SDavid du Colombier 	if (ap) {
764bd389b36SDavid du Colombier 		arinsert(ap, bp);
765219b2ee8SDavid du Colombier 		ap->size += n+SAR_HDR;
766219b2ee8SDavid du Colombier 	}
767bd389b36SDavid du Colombier }
7684de34a7eSDavid du Colombier 
769bd389b36SDavid du Colombier /*
770bd389b36SDavid du Colombier  *	Skip an archive member
771bd389b36SDavid du Colombier  */
772bd389b36SDavid du Colombier void
skip(Biobuf * bp,vlong len)7734de34a7eSDavid du Colombier skip(Biobuf *bp, vlong len)
774bd389b36SDavid du Colombier {
775bd389b36SDavid du Colombier 	if (len & 01)
776bd389b36SDavid du Colombier 		len++;
777219b2ee8SDavid du Colombier 	Bseek(bp, len, 1);
778bd389b36SDavid du Colombier }
7794de34a7eSDavid du Colombier 
780bd389b36SDavid du Colombier /*
781bd389b36SDavid du Colombier  *	Stream the three temp files to an archive
782bd389b36SDavid du Colombier  */
783bd389b36SDavid du Colombier void
install(char * arname,Arfile * astart,Arfile * amiddle,Arfile * aend,int createflag)7847dd7cddfSDavid du Colombier install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
785bd389b36SDavid du Colombier {
786bd389b36SDavid du Colombier 	int fd;
787bd389b36SDavid du Colombier 
7887dd7cddfSDavid du Colombier 	if(allobj && dupfound) {
7897dd7cddfSDavid du Colombier 		fprint(2, "%s not changed\n", arname);
7907dd7cddfSDavid du Colombier 		return;
7917dd7cddfSDavid du Colombier 	}
792bd389b36SDavid du Colombier 	/* leave note group behind when copying back; i.e. sidestep interrupts */
793bd389b36SDavid du Colombier 	rfork(RFNOTEG);
7947dd7cddfSDavid du Colombier 
7957dd7cddfSDavid du Colombier 	if(createflag)
7967dd7cddfSDavid du Colombier 		fprint(2, "ar: creating %s\n", arname);
797bd389b36SDavid du Colombier 	fd = arcreate(arname);
7987dd7cddfSDavid du Colombier 
7997dd7cddfSDavid du Colombier 	if(allobj)
800219b2ee8SDavid du Colombier 		rl(fd);
8017dd7cddfSDavid du Colombier 
802bd389b36SDavid du Colombier 	if (astart) {
803bd389b36SDavid du Colombier 		arstream(fd, astart);
804bd389b36SDavid du Colombier 		arfree(astart);
805bd389b36SDavid du Colombier 	}
806bd389b36SDavid du Colombier 	if (amiddle) {
807bd389b36SDavid du Colombier 		arstream(fd, amiddle);
808bd389b36SDavid du Colombier 		arfree(amiddle);
809bd389b36SDavid du Colombier 	}
810bd389b36SDavid du Colombier 	if (aend) {
811bd389b36SDavid du Colombier 		arstream(fd, aend);
812bd389b36SDavid du Colombier 		arfree(aend);
813bd389b36SDavid du Colombier 	}
814bd389b36SDavid du Colombier 	close(fd);
815bd389b36SDavid du Colombier }
8167dd7cddfSDavid du Colombier 
817219b2ee8SDavid du Colombier void
rl(int fd)818219b2ee8SDavid du Colombier rl(int fd)
819219b2ee8SDavid du Colombier {
820219b2ee8SDavid du Colombier 
821219b2ee8SDavid du Colombier 	Biobuf b;
822219b2ee8SDavid du Colombier 	char *cp;
823219b2ee8SDavid du Colombier 	struct ar_hdr a;
824219b2ee8SDavid du Colombier 	long len;
825219b2ee8SDavid du Colombier 
826219b2ee8SDavid du Colombier 	Binit(&b, fd, OWRITE);
827219b2ee8SDavid du Colombier 	Bseek(&b,seek(fd,0,1), 0);
828219b2ee8SDavid du Colombier 
829219b2ee8SDavid du Colombier 	len = symdefsize;
830219b2ee8SDavid du Colombier 	if(len&01)
831219b2ee8SDavid du Colombier 		len++;
832219b2ee8SDavid du Colombier 	sprint(a.date, "%-12ld", time(0));
833219b2ee8SDavid du Colombier 	sprint(a.uid, "%-6d", 0);
834219b2ee8SDavid du Colombier 	sprint(a.gid, "%-6d", 0);
8357dd7cddfSDavid du Colombier 	sprint(a.mode, "%-8lo", 0644L);
836219b2ee8SDavid du Colombier 	sprint(a.size, "%-10ld", len);
837219b2ee8SDavid du Colombier 	strncpy(a.fmag, ARFMAG, 2);
838219b2ee8SDavid du Colombier 	strcpy(a.name, symdef);
839219b2ee8SDavid du Colombier 	for (cp = strchr(a.name, 0);		/* blank pad on right */
840219b2ee8SDavid du Colombier 		cp < a.name+sizeof(a.name); cp++)
841219b2ee8SDavid du Colombier 			*cp = ' ';
842219b2ee8SDavid du Colombier 	if(HEADER_IO(Bwrite, &b, a))
843219b2ee8SDavid du Colombier 			wrerr();
844219b2ee8SDavid du Colombier 
8457dd7cddfSDavid du Colombier 	len += Boffset(&b);
846219b2ee8SDavid du Colombier 	if (astart) {
847219b2ee8SDavid du Colombier 		wrsym(&b, len, astart->sym);
848219b2ee8SDavid du Colombier 		len += astart->size;
849219b2ee8SDavid du Colombier 	}
850219b2ee8SDavid du Colombier 	if(amiddle) {
851219b2ee8SDavid du Colombier 		wrsym(&b, len, amiddle->sym);
852219b2ee8SDavid du Colombier 		len += amiddle->size;
853219b2ee8SDavid du Colombier 	}
854219b2ee8SDavid du Colombier 	if(aend)
855219b2ee8SDavid du Colombier 		wrsym(&b, len, aend->sym);
856219b2ee8SDavid du Colombier 
857219b2ee8SDavid du Colombier 	if(symdefsize&0x01)
858219b2ee8SDavid du Colombier 		Bputc(&b, 0);
859219b2ee8SDavid du Colombier 	Bterm(&b);
860219b2ee8SDavid du Colombier }
8614de34a7eSDavid du Colombier 
862219b2ee8SDavid du Colombier /*
863219b2ee8SDavid du Colombier  *	Write the defined symbols to the symdef file
864219b2ee8SDavid du Colombier  */
865219b2ee8SDavid du Colombier void
wrsym(Biobuf * bp,long offset,Arsymref * as)8664de34a7eSDavid du Colombier wrsym(Biobuf *bp, long offset, Arsymref *as)
867219b2ee8SDavid du Colombier {
868219b2ee8SDavid du Colombier 	int off;
869219b2ee8SDavid du Colombier 
870219b2ee8SDavid du Colombier 	while(as) {
871219b2ee8SDavid du Colombier 		Bputc(bp, as->type);
872219b2ee8SDavid du Colombier 		off = as->offset+offset;
873219b2ee8SDavid du Colombier 		Bputc(bp, off);
874219b2ee8SDavid du Colombier 		Bputc(bp, off>>8);
875219b2ee8SDavid du Colombier 		Bputc(bp, off>>16);
876219b2ee8SDavid du Colombier 		Bputc(bp, off>>24);
877219b2ee8SDavid du Colombier 		if (Bwrite(bp, as->name, as->len+1) != as->len+1)
878219b2ee8SDavid du Colombier 			wrerr();
879219b2ee8SDavid du Colombier 		as = as->next;
880219b2ee8SDavid du Colombier 	}
881219b2ee8SDavid du Colombier }
8824de34a7eSDavid du Colombier 
883bd389b36SDavid du Colombier /*
884bd389b36SDavid du Colombier  *	Check if the archive member matches an entry on the command line.
885bd389b36SDavid du Colombier  */
8863e12c5d1SDavid du Colombier int
match(int count,char ** files)887bd389b36SDavid du Colombier match(int count, char **files)
8883e12c5d1SDavid du Colombier {
8893e12c5d1SDavid du Colombier 	int i;
890bd389b36SDavid du Colombier 	char name[ARNAMESIZE+1];
8913e12c5d1SDavid du Colombier 
892bd389b36SDavid du Colombier 	for(i=0; i<count; i++) {
893bd389b36SDavid du Colombier 		if(files[i] == 0)
8943e12c5d1SDavid du Colombier 			continue;
895219b2ee8SDavid du Colombier 		trim(files[i], name, ARNAMESIZE);
896219b2ee8SDavid du Colombier 		if(strncmp(name, file, ARNAMESIZE) == 0) {
897bd389b36SDavid du Colombier 			file = files[i];
898bd389b36SDavid du Colombier 			files[i] = 0;
8993e12c5d1SDavid du Colombier 			return 1;
9003e12c5d1SDavid du Colombier 		}
9013e12c5d1SDavid du Colombier 	}
9023e12c5d1SDavid du Colombier 	return 0;
9033e12c5d1SDavid du Colombier }
9044de34a7eSDavid du Colombier 
905bd389b36SDavid du Colombier /*
906bd389b36SDavid du Colombier  *	compare the current member to the name of the pivot member
907bd389b36SDavid du Colombier  */
908bd389b36SDavid du Colombier int
bamatch(char * file,char * pivot)909bd389b36SDavid du Colombier bamatch(char *file, char *pivot)
9103e12c5d1SDavid du Colombier {
911bd389b36SDavid du Colombier 	static int state = 0;
9123e12c5d1SDavid du Colombier 
913bd389b36SDavid du Colombier 	switch(state)
914bd389b36SDavid du Colombier 	{
915bd389b36SDavid du Colombier 	case 0:			/* looking for position file */
916bd389b36SDavid du Colombier 		if (aflag) {
917219b2ee8SDavid du Colombier 			if (strncmp(file, pivot, ARNAMESIZE) == 0)
918bd389b36SDavid du Colombier 				state = 1;
919bd389b36SDavid du Colombier 		} else if (bflag) {
920219b2ee8SDavid du Colombier 			if (strncmp(file, pivot, ARNAMESIZE) == 0) {
921bd389b36SDavid du Colombier 				state = 2;	/* found */
922bd389b36SDavid du Colombier 				return 1;
9233e12c5d1SDavid du Colombier 			}
9243e12c5d1SDavid du Colombier 		}
925bd389b36SDavid du Colombier 		break;
926bd389b36SDavid du Colombier 	case 1:			/* found - after previous file */
927bd389b36SDavid du Colombier 		state = 2;
928bd389b36SDavid du Colombier 		return 1;
929bd389b36SDavid du Colombier 	case 2:			/* already found position file */
930bd389b36SDavid du Colombier 		break;
931bd389b36SDavid du Colombier 	}
932bd389b36SDavid du Colombier 	return 0;
933bd389b36SDavid du Colombier }
9344de34a7eSDavid du Colombier 
935bd389b36SDavid du Colombier /*
936bd389b36SDavid du Colombier  *	output a message, if 'v' option was specified
937bd389b36SDavid du Colombier  */
9383e12c5d1SDavid du Colombier void
mesg(int c,char * file)939bd389b36SDavid du Colombier mesg(int c, char *file)
9403e12c5d1SDavid du Colombier {
9413e12c5d1SDavid du Colombier 
942bd389b36SDavid du Colombier 	if(vflag)
9433e12c5d1SDavid du Colombier 		Bprint(&bout, "%c - %s\n", c, file);
9443e12c5d1SDavid du Colombier }
9454de34a7eSDavid du Colombier 
946bd389b36SDavid du Colombier /*
947bd389b36SDavid du Colombier  *	isolate file name by stripping leading directories and trailing slashes
948bd389b36SDavid du Colombier  */
949bd389b36SDavid du Colombier void
trim(char * s,char * buf,int n)950bd389b36SDavid du Colombier trim(char *s, char *buf, int n)
9513e12c5d1SDavid du Colombier {
952bd389b36SDavid du Colombier 	char *p;
9533e12c5d1SDavid du Colombier 
954bd389b36SDavid du Colombier 	for(;;) {
955bd389b36SDavid du Colombier 		p = strrchr(s, '/');
956bd389b36SDavid du Colombier 		if (!p) {		/* no slash in name */
957bd389b36SDavid du Colombier 			strncpy(buf, s, n);
958bd389b36SDavid du Colombier 			return;
9593e12c5d1SDavid du Colombier 		}
960bd389b36SDavid du Colombier 		if (p[1] != 0) {	/* p+1 is first char of file name */
961bd389b36SDavid du Colombier 			strncpy(buf, p+1, n);
962bd389b36SDavid du Colombier 			return;
9633e12c5d1SDavid du Colombier 		}
964bd389b36SDavid du Colombier 		*p = 0;			/* strip trailing slash */
965bd389b36SDavid du Colombier 	}
966bd389b36SDavid du Colombier }
9674de34a7eSDavid du Colombier 
968bd389b36SDavid du Colombier /*
969bd389b36SDavid du Colombier  *	utilities for printing long form of 't' command
970bd389b36SDavid du Colombier  */
9713e12c5d1SDavid du Colombier #define	SUID	04000
9723e12c5d1SDavid du Colombier #define	SGID	02000
9733e12c5d1SDavid du Colombier #define	ROWN	0400
9743e12c5d1SDavid du Colombier #define	WOWN	0200
9753e12c5d1SDavid du Colombier #define	XOWN	0100
9763e12c5d1SDavid du Colombier #define	RGRP	040
9773e12c5d1SDavid du Colombier #define	WGRP	020
9783e12c5d1SDavid du Colombier #define	XGRP	010
9793e12c5d1SDavid du Colombier #define	ROTH	04
9803e12c5d1SDavid du Colombier #define	WOTH	02
9813e12c5d1SDavid du Colombier #define	XOTH	01
9823e12c5d1SDavid du Colombier #define	STXT	01000
9833e12c5d1SDavid du Colombier 
9843e12c5d1SDavid du Colombier void
longt(Armember * bp)985bd389b36SDavid du Colombier longt(Armember *bp)
9863e12c5d1SDavid du Colombier {
9873e12c5d1SDavid du Colombier 	char *cp;
9883e12c5d1SDavid du Colombier 
989bd389b36SDavid du Colombier 	pmode(strtoul(bp->hdr.mode, 0, 8));
9904de34a7eSDavid du Colombier 	Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
991bd389b36SDavid du Colombier 	Bprint(&bout, "%7ld", bp->size);
992bd389b36SDavid du Colombier 	cp = ctime(bp->date);
9933e12c5d1SDavid du Colombier 	Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
9943e12c5d1SDavid du Colombier }
9953e12c5d1SDavid du Colombier 
9963e12c5d1SDavid du Colombier int	m1[] = { 1, ROWN, 'r', '-' };
9973e12c5d1SDavid du Colombier int	m2[] = { 1, WOWN, 'w', '-' };
9983e12c5d1SDavid du Colombier int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
9993e12c5d1SDavid du Colombier int	m4[] = { 1, RGRP, 'r', '-' };
10003e12c5d1SDavid du Colombier int	m5[] = { 1, WGRP, 'w', '-' };
10013e12c5d1SDavid du Colombier int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
10023e12c5d1SDavid du Colombier int	m7[] = { 1, ROTH, 'r', '-' };
10033e12c5d1SDavid du Colombier int	m8[] = { 1, WOTH, 'w', '-' };
10043e12c5d1SDavid du Colombier int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
10053e12c5d1SDavid du Colombier 
10063e12c5d1SDavid du Colombier int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
10073e12c5d1SDavid du Colombier 
10083e12c5d1SDavid du Colombier void
pmode(long mode)1009bd389b36SDavid du Colombier pmode(long mode)
10103e12c5d1SDavid du Colombier {
10113e12c5d1SDavid du Colombier 	int **mp;
10123e12c5d1SDavid du Colombier 
10133e12c5d1SDavid du Colombier 	for(mp = &m[0]; mp < &m[9];)
1014bd389b36SDavid du Colombier 		select(*mp++, mode);
10153e12c5d1SDavid du Colombier }
10163e12c5d1SDavid du Colombier 
10173e12c5d1SDavid du Colombier void
select(int * ap,long mode)1018bd389b36SDavid du Colombier select(int *ap, long mode)
10193e12c5d1SDavid du Colombier {
1020bd389b36SDavid du Colombier 	int n;
10213e12c5d1SDavid du Colombier 
10223e12c5d1SDavid du Colombier 	n = *ap++;
1023bd389b36SDavid du Colombier 	while(--n>=0 && (mode&*ap++)==0)
10243e12c5d1SDavid du Colombier 		ap++;
10253e12c5d1SDavid du Colombier 	Bputc(&bout, *ap);
10263e12c5d1SDavid du Colombier }
10274de34a7eSDavid du Colombier 
1028bd389b36SDavid du Colombier /*
1029bd389b36SDavid du Colombier  *	Temp file I/O subsystem.  We attempt to cache all three temp files in
1030bd389b36SDavid du Colombier  *	core.  When we run out of memory we spill to disk.
1031bd389b36SDavid du Colombier  *	The I/O model assumes that temp files:
1032bd389b36SDavid du Colombier  *		1) are only written on the end
1033bd389b36SDavid du Colombier  *		2) are only read from the beginning
1034bd389b36SDavid du Colombier  *		3) are only read after all writing is complete.
1035bd389b36SDavid du Colombier  *	The architecture uses one control block per temp file.  Each control
1036bd389b36SDavid du Colombier  *	block anchors a chain of buffers, each containing an archive member.
1037bd389b36SDavid du Colombier  */
1038bd389b36SDavid du Colombier Arfile *
newtempfile(char * name)1039bd389b36SDavid du Colombier newtempfile(char *name)		/* allocate a file control block */
1040bd389b36SDavid du Colombier {
1041bd389b36SDavid du Colombier 	Arfile *ap;
1042bd389b36SDavid du Colombier 
1043bd389b36SDavid du Colombier 	ap = (Arfile *) armalloc(sizeof(Arfile));
1044bd389b36SDavid du Colombier 	ap->fname = name;
1045bd389b36SDavid du Colombier 	return ap;
1046bd389b36SDavid du Colombier }
1047bd389b36SDavid du Colombier 
1048bd389b36SDavid du Colombier Armember *
newmember(void)1049bd389b36SDavid du Colombier newmember(void)			/* allocate a member buffer */
1050bd389b36SDavid du Colombier {
1051bd389b36SDavid du Colombier 	return (Armember *)armalloc(sizeof(Armember));
1052bd389b36SDavid du Colombier }
10533e12c5d1SDavid du Colombier 
10543e12c5d1SDavid du Colombier void
arread(Biobuf * b,Armember * bp,int n)1055219b2ee8SDavid du Colombier arread(Biobuf *b, Armember *bp, int n)	/* read an image into a member buffer */
10563e12c5d1SDavid du Colombier {
1057bd389b36SDavid du Colombier 	int i;
1058bd389b36SDavid du Colombier 
1059bd389b36SDavid du Colombier 	bp->member = armalloc(n);
1060219b2ee8SDavid du Colombier 	i = Bread(b, bp->member, n);
1061bd389b36SDavid du Colombier 	if (i < 0) {
1062bd389b36SDavid du Colombier 		free(bp->member);
1063bd389b36SDavid du Colombier 		bp->member = 0;
1064bd389b36SDavid du Colombier 		rderr();
1065bd389b36SDavid du Colombier 	}
1066bd389b36SDavid du Colombier }
10674de34a7eSDavid du Colombier 
1068bd389b36SDavid du Colombier /*
1069bd389b36SDavid du Colombier  * insert a member buffer into the member chain
1070bd389b36SDavid du Colombier  */
1071bd389b36SDavid du Colombier void
arinsert(Arfile * ap,Armember * bp)1072bd389b36SDavid du Colombier arinsert(Arfile *ap, Armember *bp)
1073bd389b36SDavid du Colombier {
1074bd389b36SDavid du Colombier 	bp->next = 0;
1075bd389b36SDavid du Colombier 	if (!ap->tail)
1076bd389b36SDavid du Colombier 		ap->head = bp;
1077bd389b36SDavid du Colombier 	else
1078bd389b36SDavid du Colombier 		ap->tail->next = bp;
1079bd389b36SDavid du Colombier 	ap->tail = bp;
1080bd389b36SDavid du Colombier }
10814de34a7eSDavid du Colombier 
1082bd389b36SDavid du Colombier /*
1083bd389b36SDavid du Colombier  *	stream the members in a temp file to the file referenced by 'fd'.
1084bd389b36SDavid du Colombier  */
1085bd389b36SDavid du Colombier void
arstream(int fd,Arfile * ap)1086bd389b36SDavid du Colombier arstream(int fd, Arfile *ap)
1087bd389b36SDavid du Colombier {
1088bd389b36SDavid du Colombier 	Armember *bp;
1089bd389b36SDavid du Colombier 	int i;
1090bd389b36SDavid du Colombier 	char buf[8192];
1091bd389b36SDavid du Colombier 
1092bd389b36SDavid du Colombier 	if (ap->paged) {		/* copy from disk */
1093bd389b36SDavid du Colombier 		seek(ap->fd, 0, 0);
1094bd389b36SDavid du Colombier 		for (;;) {
1095bd389b36SDavid du Colombier 			i = read(ap->fd, buf, sizeof(buf));
1096bd389b36SDavid du Colombier 			if (i < 0)
1097bd389b36SDavid du Colombier 				rderr();
1098bd389b36SDavid du Colombier 			if (i == 0)
1099bd389b36SDavid du Colombier 				break;
1100bd389b36SDavid du Colombier 			if (write(fd, buf, i) != i)
1101bd389b36SDavid du Colombier 				wrerr();
1102bd389b36SDavid du Colombier 		}
1103bd389b36SDavid du Colombier 		close(ap->fd);
1104bd389b36SDavid du Colombier 		ap->paged = 0;
1105bd389b36SDavid du Colombier 	}
1106bd389b36SDavid du Colombier 		/* dump the in-core buffers */
1107bd389b36SDavid du Colombier 	for (bp = ap->head; bp; bp = bp->next) {
1108bd389b36SDavid du Colombier 		if (!arwrite(fd, bp))
1109bd389b36SDavid du Colombier 			wrerr();
1110bd389b36SDavid du Colombier 	}
1111bd389b36SDavid du Colombier }
11124de34a7eSDavid du Colombier 
1113bd389b36SDavid du Colombier /*
1114bd389b36SDavid du Colombier  *	write a member to 'fd'.
1115bd389b36SDavid du Colombier  */
1116bd389b36SDavid du Colombier int
arwrite(int fd,Armember * bp)1117bd389b36SDavid du Colombier arwrite(int fd, Armember *bp)
1118bd389b36SDavid du Colombier {
1119bd389b36SDavid du Colombier 	int len;
1120bd389b36SDavid du Colombier 
1121219b2ee8SDavid du Colombier 	if(HEADER_IO(write, fd, bp->hdr))
1122bd389b36SDavid du Colombier 		return 0;
1123bd389b36SDavid du Colombier 	len = bp->size;
1124bd389b36SDavid du Colombier 	if (len & 01)
1125bd389b36SDavid du Colombier 		len++;
1126bd389b36SDavid du Colombier 	if (write(fd, bp->member, len) != len)
1127bd389b36SDavid du Colombier 		return 0;
1128bd389b36SDavid du Colombier 	return 1;
1129bd389b36SDavid du Colombier }
11304de34a7eSDavid du Colombier 
1131bd389b36SDavid du Colombier /*
1132bd389b36SDavid du Colombier  *	Spill a member to a disk copy of a temp file
1133bd389b36SDavid du Colombier  */
1134bd389b36SDavid du Colombier int
page(Arfile * ap)1135bd389b36SDavid du Colombier page(Arfile *ap)
1136bd389b36SDavid du Colombier {
1137bd389b36SDavid du Colombier 	Armember *bp;
1138bd389b36SDavid du Colombier 
1139bd389b36SDavid du Colombier 	bp = ap->head;
1140bd389b36SDavid du Colombier 	if (!ap->paged) {		/* not yet paged - create file */
1141bd389b36SDavid du Colombier 		ap->fname = mktemp(ap->fname);
1142bd389b36SDavid du Colombier 		ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
1143bd389b36SDavid du Colombier 		if (ap->fd < 0) {
1144bd389b36SDavid du Colombier 			fprint(2,"ar: can't create temp file\n");
1145bd389b36SDavid du Colombier 			return 0;
1146bd389b36SDavid du Colombier 		}
1147bd389b36SDavid du Colombier 		ap->paged = 1;
1148bd389b36SDavid du Colombier 	}
1149bd389b36SDavid du Colombier 	if (!arwrite(ap->fd, bp))	/* write member and free buffer block */
1150bd389b36SDavid du Colombier 		return 0;
1151bd389b36SDavid du Colombier 	ap->head = bp->next;
1152bd389b36SDavid du Colombier 	if (ap->tail == bp)
1153bd389b36SDavid du Colombier 		ap->tail = bp->next;
1154bd389b36SDavid du Colombier 	free(bp->member);
1155bd389b36SDavid du Colombier 	free(bp);
1156bd389b36SDavid du Colombier 	return 1;
1157bd389b36SDavid du Colombier }
11584de34a7eSDavid du Colombier 
1159bd389b36SDavid du Colombier /*
1160bd389b36SDavid du Colombier  *	try to reclaim space by paging.  we try to spill the start, middle,
1161bd389b36SDavid du Colombier  *	and end files, in that order.  there is no particular reason for the
1162bd389b36SDavid du Colombier  *	ordering.
1163bd389b36SDavid du Colombier  */
1164bd389b36SDavid du Colombier int
getspace(void)1165bd389b36SDavid du Colombier getspace(void)
1166bd389b36SDavid du Colombier {
1167bd389b36SDavid du Colombier 	if (astart && astart->head && page(astart))
1168bd389b36SDavid du Colombier 			return 1;
1169bd389b36SDavid du Colombier 	if (amiddle && amiddle->head && page(amiddle))
1170bd389b36SDavid du Colombier 			return 1;
1171bd389b36SDavid du Colombier 	if (aend && aend->head && page(aend))
1172bd389b36SDavid du Colombier 			return 1;
1173bd389b36SDavid du Colombier 	return 0;
1174bd389b36SDavid du Colombier }
1175bd389b36SDavid du Colombier 
1176bd389b36SDavid du Colombier void
arfree(Arfile * ap)1177bd389b36SDavid du Colombier arfree(Arfile *ap)		/* free a member buffer */
1178bd389b36SDavid du Colombier {
1179bd389b36SDavid du Colombier 	Armember *bp, *next;
1180bd389b36SDavid du Colombier 
1181bd389b36SDavid du Colombier 	for (bp = ap->head; bp; bp = next) {
1182bd389b36SDavid du Colombier 		next = bp->next;
1183bd389b36SDavid du Colombier 		if (bp->member)
1184bd389b36SDavid du Colombier 			free(bp->member);
1185bd389b36SDavid du Colombier 		free(bp);
1186bd389b36SDavid du Colombier 	}
1187bd389b36SDavid du Colombier 	free(ap);
1188bd389b36SDavid du Colombier }
11894de34a7eSDavid du Colombier 
1190bd389b36SDavid du Colombier /*
1191bd389b36SDavid du Colombier  *	allocate space for a control block or member buffer.  if the malloc
1192bd389b36SDavid du Colombier  *	fails we try to reclaim space by spilling previously allocated
1193bd389b36SDavid du Colombier  *	member buffers.
1194bd389b36SDavid du Colombier  */
1195bd389b36SDavid du Colombier char *
armalloc(int n)1196bd389b36SDavid du Colombier armalloc(int n)
1197bd389b36SDavid du Colombier {
1198bd389b36SDavid du Colombier 	char *cp;
1199bd389b36SDavid du Colombier 
1200bd389b36SDavid du Colombier 	do {
1201bd389b36SDavid du Colombier 		cp = malloc(n);
1202bd389b36SDavid du Colombier 		if (cp) {
1203bd389b36SDavid du Colombier 			memset(cp, 0, n);
1204bd389b36SDavid du Colombier 			return cp;
1205bd389b36SDavid du Colombier 		}
1206bd389b36SDavid du Colombier 	} while (getspace());
1207bd389b36SDavid du Colombier 	fprint(2, "ar: out of memory\n");
1208bd389b36SDavid du Colombier 	exits("malloc");
1209bd389b36SDavid du Colombier 	return 0;
12103e12c5d1SDavid du Colombier }
1211