Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../cmd.h"
4 : #include "../../log.h"
5 : #include "../../sbuf.h"
6 : #include "../manio.h"
7 : #include "json_output.h"
8 : #include "cache.h"
9 :
10 : typedef struct ent ent_t;
11 :
12 : struct ent
13 : {
14 : char *name;
15 : char *link;
16 : int count;
17 : struct stat statp;
18 : struct ent **ents;
19 : };
20 :
21 62 : static void ent_free(struct ent **ent)
22 : {
23 124 : if(!ent || !*ent) return;
24 62 : free_w(&(*ent)->name);
25 62 : free_w(&(*ent)->link);
26 62 : free_v((void **)&(*ent)->ents);
27 62 : free_v((void **)ent);
28 : }
29 :
30 62 : static struct ent *ent_alloc(const char *name, const char *link)
31 : {
32 : struct ent *ent;
33 62 : if(!(ent=(struct ent *)calloc_w(1, sizeof(struct ent), __func__))
34 62 : || !(ent->name=strdup_w(name, __func__)) || !(ent->link=strdup_w(link? link:"", __func__)))
35 : goto error;
36 62 : return ent;
37 : error:
38 0 : ent_free(&ent);
39 0 : return NULL;
40 : }
41 :
42 : // FIX THIS:
43 : // For extra kicks, could make the config option allow multiple caches -
44 : // eg, 'monitor_browse_cache=5', then rotate out the oldest one.
45 :
46 : static struct ent *root=NULL;
47 : static char *cached_client=NULL;
48 : static unsigned long cached_bno=0;
49 :
50 61 : static int ent_add_to_list(struct ent *ent,
51 : struct sbuf *sb, const char *ent_name)
52 : {
53 61 : struct ent *enew=NULL;
54 61 : if(!(ent->ents=(struct ent **)realloc_w(ent->ents,
55 61 : (ent->count+1)*sizeof(struct ent *), __func__))
56 61 : || !(enew=ent_alloc(ent_name, sb->link.buf)))
57 : {
58 0 : log_out_of_memory(__func__);
59 : return -1;
60 : }
61 61 : memcpy(&enew->statp, &sb->statp, sizeof(struct stat));
62 61 : ent->ents[ent->count]=enew;
63 61 : ent->count++;
64 : return 0;
65 : }
66 :
67 63 : static void ents_free(struct ent *ent)
68 : {
69 63 : int i=0;
70 126 : if(!ent) return;
71 61 : for(i=0; i<ent->count; i++)
72 61 : ents_free(ent->ents[i]);
73 62 : ent_free(&ent);
74 : }
75 :
76 2 : void cache_free(void)
77 : {
78 2 : free_w(&cached_client);
79 2 : ents_free(root);
80 2 : }
81 :
82 : /*
83 : static void cache_dump(struct ent *e, int *depth)
84 : {
85 : int count;
86 : for(count=0; count<*depth; count++)
87 : printf(" ");
88 : printf("'%s'\n", e->name);
89 : for(count=0; count<e->count; count++)
90 : {
91 : (*depth)++;
92 : cache_dump(e->ents[count], depth);
93 : (*depth)--;
94 : }
95 : }
96 : */
97 :
98 1 : int cache_load(struct manio *manio, struct sbuf *sb,
99 : const char *cname, unsigned long bno)
100 : {
101 1 : int ret=-1;
102 1 : int ars=0;
103 : // int depth=0;
104 1 : char *tok=NULL;
105 1 : struct ent *point=NULL;
106 1 : struct ent *p=NULL;
107 :
108 : //printf("in cache load\n");
109 1 : cache_free();
110 :
111 1 : if(!(root=ent_alloc("",""))) goto end;
112 :
113 : while(1)
114 : {
115 32 : sbuf_free_content(sb);
116 32 : if((ars=manio_read(manio, sb)))
117 : {
118 1 : if(ars<0) goto end;
119 : // ars==1 means it ended ok.
120 : break;
121 : }
122 :
123 31 : if(manio->protocol==PROTO_2 && sb->endfile.buf)
124 11 : continue;
125 :
126 40 : if(sb->path.cmd!=CMD_DIRECTORY
127 20 : && sb->path.cmd!=CMD_FILE
128 6 : && sb->path.cmd!=CMD_ENC_FILE
129 6 : && sb->path.cmd!=CMD_EFS_FILE
130 6 : && sb->path.cmd!=CMD_SPECIAL
131 2 : && !cmd_is_link(sb->path.cmd))
132 0 : continue;
133 :
134 : // Some messing around so that we can list '/'.
135 20 : if(!*(root->name) && !strncmp(sb->path.buf, "/", 1))
136 : {
137 1 : memcpy(&root->statp, &sb->statp, sizeof(struct stat));
138 1 : free_w(&root->name);
139 1 : if(!(root->name=strdup_w("/", __func__)))
140 : goto end;
141 : }
142 :
143 20 : point=root;
144 20 : if((tok=strtok(sb->path.buf, "/"))) do
145 : {
146 69 : if(point->count>0)
147 : {
148 27 : p=point->ents[point->count-1];
149 27 : if(!strcmp(tok, p->name))
150 : {
151 8 : point=p;
152 8 : continue;
153 : }
154 : }
155 :
156 61 : if(sb->path.buf+sb->path.len!=tok+strlen(tok))
157 : {
158 : // There is an entry in a directory where the
159 : // directory itself was not backed up.
160 : // We will make a fake entry for the directory,
161 : // and use the same stat data.
162 : // Make sure that we set the directory flag.
163 41 : sb->statp.st_mode&=S_IFDIR;
164 : }
165 61 : if(ent_add_to_list(point, sb, tok)) goto end;
166 61 : point=point->ents[point->count-1];
167 69 : } while((tok=strtok(NULL, "/")));
168 : }
169 :
170 1 : if(!(cached_client=strdup_w(cname, __func__)))
171 : goto end;
172 1 : cached_bno=bno;
173 1 : ret=0;
174 : // cache_dump(root, &depth);
175 : end:
176 1 : return ret;
177 : }
178 :
179 4 : int cache_loaded(const char *cname, unsigned long bno)
180 : {
181 4 : if(cached_client
182 2 : && !strcmp(cname, cached_client)
183 2 : && cached_bno==bno)
184 : return 1;
185 3 : return 0;
186 : }
187 :
188 : static int result_single(struct ent *ent)
189 : {
190 : // printf("result: %s\n", ent->name);
191 0 : return json_from_entry(ent->name, ent->link, &ent->statp);
192 : }
193 :
194 0 : static int result_list(struct ent *ent)
195 : {
196 0 : int i=0;
197 : // printf("in results\n");
198 0 : for(i=0; i<ent->count; i++)
199 0 : result_single(ent->ents[i]);
200 0 : return 0;
201 : }
202 :
203 0 : int cache_lookup(const char *browse)
204 : {
205 0 : int i=0;
206 0 : int ret=-1;
207 0 : char *tok=NULL;
208 0 : char *copy=NULL;
209 0 : struct ent *point=root;
210 :
211 0 : if(!browse || !*browse)
212 : {
213 : // The difference between the top level for Windows and the
214 : // top level for non-Windows.
215 0 : if(*(point->name)) ret=result_single(point);
216 0 : else ret=result_list(point);
217 : goto end;
218 : }
219 :
220 0 : if(!(copy=strdup_w(browse, __func__)))
221 : goto end;
222 0 : if((tok=strtok(copy, "/"))) do
223 : {
224 : // FIX THIS: Should do a binary search here, for monster speed
225 : // increases when there are lots of files in a directory.
226 0 : for(i=0; i<point->count; i++)
227 : {
228 0 : if(strcmp(tok, point->ents[i]->name)) continue;
229 : point=point->ents[i];
230 : break;
231 : }
232 0 : } while((tok=strtok(NULL, "/")));
233 :
234 0 : ret=result_list(point);
235 : end:
236 0 : free_w(©);
237 0 : return ret;
238 : }
|