blob: 01288908f8d8ffbb632eb153f4cd41107aeaa331 [file] [log] [blame]
#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;
}