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 }