gnunet-publish.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  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. if (NULL != emsg)
  426. {
  427. fprintf (stderr, "%s\n", emsg);
  428. ret = 1;
  429. }
  430. if (NULL == namespace)
  431. {
  432. GNUNET_SCHEDULER_shutdown ();
  433. return;
  434. }
  435. priv = GNUNET_IDENTITY_ego_get_private_key (namespace);
  436. GNUNET_FS_publish_sks (ctx,
  437. priv,
  438. this_id,
  439. next_id,
  440. meta,
  441. uri,
  442. &bo,
  443. GNUNET_FS_PUBLISH_OPTION_NONE,
  444. &uri_sks_continuation,
  445. NULL);
  446. }
  447. /**
  448. * Iterate over the results from the directory scan and extract
  449. * the desired information for the publishing operation.
  450. *
  451. * @param item root with the data from the directroy scan
  452. * @return handle with the information for the publishing operation
  453. */
  454. static struct GNUNET_FS_FileInformation *
  455. get_file_information (struct GNUNET_FS_ShareTreeItem *item)
  456. {
  457. struct GNUNET_FS_FileInformation *fi;
  458. struct GNUNET_FS_FileInformation *fic;
  459. struct GNUNET_FS_ShareTreeItem *child;
  460. if (GNUNET_YES == item->is_directory)
  461. {
  462. if (NULL == item->meta)
  463. item->meta = GNUNET_CONTAINER_meta_data_create ();
  464. GNUNET_CONTAINER_meta_data_delete (item->meta,
  465. EXTRACTOR_METATYPE_MIMETYPE,
  466. NULL,
  467. 0);
  468. GNUNET_FS_meta_data_make_directory (item->meta);
  469. if (NULL == item->ksk_uri)
  470. {
  471. const char *mime = GNUNET_FS_DIRECTORY_MIME;
  472. item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime);
  473. }
  474. else
  475. GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri,
  476. GNUNET_FS_DIRECTORY_MIME,
  477. GNUNET_NO);
  478. fi = GNUNET_FS_file_information_create_empty_directory (ctx,
  479. NULL,
  480. item->ksk_uri,
  481. item->meta,
  482. &bo,
  483. item->filename);
  484. for (child = item->children_head; child; child = child->next)
  485. {
  486. fic = get_file_information (child);
  487. GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
  488. }
  489. }
  490. else
  491. {
  492. fi = GNUNET_FS_file_information_create_from_file (ctx,
  493. NULL,
  494. item->filename,
  495. item->ksk_uri,
  496. item->meta,
  497. ! do_insert,
  498. &bo);
  499. }
  500. return fi;
  501. }
  502. /**
  503. * We've finished scanning the directory and optimized the meta data.
  504. * Begin the publication process.
  505. *
  506. * @param directory_scan_result result from the directory scan, freed in this function
  507. */
  508. static void
  509. directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result)
  510. {
  511. struct GNUNET_FS_FileInformation *fi;
  512. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
  513. fi = get_file_information (directory_scan_result);
  514. GNUNET_FS_share_tree_free (directory_scan_result);
  515. if (NULL == fi)
  516. {
  517. fprintf (stderr, "%s", _ ("Could not publish\n"));
  518. ret = 1;
  519. GNUNET_SCHEDULER_shutdown ();
  520. return;
  521. }
  522. GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL);
  523. if (extract_only)
  524. {
  525. GNUNET_FS_file_information_destroy (fi, NULL, NULL);
  526. GNUNET_SCHEDULER_shutdown ();
  527. return;
  528. }
  529. if (NULL == namespace)
  530. priv = NULL;
  531. else
  532. priv = GNUNET_IDENTITY_ego_get_private_key (namespace);
  533. pc = GNUNET_FS_publish_start (ctx,
  534. fi,
  535. priv,
  536. this_id,
  537. next_id,
  538. (do_simulate)
  539. ? GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY
  540. : GNUNET_FS_PUBLISH_OPTION_NONE);
  541. if (NULL == pc)
  542. {
  543. fprintf (stderr, "%s", _ ("Could not start publishing.\n"));
  544. ret = 1;
  545. GNUNET_SCHEDULER_shutdown ();
  546. return;
  547. }
  548. }
  549. /**
  550. * Function called by the directory scanner as we build the tree
  551. * that we will need to publish later.
  552. *
  553. * @param cls closure
  554. * @param filename which file we are making progress on
  555. * @param is_directory #GNUNET_YES if this is a directory,
  556. * #GNUNET_NO if this is a file
  557. * #GNUNET_SYSERR if it is neither (or unknown)
  558. * @param reason kind of progress we are making
  559. */
  560. static void
  561. directory_scan_cb (void *cls,
  562. const char *filename,
  563. int is_directory,
  564. enum GNUNET_FS_DirScannerProgressUpdateReason reason)
  565. {
  566. struct GNUNET_FS_ShareTreeItem *directory_scan_result;
  567. switch (reason)
  568. {
  569. case GNUNET_FS_DIRSCANNER_FILE_START:
  570. if (verbose > 1)
  571. {
  572. if (is_directory == GNUNET_YES)
  573. fprintf (stdout, _ ("Scanning directory `%s'.\n"), filename);
  574. else
  575. fprintf (stdout, _ ("Scanning file `%s'.\n"), filename);
  576. }
  577. break;
  578. case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
  579. fprintf (stderr,
  580. _ ("There was trouble processing file `%s', skipping it.\n"),
  581. filename);
  582. break;
  583. case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
  584. if (verbose)
  585. fprintf (stdout, "%s", _ ("Preprocessing complete.\n"));
  586. break;
  587. case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
  588. if (verbose > 2)
  589. fprintf (stdout,
  590. _ ("Extracting meta data from file `%s' complete.\n"),
  591. filename);
  592. break;
  593. case GNUNET_FS_DIRSCANNER_FINISHED:
  594. if (verbose > 1)
  595. fprintf (stdout, "%s", _ ("Meta data extraction has finished.\n"));
  596. directory_scan_result = GNUNET_FS_directory_scan_get_result (ds);
  597. ds = NULL;
  598. GNUNET_FS_share_tree_trim (directory_scan_result);
  599. directory_trim_complete (directory_scan_result);
  600. break;
  601. case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
  602. fprintf (stdout, "%s", _ ("Error scanning directory.\n"));
  603. ret = 1;
  604. GNUNET_SCHEDULER_shutdown ();
  605. break;
  606. default:
  607. GNUNET_assert (0);
  608. break;
  609. }
  610. fflush (stdout);
  611. }
  612. /**
  613. * Continuation proceeding with initialization after identity subsystem
  614. * has been initialized.
  615. *
  616. * @param args0 filename to publish
  617. */
  618. static void
  619. identity_continuation (const char *args0)
  620. {
  621. char *ex;
  622. char *emsg;
  623. if ((NULL != pseudonym) && (NULL == namespace))
  624. {
  625. fprintf (stderr, _ ("Selected pseudonym `%s' unknown\n"), pseudonym);
  626. ret = 1;
  627. GNUNET_SCHEDULER_shutdown ();
  628. return;
  629. }
  630. if (NULL != uri_string)
  631. {
  632. emsg = NULL;
  633. if (NULL == (uri = GNUNET_FS_uri_parse (uri_string, &emsg)))
  634. {
  635. fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg);
  636. GNUNET_free (emsg);
  637. ret = 1;
  638. GNUNET_SCHEDULER_shutdown ();
  639. return;
  640. }
  641. GNUNET_FS_publish_ksk (ctx,
  642. topKeywords,
  643. meta,
  644. uri,
  645. &bo,
  646. GNUNET_FS_PUBLISH_OPTION_NONE,
  647. &uri_ksk_continuation,
  648. NULL);
  649. return;
  650. }
  651. if (GNUNET_OK !=
  652. GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex))
  653. ex = NULL;
  654. if (0 != access (args0, R_OK))
  655. {
  656. fprintf (stderr,
  657. _ ("Failed to access `%s': %s\n"),
  658. args0,
  659. strerror (errno));
  660. GNUNET_free_non_null (ex);
  661. return;
  662. }
  663. ds = GNUNET_FS_directory_scan_start (args0,
  664. disable_extractor,
  665. ex,
  666. &directory_scan_cb,
  667. NULL);
  668. if (NULL == ds)
  669. {
  670. fprintf (
  671. stderr,
  672. "%s",
  673. _ (
  674. "Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n"));
  675. GNUNET_free_non_null (ex);
  676. return;
  677. }
  678. GNUNET_free_non_null (ex);
  679. }
  680. /**
  681. * Function called by identity service with known pseudonyms.
  682. *
  683. * @param cls closure with 'const char *' of filename to publish
  684. * @param ego ego handle
  685. * @param ctx context for application to store data for this ego
  686. * (during the lifetime of this process, initially NULL)
  687. * @param name name assigned by the user for this ego,
  688. * NULL if the user just deleted the ego and it
  689. * must thus no longer be used
  690. */
  691. static void
  692. identity_cb (void *cls,
  693. struct GNUNET_IDENTITY_Ego *ego,
  694. void **ctx,
  695. const char *name)
  696. {
  697. const char *args0 = cls;
  698. if (NULL == ego)
  699. {
  700. identity_continuation (args0);
  701. return;
  702. }
  703. if (NULL == name)
  704. return;
  705. if (0 == strcmp (name, pseudonym))
  706. namespace = ego;
  707. }
  708. /**
  709. * Main function that will be run by the scheduler.
  710. *
  711. * @param cls closure
  712. * @param args remaining command-line arguments
  713. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  714. * @param c configuration
  715. */
  716. static void
  717. run (void *cls,
  718. char *const *args,
  719. const char *cfgfile,
  720. const struct GNUNET_CONFIGURATION_Handle *c)
  721. {
  722. /* check arguments */
  723. if ((NULL != uri_string) && (extract_only))
  724. {
  725. printf (_ ("Cannot extract metadata from a URI!\n"));
  726. ret = -1;
  727. return;
  728. }
  729. if (((NULL == uri_string) || (extract_only)) &&
  730. ((NULL == args[0]) || (NULL != args[1])))
  731. {
  732. printf (_ ("You must specify one and only one filename for insertion.\n"));
  733. ret = -1;
  734. return;
  735. }
  736. if ((NULL != uri_string) && (NULL != args[0]))
  737. {
  738. printf (_ ("You must NOT specify an URI and a filename.\n"));
  739. ret = -1;
  740. return;
  741. }
  742. if (NULL != pseudonym)
  743. {
  744. if (NULL == this_id)
  745. {
  746. fprintf (stderr,
  747. _ ("Option `%s' is required when using option `%s'.\n"),
  748. "-t",
  749. "-P");
  750. ret = -1;
  751. return;
  752. }
  753. }
  754. else
  755. { /* ordinary insertion checks */
  756. if (NULL != next_id)
  757. {
  758. fprintf (stderr,
  759. _ ("Option `%s' makes no sense without option `%s'.\n"),
  760. "-N",
  761. "-P");
  762. ret = -1;
  763. return;
  764. }
  765. if (NULL != this_id)
  766. {
  767. fprintf (stderr,
  768. _ ("Option `%s' makes no sense without option `%s'.\n"),
  769. "-t",
  770. "-P");
  771. ret = -1;
  772. return;
  773. }
  774. }
  775. cfg = c;
  776. ctx = GNUNET_FS_start (cfg,
  777. "gnunet-publish",
  778. &progress_cb,
  779. NULL,
  780. GNUNET_FS_FLAGS_NONE,
  781. GNUNET_FS_OPTIONS_END);
  782. if (NULL == ctx)
  783. {
  784. fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
  785. ret = 1;
  786. return;
  787. }
  788. GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL);
  789. if (NULL != pseudonym)
  790. identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, args[0]);
  791. else
  792. identity_continuation (args[0]);
  793. }
  794. /**
  795. * The main function to publish content to GNUnet.
  796. *
  797. * @param argc number of arguments from the command line
  798. * @param argv command line arguments
  799. * @return 0 ok, 1 on error
  800. */
  801. int
  802. main (int argc, char *const *argv)
  803. {
  804. struct GNUNET_GETOPT_CommandLineOption options[] =
  805. { GNUNET_GETOPT_option_uint ('a',
  806. "anonymity",
  807. "LEVEL",
  808. gettext_noop (
  809. "set the desired LEVEL of sender-anonymity"),
  810. &bo.anonymity_level),
  811. GNUNET_GETOPT_option_flag (
  812. 'D',
  813. "disable-extractor",
  814. gettext_noop ("do not use libextractor to add keywords or metadata"),
  815. &disable_extractor),
  816. GNUNET_GETOPT_option_flag ('E',
  817. "enable-creation-time",
  818. gettext_noop (
  819. "enable adding the creation time to the "
  820. "metadata of the uploaded file"),
  821. &enable_creation_time),
  822. GNUNET_GETOPT_option_flag ('e',
  823. "extract",
  824. gettext_noop (
  825. "print list of extracted keywords that would "
  826. "be used, but do not perform upload"),
  827. &extract_only),
  828. GNUNET_FS_GETOPT_KEYWORDS (
  829. 'k',
  830. "key",
  831. "KEYWORD",
  832. gettext_noop (
  833. "add an additional keyword for the top-level "
  834. "file or directory (this option can be specified multiple times)"),
  835. &topKeywords),
  836. GNUNET_FS_GETOPT_METADATA (
  837. 'm',
  838. "meta",
  839. "TYPE:VALUE",
  840. gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
  841. &meta),
  842. GNUNET_GETOPT_option_flag (
  843. 'n',
  844. "noindex",
  845. gettext_noop ("do not index, perform full insertion (stores "
  846. "entire file in encrypted form in GNUnet database)"),
  847. &do_insert),
  848. GNUNET_GETOPT_option_string (
  849. 'N',
  850. "next",
  851. "ID",
  852. gettext_noop ("specify ID of an updated version to be "
  853. "published in the future (for namespace insertions only)"),
  854. &next_id),
  855. GNUNET_GETOPT_option_uint ('p',
  856. "priority",
  857. "PRIORITY",
  858. gettext_noop (
  859. "specify the priority of the content"),
  860. &bo.content_priority),
  861. GNUNET_GETOPT_option_string ('P',
  862. "pseudonym",
  863. "NAME",
  864. gettext_noop (
  865. "publish the files under the pseudonym "
  866. "NAME (place file into namespace)"),
  867. &pseudonym),
  868. GNUNET_GETOPT_option_uint ('r',
  869. "replication",
  870. "LEVEL",
  871. gettext_noop (
  872. "set the desired replication LEVEL"),
  873. &bo.replication_level),
  874. GNUNET_GETOPT_option_flag ('s',
  875. "simulate-only",
  876. gettext_noop (
  877. "only simulate the process but do not do "
  878. "any actual publishing (useful to compute URIs)"),
  879. &do_simulate),
  880. GNUNET_GETOPT_option_string ('t',
  881. "this",
  882. "ID",
  883. gettext_noop (
  884. "set the ID of this version of the publication "
  885. "(for namespace insertions only)"),
  886. &this_id),
  887. GNUNET_GETOPT_option_string (
  888. 'u',
  889. "uri",
  890. "URI",
  891. gettext_noop (
  892. "URI to be published (can be used instead of passing a "
  893. "file to add keywords to the file with the respective URI)"),
  894. &uri_string),
  895. GNUNET_GETOPT_option_verbose (&verbose),
  896. GNUNET_GETOPT_OPTION_END };
  897. bo.expiration_time =
  898. GNUNET_TIME_year_to_time (GNUNET_TIME_get_current_year () + 2);
  899. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  900. return 2;
  901. ret =
  902. (GNUNET_OK ==
  903. GNUNET_PROGRAM_run (argc,
  904. argv,
  905. "gnunet-publish [OPTIONS] FILENAME",
  906. gettext_noop ("Publish a file or directory on GNUnet"),
  907. options,
  908. &run,
  909. NULL))
  910. ? ret
  911. : 1;
  912. GNUNET_free ((void *) argv);
  913. return ret;
  914. }
  915. /* end of gnunet-publish.c */