|  | #include	"mk.h" | 
|  | #define	ARMAG	"!<arch>\n" | 
|  | #define	SARMAG	8 | 
|  |  | 
|  | #define	ARFMAG	"`\n" | 
|  | #define SARNAME	16 | 
|  |  | 
|  | struct	ar_hdr | 
|  | { | 
|  | char	name[SARNAME]; | 
|  | char	date[12]; | 
|  | char	uid[6]; | 
|  | char	gid[6]; | 
|  | char	mode[8]; | 
|  | char	size[10]; | 
|  | char	fmag[2]; | 
|  | }; | 
|  | #define	SAR_HDR	(SARNAME+44) | 
|  |  | 
|  | static int dolong = 1; | 
|  |  | 
|  | static void atimes(char *); | 
|  | static char *split(char*, char**); | 
|  |  | 
|  | long | 
|  | readn(int f, void *av, long n) | 
|  | { | 
|  | char *a; | 
|  | long m, t; | 
|  |  | 
|  | a = av; | 
|  | t = 0; | 
|  | while(t < n){ | 
|  | m = read(f, a+t, n-t); | 
|  | if(m <= 0){ | 
|  | if(t == 0) | 
|  | return m; | 
|  | break; | 
|  | } | 
|  | t += m; | 
|  | } | 
|  | return t; | 
|  | } | 
|  | long | 
|  | atimeof(int force, char *name) | 
|  | { | 
|  | Symtab *sym; | 
|  | long t; | 
|  | char *archive, *member, buf[512]; | 
|  |  | 
|  | archive = split(name, &member); | 
|  | if(archive == 0) | 
|  | Exit(); | 
|  |  | 
|  | t = mtime(archive); | 
|  | sym = symlook(archive, S_AGG, 0); | 
|  | if(sym){ | 
|  | if(force || (t > sym->u.value)){ | 
|  | atimes(archive); | 
|  | sym->u.value = t; | 
|  | } | 
|  | } | 
|  | else{ | 
|  | atimes(archive); | 
|  | /* mark the aggegate as having been done */ | 
|  | symlook(strdup(archive), S_AGG, "")->u.value = t; | 
|  | } | 
|  | /* truncate long member name to sizeof of name field in archive header */ | 
|  | if(dolong) | 
|  | snprint(buf, sizeof(buf), "%s(%s)", archive, member); | 
|  | else | 
|  | snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member); | 
|  | sym = symlook(buf, S_TIME, 0); | 
|  | if (sym) | 
|  | return sym->u.value; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | atouch(char *name) | 
|  | { | 
|  | char *archive, *member; | 
|  | int fd, i; | 
|  | struct ar_hdr h; | 
|  | long t; | 
|  |  | 
|  | archive = split(name, &member); | 
|  | if(archive == 0) | 
|  | Exit(); | 
|  |  | 
|  | fd = open(archive, ORDWR); | 
|  | if(fd < 0){ | 
|  | fd = create(archive, OWRITE, 0666); | 
|  | if(fd < 0){ | 
|  | fprint(2, "create %s: %r\n", archive); | 
|  | Exit(); | 
|  | } | 
|  | write(fd, ARMAG, SARMAG); | 
|  | } | 
|  | if(symlook(name, S_TIME, 0)){ | 
|  | /* hoon off and change it in situ */ | 
|  | LSEEK(fd, SARMAG, 0); | 
|  | while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){ | 
|  | for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--) | 
|  | ; | 
|  | h.name[i+1]=0; | 
|  | if(strcmp(member, h.name) == 0){ | 
|  | t = SARNAME-sizeof(h);	/* ughgghh */ | 
|  | LSEEK(fd, t, 1); | 
|  | fprint(fd, "%-12ld", time(0)); | 
|  | break; | 
|  | } | 
|  | t = atol(h.size); | 
|  | if(t&01) t++; | 
|  | LSEEK(fd, t, 1); | 
|  | } | 
|  | } | 
|  | close(fd); | 
|  | } | 
|  |  | 
|  | static void | 
|  | atimes(char *ar) | 
|  | { | 
|  | struct ar_hdr h; | 
|  | long t; | 
|  | int fd, i, namelen; | 
|  | char buf[2048], *p, *strings; | 
|  | char name[1024]; | 
|  | Symtab *sym; | 
|  |  | 
|  | strings = nil; | 
|  | fd = open(ar, OREAD); | 
|  | if(fd < 0) | 
|  | return; | 
|  |  | 
|  | if(read(fd, buf, SARMAG) != SARMAG){ | 
|  | close(fd); | 
|  | return; | 
|  | } | 
|  | while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){ | 
|  | t = atol(h.date); | 
|  | if(t == 0)	/* as it sometimes happens; thanks ken */ | 
|  | t = 1; | 
|  | 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((uchar)h.name[1])){ | 
|  | i = strtol(h.name+1, &p, 10); | 
|  | if(*p != ' ' || i >= strlen(strings)) | 
|  | goto skip; | 
|  | p = strings+i; | 
|  | for(; *p && *p != '/'; p++) | 
|  | ; | 
|  | 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); | 
|  | sym = symlook(strdup(buf), S_TIME, (void *)t); | 
|  | sym->u.value = t; | 
|  | skip: | 
|  | t = atol(h.size); | 
|  | if(t&01) t++; | 
|  | t -= namelen; | 
|  | LSEEK(fd, t, 1); | 
|  | } | 
|  | close(fd); | 
|  | free(strings); | 
|  | } | 
|  |  | 
|  | static int | 
|  | type(char *file) | 
|  | { | 
|  | int fd; | 
|  | char buf[SARMAG]; | 
|  |  | 
|  | fd = open(file, OREAD); | 
|  | if(fd < 0){ | 
|  | if(symlook(file, S_BITCH, 0) == 0){ | 
|  | if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0) | 
|  | Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file); | 
|  | symlook(file, S_BITCH, (void *)file); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | if(read(fd, buf, SARMAG) != SARMAG){ | 
|  | close(fd); | 
|  | return 0; | 
|  | } | 
|  | close(fd); | 
|  | return !strncmp(ARMAG, buf, SARMAG); | 
|  | } | 
|  |  | 
|  | static char* | 
|  | split(char *name, char **member) | 
|  | { | 
|  | char *p, *q; | 
|  |  | 
|  | p = strdup(name); | 
|  | q = utfrune(p, '('); | 
|  | if(q){ | 
|  | *q++ = 0; | 
|  | if(member) | 
|  | *member = q; | 
|  | q = utfrune(q, ')'); | 
|  | if (q) | 
|  | *q = 0; | 
|  | if(type(p)) | 
|  | return p; | 
|  | free(p); | 
|  | fprint(2, "mk: '%s' is not an archive\n", name); | 
|  | } | 
|  | return 0; | 
|  | } |