]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/tree.c
hgfs: fixed mkfile
[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)
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                                 memmove(c->hash = (uchar*)x, hash, HASHSZ);
65                                 x += HASHSZ;
66                         } else
67                                 c->hash = nil;
68                         strcpy(c->name = x, path);
69                         c->up = d;
70                         c->down = nil;
71                         if(p){
72                                 c->next = p->next;
73                                 p->next = c;
74                         } else {
75                                 c->next = d->down;
76                                 d->down = c;
77                         }
78
79                         if(c->hash){
80                                 p = c;
81                                 p->path = *((uvlong*)c->hash);
82                                 while(d->up){
83                                         d->path += p->path;
84                                         p = d;
85                                         d = d->up;
86                                 }
87                         }
88                 }
89                 d = c;
90                 path = slash;
91         }
92 }
93
94 typedef struct Hashstr Hashstr;
95 struct Hashstr
96 {
97         Hashstr *next;
98         char    str[];
99 };
100
101 static ulong
102 hashstr(char *s)
103 {
104         ulong h, t;
105         char c;
106
107         h = 0;
108         while(c = *s++){
109                 t = h & 0xf8000000;
110                 h <<= 5;
111                 h ^= t>>27;
112                 h ^= (ulong)c;
113         }
114         return h;
115 }
116
117 static int
118 loadmanifest(Revnode *root, int fd, Hashstr **ht, int nh)
119 {
120         char buf[BUFSZ], *p, *e;
121         uchar hash[HASHSZ];
122         int n;
123
124         p = buf;
125         e = buf + BUFSZ;
126         while((n = read(fd, p, e - p)) > 0){
127                 p += n;
128                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
129                         *e++ = 0;
130
131                         strhash(buf + strlen(buf) + 1, hash);
132                         if(ht == nil)
133                                 addnode(root, buf, hash);
134                         else {
135                                 Hashstr *he;
136
137                                 for(he = ht[hashstr(buf) % nh]; he; he = he->next){
138                                         if(strcmp(he->str, buf) == 0){
139                                                 addnode(root, buf, hash);
140                                                 break;
141                                         }
142                                 }
143                         }
144
145                         p -= e - buf;
146                         if(p > buf)
147                                 memmove(buf, e, p - buf);
148                 }
149                 e = buf + BUFSZ;
150         }
151         return 0;
152 }
153
154 static Revtree*
155 loadtree(Revlog *manifest, Revinfo *ri, Hashstr **ht, int nh)
156 {
157         Revtree *t;
158         int fd;
159
160         if((fd = revlogopentemp(manifest, hashrev(manifest, ri->mhash))) < 0)
161                 return nil;
162
163         t = malloc(sizeof(*t));
164         memset(t, 0, sizeof(*t));
165         incref(t);
166
167         t->root = malloc(sizeof(Revnode));
168         t->root->path = 0;
169         t->root->name = 0;
170         t->root->up = nil;
171         t->root->down = nil;
172         t->root->next = nil;
173         t->root->hash = nil;
174
175         if(loadmanifest(t->root, fd, ht, nh) < 0){
176                 close(fd);
177                 closerevtree(t);
178                 return nil;
179         }
180
181         close(fd);
182
183         return t;
184 }
185
186 Revtree*
187 loadfilestree(Revlog *, Revlog *manifest, Revinfo *ri)
188 {
189         return loadtree(manifest, ri, nil, 0);
190 }
191
192 Revtree*
193 loadchangestree(Revlog *changelog, Revlog *manifest, Revinfo *ri)
194 {
195         char buf[BUFSZ], *p, *e;
196         Hashstr *ht[256], *he, **hp;
197         int fd, done, line, n;
198         Revtree *t;
199
200         if((fd = revlogopentemp(changelog, hashrev(changelog, ri->chash))) < 0)
201                 return nil;
202
203         done = 0;
204         line = 0;
205         memset(ht, 0, sizeof(ht));
206
207         p = buf;
208         e = buf + BUFSZ;
209         while((n = read(fd, p, e - p)) > 0){
210                 p += n;
211                 while((p > buf) && (e = memchr(buf, '\n', p - buf))){
212                         *e++ = 0;
213
214                         if(++line >= 4){
215                                 if(*buf == 0){
216                                         done = 1;
217                                         break;
218                                 }
219
220                                 he = malloc(sizeof(*he) + strlen(buf)+1);
221                                 hp = &ht[hashstr(strcpy(he->str, buf)) % nelem(ht)];
222                                 he->next = *hp;
223                                 *hp = he;
224                         }
225
226                         p -= e - buf;
227                         if(p > buf)
228                                 memmove(buf, e, p - buf);
229                 }
230                 if(done)
231                         break;
232                 e = buf + BUFSZ;
233         }
234         close(fd);
235
236         t = loadtree(manifest, ri, ht, nelem(ht));
237
238         for(hp = ht; hp != &ht[nelem(ht)]; hp++){
239                 while(he = *hp){
240                         *hp = he->next;
241                         free(he);
242                 }
243         }
244
245         return t;
246 }
247
248 static void
249 freenode(Revnode *nd)
250 {
251         if(nd == nil)
252                 return;
253         freenode(nd->down);
254         freenode(nd->next);
255         free(nd);
256 }
257
258 void
259 closerevtree(Revtree *t)
260 {
261         if(t == nil || decref(t))
262                 return;
263         freenode(t->root);
264         free(t);
265 }