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 63 : static void ent_free(struct ent **ent)
22 : {
23 63 : if(!ent || !*ent) return;
24 63 : free_w(&(*ent)->name);
25 63 : free_w(&(*ent)->link);
26 63 : free_v((void **)&(*ent)->ents);
27 63 : free_v((void **)ent);
28 : }
29 :
30 63 : static struct ent *ent_alloc(const char *name, const char *link)
31 : {
32 : struct ent *ent;
33 63 : if(!(ent=(struct ent *)calloc_w(1, sizeof(struct ent), __func__))
34 63 : || !(ent->name=strdup_w(name, __func__)) || !(ent->link=strdup_w(link? link:"", __func__)))
35 : goto error;
36 63 : 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 62 : static int ent_add_to_list(struct ent *ent,
51 : struct sbuf *sb, const char *ent_name)
52 : {
53 62 : struct ent *enew=NULL;
54 62 : if(!(ent->ents=(struct ent **)realloc_w(ent->ents,
55 62 : (ent->count+1)*sizeof(struct ent *), __func__))
56 62 : || !(enew=ent_alloc(ent_name, sb->link.buf)))
57 : {
58 0 : log_out_of_memory(__func__);
59 : return -1;
60 : }
61 62 : memcpy(&enew->statp, &sb->statp, sizeof(struct stat));
62 62 : ent->ents[ent->count]=enew;
63 62 : ent->count++;
64 : return 0;
65 : }
66 :
67 64 : static void ents_free(struct ent *ent)
68 : {
69 64 : int i=0;
70 64 : if(!ent) return;
71 62 : for(i=0; i<ent->count; i++)
72 62 : ents_free(ent->ents[i]);
73 63 : ent_free(&ent);
74 : }
75 :
76 1 : void cache_free(void)
77 : {
78 2 : free_w(&cached_client);
79 2 : ents_free(root);
80 1 : }
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 : cache_free();
110 :
111 1 : if(!(root=ent_alloc("",""))) goto end;
112 :
113 : while(1)
114 : {
115 21 : sbuf_free_content(sb);
116 21 : 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 40 : if(sb->path.cmd!=CMD_DIRECTORY
124 20 : && sb->path.cmd!=CMD_FILE
125 7 : && sb->path.cmd!=CMD_ENC_FILE
126 5 : && sb->path.cmd!=CMD_EFS_FILE
127 5 : && sb->path.cmd!=CMD_SPECIAL
128 3 : && !cmd_is_link(sb->path.cmd))
129 0 : continue;
130 :
131 : // Some messing around so that we can list '/'.
132 20 : if(!*(root->name) && !strncmp(sb->path.buf, "/", 1))
133 : {
134 1 : memcpy(&root->statp, &sb->statp, sizeof(struct stat));
135 1 : free_w(&root->name);
136 1 : if(!(root->name=strdup_w("/", __func__)))
137 : goto end;
138 : }
139 :
140 20 : point=root;
141 20 : if((tok=strtok(sb->path.buf, "/"))) do
142 : {
143 89 : if(point->count>0)
144 : {
145 46 : p=point->ents[point->count-1];
146 46 : if(!strcmp(tok, p->name))
147 : {
148 27 : point=p;
149 27 : continue;
150 : }
151 : }
152 :
153 62 : if(sb->path.buf+sb->path.len!=tok+strlen(tok))
154 : {
155 : // There is an entry in a directory where the
156 : // directory itself was not backed up.
157 : // We will make a fake entry for the directory,
158 : // and use the same stat data.
159 : // Make sure that we set the directory flag.
160 42 : sb->statp.st_mode&=S_IFDIR;
161 : }
162 62 : if(ent_add_to_list(point, sb, tok)) goto end;
163 62 : point=point->ents[point->count-1];
164 89 : } while((tok=strtok(NULL, "/")));
165 : }
166 :
167 1 : if(!(cached_client=strdup_w(cname, __func__)))
168 : goto end;
169 1 : cached_bno=bno;
170 1 : ret=0;
171 : // cache_dump(root, &depth);
172 : end:
173 1 : return ret;
174 : }
175 :
176 4 : int cache_loaded(const char *cname, unsigned long bno)
177 : {
178 4 : if(cached_client
179 2 : && !strcmp(cname, cached_client)
180 2 : && cached_bno==bno)
181 : return 1;
182 3 : return 0;
183 : }
184 :
185 : static int result_single(struct ent *ent)
186 : {
187 : // printf("result: %s\n", ent->name);
188 0 : return json_from_entry(ent->name, ent->link, &ent->statp);
189 : }
190 :
191 0 : static int result_list(struct ent *ent)
192 : {
193 0 : int i=0;
194 : // printf("in results\n");
195 0 : for(i=0; i<ent->count; i++)
196 0 : result_single(ent->ents[i]);
197 0 : return 0;
198 : }
199 :
200 0 : int cache_lookup(const char *browse)
201 : {
202 0 : int i=0;
203 0 : int ret=-1;
204 0 : char *tok=NULL;
205 0 : char *copy=NULL;
206 0 : struct ent *point=root;
207 :
208 0 : if(!browse || !*browse)
209 : {
210 : // The difference between the top level for Windows and the
211 : // top level for non-Windows.
212 0 : if(*(point->name)) ret=result_single(point);
213 0 : else ret=result_list(point);
214 : goto end;
215 : }
216 :
217 0 : if(!(copy=strdup_w(browse, __func__)))
218 : goto end;
219 0 : if((tok=strtok(copy, "/"))) do
220 : {
221 : // FIX THIS: Should do a binary search here, for monster speed
222 : // increases when there are lots of files in a directory.
223 0 : for(i=0; i<point->count; i++)
224 : {
225 0 : if(strcmp(tok, point->ents[i]->name)) continue;
226 : point=point->ents[i];
227 : break;
228 : }
229 0 : } while((tok=strtok(NULL, "/")));
230 :
231 0 : ret=result_list(point);
232 : end:
233 0 : free_w(©);
234 0 : return ret;
235 : }
|