plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

archive.c (5052B)


      1 #include	"mk.h"
      2 #if defined(__AIX__)
      3 #define ARMAG	"<bigaf>\n"
      4 #else
      5 #define	ARMAG	"!<arch>\n"
      6 #endif
      7 #define	SARMAG	(sizeof(ARMAG) - sizeof(""))
      8 
      9 #define	ARFMAG	"`\n"
     10 #define SARNAME	16
     11 
     12 struct	ar_hdr
     13 {
     14 	char	name[SARNAME];
     15 	char	date[12];
     16 	char	uid[6];
     17 	char	gid[6];
     18 	char	mode[8];
     19 	char	size[10];
     20 	char	fmag[2];
     21 };
     22 #define	SAR_HDR	(SARNAME+44)
     23 
     24 static int dolong = 1;
     25 
     26 static void atimes(char *);
     27 static char *split(char*, char**);
     28 
     29 long
     30 readn(int f, void *av, long n)
     31 {
     32 	char *a;
     33 	long m, t;
     34 
     35 	a = av;
     36 	t = 0;
     37 	while(t < n){
     38 		m = read(f, a+t, n-t);
     39 		if(m <= 0){
     40 			if(t == 0)
     41 				return m;
     42 			break;
     43 		}
     44 		t += m;
     45 	}
     46 	return t;
     47 }
     48 long
     49 atimeof(int force, char *name)
     50 {
     51 	Symtab *sym;
     52 	long t;
     53 	char *archive, *member, buf[512];
     54 
     55 	archive = split(name, &member);
     56 	if(archive == 0)
     57 		Exit();
     58 
     59 	t = mtime(archive);
     60 	sym = symlook(archive, S_AGG, 0);
     61 	if(sym){
     62 		if(force || (t > sym->u.value)){
     63 			atimes(archive);
     64 			sym->u.value = t;
     65 		}
     66 	}
     67 	else{
     68 		atimes(archive);
     69 		/* mark the aggegate as having been done */
     70 		symlook(strdup(archive), S_AGG, "")->u.value = t;
     71 	}
     72 		/* truncate long member name to sizeof of name field in archive header */
     73 	if(dolong)
     74 		snprint(buf, sizeof(buf), "%s(%s)", archive, member);
     75 	else
     76 		snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member);
     77 	sym = symlook(buf, S_TIME, 0);
     78 	if (sym)
     79 		return sym->u.value;
     80 	return 0;
     81 }
     82 
     83 void
     84 atouch(char *name)
     85 {
     86 	char *archive, *member;
     87 	int fd, i;
     88 	struct ar_hdr h;
     89 	long t;
     90 
     91 	archive = split(name, &member);
     92 	if(archive == 0)
     93 		Exit();
     94 
     95 	fd = open(archive, ORDWR);
     96 	if(fd < 0){
     97 		fd = create(archive, OWRITE, 0666);
     98 		if(fd < 0){
     99 			fprint(2, "create %s: %r\n", archive);
    100 			Exit();
    101 		}
    102 		write(fd, ARMAG, SARMAG);
    103 	}
    104 	if(symlook(name, S_TIME, 0)){
    105 		/* hoon off and change it in situ */
    106 		LSEEK(fd, SARMAG, 0);
    107 		while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
    108 			for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
    109 				;
    110 			h.name[i+1]=0;
    111 			if(strcmp(member, h.name) == 0){
    112 				t = SARNAME-sizeof(h);	/* ughgghh */
    113 				LSEEK(fd, t, 1);
    114 				fprint(fd, "%-12ld", time(0));
    115 				break;
    116 			}
    117 			t = atol(h.size);
    118 			if(t&01) t++;
    119 			LSEEK(fd, t, 1);
    120 		}
    121 	}
    122 	close(fd);
    123 }
    124 
    125 static int
    126 allspaces(char *a, int n)
    127 {
    128 	int i;
    129 
    130 	for(i=0; i<n; i++)
    131 		if(a[i] != ' ')
    132 			return 0;
    133 
    134 	return 1;
    135 }
    136 
    137 static void
    138 atimes(char *ar)
    139 {
    140 	struct ar_hdr h;
    141 	long t;
    142 	int fd, i, namelen;
    143 	char buf[2048], *p, *strings;
    144 	char name[1024];
    145 	Symtab *sym;
    146 
    147 	strings = nil;
    148 	fd = open(ar, OREAD);
    149 	if(fd < 0)
    150 		return;
    151 
    152 	if(read(fd, buf, SARMAG) != SARMAG){
    153 		close(fd);
    154 		return;
    155 	}
    156 	while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
    157 		t = atol(h.date);
    158 		if(t == 0)	/* as it sometimes happens; thanks ken */
    159 			t = 1;
    160 		namelen = 0;
    161 		if(memcmp(h.name, "#1/", 3) == 0){	/* BSD */
    162 			namelen = atoi(h.name+3);
    163 			if(namelen >= sizeof name){
    164 				namelen = 0;
    165 				goto skip;
    166 			}
    167 			if(readn(fd, name, namelen) != namelen)
    168 				break;
    169 			name[namelen] = 0;
    170 		}else if(memcmp(h.name, "// ", 3) == 0){ /* GNU */
    171 			/* date, uid, gid, mode all ' ' */
    172 			if(!allspaces(&h.name[3], sizeof(h.name) - 3) ||
    173 			   !allspaces(h.date, sizeof(h.date)) ||
    174 			   !allspaces(h.uid, sizeof(h.uid)) ||
    175 			   !allspaces(h.gid, sizeof(h.gid)) ||
    176 			   !allspaces(h.mode, sizeof(h.mode)))
    177 				goto skip;
    178 			t = atol(h.size);
    179 			if(t&01)
    180 				t++;
    181 			free(strings);
    182 			strings = malloc(t+1);
    183 			if(strings){
    184 				if(readn(fd, strings, t) != t){
    185 					free(strings);
    186 					strings = nil;
    187 					break;
    188 				}
    189 				strings[t] = 0;
    190 				continue;
    191 			}
    192 			goto skip;
    193 		}else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1])){
    194 			i = strtol(h.name+1, &p, 10);
    195 			if(*p != ' ' || i >= strlen(strings))
    196 				goto skip;
    197 			p = strings+i;
    198 			for(; *p && *p != '/'; p++)
    199 				;
    200 			namelen = p-(strings+i);
    201 			if(namelen >= sizeof name){
    202 				namelen = 0;
    203 				goto skip;
    204 			}
    205 			memmove(name, strings+i, namelen);
    206 			name[namelen] = 0;
    207 			namelen = 0;
    208 		}else{
    209 			memmove(name, h.name, sizeof(h.name));
    210 			for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
    211 				;
    212 			if(name[i] == '/')		/* system V bug */
    213 				i--;
    214 			name[i+1]=0;
    215 		}
    216 		snprint(buf, sizeof buf, "%s(%s)", ar, name);
    217 		sym = symlook(strdup(buf), S_TIME, (void *)t);
    218 		sym->u.value = t;
    219 	skip:
    220 		t = atol(h.size);
    221 		if(t&01) t++;
    222 		t -= namelen;
    223 		LSEEK(fd, t, 1);
    224 	}
    225 	close(fd);
    226 	free(strings);
    227 }
    228 
    229 static int
    230 type(char *file)
    231 {
    232 	int fd;
    233 	char buf[SARMAG];
    234 
    235 	fd = open(file, OREAD);
    236 	if(fd < 0){
    237 		if(symlook(file, S_BITCH, 0) == 0){
    238 			if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0)
    239 				Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
    240 			symlook(file, S_BITCH, (void *)file);
    241 		}
    242 		return 1;
    243 	}
    244 	if(read(fd, buf, SARMAG) != SARMAG){
    245 		close(fd);
    246 		return 0;
    247 	}
    248 	close(fd);
    249 	return !strncmp(ARMAG, buf, SARMAG);
    250 }
    251 
    252 static char*
    253 split(char *name, char **member)
    254 {
    255 	char *p, *q;
    256 
    257 	p = strdup(name);
    258 	q = utfrune(p, '(');
    259 	if(q){
    260 		*q++ = 0;
    261 		if(member)
    262 			*member = q;
    263 		q = utfrune(q, ')');
    264 		if (q)
    265 			*q = 0;
    266 		if(type(p))
    267 			return p;
    268 		free(p);
    269 		fprint(2, "mk: '%s' is not an archive\n", name);
    270 	}
    271 	return 0;
    272 }