diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-15 11:59:08 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-15 11:59:08 +0000 |
commit | 943110ad52014e30c1ea29b0c68166149902ab85 (patch) | |
tree | dfaa498c6f31af54ae86d31ad56ddadbfb73835c /src/fs/fs_dirmetascan.c | |
parent | 72724deec7f8d42fb33d02034bd24cd9e95eac7a (diff) | |
download | gnunet-943110ad52014e30c1ea29b0c68166149902ab85.tar.gz gnunet-943110ad52014e30c1ea29b0c68166149902ab85.zip |
-LRN: harmonize dirmetascanner, plus fixing compile errors on GNU
Diffstat (limited to 'src/fs/fs_dirmetascan.c')
-rw-r--r-- | src/fs/fs_dirmetascan.c | 2574 |
1 files changed, 1288 insertions, 1286 deletions
diff --git a/src/fs/fs_dirmetascan.c b/src/fs/fs_dirmetascan.c index fd8ab15c4..b9e400c00 100644 --- a/src/fs/fs_dirmetascan.c +++ b/src/fs/fs_dirmetascan.c | |||
@@ -1,1286 +1,1288 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2005-2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2005-2012 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation; either version 2, or (at your | 7 | by the Free Software Foundation; either version 2, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 10 | GNUnet is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | General Public License for more details. | 13 | General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU General Public License |
16 | along with GNUnet; see the file COPYING. If not, write to the | 16 | along with GNUnet; see the file COPYING. If not, write to the |
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "platform.h" | 21 | #include "platform.h" |
22 | #include "gnunet_fs_service.h" | 22 | #include "gnunet_fs_service.h" |
23 | #include "gnunet_scheduler_lib.h" | 23 | #include "gnunet_scheduler_lib.h" |
24 | 24 | #include <pthread.h> | |
25 | /** | 25 | |
26 | * Entry for each unique keyword to track how often | 26 | /** |
27 | * it occured. Contains the keyword and the counter. | 27 | * Entry for each unique keyword to track how often |
28 | */ | 28 | * it occured. Contains the keyword and the counter. |
29 | struct KeywordCounter | 29 | */ |
30 | { | 30 | struct KeywordCounter |
31 | 31 | { | |
32 | /** | 32 | |
33 | * Keyword that was found. | 33 | /** |
34 | */ | 34 | * Keyword that was found. |
35 | const char *value; | 35 | */ |
36 | 36 | const char *value; | |
37 | /** | 37 | |
38 | * How many files have this keyword? | 38 | /** |
39 | */ | 39 | * How many files have this keyword? |
40 | unsigned int count; | 40 | */ |
41 | 41 | unsigned int count; | |
42 | /** | 42 | |
43 | * This is a doubly-linked list | 43 | /** |
44 | */ | 44 | * This is a doubly-linked list |
45 | struct KeywordCounter *prev; | 45 | */ |
46 | 46 | struct KeywordCounter *prev; | |
47 | /** | 47 | |
48 | * This is a doubly-linked list | 48 | /** |
49 | */ | 49 | * This is a doubly-linked list |
50 | struct KeywordCounter *next; | 50 | */ |
51 | }; | 51 | struct KeywordCounter *next; |
52 | 52 | }; | |
53 | /** | 53 | |
54 | * Aggregate information we keep for meta data in each directory. | 54 | /** |
55 | */ | 55 | * Aggregate information we keep for meta data in each directory. |
56 | struct MetaCounter | 56 | */ |
57 | { | 57 | struct MetaCounter |
58 | /** | 58 | { |
59 | * The actual meta data. | 59 | /** |
60 | */ | 60 | * The actual meta data. |
61 | const char *data; | 61 | */ |
62 | 62 | const char *data; | |
63 | /** | 63 | |
64 | * Number of bytes in 'data'. | 64 | /** |
65 | */ | 65 | * Number of bytes in 'data'. |
66 | size_t data_size; | 66 | */ |
67 | 67 | size_t data_size; | |
68 | /** | 68 | |
69 | * Name of the plugin that provided that piece of metadata | 69 | /** |
70 | */ | 70 | * Name of the plugin that provided that piece of metadata |
71 | const char *plugin_name; | 71 | */ |
72 | 72 | const char *plugin_name; | |
73 | /** | 73 | |
74 | * Type of the data | 74 | /** |
75 | */ | 75 | * Type of the data |
76 | enum EXTRACTOR_MetaType type; | 76 | */ |
77 | 77 | enum EXTRACTOR_MetaType type; | |
78 | /** | 78 | |
79 | * Format of the data | 79 | /** |
80 | */ | 80 | * Format of the data |
81 | enum EXTRACTOR_MetaFormat format; | 81 | */ |
82 | 82 | enum EXTRACTOR_MetaFormat format; | |
83 | /** | 83 | |
84 | * MIME-type of the metadata itself | 84 | /** |
85 | */ | 85 | * MIME-type of the metadata itself |
86 | const char *data_mime_type; | 86 | */ |
87 | 87 | const char *data_mime_type; | |
88 | /** | 88 | |
89 | * How many files have meta entries matching this value? | 89 | /** |
90 | * (type and format do not have to match). | 90 | * How many files have meta entries matching this value? |
91 | */ | 91 | * (type and format do not have to match). |
92 | unsigned int count; | 92 | */ |
93 | 93 | unsigned int count; | |
94 | /** | 94 | |
95 | * This is a doubly-linked list | 95 | /** |
96 | */ | 96 | * This is a doubly-linked list |
97 | struct MetaCounter *prev; | 97 | */ |
98 | 98 | struct MetaCounter *prev; | |
99 | /** | 99 | |
100 | * This is a doubly-linked list | 100 | /** |
101 | */ | 101 | * This is a doubly-linked list |
102 | struct MetaCounter *next; | 102 | */ |
103 | }; | 103 | struct MetaCounter *next; |
104 | 104 | }; | |
105 | struct AddDirContext; | 105 | |
106 | 106 | struct AddDirContext; | |
107 | /** | 107 | |
108 | * A structure used to hold a pointer to the tree item that is being | 108 | /** |
109 | * processed. | 109 | * A structure used to hold a pointer to the tree item that is being |
110 | * Needed to avoid changing the context for every recursive call. | 110 | * processed. |
111 | */ | 111 | * Needed to avoid changing the context for every recursive call. |
112 | struct AddDirStack | 112 | */ |
113 | { | 113 | struct AddDirStack |
114 | /** | 114 | { |
115 | * Context pointer | 115 | /** |
116 | */ | 116 | * Context pointer |
117 | struct AddDirContext *adc; | 117 | */ |
118 | 118 | struct AddDirContext *adc; | |
119 | /** | 119 | |
120 | * Parent directory | 120 | /** |
121 | */ | 121 | * Parent directory |
122 | struct ShareTreeItem *parent; | 122 | */ |
123 | }; | 123 | struct GNUNET_FS_ShareTreeItem *parent; |
124 | 124 | }; | |
125 | /** | 125 | |
126 | * Execution context for 'add_dir' | 126 | /** |
127 | * Owned by the initiator thread. | 127 | * Execution context for 'add_dir' |
128 | */ | 128 | * Owned by the initiator thread. |
129 | struct AddDirContext | 129 | */ |
130 | { | 130 | struct AddDirContext |
131 | /** | 131 | { |
132 | * After the scan is finished, it will contain a pointer to the | 132 | /** |
133 | * top-level directory entry in the directory tree built by the | 133 | * After the scan is finished, it will contain a pointer to the |
134 | * scanner. | 134 | * top-level directory entry in the directory tree built by the |
135 | */ | 135 | * scanner. |
136 | struct ShareTreeItem *toplevel; | 136 | */ |
137 | 137 | struct GNUNET_FS_ShareTreeItem *toplevel; | |
138 | /** | 138 | |
139 | * Expanded filename (as given by the scan initiator). | 139 | /** |
140 | * The scanner thread stores a copy here, and frees it when it finishes. | 140 | * Expanded filename (as given by the scan initiator). |
141 | */ | 141 | * The scanner thread stores a copy here, and frees it when it finishes. |
142 | char *filename_expanded; | 142 | */ |
143 | 143 | char *filename_expanded; | |
144 | /** | 144 | |
145 | * A pipe end to read signals from. | 145 | /** |
146 | * Owned by the initiator thread. | 146 | * A pipe end to read signals from. |
147 | */ | 147 | * Owned by the initiator thread. |
148 | const struct GNUNET_DISK_FileHandle *stop_read; | 148 | */ |
149 | 149 | const struct GNUNET_DISK_FileHandle *stop_read; | |
150 | /** | 150 | |
151 | * 1 if the scanner should stop, 0 otherwise. Set in response | 151 | /** |
152 | * to communication errors or when the initiator wants the scanning | 152 | * 1 if the scanner should stop, 0 otherwise. Set in response |
153 | * process to stop. | 153 | * to communication errors or when the initiator wants the scanning |
154 | */ | 154 | * process to stop. |
155 | char do_stop; | 155 | */ |
156 | 156 | char do_stop; | |
157 | /** | 157 | |
158 | * Handle of the pipe end into which the progress messages are written | 158 | /** |
159 | * The pipe is owned by the initiator thread, and there's no way to | 159 | * Handle of the pipe end into which the progress messages are written |
160 | * close this end without having access to the pipe, so it won't | 160 | * The pipe is owned by the initiator thread, and there's no way to |
161 | * be closed by the scanner thread. | 161 | * close this end without having access to the pipe, so it won't |
162 | * The initiator MUST keep it alive until the scanner thread is finished. | 162 | * be closed by the scanner thread. |
163 | */ | 163 | * The initiator MUST keep it alive until the scanner thread is finished. |
164 | const struct GNUNET_DISK_FileHandle *progress_write; | 164 | */ |
165 | 165 | const struct GNUNET_DISK_FileHandle *progress_write; | |
166 | 166 | ||
167 | /** | 167 | |
168 | * List of libextractor plugins to use for extracting. | 168 | /** |
169 | * Initialized when the scan starts, removed when it finishes. | 169 | * List of libextractor plugins to use for extracting. |
170 | */ | 170 | * Initialized when the scan starts, removed when it finishes. |
171 | struct EXTRACTOR_PluginList *plugins; | 171 | */ |
172 | }; | 172 | struct EXTRACTOR_PluginList *plugins; |
173 | 173 | }; | |
174 | /** | 174 | |
175 | * An opaque structure a pointer to which is returned to the | 175 | /** |
176 | * caller to be used to control the scanner. | 176 | * An opaque structure a pointer to which is returned to the |
177 | */ | 177 | * caller to be used to control the scanner. |
178 | struct GNUNET_FS_DirScanner | 178 | */ |
179 | { | 179 | struct GNUNET_FS_DirScanner |
180 | /** | 180 | { |
181 | * A pipe end to read signals from. | 181 | /** |
182 | * Owned by the initiator thread. | 182 | * A pipe end to read signals from. |
183 | */ | 183 | * Owned by the initiator thread. |
184 | const struct GNUNET_DISK_FileHandle *stop_write; | 184 | */ |
185 | 185 | const struct GNUNET_DISK_FileHandle *stop_write; | |
186 | /** | 186 | |
187 | * A pipe transfer signals to the scanner. | 187 | /** |
188 | * Owned by the initiator thread. | 188 | * A pipe transfer signals to the scanner. |
189 | */ | 189 | * Owned by the initiator thread. |
190 | struct GNUNET_DISK_PipeHandle *stop_pipe; | 190 | */ |
191 | 191 | struct GNUNET_DISK_PipeHandle *stop_pipe; | |
192 | /** | 192 | |
193 | * A thread object for the scanner thread. | 193 | /** |
194 | * Owned by the initiator thread. | 194 | * A thread object for the scanner thread. |
195 | */ | 195 | * Owned by the initiator thread. |
196 | #if WINDOWS | 196 | */ |
197 | HANDLE thread; | 197 | #if WINDOWS |
198 | #else | 198 | HANDLE thread; |
199 | pthread_t thread; | 199 | #else |
200 | #endif | 200 | pthread_t thread; |
201 | 201 | #endif | |
202 | /** | 202 | |
203 | * A task for reading progress messages from the scanner. | 203 | /** |
204 | */ | 204 | * A task for reading progress messages from the scanner. |
205 | GNUNET_SCHEDULER_TaskIdentifier progress_read_task; | 205 | */ |
206 | 206 | GNUNET_SCHEDULER_TaskIdentifier progress_read_task; | |
207 | /** | 207 | |
208 | * The end of the pipe that is used to read progress messages. | 208 | /** |
209 | */ | 209 | * The end of the pipe that is used to read progress messages. |
210 | const struct GNUNET_DISK_FileHandle *progress_read; | 210 | */ |
211 | 211 | const struct GNUNET_DISK_FileHandle *progress_read; | |
212 | /** | 212 | |
213 | * The pipe that is used to read progress messages. | 213 | /** |
214 | * Owned (along with both of its ends) by the initiator thread. | 214 | * The pipe that is used to read progress messages. |
215 | * Only closed after the scanner thread is finished. | 215 | * Owned (along with both of its ends) by the initiator thread. |
216 | */ | 216 | * Only closed after the scanner thread is finished. |
217 | struct GNUNET_DISK_PipeHandle *progress_pipe; | 217 | */ |
218 | 218 | struct GNUNET_DISK_PipeHandle *progress_pipe; | |
219 | /** | 219 | |
220 | * The function that will be called every time there's a progress | 220 | /** |
221 | * message. | 221 | * The function that will be called every time there's a progress |
222 | */ | 222 | * message. |
223 | GNUNET_FS_DirScannerProgressCallback progress_callback; | 223 | */ |
224 | 224 | GNUNET_FS_DirScannerProgressCallback progress_callback; | |
225 | /** | 225 | |
226 | * A closure for progress_callback. | 226 | /** |
227 | */ | 227 | * A closure for progress_callback. |
228 | void *cls; | 228 | */ |
229 | 229 | void *cls; | |
230 | /** | 230 | |
231 | * A pointer to the context of the scanner. | 231 | /** |
232 | * Owned by the initiator thread. | 232 | * A pointer to the context of the scanner. |
233 | * Initiator thread shouldn't touch it until the scanner thread | 233 | * Owned by the initiator thread. |
234 | * is finished. | 234 | * Initiator thread shouldn't touch it until the scanner thread |
235 | */ | 235 | * is finished. |
236 | struct AddDirContext *adc; | 236 | */ |
237 | }; | 237 | struct AddDirContext *adc; |
238 | 238 | }; | |
239 | /** | 239 | |
240 | * A structure that forms a singly-linked list that serves as a stack | 240 | /** |
241 | * for metadata-processing function. | 241 | * A structure that forms a singly-linked list that serves as a stack |
242 | */ | 242 | * for metadata-processing function. |
243 | struct ProcessMetadataStackItem | 243 | */ |
244 | { | 244 | struct ProcessMetadataStackItem |
245 | /** | 245 | { |
246 | * A pointer to metadata-processing context. | 246 | /** |
247 | * The same in every stack item. | 247 | * A pointer to metadata-processing context. |
248 | */ | 248 | * The same in every stack item. |
249 | struct ProcessMetadataContext *ctx; | 249 | */ |
250 | 250 | struct GNUNET_FS_ProcessMetadataContext *ctx; | |
251 | /** | 251 | |
252 | * This is a singly-linked list. A pointer to its end is kept, and | 252 | /** |
253 | * this pointer is used to walk it backwards. | 253 | * This is a singly-linked list. A pointer to its end is kept, and |
254 | */ | 254 | * this pointer is used to walk it backwards. |
255 | struct ProcessMetadataStackItem *parent; | 255 | */ |
256 | 256 | struct ProcessMetadataStackItem *parent; | |
257 | /** | 257 | |
258 | * Map from the hash over the keyword to an 'struct KeywordCounter *' | 258 | /** |
259 | * counter that says how often this keyword was | 259 | * Map from the hash over the keyword to an 'struct KeywordCounter *' |
260 | * encountered in the current directory. | 260 | * counter that says how often this keyword was |
261 | */ | 261 | * encountered in the current directory. |
262 | struct GNUNET_CONTAINER_MultiHashMap *keywordcounter; | 262 | */ |
263 | 263 | struct GNUNET_CONTAINER_MultiHashMap *keywordcounter; | |
264 | /** | 264 | |
265 | * Map from the hash over the metadata to an 'struct MetaCounter *' | 265 | /** |
266 | * counter that says how often this metadata was | 266 | * Map from the hash over the metadata to an 'struct MetaCounter *' |
267 | * encountered in the current directory. | 267 | * counter that says how often this metadata was |
268 | */ | 268 | * encountered in the current directory. |
269 | struct GNUNET_CONTAINER_MultiHashMap *metacounter; | 269 | */ |
270 | 270 | struct GNUNET_CONTAINER_MultiHashMap *metacounter; | |
271 | /** | 271 | |
272 | * Number of files in the current directory. | 272 | /** |
273 | */ | 273 | * Number of files in the current directory. |
274 | unsigned int dir_entry_count; | 274 | */ |
275 | 275 | unsigned int dir_entry_count; | |
276 | /** | 276 | |
277 | * Keywords to exclude from using for KSK since they'll be associated | 277 | /** |
278 | * with the parent as well. NULL for nothing blocked. | 278 | * Keywords to exclude from using for KSK since they'll be associated |
279 | */ | 279 | * with the parent as well. NULL for nothing blocked. |
280 | struct GNUNET_FS_Uri *exclude_ksk; | 280 | */ |
281 | 281 | struct GNUNET_FS_Uri *exclude_ksk; | |
282 | /** | 282 | |
283 | * A share tree item that is being processed. | 283 | /** |
284 | */ | 284 | * A share tree item that is being processed. |
285 | struct ShareTreeItem *item; | 285 | */ |
286 | 286 | struct GNUNET_FS_ShareTreeItem *item; | |
287 | /** | 287 | |
288 | * Set to GNUNET_YES to indicate that the directory pointer by 'item' | 288 | /** |
289 | * was processed, and we should move on to the next. | 289 | * Set to GNUNET_YES to indicate that the directory pointer by 'item' |
290 | * Otherwise the directory will be recursed into. | 290 | * was processed, and we should move on to the next. |
291 | */ | 291 | * Otherwise the directory will be recursed into. |
292 | int end_directory; | 292 | */ |
293 | 293 | int end_directory; | |
294 | }; | 294 | |
295 | 295 | }; | |
296 | /** | 296 | |
297 | * The structure to keep the state of metadata processing | 297 | /** |
298 | */ | 298 | * The structure to keep the state of metadata processing |
299 | struct ProcessMetadataContext | 299 | */ |
300 | { | 300 | struct GNUNET_FS_ProcessMetadataContext |
301 | /** | 301 | { |
302 | * The top of the stack. | 302 | /** |
303 | */ | 303 | * The top of the stack. |
304 | struct ProcessMetadataStackItem *stack; | 304 | */ |
305 | 305 | struct ProcessMetadataStackItem *stack; | |
306 | /** | 306 | |
307 | * Callback to invoke when processing is finished | 307 | /** |
308 | */ | 308 | * Callback to invoke when processing is finished |
309 | GNUNET_SCHEDULER_Task cb; | 309 | */ |
310 | 310 | GNUNET_SCHEDULER_Task cb; | |
311 | /** | 311 | |
312 | * Closure for 'cb' | 312 | /** |
313 | */ | 313 | * Closure for 'cb' |
314 | void *cls; | 314 | */ |
315 | 315 | void *cls; | |
316 | /** | 316 | |
317 | * Toplevel directory item of the tree to process. | 317 | /** |
318 | */ | 318 | * Toplevel directory item of the tree to process. |
319 | struct ShareTreeItem *toplevel; | 319 | */ |
320 | }; | 320 | struct GNUNET_FS_ShareTreeItem *toplevel; |
321 | 321 | }; | |
322 | /** | 322 | |
323 | * Called every now and then by the scanner. | 323 | /** |
324 | * Checks the synchronization privitive. | 324 | * Called every now and then by the scanner. |
325 | * Returns 1 if the scanner should stop, 0 otherwise. | 325 | * Checks the synchronization privitive. |
326 | */ | 326 | * Returns 1 if the scanner should stop, 0 otherwise. |
327 | static int | 327 | */ |
328 | should_stop (struct AddDirContext *adc) | 328 | static int |
329 | { | 329 | should_stop (struct AddDirContext *adc) |
330 | errno = 0; | 330 | { |
331 | char c; | 331 | errno = 0; |
332 | if (GNUNET_DISK_file_read_non_blocking (adc->stop_read, &c, 1) == 1 | 332 | char c; |
333 | || errno != EAGAIN) | 333 | if (GNUNET_DISK_file_read_non_blocking (adc->stop_read, &c, 1) == 1 |
334 | { | 334 | || errno != EAGAIN) |
335 | adc->do_stop = 1; | 335 | { |
336 | } | 336 | adc->do_stop = 1; |
337 | return adc->do_stop; | 337 | } |
338 | } | 338 | return adc->do_stop; |
339 | 339 | } | |
340 | /** | 340 | |
341 | * Write progress message. | 341 | /** |
342 | * Format is: | 342 | * Write progress message. |
343 | * <reason><filename length><filename><directory flag> | 343 | * Format is: |
344 | * If filename is NULL, filename is not written, and its length | 344 | * <reason><filename length><filename><directory flag> |
345 | * is written as 0, and nothing else is written. It signals the initiator | 345 | * If filename is NULL, filename is not written, and its length |
346 | * thread that the scanner is finished, and that it can now join its thread. | 346 | * is written as 0, and nothing else is written. It signals the initiator |
347 | * | 347 | * thread that the scanner is finished, and that it can now join its thread. |
348 | * Also checks if the initiator thread wants the scanner to stop, | 348 | * |
349 | * Returns 1 to stop scanning (if the signal was received, or | 349 | * Also checks if the initiator thread wants the scanner to stop, |
350 | * if the pipe was broken somehow), 0 otherwise. | 350 | * Returns 1 to stop scanning (if the signal was received, or |
351 | */ | 351 | * if the pipe was broken somehow), 0 otherwise. |
352 | static int | 352 | */ |
353 | write_progress (struct AddDirContext *adc, const char *filename, | 353 | static int |
354 | char is_directory, enum GNUNET_DirScannerProgressUpdateReason reason) | 354 | write_progress (struct AddDirContext *adc, const char *filename, |
355 | { | 355 | char is_directory, enum GNUNET_FS_DirScannerProgressUpdateReason reason) |
356 | size_t filename_len; | 356 | { |
357 | ssize_t wr; | 357 | size_t filename_len; |
358 | size_t total_write; | 358 | ssize_t wr; |
359 | if ((adc->do_stop || should_stop (adc)) && reason != GNUNET_DIR_SCANNER_ASKED_TO_STOP | 359 | size_t total_write; |
360 | && reason != GNUNET_DIR_SCANNER_FINISHED) | 360 | if ((adc->do_stop || should_stop (adc)) && reason != GNUNET_DIR_SCANNER_ASKED_TO_STOP |
361 | return 1; | 361 | && reason != GNUNET_DIR_SCANNER_FINISHED) |
362 | total_write = 0; | 362 | return 1; |
363 | wr = 1; | 363 | total_write = 0; |
364 | while ((wr > 0 || errno == EAGAIN) && total_write < sizeof (reason)) | 364 | wr = 1; |
365 | { | 365 | while ((wr > 0 || errno == EAGAIN) && total_write < sizeof (reason)) |
366 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, | 366 | { |
367 | &((char *)&reason)[total_write], sizeof (reason) - total_write); | 367 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, |
368 | if (wr > 0) | 368 | &((char *)&reason)[total_write], sizeof (reason) - total_write); |
369 | total_write += wr; | 369 | if (wr > 0) |
370 | } | 370 | total_write += wr; |
371 | if (sizeof (reason) != total_write) | 371 | } |
372 | return adc->do_stop = 1; | 372 | if (sizeof (reason) != total_write) |
373 | if (filename) | 373 | return adc->do_stop = 1; |
374 | filename_len = strlen (filename) + 1; | 374 | if (filename) |
375 | else | 375 | filename_len = strlen (filename) + 1; |
376 | filename_len = 0; | 376 | else |
377 | total_write = 0; | 377 | filename_len = 0; |
378 | wr = 1; | 378 | total_write = 0; |
379 | while ((wr > 0 || errno == EAGAIN) && total_write < sizeof (size_t)) | 379 | wr = 1; |
380 | { | 380 | while ((wr > 0 || errno == EAGAIN) && total_write < sizeof (size_t)) |
381 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, | 381 | { |
382 | &((char *)&filename_len)[total_write], sizeof (size_t) - total_write); | 382 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, |
383 | if (wr > 0) | 383 | &((char *)&filename_len)[total_write], sizeof (size_t) - total_write); |
384 | total_write += wr; | 384 | if (wr > 0) |
385 | } | 385 | total_write += wr; |
386 | if (sizeof (size_t) != total_write) | 386 | } |
387 | return adc->do_stop = 1; | 387 | if (sizeof (size_t) != total_write) |
388 | if (filename) | 388 | return adc->do_stop = 1; |
389 | { | 389 | if (filename) |
390 | total_write = 0; | 390 | { |
391 | wr = 1; | 391 | total_write = 0; |
392 | while ((wr > 0 || errno == EAGAIN) && total_write < filename_len) | 392 | wr = 1; |
393 | { | 393 | while ((wr > 0 || errno == EAGAIN) && total_write < filename_len) |
394 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, | 394 | { |
395 | &((char *)filename)[total_write], filename_len - total_write); | 395 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, |
396 | if (wr > 0) | 396 | &((char *)filename)[total_write], filename_len - total_write); |
397 | total_write += wr; | 397 | if (wr > 0) |
398 | } | 398 | total_write += wr; |
399 | if (filename_len != total_write) | 399 | } |
400 | return adc->do_stop = 1; | 400 | if (filename_len != total_write) |
401 | total_write = 0; | 401 | return adc->do_stop = 1; |
402 | wr = 1; | 402 | total_write = 0; |
403 | while ((wr > 0 || errno == EAGAIN) && total_write < sizeof (char)) | 403 | wr = 1; |
404 | { | 404 | while ((wr > 0 || errno == EAGAIN) && total_write < sizeof (char)) |
405 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, | 405 | { |
406 | &((char *)&is_directory)[total_write], sizeof (char) - total_write); | 406 | wr = GNUNET_DISK_file_write_blocking (adc->progress_write, |
407 | if (wr > 0) | 407 | &((char *)&is_directory)[total_write], sizeof (char) - total_write); |
408 | total_write += wr; | 408 | if (wr > 0) |
409 | } | 409 | total_write += wr; |
410 | if (sizeof (char) != total_write) | 410 | } |
411 | return adc->do_stop = 1; | 411 | if (sizeof (char) != total_write) |
412 | } | 412 | return adc->do_stop = 1; |
413 | return 0; | 413 | } |
414 | } | 414 | return 0; |
415 | 415 | } | |
416 | /** | 416 | |
417 | * Add the given keyword to the | 417 | /** |
418 | * keyword statistics tracker. | 418 | * Add the given keyword to the |
419 | * | 419 | * keyword statistics tracker. |
420 | * @param cls closure (user-defined) | 420 | * |
421 | * @param keyword the keyword to count | 421 | * @param cls closure (user-defined) |
422 | * @param is_mandatory ignored | 422 | * @param keyword the keyword to count |
423 | * @return always GNUNET_OK | 423 | * @param is_mandatory ignored |
424 | */ | 424 | * @return always GNUNET_OK |
425 | static int | 425 | */ |
426 | add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory) | 426 | static int |
427 | { | 427 | add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory) |
428 | struct GNUNET_CONTAINER_MultiHashMap *mcm = cls; | 428 | { |
429 | struct KeywordCounter *cnt, *first_cnt; | 429 | struct GNUNET_CONTAINER_MultiHashMap *mcm = cls; |
430 | GNUNET_HashCode hc; | 430 | struct KeywordCounter *cnt, *first_cnt; |
431 | size_t klen; | 431 | GNUNET_HashCode hc; |
432 | 432 | size_t klen; | |
433 | klen = strlen (keyword) + 1; | 433 | |
434 | GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); | 434 | klen = strlen (keyword) + 1; |
435 | /* Since the map might contain multiple values per keyword, we only | 435 | GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); |
436 | * store one value, and attach all other to it, forming a linked list. | 436 | /* Since the map might contain multiple values per keyword, we only |
437 | * Somewhat easier than retrieving multiple items via callback. | 437 | * store one value, and attach all other to it, forming a linked list. |
438 | */ | 438 | * Somewhat easier than retrieving multiple items via callback. |
439 | first_cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc); | 439 | */ |
440 | for (cnt = first_cnt; cnt && strcmp (cnt->value, keyword) != 0; cnt = cnt->next); | 440 | first_cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc); |
441 | if (cnt == NULL) | 441 | for (cnt = first_cnt; cnt && strcmp (cnt->value, keyword) != 0; cnt = cnt->next); |
442 | { | 442 | if (cnt == NULL) |
443 | cnt = GNUNET_malloc (sizeof (struct KeywordCounter) + klen); | 443 | { |
444 | cnt->value = (const char *) &cnt[1]; | 444 | cnt = GNUNET_malloc (sizeof (struct KeywordCounter) + klen); |
445 | memcpy (&cnt[1], keyword, klen); | 445 | cnt->value = (const char *) &cnt[1]; |
446 | if (first_cnt != NULL) | 446 | memcpy (&cnt[1], keyword, klen); |
447 | { | 447 | if (first_cnt != NULL) |
448 | if (first_cnt->prev != NULL) | 448 | { |
449 | { | 449 | if (first_cnt->prev != NULL) |
450 | first_cnt->prev->next = cnt; | 450 | { |
451 | cnt->prev = first_cnt->prev; | 451 | first_cnt->prev->next = cnt; |
452 | } | 452 | cnt->prev = first_cnt->prev; |
453 | first_cnt->prev = cnt; | 453 | } |
454 | cnt->next = first_cnt; | 454 | first_cnt->prev = cnt; |
455 | } | 455 | cnt->next = first_cnt; |
456 | else | 456 | } |
457 | GNUNET_CONTAINER_multihashmap_put (mcm, &hc, cnt, | 457 | else |
458 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | 458 | GNUNET_CONTAINER_multihashmap_put (mcm, &hc, cnt, |
459 | } | 459 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); |
460 | cnt->count++; | 460 | } |
461 | return GNUNET_OK; | 461 | cnt->count++; |
462 | } | 462 | return GNUNET_OK; |
463 | 463 | } | |
464 | /** | 464 | |
465 | * Type of a function that libextractor calls for each | 465 | /** |
466 | * meta data item found. | 466 | * Type of a function that libextractor calls for each |
467 | * | 467 | * meta data item found. |
468 | * @param cls the container multihashmap to update | 468 | * |
469 | * @param plugin_name name of the plugin that produced this value; | 469 | * @param cls the container multihashmap to update |
470 | * special values can be used (i.e. '<zlib>' for zlib being | 470 | * @param plugin_name name of the plugin that produced this value; |
471 | * used in the main libextractor library and yielding | 471 | * special values can be used (i.e. '<zlib>' for zlib being |
472 | * meta data). | 472 | * used in the main libextractor library and yielding |
473 | * @param type libextractor-type describing the meta data | 473 | * meta data). |
474 | * @param format basic format information about data | 474 | * @param type libextractor-type describing the meta data |
475 | * @param data_mime_type mime-type of data (not of the original file); | 475 | * @param format basic format information about data |
476 | * can be NULL (if mime-type is not known) | 476 | * @param data_mime_type mime-type of data (not of the original file); |
477 | * @param data actual meta-data found | 477 | * can be NULL (if mime-type is not known) |
478 | * @param data_len number of bytes in data | 478 | * @param data actual meta-data found |
479 | * @return GNUNET_OK to continue extracting / iterating | 479 | * @param data_len number of bytes in data |
480 | */ | 480 | * @return GNUNET_OK to continue extracting / iterating |
481 | static int | 481 | */ |
482 | add_to_meta_counter (void *cls, const char *plugin_name, | 482 | static int |
483 | enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, | 483 | add_to_meta_counter (void *cls, const char *plugin_name, |
484 | const char *data_mime_type, const char *data, size_t data_len) | 484 | enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, |
485 | { | 485 | const char *data_mime_type, const char *data, size_t data_len) |
486 | struct GNUNET_CONTAINER_MultiHashMap *map = cls; | 486 | { |
487 | GNUNET_HashCode key; | 487 | struct GNUNET_CONTAINER_MultiHashMap *map = cls; |
488 | struct MetaCounter *cnt, *first_cnt; | 488 | GNUNET_HashCode key; |
489 | 489 | struct MetaCounter *cnt, *first_cnt; | |
490 | GNUNET_CRYPTO_hash (data, data_len, &key); | 490 | |
491 | first_cnt = GNUNET_CONTAINER_multihashmap_get (map, &key); | 491 | GNUNET_CRYPTO_hash (data, data_len, &key); |
492 | for (cnt = first_cnt; cnt | 492 | first_cnt = GNUNET_CONTAINER_multihashmap_get (map, &key); |
493 | && cnt->data_size != data_len | 493 | for (cnt = first_cnt; cnt |
494 | && memcmp (cnt->data, data, cnt->data_size) != 0; cnt = cnt->next); | 494 | && cnt->data_size != data_len |
495 | if (cnt == NULL) | 495 | && memcmp (cnt->data, data, cnt->data_size) != 0; cnt = cnt->next); |
496 | { | 496 | if (cnt == NULL) |
497 | cnt = GNUNET_malloc (sizeof (struct MetaCounter)); | 497 | { |
498 | cnt->data = data; | 498 | cnt = GNUNET_malloc (sizeof (struct MetaCounter)); |
499 | cnt->data_size = data_len; | 499 | cnt->data = data; |
500 | cnt->plugin_name = plugin_name; | 500 | cnt->data_size = data_len; |
501 | cnt->type = type; | 501 | cnt->plugin_name = plugin_name; |
502 | cnt->format = format; | 502 | cnt->type = type; |
503 | cnt->data_mime_type = data_mime_type; | 503 | cnt->format = format; |
504 | 504 | cnt->data_mime_type = data_mime_type; | |
505 | if (first_cnt != NULL) | 505 | |
506 | { | 506 | if (first_cnt != NULL) |
507 | if (first_cnt->prev != NULL) | 507 | { |
508 | { | 508 | if (first_cnt->prev != NULL) |
509 | first_cnt->prev->next = cnt; | 509 | { |
510 | cnt->prev = first_cnt->prev; | 510 | first_cnt->prev->next = cnt; |
511 | } | 511 | cnt->prev = first_cnt->prev; |
512 | first_cnt->prev = cnt; | 512 | } |
513 | cnt->next = first_cnt; | 513 | first_cnt->prev = cnt; |
514 | } | 514 | cnt->next = first_cnt; |
515 | else | 515 | } |
516 | GNUNET_CONTAINER_multihashmap_put (map, &key, cnt, | 516 | else |
517 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | 517 | GNUNET_CONTAINER_multihashmap_put (map, &key, cnt, |
518 | } | 518 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); |
519 | cnt->count++; | 519 | } |
520 | return 0; | 520 | cnt->count++; |
521 | } | 521 | return 0; |
522 | 522 | } | |
523 | /** | 523 | |
524 | * Allocates a struct ShareTreeItem and adds it to its parent. | 524 | /** |
525 | */ | 525 | * Allocates a struct GNUNET_FS_ShareTreeItem and adds it to its parent. |
526 | static struct ShareTreeItem * | 526 | */ |
527 | make_item (struct ShareTreeItem *parent) | 527 | static struct GNUNET_FS_ShareTreeItem * |
528 | { | 528 | make_item (struct GNUNET_FS_ShareTreeItem *parent) |
529 | struct ShareTreeItem *item; | 529 | { |
530 | item = GNUNET_malloc (sizeof (struct ShareTreeItem)); | 530 | struct GNUNET_FS_ShareTreeItem *item; |
531 | 531 | item = GNUNET_malloc (sizeof (struct GNUNET_FS_ShareTreeItem)); | |
532 | item->parent = parent; | 532 | |
533 | if (parent) | 533 | item->parent = parent; |
534 | GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, | 534 | if (parent) |
535 | item); | 535 | GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, |
536 | return item; | 536 | item); |
537 | } | 537 | return item; |
538 | 538 | } | |
539 | /** | 539 | |
540 | * Extract metadata from a file and add it to the share tree | 540 | /** |
541 | * | 541 | * Extract metadata from a file and add it to the share tree |
542 | * @param adc context to modify | 542 | * |
543 | * @param filename name of the file to process | 543 | * @param adc context to modify |
544 | */ | 544 | * @param filename name of the file to process |
545 | static void | 545 | */ |
546 | extract_file (struct AddDirStack *ads, const char *filename) | 546 | static void |
547 | { | 547 | extract_file (struct AddDirStack *ads, const char *filename) |
548 | struct ShareTreeItem *item; | 548 | { |
549 | const char *short_fn; | 549 | struct GNUNET_FS_ShareTreeItem *item; |
550 | 550 | const char *short_fn; | |
551 | item = make_item (ads->parent); | 551 | |
552 | 552 | item = make_item (ads->parent); | |
553 | GNUNET_DISK_file_size (filename, &item->file_size, GNUNET_YES); | 553 | |
554 | item->is_directory = GNUNET_NO; | 554 | GNUNET_DISK_file_size (filename, &item->file_size, GNUNET_YES); |
555 | 555 | item->is_directory = GNUNET_NO; | |
556 | item->meta = GNUNET_CONTAINER_meta_data_create (); | 556 | |
557 | GNUNET_FS_meta_data_extract_from_file (item->meta, filename, | 557 | item->meta = GNUNET_CONTAINER_meta_data_create (); |
558 | ads->adc->plugins); | 558 | GNUNET_FS_meta_data_extract_from_file (item->meta, filename, |
559 | GNUNET_CONTAINER_meta_data_delete (item->meta, EXTRACTOR_METATYPE_FILENAME, | 559 | ads->adc->plugins); |
560 | NULL, 0); | 560 | GNUNET_CONTAINER_meta_data_delete (item->meta, EXTRACTOR_METATYPE_FILENAME, |
561 | short_fn = GNUNET_STRINGS_get_short_name (filename); | 561 | NULL, 0); |
562 | 562 | short_fn = GNUNET_STRINGS_get_short_name (filename); | |
563 | item->filename = GNUNET_strdup (filename); | 563 | |
564 | item->short_filename = GNUNET_strdup (short_fn); | 564 | item->filename = GNUNET_strdup (filename); |
565 | 565 | item->short_filename = GNUNET_strdup (short_fn); | |
566 | GNUNET_CONTAINER_meta_data_insert (item->meta, "<libgnunetfs>", | 566 | |
567 | EXTRACTOR_METATYPE_FILENAME, | 567 | GNUNET_CONTAINER_meta_data_insert (item->meta, "<libgnunetfs>", |
568 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | 568 | EXTRACTOR_METATYPE_FILENAME, |
569 | short_fn, strlen (short_fn) + 1); | 569 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", |
570 | } | 570 | short_fn, strlen (short_fn) + 1); |
571 | 571 | } | |
572 | /** | 572 | |
573 | * Remove the keyword from the ksk URI. | 573 | /** |
574 | * | 574 | * Remove the keyword from the ksk URI. |
575 | * @param cls the ksk uri | 575 | * |
576 | * @param keyword the word to remove | 576 | * @param cls the ksk uri |
577 | * @param is_mandatory ignored | 577 | * @param keyword the word to remove |
578 | * @return always GNUNET_OK | 578 | * @param is_mandatory ignored |
579 | */ | 579 | * @return always GNUNET_OK |
580 | static int | 580 | */ |
581 | remove_keyword (void *cls, const char *keyword, int is_mandatory) | 581 | static int |
582 | { | 582 | remove_keyword (void *cls, const char *keyword, int is_mandatory) |
583 | struct GNUNET_FS_Uri *ksk = cls; | 583 | { |
584 | 584 | struct GNUNET_FS_Uri *ksk = cls; | |
585 | GNUNET_FS_uri_ksk_remove_keyword (ksk, keyword); | 585 | |
586 | return GNUNET_OK; | 586 | GNUNET_FS_uri_ksk_remove_keyword (ksk, keyword); |
587 | } | 587 | return GNUNET_OK; |
588 | 588 | } | |
589 | /** | 589 | |
590 | * Remove keywords from current directory's children, if they are | 590 | /** |
591 | * in the exluded keywords list of that directory. | 591 | * Remove keywords from current directory's children, if they are |
592 | * | 592 | * in the exluded keywords list of that directory. |
593 | * @param cls the ksk uri | 593 | * |
594 | * @param keyword the word to remove | 594 | * @param cls the ksk uri |
595 | * @param is_mandatory ignored | 595 | * @param keyword the word to remove |
596 | * @return always GNUNET_OK | 596 | * @param is_mandatory ignored |
597 | */ | 597 | * @return always GNUNET_OK |
598 | static int | 598 | */ |
599 | remove_keywords (struct ProcessMetadataStackItem *stack, struct ShareTreeItem *dir) | 599 | static int |
600 | { | 600 | remove_keywords (struct ProcessMetadataStackItem *stack, struct GNUNET_FS_ShareTreeItem *dir) |
601 | struct ShareTreeItem *item; | 601 | { |
602 | 602 | struct GNUNET_FS_ShareTreeItem *item; | |
603 | for (item = dir->children_head; item; item = item->next) | 603 | |
604 | { | 604 | for (item = dir->children_head; item; item = item->next) |
605 | if (stack->exclude_ksk != NULL) | 605 | { |
606 | GNUNET_FS_uri_ksk_get_keywords (stack->exclude_ksk, &remove_keyword, item->ksk_uri); | 606 | if (stack->exclude_ksk != NULL) |
607 | } | 607 | GNUNET_FS_uri_ksk_get_keywords (stack->exclude_ksk, &remove_keyword, item->ksk_uri); |
608 | return GNUNET_OK; | 608 | } |
609 | } | 609 | return GNUNET_OK; |
610 | 610 | } | |
611 | /** | 611 | |
612 | * Context passed to 'migrate_and_drop'. | 612 | /** |
613 | */ | 613 | * Context passed to 'migrate_and_drop'. |
614 | struct KeywordProcessContext | 614 | */ |
615 | { | 615 | struct KeywordProcessContext |
616 | /** | 616 | { |
617 | * All the keywords we migrated to the parent. | 617 | /** |
618 | */ | 618 | * All the keywords we migrated to the parent. |
619 | struct GNUNET_FS_Uri *ksk; | 619 | */ |
620 | 620 | struct GNUNET_FS_Uri *ksk; | |
621 | /** | 621 | |
622 | * How often does a keyword have to occur to be | 622 | /** |
623 | * migrated to the parent? | 623 | * How often does a keyword have to occur to be |
624 | */ | 624 | * migrated to the parent? |
625 | unsigned int threshold; | 625 | */ |
626 | }; | 626 | unsigned int threshold; |
627 | 627 | }; | |
628 | /** | 628 | |
629 | * Context passed to 'migrate_and_drop'. | 629 | /** |
630 | */ | 630 | * Context passed to 'migrate_and_drop'. |
631 | struct MetaProcessContext | 631 | */ |
632 | { | 632 | struct MetaProcessContext |
633 | /** | 633 | { |
634 | * All the metadata we copy to the parent. | 634 | /** |
635 | */ | 635 | * All the metadata we copy to the parent. |
636 | struct GNUNET_CONTAINER_MetaData *meta; | 636 | */ |
637 | 637 | struct GNUNET_CONTAINER_MetaData *meta; | |
638 | /** | 638 | |
639 | * How often does a metadata have to occur to be | 639 | /** |
640 | * migrated to the parent? | 640 | * How often does a metadata have to occur to be |
641 | */ | 641 | * migrated to the parent? |
642 | unsigned int threshold; | 642 | */ |
643 | }; | 643 | unsigned int threshold; |
644 | 644 | }; | |
645 | 645 | ||
646 | /** | 646 | |
647 | * Move "frequent" keywords over to the | 647 | /** |
648 | * target ksk uri, free the counters. | 648 | * Move "frequent" keywords over to the |
649 | * | 649 | * target ksk uri, free the counters. |
650 | */ | 650 | * |
651 | static int | 651 | */ |
652 | migrate_and_drop (void *cls, const GNUNET_HashCode * key, void *value) | 652 | static int |
653 | { | 653 | migrate_and_drop (void *cls, const GNUNET_HashCode * key, void *value) |
654 | struct KeywordProcessContext *kpc = cls; | 654 | { |
655 | struct KeywordCounter *counter = value; | 655 | struct KeywordProcessContext *kpc = cls; |
656 | 656 | struct KeywordCounter *counter = value; | |
657 | if (counter->count >= kpc->threshold && counter->count > 1) | 657 | |
658 | { | 658 | if (counter->count >= kpc->threshold && counter->count > 1) |
659 | GNUNET_FS_uri_ksk_add_keyword (kpc->ksk, counter->value, GNUNET_NO); | 659 | { |
660 | } | 660 | GNUNET_FS_uri_ksk_add_keyword (kpc->ksk, counter->value, GNUNET_NO); |
661 | GNUNET_free (counter); | 661 | } |
662 | return GNUNET_YES; | 662 | GNUNET_free (counter); |
663 | } | 663 | return GNUNET_YES; |
664 | /** | 664 | } |
665 | * Copy "frequent" metadata items over to the | 665 | /** |
666 | * target metadata container, free the counters. | 666 | * Copy "frequent" metadata items over to the |
667 | * | 667 | * target metadata container, free the counters. |
668 | */ | 668 | * |
669 | static int | 669 | */ |
670 | migrate_and_drop_metadata (void *cls, const GNUNET_HashCode * key, void *value) | 670 | static int |
671 | { | 671 | migrate_and_drop_metadata (void *cls, const GNUNET_HashCode * key, void *value) |
672 | struct MetaProcessContext *mpc = cls; | 672 | { |
673 | struct MetaCounter *counter = value; | 673 | struct MetaProcessContext *mpc = cls; |
674 | 674 | struct MetaCounter *counter = value; | |
675 | if (counter->count >= mpc->threshold && counter->count > 1) | 675 | |
676 | { | 676 | if (counter->count >= mpc->threshold && counter->count > 1) |
677 | GNUNET_CONTAINER_meta_data_insert (mpc->meta, | 677 | { |
678 | counter->plugin_name, | 678 | GNUNET_CONTAINER_meta_data_insert (mpc->meta, |
679 | counter->type, | 679 | counter->plugin_name, |
680 | counter->format, | 680 | counter->type, |
681 | counter->data_mime_type, counter->data, | 681 | counter->format, |
682 | counter->data_size); | 682 | counter->data_mime_type, counter->data, |
683 | } | 683 | counter->data_size); |
684 | GNUNET_free (counter); | 684 | } |
685 | return GNUNET_YES; | 685 | GNUNET_free (counter); |
686 | } | 686 | return GNUNET_YES; |
687 | 687 | } | |
688 | /** | 688 | |
689 | * Go over the collected keywords from all entries in the | 689 | /** |
690 | * directory and push common keywords up one level (by | 690 | * Go over the collected keywords from all entries in the |
691 | * adding it to the returned struct). Do the same for metadata. | 691 | * directory and push common keywords up one level (by |
692 | * Destroys keywordcounter and metacoutner for current directory. | 692 | * adding it to the returned struct). Do the same for metadata. |
693 | * | 693 | * Destroys keywordcounter and metacoutner for current directory. |
694 | * @param adc collection of child meta data | 694 | * |
695 | * @param exclude_ksk pointer to where moveable keywords will be stored | 695 | * @param adc collection of child meta data |
696 | * @param copy_meta pointer to where copyable metadata will be stored | 696 | * @param exclude_ksk pointer to where moveable keywords will be stored |
697 | */ | 697 | * @param copy_meta pointer to where copyable metadata will be stored |
698 | static void | 698 | */ |
699 | process_keywords_and_metadata (struct ProcessMetadataStackItem *stack, | 699 | static void |
700 | struct GNUNET_FS_Uri **exclude_ksk, | 700 | process_keywords_and_metadata (struct ProcessMetadataStackItem *stack, |
701 | struct GNUNET_CONTAINER_MetaData **copy_meta) | 701 | struct GNUNET_FS_Uri **exclude_ksk, |
702 | { | 702 | struct GNUNET_CONTAINER_MetaData **copy_meta) |
703 | struct KeywordProcessContext kpc; | 703 | { |
704 | struct MetaProcessContext mpc; | 704 | struct KeywordProcessContext kpc; |
705 | struct GNUNET_CONTAINER_MetaData *tmp; | 705 | struct MetaProcessContext mpc; |
706 | 706 | struct GNUNET_CONTAINER_MetaData *tmp; | |
707 | /* Surprisingly, it's impossible to create a ksk with 0 keywords directly. | 707 | |
708 | * But we can create one from an empty metadata set | 708 | /* Surprisingly, it's impossible to create a ksk with 0 keywords directly. |
709 | */ | 709 | * But we can create one from an empty metadata set |
710 | tmp = GNUNET_CONTAINER_meta_data_create (); | 710 | */ |
711 | kpc.ksk = GNUNET_FS_uri_ksk_create_from_meta_data (tmp); | 711 | tmp = GNUNET_CONTAINER_meta_data_create (); |
712 | GNUNET_CONTAINER_meta_data_destroy (tmp); | 712 | kpc.ksk = GNUNET_FS_uri_ksk_create_from_meta_data (tmp); |
713 | mpc.meta = GNUNET_CONTAINER_meta_data_create (); | 713 | GNUNET_CONTAINER_meta_data_destroy (tmp); |
714 | 714 | mpc.meta = GNUNET_CONTAINER_meta_data_create (); | |
715 | kpc.threshold = mpc.threshold = (stack->dir_entry_count + 1) / 2; /* 50% */ | 715 | |
716 | 716 | kpc.threshold = mpc.threshold = (stack->dir_entry_count + 1) / 2; /* 50% */ | |
717 | GNUNET_CONTAINER_multihashmap_iterate (stack->keywordcounter, | 717 | |
718 | &migrate_and_drop, &kpc); | 718 | GNUNET_CONTAINER_multihashmap_iterate (stack->keywordcounter, |
719 | GNUNET_CONTAINER_multihashmap_iterate (stack->metacounter, | 719 | &migrate_and_drop, &kpc); |
720 | &migrate_and_drop_metadata, &mpc); | 720 | GNUNET_CONTAINER_multihashmap_iterate (stack->metacounter, |
721 | 721 | &migrate_and_drop_metadata, &mpc); | |
722 | GNUNET_CONTAINER_multihashmap_destroy (stack->keywordcounter); | 722 | |
723 | GNUNET_CONTAINER_multihashmap_destroy (stack->metacounter); | 723 | GNUNET_CONTAINER_multihashmap_destroy (stack->keywordcounter); |
724 | *exclude_ksk = kpc.ksk; | 724 | GNUNET_CONTAINER_multihashmap_destroy (stack->metacounter); |
725 | *copy_meta = mpc.meta; | 725 | *exclude_ksk = kpc.ksk; |
726 | } | 726 | *copy_meta = mpc.meta; |
727 | 727 | } | |
728 | /** | 728 | |
729 | * Function called by the directory iterator to | 729 | /** |
730 | * (recursively) add all of the files in the | 730 | * Function called by the directory iterator to |
731 | * directory to the tree. | 731 | * (recursively) add all of the files in the |
732 | * Called by the directory scanner to initiate the | 732 | * directory to the tree. |
733 | * scan. | 733 | * Called by the directory scanner to initiate the |
734 | * TODO: find a way to make it non-recursive. | 734 | * scan. |
735 | * | 735 | * TODO: find a way to make it non-recursive. |
736 | * @param cls the 'struct AddDirStack *' we're in | 736 | * |
737 | * @param filename file or directory to scan | 737 | * @param cls the 'struct AddDirStack *' we're in |
738 | */ | 738 | * @param filename file or directory to scan |
739 | static int | 739 | */ |
740 | scan_directory (void *cls, const char *filename) | 740 | static int |
741 | { | 741 | scan_directory (void *cls, const char *filename) |
742 | struct AddDirStack *ads = cls, recurse_ads; | 742 | { |
743 | struct AddDirContext *adc = ads->adc; | 743 | struct AddDirStack *ads = cls, recurse_ads; |
744 | struct stat sbuf; | 744 | struct AddDirContext *adc = ads->adc; |
745 | struct ShareTreeItem *item; | 745 | struct stat sbuf; |
746 | const char *short_fn; | 746 | struct GNUNET_FS_ShareTreeItem *item; |
747 | int do_stop = 0; | 747 | const char *short_fn; |
748 | 748 | int do_stop = 0; | |
749 | /* Wrap up fast */ | 749 | |
750 | if (adc->do_stop) | 750 | /* Wrap up fast */ |
751 | return GNUNET_SYSERR; | 751 | if (adc->do_stop) |
752 | 752 | return GNUNET_SYSERR; | |
753 | /* If the file doesn't exist (or is not statable for any other reason, | 753 | |
754 | * skip it, and report it. | 754 | /* If the file doesn't exist (or is not statable for any other reason, |
755 | */ | 755 | * skip it, and report it. |
756 | if (0 != STAT (filename, &sbuf)) | 756 | */ |
757 | { | 757 | if (0 != STAT (filename, &sbuf)) |
758 | do_stop = write_progress (adc, filename, S_ISDIR (sbuf.st_mode), | 758 | { |
759 | GNUNET_DIR_SCANNER_DOES_NOT_EXIST); | 759 | do_stop = write_progress (adc, filename, S_ISDIR (sbuf.st_mode), |
760 | return GNUNET_OK; | 760 | GNUNET_DIR_SCANNER_DOES_NOT_EXIST); |
761 | } | 761 | return GNUNET_OK; |
762 | 762 | } | |
763 | /* Report the progress */ | 763 | |
764 | do_stop = write_progress (adc, filename, S_ISDIR (sbuf.st_mode), | 764 | /* Report the progress */ |
765 | GNUNET_DIR_SCANNER_NEW_FILE); | 765 | do_stop = write_progress (adc, filename, S_ISDIR (sbuf.st_mode), |
766 | if (do_stop) | 766 | GNUNET_DIR_SCANNER_NEW_FILE); |
767 | { | 767 | if (do_stop) |
768 | /* We were asked to stop, acknowledge that and return */ | 768 | { |
769 | do_stop = write_progress (adc, filename, S_ISDIR (sbuf.st_mode), | 769 | /* We were asked to stop, acknowledge that and return */ |
770 | GNUNET_DIR_SCANNER_ASKED_TO_STOP); | 770 | do_stop = write_progress (adc, filename, S_ISDIR (sbuf.st_mode), |
771 | return GNUNET_SYSERR; | 771 | GNUNET_DIR_SCANNER_ASKED_TO_STOP); |
772 | } | 772 | return GNUNET_SYSERR; |
773 | 773 | } | |
774 | if (!S_ISDIR (sbuf.st_mode)) | 774 | |
775 | extract_file (ads, filename); | 775 | if (!S_ISDIR (sbuf.st_mode)) |
776 | else | 776 | extract_file (ads, filename); |
777 | { | 777 | else |
778 | item = make_item (ads->parent); | 778 | { |
779 | item->meta = GNUNET_CONTAINER_meta_data_create (); | 779 | item = make_item (ads->parent); |
780 | 780 | item->meta = GNUNET_CONTAINER_meta_data_create (); | |
781 | item->is_directory = GNUNET_YES; | 781 | |
782 | 782 | item->is_directory = GNUNET_YES; | |
783 | recurse_ads.adc = adc; | 783 | |
784 | recurse_ads.parent = item; | 784 | recurse_ads.adc = adc; |
785 | 785 | recurse_ads.parent = item; | |
786 | /* recurse into directory */ | 786 | |
787 | GNUNET_DISK_directory_scan (filename, &scan_directory, &recurse_ads); | 787 | /* recurse into directory */ |
788 | 788 | GNUNET_DISK_directory_scan (filename, &scan_directory, &recurse_ads); | |
789 | short_fn = GNUNET_STRINGS_get_short_name (filename); | 789 | |
790 | 790 | short_fn = GNUNET_STRINGS_get_short_name (filename); | |
791 | item->filename = GNUNET_strdup (filename); | 791 | |
792 | item->short_filename = GNUNET_strdup (short_fn); | 792 | item->filename = GNUNET_strdup (filename); |
793 | 793 | item->short_filename = GNUNET_strdup (short_fn); | |
794 | if (ads->parent == NULL) | 794 | |
795 | { | 795 | if (ads->parent == NULL) |
796 | /* we're finished with the scan, make sure caller gets the top-level | 796 | { |
797 | * directory pointer | 797 | /* we're finished with the scan, make sure caller gets the top-level |
798 | */ | 798 | * directory pointer |
799 | adc->toplevel = item; | 799 | */ |
800 | } | 800 | adc->toplevel = item; |
801 | } | 801 | } |
802 | return GNUNET_OK; | 802 | } |
803 | } | 803 | return GNUNET_OK; |
804 | 804 | } | |
805 | /** | 805 | |
806 | * Signals the scanner to finish the scan as fast as possible. | 806 | /** |
807 | * Does not block. | 807 | * Signals the scanner to finish the scan as fast as possible. |
808 | * Can close the pipe if asked to, but that is only used by the | 808 | * Does not block. |
809 | * internal call to this function during cleanup. The client | 809 | * Can close the pipe if asked to, but that is only used by the |
810 | * must understand the consequences of closing the pipe too early. | 810 | * internal call to this function during cleanup. The client |
811 | * | 811 | * must understand the consequences of closing the pipe too early. |
812 | * @param ds directory scanner structure | 812 | * |
813 | * @param close_pipe GNUNET_YES to close | 813 | * @param ds directory scanner structure |
814 | */ | 814 | * @param close_pipe GNUNET_YES to close |
815 | void | 815 | */ |
816 | GNUNET_FS_directory_scan_finish (struct GNUNET_FS_DirScanner *ds, | 816 | void |
817 | int close_pipe) | 817 | GNUNET_FS_directory_scan_finish (struct GNUNET_FS_DirScanner *ds, |
818 | { | 818 | int close_pipe) |
819 | char c = 1; | 819 | { |
820 | GNUNET_DISK_file_write (ds->stop_write, &c, 1); | 820 | char c = 1; |
821 | 821 | GNUNET_DISK_file_write (ds->stop_write, &c, 1); | |
822 | if (close_pipe) | 822 | |
823 | { | 823 | if (close_pipe) |
824 | if (ds->progress_read_task != GNUNET_SCHEDULER_NO_TASK) | 824 | { |
825 | { | 825 | if (ds->progress_read_task != GNUNET_SCHEDULER_NO_TASK) |
826 | GNUNET_SCHEDULER_cancel (ds->progress_read_task); | 826 | { |
827 | ds->progress_read_task = GNUNET_SCHEDULER_NO_TASK; | 827 | GNUNET_SCHEDULER_cancel (ds->progress_read_task); |
828 | } | 828 | ds->progress_read_task = GNUNET_SCHEDULER_NO_TASK; |
829 | GNUNET_DISK_pipe_close_end (ds->progress_pipe, GNUNET_DISK_PIPE_END_READ); | 829 | } |
830 | ds->progress_read = NULL; | 830 | GNUNET_DISK_pipe_close_end (ds->progress_pipe, GNUNET_DISK_PIPE_END_READ); |
831 | } | 831 | ds->progress_read = NULL; |
832 | } | 832 | } |
833 | 833 | } | |
834 | /** | 834 | |
835 | * Signals the scanner thread to finish (in case it isn't finishing | 835 | /** |
836 | * already) and joins the scanner thread. Closes the pipes, frees the | 836 | * Signals the scanner thread to finish (in case it isn't finishing |
837 | * scanner contexts (both of them), returns the results of the scan. | 837 | * already) and joins the scanner thread. Closes the pipes, frees the |
838 | * Results are valid (and have to be freed) even if the scanner had | 838 | * scanner contexts (both of them), returns the results of the scan. |
839 | * an error or was rushed to finish prematurely. | 839 | * Results are valid (and have to be freed) even if the scanner had |
840 | * Blocks until the scanner is finished. | 840 | * an error or was rushed to finish prematurely. |
841 | * | 841 | * Blocks until the scanner is finished. |
842 | * @param ds directory scanner structure | 842 | * |
843 | * @return the results of the scan (a directory tree) | 843 | * @param ds directory scanner structure |
844 | */ | 844 | * @return the results of the scan (a directory tree) |
845 | struct ShareTreeItem * | 845 | */ |
846 | GNUNET_FS_directory_scan_cleanup (struct GNUNET_FS_DirScanner *ds) | 846 | struct GNUNET_FS_ShareTreeItem * |
847 | { | 847 | GNUNET_FS_directory_scan_cleanup (struct GNUNET_FS_DirScanner *ds) |
848 | struct ShareTreeItem *result; | 848 | { |
849 | 849 | struct GNUNET_FS_ShareTreeItem *result; | |
850 | GNUNET_FS_directory_scan_finish (ds, GNUNET_YES); | 850 | |
851 | #if WINDOWS | 851 | GNUNET_FS_directory_scan_finish (ds, GNUNET_YES); |
852 | WaitForSingleObject (ds->thread, INFINITE); | 852 | #if WINDOWS |
853 | CloseHandle (ds->thread); | 853 | WaitForSingleObject (ds->thread, INFINITE); |
854 | #else | 854 | CloseHandle (ds->thread); |
855 | pthread_join (ds->thread, NULL); | 855 | #else |
856 | pthread_detach (ds->thread); | 856 | pthread_join (ds->thread, NULL); |
857 | #endif | 857 | pthread_detach (ds->thread); |
858 | 858 | #endif | |
859 | GNUNET_DISK_pipe_close (ds->stop_pipe); | 859 | |
860 | GNUNET_DISK_pipe_close (ds->progress_pipe); | 860 | GNUNET_DISK_pipe_close (ds->stop_pipe); |
861 | result = ds->adc->toplevel; | 861 | GNUNET_DISK_pipe_close (ds->progress_pipe); |
862 | GNUNET_free (ds->adc); | 862 | result = ds->adc->toplevel; |
863 | GNUNET_free (ds); | 863 | GNUNET_free (ds->adc); |
864 | return result; | 864 | GNUNET_free (ds); |
865 | } | 865 | return result; |
866 | 866 | } | |
867 | /** | 867 | |
868 | * The function from which the scanner thread starts | 868 | /** |
869 | */ | 869 | * The function from which the scanner thread starts |
870 | #if WINDOWS | 870 | */ |
871 | static DWORD | 871 | #if WINDOWS |
872 | #else | 872 | static DWORD |
873 | static int | 873 | #else |
874 | #endif | 874 | static void * |
875 | run_directory_scan_thread (struct AddDirContext *adc) | 875 | #endif |
876 | { | 876 | run_directory_scan_thread (void *cls) |
877 | struct AddDirStack ads; | 877 | { |
878 | ads.adc = adc; | 878 | struct AddDirContext *adc = cls; |
879 | ads.parent = NULL; | 879 | struct AddDirStack ads; |
880 | scan_directory (&ads, adc->filename_expanded); | 880 | ads.adc = adc; |
881 | GNUNET_free (adc->filename_expanded); | 881 | ads.parent = NULL; |
882 | if (adc->plugins != NULL) | 882 | scan_directory (&ads, adc->filename_expanded); |
883 | EXTRACTOR_plugin_remove_all (adc->plugins); | 883 | GNUNET_free (adc->filename_expanded); |
884 | /* Tell the initiator that we're finished, it can now join the thread */ | 884 | if (adc->plugins != NULL) |
885 | write_progress (adc, NULL, 0, GNUNET_DIR_SCANNER_FINISHED); | 885 | EXTRACTOR_plugin_remove_all (adc->plugins); |
886 | return 0; | 886 | /* Tell the initiator that we're finished, it can now join the thread */ |
887 | } | 887 | write_progress (adc, NULL, 0, GNUNET_DIR_SCANNER_FINISHED); |
888 | 888 | return 0; | |
889 | /** | 889 | } |
890 | * Called every time there is data to read from the scanner. | 890 | |
891 | * Calls the scanner progress handler. | 891 | /** |
892 | * | 892 | * Called every time there is data to read from the scanner. |
893 | * @param cls the closure (directory scanner object) | 893 | * Calls the scanner progress handler. |
894 | * @param tc task context in which the task is running | 894 | * |
895 | */ | 895 | * @param cls the closure (directory scanner object) |
896 | static void | 896 | * @param tc task context in which the task is running |
897 | read_progress_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 897 | */ |
898 | { | 898 | static void |
899 | struct GNUNET_FS_DirScanner *ds; | 899 | read_progress_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
900 | int end_it = 0; | 900 | { |
901 | enum GNUNET_DirScannerProgressUpdateReason reason; | 901 | struct GNUNET_FS_DirScanner *ds; |
902 | ssize_t rd; | 902 | int end_it = 0; |
903 | ssize_t total_read; | 903 | enum GNUNET_FS_DirScannerProgressUpdateReason reason; |
904 | 904 | ssize_t rd; | |
905 | size_t filename_len; | 905 | ssize_t total_read; |
906 | char is_directory; | 906 | |
907 | char *filename; | 907 | size_t filename_len; |
908 | 908 | char is_directory; | |
909 | ds = cls; | 909 | char *filename; |
910 | 910 | ||
911 | ds->progress_read_task = GNUNET_SCHEDULER_NO_TASK; | 911 | ds = cls; |
912 | 912 | ||
913 | if (!(tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) | 913 | ds->progress_read_task = GNUNET_SCHEDULER_NO_TASK; |
914 | { | 914 | |
915 | ds->progress_callback (ds->cls, ds, NULL, 0, GNUNET_DIR_SCANNER_SHUTDOWN); | 915 | if (!(tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) |
916 | return; | 916 | { |
917 | } | 917 | ds->progress_callback (ds->cls, ds, NULL, 0, GNUNET_DIR_SCANNER_SHUTDOWN); |
918 | 918 | return; | |
919 | /* Read one message. If message is malformed or can't be read, end the scanner */ | 919 | } |
920 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, &reason, sizeof (reason)); | 920 | |
921 | while (rd > 0 && total_read < sizeof (reason)) | 921 | /* Read one message. If message is malformed or can't be read, end the scanner */ |
922 | { | 922 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, &reason, sizeof (reason)); |
923 | rd = GNUNET_DISK_file_read (ds->progress_read, | 923 | while (rd > 0 && total_read < sizeof (reason)) |
924 | &((char *) &reason)[total_read], | 924 | { |
925 | sizeof (reason) - total_read); | 925 | rd = GNUNET_DISK_file_read (ds->progress_read, |
926 | if (rd > 0) | 926 | &((char *) &reason)[total_read], |
927 | total_read += rd; | 927 | sizeof (reason) - total_read); |
928 | } | 928 | if (rd > 0) |
929 | if (total_read != sizeof (reason) | 929 | total_read += rd; |
930 | || reason <= GNUNET_DIR_SCANNER_FIRST | 930 | } |
931 | || reason >= GNUNET_DIR_SCANNER_LAST) | 931 | if (total_read != sizeof (reason) |
932 | { | 932 | || reason <= GNUNET_DIR_SCANNER_FIRST |
933 | end_it = 1; | 933 | || reason >= GNUNET_DIR_SCANNER_LAST) |
934 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; | 934 | { |
935 | } | 935 | end_it = 1; |
936 | 936 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; | |
937 | if (!end_it) | 937 | } |
938 | { | 938 | |
939 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, &filename_len, | 939 | if (!end_it) |
940 | sizeof (size_t)); | 940 | { |
941 | while (rd > 0 && total_read < sizeof (size_t)) | 941 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, &filename_len, |
942 | { | 942 | sizeof (size_t)); |
943 | rd = GNUNET_DISK_file_read (ds->progress_read, | 943 | while (rd > 0 && total_read < sizeof (size_t)) |
944 | &((char *) &filename_len)[total_read], | 944 | { |
945 | sizeof (size_t) - total_read); | 945 | rd = GNUNET_DISK_file_read (ds->progress_read, |
946 | if (rd > 0) | 946 | &((char *) &filename_len)[total_read], |
947 | total_read += rd; | 947 | sizeof (size_t) - total_read); |
948 | } | 948 | if (rd > 0) |
949 | if (rd != sizeof (size_t)) | 949 | total_read += rd; |
950 | { | 950 | } |
951 | end_it = 1; | 951 | if (rd != sizeof (size_t)) |
952 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; | 952 | { |
953 | } | 953 | end_it = 1; |
954 | } | 954 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; |
955 | if (!end_it) | 955 | } |
956 | { | 956 | } |
957 | if (filename_len == 0) | 957 | if (!end_it) |
958 | end_it = 1; | 958 | { |
959 | else if (filename_len > MAX_PATH) | 959 | if (filename_len == 0) |
960 | { | 960 | end_it = 1; |
961 | end_it = 1; | 961 | else if (filename_len > PATH_MAX) |
962 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; | 962 | { |
963 | } | 963 | end_it = 1; |
964 | } | 964 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; |
965 | if (!end_it) | 965 | } |
966 | { | 966 | } |
967 | filename = GNUNET_malloc (filename_len); | 967 | if (!end_it) |
968 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, filename, | 968 | { |
969 | filename_len); | 969 | filename = GNUNET_malloc (filename_len); |
970 | while (rd > 0 && total_read < filename_len) | 970 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, filename, |
971 | { | 971 | filename_len); |
972 | rd = GNUNET_DISK_file_read (ds->progress_read, &filename[total_read], | 972 | while (rd > 0 && total_read < filename_len) |
973 | filename_len - total_read); | 973 | { |
974 | if (rd > 0) | 974 | rd = GNUNET_DISK_file_read (ds->progress_read, &filename[total_read], |
975 | total_read += rd; | 975 | filename_len - total_read); |
976 | } | 976 | if (rd > 0) |
977 | if (rd != filename_len) | 977 | total_read += rd; |
978 | { | 978 | } |
979 | GNUNET_free (filename); | 979 | if (rd != filename_len) |
980 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; | 980 | { |
981 | end_it = 1; | 981 | GNUNET_free (filename); |
982 | } | 982 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; |
983 | } | 983 | end_it = 1; |
984 | if (!end_it && filename_len > 0) | 984 | } |
985 | { | 985 | } |
986 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, &is_directory, | 986 | if (!end_it && filename_len > 0) |
987 | sizeof (char)); | 987 | { |
988 | while (rd > 0 && total_read < sizeof (char)) | 988 | total_read = rd = GNUNET_DISK_file_read (ds->progress_read, &is_directory, |
989 | { | 989 | sizeof (char)); |
990 | rd = GNUNET_DISK_file_read (ds->progress_read, &(&is_directory)[total_read], | 990 | while (rd > 0 && total_read < sizeof (char)) |
991 | sizeof (char) - total_read); | 991 | { |
992 | if (rd > 0) | 992 | rd = GNUNET_DISK_file_read (ds->progress_read, &(&is_directory)[total_read], |
993 | total_read += rd; | 993 | sizeof (char) - total_read); |
994 | } | 994 | if (rd > 0) |
995 | if (rd != sizeof (char)) | 995 | total_read += rd; |
996 | { | 996 | } |
997 | GNUNET_free (filename); | 997 | if (rd != sizeof (char)) |
998 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; | 998 | { |
999 | end_it = 1; | 999 | GNUNET_free (filename); |
1000 | } | 1000 | reason = GNUNET_DIR_SCANNER_PROTOCOL_ERROR; |
1001 | } | 1001 | end_it = 1; |
1002 | if (!end_it) | 1002 | } |
1003 | { | 1003 | } |
1004 | end_it = ds->progress_callback (ds->cls, ds, (const char *) filename, is_directory, reason); | 1004 | if (!end_it) |
1005 | GNUNET_free (filename); | 1005 | { |
1006 | if (!end_it) | 1006 | end_it = ds->progress_callback (ds->cls, ds, (const char *) filename, is_directory, reason); |
1007 | { | 1007 | GNUNET_free (filename); |
1008 | ds->progress_read_task = GNUNET_SCHEDULER_add_read_file ( | 1008 | if (!end_it) |
1009 | GNUNET_TIME_UNIT_FOREVER_REL, ds->progress_read, &read_progress_task, | 1009 | { |
1010 | cls); | 1010 | ds->progress_read_task = GNUNET_SCHEDULER_add_read_file ( |
1011 | } | 1011 | GNUNET_TIME_UNIT_FOREVER_REL, ds->progress_read, &read_progress_task, |
1012 | } | 1012 | cls); |
1013 | else | 1013 | } |
1014 | { | 1014 | } |
1015 | ds->progress_callback (ds->cls, ds, NULL, 0, reason); | 1015 | else |
1016 | } | 1016 | { |
1017 | } | 1017 | ds->progress_callback (ds->cls, ds, NULL, 0, reason); |
1018 | 1018 | } | |
1019 | 1019 | } | |
1020 | /** | 1020 | |
1021 | * Start a directory scanner thread. | 1021 | |
1022 | * | 1022 | /** |
1023 | * @param filename name of the directory to scan | 1023 | * Start a directory scanner thread. |
1024 | * @param GNUNET_YES to not to run libextractor on files (only build a tree) | 1024 | * |
1025 | * @param ex if not NULL, must be a list of extra plugins for extractor | 1025 | * @param filename name of the directory to scan |
1026 | * @param cb the callback to call when there are scanning progress messages | 1026 | * @param GNUNET_YES to not to run libextractor on files (only build a tree) |
1027 | * @param cls closure for 'cb' | 1027 | * @param ex if not NULL, must be a list of extra plugins for extractor |
1028 | * @return directory scanner object to be used for controlling the scanner | 1028 | * @param cb the callback to call when there are scanning progress messages |
1029 | */ | 1029 | * @param cls closure for 'cb' |
1030 | struct GNUNET_FS_DirScanner * | 1030 | * @return directory scanner object to be used for controlling the scanner |
1031 | GNUNET_FS_directory_scan_start (const char *filename, | 1031 | */ |
1032 | int disable_extractor, const char *ex, | 1032 | struct GNUNET_FS_DirScanner * |
1033 | GNUNET_FS_DirScannerProgressCallback cb, void *cls) | 1033 | GNUNET_FS_directory_scan_start (const char *filename, |
1034 | { | 1034 | int disable_extractor, const char *ex, |
1035 | struct stat sbuf; | 1035 | GNUNET_FS_DirScannerProgressCallback cb, void *cls) |
1036 | struct AddDirContext *adc; | 1036 | { |
1037 | char *filename_expanded; | 1037 | struct stat sbuf; |
1038 | struct GNUNET_FS_DirScanner *ds; | 1038 | struct AddDirContext *adc; |
1039 | struct GNUNET_DISK_PipeHandle *progress_pipe; | 1039 | char *filename_expanded; |
1040 | int ok; | 1040 | struct GNUNET_FS_DirScanner *ds; |
1041 | 1041 | struct GNUNET_DISK_PipeHandle *progress_pipe; | |
1042 | if (0 != STAT (filename, &sbuf)) | 1042 | int ok; |
1043 | return NULL; | 1043 | |
1044 | /* TODO: consider generalizing this for files too! */ | 1044 | if (0 != STAT (filename, &sbuf)) |
1045 | if (!S_ISDIR (sbuf.st_mode)) | 1045 | return NULL; |
1046 | { | 1046 | /* TODO: consider generalizing this for files too! */ |
1047 | GNUNET_break (0); | 1047 | if (!S_ISDIR (sbuf.st_mode)) |
1048 | return NULL; | 1048 | { |
1049 | } | 1049 | GNUNET_break (0); |
1050 | /* scan_directory() is guaranteed to be given expanded filenames, | 1050 | return NULL; |
1051 | * so expand we will! | 1051 | } |
1052 | */ | 1052 | /* scan_directory() is guaranteed to be given expanded filenames, |
1053 | filename_expanded = GNUNET_STRINGS_filename_expand (filename); | 1053 | * so expand we will! |
1054 | if (filename_expanded == NULL) | 1054 | */ |
1055 | return NULL; | 1055 | filename_expanded = GNUNET_STRINGS_filename_expand (filename); |
1056 | 1056 | if (filename_expanded == NULL) | |
1057 | progress_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); | 1057 | return NULL; |
1058 | if (progress_pipe == NULL) | 1058 | |
1059 | { | 1059 | progress_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); |
1060 | GNUNET_free (filename_expanded); | 1060 | if (progress_pipe == NULL) |
1061 | return NULL; | 1061 | { |
1062 | } | 1062 | GNUNET_free (filename_expanded); |
1063 | 1063 | return NULL; | |
1064 | adc = GNUNET_malloc (sizeof (struct AddDirContext)); | 1064 | } |
1065 | 1065 | ||
1066 | ds = GNUNET_malloc (sizeof (struct GNUNET_FS_DirScanner)); | 1066 | adc = GNUNET_malloc (sizeof (struct AddDirContext)); |
1067 | 1067 | ||
1068 | ds->adc = adc; | 1068 | ds = GNUNET_malloc (sizeof (struct GNUNET_FS_DirScanner)); |
1069 | 1069 | ||
1070 | ds->stop_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); | 1070 | ds->adc = adc; |
1071 | if (ds->stop_pipe == NULL) | 1071 | |
1072 | { | 1072 | ds->stop_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); |
1073 | GNUNET_free (adc); | 1073 | if (ds->stop_pipe == NULL) |
1074 | GNUNET_free (ds); | 1074 | { |
1075 | GNUNET_free (filename_expanded); | 1075 | GNUNET_free (adc); |
1076 | GNUNET_DISK_pipe_close (progress_pipe); | 1076 | GNUNET_free (ds); |
1077 | return NULL; | 1077 | GNUNET_free (filename_expanded); |
1078 | } | 1078 | GNUNET_DISK_pipe_close (progress_pipe); |
1079 | ds->stop_write = GNUNET_DISK_pipe_handle (ds->stop_pipe, | 1079 | return NULL; |
1080 | GNUNET_DISK_PIPE_END_WRITE); | 1080 | } |
1081 | adc->stop_read = GNUNET_DISK_pipe_handle (ds->stop_pipe, | 1081 | ds->stop_write = GNUNET_DISK_pipe_handle (ds->stop_pipe, |
1082 | GNUNET_DISK_PIPE_END_READ); | 1082 | GNUNET_DISK_PIPE_END_WRITE); |
1083 | 1083 | adc->stop_read = GNUNET_DISK_pipe_handle (ds->stop_pipe, | |
1084 | adc->plugins = NULL; | 1084 | GNUNET_DISK_PIPE_END_READ); |
1085 | if (!disable_extractor) | 1085 | |
1086 | { | 1086 | adc->plugins = NULL; |
1087 | adc->plugins = EXTRACTOR_plugin_add_defaults ( | 1087 | if (!disable_extractor) |
1088 | EXTRACTOR_OPTION_DEFAULT_POLICY); | 1088 | { |
1089 | if (ex && strlen (ex) > 0) | 1089 | adc->plugins = EXTRACTOR_plugin_add_defaults ( |
1090 | adc->plugins = EXTRACTOR_plugin_add_config (adc->plugins, ex, | 1090 | EXTRACTOR_OPTION_DEFAULT_POLICY); |
1091 | EXTRACTOR_OPTION_DEFAULT_POLICY); | 1091 | if (ex && strlen (ex) > 0) |
1092 | } | 1092 | adc->plugins = EXTRACTOR_plugin_add_config (adc->plugins, ex, |
1093 | 1093 | EXTRACTOR_OPTION_DEFAULT_POLICY); | |
1094 | adc->filename_expanded = filename_expanded; | 1094 | } |
1095 | adc->progress_write = GNUNET_DISK_pipe_handle (progress_pipe, | 1095 | |
1096 | GNUNET_DISK_PIPE_END_WRITE); | 1096 | adc->filename_expanded = filename_expanded; |
1097 | 1097 | adc->progress_write = GNUNET_DISK_pipe_handle (progress_pipe, | |
1098 | 1098 | GNUNET_DISK_PIPE_END_WRITE); | |
1099 | ds->progress_read = GNUNET_DISK_pipe_handle (progress_pipe, | 1099 | |
1100 | GNUNET_DISK_PIPE_END_READ); | 1100 | |
1101 | 1101 | ds->progress_read = GNUNET_DISK_pipe_handle (progress_pipe, | |
1102 | #if WINDOWS | 1102 | GNUNET_DISK_PIPE_END_READ); |
1103 | ds->thread = CreateThread (NULL, 0, | 1103 | |
1104 | (LPTHREAD_START_ROUTINE) &run_directory_scan_thread, (LPVOID) adc, | 1104 | #if WINDOWS |
1105 | 0, NULL); | 1105 | ds->thread = CreateThread (NULL, 0, |
1106 | ok = ds->thread != NULL; | 1106 | (LPTHREAD_START_ROUTINE) &run_directory_scan_thread, (LPVOID) adc, |
1107 | #else | 1107 | 0, NULL); |
1108 | ok = !pthread_create (&ds->thread, NULL, &run_directory_scan_thread, | 1108 | ok = ds->thread != NULL; |
1109 | (void *) adc); | 1109 | #else |
1110 | #endif | 1110 | ok = !pthread_create (&ds->thread, NULL, &run_directory_scan_thread, |
1111 | if (!ok) | 1111 | (void *) adc); |
1112 | { | 1112 | #endif |
1113 | GNUNET_free (adc); | 1113 | if (!ok) |
1114 | GNUNET_free (filename_expanded); | 1114 | { |
1115 | GNUNET_DISK_pipe_close (progress_pipe); | 1115 | GNUNET_free (adc); |
1116 | GNUNET_free (ds); | 1116 | GNUNET_free (filename_expanded); |
1117 | return NULL; | 1117 | GNUNET_DISK_pipe_close (progress_pipe); |
1118 | } | 1118 | GNUNET_free (ds); |
1119 | 1119 | return NULL; | |
1120 | ds->progress_callback = cb; | 1120 | } |
1121 | ds->cls = cls; | 1121 | |
1122 | ds->adc = adc; | 1122 | ds->progress_callback = cb; |
1123 | ds->progress_pipe = progress_pipe; | 1123 | ds->cls = cls; |
1124 | 1124 | ds->adc = adc; | |
1125 | ds->progress_read_task = GNUNET_SCHEDULER_add_read_file ( | 1125 | ds->progress_pipe = progress_pipe; |
1126 | GNUNET_TIME_UNIT_FOREVER_REL, ds->progress_read, &read_progress_task, | 1126 | |
1127 | ds); | 1127 | ds->progress_read_task = GNUNET_SCHEDULER_add_read_file ( |
1128 | 1128 | GNUNET_TIME_UNIT_FOREVER_REL, ds->progress_read, &read_progress_task, | |
1129 | return ds; | 1129 | ds); |
1130 | } | 1130 | |
1131 | 1131 | return ds; | |
1132 | /** | 1132 | } |
1133 | * Task that post-processes the share item tree. | 1133 | |
1134 | * This processing has to be done in the main thread, because | 1134 | /** |
1135 | * it requires access to libgcrypt's hashing functions, and | 1135 | * Task that post-processes the share item tree. |
1136 | * libgcrypt is not thread-safe without some special magic. | 1136 | * This processing has to be done in the main thread, because |
1137 | * | 1137 | * it requires access to libgcrypt's hashing functions, and |
1138 | * @param cls top of the stack | 1138 | * libgcrypt is not thread-safe without some special magic. |
1139 | * @param tc task context | 1139 | * |
1140 | */ | 1140 | * @param cls top of the stack |
1141 | static void | 1141 | * @param tc task context |
1142 | trim_share_tree_task (void *cls, | 1142 | */ |
1143 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 1143 | static void |
1144 | { | 1144 | trim_share_tree_task (void *cls, |
1145 | struct ProcessMetadataStackItem *stack = cls; | 1145 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
1146 | struct ProcessMetadataStackItem *next = stack; | 1146 | { |
1147 | /* FIXME: figure out what to do when tc says we're shutting down */ | 1147 | struct ProcessMetadataStackItem *stack = cls; |
1148 | 1148 | struct ProcessMetadataStackItem *next = stack; | |
1149 | /* item == NULL means that we've just finished going over the children of | 1149 | /* FIXME: figure out what to do when tc says we're shutting down */ |
1150 | * current directory. | 1150 | |
1151 | */ | 1151 | /* item == NULL means that we've just finished going over the children of |
1152 | if (stack->item == NULL) | 1152 | * current directory. |
1153 | { | 1153 | */ |
1154 | if (stack->parent->item != NULL) | 1154 | if (stack->item == NULL) |
1155 | { | 1155 | { |
1156 | /* end of a directory */ | 1156 | if (stack->parent->item != NULL) |
1157 | struct GNUNET_FS_Uri *ksk; | 1157 | { |
1158 | 1158 | /* end of a directory */ | |
1159 | /* use keyword and metadata counters to create lists of keywords to move | 1159 | struct GNUNET_FS_Uri *ksk; |
1160 | * and metadata to copy. | 1160 | |
1161 | */ | 1161 | /* use keyword and metadata counters to create lists of keywords to move |
1162 | process_keywords_and_metadata (stack, &stack->parent->exclude_ksk, &stack->parent->item->meta); | 1162 | * and metadata to copy. |
1163 | 1163 | */ | |
1164 | /* create keywords from metadata (copies all text-metadata as keywords, | 1164 | process_keywords_and_metadata (stack, &stack->parent->exclude_ksk, &stack->parent->item->meta); |
1165 | * AND parses the directory name we've just added, producing even more | 1165 | |
1166 | * keywords. | 1166 | /* create keywords from metadata (copies all text-metadata as keywords, |
1167 | * then merge these keywords with the ones moved from children. | 1167 | * AND parses the directory name we've just added, producing even more |
1168 | */ | 1168 | * keywords. |
1169 | ksk = GNUNET_FS_uri_ksk_create_from_meta_data (stack->parent->item->meta); | 1169 | * then merge these keywords with the ones moved from children. |
1170 | stack->parent->item->ksk_uri = GNUNET_FS_uri_ksk_merge (ksk, stack->parent->exclude_ksk); | 1170 | */ |
1171 | GNUNET_FS_uri_destroy (ksk); | 1171 | ksk = GNUNET_FS_uri_ksk_create_from_meta_data (stack->parent->item->meta); |
1172 | 1172 | stack->parent->item->ksk_uri = GNUNET_FS_uri_ksk_merge (ksk, stack->parent->exclude_ksk); | |
1173 | /* remove moved keywords from children (complete the move) */ | 1173 | GNUNET_FS_uri_destroy (ksk); |
1174 | remove_keywords (stack->parent, stack->parent->item); | 1174 | |
1175 | GNUNET_FS_uri_destroy (stack->parent->exclude_ksk); | 1175 | /* remove moved keywords from children (complete the move) */ |
1176 | 1176 | remove_keywords (stack->parent, stack->parent->item); | |
1177 | /* go up the stack */ | 1177 | GNUNET_FS_uri_destroy (stack->parent->exclude_ksk); |
1178 | next = stack->parent; | 1178 | |
1179 | GNUNET_free (stack); | 1179 | /* go up the stack */ |
1180 | next->end_directory = GNUNET_YES; | 1180 | next = stack->parent; |
1181 | } | 1181 | GNUNET_free (stack); |
1182 | else | 1182 | next->end_directory = GNUNET_YES; |
1183 | { | 1183 | } |
1184 | /* we've just finished processing the toplevel directory */ | 1184 | else |
1185 | struct ProcessMetadataContext *ctx = stack->ctx; | 1185 | { |
1186 | next = NULL; | 1186 | /* we've just finished processing the toplevel directory */ |
1187 | GNUNET_SCHEDULER_add_continuation (ctx->cb, ctx->cls, | 1187 | struct GNUNET_FS_ProcessMetadataContext *ctx = stack->ctx; |
1188 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | 1188 | next = NULL; |
1189 | GNUNET_free (stack->parent); | 1189 | GNUNET_SCHEDULER_add_continuation (ctx->cb, ctx->cls, |
1190 | GNUNET_free (stack); | 1190 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); |
1191 | GNUNET_free (ctx); | 1191 | GNUNET_free (stack->parent); |
1192 | } | 1192 | GNUNET_free (stack); |
1193 | } | 1193 | GNUNET_free (ctx); |
1194 | else if (stack->item->is_directory | 1194 | } |
1195 | && !stack->end_directory | 1195 | } |
1196 | && stack->item->children_head != NULL) | 1196 | else if (stack->item->is_directory |
1197 | { | 1197 | && !stack->end_directory |
1198 | /* recurse into subdirectory */ | 1198 | && stack->item->children_head != NULL) |
1199 | next = GNUNET_malloc (sizeof (struct ProcessMetadataStackItem)); | 1199 | { |
1200 | next->ctx = stack->ctx; | 1200 | /* recurse into subdirectory */ |
1201 | next->item = stack->item->children_head; | 1201 | next = GNUNET_malloc (sizeof (struct ProcessMetadataStackItem)); |
1202 | next->keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); | 1202 | next->ctx = stack->ctx; |
1203 | next->metacounter = GNUNET_CONTAINER_multihashmap_create (1024); | 1203 | next->item = stack->item->children_head; |
1204 | next->dir_entry_count = 0; | 1204 | next->keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); |
1205 | next->parent = stack; | 1205 | next->metacounter = GNUNET_CONTAINER_multihashmap_create (1024); |
1206 | } | 1206 | next->dir_entry_count = 0; |
1207 | else | 1207 | next->parent = stack; |
1208 | { | 1208 | } |
1209 | /* process a child entry (a file or a directory) and move to the next one*/ | 1209 | else |
1210 | if (stack->item->is_directory) | 1210 | { |
1211 | stack->end_directory = GNUNET_NO; | 1211 | /* process a child entry (a file or a directory) and move to the next one*/ |
1212 | stack->dir_entry_count++; | 1212 | if (stack->item->is_directory) |
1213 | GNUNET_CONTAINER_meta_data_iterate (stack->item->meta, &add_to_meta_counter, stack->metacounter); | 1213 | stack->end_directory = GNUNET_NO; |
1214 | 1214 | stack->dir_entry_count++; | |
1215 | if (stack->item->is_directory) | 1215 | GNUNET_CONTAINER_meta_data_iterate (stack->item->meta, &add_to_meta_counter, stack->metacounter); |
1216 | { | 1216 | |
1217 | char *user = getenv ("USER"); | 1217 | if (stack->item->is_directory) |
1218 | if ((user == NULL) || (0 != strncasecmp (user, stack->item->short_filename, strlen(user)))) | 1218 | { |
1219 | { | 1219 | char *user = getenv ("USER"); |
1220 | /* only use filename if it doesn't match $USER */ | 1220 | if ((user == NULL) || (0 != strncasecmp (user, stack->item->short_filename, strlen(user)))) |
1221 | GNUNET_CONTAINER_meta_data_insert (stack->item->meta, "<libgnunetfs>", | 1221 | { |
1222 | EXTRACTOR_METATYPE_FILENAME, | 1222 | /* only use filename if it doesn't match $USER */ |
1223 | EXTRACTOR_METAFORMAT_UTF8, | 1223 | GNUNET_CONTAINER_meta_data_insert (stack->item->meta, "<libgnunetfs>", |
1224 | "text/plain", stack->item->short_filename, | 1224 | EXTRACTOR_METATYPE_FILENAME, |
1225 | strlen (stack->item->short_filename) + 1); | 1225 | EXTRACTOR_METAFORMAT_UTF8, |
1226 | GNUNET_CONTAINER_meta_data_insert (stack->item->meta, "<libgnunetfs>", | 1226 | "text/plain", stack->item->short_filename, |
1227 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | 1227 | strlen (stack->item->short_filename) + 1); |
1228 | EXTRACTOR_METAFORMAT_UTF8, | 1228 | GNUNET_CONTAINER_meta_data_insert (stack->item->meta, "<libgnunetfs>", |
1229 | "text/plain", stack->item->short_filename, | 1229 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, |
1230 | strlen (stack->item->short_filename) + 1); | 1230 | EXTRACTOR_METAFORMAT_UTF8, |
1231 | } | 1231 | "text/plain", stack->item->short_filename, |
1232 | } | 1232 | strlen (stack->item->short_filename) + 1); |
1233 | 1233 | } | |
1234 | stack->item->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (stack->item->meta); | 1234 | } |
1235 | GNUNET_FS_uri_ksk_get_keywords (stack->item->ksk_uri, &add_to_keyword_counter, stack->keywordcounter); | 1235 | |
1236 | stack->item = stack->item->next; | 1236 | stack->item->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (stack->item->meta); |
1237 | } | 1237 | GNUNET_FS_uri_ksk_get_keywords (stack->item->ksk_uri, &add_to_keyword_counter, stack->keywordcounter); |
1238 | /* Call this task again later, if there are more entries to process */ | 1238 | stack->item = stack->item->next; |
1239 | if (next) | 1239 | } |
1240 | GNUNET_SCHEDULER_add_continuation (&trim_share_tree_task, next, | 1240 | /* Call this task again later, if there are more entries to process */ |
1241 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | 1241 | if (next) |
1242 | } | 1242 | GNUNET_SCHEDULER_add_continuation (&trim_share_tree_task, next, |
1243 | 1243 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | |
1244 | /** | 1244 | } |
1245 | * Process a share item tree, moving frequent keywords up and | 1245 | |
1246 | * copying frequent metadata up. | 1246 | /** |
1247 | * | 1247 | * Process a share item tree, moving frequent keywords up and |
1248 | * @param toplevel toplevel directory in the tree, returned by the scanner | 1248 | * copying frequent metadata up. |
1249 | * @param cb called after processing is done | 1249 | * |
1250 | * @param cls closure for 'cb' | 1250 | * @param toplevel toplevel directory in the tree, returned by the scanner |
1251 | */ | 1251 | * @param cb called after processing is done |
1252 | struct ProcessMetadataContext * | 1252 | * @param cls closure for 'cb' |
1253 | GNUNET_FS_trim_share_tree (struct ShareTreeItem *toplevel, | 1253 | */ |
1254 | GNUNET_SCHEDULER_Task cb, void *cls) | 1254 | struct GNUNET_FS_ProcessMetadataContext * |
1255 | { | 1255 | GNUNET_FS_trim_share_tree (struct GNUNET_FS_ShareTreeItem *toplevel, |
1256 | struct ProcessMetadataContext *ret; | 1256 | GNUNET_SCHEDULER_Task cb, void *cls) |
1257 | 1257 | { | |
1258 | if (toplevel == NULL) | 1258 | struct GNUNET_FS_ProcessMetadataContext *ret; |
1259 | { | 1259 | |
1260 | struct GNUNET_SCHEDULER_TaskContext tc; | 1260 | if (toplevel == NULL) |
1261 | tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE; | 1261 | { |
1262 | cb (cls, &tc); | 1262 | struct GNUNET_SCHEDULER_TaskContext tc; |
1263 | return NULL; | 1263 | tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE; |
1264 | } | 1264 | cb (cls, &tc); |
1265 | 1265 | return NULL; | |
1266 | ret = GNUNET_malloc (sizeof (struct ProcessMetadataContext)); | 1266 | } |
1267 | ret->toplevel = toplevel; | 1267 | |
1268 | ret->stack = GNUNET_malloc (sizeof (struct ProcessMetadataStackItem)); | 1268 | ret = GNUNET_malloc (sizeof (struct GNUNET_FS_ProcessMetadataContext)); |
1269 | ret->stack->ctx = ret; | 1269 | ret->toplevel = toplevel; |
1270 | ret->stack->item = toplevel; | 1270 | ret->stack = GNUNET_malloc (sizeof (struct ProcessMetadataStackItem)); |
1271 | ret->stack->keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); | 1271 | ret->stack->ctx = ret; |
1272 | ret->stack->metacounter = GNUNET_CONTAINER_multihashmap_create (1024); | 1272 | ret->stack->item = toplevel; |
1273 | ret->stack->dir_entry_count = 0; | 1273 | ret->stack->keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); |
1274 | ret->stack->end_directory = GNUNET_NO; | 1274 | ret->stack->metacounter = GNUNET_CONTAINER_multihashmap_create (1024); |
1275 | 1275 | ret->stack->dir_entry_count = 0; | |
1276 | /* dummy stack entry that tells us we're at the top of the stack */ | 1276 | ret->stack->end_directory = GNUNET_NO; |
1277 | ret->stack->parent = GNUNET_malloc (sizeof (struct ProcessMetadataStackItem)); | 1277 | |
1278 | ret->stack->parent->ctx = ret; | 1278 | /* dummy stack entry that tells us we're at the top of the stack */ |
1279 | 1279 | ret->stack->parent = GNUNET_malloc (sizeof (struct ProcessMetadataStackItem)); | |
1280 | ret->cb = cb; | 1280 | ret->stack->parent->ctx = ret; |
1281 | ret->cls = cls; | 1281 | |
1282 | 1282 | ret->cb = cb; | |
1283 | GNUNET_SCHEDULER_add_continuation (&trim_share_tree_task, ret->stack, | 1283 | ret->cls = cls; |
1284 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | 1284 | |
1285 | return ret; | 1285 | GNUNET_SCHEDULER_add_continuation (&trim_share_tree_task, ret->stack, |
1286 | } \ No newline at end of file | 1286 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); |
1287 | return ret; | ||
1288 | } | ||