Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../bu.h"
4 : #include "../../cmd.h"
5 : #include "../../cstat.h"
6 : #include "../../log.h"
7 : #include "../../sbuf.h"
8 : #include "../manio.h"
9 : #include "json_output.h"
10 :
11 : typedef struct ent ent_t;
12 :
13 : struct ent
14 : {
15 : char *name;
16 : int count;
17 : struct stat statp;
18 : struct ent **ents;
19 : };
20 :
21 0 : static void ent_free(struct ent **ent)
22 : {
23 0 : if(!ent || !*ent) return;
24 0 : free_w(&(*ent)->name);
25 0 : free_v((void **)&(*ent)->ents);
26 0 : free_v((void **)ent);
27 : }
28 :
29 0 : static struct ent *ent_alloc(const char *name)
30 : {
31 : struct ent *ent;
32 0 : if(!(ent=(struct ent *)calloc_w(1, sizeof(struct ent), __func__))
33 0 : || !(ent->name=strdup_w(name, __func__)))
34 : goto error;
35 0 : return ent;
36 : error:
37 0 : ent_free(&ent);
38 0 : return NULL;
39 : }
40 :
41 : // FIX THIS:
42 : // For extra kicks, could make the config option allow multiple caches -
43 : // eg, 'monitor_browse_cache=5', then rotate out the oldest one.
44 :
45 : static struct ent *root=NULL;
46 : static char *cached_client=NULL;
47 : static unsigned long cached_bno=0;
48 :
49 0 : static int ent_add_to_list(struct ent *ent,
50 : struct sbuf *sb, const char *ent_name)
51 : {
52 0 : struct ent *enew=NULL;
53 0 : if(!(ent->ents=(struct ent **)realloc_w(ent->ents,
54 0 : (ent->count+1)*sizeof(struct ent *), __func__))
55 0 : || !(enew=ent_alloc(ent_name)))
56 : {
57 0 : log_out_of_memory(__func__);
58 : return -1;
59 : }
60 0 : memcpy(&enew->statp, &sb->statp, sizeof(struct stat));
61 0 : ent->ents[ent->count]=enew;
62 0 : ent->count++;
63 : return 0;
64 : }
65 :
66 0 : static void ents_free(struct ent *ent)
67 : {
68 0 : int i=0;
69 0 : for(i=0; i<ent->count; i++)
70 0 : ents_free(ent->ents[i]);
71 0 : ent_free(&ent);
72 0 : }
73 :
74 0 : void cache_free(void)
75 : {
76 0 : if(!root) return;
77 0 : ents_free(root);
78 : }
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 0 : int cache_load(struct asfd *srfd, struct manio *manio, struct sbuf *sb,
97 : struct cstat *cstat, struct bu *bu)
98 : {
99 0 : int ret=-1;
100 0 : int ars=0;
101 : // int depth=0;
102 0 : char *tok=NULL;
103 0 : struct ent *point=NULL;
104 0 : struct ent *p=NULL;
105 :
106 : //printf("in cache load\n");
107 : cache_free();
108 :
109 0 : if(!(root=ent_alloc(""))) goto end;
110 :
111 : while(1)
112 : {
113 0 : sbuf_free_content(sb);
114 0 : if((ars=manio_read(manio, sb)))
115 : {
116 0 : if(ars<0) goto end;
117 : // ars==1 means it ended ok.
118 : break;
119 : }
120 :
121 0 : if(manio->protocol==PROTO_2 && sb->endfile.buf)
122 : continue;
123 :
124 0 : if(sb->path.cmd!=CMD_DIRECTORY
125 0 : && sb->path.cmd!=CMD_FILE
126 0 : && sb->path.cmd!=CMD_ENC_FILE
127 0 : && sb->path.cmd!=CMD_EFS_FILE
128 0 : && sb->path.cmd!=CMD_SPECIAL
129 0 : && !cmd_is_link(sb->path.cmd))
130 : continue;
131 :
132 : // Some messing around so that we can list '/'.
133 0 : if(!*(root->name) && !strncmp(sb->path.buf, "/", 1))
134 : {
135 0 : memcpy(&root->statp, &sb->statp, sizeof(struct stat));
136 0 : free_w(&root->name);
137 0 : if(!(root->name=strdup_w("/", __func__)))
138 : goto end;
139 : }
140 :
141 0 : point=root;
142 0 : if((tok=strtok(sb->path.buf, "/"))) do
143 : {
144 0 : if(point->count>0)
145 : {
146 0 : p=point->ents[point->count-1];
147 0 : if(!strcmp(tok, p->name))
148 : {
149 : point=p;
150 : continue;
151 : }
152 : }
153 :
154 0 : 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 0 : sb->statp.st_mode&=S_IFDIR;
162 : }
163 0 : if(ent_add_to_list(point, sb, tok)) goto end;
164 0 : point=point->ents[point->count-1];
165 : } while((tok=strtok(NULL, "/")));
166 : }
167 :
168 0 : if(!(cached_client=strdup_w(cstat->name, __func__)))
169 : goto end;
170 0 : cached_bno=bu->bno;
171 0 : ret=0;
172 : // cache_dump(root, &depth);
173 : end:
174 0 : return ret;
175 : }
176 :
177 0 : int cache_loaded(struct cstat *cstat, struct bu *bu)
178 : {
179 0 : if(cached_client
180 0 : && !strcmp(cstat->name, cached_client)
181 0 : && cached_bno==bu->bno)
182 : return 1;
183 0 : 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 : } while((tok=strtok(NULL, "/")));
231 :
232 0 : ret=result_list(point);
233 : end:
234 0 : free_w(©);
235 0 : return ret;
236 : }
|