]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/tree.c
hgfs: fix path mangeling bug, find dothg on startup
[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, l;
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                 l = strlen(frogs[i]);
26                 if((strncmp(frogs[i], p, l) == 0) && (p[l] == 0 || p[l] == '.'))
27                         return seprint(s, e, "%.2s~%.2x%s", p, p[2], p+3);
28         }
29         for(; s+4 < e && *p; p++){
30                 if(*p == '_'){
31                         *s++ = '_';
32                         *s++ = '_';
33                 } else if(*p >= 'A' && *p <= 'Z'){
34                         *s++ = '_';
35                         *s++ = 'a' + (*p - 'A');
36                 } else if(*p >= 126 || strchr("\\:*?\"<>|", *p)){
37                         *s++ = '~';
38                         s = seprint(s, e, "%.2x", *p);
39                 } else
40                         *s++ = *p;
41         }
42         *s = 0;
43
44         return s;
45 }
46
47 Revnode*
48 mknode(char *name, uchar *hash, char mode)
49 {
50         Revnode *d;
51         char *s;
52
53         d = malloc(sizeof(*d) + (hash ? HASHSZ : 0) + (name ? strlen(name)+1 : 0));
54         memset(d, 0, sizeof(*d));
55         s = (char*)&d[1];
56         if(hash){
57                 d->path = *((uvlong*)hash);
58                 memmove(d->hash = (uchar*)s, hash, HASHSZ);
59                 s += HASHSZ;
60         }else
61                 d->path = 1;
62         if(name)
63                 strcpy(d->name = s, name);
64         d->mode = mode;
65         return d;
66 }
67
68 static void
69 addnode(Revnode *d, char *path, uchar *hash, char mode)
70 {
71         char *slash;
72         Revnode *c, *p;
73
74         while(path && *path){
75                 if(slash = strchr(path, '/'))
76                         *slash++ = 0;
77                 p = nil;
78                 for(c = d->down; c; p = c, c = c->next)
79                         if(strcmp(c->name, path) == 0)
80                                 break;
81                 if(c == nil){
82                         c = mknode(path, slash ? nil : hash, slash ? 0 : mode);
83                         c->up = d;
84                         if(p){
85                                 c->next = p->next;
86                                 p->next = c;
87                         } else {
88                                 c->next = d->down;
89                                 d->down = c;
90                         }
91                         if(c->hash){
92                                 p = c;
93                                 p->path = *((uvlong*)c->hash);
94                                 while(d->up){
95                                         d->path += p->path;
96                                         p = d;
97                                         d = d->up;
98                                 }
99                         }
100                 }
101                 d = c;
102                 path = slash;
103         }
104 }
105
106 typedef struct Hashstr Hashstr;
107 struct Hashstr
108 {
109         Hashstr *next;
110         char    str[];
111 };
112
113 static ulong
114 hashstr(char *s)
115 {
116         ulong h, t;
117         char c;
118
119         h = 0;
120         while(c = *s++){
121                 t = h & 0xf8000000;
122                 h <<= 5;
123                 h ^= t>>27;
124                 h ^= (ulong)c;
125         }
126         return h;
127 }
128
129 static int
130 loadmanifest(Revnode *root, int fd, Hashstr **ht, int nh)
131 {
132         char buf[BUFSZ], *p, *e, *x;
133         uchar hash[HASHSZ];
134         int n;
135
136         p = buf;
137         e = buf + BUFSZ;
138         while((n = read(fd, p, e - p)) > 0){
139                 p += n;
140                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
141                         *e++ = 0;
142
143                         x = buf;
144                         x += strlen(x) + 1;
145                         strhash(x, hash);
146                         x += HASHSZ*2;
147
148                         if(ht == nil)
149                                 addnode(root, buf, hash, *x);
150                         else {
151                                 Hashstr *he;
152
153                                 for(he = ht[hashstr(buf) % nh]; he; he = he->next){
154                                         if(strcmp(he->str, buf) == 0){
155                                                 addnode(root, buf, hash, *x);
156                                                 break;
157                                         }
158                                 }
159                         }
160
161                         p -= e - buf;
162                         if(p > buf)
163                                 memmove(buf, e, p - buf);
164                 }
165                 e = buf + BUFSZ;
166         }
167         return 0;
168 }
169
170 static Revtree*
171 loadtree(Revlog *manifest, Revinfo *ri, Hashstr **ht, int nh)
172 {
173         Revtree *t;
174         int fd;
175
176         if((fd = revlogopentemp(manifest, hashrev(manifest, ri->mhash))) < 0)
177                 return nil;
178
179         t = malloc(sizeof(*t));
180         memset(t, 0, sizeof(*t));
181         incref(t);
182         t->root = mknode(nil, nil, 0);
183         if(loadmanifest(t->root, fd, ht, nh) < 0){
184                 close(fd);
185                 closerevtree(t);
186                 return nil;
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, n;
205         Revtree *t;
206         vlong off;
207
208         if((fd = revlogopentemp(changelog, hashrev(changelog, ri->chash))) < 0)
209                 return nil;
210
211         off = seek(fd, ri->logoff, 0);
212         if(off < 0){
213                 close(fd);
214                 return nil;
215         }
216
217         memset(ht, 0, sizeof(ht));
218
219         p = buf;
220         e = buf + BUFSZ;
221         while((off - ri->logoff) < ri->loglen){
222                 if((n = read(fd, p, e - p)) <= 0)
223                         break;
224                 p += n;
225                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
226                         *e++ = 0;
227
228                         he = malloc(sizeof(*he) + strlen(buf)+1);
229                         hp = &ht[hashstr(strcpy(he->str, buf)) % nelem(ht)];
230                         he->next = *hp;
231                         *hp = he;
232
233                         n = e - buf;
234                         p -= n;
235                         if(p > buf)
236                                 memmove(buf, e, p - buf);
237                         off += n;
238                 }
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         freenode(nd->before);
263         free(nd);
264 }
265
266 void
267 closerevtree(Revtree *t)
268 {
269         if(t == nil || decref(t))
270                 return;
271         freenode(t->root);
272         free(t);
273 }