Commit Diff


commit - a29753a17ffd2be43fbadb9f1851d1aacf771d44
commit + d946e4dc5df1c0fb9a06e6d94013613848c5df16
blob - 8bb80bbfefc2e915c6df6f68d94caec24c98afd0
blob + 14d2082dafb110ea30a9dcaec957ec7b6349043d
--- src/cmd/mk/archive.c
+++ src/cmd/mk/archive.c
@@ -104,10 +104,12 @@ atimes(char *ar)
 {
 	struct ar_hdr h;
 	long t;
-	int fd, i;
-	char buf[1024];
-	char name[sizeof(h.name)+1];
+	int fd, i, namelen;
+	char buf[2048], *p, *strings;
+	char name[1024];
+	Symtab *sym;
 
+	strings = nil;
 	fd = open(ar, OREAD);
 	if(fd < 0)
 		return;
@@ -116,23 +118,74 @@ atimes(char *ar)
 		close(fd);
 		return;
 	}
-	while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
+	while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
 		t = atol(h.date);
 		if(t == 0)	/* as it sometimes happens; thanks ken */
 			t = 1;
-		strncpy(name, h.name, sizeof(h.name));
-		for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
+		namelen = 0;
+		if(memcmp(h.name, "#1/", 3) == 0){	/* BSD */
+			namelen = atoi(h.name+3);
+			if(namelen >= sizeof name){
+				namelen = 0;
+				goto skip;
+			}
+			if(readn(fd, name, namelen) != namelen)
+				break;
+			name[namelen] = 0;
+		}else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */
+			/* date, uid, gid, mode all ' ' */
+			for(i=2; i<16+12+6+6+8; i++)
+				if(h.name[i] != ' ')
+					goto skip;
+			t = atol(h.size);
+			if(t&01)
+				t++;
+			free(strings);
+			strings = malloc(t+1);
+			if(strings){
+				if(readn(fd, strings, t) != t){
+					free(strings);
+					strings = nil;
+					break;
+				}
+				strings[t] = 0;
+				continue;
+			}
+			goto skip;
+		}else if(strings && h.name[0]=='/' && isdigit(h.name[1])){
+			i = strtol(h.name+1, &p, 10);
+			if(*p != ' ' || strlen(strings) < i)
+				goto skip;
+			p = strings+i;
+			for(; *p && *p != '/'; p++)
 				;
-		if(name[i] == '/')		/* system V bug */
-			i--;
-		name[i+1]=0;
+			namelen = p-(strings+i);
+			if(namelen >= sizeof name){
+				namelen = 0;
+				goto skip;
+			}
+			memmove(name, strings+i, namelen);
+			name[namelen] = 0;
+			namelen = 0;
+		}else{
+			strncpy(name, h.name, sizeof(h.name));
+			for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
+					;
+			if(name[i] == '/')		/* system V bug */
+				i--;
+			name[i+1]=0;
+		}
 		snprint(buf, sizeof buf, "%s(%s)", ar, name);
-		symlook(strdup(buf), S_TIME, (void *)t)->value = (void *)t;
+		sym = symlook(strdup(buf), S_TIME, (void *)t);
+		sym->value = (void *)t;
+	skip:
 		t = atol(h.size);
 		if(t&01) t++;
+		t -= namelen;
 		LSEEK(fd, t, 1);
 	}
 	close(fd);
+	free(strings);
 }
 
 static int