#include "mk.h" #define ARMAG "!\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 > (long)sym->value)){ atimes(archive); sym->value = (void *)t; } } else{ atimes(archive); /* mark the aggegate as having been done */ symlook(strdup(archive), S_AGG, "")->value = (void *)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 (long)sym->value; /* uggh */ 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->value = (void *)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; }