fs_publish.c 46 KB

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