fs_publish.c 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2010 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/fs_publish.c
  18. * @brief publish a file or directory in GNUnet
  19. * @see https://gnunet.org/encoding
  20. * @author Krista Bennett
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_signatures.h"
  26. #include "gnunet_util_lib.h"
  27. #include "gnunet_fs_service.h"
  28. #include "fs_api.h"
  29. #include "fs_tree.h"
  30. /**
  31. * Fill in all of the generic fields for
  32. * a publish event and call the callback.
  33. *
  34. * @param pi structure to fill in
  35. * @param pc overall publishing context
  36. * @param p file information for the file being published
  37. * @param offset where in the file are we so far
  38. * @return value returned from callback
  39. */
  40. void *
  41. GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
  42. struct GNUNET_FS_PublishContext *pc,
  43. const struct GNUNET_FS_FileInformation *p,
  44. uint64_t offset)
  45. {
  46. pi->value.publish.pc = pc;
  47. pi->value.publish.fi = p;
  48. pi->value.publish.cctx = p->client_info;
  49. pi->value.publish.pctx = (NULL == p->dir) ? NULL : p->dir->client_info;
  50. pi->value.publish.filename = p->filename;
  51. pi->value.publish.size =
  52. (GNUNET_YES == p->is_directory) ? p->data.dir.dir_size :
  53. p->data.file.file_size;
  54. pi->value.publish.eta =
  55. GNUNET_TIME_calculate_eta (p->start_time, offset,
  56. pi->value.publish.size);
  57. pi->value.publish.completed = offset;
  58. pi->value.publish.duration =
  59. GNUNET_TIME_absolute_get_duration (p->start_time);
  60. pi->value.publish.anonymity = p->bo.anonymity_level;
  61. pi->fsh = pc->h;
  62. return pc->h->upcb (pc->h->upcb_cls, pi);
  63. }
  64. /**
  65. * Cleanup the publish context, we're done with it.
  66. *
  67. * @param pc struct to clean up
  68. */
  69. static void
  70. publish_cleanup (struct GNUNET_FS_PublishContext *pc)
  71. {
  72. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  73. "Cleaning up publish context (done!)\n");
  74. if (NULL != pc->fhc)
  75. {
  76. GNUNET_CRYPTO_hash_file_cancel (pc->fhc);
  77. pc->fhc = NULL;
  78. }
  79. GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL);
  80. GNUNET_free_non_null (pc->nid);
  81. GNUNET_free_non_null (pc->nuid);
  82. GNUNET_free_non_null (pc->serialization);
  83. if (NULL != pc->dsh)
  84. {
  85. GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO);
  86. pc->dsh = NULL;
  87. }
  88. if (NULL != pc->mq)
  89. {
  90. GNUNET_MQ_destroy (pc->mq);
  91. pc->mq = NULL;
  92. }
  93. GNUNET_assert (NULL == pc->upload_task);
  94. GNUNET_free (pc);
  95. }
  96. /**
  97. * Function called by the datastore API with
  98. * the result from the PUT request.
  99. *
  100. * @param cls the `struct GNUNET_FS_PublishContext *`
  101. * @param success #GNUNET_OK on success
  102. * @param min_expiration minimum expiration time required for content to be stored
  103. * @param msg error message (or NULL)
  104. */
  105. static void
  106. ds_put_cont (void *cls,
  107. int success,
  108. struct GNUNET_TIME_Absolute min_expiration,
  109. const char *msg)
  110. {
  111. struct GNUNET_FS_PublishContext *pc = cls;
  112. struct GNUNET_FS_ProgressInfo pi;
  113. pc->qre = NULL;
  114. if (GNUNET_SYSERR == success)
  115. {
  116. GNUNET_asprintf (&pc->fi_pos->emsg,
  117. _ ("Publishing failed: %s"),
  118. msg);
  119. pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
  120. pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
  121. pi.value.publish.specifics.error.message = pc->fi_pos->emsg;
  122. pc->fi_pos->client_info =
  123. GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi_pos, 0);
  124. if ((GNUNET_YES != pc->fi_pos->is_directory) &&
  125. (NULL != pc->fi_pos->filename) &&
  126. (GNUNET_YES == pc->any_done) &&
  127. (GNUNET_YES == pc->fi_pos->data.file.do_index))
  128. {
  129. /* run unindex to clean up */
  130. GNUNET_FS_unindex_start (pc->h,
  131. pc->fi_pos->filename,
  132. NULL);
  133. }
  134. return;
  135. }
  136. pc->any_done = GNUNET_YES;
  137. GNUNET_assert (NULL == pc->upload_task);
  138. pc->upload_task =
  139. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
  140. &GNUNET_FS_publish_main_, pc);
  141. }
  142. /**
  143. * Generate the callback that signals clients
  144. * that a file (or directory) has been completely
  145. * published.
  146. *
  147. * @param p the completed upload
  148. * @param pc context of the publication
  149. */
  150. static void
  151. signal_publish_completion (struct GNUNET_FS_FileInformation *p,
  152. struct GNUNET_FS_PublishContext *pc)
  153. {
  154. struct GNUNET_FS_ProgressInfo pi;
  155. pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED;
  156. pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO;
  157. pi.value.publish.specifics.completed.chk_uri = p->chk_uri;
  158. pi.value.publish.specifics.completed.sks_uri = p->sks_uri;
  159. p->client_info =
  160. GNUNET_FS_publish_make_status_ (&pi, pc, p,
  161. p->data.file.file_size);
  162. }
  163. /**
  164. * Generate the callback that signals clients
  165. * that a file (or directory) has encountered
  166. * a problem during publication.
  167. *
  168. * @param p the upload that had trouble
  169. * @param pc context of the publication
  170. * @param emsg error message
  171. */
  172. static void
  173. signal_publish_error (struct GNUNET_FS_FileInformation *p,
  174. struct GNUNET_FS_PublishContext *pc,
  175. const char *emsg)
  176. {
  177. struct GNUNET_FS_ProgressInfo pi;
  178. p->emsg = GNUNET_strdup (emsg);
  179. pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
  180. pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
  181. pi.value.publish.specifics.error.message = emsg;
  182. p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0);
  183. if ((p->is_directory != GNUNET_YES) &&
  184. (NULL != p->filename) &&
  185. (GNUNET_YES == pc->any_done) &&
  186. (p->data.file.do_index == GNUNET_YES))
  187. {
  188. /* run unindex to clean up */
  189. GNUNET_FS_unindex_start (pc->h,
  190. p->filename,
  191. NULL);
  192. }
  193. }
  194. /**
  195. * Datastore returns from reservation cancel request.
  196. *
  197. * @param cls the `struct GNUNET_FS_PublishContext *`
  198. * @param success success code (not used)
  199. * @param min_expiration minimum expiration time required for content to be stored
  200. * @param msg error message (typically NULL, not used)
  201. */
  202. static void
  203. finish_release_reserve (void *cls, int success,
  204. struct GNUNET_TIME_Absolute min_expiration,
  205. const char *msg)
  206. {
  207. struct GNUNET_FS_PublishContext *pc = cls;
  208. pc->qre = NULL;
  209. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  210. "Releasing reserve done!\n");
  211. signal_publish_completion (pc->fi, pc);
  212. pc->all_done = GNUNET_YES;
  213. GNUNET_FS_publish_sync_ (pc);
  214. }
  215. /**
  216. * We've finished publishing the SBlock as part of a larger upload.
  217. * Check the result and complete the larger upload.
  218. *
  219. * @param cls the `struct GNUNET_FS_PublishContext *` of the larger upload
  220. * @param uri URI of the published SBlock
  221. * @param emsg NULL on success, otherwise error message
  222. */
  223. static void
  224. publish_sblocks_cont (void *cls,
  225. const struct GNUNET_FS_Uri *uri,
  226. const char *emsg)
  227. {
  228. struct GNUNET_FS_PublishContext *pc = cls;
  229. pc->sks_pc = NULL;
  230. if (NULL != emsg)
  231. {
  232. signal_publish_error (pc->fi, pc, emsg);
  233. GNUNET_FS_publish_sync_ (pc);
  234. return;
  235. }
  236. if (NULL != uri)
  237. {
  238. /* sks publication, remember namespace URI */
  239. pc->fi->sks_uri = GNUNET_FS_uri_dup (uri);
  240. }
  241. GNUNET_assert (pc->qre == NULL);
  242. if ((pc->dsh != NULL) && (pc->rid != 0))
  243. {
  244. pc->qre =
  245. GNUNET_DATASTORE_release_reserve (pc->dsh, pc->rid, UINT_MAX, UINT_MAX,
  246. &finish_release_reserve, pc);
  247. }
  248. else
  249. {
  250. finish_release_reserve (pc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL);
  251. }
  252. }
  253. /**
  254. * We are almost done publishing the structure,
  255. * add SBlocks (if needed).
  256. *
  257. * @param pc overall upload data
  258. */
  259. static void
  260. publish_sblock (struct GNUNET_FS_PublishContext *pc)
  261. {
  262. if (NULL != pc->ns)
  263. pc->sks_pc = GNUNET_FS_publish_sks (pc->h,
  264. pc->ns,
  265. pc->nid,
  266. pc->nuid,
  267. pc->fi->meta,
  268. pc->fi->chk_uri,
  269. &pc->fi->bo,
  270. pc->options,
  271. &publish_sblocks_cont, pc);
  272. else
  273. publish_sblocks_cont (pc, NULL, NULL);
  274. }
  275. /**
  276. * We've finished publishing a KBlock as part of a larger upload.
  277. * Check the result and continue the larger upload.
  278. *
  279. * @param cls the `struct GNUNET_FS_PublishContext *`
  280. * of the larger upload
  281. * @param uri URI of the published blocks
  282. * @param emsg NULL on success, otherwise error message
  283. */
  284. static void
  285. publish_kblocks_cont (void *cls,
  286. const struct GNUNET_FS_Uri *uri,
  287. const char *emsg)
  288. {
  289. struct GNUNET_FS_PublishContext *pc = cls;
  290. struct GNUNET_FS_FileInformation *p = pc->fi_pos;
  291. pc->ksk_pc = NULL;
  292. if (NULL != emsg)
  293. {
  294. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  295. "Error uploading KSK blocks: %s\n",
  296. emsg);
  297. signal_publish_error (p, pc, emsg);
  298. GNUNET_FS_file_information_sync_ (p);
  299. GNUNET_FS_publish_sync_ (pc);
  300. GNUNET_assert (NULL == pc->upload_task);
  301. pc->upload_task =
  302. GNUNET_SCHEDULER_add_with_priority
  303. (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
  304. &GNUNET_FS_publish_main_,
  305. pc);
  306. return;
  307. }
  308. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  309. "KSK blocks published, moving on to next file\n");
  310. if (NULL != p->dir)
  311. signal_publish_completion (p, pc);
  312. /* move on to next file */
  313. if (NULL != p->next)
  314. pc->fi_pos = p->next;
  315. else
  316. pc->fi_pos = p->dir;
  317. GNUNET_FS_publish_sync_ (pc);
  318. GNUNET_assert (NULL == pc->upload_task);
  319. pc->upload_task =
  320. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
  321. &GNUNET_FS_publish_main_, pc);
  322. }
  323. /**
  324. * Function called by the tree encoder to obtain
  325. * a block of plaintext data (for the lowest level
  326. * of the tree).
  327. *
  328. * @param cls our publishing context
  329. * @param offset identifies which block to get
  330. * @param max (maximum) number of bytes to get; returning
  331. * fewer will also cause errors
  332. * @param buf where to copy the plaintext buffer
  333. * @param emsg location to store an error message (on error)
  334. * @return number of bytes copied to buf, 0 on error
  335. */
  336. static size_t
  337. block_reader (void *cls,
  338. uint64_t offset,
  339. size_t max,
  340. void *buf,
  341. char **emsg)
  342. {
  343. struct GNUNET_FS_PublishContext *pc = cls;
  344. struct GNUNET_FS_FileInformation *p;
  345. const char *dd;
  346. size_t pt_size;
  347. p = pc->fi_pos;
  348. if (GNUNET_YES == p->is_directory)
  349. {
  350. pt_size = GNUNET_MIN (max, p->data.dir.dir_size - offset);
  351. dd = p->data.dir.dir_data;
  352. GNUNET_memcpy (buf, &dd[offset], pt_size);
  353. }
  354. else
  355. {
  356. if (UINT64_MAX == offset)
  357. {
  358. if (&GNUNET_FS_data_reader_file_ == p->data.file.reader)
  359. {
  360. /* force closing the file to avoid keeping too many files open */
  361. p->data.file.reader (p->data.file.reader_cls, offset, 0, NULL, NULL);
  362. }
  363. return 0;
  364. }
  365. pt_size = GNUNET_MIN (max, p->data.file.file_size - offset);
  366. if (0 == pt_size)
  367. return 0; /* calling reader with pt_size==0
  368. * might free buf, so don't! */
  369. if (pt_size !=
  370. p->data.file.reader (p->data.file.reader_cls, offset, pt_size, buf,
  371. emsg))
  372. return 0;
  373. }
  374. return pt_size;
  375. }
  376. /**
  377. * The tree encoder has finished processing a
  378. * file. Call it's finish method and deal with
  379. * the final result.
  380. *
  381. * @param cls our publishing context
  382. */
  383. static void
  384. encode_cont (void *cls)
  385. {
  386. struct GNUNET_FS_PublishContext *pc = cls;
  387. struct GNUNET_FS_FileInformation *p;
  388. struct GNUNET_FS_ProgressInfo pi;
  389. char *emsg;
  390. uint64_t flen;
  391. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  392. "Finished with tree encoder\n");
  393. p = pc->fi_pos;
  394. p->chk_uri = GNUNET_FS_tree_encoder_get_uri (p->te);
  395. GNUNET_FS_file_information_sync_ (p);
  396. GNUNET_FS_tree_encoder_finish (p->te, &emsg);
  397. p->te = NULL;
  398. if (NULL != emsg)
  399. {
  400. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  401. "Error during tree walk: %s\n",
  402. emsg);
  403. GNUNET_asprintf (&p->emsg,
  404. _ ("Publishing failed: %s"),
  405. emsg);
  406. GNUNET_free (emsg);
  407. pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
  408. pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
  409. pi.value.publish.specifics.error.message = p->emsg;
  410. p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0);
  411. }
  412. else
  413. {
  414. /* final progress event */
  415. GNUNET_assert (NULL != p->chk_uri);
  416. flen = GNUNET_FS_uri_chk_get_file_size (p->chk_uri);
  417. pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS;
  418. pi.value.publish.specifics.progress.data = NULL;
  419. pi.value.publish.specifics.progress.offset = flen;
  420. pi.value.publish.specifics.progress.data_len = 0;
  421. pi.value.publish.specifics.progress.depth = GNUNET_FS_compute_depth (flen);
  422. p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, flen);
  423. }
  424. /* continue with main */ /* continue with main */
  425. GNUNET_assert (NULL == pc->upload_task);
  426. pc->upload_task =
  427. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
  428. &GNUNET_FS_publish_main_, pc);
  429. }
  430. /**
  431. * Function called asking for the current (encoded)
  432. * block to be processed. After processing the
  433. * client should either call #GNUNET_FS_tree_encoder_next
  434. * or (on error) #GNUNET_FS_tree_encoder_finish.
  435. *
  436. * @param cls closure
  437. * @param chk content hash key for the block
  438. * @param offset offset of the block in the file
  439. * @param depth depth of the block in the file, 0 for DBLOCK
  440. * @param type type of the block (IBLOCK or DBLOCK)
  441. * @param block the (encrypted) block
  442. * @param block_size size of @a block (in bytes)
  443. */
  444. static void
  445. block_proc (void *cls,
  446. const struct ContentHashKey *chk,
  447. uint64_t offset,
  448. unsigned int depth,
  449. enum GNUNET_BLOCK_Type type,
  450. const void *block,
  451. uint16_t block_size)
  452. {
  453. struct GNUNET_FS_PublishContext *pc = cls;
  454. struct GNUNET_FS_FileInformation *p;
  455. struct OnDemandBlock odb;
  456. p = pc->fi_pos;
  457. if (NULL == pc->dsh)
  458. {
  459. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  460. "Waiting for datastore connection\n");
  461. GNUNET_assert (NULL == pc->upload_task);
  462. pc->upload_task =
  463. GNUNET_SCHEDULER_add_with_priority
  464. (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc);
  465. return;
  466. }
  467. if ((GNUNET_YES != p->is_directory) &&
  468. (GNUNET_YES == p->data.file.do_index) &&
  469. (GNUNET_BLOCK_TYPE_FS_DBLOCK == type))
  470. {
  471. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  472. "Indexing block `%s' for offset %llu with index size %u\n",
  473. GNUNET_h2s (&chk->query),
  474. (unsigned long long) offset,
  475. (unsigned int) sizeof(struct OnDemandBlock));
  476. odb.offset = GNUNET_htonll (offset);
  477. odb.file_id = p->data.file.file_id;
  478. GNUNET_assert (pc->qre == NULL);
  479. pc->qre =
  480. GNUNET_DATASTORE_put (pc->dsh,
  481. (p->is_directory == GNUNET_YES) ? 0 : pc->rid,
  482. &chk->query,
  483. sizeof(struct OnDemandBlock),
  484. &odb,
  485. GNUNET_BLOCK_TYPE_FS_ONDEMAND,
  486. p->bo.content_priority,
  487. p->bo.anonymity_level,
  488. p->bo.replication_level,
  489. p->bo.expiration_time,
  490. -2, 1,
  491. &ds_put_cont, pc);
  492. return;
  493. }
  494. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  495. "Publishing block `%s' for offset %llu with size %u\n",
  496. GNUNET_h2s (&chk->query),
  497. (unsigned long long) offset,
  498. (unsigned int) block_size);
  499. GNUNET_assert (pc->qre == NULL);
  500. pc->qre =
  501. GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 :
  502. pc->rid,
  503. &chk->query,
  504. block_size,
  505. block,
  506. type,
  507. p->bo.content_priority,
  508. p->bo.anonymity_level,
  509. p->bo.replication_level,
  510. p->bo.expiration_time,
  511. -2, 1,
  512. &ds_put_cont,
  513. pc);
  514. }
  515. /**
  516. * Function called with information about our
  517. * progress in computing the tree encoding.
  518. *
  519. * @param cls closure
  520. * @param offset where are we in the file
  521. * @param pt_block plaintext of the currently processed block
  522. * @param pt_size size of @a pt_block
  523. * @param depth depth of the block in the tree, 0 for DBLOCK
  524. */
  525. static void
  526. progress_proc (void *cls, uint64_t offset,
  527. const void *pt_block,
  528. size_t pt_size,
  529. unsigned int depth)
  530. {
  531. struct GNUNET_FS_PublishContext *pc = cls;
  532. struct GNUNET_FS_FileInformation *p;
  533. struct GNUNET_FS_FileInformation *par;
  534. struct GNUNET_FS_ProgressInfo pi;
  535. p = pc->fi_pos;
  536. pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS;
  537. pi.value.publish.specifics.progress.data = pt_block;
  538. pi.value.publish.specifics.progress.offset = offset;
  539. pi.value.publish.specifics.progress.data_len = pt_size;
  540. pi.value.publish.specifics.progress.depth = depth;
  541. p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, offset);
  542. if ((0 != depth) ||
  543. (GNUNET_YES == p->is_directory))
  544. return;
  545. while (NULL != (par = p->dir))
  546. {
  547. p = par;
  548. GNUNET_assert (GNUNET_YES == par->is_directory);
  549. p->data.dir.contents_completed += pt_size;
  550. pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY;
  551. pi.value.publish.specifics.progress_directory.completed =
  552. p->data.dir.contents_completed;
  553. pi.value.publish.specifics.progress_directory.total =
  554. p->data.dir.contents_size;
  555. pi.value.publish.specifics.progress_directory.eta =
  556. GNUNET_TIME_calculate_eta (p->start_time,
  557. p
  558. ->data.dir.contents_completed,
  559. p
  560. ->data.dir.contents_size);
  561. p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0);
  562. }
  563. }
  564. /**
  565. * We are uploading a file or directory; load (if necessary) the next
  566. * block into memory, encrypt it and send it to the FS service. Then
  567. * continue with the main task.
  568. *
  569. * @param pc overall upload data
  570. */
  571. static void
  572. publish_content (struct GNUNET_FS_PublishContext *pc)
  573. {
  574. struct GNUNET_FS_FileInformation *p;
  575. char *emsg;
  576. struct GNUNET_FS_DirectoryBuilder *db;
  577. struct GNUNET_FS_FileInformation *dirpos;
  578. void *raw_data;
  579. uint64_t size;
  580. p = pc->fi_pos;
  581. GNUNET_assert (NULL != p);
  582. if (NULL == p->te)
  583. {
  584. if (GNUNET_YES == p->is_directory)
  585. {
  586. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating directory\n");
  587. db = GNUNET_FS_directory_builder_create (p->meta);
  588. dirpos = p->data.dir.entries;
  589. while (NULL != dirpos)
  590. {
  591. if (GNUNET_YES == dirpos->is_directory)
  592. {
  593. raw_data = dirpos->data.dir.dir_data;
  594. dirpos->data.dir.dir_data = NULL;
  595. }
  596. else
  597. {
  598. raw_data = NULL;
  599. if ((dirpos->data.file.file_size < MAX_INLINE_SIZE) &&
  600. (dirpos->data.file.file_size > 0))
  601. {
  602. raw_data = GNUNET_malloc (dirpos->data.file.file_size);
  603. emsg = NULL;
  604. if (dirpos->data.file.file_size !=
  605. dirpos->data.file.reader (dirpos->data.file.reader_cls, 0,
  606. dirpos->data.file.file_size, raw_data,
  607. &emsg))
  608. {
  609. GNUNET_free_non_null (emsg);
  610. GNUNET_free (raw_data);
  611. raw_data = NULL;
  612. }
  613. dirpos->data.file.reader (dirpos->data.file.reader_cls, UINT64_MAX,
  614. 0, 0, NULL);
  615. }
  616. }
  617. GNUNET_FS_directory_builder_add (db, dirpos->chk_uri, dirpos->meta,
  618. raw_data);
  619. GNUNET_free_non_null (raw_data);
  620. dirpos = dirpos->next;
  621. }
  622. GNUNET_free_non_null (p->data.dir.dir_data);
  623. p->data.dir.dir_data = NULL;
  624. p->data.dir.dir_size = 0;
  625. GNUNET_FS_directory_builder_finish (db, &p->data.dir.dir_size,
  626. &p->data.dir.dir_data);
  627. GNUNET_FS_file_information_sync_ (p);
  628. }
  629. size = (GNUNET_YES == p->is_directory) ? p->data.dir.dir_size :
  630. p->data.file.file_size;
  631. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  632. "Creating tree encoder\n");
  633. p->te =
  634. GNUNET_FS_tree_encoder_create (pc->h, size, pc, &block_reader,
  635. &block_proc, &progress_proc,
  636. &encode_cont);
  637. }
  638. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  639. "Processing next block from tree\n");
  640. GNUNET_FS_tree_encoder_next (p->te);
  641. }
  642. /**
  643. * Check the response from the "fs" service to our 'start index'
  644. * request.
  645. *
  646. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  647. * @param msg the response we got
  648. */
  649. static int
  650. check_index_start_failed (void *cls,
  651. const struct GNUNET_MessageHeader *msg)
  652. {
  653. size_t msize = ntohs (msg->size) - sizeof(*msg);
  654. const char *emsg = (const char *) &msg[1];
  655. if (emsg[msize - sizeof(struct GNUNET_MessageHeader) - 1] != '\0')
  656. {
  657. GNUNET_break (0);
  658. return GNUNET_SYSERR;
  659. }
  660. return GNUNET_OK;
  661. }
  662. /**
  663. * Process the response from the "fs" service to our 'start index'
  664. * request.
  665. *
  666. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  667. * @param msg the response we got
  668. */
  669. static void
  670. handle_index_start_failed (void *cls,
  671. const struct GNUNET_MessageHeader *msg)
  672. {
  673. struct GNUNET_FS_PublishContext *pc = cls;
  674. struct GNUNET_FS_FileInformation *p;
  675. const char *emsg = (const char *) &msg[1];
  676. char *msgtxt;
  677. GNUNET_MQ_destroy (pc->mq);
  678. pc->mq = NULL;
  679. p = pc->fi_pos;
  680. GNUNET_asprintf (&msgtxt,
  681. _ ("Can not index file `%s': %s.\n"),
  682. p->filename,
  683. gettext (emsg));
  684. signal_publish_error (p,
  685. pc,
  686. msgtxt);
  687. GNUNET_free (msgtxt);
  688. GNUNET_FS_file_information_sync_ (p);
  689. GNUNET_FS_publish_sync_ (pc);
  690. }
  691. /**
  692. * Process the response from the "fs" service to our 'start index'
  693. * request.
  694. *
  695. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  696. * @param msg the response we got
  697. */
  698. static void
  699. handle_index_start_ok (void *cls,
  700. const struct GNUNET_MessageHeader *msg)
  701. {
  702. struct GNUNET_FS_PublishContext *pc = cls;
  703. struct GNUNET_FS_FileInformation *p;
  704. GNUNET_MQ_destroy (pc->mq);
  705. pc->mq = NULL;
  706. p = pc->fi_pos;
  707. p->data.file.index_start_confirmed = GNUNET_YES;
  708. GNUNET_FS_file_information_sync_ (p);
  709. publish_content (pc);
  710. }
  711. /**
  712. * Generic error handler, called with the appropriate error code and
  713. * the same closure specified at the creation of the message queue.
  714. * Not every message queue implementation supports an error handler.
  715. *
  716. * @param cls closure with the `struct GNUNET_FS_PublishContext *`
  717. * @param error error code
  718. */
  719. static void
  720. index_mq_error_handler (void *cls,
  721. enum GNUNET_MQ_Error error)
  722. {
  723. struct GNUNET_FS_PublishContext *pc = cls;
  724. struct GNUNET_FS_FileInformation *p;
  725. if (NULL != pc->mq)
  726. {
  727. GNUNET_MQ_destroy (pc->mq);
  728. pc->mq = NULL;
  729. }
  730. p = pc->fi_pos;
  731. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  732. _ ("Can not index file `%s': %s. Will try to insert instead.\n"),
  733. p->filename,
  734. _ ("error on index-start request to `fs' service"));
  735. p->data.file.do_index = GNUNET_NO;
  736. GNUNET_FS_file_information_sync_ (p);
  737. publish_content (pc);
  738. }
  739. /**
  740. * Function called once the hash computation over an
  741. * indexed file has completed.
  742. *
  743. * @param cls closure, our publishing context
  744. * @param res resulting hash, NULL on error
  745. */
  746. static void
  747. hash_for_index_cb (void *cls,
  748. const struct GNUNET_HashCode *res)
  749. {
  750. struct GNUNET_FS_PublishContext *pc = cls;
  751. struct GNUNET_MQ_MessageHandler handlers[] = {
  752. GNUNET_MQ_hd_fixed_size (index_start_ok,
  753. GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK,
  754. struct GNUNET_MessageHeader,
  755. pc),
  756. GNUNET_MQ_hd_var_size (index_start_failed,
  757. GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED,
  758. struct GNUNET_MessageHeader,
  759. pc),
  760. GNUNET_MQ_handler_end ()
  761. };
  762. struct GNUNET_FS_FileInformation *p;
  763. struct GNUNET_MQ_Envelope *env;
  764. struct IndexStartMessage *ism;
  765. size_t slen;
  766. uint64_t dev;
  767. uint64_t ino;
  768. char *fn;
  769. pc->fhc = NULL;
  770. p = pc->fi_pos;
  771. if (NULL == res)
  772. {
  773. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  774. _ (
  775. "Can not index file `%s': %s. Will try to insert instead.\n"),
  776. p->filename,
  777. _ ("failed to compute hash"));
  778. p->data.file.do_index = GNUNET_NO;
  779. GNUNET_FS_file_information_sync_ (p);
  780. publish_content (pc);
  781. return;
  782. }
  783. if (GNUNET_YES == p->data.file.index_start_confirmed)
  784. {
  785. publish_content (pc);
  786. return;
  787. }
  788. fn = GNUNET_STRINGS_filename_expand (p->filename);
  789. GNUNET_assert (fn != NULL);
  790. slen = strlen (fn) + 1;
  791. if (slen >=
  792. GNUNET_MAX_MESSAGE_SIZE - sizeof(struct IndexStartMessage))
  793. {
  794. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  795. _
  796. ("Can not index file `%s': %s. Will try to insert instead.\n"),
  797. fn, _ ("filename too long"));
  798. GNUNET_free (fn);
  799. p->data.file.do_index = GNUNET_NO;
  800. GNUNET_FS_file_information_sync_ (p);
  801. publish_content (pc);
  802. return;
  803. }
  804. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  805. "Hash of indexed file `%s' is `%s'\n",
  806. p->filename,
  807. GNUNET_h2s (res));
  808. if (0 != (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
  809. {
  810. p->data.file.file_id = *res;
  811. p->data.file.have_hash = GNUNET_YES;
  812. p->data.file.index_start_confirmed = GNUNET_YES;
  813. GNUNET_FS_file_information_sync_ (p);
  814. publish_content (pc);
  815. GNUNET_free (fn);
  816. return;
  817. }
  818. pc->mq = GNUNET_CLIENT_connect (pc->h->cfg,
  819. "fs",
  820. handlers,
  821. &index_mq_error_handler,
  822. pc);
  823. if (NULL == pc->mq)
  824. {
  825. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  826. _ (
  827. "Can not index file `%s': %s. Will try to insert instead.\n"),
  828. p->filename,
  829. _ ("could not connect to `fs' service"));
  830. p->data.file.do_index = GNUNET_NO;
  831. publish_content (pc);
  832. GNUNET_free (fn);
  833. return;
  834. }
  835. if (p->data.file.have_hash != GNUNET_YES)
  836. {
  837. p->data.file.file_id = *res;
  838. p->data.file.have_hash = GNUNET_YES;
  839. GNUNET_FS_file_information_sync_ (p);
  840. }
  841. env = GNUNET_MQ_msg_extra (ism,
  842. slen,
  843. GNUNET_MESSAGE_TYPE_FS_INDEX_START);
  844. if (GNUNET_OK ==
  845. GNUNET_DISK_file_get_identifiers (p->filename,
  846. &dev,
  847. &ino))
  848. {
  849. ism->device = GNUNET_htonll (dev);
  850. ism->inode = GNUNET_htonll (ino);
  851. }
  852. else
  853. {
  854. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  855. _ ("Failed to get file identifiers for `%s'\n"),
  856. p->filename);
  857. }
  858. ism->file_id = *res;
  859. GNUNET_memcpy (&ism[1],
  860. fn,
  861. slen);
  862. GNUNET_free (fn);
  863. GNUNET_MQ_send (pc->mq,
  864. env);
  865. }
  866. /**
  867. * We've computed the CHK/LOC URI, now publish the KSKs (if applicable).
  868. *
  869. * @param pc publishing context to do this for
  870. */
  871. static void
  872. publish_kblocks (struct GNUNET_FS_PublishContext *pc)
  873. {
  874. struct GNUNET_FS_FileInformation *p;
  875. p = pc->fi_pos;
  876. /* upload of "p" complete, publish KBlocks! */
  877. if (NULL != p->keywords)
  878. {
  879. pc->ksk_pc = GNUNET_FS_publish_ksk (pc->h,
  880. p->keywords,
  881. p->meta,
  882. p->chk_uri,
  883. &p->bo,
  884. pc->options,
  885. &publish_kblocks_cont,
  886. pc);
  887. }
  888. else
  889. {
  890. publish_kblocks_cont (pc, p->chk_uri, NULL);
  891. }
  892. }
  893. /**
  894. * Process the response from the "fs" service to our LOC sign request.
  895. *
  896. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  897. * @param sig the response we got
  898. */
  899. static void
  900. handle_signature_response (void *cls,
  901. const struct ResponseLocSignatureMessage *sig)
  902. {
  903. struct GNUNET_FS_PublishContext *pc = cls;
  904. struct GNUNET_FS_FileInformation *p;
  905. p = pc->fi_pos;
  906. p->chk_uri->type = GNUNET_FS_URI_LOC;
  907. /* p->data.loc.fi kept from CHK before */
  908. p->chk_uri->data.loc.peer = sig->peer;
  909. p->chk_uri->data.loc.expirationTime
  910. = GNUNET_TIME_absolute_ntoh (sig->expiration_time);
  911. p->chk_uri->data.loc.contentSignature = sig->signature;
  912. GNUNET_FS_file_information_sync_ (p);
  913. GNUNET_FS_publish_sync_ (pc);
  914. publish_kblocks (pc);
  915. }
  916. /**
  917. * Generic error handler, called with the appropriate error code and
  918. * the same closure specified at the creation of the message queue.
  919. * Not every message queue implementation supports an error handler.
  920. *
  921. * @param cls closure with the `struct GNUNET_FS_PublishContext *`
  922. * @param error error code
  923. */
  924. static void
  925. loc_mq_error_handler (void *cls,
  926. enum GNUNET_MQ_Error error)
  927. {
  928. struct GNUNET_FS_PublishContext *pc = cls;
  929. if (NULL != pc->mq)
  930. {
  931. GNUNET_MQ_destroy (pc->mq);
  932. pc->mq = NULL;
  933. }
  934. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  935. _ ("Can not create LOC URI. Will continue with CHK instead.\n"));
  936. publish_kblocks (pc);
  937. }
  938. /**
  939. * We're publishing without anonymity. Contact the FS service
  940. * to create a signed LOC URI for further processing, then
  941. * continue with KSKs.
  942. *
  943. * @param pc the publishing context do to this for
  944. */
  945. static void
  946. create_loc_uri (struct GNUNET_FS_PublishContext *pc)
  947. {
  948. struct GNUNET_MQ_MessageHandler handlers[] = {
  949. GNUNET_MQ_hd_fixed_size (signature_response,
  950. GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE,
  951. struct ResponseLocSignatureMessage,
  952. pc),
  953. GNUNET_MQ_handler_end ()
  954. };
  955. struct GNUNET_MQ_Envelope *env;
  956. struct RequestLocSignatureMessage *req;
  957. struct GNUNET_FS_FileInformation *p;
  958. if (NULL != pc->mq)
  959. GNUNET_MQ_destroy (pc->mq);
  960. pc->mq = GNUNET_CLIENT_connect (pc->h->cfg,
  961. "fs",
  962. handlers,
  963. &loc_mq_error_handler,
  964. pc);
  965. if (NULL == pc->mq)
  966. {
  967. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  968. _ (
  969. "Can not create LOC URI. Will continue with CHK instead.\n"));
  970. publish_kblocks (pc);
  971. return;
  972. }
  973. p = pc->fi_pos;
  974. env = GNUNET_MQ_msg (req,
  975. GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN);
  976. req->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
  977. req->expiration_time = GNUNET_TIME_absolute_hton (p->bo.expiration_time);
  978. req->chk = p->chk_uri->data.chk.chk;
  979. req->file_length = GNUNET_htonll (p->chk_uri->data.chk.file_length);
  980. GNUNET_MQ_send (pc->mq,
  981. env);
  982. }
  983. /**
  984. * Main function that performs the upload.
  985. *
  986. * @param cls `struct GNUNET_FS_PublishContext *` identifies the upload
  987. */
  988. void
  989. GNUNET_FS_publish_main_ (void *cls)
  990. {
  991. struct GNUNET_FS_PublishContext *pc = cls;
  992. struct GNUNET_FS_ProgressInfo pi;
  993. struct GNUNET_FS_FileInformation *p;
  994. char *fn;
  995. pc->upload_task = NULL;
  996. p = pc->fi_pos;
  997. if (NULL == p)
  998. {
  999. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1000. "Publishing complete, now publishing SKS and KSK blocks.\n");
  1001. /* upload of entire hierarchy complete,
  1002. * publish namespace entries */
  1003. GNUNET_FS_publish_sync_ (pc);
  1004. publish_sblock (pc);
  1005. return;
  1006. }
  1007. /* find starting position */
  1008. while ((GNUNET_YES == p->is_directory) &&
  1009. (NULL != p->data.dir.entries) &&
  1010. (NULL == p->emsg) &&
  1011. (NULL == p->data.dir.entries->chk_uri))
  1012. {
  1013. p = p->data.dir.entries;
  1014. pc->fi_pos = p;
  1015. GNUNET_FS_publish_sync_ (pc);
  1016. }
  1017. /* abort on error */
  1018. if (NULL != p->emsg)
  1019. {
  1020. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1021. "Error uploading: %s\n",
  1022. p->emsg);
  1023. /* error with current file, abort all
  1024. * related files as well! */
  1025. while (NULL != p->dir)
  1026. {
  1027. fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta,
  1028. EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
  1029. p = p->dir;
  1030. if (fn != NULL)
  1031. {
  1032. GNUNET_asprintf (&p->emsg,
  1033. _ ("Recursive upload failed at `%s': %s"),
  1034. fn,
  1035. p->emsg);
  1036. GNUNET_free (fn);
  1037. }
  1038. else
  1039. {
  1040. GNUNET_asprintf (&p->emsg,
  1041. _ ("Recursive upload failed: %s"),
  1042. p->emsg);
  1043. }
  1044. pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
  1045. pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
  1046. pi.value.publish.specifics.error.message = p->emsg;
  1047. p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0);
  1048. }
  1049. pc->all_done = GNUNET_YES;
  1050. GNUNET_FS_publish_sync_ (pc);
  1051. return;
  1052. }
  1053. /* handle completion */
  1054. if (NULL != p->chk_uri)
  1055. {
  1056. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1057. "File upload complete, now publishing KSK blocks.\n");
  1058. GNUNET_FS_publish_sync_ (pc);
  1059. if ((0 == p->bo.anonymity_level) &&
  1060. (GNUNET_YES !=
  1061. GNUNET_FS_uri_test_loc (p->chk_uri)))
  1062. {
  1063. /* zero anonymity, box CHK URI in LOC URI */
  1064. create_loc_uri (pc);
  1065. }
  1066. else
  1067. {
  1068. publish_kblocks (pc);
  1069. }
  1070. return;
  1071. }
  1072. if ((GNUNET_YES != p->is_directory) && (p->data.file.do_index))
  1073. {
  1074. if (NULL == p->filename)
  1075. {
  1076. p->data.file.do_index = GNUNET_NO;
  1077. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1078. _ (
  1079. "Can not index file `%s': %s. Will try to insert instead.\n"),
  1080. "<no-name>",
  1081. _ ("needs to be an actual file"));
  1082. GNUNET_FS_file_information_sync_ (p);
  1083. publish_content (pc);
  1084. return;
  1085. }
  1086. if (p->data.file.have_hash)
  1087. {
  1088. hash_for_index_cb (pc, &p->data.file.file_id);
  1089. }
  1090. else
  1091. {
  1092. p->start_time = GNUNET_TIME_absolute_get ();
  1093. pc->fhc =
  1094. GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, p->filename,
  1095. HASHING_BLOCKSIZE, &hash_for_index_cb, pc);
  1096. }
  1097. return;
  1098. }
  1099. publish_content (pc);
  1100. }
  1101. /**
  1102. * Signal the FS's progress function that we are starting
  1103. * an upload.
  1104. *
  1105. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  1106. * @param fi the entry in the publish-structure
  1107. * @param length length of the file or directory
  1108. * @param meta metadata for the file or directory (can be modified)
  1109. * @param uri pointer to the keywords that will be used for this entry (can be modified)
  1110. * @param bo block options
  1111. * @param do_index should we index?
  1112. * @param client_info pointer to client context set upon creation (can be modified)
  1113. * @return #GNUNET_OK to continue (always)
  1114. */
  1115. static int
  1116. fip_signal_start (void *cls,
  1117. struct GNUNET_FS_FileInformation *fi,
  1118. uint64_t length,
  1119. struct GNUNET_CONTAINER_MetaData *meta,
  1120. struct GNUNET_FS_Uri **uri,
  1121. struct GNUNET_FS_BlockOptions *bo,
  1122. int *do_index,
  1123. void **client_info)
  1124. {
  1125. struct GNUNET_FS_PublishContext *pc = cls;
  1126. struct GNUNET_FS_ProgressInfo pi;
  1127. unsigned int kc;
  1128. uint64_t left;
  1129. if (GNUNET_YES == pc->skip_next_fi_callback)
  1130. {
  1131. pc->skip_next_fi_callback = GNUNET_NO;
  1132. return GNUNET_OK;
  1133. }
  1134. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1135. "Starting publish operation\n");
  1136. if (*do_index)
  1137. {
  1138. /* space for on-demand blocks */
  1139. pc->reserve_space +=
  1140. ((length + DBLOCK_SIZE
  1141. - 1) / DBLOCK_SIZE) * sizeof(struct OnDemandBlock);
  1142. }
  1143. else
  1144. {
  1145. /* space for DBlocks */
  1146. pc->reserve_space += length;
  1147. }
  1148. /* entries for IBlocks and DBlocks, space for IBlocks */
  1149. left = length;
  1150. while (1)
  1151. {
  1152. left = (left + DBLOCK_SIZE - 1) / DBLOCK_SIZE;
  1153. pc->reserve_entries += left;
  1154. if (left <= 1)
  1155. break;
  1156. left = left * sizeof(struct ContentHashKey);
  1157. pc->reserve_space += left;
  1158. }
  1159. pc->reserve_entries++;
  1160. /* entries and space for keywords */
  1161. if (NULL != *uri)
  1162. {
  1163. kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri);
  1164. pc->reserve_entries += kc;
  1165. pc->reserve_space += GNUNET_MAX_MESSAGE_SIZE * kc;
  1166. }
  1167. pi.status = GNUNET_FS_STATUS_PUBLISH_START;
  1168. *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0);
  1169. GNUNET_FS_file_information_sync_ (fi);
  1170. if ((fi->is_directory) && (fi->dir != NULL))
  1171. {
  1172. /* We are a directory, and we are not top-level; process entries in directory */
  1173. pc->skip_next_fi_callback = GNUNET_YES;
  1174. GNUNET_FS_file_information_inspect (fi, &fip_signal_start, pc);
  1175. }
  1176. return GNUNET_OK;
  1177. }
  1178. /**
  1179. * Actually signal the FS's progress function that we are suspending
  1180. * an upload.
  1181. *
  1182. * @param fi the entry in the publish-structure
  1183. * @param pc the publish context of which a file is being suspended
  1184. */
  1185. static void
  1186. suspend_operation (struct GNUNET_FS_FileInformation *fi,
  1187. struct GNUNET_FS_PublishContext *pc)
  1188. {
  1189. struct GNUNET_FS_ProgressInfo pi;
  1190. uint64_t off;
  1191. if (NULL != pc->ksk_pc)
  1192. {
  1193. GNUNET_FS_publish_ksk_cancel (pc->ksk_pc);
  1194. pc->ksk_pc = NULL;
  1195. }
  1196. if (NULL != pc->sks_pc)
  1197. {
  1198. GNUNET_FS_publish_sks_cancel (pc->sks_pc);
  1199. pc->sks_pc = NULL;
  1200. }
  1201. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1202. "Suspending publish operation\n");
  1203. GNUNET_free_non_null (fi->serialization);
  1204. fi->serialization = NULL;
  1205. off = (NULL == fi->chk_uri) ? 0 : (GNUNET_YES == fi->is_directory) ?
  1206. fi->data.dir.dir_size : fi->data.file.file_size;
  1207. pi.status = GNUNET_FS_STATUS_PUBLISH_SUSPEND;
  1208. GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off));
  1209. if (NULL != pc->qre)
  1210. {
  1211. GNUNET_DATASTORE_cancel (pc->qre);
  1212. pc->qre = NULL;
  1213. }
  1214. if (NULL != pc->dsh)
  1215. {
  1216. GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO);
  1217. pc->dsh = NULL;
  1218. }
  1219. pc->rid = 0;
  1220. }
  1221. /**
  1222. * Signal the FS's progress function that we are suspending
  1223. * an upload. Performs the recursion.
  1224. *
  1225. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  1226. * @param fi the entry in the publish-structure
  1227. * @param length length of the file or directory
  1228. * @param meta metadata for the file or directory (can be modified)
  1229. * @param uri pointer to the keywords that will be used for this entry (can be modified)
  1230. * @param bo block options
  1231. * @param do_index should we index?
  1232. * @param client_info pointer to client context set upon creation (can be modified)
  1233. * @return #GNUNET_OK to continue (always)
  1234. */
  1235. static int
  1236. fip_signal_suspend (void *cls,
  1237. struct GNUNET_FS_FileInformation *fi,
  1238. uint64_t length,
  1239. struct GNUNET_CONTAINER_MetaData *meta,
  1240. struct GNUNET_FS_Uri **uri,
  1241. struct GNUNET_FS_BlockOptions *bo,
  1242. int *do_index,
  1243. void **client_info)
  1244. {
  1245. struct GNUNET_FS_PublishContext *pc = cls;
  1246. if (GNUNET_YES == pc->skip_next_fi_callback)
  1247. {
  1248. pc->skip_next_fi_callback = GNUNET_NO;
  1249. return GNUNET_OK;
  1250. }
  1251. if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta))
  1252. {
  1253. /* process entries in directory */
  1254. pc->skip_next_fi_callback = GNUNET_YES;
  1255. GNUNET_FS_file_information_inspect (fi, &fip_signal_suspend, pc);
  1256. }
  1257. suspend_operation (fi, pc);
  1258. *client_info = NULL;
  1259. return GNUNET_OK;
  1260. }
  1261. /**
  1262. * Create SUSPEND event for the given publish operation
  1263. * and then clean up our state (without stop signal).
  1264. *
  1265. * @param cls the `struct GNUNET_FS_PublishContext` to signal for
  1266. */
  1267. void
  1268. GNUNET_FS_publish_signal_suspend_ (void *cls)
  1269. {
  1270. struct GNUNET_FS_PublishContext *pc = cls;
  1271. if (NULL != pc->upload_task)
  1272. {
  1273. GNUNET_SCHEDULER_cancel (pc->upload_task);
  1274. pc->upload_task = NULL;
  1275. }
  1276. pc->skip_next_fi_callback = GNUNET_YES;
  1277. GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_suspend, pc);
  1278. suspend_operation (pc->fi, pc);
  1279. GNUNET_FS_end_top (pc->h, pc->top);
  1280. pc->top = NULL;
  1281. publish_cleanup (pc);
  1282. }
  1283. /**
  1284. * We have gotten a reply for our space reservation request.
  1285. * Either fail (insufficient space) or start publishing for good.
  1286. *
  1287. * @param cls the `struct GNUNET_FS_PublishContext *`
  1288. * @param success positive reservation ID on success
  1289. * @param min_expiration minimum expiration time required for content to be stored
  1290. * @param msg error message on error, otherwise NULL
  1291. */
  1292. static void
  1293. finish_reserve (void *cls,
  1294. int success,
  1295. struct GNUNET_TIME_Absolute min_expiration,
  1296. const char *msg)
  1297. {
  1298. struct GNUNET_FS_PublishContext *pc = cls;
  1299. pc->qre = NULL;
  1300. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1301. "Reservation complete (%d)!\n",
  1302. success);
  1303. if ((msg != NULL) || (success <= 0))
  1304. {
  1305. GNUNET_asprintf (&pc->fi->emsg,
  1306. _ ("Datastore failure: %s"),
  1307. msg);
  1308. signal_publish_error (pc->fi, pc, pc->fi->emsg);
  1309. return;
  1310. }
  1311. pc->rid = success;
  1312. GNUNET_assert (NULL == pc->upload_task);
  1313. pc->upload_task =
  1314. GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
  1315. &GNUNET_FS_publish_main_, pc);
  1316. }
  1317. /**
  1318. * Calculate the total size of all of the files in the directory structure.
  1319. *
  1320. * @param fi file structure to traverse
  1321. */
  1322. static uint64_t
  1323. compute_contents_size (struct GNUNET_FS_FileInformation *fi)
  1324. {
  1325. struct GNUNET_FS_FileInformation *ent;
  1326. if (GNUNET_YES != fi->is_directory)
  1327. return fi->data.file.file_size;
  1328. fi->data.dir.contents_size = 0;
  1329. for (ent = fi->data.dir.entries; NULL != ent; ent = ent->next)
  1330. fi->data.dir.contents_size += compute_contents_size (ent);
  1331. return fi->data.dir.contents_size;
  1332. }
  1333. /**
  1334. * Publish a file or directory.
  1335. *
  1336. * @param h handle to the file sharing subsystem
  1337. * @param fi information about the file or directory structure to publish
  1338. * @param ns namespace to publish the file in, NULL for no namespace
  1339. * @param nid identifier to use for the publishd content in the namespace
  1340. * (can be NULL, must be NULL if namespace is NULL)
  1341. * @param nuid update-identifier that will be used for future updates
  1342. * (can be NULL, must be NULL if namespace or nid is NULL)
  1343. * @param options options for the publication
  1344. * @return context that can be used to control the publish operation
  1345. */
  1346. struct GNUNET_FS_PublishContext *
  1347. GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h,
  1348. struct GNUNET_FS_FileInformation *fi,
  1349. const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
  1350. const char *nid,
  1351. const char *nuid,
  1352. enum GNUNET_FS_PublishOptions options)
  1353. {
  1354. struct GNUNET_FS_PublishContext *ret;
  1355. struct GNUNET_DATASTORE_Handle *dsh;
  1356. GNUNET_assert (NULL != h);
  1357. compute_contents_size (fi);
  1358. if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
  1359. {
  1360. dsh = GNUNET_DATASTORE_connect (h->cfg);
  1361. if (NULL == dsh)
  1362. return NULL;
  1363. }
  1364. else
  1365. {
  1366. dsh = NULL;
  1367. }
  1368. ret = GNUNET_new (struct GNUNET_FS_PublishContext);
  1369. ret->dsh = dsh;
  1370. ret->h = h;
  1371. ret->fi = fi;
  1372. if (NULL != ns)
  1373. {
  1374. ret->ns = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
  1375. *ret->ns = *ns;
  1376. GNUNET_assert (NULL != nid);
  1377. ret->nid = GNUNET_strdup (nid);
  1378. if (NULL != nuid)
  1379. ret->nuid = GNUNET_strdup (nuid);
  1380. }
  1381. ret->options = options;
  1382. /* signal start */
  1383. GNUNET_FS_file_information_inspect (ret->fi, &fip_signal_start, ret);
  1384. ret->fi_pos = ret->fi;
  1385. ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, ret);
  1386. GNUNET_FS_publish_sync_ (ret);
  1387. if (NULL != ret->dsh)
  1388. {
  1389. GNUNET_assert (NULL == ret->qre);
  1390. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  1391. _ (
  1392. "Reserving space for %u entries and %llu bytes for publication\n"),
  1393. (unsigned int) ret->reserve_entries,
  1394. (unsigned long long) ret->reserve_space);
  1395. ret->qre =
  1396. GNUNET_DATASTORE_reserve (ret->dsh, ret->reserve_space,
  1397. ret->reserve_entries,
  1398. &finish_reserve,
  1399. ret);
  1400. }
  1401. else
  1402. {
  1403. GNUNET_assert (NULL == ret->upload_task);
  1404. ret->upload_task =
  1405. GNUNET_SCHEDULER_add_with_priority
  1406. (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, ret);
  1407. }
  1408. return ret;
  1409. }
  1410. /**
  1411. * Signal the FS's progress function that we are stopping
  1412. * an upload.
  1413. *
  1414. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`)
  1415. * @param fi the entry in the publish-structure
  1416. * @param length length of the file or directory
  1417. * @param meta metadata for the file or directory (can be modified)
  1418. * @param uri pointer to the keywords that will be used for this entry (can be modified)
  1419. * @param bo block options (can be modified)
  1420. * @param do_index should we index?
  1421. * @param client_info pointer to client context set upon creation (can be modified)
  1422. * @return #GNUNET_OK to continue (always)
  1423. */
  1424. static int
  1425. fip_signal_stop (void *cls,
  1426. struct GNUNET_FS_FileInformation *fi,
  1427. uint64_t length,
  1428. struct GNUNET_CONTAINER_MetaData *meta,
  1429. struct GNUNET_FS_Uri **uri,
  1430. struct GNUNET_FS_BlockOptions *bo,
  1431. int *do_index, void **client_info)
  1432. {
  1433. struct GNUNET_FS_PublishContext *pc = cls;
  1434. struct GNUNET_FS_ProgressInfo pi;
  1435. uint64_t off;
  1436. if (GNUNET_YES == pc->skip_next_fi_callback)
  1437. {
  1438. pc->skip_next_fi_callback = GNUNET_NO;
  1439. return GNUNET_OK;
  1440. }
  1441. if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta))
  1442. {
  1443. /* process entries in directory first */
  1444. pc->skip_next_fi_callback = GNUNET_YES;
  1445. GNUNET_FS_file_information_inspect (fi, &fip_signal_stop, pc);
  1446. }
  1447. if (NULL != fi->serialization)
  1448. {
  1449. GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO,
  1450. fi->serialization);
  1451. GNUNET_free (fi->serialization);
  1452. fi->serialization = NULL;
  1453. }
  1454. off = (fi->chk_uri == NULL) ? 0 : length;
  1455. pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED;
  1456. GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off));
  1457. *client_info = NULL;
  1458. return GNUNET_OK;
  1459. }
  1460. /**
  1461. * Stop an upload. Will abort incomplete uploads (but
  1462. * not remove blocks that have already been publishd) or
  1463. * simply clean up the state for completed uploads.
  1464. * Must NOT be called from within the event callback!
  1465. *
  1466. * @param pc context for the upload to stop
  1467. */
  1468. void
  1469. GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc)
  1470. {
  1471. struct GNUNET_FS_ProgressInfo pi;
  1472. uint64_t off;
  1473. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1474. "Publish stop called\n");
  1475. GNUNET_FS_end_top (pc->h, pc->top);
  1476. if (NULL != pc->ksk_pc)
  1477. {
  1478. GNUNET_FS_publish_ksk_cancel (pc->ksk_pc);
  1479. pc->ksk_pc = NULL;
  1480. }
  1481. if (NULL != pc->sks_pc)
  1482. {
  1483. GNUNET_FS_publish_sks_cancel (pc->sks_pc);
  1484. pc->sks_pc = NULL;
  1485. }
  1486. if (NULL != pc->upload_task)
  1487. {
  1488. GNUNET_SCHEDULER_cancel (pc->upload_task);
  1489. pc->upload_task = NULL;
  1490. }
  1491. pc->skip_next_fi_callback = GNUNET_YES;
  1492. GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_stop, pc);
  1493. if (NULL != pc->fi->serialization)
  1494. {
  1495. GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO,
  1496. pc->fi->serialization);
  1497. GNUNET_free (pc->fi->serialization);
  1498. pc->fi->serialization = NULL;
  1499. }
  1500. off = (NULL == pc->fi->chk_uri) ? 0 : GNUNET_ntohll (
  1501. pc->fi->chk_uri->data.chk.file_length);
  1502. if (NULL != pc->serialization)
  1503. {
  1504. GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
  1505. pc->serialization);
  1506. GNUNET_free (pc->serialization);
  1507. pc->serialization = NULL;
  1508. }
  1509. if (NULL != pc->qre)
  1510. {
  1511. GNUNET_DATASTORE_cancel (pc->qre);
  1512. pc->qre = NULL;
  1513. }
  1514. pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED;
  1515. GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi, off));
  1516. publish_cleanup (pc);
  1517. }
  1518. /* end of fs_publish.c */