]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/tree.c
hgfs: honor x-bit in manifest
[plan9front.git] / sys / src / cmd / hgfs / tree.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 char*
8 nodepath(char *s, char *e, Revnode *nd)
9 {
10         static char *frogs[] = {
11                 "con", "prn", "aux", "nul",
12                 "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
13                 "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
14         };
15         char *p;
16         int i;
17
18         if(nd == nil || nd->name == nil)
19                 return s;
20
21         s = seprint(nodepath(s, e, nd->up), e, "/");
22
23         p = nd->name;
24         for(i=0; i<nelem(frogs); i++)
25                 if(strcmp(frogs[i], p) == 0)
26                         return seprint(s, e, "%.2s~%.2x%s", p, p[2], p+3);
27
28         for(; s+4 < e && *p; p++){
29                 if(*p == '_'){
30                         *s++ = '_';
31                         *s++ = '_';
32                 } else if(*p >= 'A' && *p <= 'Z'){
33                         *s++ = '_';
34                         *s++ = 'a' + (*p - 'A');
35                 } else if(*p >= 126 || strchr("\\:*?\"<>|", *p)){
36                         *s++ = '~';
37                         s = seprint(s, e, "%.2x", *p);
38                 } else
39                         *s++ = *p;
40         }
41         *s = 0;
42
43         return s;
44 }
45
46 static void
47 addnode(Revnode *d, char *path, uchar *hash, char mode)
48 {
49         char *slash, *x;
50         Revnode *c, *p;
51
52         while(path && *path){
53                 if(slash = strchr(path, '/'))
54                         *slash++ = 0;
55                 p = nil;
56                 for(c = d->down; c; p = c, c = c->next)
57                         if(strcmp(c->name, path) == 0)
58                                 break;
59                 if(c == nil){
60                         c = malloc(sizeof(*c) + (!slash ? HASHSZ : 0) + strlen(path)+1);
61                         c->path = 1;
62                         x = (char*)&c[1];
63                         if(!slash){
64                                 c->mode = mode;
65                                 memmove(c->hash = (uchar*)x, hash, HASHSZ);
66                                 x += HASHSZ;
67                         }else{
68                                 c->mode = 0;
69                                 c->hash = nil;
70                         }
71                         strcpy(c->name = x, path);
72                         c->up = d;
73                         c->down = nil;
74                         if(p){
75                                 c->next = p->next;
76                                 p->next = c;
77                         } else {
78                                 c->next = d->down;
79                                 d->down = c;
80                         }
81
82                         if(c->hash){
83                                 p = c;
84                                 p->path = *((uvlong*)c->hash);
85                                 while(d->up){
86                                         d->path += p->path;
87                                         p = d;
88                                         d = d->up;
89                                 }
90                         }
91                 }
92                 d = c;
93                 path = slash;
94         }
95 }
96
97 typedef struct Hashstr Hashstr;
98 struct Hashstr
99 {
100         Hashstr *next;
101         char    str[];
102 };
103
104 static ulong
105 hashstr(char *s)
106 {
107         ulong h, t;
108         char c;
109
110         h = 0;
111         while(c = *s++){
112                 t = h & 0xf8000000;
113                 h <<= 5;
114                 h ^= t>>27;
115                 h ^= (ulong)c;
116         }
117         return h;
118 }
119
120 static int
121 loadmanifest(Revnode *root, int fd, Hashstr **ht, int nh)
122 {
123         char buf[BUFSZ], *p, *e, *x;
124         uchar hash[HASHSZ];
125         int n;
126
127         p = buf;
128         e = buf + BUFSZ;
129         while((n = read(fd, p, e - p)) > 0){
130                 p += n;
131                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
132                         *e++ = 0;
133
134                         x = buf;
135                         x += strlen(x) + 1;
136                         strhash(x, hash);
137                         x += HASHSZ*2;
138
139                         if(ht == nil)
140                                 addnode(root, buf, hash, *x);
141                         else {
142                                 Hashstr *he;
143
144                                 for(he = ht[hashstr(buf) % nh]; he; he = he->next){
145                                         if(strcmp(he->str, buf) == 0){
146                                                 addnode(root, buf, hash, *x);
147                                                 break;
148                                         }
149                                 }
150                         }
151
152                         p -= e - buf;
153                         if(p > buf)
154                                 memmove(buf, e, p - buf);
155                 }
156                 e = buf + BUFSZ;
157         }
158         return 0;
159 }
160
161 static Revtree*
162 loadtree(Revlog *manifest, Revinfo *ri, Hashstr **ht, int nh)
163 {
164         Revtree *t;
165         int fd;
166
167         if((fd = revlogopentemp(manifest, hashrev(manifest, ri->mhash))) < 0)
168                 return nil;
169
170         t = malloc(sizeof(*t));
171         memset(t, 0, sizeof(*t));
172         incref(t);
173
174         t->root = malloc(sizeof(Revnode));
175         t->root->path = 0;
176         t->root->name = 0;
177         t->root->up = nil;
178         t->root->down = nil;
179         t->root->next = nil;
180         t->root->hash = nil;
181
182         if(loadmanifest(t->root, fd, ht, nh) < 0){
183                 close(fd);
184                 closerevtree(t);
185                 return nil;
186         }
187
188         close(fd);
189
190         return t;
191 }
192
193 Revtree*
194 loadfilestree(Revlog *, Revlog *manifest, Revinfo *ri)
195 {
196         return loadtree(manifest, ri, nil, 0);
197 }
198
199 Revtree*
200 loadchangestree(Revlog *changelog, Revlog *manifest, Revinfo *ri)
201 {
202         char buf[BUFSZ], *p, *e;
203         Hashstr *ht[256], *he, **hp;
204         int fd, done, line, n;
205         Revtree *t;
206
207         if((fd = revlogopentemp(changelog, hashrev(changelog, ri->chash))) < 0)
208                 return nil;
209
210         done = 0;
211         line = 0;
212         memset(ht, 0, sizeof(ht));
213
214         p = buf;
215         e = buf + BUFSZ;
216         while((n = read(fd, p, e - p)) > 0){
217                 p += n;
218                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
219                         *e++ = 0;
220
221                         if(++line >= 4){
222                                 if(*buf == 0){
223                                         done = 1;
224                                         break;
225                                 }
226
227                                 he = malloc(sizeof(*he) + strlen(buf)+1);
228                                 hp = &ht[hashstr(strcpy(he->str, buf)) % nelem(ht)];
229                                 he->next = *hp;
230                                 *hp = he;
231                         }
232
233                         p -= e - buf;
234                         if(p > buf)
235                                 memmove(buf, e, p - buf);
236                 }
237                 if(done)
238                         break;
239                 e = buf + BUFSZ;
240         }
241         close(fd);
242
243         t = loadtree(manifest, ri, ht, nelem(ht));
244
245         for(hp = ht; hp != &ht[nelem(ht)]; hp++){
246                 while(he = *hp){
247                         *hp = he->next;
248                         free(he);
249                 }
250         }
251
252         return t;
253 }
254
255 static void
256 freenode(Revnode *nd)
257 {
258         if(nd == nil)
259                 return;
260         freenode(nd->down);
261         freenode(nd->next);
262         free(nd);
263 }
264
265 void
266 closerevtree(Revtree *t)
267 {
268         if(t == nil || decref(t))
269                 return;
270         freenode(t->root);
271         free(t);
272 }