http://prdownloads.sourceforge.net/lufs/lufs-0.9.7.tar.gz?download
[lufs.git] / filesystems / gnetfs / search.c
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <time.h>
6 #include <pthread.h>
7
8 #include <sys/stat.h>
9
10 #include <lufs/proto.h>
11 #include <lufs/fs.h>
12
13 #include "list.h"
14 #include "vtree.h"
15 #include "gnet.h"
16 #include "gnetfs.h"
17 #include "search.h"
18
19 #define MAX_PATH        1024
20
21 static char path_buf[MAX_PATH];
22
23 void
24 delete_result(struct result *res){
25     struct list_head *p, *tmp;
26     struct gnet_locator *loc;
27
28     list_for_each_safe(p, tmp, &res->locators){
29         loc = list_entry(p, struct gnet_locator, list);
30
31         list_del(&loc->list);
32         free(loc);
33     }
34
35     list_del(&res->list);
36     free(res->name);
37     free(res);
38 }
39
40 void
41 delete_search(struct search *srch){
42     struct list_head *p, *tmp;
43
44     list_for_each_safe(p, tmp, &srch->results)
45         delete_result(list_entry(p, struct result, list));
46
47     list_del(&srch->list);
48     free(srch->txt);
49     free(srch);
50 }
51
52 struct search*
53 find_search_by_txt(struct global_ctx *glob, char *txt){
54     struct list_head *p;
55     struct search *srch;
56
57     list_for_each(p, &glob->searches){
58         srch = list_entry(p, struct search, list);
59         if(!strcmp(srch->txt, txt)){
60             TRACE("search found");
61             return srch;
62         }
63     }
64
65     TRACE("search not found");
66
67     return NULL;    
68 }
69
70 struct search*
71 find_search_by_id(struct global_ctx *glob, unsigned long id){
72     struct list_head *p;
73     struct search *srch;
74
75     list_for_each(p, &glob->searches){
76         srch = list_entry(p, struct search, list);
77         if(srch->id == id){
78             TRACE("search found");
79             return srch;
80         }
81     }
82
83     TRACE("search not found");
84
85     return NULL;
86 }
87
88 struct result*
89 find_result_by_name(struct search *srch, char *name){
90     struct list_head *p;
91     struct result *r;
92
93     list_for_each(p, &srch->results){
94         r = list_entry(p, struct result, list);
95
96         if(!strcmp(r->name, name)){
97             TRACE("result found");
98             return r;
99         }
100     }
101
102     TRACE("result not found");
103
104     return NULL;
105
106 }
107
108 static struct result*
109 find_result_by_locator(struct search *srch, struct gnet_locator *loc){
110     struct list_head *p;
111     struct result *r;
112
113     list_for_each(p, &srch->results){
114         r = list_entry(p, struct result, list);
115
116         if(!(strcmp(r->name, loc->name)) && (r->size == loc->size)){
117             TRACE("result found");
118             return r;
119         }
120     }
121
122     TRACE("result not found");
123
124     return NULL;
125 }
126
127 static void
128 search_hit(void *c, struct gnet_locator *loc, unsigned long id){
129     struct global_ctx *glob = c;
130     struct search *srch;
131     struct result *res;
132     struct gnet_locator *new_loc;
133     struct lufs_fattr fattr;
134
135     TRACE("got a search hit, search id=%lx, file=%s", id, loc->name);
136     
137     pthread_mutex_lock(&glob->lock);
138
139     if(!(srch = find_search_by_id(glob, id))){
140         WARN("unknown search id %lx", id);
141         goto out;
142     }
143
144     if(!(res = find_result_by_locator(srch, loc))){
145         TRACE("new result");
146
147         if(!(res = malloc(sizeof(struct result)))){
148             WARN("could not allocate result: %s", strerror(errno));
149             goto out;
150         }
151             
152         memset(res, 0, sizeof(struct result));
153
154         if(!(res->name = malloc(strlen(loc->name) + 1))){
155             WARN("could not allocate result: %s", strerror(errno));
156             free(res);
157             goto out;       
158         }
159
160         INIT_LIST_HEAD(&res->locators);
161         res->stamp = time(NULL);
162         res->size = loc->size;
163         strcpy(res->name, loc->name);   
164         list_add(&res->list, &srch->results);
165     }
166
167     if(!(new_loc = malloc(sizeof(struct gnet_locator)))){
168         WARN("could not allocate result locator");
169         goto out;
170     }
171
172     memset(new_loc, 0, sizeof(struct gnet_locator));
173
174     new_loc->name = res->name;
175     memcpy(new_loc->ip, loc->ip, 4);
176     memcpy(new_loc->guid, loc->guid, 16);
177     new_loc->port = loc->port;
178     new_loc->index = loc->index;
179     new_loc->size = loc->size;
180     new_loc->bwidth = loc->bwidth;
181
182     list_add(&new_loc->list, &res->locators);
183     res->nr_locators ++;
184
185     if(snprintf(path_buf, MAX_PATH, "%s/%s", SEARCH_DIR, srch->txt) >= MAX_PATH){
186         WARN("search string too long");
187         goto out;
188     }
189
190     TRACE("adding %s to %s", loc->name, path_buf);
191
192     memset(&fattr, 0, sizeof(struct lufs_fattr));
193     fattr.f_nlink = res->nr_locators;
194     fattr.f_uid = fattr.f_gid = 1;
195     fattr.f_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IFREG;
196     fattr.f_mtime = fattr.f_ctime = fattr.f_atime = res->stamp;
197     fattr.f_size = res->size;
198     
199     lu_vtree_add(glob->vtree, path_buf, res->name, NULL, &fattr, NULL);
200
201   out:
202     pthread_mutex_unlock(&glob->lock);
203 }
204
205 int
206 start_search(struct local_ctx *ctx, char *txt){
207     struct search *srch;
208     struct global_ctx *glob = *ctx->global;
209
210     TRACE("starting search for \"%s\"", txt);
211
212     if(!(srch = malloc(sizeof(struct search))))
213         goto fail;
214
215     memset(srch, 0, sizeof(struct search));
216
217     if(!(srch->txt = malloc(strlen(txt) + 1)))
218         goto fail_srch;
219
220     strcpy(srch->txt, txt);
221
222     INIT_LIST_HEAD(&srch->results);
223     srch->stamp = time(NULL);
224     
225     if(gnet_start_search(glob->gnet, txt, search_hit, glob, 0, &srch->id) < 0){
226         WARN("could not start gnet search: %s", strerror(errno));
227         goto fail_txt;
228     }
229     
230     pthread_mutex_lock(&glob->lock);
231
232     list_add_tail(&srch->list, &glob->searches);
233
234     pthread_mutex_unlock(&glob->lock);
235
236     TRACE("search started");
237
238     return 0;
239
240   fail_txt:
241     free(srch->txt);
242   fail_srch:
243     free(srch);
244   fail:
245     return -1;
246 }