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