archive.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
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 … | |
69 if(dolong) | |
70 snprint(buf, sizeof(buf), "%s(%s)", archive, member); | |
71 else | |
72 snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, … | |
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.n… | |
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] == ' … | |
192 ; | |
193 if(name[i] == '/') /* system V bu… | |
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)-… | |
220 Bprint(&bout, "%s doesn't exist: assumin… | |
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 } |