Blob


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(""))
9 #define ARFMAG "`\n"
10 #define SARNAME 16
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)
24 static int dolong = 1;
26 static void atimes(char *);
27 static char *split(char*, char**);
29 long
30 readn(int f, void *av, long n)
31 {
32 char *a;
33 long m, t;
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];
55 archive = split(name, &member);
56 if(archive == 0)
57 Exit();
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 }
83 void
84 atouch(char *name)
85 {
86 char *archive, *member;
87 int fd, i;
88 struct ar_hdr h;
89 long t;
91 archive = split(name, &member);
92 if(archive == 0)
93 Exit();
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();
102 write(fd, ARMAG, SARMAG);
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--)
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;
117 t = atol(h.size);
118 if(t&01) t++;
119 LSEEK(fd, t, 1);
122 close(fd);
125 static int
126 allspaces(char *a, int n)
128 int i;
130 for(i=0; i<n; i++)
131 if(a[i] != ' ')
132 return 0;
134 return 1;
137 static void
138 atimes(char *ar)
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;
147 strings = nil;
148 fd = open(ar, OREAD);
149 if(fd < 0)
150 return;
152 if(read(fd, buf, SARMAG) != SARMAG){
153 close(fd);
154 return;
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;
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;
189 strings[t] = 0;
190 continue;
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++)
200 namelen = p-(strings+i);
201 if(namelen >= sizeof name){
202 namelen = 0;
203 goto skip;
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--)
212 if(name[i] == '/') /* system V bug */
213 i--;
214 name[i+1]=0;
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);
225 close(fd);
226 free(strings);
229 static int
230 type(char *file)
232 int fd;
233 char buf[SARMAG];
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);
242 return 1;
244 if(read(fd, buf, SARMAG) != SARMAG){
245 close(fd);
246 return 0;
248 close(fd);
249 return !strncmp(ARMAG, buf, SARMAG);
252 static char*
253 split(char *name, char **member)
255 char *p, *q;
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);
271 return 0;