scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  1#include <ctype.h>
  2#include <errno.h>
  3#include <limits.h>
  4#include <stdarg.h>
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <string.h>
  8#include <time.h>
  9
 10#include <scc/ar.h>
 11#include <scc/arg.h>
 12#include <scc/mach.h>
 13#include <scc/scc.h>
 14
 15#define NR_SYMDEF 32
 16
 17typedef struct symdef Symdef;
 18
 19struct symdef {
 20	char *name;
 21	int type;
 22	long offset;
 23	Symdef *hash, *next;
 24};
 25
 26static char *namidx;
 27static long nsymbols;
 28static int status, artype, nolib;
 29static char *filename, *membname;
 30static Symdef *htab[NR_SYMDEF], *head;
 31char *argv0;
 32
 33static void
 34error(char *fmt, ...)
 35{
 36	va_list va;
 37
 38	va_start(va, fmt);
 39	fprintf(stderr, "scc-ranlib: %s: ", filename);
 40	if (membname)
 41		fprintf(stderr, "%s: ", membname);
 42	vfprintf(stderr, fmt, va);
 43	putc('\n', stderr);
 44	va_end(va);
 45
 46	status = EXIT_FAILURE;
 47}
 48
 49Symdef *
 50lookup(char *name)
 51{
 52	unsigned h;
 53	Symdef *dp;
 54	char *s;
 55	size_t len;
 56
 57	h = genhash(name) % NR_SYMDEF;
 58
 59	for (dp = htab[h]; dp; dp = dp->next) {
 60		if (!strcmp(dp->name, name))
 61			return dp;
 62	}
 63
 64	len = strlen(name) + 1;
 65	dp = malloc(sizeof(*dp));
 66	s = malloc(len);
 67	if (!dp || !s) {
 68		free(s);
 69		free(dp);
 70		return NULL;
 71	}
 72
 73	nsymbols++;
 74	dp->name = s;
 75	memcpy(dp->name, name, len);
 76	dp->type = 'U';
 77	dp->offset = -1;
 78	dp->hash = htab[h];
 79	htab[h] = dp;
 80	dp->next = head;
 81	head = dp;
 82
 83	return dp;
 84}
 85
 86static int
 87newsymbol(Symbol *sym, long off)
 88{
 89	Symdef *np;
 90
 91	if (!isupper(sym->type) || sym->type == 'N' || sym->type == 'U')
 92		return 1;
 93
 94	if ((np = lookup(sym->name)) == NULL) {
 95		error(strerror(errno));
 96		return 0;
 97	}
 98
 99	switch (np->type) {
100	case 'C':
101		if (sym->type == 'C')
102			break;
103	case 'U':
104		np->type = sym->type;
105		np->offset = off;
106		break;
107	default:
108		if (sym->type != 'C') {
109			error("multiple definitions of '%s'", sym->name);
110			return 0;
111		}
112	}
113
114	return 1;
115}
116
117static void
118freehash(void)
119{
120	Symdef **npp, *next, *np;
121
122	for (npp = htab; npp < &htab[NR_SYMDEF]; npp++)
123		*npp = NULL;
124
125	for (np = head; np; np = next) {
126		next = np->next;
127		free(np->name);
128		free(np);
129	}
130
131	head = NULL;
132}
133
134static int
135newmember(FILE *fp, long off)
136{
137	int i,t, ret = 0;
138	Obj *obj;
139	Symbol sym;
140
141	t = objprobe(fp, NULL);
142	if (t == -1 || artype != -1 && artype != t) {
143		nolib = 1;
144		return 0;
145	}
146	artype = t;
147
148	if ((obj = newobj(t)) == NULL) {
149		error(strerror(errno));
150		return 0;
151	}
152	namidx = obj->index;
153
154	if (readobj(obj, fp) < 0) {
155		error(strerror(errno));
156		goto error;
157	}
158
159	for (i = 0; getsym(obj, &i, &sym); i++) {
160		if (!newsymbol(&sym, off))
161			goto error;
162	}
163
164	ret = 1;
165
166error:
167	delobj(obj);
168	return ret;
169}
170
171static int
172readsyms(FILE *fp)
173{
174	long idxsiz, cur, off;
175	char memb[SARNAM+1];
176
177	nolib = 0;
178	artype = -1;
179	nsymbols = 0;
180	idxsiz = 0;
181
182	if (!archive(fp)) {
183		error("file format not recognized");
184		return 0;
185	}
186
187	cur = ftell(fp);
188	if ((off = armember(fp, memb, NULL)) < 0)
189		goto corrupted;
190
191	if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) {
192		idxsiz = off;
193		cur += off;
194	}
195
196	fseek(fp, cur, SEEK_SET);
197	for (;;) {
198		cur = ftell(fp);
199		off = armember(fp, memb, NULL);
200		switch (off) {
201		case -1:
202			goto corrupted;
203		case 0:
204			return (nolib || nsymbols == 0) ? -1 : 0;
205		default:
206			membname = memb;
207			if (objprobe(fp, NULL) != -1)
208				newmember(fp, cur - idxsiz);
209			membname = NULL;
210			fseek(fp, cur, SEEK_SET);
211			fseek(fp, off, SEEK_CUR);
212			break;
213		}
214	}
215
216corrupted:
217	error(strerror(errno));
218	error("library corrupted");
219	return 0;
220}
221
222static void
223merge(FILE *to, struct fprop *prop, FILE *lib, FILE *idx)
224{
225	int c;
226	struct ar_hdr first;
227
228	rewind(lib);
229	rewind(idx);
230	fseek(lib, SARMAG, SEEK_SET);
231
232	if (fread(&first, sizeof(first), 1, lib) != 1)
233		return;
234
235	if (!strncmp(first.ar_name, namidx, strlen(namidx))) {
236		long siz = atol(first.ar_size);
237		fseek(lib, siz + (siz & 1), SEEK_CUR);
238	} else {
239		fseek(lib, SARMAG, SEEK_SET);
240	}
241
242	fwrite(ARMAG, SARMAG, 1, to);
243
244        fprintf(to,
245                "%-16.16s%-12lld%-6u%-6u%-8lo%-10ld`\n",
246                namidx,
247                fromepoch(prop->time),
248                prop->uid,
249                prop->gid,
250                prop->mode,
251                prop->size);
252
253	while ((c = getc(idx)) != EOF)
254		putc(c, to);
255	if (prop->size & 1)
256		putc('\n', to);
257
258	while ((c = getc(lib)) != EOF)
259		putc(c, to);
260
261	fflush(to);
262}
263
264static void
265ranlib(char *fname)
266{
267	size_t r;
268	long *offs, size, i;
269	char **names;
270	FILE *fp, *idx, *out;
271	Symdef *dp;
272	struct fprop prop;
273	char tmpname[FILENAME_MAX];
274
275	filename = fname;
276	if ((fp = fopen(fname, "rb")) == NULL) {
277		error(strerror(errno));
278		return;
279	}
280
281	if (readsyms(fp) <0)
282		goto err2;
283
284	if ((idx = tmpfile()) == NULL) {
285		error(strerror(errno));
286		goto err2;
287	}
288
289	offs = malloc(sizeof(long) * nsymbols);
290	names = malloc(sizeof(*names) * nsymbols);
291	if (!offs || !names) {
292		error(strerror(errno));
293		goto err3;
294	}
295
296	for (dp = head, i = 0; i < nsymbols; dp = dp->next, i++) {
297		offs[i] = dp->offset;
298		names[i] = dp->name;
299	}
300
301	/* First pass: write index to determine its size */
302	if (setindex(artype, nsymbols, names, offs, idx) < 0) {
303		error(strerror(errno));
304		goto err3;
305	}
306
307	if (getstat(fname, &prop) < 0) {
308		error(strerror(errno));
309		goto err3;
310	}
311	prop.time = time(NULL);
312	prop.size = ftell(idx);
313
314	size = sizeof(struct ar_hdr) + prop.size + (prop.size & 1);
315	for (i = 0; i < nsymbols; i++)
316		offs[i] += size;
317
318	/* Second pass: rewrite index with corrected offsets */
319	rewind(idx);
320	if (setindex(artype, nsymbols, names, offs, idx) < 0) {
321		error(strerror(errno));
322		goto err3;
323	}
324
325	r = snprintf(tmpname, sizeof(tmpname), "%s.tmp", fname);
326	if (r >= sizeof(tmpname)) {
327		error("too long temporary name");
328		goto err3;
329	}
330
331	if ((out = fopen(tmpname, "wb")) == NULL) {
332		error(strerror(errno));
333		goto err3;
334	}
335
336	merge(out, &prop, fp, idx);
337	if (ferror(out) || ferror(fp) || ferror(idx)) {
338		error(strerror(errno));
339		fclose(out);
340		goto err4;
341	}
342
343	fclose(out);
344	if (rename(tmpname, fname) == EOF) {
345		error(strerror(errno));
346		goto err4;
347	}
348
349err4:
350	remove(tmpname);
351err3:
352	free(offs);
353	free(names);
354	fclose(idx);
355err2:
356	freehash();
357err1:
358	fclose(fp);
359}
360
361static void
362usage(void)
363{
364	fputs("usage: scc-ranlib [-t] file...\n", stderr);
365	exit(EXIT_FAILURE);
366}
367
368int
369main(int argc, char *argv[])
370{
371	ARGBEGIN {
372	case 't':
373		break;
374	default:
375		usage();
376	} ARGEND
377
378	if (argc == 0)
379		usage();
380
381	for (; *argv; ++argv)
382		ranlib(*argv);
383
384	return status;
385}