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