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