gnunet-publish.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2001-2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file fs/gnunet-publish.c
  18. * @brief publishing files on GNUnet
  19. * @author Christian Grothoff
  20. * @author Krista Bennett
  21. * @author James Blackwell
  22. * @author Igor Wronsky
  23. */
  24. #include "platform.h"
  25. #include "gnunet_fs_service.h"
  26. #include "gnunet_identity_service.h"
  27. /**
  28. * Global return value from #main().
  29. */
  30. static int ret;
  31. /**
  32. * Command line option 'verbose' set
  33. */
  34. static unsigned int verbose;
  35. /**
  36. * Handle to our configuration.
  37. */
  38. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  39. /**
  40. * Handle for interaction with file-sharing service.
  41. */
  42. static struct GNUNET_FS_Handle *ctx;
  43. /**
  44. * Handle to FS-publishing operation.
  45. */
  46. static struct GNUNET_FS_PublishContext *pc;
  47. /**
  48. * Meta-data provided via command-line option.
  49. */
  50. static struct GNUNET_CONTAINER_MetaData *meta;
  51. /**
  52. * Keywords provided via command-line option.
  53. */
  54. static struct GNUNET_FS_Uri *topKeywords;
  55. /**
  56. * Options we set for published blocks.
  57. */
  58. static struct GNUNET_FS_BlockOptions bo = { { 0LL }, 1, 365, 1 };
  59. /**
  60. * Value of URI provided on command-line (when not publishing
  61. * a file but just creating UBlocks to refer to an existing URI).
  62. */
  63. static char *uri_string;
  64. /**
  65. * Value of URI provided on command-line (when not publishing
  66. * a file but just creating UBlocks to refer to an existing URI);
  67. * parsed version of 'uri_string'.
  68. */
  69. static struct GNUNET_FS_Uri *uri;
  70. /**
  71. * Command-line option for namespace publishing: identifier for updates
  72. * to this publication.
  73. */
  74. static char *next_id;
  75. /**
  76. * Command-line option for namespace publishing: identifier for this
  77. * publication.
  78. */
  79. static char *this_id;
  80. /**
  81. * Command-line option identifying the pseudonym to use for the publication.
  82. */
  83. static char *pseudonym;
  84. /**
  85. * Command-line option for 'inserting'
  86. */
  87. static int do_insert;
  88. /**
  89. * Command-line option to disable meta data extraction.
  90. */
  91. static int disable_extractor;
  92. /**
  93. * Command-line option to merely simulate publishing operation.
  94. */
  95. static int do_simulate;
  96. /**
  97. * Command-line option to only perform meta data extraction, but not publish.
  98. */
  99. static int extract_only;
  100. /**
  101. * Command-line option to disable adding creation time.
  102. */
  103. static int enable_creation_time;
  104. /**
  105. * Handle to the directory scanner (for recursive insertions).
  106. */
  107. static struct GNUNET_FS_DirScanner *ds;
  108. /**
  109. * Which namespace do we publish to? NULL if we do not publish to
  110. * a namespace.
  111. */
  112. static struct GNUNET_IDENTITY_Ego *namespace;
  113. /**
  114. * Handle to identity service.
  115. */
  116. static struct GNUNET_IDENTITY_Handle *identity;
  117. /**
  118. * We are finished with the publishing operation, clean up all
  119. * FS state.
  120. *
  121. * @param cls NULL
  122. */
  123. static void
  124. do_stop_task (void *cls)
  125. {
  126. struct GNUNET_FS_PublishContext *p;
  127. if (NULL != ds)
  128. {
  129. GNUNET_FS_directory_scan_abort (ds);
  130. ds = NULL;
  131. }
  132. if (NULL != identity)
  133. {
  134. GNUNET_IDENTITY_disconnect (identity);
  135. identity = NULL;
  136. }
  137. if (NULL != pc)
  138. {
  139. p = pc;
  140. pc = NULL;
  141. GNUNET_FS_publish_stop (p);
  142. }
  143. if (NULL != ctx)
  144. {
  145. GNUNET_FS_stop (ctx);
  146. ctx = NULL;
  147. }
  148. if (NULL != meta)
  149. {
  150. GNUNET_CONTAINER_meta_data_destroy (meta);
  151. meta = NULL;
  152. }
  153. if (NULL != uri)
  154. {
  155. GNUNET_FS_uri_destroy (uri);
  156. uri = NULL;
  157. }
  158. }
  159. /**
  160. * Called by FS client to give information about the progress of an
  161. * operation.
  162. *
  163. * @param cls closure
  164. * @param info details about the event, specifying the event type
  165. * and various bits about the event
  166. * @return client-context (for the next progress call
  167. * for this operation; should be set to NULL for
  168. * SUSPEND and STOPPED events). The value returned
  169. * will be passed to future callbacks in the respective
  170. * field in the GNUNET_FS_ProgressInfo struct.
  171. */
  172. static void *
  173. progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
  174. {
  175. const char *s;
  176. char *suri;
  177. switch (info->status)
  178. {
  179. case GNUNET_FS_STATUS_PUBLISH_START:
  180. break;
  181. case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
  182. if (verbose)
  183. {
  184. s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.eta,
  185. GNUNET_YES);
  186. fprintf (stdout,
  187. _ ("Publishing `%s' at %llu/%llu (%s remaining)\n"),
  188. info->value.publish.filename,
  189. (unsigned long long) info->value.publish.completed,
  190. (unsigned long long) info->value.publish.size,
  191. s);
  192. }
  193. break;
  194. case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY:
  195. if (verbose)
  196. {
  197. s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.specifics
  198. .progress_directory.eta,
  199. GNUNET_YES);
  200. fprintf (stdout,
  201. _ ("Publishing `%s' at %llu/%llu (%s remaining)\n"),
  202. info->value.publish.filename,
  203. (unsigned long long)
  204. info->value.publish.specifics.progress_directory.completed,
  205. (unsigned long long)
  206. info->value.publish.specifics.progress_directory.total,
  207. s);
  208. }
  209. break;
  210. case GNUNET_FS_STATUS_PUBLISH_ERROR:
  211. fprintf (stderr,
  212. _ ("Error publishing: %s.\n"),
  213. info->value.publish.specifics.error.message);
  214. ret = 1;
  215. GNUNET_SCHEDULER_shutdown ();
  216. break;
  217. case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
  218. fprintf (stdout,
  219. _ ("Publishing `%s' done.\n"),
  220. info->value.publish.filename);
  221. suri =
  222. GNUNET_FS_uri_to_string (info->value.publish.specifics.completed.chk_uri);
  223. fprintf (stdout, _ ("URI is `%s'.\n"), suri);
  224. GNUNET_free (suri);
  225. if (NULL != info->value.publish.specifics.completed.sks_uri)
  226. {
  227. suri = GNUNET_FS_uri_to_string (
  228. info->value.publish.specifics.completed.sks_uri);
  229. fprintf (stdout, _ ("Namespace URI is `%s'.\n"), suri);
  230. GNUNET_free (suri);
  231. }
  232. if (NULL == info->value.publish.pctx)
  233. {
  234. ret = 0;
  235. GNUNET_SCHEDULER_shutdown ();
  236. }
  237. break;
  238. case GNUNET_FS_STATUS_PUBLISH_STOPPED:
  239. GNUNET_break (NULL == pc);
  240. return NULL;
  241. case GNUNET_FS_STATUS_UNINDEX_START:
  242. fprintf (stderr, "%s", _ ("Starting cleanup after abort\n"));
  243. return NULL;
  244. case GNUNET_FS_STATUS_UNINDEX_PROGRESS:
  245. return NULL;
  246. case GNUNET_FS_STATUS_UNINDEX_COMPLETED:
  247. fprintf (stderr, "%s", _ ("Cleanup after abort completed.\n"));
  248. GNUNET_FS_unindex_stop (info->value.unindex.uc);
  249. return NULL;
  250. case GNUNET_FS_STATUS_UNINDEX_ERROR:
  251. fprintf (stderr, "%s", _ ("Cleanup after abort failed.\n"));
  252. GNUNET_FS_unindex_stop (info->value.unindex.uc);
  253. return NULL;
  254. case GNUNET_FS_STATUS_UNINDEX_STOPPED:
  255. return NULL;
  256. default:
  257. fprintf (stderr, _ ("Unexpected status: %d\n"), info->status);
  258. return NULL;
  259. }
  260. return ""; /* non-null */
  261. }
  262. /**
  263. * Print metadata entries (except binary
  264. * metadata and the filename).
  265. *
  266. * @param cls closure
  267. * @param plugin_name name of the plugin that generated the meta data
  268. * @param type type of the meta data
  269. * @param format format of data
  270. * @param data_mime_type mime type of @a data
  271. * @param data value of the meta data
  272. * @param data_size number of bytes in @a data
  273. * @return always 0
  274. */
  275. static int
  276. meta_printer (void *cls,
  277. const char *plugin_name,
  278. enum EXTRACTOR_MetaType type,
  279. enum EXTRACTOR_MetaFormat format,
  280. const char *data_mime_type,
  281. const char *data,
  282. size_t data_size)
  283. {
  284. if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
  285. (EXTRACTOR_METAFORMAT_C_STRING != format))
  286. return 0;
  287. if (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type)
  288. return 0;
  289. #if HAVE_LIBEXTRACTOR
  290. fprintf (stdout, "\t%s - %s\n", EXTRACTOR_metatype_to_string (type), data);
  291. #else
  292. fprintf (stdout, "\t%d - %s\n", type, data);
  293. #endif
  294. return 0;
  295. }
  296. /**
  297. * Iterator printing keywords
  298. *
  299. * @param cls closure
  300. * @param keyword the keyword
  301. * @param is_mandatory is the keyword mandatory (in a search)
  302. * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to abort
  303. */
  304. static int
  305. keyword_printer (void *cls, const char *keyword, int is_mandatory)
  306. {
  307. fprintf (stdout, "\t%s\n", keyword);
  308. return GNUNET_OK;
  309. }
  310. /**
  311. * Function called on all entries before the publication. This is
  312. * where we perform modifications to the default based on command-line
  313. * options.
  314. *
  315. * @param cls closure
  316. * @param fi the entry in the publish-structure
  317. * @param length length of the file or directory
  318. * @param m metadata for the file or directory (can be modified)
  319. * @param uri pointer to the keywords that will be used for this entry (can be modified)
  320. * @param bo block options
  321. * @param do_index should we index?
  322. * @param client_info pointer to client context set upon creation (can be modified)
  323. * @return #GNUNET_OK to continue, #GNUNET_NO to remove
  324. * this entry from the directory, #GNUNET_SYSERR
  325. * to abort the iteration
  326. */
  327. static int
  328. publish_inspector (void *cls,
  329. struct GNUNET_FS_FileInformation *fi,
  330. uint64_t length,
  331. struct GNUNET_CONTAINER_MetaData *m,
  332. struct GNUNET_FS_Uri **uri,
  333. struct GNUNET_FS_BlockOptions *bo,
  334. int *do_index,
  335. void **client_info)
  336. {
  337. char *fn;
  338. char *fs;
  339. struct GNUNET_FS_Uri *new_uri;
  340. if (cls == fi)
  341. return GNUNET_OK;
  342. if ((disable_extractor) && (NULL != *uri))
  343. {
  344. GNUNET_FS_uri_destroy (*uri);
  345. *uri = NULL;
  346. }
  347. if (NULL != topKeywords)
  348. {
  349. if (NULL != *uri)
  350. {
  351. new_uri = GNUNET_FS_uri_ksk_merge (topKeywords, *uri);
  352. GNUNET_FS_uri_destroy (*uri);
  353. *uri = new_uri;
  354. GNUNET_FS_uri_destroy (topKeywords);
  355. }
  356. else
  357. {
  358. *uri = topKeywords;
  359. }
  360. topKeywords = NULL;
  361. }
  362. if (NULL != meta)
  363. {
  364. GNUNET_CONTAINER_meta_data_merge (m, meta);
  365. GNUNET_CONTAINER_meta_data_destroy (meta);
  366. meta = NULL;
  367. }
  368. if (enable_creation_time)
  369. GNUNET_CONTAINER_meta_data_add_publication_date (m);
  370. if (extract_only)
  371. {
  372. fn = GNUNET_CONTAINER_meta_data_get_by_type (
  373. m,
  374. EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
  375. fs = GNUNET_STRINGS_byte_size_fancy (length);
  376. fprintf (stdout, _ ("Meta data for file `%s' (%s)\n"), fn, fs);
  377. GNUNET_CONTAINER_meta_data_iterate (m, &meta_printer, NULL);
  378. fprintf (stdout, _ ("Keywords for file `%s' (%s)\n"), fn, fs);
  379. GNUNET_free (fn);
  380. GNUNET_free (fs);
  381. if (NULL != *uri)
  382. GNUNET_FS_uri_ksk_get_keywords (*uri, &keyword_printer, NULL);
  383. fprintf (stdout, "%s", "\n");
  384. }
  385. if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (m))
  386. GNUNET_FS_file_information_inspect (fi, &publish_inspector, fi);
  387. return GNUNET_OK;
  388. }
  389. /**
  390. * Function called upon completion of the publishing
  391. * of the UBLOCK for the SKS URI. As this is the last
  392. * step, stop our interaction with FS (clean up).
  393. *
  394. * @param cls NULL (closure)
  395. * @param sks_uri URI for the block that was published
  396. * @param emsg error message, NULL on success
  397. */
  398. static void
  399. uri_sks_continuation (void *cls,
  400. const struct GNUNET_FS_Uri *sks_uri,
  401. const char *emsg)
  402. {
  403. if (NULL != emsg)
  404. {
  405. fprintf (stderr, "%s\n", emsg);
  406. ret = 1;
  407. }
  408. GNUNET_SCHEDULER_shutdown ();
  409. }
  410. /**
  411. * Function called upon completion of the publishing
  412. * of the UBLOCK for the KSK URI. Continue with
  413. * publishing the SKS URI (if applicable) or clean up.
  414. *
  415. * @param cls NULL (closure)
  416. * @param ksk_uri URI for the block that was published
  417. * @param emsg error message, NULL on success
  418. */
  419. static void
  420. uri_ksk_continuation (void *cls,
  421. const struct GNUNET_FS_Uri *ksk_uri,
  422. const char *emsg)
  423. {
  424. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
  425. const struct GNUNET_IDENTITY_PrivateKey *pk;
  426. if (NULL != emsg)
  427. {
  428. fprintf (stderr, "%s\n", emsg);
  429. ret = 1;
  430. }
  431. if (NULL == namespace)
  432. {
  433. GNUNET_SCHEDULER_shutdown ();
  434. return;
  435. }
  436. pk = GNUNET_IDENTITY_ego_get_private_key (namespace);
  437. if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (pk->type))
  438. return;
  439. priv = &pk->ecdsa_key;
  440. GNUNET_FS_publish_sks (ctx,
  441. priv,
  442. this_id,
  443. next_id,
  444. meta,
  445. uri,
  446. &bo,
  447. GNUNET_FS_PUBLISH_OPTION_NONE,
  448. &uri_sks_continuation,
  449. NULL);
  450. }
  451. /**
  452. * Iterate over the results from the directory scan and extract
  453. * the desired information for the publishing operation.
  454. *
  455. * @param item root with the data from the directroy scan
  456. * @return handle with the information for the publishing operation
  457. */
  458. static struct GNUNET_FS_FileInformation *
  459. get_file_information (struct GNUNET_FS_ShareTreeItem *item)
  460. {
  461. struct GNUNET_FS_FileInformation *fi;
  462. struct GNUNET_FS_FileInformation *fic;
  463. struct GNUNET_FS_ShareTreeItem *child;
  464. if (GNUNET_YES == item->is_directory)
  465. {
  466. if (NULL == item->meta)
  467. item->meta = GNUNET_CONTAINER_meta_data_create ();
  468. GNUNET_CONTAINER_meta_data_delete (item->meta,
  469. EXTRACTOR_METATYPE_MIMETYPE,
  470. NULL,
  471. 0);
  472. GNUNET_FS_meta_data_make_directory (item->meta);
  473. if (NULL == item->ksk_uri)
  474. {
  475. const char *mime = GNUNET_FS_DIRECTORY_MIME;
  476. item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime);
  477. }
  478. else
  479. GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri,
  480. GNUNET_FS_DIRECTORY_MIME,
  481. GNUNET_NO);
  482. fi = GNUNET_FS_file_information_create_empty_directory (ctx,
  483. NULL,
  484. item->ksk_uri,
  485. item->meta,
  486. &bo,
  487. item->filename);
  488. for (child = item->children_head; child; child = child->next)
  489. {
  490. fic = get_file_information (child);
  491. GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
  492. }
  493. }
  494. else
  495. {
  496. fi = GNUNET_FS_file_information_create_from_file (ctx,
  497. NULL,
  498. item->filename,
  499. item->ksk_uri,
  500. item->meta,
  501. ! do_insert,
  502. &bo);
  503. }
  504. return fi;
  505. }
  506. /**
  507. * We've finished scanning the directory and optimized the meta data.
  508. * Begin the publication process.
  509. *
  510. * @param directory_scan_result result from the directory scan, freed in this function
  511. */
  512. static void
  513. directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result)
  514. {
  515. struct GNUNET_FS_FileInformation *fi;
  516. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
  517. const struct GNUNET_IDENTITY_PrivateKey *pk;
  518. fi = get_file_information (directory_scan_result);
  519. GNUNET_FS_share_tree_free (directory_scan_result);
  520. if (NULL == fi)
  521. {
  522. fprintf (stderr, "%s", _ ("Could not publish\n"));
  523. ret = 1;
  524. GNUNET_SCHEDULER_shutdown ();
  525. return;
  526. }
  527. GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL);
  528. if (extract_only)
  529. {
  530. GNUNET_FS_file_information_destroy (fi, NULL, NULL);
  531. GNUNET_SCHEDULER_shutdown ();
  532. return;
  533. }
  534. priv = NULL;
  535. if (NULL != namespace)
  536. {
  537. pk = GNUNET_IDENTITY_ego_get_private_key (namespace);
  538. GNUNET_assert (GNUNET_IDENTITY_TYPE_ECDSA == ntohl (pk->type));
  539. priv = &pk->ecdsa_key;
  540. }
  541. pc = GNUNET_FS_publish_start (ctx,
  542. fi,
  543. priv,
  544. this_id,
  545. next_id,
  546. (do_simulate)
  547. ? GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY
  548. : GNUNET_FS_PUBLISH_OPTION_NONE);
  549. if (NULL == pc)
  550. {
  551. fprintf (stderr, "%s", _ ("Could not start publishing.\n"));
  552. ret = 1;
  553. GNUNET_SCHEDULER_shutdown ();
  554. return;
  555. }
  556. }
  557. /**
  558. * Function called by the directory scanner as we build the tree
  559. * that we will need to publish later.
  560. *
  561. * @param cls closure
  562. * @param filename which file we are making progress on
  563. * @param is_directory #GNUNET_YES if this is a directory,
  564. * #GNUNET_NO if this is a file
  565. * #GNUNET_SYSERR if it is neither (or unknown)
  566. * @param reason kind of progress we are making
  567. */
  568. static void
  569. directory_scan_cb (void *cls,
  570. const char *filename,
  571. int is_directory,
  572. enum GNUNET_FS_DirScannerProgressUpdateReason reason)
  573. {
  574. struct GNUNET_FS_ShareTreeItem *directory_scan_result;
  575. switch (reason)
  576. {
  577. case GNUNET_FS_DIRSCANNER_FILE_START:
  578. if (verbose > 1)
  579. {
  580. if (is_directory == GNUNET_YES)
  581. fprintf (stdout, _ ("Scanning directory `%s'.\n"), filename);
  582. else
  583. fprintf (stdout, _ ("Scanning file `%s'.\n"), filename);
  584. }
  585. break;
  586. case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
  587. fprintf (stderr,
  588. _ ("There was trouble processing file `%s', skipping it.\n"),
  589. filename);
  590. break;
  591. case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
  592. if (verbose)
  593. fprintf (stdout, "%s", _ ("Preprocessing complete.\n"));
  594. break;
  595. case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
  596. if (verbose > 2)
  597. fprintf (stdout,
  598. _ ("Extracting meta data from file `%s' complete.\n"),
  599. filename);
  600. break;
  601. case GNUNET_FS_DIRSCANNER_FINISHED:
  602. if (verbose > 1)
  603. fprintf (stdout, "%s", _ ("Meta data extraction has finished.\n"));
  604. directory_scan_result = GNUNET_FS_directory_scan_get_result (ds);
  605. ds = NULL;
  606. GNUNET_FS_share_tree_trim (directory_scan_result);
  607. directory_trim_complete (directory_scan_result);
  608. break;
  609. case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
  610. fprintf (stdout, "%s", _ ("Error scanning directory.\n"));
  611. ret = 1;
  612. GNUNET_SCHEDULER_shutdown ();
  613. break;
  614. default:
  615. GNUNET_assert (0);
  616. break;
  617. }
  618. fflush (stdout);
  619. }
  620. /**
  621. * Continuation proceeding with initialization after identity subsystem
  622. * has been initialized.
  623. *
  624. * @param args0 filename to publish
  625. */
  626. static void
  627. identity_continuation (const char *args0)
  628. {
  629. char *ex;
  630. char *emsg;
  631. if ((NULL != pseudonym) && (NULL == namespace))
  632. {
  633. fprintf (stderr, _ ("Selected pseudonym `%s' unknown\n"), pseudonym);
  634. ret = 1;
  635. GNUNET_SCHEDULER_shutdown ();
  636. return;
  637. }
  638. if (NULL != uri_string)
  639. {
  640. emsg = NULL;
  641. if (NULL == (uri = GNUNET_FS_uri_parse (uri_string, &emsg)))
  642. {
  643. fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg);
  644. GNUNET_free (emsg);
  645. ret = 1;
  646. GNUNET_SCHEDULER_shutdown ();
  647. return;
  648. }
  649. GNUNET_FS_publish_ksk (ctx,
  650. topKeywords,
  651. meta,
  652. uri,
  653. &bo,
  654. GNUNET_FS_PUBLISH_OPTION_NONE,
  655. &uri_ksk_continuation,
  656. NULL);
  657. return;
  658. }
  659. if (GNUNET_OK !=
  660. GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex))
  661. ex = NULL;
  662. if (0 != access (args0, R_OK))
  663. {
  664. fprintf (stderr,
  665. _ ("Failed to access `%s': %s\n"),
  666. args0,
  667. strerror (errno));
  668. GNUNET_free (ex);
  669. return;
  670. }
  671. ds = GNUNET_FS_directory_scan_start (args0,
  672. disable_extractor,
  673. ex,
  674. &directory_scan_cb,
  675. NULL);
  676. if (NULL == ds)
  677. {
  678. fprintf (
  679. stderr,
  680. "%s",
  681. _ (
  682. "Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n"));
  683. GNUNET_free (ex);
  684. return;
  685. }
  686. GNUNET_free (ex);
  687. }
  688. /**
  689. * Function called by identity service with known pseudonyms.
  690. *
  691. * @param cls closure with 'const char *' of filename to publish
  692. * @param ego ego handle
  693. * @param ctx context for application to store data for this ego
  694. * (during the lifetime of this process, initially NULL)
  695. * @param name name assigned by the user for this ego,
  696. * NULL if the user just deleted the ego and it
  697. * must thus no longer be used
  698. */
  699. static void
  700. identity_cb (void *cls,
  701. struct GNUNET_IDENTITY_Ego *ego,
  702. void **ctx,
  703. const char *name)
  704. {
  705. const char *args0 = cls;
  706. if (NULL == ego)
  707. {
  708. identity_continuation (args0);
  709. return;
  710. }
  711. if (NULL == name)
  712. return;
  713. if (0 == strcmp (name, pseudonym))
  714. namespace = ego;
  715. }
  716. /**
  717. * Main function that will be run by the scheduler.
  718. *
  719. * @param cls closure
  720. * @param args remaining command-line arguments
  721. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  722. * @param c configuration
  723. */
  724. static void
  725. run (void *cls,
  726. char *const *args,
  727. const char *cfgfile,
  728. const struct GNUNET_CONFIGURATION_Handle *c)
  729. {
  730. /* check arguments */
  731. if ((NULL != uri_string) && (extract_only))
  732. {
  733. printf (_ ("Cannot extract metadata from a URI!\n"));
  734. ret = -1;
  735. return;
  736. }
  737. if (((NULL == uri_string) || (extract_only)) &&
  738. ((NULL == args[0]) || (NULL != args[1])))
  739. {
  740. printf (_ ("You must specify one and only one filename for insertion.\n"));
  741. ret = -1;
  742. return;
  743. }
  744. if ((NULL != uri_string) && (NULL != args[0]))
  745. {
  746. printf (_ ("You must NOT specify an URI and a filename.\n"));
  747. ret = -1;
  748. return;
  749. }
  750. if (NULL != pseudonym)
  751. {
  752. if (NULL == this_id)
  753. {
  754. fprintf (stderr,
  755. _ ("Option `%s' is required when using option `%s'.\n"),
  756. "-t",
  757. "-P");
  758. ret = -1;
  759. return;
  760. }
  761. }
  762. else
  763. { /* ordinary insertion checks */
  764. if (NULL != next_id)
  765. {
  766. fprintf (stderr,
  767. _ ("Option `%s' makes no sense without option `%s'.\n"),
  768. "-N",
  769. "-P");
  770. ret = -1;
  771. return;
  772. }
  773. if (NULL != this_id)
  774. {
  775. fprintf (stderr,
  776. _ ("Option `%s' makes no sense without option `%s'.\n"),
  777. "-t",
  778. "-P");
  779. ret = -1;
  780. return;
  781. }
  782. }
  783. cfg = c;
  784. ctx = GNUNET_FS_start (cfg,
  785. "gnunet-publish",
  786. &progress_cb,
  787. NULL,
  788. GNUNET_FS_FLAGS_NONE,
  789. GNUNET_FS_OPTIONS_END);
  790. if (NULL == ctx)
  791. {
  792. fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
  793. ret = 1;
  794. return;
  795. }
  796. GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL);
  797. if (NULL != pseudonym)
  798. identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, args[0]);
  799. else
  800. identity_continuation (args[0]);
  801. }
  802. /**
  803. * The main function to publish content to GNUnet.
  804. *
  805. * @param argc number of arguments from the command line
  806. * @param argv command line arguments
  807. * @return 0 ok, 1 on error
  808. */
  809. int
  810. main (int argc, char *const *argv)
  811. {
  812. struct GNUNET_GETOPT_CommandLineOption options[] =
  813. { GNUNET_GETOPT_option_uint ('a',
  814. "anonymity",
  815. "LEVEL",
  816. gettext_noop (
  817. "set the desired LEVEL of sender-anonymity"),
  818. &bo.anonymity_level),
  819. GNUNET_GETOPT_option_flag (
  820. 'D',
  821. "disable-extractor",
  822. gettext_noop ("do not use libextractor to add keywords or metadata"),
  823. &disable_extractor),
  824. GNUNET_GETOPT_option_flag ('E',
  825. "enable-creation-time",
  826. gettext_noop (
  827. "enable adding the creation time to the "
  828. "metadata of the uploaded file"),
  829. &enable_creation_time),
  830. GNUNET_GETOPT_option_flag ('e',
  831. "extract",
  832. gettext_noop (
  833. "print list of extracted keywords that would "
  834. "be used, but do not perform upload"),
  835. &extract_only),
  836. GNUNET_FS_GETOPT_KEYWORDS (
  837. 'k',
  838. "key",
  839. "KEYWORD",
  840. gettext_noop (
  841. "add an additional keyword for the top-level "
  842. "file or directory (this option can be specified multiple times)"),
  843. &topKeywords),
  844. GNUNET_FS_GETOPT_METADATA (
  845. 'm',
  846. "meta",
  847. "TYPE:VALUE",
  848. gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
  849. &meta),
  850. GNUNET_GETOPT_option_flag (
  851. 'n',
  852. "noindex",
  853. gettext_noop ("do not index, perform full insertion (stores "
  854. "entire file in encrypted form in GNUnet database)"),
  855. &do_insert),
  856. GNUNET_GETOPT_option_string (
  857. 'N',
  858. "next",
  859. "ID",
  860. gettext_noop ("specify ID of an updated version to be "
  861. "published in the future (for namespace insertions only)"),
  862. &next_id),
  863. GNUNET_GETOPT_option_uint ('p',
  864. "priority",
  865. "PRIORITY",
  866. gettext_noop (
  867. "specify the priority of the content"),
  868. &bo.content_priority),
  869. GNUNET_GETOPT_option_string ('P',
  870. "pseudonym",
  871. "NAME",
  872. gettext_noop (
  873. "publish the files under the pseudonym "
  874. "NAME (place file into namespace)"),
  875. &pseudonym),
  876. GNUNET_GETOPT_option_uint ('r',
  877. "replication",
  878. "LEVEL",
  879. gettext_noop (
  880. "set the desired replication LEVEL"),
  881. &bo.replication_level),
  882. GNUNET_GETOPT_option_flag ('s',
  883. "simulate-only",
  884. gettext_noop (
  885. "only simulate the process but do not do "
  886. "any actual publishing (useful to compute URIs)"),
  887. &do_simulate),
  888. GNUNET_GETOPT_option_string ('t',
  889. "this",
  890. "ID",
  891. gettext_noop (
  892. "set the ID of this version of the publication "
  893. "(for namespace insertions only)"),
  894. &this_id),
  895. GNUNET_GETOPT_option_string (
  896. 'u',
  897. "uri",
  898. "URI",
  899. gettext_noop (
  900. "URI to be published (can be used instead of passing a "
  901. "file to add keywords to the file with the respective URI)"),
  902. &uri_string),
  903. GNUNET_GETOPT_option_verbose (&verbose),
  904. GNUNET_GETOPT_OPTION_END };
  905. bo.expiration_time =
  906. GNUNET_TIME_year_to_time (GNUNET_TIME_get_current_year () + 2);
  907. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  908. return 2;
  909. ret =
  910. (GNUNET_OK ==
  911. GNUNET_PROGRAM_run (argc,
  912. argv,
  913. "gnunet-publish [OPTIONS] FILENAME",
  914. gettext_noop ("Publish a file or directory on GNUnet"),
  915. options,
  916. &run,
  917. NULL))
  918. ? ret
  919. : 1;
  920. GNUNET_free_nz ((void *) argv);
  921. return ret;
  922. }
  923. /* end of gnunet-publish.c */