aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-helper-fs-publish.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-29 20:21:09 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-29 20:21:09 +0000
commit6f912718b1e65181e9e3a62c6c7b8cf32f7d1165 (patch)
treee9165b2ca830301b04774410956c37739a98ef83 /src/fs/gnunet-helper-fs-publish.c
parent4419d11120f7cdb592e612993ef1e1df2d023e8e (diff)
downloadgnunet-6f912718b1e65181e9e3a62c6c7b8cf32f7d1165.tar.gz
gnunet-6f912718b1e65181e9e3a62c6c7b8cf32f7d1165.zip
-finishing new helper
Diffstat (limited to 'src/fs/gnunet-helper-fs-publish.c')
-rw-r--r--src/fs/gnunet-helper-fs-publish.c298
1 files changed, 177 insertions, 121 deletions
diff --git a/src/fs/gnunet-helper-fs-publish.c b/src/fs/gnunet-helper-fs-publish.c
index 5edc2ec36..21ec19fe9 100644
--- a/src/fs/gnunet-helper-fs-publish.c
+++ b/src/fs/gnunet-helper-fs-publish.c
@@ -29,24 +29,94 @@
29#include "platform.h" 29#include "platform.h"
30#include "gnunet_fs_service.h" 30#include "gnunet_fs_service.h"
31 31
32
33/**
34 * A node of a directory tree.
35 */
36struct ScanTreeNode
37{
38
39 /**
40 * This is a doubly-linked list
41 */
42 struct ScanTreeNode *next;
43
44 /**
45 * This is a doubly-linked list
46 */
47 struct ScanTreeNode *prev;
48
49 /**
50 * Parent of this node, NULL for top-level entries.
51 */
52 struct ScanTreeNode *parent;
53
54 /**
55 * This is a doubly-linked tree
56 * NULL for files and empty directories
57 */
58 struct ScanTreeNode *children_head;
59
60 /**
61 * This is a doubly-linked tree
62 * NULL for files and empty directories
63 */
64 struct ScanTreeNode *children_tail;
65
66 /**
67 * Name of the file/directory
68 */
69 char *filename;
70
71 /**
72 * Size of the file (if it is a file), in bytes
73 */
74 uint64_t file_size;
75
76 /**
77 * GNUNET_YES if this is a directory
78 */
79 int is_directory;
80
81};
82
83
32/** 84/**
33 * List of libextractor plugins to use for extracting. 85 * List of libextractor plugins to use for extracting.
34 */ 86 */
35static struct EXTRACTOR_PluginList *plugins; 87static struct EXTRACTOR_PluginList *plugins;
36 88
37 89
38#if 0 90/**
91 * Free memory of the 'tree' structure
92 *
93 * @param tree tree to free
94 */
95static void
96free_tree (struct ScanTreeNode *tree)
97{
98 struct ScanTreeNode *pos;
99
100 while (NULL != (pos = tree->children_head))
101 free_tree (pos);
102 if (NULL != tree->parent)
103 GNUNET_CONTAINER_DLL_remove (tree->parent->children_head,
104 tree->parent->children_tail,
105 tree);
106 GNUNET_free (tree->filename);
107 GNUNET_free (tree);
108}
109
110
39/** 111/**
40 * Write 'size' bytes from 'buf' into 'out'. 112 * Write 'size' bytes from 'buf' into 'out'.
41 * 113 *
42 * @param in pipe to write to
43 * @param buf buffer with data to write 114 * @param buf buffer with data to write
44 * @param size number of bytes to write 115 * @param size number of bytes to write
45 * @return GNUNET_OK on success, GNUNET_SYSERR on error 116 * @return GNUNET_OK on success, GNUNET_SYSERR on error
46 */ 117 */
47static int 118static int
48write_all (const struct GNUNET_DISK_FileHandle *out, 119write_all (const void *buf,
49 const void *buf,
50 size_t size) 120 size_t size)
51{ 121{
52 const char *cbuf = buf; 122 const char *cbuf = buf;
@@ -56,54 +126,43 @@ write_all (const struct GNUNET_DISK_FileHandle *out,
56 total = 0; 126 total = 0;
57 do 127 do
58 { 128 {
59 wr = GNUNET_DISK_file_write (out, 129 wr = write (1,
60 &cbuf[total], 130 &cbuf[total],
61 size - total); 131 size - total);
62 if (wr > 0) 132 if (wr > 0)
63 total += wr; 133 total += wr;
64 } while ( (wr > 0) && (total < size) ); 134 } while ( (wr > 0) && (total < size) );
65 if (wr <= 0) 135 if (wr <= 0)
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Failed to write to inter thread communication pipe: %s\n", 137 "Failed to write to stdout: %s\n",
68 strerror (errno)); 138 strerror (errno));
69 return (total == size) ? GNUNET_OK : GNUNET_SYSERR; 139 return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
70} 140}
71 141
72 142
73/** 143/**
74 * Write progress message. 144 * Write message to the master process.
75 * 145 *
76 * @param ds 146 * @param message_type message type to use
77 * @param filename name of the file to transmit, never NULL 147 * @param data data to append, NULL for none
78 * @param is_directory GNUNET_YES for directory, GNUNET_NO for file, GNUNET_SYSERR for neither 148 * @param data_length number of bytes in data
79 * @param reason reason for the progress call
80 * @return GNUNET_SYSERR to stop scanning (the pipe was broken somehow) 149 * @return GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
81 */ 150 */
82static int 151static int
83write_progress (struct GNUNET_FS_DirScanner *ds, 152write_message (uint16_t message_type,
84 const char *filename, 153 const char *data,
85 int is_directory, 154 size_t data_length)
86 enum GNUNET_FS_DirScannerProgressUpdateReason reason)
87{ 155{
88 size_t slen; 156 struct GNUNET_MessageHeader hdr;
89 157
90 slen = strlen (filename) + 1; 158 hdr.type = htons (message_type);
159 hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length);
91 if ( (GNUNET_OK != 160 if ( (GNUNET_OK !=
92 write_all (ds->progress_write, 161 write_all (&hdr,
93 &reason, 162 sizeof (hdr))) ||
94 sizeof (reason))) ||
95 (GNUNET_OK !=
96 write_all (ds->progress_write,
97 &slen,
98 sizeof (slen))) ||
99 (GNUNET_OK !=
100 write_all (ds->progress_write,
101 filename,
102 slen)) ||
103 (GNUNET_OK != 163 (GNUNET_OK !=
104 write_all (ds->progress_write, 164 write_all (data,
105 &is_directory, 165 data_length)) )
106 sizeof (is_directory))) )
107 return GNUNET_SYSERR; 166 return GNUNET_SYSERR;
108 return GNUNET_OK; 167 return GNUNET_OK;
109} 168}
@@ -114,15 +173,13 @@ write_progress (struct GNUNET_FS_DirScanner *ds,
114 * directory to the tree. Called by the directory scanner to initiate 173 * directory to the tree. Called by the directory scanner to initiate
115 * the scan. Does NOT yet add any metadata. 174 * the scan. Does NOT yet add any metadata.
116 * 175 *
117 * @param ds directory scanner context to use
118 * @param filename file or directory to scan 176 * @param filename file or directory to scan
119 * @param dst where to store the resulting share tree item 177 * @param dst where to store the resulting share tree item
120 * @return GNUNET_OK on success, GNUNET_SYSERR on error 178 * @return GNUNET_OK on success, GNUNET_SYSERR on error
121 */ 179 */
122static int 180static int
123preprocess_file (struct GNUNET_FS_DirScanner *ds, 181preprocess_file (const char *filename,
124 const char *filename, 182 struct ScanTreeNode **dst);
125 struct GNUNET_FS_ShareTreeItem **dst);
126 183
127 184
128/** 185/**
@@ -131,14 +188,9 @@ preprocess_file (struct GNUNET_FS_DirScanner *ds,
131struct RecursionContext 188struct RecursionContext
132{ 189{
133 /** 190 /**
134 * Global scanner context.
135 */
136 struct GNUNET_FS_DirScanner *ds;
137
138 /**
139 * Parent to add the files to. 191 * Parent to add the files to.
140 */ 192 */
141 struct GNUNET_FS_ShareTreeItem *parent; 193 struct ScanTreeNode *parent;
142 194
143 /** 195 /**
144 * Flag to set to GNUNET_YES on serious errors. 196 * Flag to set to GNUNET_YES on serious errors.
@@ -161,11 +213,10 @@ scan_callback (void *cls,
161 const char *filename) 213 const char *filename)
162{ 214{
163 struct RecursionContext *rc = cls; 215 struct RecursionContext *rc = cls;
164 struct GNUNET_FS_ShareTreeItem *chld; 216 struct ScanTreeNode *chld;
165 217
166 if (GNUNET_OK != 218 if (GNUNET_OK !=
167 preprocess_file (rc->ds, 219 preprocess_file (filename,
168 filename,
169 &chld)) 220 &chld))
170 { 221 {
171 rc->stop = GNUNET_YES; 222 rc->stop = GNUNET_YES;
@@ -184,17 +235,15 @@ scan_callback (void *cls,
184 * directory to the tree. Called by the directory scanner to initiate 235 * directory to the tree. Called by the directory scanner to initiate
185 * the scan. Does NOT yet add any metadata. 236 * the scan. Does NOT yet add any metadata.
186 * 237 *
187 * @param ds directory scanner context to use
188 * @param filename file or directory to scan 238 * @param filename file or directory to scan
189 * @param dst where to store the resulting share tree item 239 * @param dst where to store the resulting share tree item
190 * @return GNUNET_OK on success, GNUNET_SYSERR on error 240 * @return GNUNET_OK on success, GNUNET_SYSERR on error
191 */ 241 */
192static int 242static int
193preprocess_file (struct GNUNET_FS_DirScanner *ds, 243preprocess_file (const char *filename,
194 const char *filename, 244 struct ScanTreeNode **dst)
195 struct GNUNET_FS_ShareTreeItem **dst)
196{ 245{
197 struct GNUNET_FS_ShareTreeItem *item; 246 struct ScanTreeNode *item;
198 struct stat sbuf; 247 struct stat sbuf;
199 248
200 if (0 != STAT (filename, &sbuf)) 249 if (0 != STAT (filename, &sbuf))
@@ -202,23 +251,21 @@ preprocess_file (struct GNUNET_FS_DirScanner *ds,
202 /* If the file doesn't exist (or is not stat-able for any other reason) 251 /* If the file doesn't exist (or is not stat-able for any other reason)
203 skip it (but report it), but do continue. */ 252 skip it (but report it), but do continue. */
204 if (GNUNET_OK != 253 if (GNUNET_OK !=
205 write_progress (ds, filename, GNUNET_SYSERR, 254 write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE,
206 GNUNET_FS_DIRSCANNER_DOES_NOT_EXIST)) 255 filename, strlen (filename) + 1))
207 return GNUNET_SYSERR; 256 return GNUNET_SYSERR;
208 return GNUNET_OK; 257 return GNUNET_OK;
209 } 258 }
210 259
211 /* Report the progress */ 260 /* Report the progress */
212 if (GNUNET_OK != 261 if (GNUNET_OK !=
213 write_progress (ds, 262 write_message (S_ISDIR (sbuf.st_mode)
214 filename, 263 ? GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY
215 S_ISDIR (sbuf.st_mode) ? GNUNET_YES : GNUNET_NO, 264 : GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE,
216 GNUNET_FS_DIRSCANNER_FILE_START)) 265 filename, strlen (filename) + 1))
217 return GNUNET_SYSERR; 266 return GNUNET_SYSERR;
218 item = GNUNET_malloc (sizeof (struct GNUNET_FS_ShareTreeItem)); 267 item = GNUNET_malloc (sizeof (struct ScanTreeNode));
219 item->meta = GNUNET_CONTAINER_meta_data_create ();
220 item->filename = GNUNET_strdup (filename); 268 item->filename = GNUNET_strdup (filename);
221 item->short_filename = GNUNET_strdup (GNUNET_STRINGS_get_short_name (filename));
222 item->is_directory = (S_ISDIR (sbuf.st_mode)) ? GNUNET_YES : GNUNET_NO; 269 item->is_directory = (S_ISDIR (sbuf.st_mode)) ? GNUNET_YES : GNUNET_NO;
223 item->file_size = (uint64_t) sbuf.st_size; 270 item->file_size = (uint64_t) sbuf.st_size;
224 if (item->is_directory) 271 if (item->is_directory)
@@ -226,29 +273,16 @@ preprocess_file (struct GNUNET_FS_DirScanner *ds,
226 struct RecursionContext rc; 273 struct RecursionContext rc;
227 274
228 rc.parent = item; 275 rc.parent = item;
229 rc.ds = ds;
230 rc.stop = GNUNET_NO; 276 rc.stop = GNUNET_NO;
231 GNUNET_DISK_directory_scan (filename, 277 GNUNET_DISK_directory_scan (filename,
232 &scan_callback, 278 &scan_callback,
233 &rc); 279 &rc);
234 if ( (rc.stop == GNUNET_YES) || 280 if (rc.stop == GNUNET_YES)
235 (GNUNET_OK !=
236 test_thread_stop (ds)) )
237 { 281 {
238 GNUNET_FS_share_tree_free (item); 282 free_tree (item);
239 return GNUNET_SYSERR; 283 return GNUNET_SYSERR;
240 } 284 }
241 } 285 }
242 /* Report the progress */
243 if (GNUNET_OK !=
244 write_progress (ds,
245 filename,
246 S_ISDIR (sbuf.st_mode) ? GNUNET_YES : GNUNET_NO,
247 GNUNET_FS_DIRSCANNER_SUBTREE_COUNTED))
248 {
249 GNUNET_FS_share_tree_free (item);
250 return GNUNET_SYSERR;
251 }
252 *dst = item; 286 *dst = item;
253 return GNUNET_OK; 287 return GNUNET_OK;
254} 288}
@@ -262,67 +296,85 @@ preprocess_file (struct GNUNET_FS_DirScanner *ds,
262 * @return GNUNET_OK on success, GNUNET_SYSERR on fatal errors 296 * @return GNUNET_OK on success, GNUNET_SYSERR on fatal errors
263 */ 297 */
264static int 298static int
265extract_files (struct GNUNET_FS_DirScanner *ds, 299extract_files (struct ScanTreeNode *item)
266 struct GNUNET_FS_ShareTreeItem *item)
267{ 300{
301 struct GNUNET_CONTAINER_MetaData *meta;
302 ssize_t size;
303 size_t slen;
304
268 if (item->is_directory) 305 if (item->is_directory)
269 { 306 {
270 /* for directories, we simply only descent, no extraction, no 307 /* for directories, we simply only descent, no extraction, no
271 progress reporting */ 308 progress reporting */
272 struct GNUNET_FS_ShareTreeItem *pos; 309 struct ScanTreeNode *pos;
273 310
274 for (pos = item->children_head; NULL != pos; pos = pos->next) 311 for (pos = item->children_head; NULL != pos; pos = pos->next)
275 if (GNUNET_OK != 312 if (GNUNET_OK !=
276 extract_files (ds, pos)) 313 extract_files (pos))
277 return GNUNET_SYSERR; 314 return GNUNET_SYSERR;
278 return GNUNET_OK; 315 return GNUNET_OK;
279 } 316 }
280 317
281 /* this is the expensive operation, *afterwards* we'll check for aborts */ 318 /* this is the expensive operation, *afterwards* we'll check for aborts */
282 fprintf (stderr, "\tCalling extract on `%s'\n", item->filename); 319 meta = GNUNET_CONTAINER_meta_data_create ();
283 GNUNET_FS_meta_data_extract_from_file (item->meta, 320 GNUNET_FS_meta_data_extract_from_file (meta,
284 item->filename, 321 item->filename,
285 ds->plugins); 322 plugins);
286 fprintf (stderr, "\tExtract `%s' done\n", item->filename); 323 slen = strlen (item->filename) + 1;
287 324 size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
288 /* having full filenames is too dangerous; always make sure we clean them up */ 325 if ( (-1 == size) ||
289 GNUNET_CONTAINER_meta_data_delete (item->meta, 326 (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE - slen) )
290 EXTRACTOR_METATYPE_FILENAME, 327 {
291 NULL, 0); 328 /* no meta data */
292 GNUNET_CONTAINER_meta_data_insert (item->meta, "<libgnunetfs>", 329 GNUNET_CONTAINER_meta_data_destroy (meta);
293 EXTRACTOR_METATYPE_FILENAME, 330 if (GNUNET_OK !=
294 EXTRACTOR_METAFORMAT_UTF8, "text/plain", 331 write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA,
295 item->short_filename, 332 item->filename, slen))
296 strlen (item->short_filename) + 1); 333 return GNUNET_SYSERR;
297 /* check for abort */ 334 return GNUNET_OK;
298 if (GNUNET_OK != 335 }
299 test_thread_stop (ds)) 336 {
300 return GNUNET_SYSERR; 337 char buf[size + slen];
301 338 char *dst = buf;
302 /* Report the progress */ 339
303 if (GNUNET_OK != 340 memcpy (buf, item->filename, slen);
304 write_progress (ds, 341 size = GNUNET_CONTAINER_meta_data_serialize (meta,
305 item->filename, 342 &dst, size,
306 GNUNET_NO, 343 GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
307 GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED)) 344 GNUNET_CONTAINER_meta_data_destroy (meta);
308 return GNUNET_SYSERR; 345 if (GNUNET_OK !=
346 write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA,
347 buf,
348 slen + size))
349 return GNUNET_SYSERR;
350 }
309 return GNUNET_OK; 351 return GNUNET_OK;
310} 352}
311 353
312#endif
313
314 354
355/**
356 * Main function of the helper process to extract meta data.
357 *
358 * @param argc should be 3
359 * @param argv [0] our binary name
360 * [1] name of the file or directory to process
361 * [2] "-" to disable extraction, NULL for defaults,
362 * otherwise custom plugins to load from LE
363 * @return 0 on success
364 */
315int main(int argc, 365int main(int argc,
316 char **argv) 366 char **argv)
317{ 367{
318 const char *filename_expanded; 368 const char *filename_expanded;
319 const char *ex; 369 const char *ex;
370 struct ScanTreeNode *root;
320 371
321 if (argc < 3) 372 /* parse command line */
373 if ( (argc != 3) && (argc != 2) )
322 { 374 {
323 FPRINTF (stderr, 375 FPRINTF (stderr,
324 "%s", 376 "%s",
325 "gnunet-helper-fs-publish needs at least two arguments\n"); 377 "gnunet-helper-fs-publish needs exactly one or two arguments\n");
326 return 1; 378 return 1;
327 } 379 }
328 filename_expanded = argv[1]; 380 filename_expanded = argv[1];
@@ -335,29 +387,33 @@ int main(int argc,
335 EXTRACTOR_OPTION_DEFAULT_POLICY); 387 EXTRACTOR_OPTION_DEFAULT_POLICY);
336 } 388 }
337 389
338#if 0 390 /* scan tree to find out how much work there is to be done */
339 if (GNUNET_OK != preprocess_file (filename_expanded, 391 if (GNUNET_OK != preprocess_file (filename_expanded,
340 &toplevel)) 392 &root))
341 { 393 {
342 (void) write_progress (ds, "", GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_INTERNAL_ERROR); 394 (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0);
343 GNUNET_DISK_pipe_close_end (ds->progress_pipe, GNUNET_DISK_PIPE_END_WRITE);
344 return 2; 395 return 2;
345 } 396 }
397 /* signal that we're done counting files, so that a percentage of
398 progress can now be calculated */
346 if (GNUNET_OK != 399 if (GNUNET_OK !=
347 write_progress (ds, "", GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_ALL_COUNTED)) 400 write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE, NULL, 0))
348 { 401 return 3;
349 return 3;
350 }
351 if (GNUNET_OK != 402 if (GNUNET_OK !=
352 extract_files (ds, ds->toplevel)) 403 extract_files (root))
353 { 404 {
354 (void) write_progress (ds, "", GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_INTERNAL_ERROR); 405 (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0);
406 free_tree (root);
355 return 4; 407 return 4;
356 } 408 }
357 (void) write_progress (ds, "", GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_FINISHED); 409 free_tree (root);
358#endif 410 /* enable "clean" shutdown by telling parent that we are done */
411 (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED, NULL, 0);
359 if (NULL != plugins) 412 if (NULL != plugins)
360 EXTRACTOR_plugin_remove_all (plugins); 413 EXTRACTOR_plugin_remove_all (plugins);
361 414
362 return 0; 415 return 0;
363} 416}
417
418/* end of gnunet-helper-fs-publish.c */
419