fs_api.c 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2001--2012 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_api.c
  19. * @brief main FS functions (master initialization, serialization, deserialization, shared code)
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_fs_service.h"
  25. #include "fs_api.h"
  26. #include "fs_tree.h"
  27. /**
  28. * How many block requests can we have outstanding in parallel at a time by default?
  29. */
  30. #define DEFAULT_MAX_PARALLEL_REQUESTS (1024 * 10)
  31. /**
  32. * How many downloads can we have outstanding in parallel at a time by default?
  33. */
  34. #define DEFAULT_MAX_PARALLEL_DOWNLOADS 16
  35. /**
  36. * Start the given job (send signal, remove from pending queue, update
  37. * counters and state).
  38. *
  39. * @param qe job to start
  40. */
  41. static void
  42. start_job (struct GNUNET_FS_QueueEntry *qe)
  43. {
  44. GNUNET_assert (NULL == qe->client);
  45. qe->client = GNUNET_CLIENT_connect ("fs", qe->h->cfg);
  46. if (NULL == qe->client)
  47. {
  48. GNUNET_break (0);
  49. return;
  50. }
  51. qe->start (qe->cls, qe->client);
  52. qe->start_times++;
  53. qe->h->active_blocks += qe->blocks;
  54. qe->h->active_downloads++;
  55. qe->start_time = GNUNET_TIME_absolute_get ();
  56. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  57. "Starting job %p (%u active)\n",
  58. qe,
  59. qe->h->active_downloads);
  60. GNUNET_CONTAINER_DLL_remove (qe->h->pending_head, qe->h->pending_tail, qe);
  61. GNUNET_CONTAINER_DLL_insert_after (qe->h->running_head, qe->h->running_tail,
  62. qe->h->running_tail, qe);
  63. }
  64. /**
  65. * Stop the given job (send signal, remove from active queue, update
  66. * counters and state).
  67. *
  68. * @param qe job to stop
  69. */
  70. static void
  71. stop_job (struct GNUNET_FS_QueueEntry *qe)
  72. {
  73. qe->client = NULL;
  74. qe->stop (qe->cls);
  75. GNUNET_assert (0 < qe->h->active_downloads);
  76. qe->h->active_downloads--;
  77. qe->h->active_blocks -= qe->blocks;
  78. qe->run_time =
  79. GNUNET_TIME_relative_add (qe->run_time,
  80. GNUNET_TIME_absolute_get_duration
  81. (qe->start_time));
  82. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  83. "Stopping job %p (%u active)\n",
  84. qe,
  85. qe->h->active_downloads);
  86. GNUNET_CONTAINER_DLL_remove (qe->h->running_head, qe->h->running_tail, qe);
  87. GNUNET_CONTAINER_DLL_insert_after (qe->h->pending_head, qe->h->pending_tail,
  88. qe->h->pending_tail, qe);
  89. }
  90. /**
  91. * Process the jobs in the job queue, possibly starting some
  92. * and stopping others.
  93. *
  94. * @param cls the `struct GNUNET_FS_Handle *`
  95. * @param tc scheduler context
  96. */
  97. static void
  98. process_job_queue (void *cls,
  99. const struct GNUNET_SCHEDULER_TaskContext *tc)
  100. {
  101. struct GNUNET_FS_Handle *h = cls;
  102. struct GNUNET_FS_QueueEntry *qe;
  103. struct GNUNET_FS_QueueEntry *next;
  104. struct GNUNET_TIME_Relative run_time;
  105. struct GNUNET_TIME_Relative restart_at;
  106. struct GNUNET_TIME_Relative rst;
  107. struct GNUNET_TIME_Absolute end_time;
  108. unsigned int num_downloads_waiting;
  109. unsigned int num_downloads_active;
  110. unsigned int num_downloads_expired;
  111. unsigned int num_probes_active;
  112. unsigned int num_probes_waiting;
  113. unsigned int num_probes_expired;
  114. int num_probes_change;
  115. int num_downloads_change;
  116. int block_limit_hit;
  117. h->queue_job = GNUNET_SCHEDULER_NO_TASK;
  118. /* restart_at will be set to the time when it makes sense to
  119. re-evaluate the job queue (unless, of course, jobs complete
  120. or are added, then we'll be triggered immediately */
  121. restart_at = GNUNET_TIME_UNIT_FOREVER_REL;
  122. /* first, calculate some basic statistics on pending jobs */
  123. num_probes_waiting = 0;
  124. num_downloads_waiting = 0;
  125. for (qe = h->pending_head; NULL != qe; qe = qe->next)
  126. {
  127. switch (qe->priority)
  128. {
  129. case GNUNET_FS_QUEUE_PRIORITY_PROBE:
  130. num_probes_waiting++;
  131. break;
  132. case GNUNET_FS_QUEUE_PRIORITY_NORMAL:
  133. num_downloads_waiting++;
  134. break;
  135. default:
  136. GNUNET_break (0);
  137. break;
  138. }
  139. }
  140. /* now, calculate some basic statistics on running jobs */
  141. num_probes_active = 0;
  142. num_probes_expired = 0;
  143. num_downloads_active = 0;
  144. num_downloads_expired = 0;
  145. next = h->running_head;
  146. while (NULL != (qe = next))
  147. {
  148. next = qe->next;
  149. switch (qe->priority)
  150. {
  151. case GNUNET_FS_QUEUE_PRIORITY_PROBE:
  152. run_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2);
  153. end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time);
  154. rst = GNUNET_TIME_absolute_get_remaining (end_time);
  155. if (0 == rst.rel_value_us)
  156. {
  157. num_probes_expired++;
  158. stop_job (qe);
  159. }
  160. else
  161. {
  162. num_probes_active++;
  163. restart_at = GNUNET_TIME_relative_min (rst, restart_at);
  164. }
  165. break;
  166. case GNUNET_FS_QUEUE_PRIORITY_NORMAL:
  167. run_time =
  168. GNUNET_TIME_relative_multiply (h->avg_block_latency,
  169. qe->blocks * qe->start_times);
  170. end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time);
  171. rst = GNUNET_TIME_absolute_get_remaining (end_time);
  172. if (0 == rst.rel_value_us)
  173. {
  174. num_downloads_expired++;
  175. stop_job (qe);
  176. }
  177. else
  178. {
  179. num_downloads_active++;
  180. restart_at = GNUNET_TIME_relative_min (rst, restart_at);
  181. }
  182. break;
  183. default:
  184. GNUNET_break (0);
  185. break;
  186. }
  187. }
  188. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  189. "PA: %u, PE: %u, PW: %u; DA: %u, DE: %u, DW: %u\n",
  190. num_probes_active,
  191. num_probes_expired,
  192. num_probes_waiting,
  193. num_downloads_active,
  194. num_downloads_expired,
  195. num_downloads_waiting);
  196. /* calculate start/stop decisions */
  197. if (h->active_downloads + num_downloads_waiting > h->max_parallel_requests)
  198. {
  199. /* stop probes if possible */
  200. num_probes_change = - num_probes_active;
  201. num_downloads_change = h->max_parallel_requests - h->active_downloads;
  202. }
  203. else
  204. {
  205. /* start all downloads */
  206. num_downloads_change = num_downloads_waiting;
  207. /* start as many probes as we can */
  208. num_probes_change = GNUNET_MIN (num_probes_waiting,
  209. h->max_parallel_requests - (h->active_downloads + num_downloads_waiting));
  210. }
  211. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  212. "Changing %d probes and %d downloads\n",
  213. num_probes_change,
  214. num_downloads_change);
  215. /* actually stop probes */
  216. next = h->running_head;
  217. while (NULL != (qe = next))
  218. {
  219. next = qe->next;
  220. if (GNUNET_FS_QUEUE_PRIORITY_PROBE != qe->priority)
  221. continue;
  222. if (num_probes_change < 0)
  223. {
  224. stop_job (qe);
  225. num_probes_change++;
  226. if (0 == num_probes_change)
  227. break;
  228. }
  229. }
  230. GNUNET_break (0 <= num_probes_change);
  231. /* start some more tasks if we now have empty slots */
  232. block_limit_hit = GNUNET_NO;
  233. next = h->pending_head;
  234. while ( (NULL != (qe = next)) &&
  235. ( (num_probes_change > 0) ||
  236. (num_downloads_change > 0) ) )
  237. {
  238. next = qe->next;
  239. switch (qe->priority)
  240. {
  241. case GNUNET_FS_QUEUE_PRIORITY_PROBE:
  242. if (num_probes_change > 0)
  243. {
  244. start_job (qe);
  245. num_probes_change--;
  246. run_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2);
  247. restart_at = GNUNET_TIME_relative_min (run_time, restart_at);
  248. }
  249. break;
  250. case GNUNET_FS_QUEUE_PRIORITY_NORMAL:
  251. if ( (num_downloads_change > 0) &&
  252. ( (qe->blocks + h->active_blocks <= h->max_parallel_requests) ||
  253. ( (qe->blocks > h->max_parallel_requests) &&
  254. (0 == h->active_downloads) ) ) )
  255. {
  256. start_job (qe);
  257. num_downloads_change--;
  258. }
  259. else if (num_downloads_change > 0)
  260. block_limit_hit = GNUNET_YES;
  261. break;
  262. default:
  263. GNUNET_break (0);
  264. break;
  265. }
  266. }
  267. GNUNET_break ( (0 == num_downloads_change) || (GNUNET_YES == block_limit_hit) );
  268. GNUNET_break (0 == num_probes_change);
  269. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  270. "AD: %u, MP: %u; %d probes and %d downloads to start, will run again in %s\n",
  271. h->active_downloads,
  272. h->max_parallel_requests,
  273. num_probes_change,
  274. num_downloads_change,
  275. GNUNET_STRINGS_relative_time_to_string (restart_at, GNUNET_YES));
  276. /* make sure we run again */
  277. h->queue_job =
  278. GNUNET_SCHEDULER_add_delayed (restart_at, &process_job_queue, h);
  279. }
  280. /**
  281. * Add a job to the queue.
  282. *
  283. * @param h handle to the overall FS state
  284. * @param start function to call to begin the job
  285. * @param stop function to call to pause the job, or on dequeue (if the job was running)
  286. * @param cls closure for start and stop
  287. * @param blocks number of blocks this jobs uses
  288. * @param priority how important is this download
  289. * @return queue handle
  290. */
  291. struct GNUNET_FS_QueueEntry *
  292. GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h,
  293. GNUNET_FS_QueueStart start,
  294. GNUNET_FS_QueueStop stop, void *cls,
  295. unsigned int blocks,
  296. enum GNUNET_FS_QueuePriority priority)
  297. {
  298. struct GNUNET_FS_QueueEntry *qe;
  299. qe = GNUNET_new (struct GNUNET_FS_QueueEntry);
  300. qe->h = h;
  301. qe->start = start;
  302. qe->stop = stop;
  303. qe->cls = cls;
  304. qe->queue_time = GNUNET_TIME_absolute_get ();
  305. qe->blocks = blocks;
  306. qe->priority = priority;
  307. GNUNET_CONTAINER_DLL_insert_after (h->pending_head, h->pending_tail,
  308. h->pending_tail, qe);
  309. if (h->queue_job != GNUNET_SCHEDULER_NO_TASK)
  310. GNUNET_SCHEDULER_cancel (h->queue_job);
  311. h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h);
  312. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  313. "Queueing job %p\n",
  314. qe);
  315. return qe;
  316. }
  317. /**
  318. * Dequeue a job from the queue.
  319. *
  320. * @param qe handle for the job
  321. */
  322. void
  323. GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qe)
  324. {
  325. struct GNUNET_FS_Handle *h;
  326. h = qe->h;
  327. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  328. "Dequeueing job %p\n",
  329. qe);
  330. if (NULL != qe->client)
  331. stop_job (qe);
  332. GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, qe);
  333. GNUNET_free (qe);
  334. if (h->queue_job != GNUNET_SCHEDULER_NO_TASK)
  335. GNUNET_SCHEDULER_cancel (h->queue_job);
  336. h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h);
  337. }
  338. /**
  339. * Create a top-level activity entry.
  340. *
  341. * @param h global fs handle
  342. * @param ssf suspend signal function to use
  343. * @param ssf_cls closure for @a ssf
  344. * @return fresh top-level activity handle
  345. */
  346. struct TopLevelActivity *
  347. GNUNET_FS_make_top (struct GNUNET_FS_Handle *h,
  348. SuspendSignalFunction ssf,
  349. void *ssf_cls)
  350. {
  351. struct TopLevelActivity *ret;
  352. ret = GNUNET_new (struct TopLevelActivity);
  353. ret->ssf = ssf;
  354. ret->ssf_cls = ssf_cls;
  355. GNUNET_CONTAINER_DLL_insert (h->top_head, h->top_tail, ret);
  356. return ret;
  357. }
  358. /**
  359. * Destroy a top-level activity entry.
  360. *
  361. * @param h global fs handle
  362. * @param top top level activity entry
  363. */
  364. void
  365. GNUNET_FS_end_top (struct GNUNET_FS_Handle *h,
  366. struct TopLevelActivity *top)
  367. {
  368. GNUNET_CONTAINER_DLL_remove (h->top_head, h->top_tail, top);
  369. GNUNET_free (top);
  370. }
  371. /**
  372. * Closure for #GNUNET_FS_data_reader_file_().
  373. */
  374. struct FileInfo
  375. {
  376. /**
  377. * Name of the file to read.
  378. */
  379. char *filename;
  380. /**
  381. * File descriptor, NULL if it has not yet been opened.
  382. */
  383. struct GNUNET_DISK_FileHandle *fd;
  384. };
  385. /**
  386. * Function that provides data by reading from a file.
  387. *
  388. * @param cls closure with the `struct FileInfo *`
  389. * @param offset offset to read from; it is possible
  390. * that the caller might need to go backwards
  391. * a bit at times; set to `UINT64_MAX` to tell
  392. * the reader that we won't be reading for a while
  393. * (used to close the file descriptor but NOT fully
  394. * clean up the reader's state); in this case,
  395. * a value of '0' for @a max should be ignored
  396. * @param max maximum number of bytes that should be
  397. * copied to @a buf; readers are not allowed
  398. * to provide less data unless there is an error;
  399. * a value of "0" will be used at the end to allow
  400. * the reader to clean up its internal state
  401. * @param buf where the reader should write the data
  402. * @param emsg location for the reader to store an error message
  403. * @return number of bytes written, usually @a max, 0 on error
  404. */
  405. size_t
  406. GNUNET_FS_data_reader_file_ (void *cls,
  407. uint64_t offset,
  408. size_t max,
  409. void *buf,
  410. char **emsg)
  411. {
  412. struct FileInfo *fi = cls;
  413. ssize_t ret;
  414. if (UINT64_MAX == offset)
  415. {
  416. if (NULL != fi->fd)
  417. {
  418. GNUNET_DISK_file_close (fi->fd);
  419. fi->fd = NULL;
  420. }
  421. return 0;
  422. }
  423. if (0 == max)
  424. {
  425. if (NULL != fi->fd)
  426. GNUNET_DISK_file_close (fi->fd);
  427. GNUNET_free (fi->filename);
  428. GNUNET_free (fi);
  429. return 0;
  430. }
  431. if (NULL == fi->fd)
  432. {
  433. fi->fd =
  434. GNUNET_DISK_file_open (fi->filename,
  435. GNUNET_DISK_OPEN_READ,
  436. GNUNET_DISK_PERM_NONE);
  437. if (NULL == fi->fd)
  438. {
  439. GNUNET_asprintf (emsg,
  440. _("Could not open file `%s': %s"),
  441. fi->filename,
  442. STRERROR (errno));
  443. return 0;
  444. }
  445. }
  446. if ( (GNUNET_SYSERR ==
  447. GNUNET_DISK_file_seek (fi->fd, offset, GNUNET_DISK_SEEK_SET)) ||
  448. (-1 == (ret = GNUNET_DISK_file_read (fi->fd, buf, max))) )
  449. {
  450. GNUNET_asprintf (emsg,
  451. _("Could not read file `%s': %s"),
  452. fi->filename,
  453. STRERROR (errno));
  454. return 0;
  455. }
  456. if (ret != max)
  457. {
  458. GNUNET_asprintf (emsg,
  459. _("Short read reading from file `%s'!"),
  460. fi->filename);
  461. return 0;
  462. }
  463. return max;
  464. }
  465. /**
  466. * Create the closure for the #GNUNET_FS_data_reader_file_() callback.
  467. *
  468. * @param filename file to read
  469. * @return closure to use, NULL on error
  470. */
  471. void *
  472. GNUNET_FS_make_file_reader_context_ (const char *filename)
  473. {
  474. struct FileInfo *fi;
  475. fi = GNUNET_new (struct FileInfo);
  476. fi->filename = GNUNET_STRINGS_filename_expand (filename);
  477. if (NULL == fi->filename)
  478. {
  479. GNUNET_free (fi);
  480. return NULL;
  481. }
  482. return fi;
  483. }
  484. /**
  485. * Function that provides data by copying from a buffer.
  486. *
  487. * @param cls closure (points to the buffer)
  488. * @param offset offset to read from; it is possible
  489. * that the caller might need to go backwards
  490. * a bit at times; set to `UINT64_MAX` to tell
  491. * the reader that we won't be reading for a while
  492. * (used to close the file descriptor but NOT fully
  493. * clean up the reader's state); in this case,
  494. * a value of '0' for @a max should be ignored
  495. * @param max maximum number of bytes that should be
  496. * copied to @a buf; readers are not allowed
  497. * to provide less data unless there is an error;
  498. * a value of "0" will be used at the end to allow
  499. * the reader to clean up its internal state
  500. * @param buf where the reader should write the data
  501. * @param emsg location for the reader to store an error message
  502. * @return number of bytes written, usually @a max, 0 on error
  503. */
  504. size_t
  505. GNUNET_FS_data_reader_copy_ (void *cls,
  506. uint64_t offset,
  507. size_t max,
  508. void *buf,
  509. char **emsg)
  510. {
  511. char *data = cls;
  512. if (UINT64_MAX == offset)
  513. return 0;
  514. if (0 == max)
  515. {
  516. GNUNET_free_non_null (data);
  517. return 0;
  518. }
  519. memcpy (buf, &data[offset], max);
  520. return max;
  521. }
  522. /**
  523. * Return the full filename where we would store state information
  524. * (for serialization/deserialization).
  525. *
  526. * @param h master context
  527. * @param ext component of the path
  528. * @param ent entity identifier (or emtpy string for the directory)
  529. * @return NULL on error
  530. */
  531. static char *
  532. get_serialization_file_name (struct GNUNET_FS_Handle *h,
  533. const char *ext,
  534. const char *ent)
  535. {
  536. char *basename;
  537. char *ret;
  538. if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
  539. return NULL; /* persistence not requested */
  540. if (GNUNET_OK !=
  541. GNUNET_CONFIGURATION_get_value_filename (h->cfg, "fs", "STATE_DIR",
  542. &basename))
  543. return NULL;
  544. GNUNET_asprintf (&ret, "%s%s%s%s%s%s%s", basename, DIR_SEPARATOR_STR,
  545. h->client_name, DIR_SEPARATOR_STR, ext, DIR_SEPARATOR_STR,
  546. ent);
  547. GNUNET_free (basename);
  548. return ret;
  549. }
  550. /**
  551. * Return the full filename where we would store state information
  552. * (for serialization/deserialization) that is associated with a
  553. * parent operation.
  554. *
  555. * @param h master context
  556. * @param ext component of the path
  557. * @param uni name of the parent operation
  558. * @param ent entity identifier (or emtpy string for the directory)
  559. * @return NULL on error
  560. */
  561. static char *
  562. get_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h,
  563. const char *ext,
  564. const char *uni,
  565. const char *ent)
  566. {
  567. char *basename;
  568. char *ret;
  569. if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
  570. return NULL; /* persistence not requested */
  571. if (GNUNET_OK !=
  572. GNUNET_CONFIGURATION_get_value_filename (h->cfg, "fs", "STATE_DIR",
  573. &basename))
  574. return NULL;
  575. GNUNET_asprintf (&ret, "%s%s%s%s%s%s%s.dir%s%s", basename, DIR_SEPARATOR_STR,
  576. h->client_name, DIR_SEPARATOR_STR, ext, DIR_SEPARATOR_STR,
  577. uni, DIR_SEPARATOR_STR, ent);
  578. GNUNET_free (basename);
  579. return ret;
  580. }
  581. /**
  582. * Return a read handle for deserialization.
  583. *
  584. * @param h master context
  585. * @param ext component of the path
  586. * @param ent entity identifier (or emtpy string for the directory)
  587. * @return NULL on error
  588. */
  589. static struct GNUNET_BIO_ReadHandle *
  590. get_read_handle (struct GNUNET_FS_Handle *h,
  591. const char *ext,
  592. const char *ent)
  593. {
  594. char *fn;
  595. struct GNUNET_BIO_ReadHandle *ret;
  596. fn = get_serialization_file_name (h, ext, ent);
  597. if (NULL == fn)
  598. return NULL;
  599. ret = GNUNET_BIO_read_open (fn);
  600. GNUNET_free (fn);
  601. return ret;
  602. }
  603. /**
  604. * Return a write handle for serialization.
  605. *
  606. * @param h master context
  607. * @param ext component of the path
  608. * @param ent entity identifier (or emtpy string for the directory)
  609. * @return NULL on error
  610. */
  611. static struct GNUNET_BIO_WriteHandle *
  612. get_write_handle (struct GNUNET_FS_Handle *h,
  613. const char *ext,
  614. const char *ent)
  615. {
  616. char *fn;
  617. struct GNUNET_BIO_WriteHandle *ret;
  618. fn = get_serialization_file_name (h, ext, ent);
  619. if (NULL == fn)
  620. return NULL;
  621. ret = GNUNET_BIO_write_open (fn);
  622. GNUNET_break (NULL != ret);
  623. GNUNET_free (fn);
  624. return ret;
  625. }
  626. /**
  627. * Return a write handle for serialization.
  628. *
  629. * @param h master context
  630. * @param ext component of the path
  631. * @param uni name of parent
  632. * @param ent entity identifier (or emtpy string for the directory)
  633. * @return NULL on error
  634. */
  635. static struct GNUNET_BIO_WriteHandle *
  636. get_write_handle_in_dir (struct GNUNET_FS_Handle *h, const char *ext,
  637. const char *uni, const char *ent)
  638. {
  639. char *fn;
  640. struct GNUNET_BIO_WriteHandle *ret;
  641. fn = get_serialization_file_name_in_dir (h, ext, uni, ent);
  642. if (NULL == fn)
  643. return NULL;
  644. ret = GNUNET_BIO_write_open (fn);
  645. GNUNET_free (fn);
  646. return ret;
  647. }
  648. /**
  649. * Remove serialization/deserialization file from disk.
  650. *
  651. * @param h master context
  652. * @param ext component of the path
  653. * @param ent entity identifier
  654. */
  655. void
  656. GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h,
  657. const char *ext,
  658. const char *ent)
  659. {
  660. char *filename;
  661. if ((NULL == ent) || (0 == strlen (ent)))
  662. {
  663. GNUNET_break (0);
  664. return;
  665. }
  666. filename = get_serialization_file_name (h, ext, ent);
  667. if (NULL != filename)
  668. {
  669. if ( (0 != UNLINK (filename)) &&
  670. (ENOENT != errno) )
  671. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
  672. GNUNET_free (filename);
  673. }
  674. }
  675. /**
  676. * Remove serialization/deserialization file from disk.
  677. *
  678. * @param h master context
  679. * @param ext component of the path
  680. * @param uni parent name
  681. * @param ent entity identifier
  682. */
  683. static void
  684. remove_sync_file_in_dir (struct GNUNET_FS_Handle *h,
  685. const char *ext,
  686. const char *uni, const char *ent)
  687. {
  688. char *filename;
  689. if ((NULL == ent) || (0 == strlen (ent)))
  690. {
  691. GNUNET_break (0);
  692. return;
  693. }
  694. filename = get_serialization_file_name_in_dir (h, ext, uni, ent);
  695. if (NULL == filename)
  696. return;
  697. if (0 != UNLINK (filename))
  698. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
  699. GNUNET_free (filename);
  700. }
  701. /**
  702. * Remove serialization/deserialization directory from disk.
  703. *
  704. * @param h master context
  705. * @param ext component of the path
  706. * @param uni unique name of parent
  707. */
  708. void
  709. GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h,
  710. const char *ext,
  711. const char *uni)
  712. {
  713. char *dn;
  714. if (NULL == uni)
  715. return;
  716. dn = get_serialization_file_name_in_dir (h, ext, uni, "");
  717. if (NULL == dn)
  718. return;
  719. if ((GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES)) &&
  720. (GNUNET_OK != GNUNET_DISK_directory_remove (dn)))
  721. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dn);
  722. GNUNET_free (dn);
  723. }
  724. /**
  725. * Serialize a start-time. Since we use start-times to
  726. * calculate the duration of some operation, we actually
  727. * do not serialize the absolute time but the (relative)
  728. * duration since the start time. When we then
  729. * deserialize the start time, we take the current time and
  730. * subtract that duration so that we get again an absolute
  731. * time stamp that will result in correct performance
  732. * calculations.
  733. *
  734. * @param wh handle for writing
  735. * @param timestamp time to serialize
  736. * @return #GNUNET_OK on success
  737. */
  738. static int
  739. write_start_time (struct GNUNET_BIO_WriteHandle *wh,
  740. struct GNUNET_TIME_Absolute timestamp)
  741. {
  742. struct GNUNET_TIME_Relative dur;
  743. dur = GNUNET_TIME_absolute_get_duration (timestamp);
  744. return GNUNET_BIO_write_int64 (wh, dur.rel_value_us);
  745. }
  746. /**
  747. * Deserialize a start-time. Since we use start-times to
  748. * calculate the duration of some operation, we actually
  749. * do not serialize the absolute time but the (relative)
  750. * duration since the start time. Thus, when we then
  751. * deserialize the start time, we take the current time and
  752. * subtract that duration so that we get again an absolute
  753. * time stamp that will result in correct performance
  754. * calculations.
  755. *
  756. * @param rh handle for reading
  757. * @param timestamp where to write the deserialized timestamp
  758. * @return #GNUNET_OK on success
  759. */
  760. static int
  761. read_start_time (struct GNUNET_BIO_ReadHandle *rh,
  762. struct GNUNET_TIME_Absolute *timestamp)
  763. {
  764. struct GNUNET_TIME_Relative dur;
  765. if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dur.rel_value_us))
  766. return GNUNET_SYSERR;
  767. *timestamp = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), dur);
  768. return GNUNET_OK;
  769. }
  770. /**
  771. * Using the given serialization filename, try to deserialize
  772. * the file-information tree associated with it.
  773. *
  774. * @param h master context
  775. * @param filename name of the file (without directory) with
  776. * the infromation
  777. * @return NULL on error
  778. */
  779. static struct GNUNET_FS_FileInformation *
  780. deserialize_file_information (struct GNUNET_FS_Handle *h,
  781. const char *filename);
  782. /**
  783. * Using the given serialization filename, try to deserialize
  784. * the file-information tree associated with it.
  785. *
  786. * @param h master context
  787. * @param fn name of the file (without directory) with
  788. * the infromation
  789. * @param rh handle for reading
  790. * @return NULL on error
  791. */
  792. static struct GNUNET_FS_FileInformation *
  793. deserialize_fi_node (struct GNUNET_FS_Handle *h,
  794. const char *fn,
  795. struct GNUNET_BIO_ReadHandle *rh)
  796. {
  797. struct GNUNET_FS_FileInformation *ret;
  798. struct GNUNET_FS_FileInformation *nxt;
  799. char b;
  800. char *ksks;
  801. char *chks;
  802. char *skss;
  803. char *filename;
  804. uint32_t dsize;
  805. if (GNUNET_OK != GNUNET_BIO_read (rh, "status flag", &b, sizeof (b)))
  806. {
  807. GNUNET_break (0);
  808. return NULL;
  809. }
  810. ret = GNUNET_new (struct GNUNET_FS_FileInformation);
  811. ret->h = h;
  812. ksks = NULL;
  813. chks = NULL;
  814. skss = NULL;
  815. filename = NULL;
  816. if ((GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "metadata", &ret->meta)) ||
  817. (GNUNET_OK != GNUNET_BIO_read_string (rh, "ksk-uri", &ksks, 32 * 1024)) ||
  818. ( (NULL != ksks) &&
  819. ( (NULL == (ret->keywords = GNUNET_FS_uri_parse (ksks, NULL))) ||
  820. (GNUNET_YES != GNUNET_FS_uri_test_ksk (ret->keywords)) ) ) ||
  821. (GNUNET_OK != GNUNET_BIO_read_string (rh, "chk-uri", &chks, 1024)) ||
  822. ( (NULL != chks) &&
  823. ( (NULL == (ret->chk_uri = GNUNET_FS_uri_parse (chks, NULL))) ||
  824. (GNUNET_YES != GNUNET_FS_uri_test_chk (ret->chk_uri))) ) ||
  825. (GNUNET_OK != GNUNET_BIO_read_string (rh, "sks-uri", &skss, 1024)) ||
  826. ( (NULL != skss) &&
  827. ( (NULL == (ret->sks_uri = GNUNET_FS_uri_parse (skss, NULL))) ||
  828. (GNUNET_YES != GNUNET_FS_uri_test_sks (ret->sks_uri))) ) ||
  829. (GNUNET_OK != read_start_time (rh, &ret->start_time)) ||
  830. (GNUNET_OK != GNUNET_BIO_read_string (rh, "emsg", &ret->emsg, 16 * 1024))
  831. || (GNUNET_OK !=
  832. GNUNET_BIO_read_string (rh, "fn", &ret->filename, 16 * 1024)) ||
  833. (GNUNET_OK !=
  834. GNUNET_BIO_read_int64 (rh, &ret->bo.expiration_time.abs_value_us)) ||
  835. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.anonymity_level)) ||
  836. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.content_priority)) ||
  837. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.replication_level)))
  838. {
  839. GNUNET_break (0);
  840. goto cleanup;
  841. }
  842. switch (b)
  843. {
  844. case 0: /* file-insert */
  845. if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size))
  846. {
  847. GNUNET_break (0);
  848. goto cleanup;
  849. }
  850. ret->is_directory = GNUNET_NO;
  851. ret->data.file.do_index = GNUNET_NO;
  852. ret->data.file.have_hash = GNUNET_NO;
  853. ret->data.file.index_start_confirmed = GNUNET_NO;
  854. if (GNUNET_NO == ret->is_published)
  855. {
  856. if (NULL == ret->filename)
  857. {
  858. ret->data.file.reader = &GNUNET_FS_data_reader_copy_;
  859. ret->data.file.reader_cls =
  860. GNUNET_malloc_large (ret->data.file.file_size);
  861. if (ret->data.file.reader_cls == NULL)
  862. goto cleanup;
  863. if (GNUNET_OK !=
  864. GNUNET_BIO_read (rh, "file-data", ret->data.file.reader_cls,
  865. ret->data.file.file_size))
  866. {
  867. GNUNET_break (0);
  868. goto cleanup;
  869. }
  870. }
  871. else
  872. {
  873. ret->data.file.reader = &GNUNET_FS_data_reader_file_;
  874. ret->data.file.reader_cls =
  875. GNUNET_FS_make_file_reader_context_ (ret->filename);
  876. }
  877. }
  878. break;
  879. case 1: /* file-index, no hash */
  880. if (NULL == ret->filename)
  881. {
  882. GNUNET_break (0);
  883. goto cleanup;
  884. }
  885. if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size))
  886. {
  887. GNUNET_break (0);
  888. goto cleanup;
  889. }
  890. ret->is_directory = GNUNET_NO;
  891. ret->data.file.do_index = GNUNET_YES;
  892. ret->data.file.have_hash = GNUNET_NO;
  893. ret->data.file.index_start_confirmed = GNUNET_NO;
  894. ret->data.file.reader = &GNUNET_FS_data_reader_file_;
  895. ret->data.file.reader_cls =
  896. GNUNET_FS_make_file_reader_context_ (ret->filename);
  897. break;
  898. case 2: /* file-index-with-hash */
  899. if (NULL == ret->filename)
  900. {
  901. GNUNET_break (0);
  902. goto cleanup;
  903. }
  904. if ((GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) ||
  905. (GNUNET_OK !=
  906. GNUNET_BIO_read (rh, "fileid", &ret->data.file.file_id,
  907. sizeof (struct GNUNET_HashCode))))
  908. {
  909. GNUNET_break (0);
  910. goto cleanup;
  911. }
  912. ret->is_directory = GNUNET_NO;
  913. ret->data.file.do_index = GNUNET_YES;
  914. ret->data.file.have_hash = GNUNET_YES;
  915. ret->data.file.index_start_confirmed = GNUNET_NO;
  916. ret->data.file.reader = &GNUNET_FS_data_reader_file_;
  917. ret->data.file.reader_cls =
  918. GNUNET_FS_make_file_reader_context_ (ret->filename);
  919. break;
  920. case 3: /* file-index-with-hash-confirmed */
  921. if (NULL == ret->filename)
  922. {
  923. GNUNET_break (0);
  924. goto cleanup;
  925. }
  926. if ((GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) ||
  927. (GNUNET_OK !=
  928. GNUNET_BIO_read (rh, "fileid", &ret->data.file.file_id,
  929. sizeof (struct GNUNET_HashCode))))
  930. {
  931. GNUNET_break (0);
  932. goto cleanup;
  933. }
  934. ret->is_directory = GNUNET_NO;
  935. ret->data.file.do_index = GNUNET_YES;
  936. ret->data.file.have_hash = GNUNET_YES;
  937. ret->data.file.index_start_confirmed = GNUNET_YES;
  938. ret->data.file.reader = &GNUNET_FS_data_reader_file_;
  939. ret->data.file.reader_cls =
  940. GNUNET_FS_make_file_reader_context_ (ret->filename);
  941. break;
  942. case 4: /* directory */
  943. ret->is_directory = GNUNET_YES;
  944. if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dsize)) ||
  945. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.dir.contents_completed)) ||
  946. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.dir.contents_size)) ||
  947. (NULL == (ret->data.dir.dir_data = GNUNET_malloc_large (dsize))) ||
  948. (GNUNET_OK !=
  949. GNUNET_BIO_read (rh, "dir-data", ret->data.dir.dir_data, dsize)) ||
  950. (GNUNET_OK !=
  951. GNUNET_BIO_read_string (rh, "ent-filename", &filename, 16 * 1024)))
  952. {
  953. GNUNET_break (0);
  954. goto cleanup;
  955. }
  956. ret->data.dir.dir_size = (uint32_t) dsize;
  957. if (NULL != filename)
  958. {
  959. ret->data.dir.entries = deserialize_file_information (h, filename);
  960. GNUNET_free (filename);
  961. filename = NULL;
  962. nxt = ret->data.dir.entries;
  963. while (NULL != nxt)
  964. {
  965. nxt->dir = ret;
  966. nxt = nxt->next;
  967. }
  968. }
  969. break;
  970. default:
  971. GNUNET_break (0);
  972. goto cleanup;
  973. }
  974. ret->serialization = GNUNET_strdup (fn);
  975. if (GNUNET_OK !=
  976. GNUNET_BIO_read_string (rh, "nxt-filename", &filename, 16 * 1024))
  977. {
  978. GNUNET_break (0);
  979. goto cleanup;
  980. }
  981. if (NULL != filename)
  982. {
  983. ret->next = deserialize_file_information (h, filename);
  984. GNUNET_free (filename);
  985. filename = NULL;
  986. }
  987. GNUNET_free_non_null (ksks);
  988. GNUNET_free_non_null (skss);
  989. GNUNET_free_non_null (chks);
  990. return ret;
  991. cleanup:
  992. GNUNET_free_non_null (ksks);
  993. GNUNET_free_non_null (chks);
  994. GNUNET_free_non_null (skss);
  995. GNUNET_free_non_null (filename);
  996. GNUNET_FS_file_information_destroy (ret, NULL, NULL);
  997. return NULL;
  998. }
  999. /**
  1000. * Using the given serialization filename, try to deserialize
  1001. * the file-information tree associated with it.
  1002. *
  1003. * @param h master context
  1004. * @param filename name of the file (without directory) with
  1005. * the infromation
  1006. * @return NULL on error
  1007. */
  1008. static struct GNUNET_FS_FileInformation *
  1009. deserialize_file_information (struct GNUNET_FS_Handle *h,
  1010. const char *filename)
  1011. {
  1012. struct GNUNET_FS_FileInformation *ret;
  1013. struct GNUNET_BIO_ReadHandle *rh;
  1014. char *emsg;
  1015. char *fn;
  1016. rh = get_read_handle (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename);
  1017. if (NULL == rh)
  1018. return NULL;
  1019. ret = deserialize_fi_node (h, filename, rh);
  1020. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  1021. {
  1022. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1023. _("Failed to resume publishing information `%s': %s\n"),
  1024. filename, emsg);
  1025. GNUNET_free (emsg);
  1026. }
  1027. if (NULL == ret)
  1028. {
  1029. fn = get_serialization_file_name (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename);
  1030. if (NULL != fn)
  1031. {
  1032. if (0 != UNLINK (fn))
  1033. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
  1034. GNUNET_free (fn);
  1035. }
  1036. }
  1037. return ret;
  1038. }
  1039. /**
  1040. * Given a serialization name (full absolute path), return the
  1041. * basename of the file (without the path), which must only
  1042. * consist of the 6 random characters.
  1043. *
  1044. * @param fullname name to extract the basename from
  1045. * @return copy of the basename, NULL on error
  1046. */
  1047. static char *
  1048. get_serialization_short_name (const char *fullname)
  1049. {
  1050. const char *end;
  1051. const char *nxt;
  1052. end = NULL;
  1053. nxt = fullname;
  1054. /* FIXME: we could do this faster since we know
  1055. * the length of 'end'... */
  1056. while ('\0' != *nxt)
  1057. {
  1058. if (DIR_SEPARATOR == *nxt)
  1059. end = nxt + 1;
  1060. nxt++;
  1061. }
  1062. if ((NULL == end) || (0 == strlen (end)))
  1063. {
  1064. GNUNET_break (0);
  1065. return NULL;
  1066. }
  1067. GNUNET_break (6 == strlen (end));
  1068. return GNUNET_strdup (end);
  1069. }
  1070. /**
  1071. * Create a new random name for serialization. Also checks if persistence
  1072. * is enabled and returns NULL if not.
  1073. *
  1074. * @param h master context
  1075. * @param ext component of the path
  1076. * @return NULL on errror
  1077. */
  1078. static char *
  1079. make_serialization_file_name (struct GNUNET_FS_Handle *h,
  1080. const char *ext)
  1081. {
  1082. char *fn;
  1083. char *dn;
  1084. char *ret;
  1085. if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
  1086. return NULL; /* persistence not requested */
  1087. dn = get_serialization_file_name (h, ext, "");
  1088. if (NULL == dn)
  1089. return NULL;
  1090. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn))
  1091. {
  1092. GNUNET_free (dn);
  1093. return NULL;
  1094. }
  1095. fn = GNUNET_DISK_mktemp (dn);
  1096. GNUNET_free (dn);
  1097. if (NULL == fn)
  1098. return NULL; /* epic fail */
  1099. ret = get_serialization_short_name (fn);
  1100. GNUNET_free (fn);
  1101. return ret;
  1102. }
  1103. /**
  1104. * Create a new random name for serialization. Also checks if persistence
  1105. * is enabled and returns NULL if not.
  1106. *
  1107. * @param h master context
  1108. * @param ext component of the path
  1109. * @param uni name of parent
  1110. * @return NULL on errror
  1111. */
  1112. static char *
  1113. make_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h,
  1114. const char *ext,
  1115. const char *uni)
  1116. {
  1117. char *fn;
  1118. char *dn;
  1119. char *ret;
  1120. if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE))
  1121. return NULL; /* persistence not requested */
  1122. dn = get_serialization_file_name_in_dir (h, ext, uni, "");
  1123. if (NULL == dn)
  1124. return NULL;
  1125. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn))
  1126. {
  1127. GNUNET_free (dn);
  1128. return NULL;
  1129. }
  1130. fn = GNUNET_DISK_mktemp (dn);
  1131. GNUNET_free (dn);
  1132. if (NULL == fn)
  1133. return NULL; /* epic fail */
  1134. ret = get_serialization_short_name (fn);
  1135. GNUNET_free (fn);
  1136. return ret;
  1137. }
  1138. /**
  1139. * Copy all of the data from the reader to the write handle.
  1140. *
  1141. * @param wh write handle
  1142. * @param fi file with reader
  1143. * @return #GNUNET_OK on success
  1144. */
  1145. static int
  1146. copy_from_reader (struct GNUNET_BIO_WriteHandle *wh,
  1147. struct GNUNET_FS_FileInformation *fi)
  1148. {
  1149. char buf[32 * 1024];
  1150. uint64_t off;
  1151. size_t ret;
  1152. size_t left;
  1153. char *emsg;
  1154. emsg = NULL;
  1155. off = 0;
  1156. while (off < fi->data.file.file_size)
  1157. {
  1158. left = GNUNET_MIN (sizeof (buf), fi->data.file.file_size - off);
  1159. ret =
  1160. fi->data.file.reader (fi->data.file.reader_cls, off, left, buf, &emsg);
  1161. if (0 == ret)
  1162. {
  1163. GNUNET_free (emsg);
  1164. return GNUNET_SYSERR;
  1165. }
  1166. if (GNUNET_OK != GNUNET_BIO_write (wh, buf, ret))
  1167. return GNUNET_SYSERR;
  1168. off += ret;
  1169. }
  1170. return GNUNET_OK;
  1171. }
  1172. /**
  1173. * Create a temporary file on disk to store the current
  1174. * state of @a fi in.
  1175. *
  1176. * @param fi file information to sync with disk
  1177. */
  1178. void
  1179. GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *fi)
  1180. {
  1181. char *fn;
  1182. struct GNUNET_BIO_WriteHandle *wh;
  1183. char b;
  1184. char *ksks;
  1185. char *chks;
  1186. char *skss;
  1187. if (NULL == fi->serialization)
  1188. fi->serialization =
  1189. make_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO);
  1190. if (NULL == fi->serialization)
  1191. return;
  1192. wh = get_write_handle (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO,
  1193. fi->serialization);
  1194. if (NULL == wh)
  1195. {
  1196. GNUNET_free (fi->serialization);
  1197. fi->serialization = NULL;
  1198. return;
  1199. }
  1200. if (GNUNET_YES == fi->is_directory)
  1201. b = 4;
  1202. else if (GNUNET_YES == fi->data.file.index_start_confirmed)
  1203. b = 3;
  1204. else if (GNUNET_YES == fi->data.file.have_hash)
  1205. b = 2;
  1206. else if (GNUNET_YES == fi->data.file.do_index)
  1207. b = 1;
  1208. else
  1209. b = 0;
  1210. if (NULL != fi->keywords)
  1211. ksks = GNUNET_FS_uri_to_string (fi->keywords);
  1212. else
  1213. ksks = NULL;
  1214. if (NULL != fi->chk_uri)
  1215. chks = GNUNET_FS_uri_to_string (fi->chk_uri);
  1216. else
  1217. chks = NULL;
  1218. if (NULL != fi->sks_uri)
  1219. skss = GNUNET_FS_uri_to_string (fi->sks_uri);
  1220. else
  1221. skss = NULL;
  1222. if ((GNUNET_OK != GNUNET_BIO_write (wh, &b, sizeof (b))) ||
  1223. (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, fi->meta)) ||
  1224. (GNUNET_OK != GNUNET_BIO_write_string (wh, ksks)) ||
  1225. (GNUNET_OK != GNUNET_BIO_write_string (wh, chks)) ||
  1226. (GNUNET_OK != GNUNET_BIO_write_string (wh, skss)) ||
  1227. (GNUNET_OK != write_start_time (wh, fi->start_time)) ||
  1228. (GNUNET_OK != GNUNET_BIO_write_string (wh, fi->emsg)) ||
  1229. (GNUNET_OK != GNUNET_BIO_write_string (wh, fi->filename)) ||
  1230. (GNUNET_OK !=
  1231. GNUNET_BIO_write_int64 (wh, fi->bo.expiration_time.abs_value_us)) ||
  1232. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.anonymity_level)) ||
  1233. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.content_priority)) ||
  1234. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.replication_level)))
  1235. {
  1236. GNUNET_break (0);
  1237. goto cleanup;
  1238. }
  1239. GNUNET_free_non_null (chks);
  1240. chks = NULL;
  1241. GNUNET_free_non_null (ksks);
  1242. ksks = NULL;
  1243. GNUNET_free_non_null (skss);
  1244. skss = NULL;
  1245. switch (b)
  1246. {
  1247. case 0: /* file-insert */
  1248. if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size))
  1249. {
  1250. GNUNET_break (0);
  1251. goto cleanup;
  1252. }
  1253. if ((GNUNET_NO == fi->is_published) && (NULL == fi->filename))
  1254. if (GNUNET_OK != copy_from_reader (wh, fi))
  1255. {
  1256. GNUNET_break (0);
  1257. goto cleanup;
  1258. }
  1259. break;
  1260. case 1: /* file-index, no hash */
  1261. if (NULL == fi->filename)
  1262. {
  1263. GNUNET_break (0);
  1264. goto cleanup;
  1265. }
  1266. if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size))
  1267. {
  1268. GNUNET_break (0);
  1269. goto cleanup;
  1270. }
  1271. break;
  1272. case 2: /* file-index-with-hash */
  1273. case 3: /* file-index-with-hash-confirmed */
  1274. if (NULL == fi->filename)
  1275. {
  1276. GNUNET_break (0);
  1277. goto cleanup;
  1278. }
  1279. if ((GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) ||
  1280. (GNUNET_OK !=
  1281. GNUNET_BIO_write (wh, &fi->data.file.file_id,
  1282. sizeof (struct GNUNET_HashCode))))
  1283. {
  1284. GNUNET_break (0);
  1285. goto cleanup;
  1286. }
  1287. break;
  1288. case 4: /* directory */
  1289. if ( (NULL != fi->data.dir.entries) &&
  1290. (NULL == fi->data.dir.entries->serialization) )
  1291. GNUNET_FS_file_information_sync_ (fi->data.dir.entries);
  1292. if ((GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->data.dir.dir_size)) ||
  1293. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.dir.contents_completed)) ||
  1294. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.dir.contents_size)) ||
  1295. (GNUNET_OK !=
  1296. GNUNET_BIO_write (wh, fi->data.dir.dir_data,
  1297. (uint32_t) fi->data.dir.dir_size)) ||
  1298. (GNUNET_OK !=
  1299. GNUNET_BIO_write_string (wh,
  1300. (fi->data.dir.entries ==
  1301. NULL) ? NULL : fi->data.dir.
  1302. entries->serialization)))
  1303. {
  1304. GNUNET_break (0);
  1305. goto cleanup;
  1306. }
  1307. break;
  1308. default:
  1309. GNUNET_assert (0);
  1310. goto cleanup;
  1311. }
  1312. if ( (NULL != fi->next) &&
  1313. (NULL == fi->next->serialization) )
  1314. GNUNET_FS_file_information_sync_ (fi->next);
  1315. if (GNUNET_OK !=
  1316. GNUNET_BIO_write_string (wh,
  1317. (fi->next !=
  1318. NULL) ? fi->next->serialization : NULL))
  1319. {
  1320. GNUNET_break (0);
  1321. goto cleanup;
  1322. }
  1323. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  1324. {
  1325. wh = NULL;
  1326. GNUNET_break (0);
  1327. goto cleanup;
  1328. }
  1329. return; /* done! */
  1330. cleanup:
  1331. if (NULL != wh)
  1332. (void) GNUNET_BIO_write_close (wh);
  1333. GNUNET_free_non_null (chks);
  1334. GNUNET_free_non_null (ksks);
  1335. GNUNET_free_non_null (skss);
  1336. fn = get_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO,
  1337. fi->serialization);
  1338. if (NULL != fn)
  1339. {
  1340. if (0 != UNLINK (fn))
  1341. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
  1342. GNUNET_free (fn);
  1343. }
  1344. GNUNET_free (fi->serialization);
  1345. fi->serialization = NULL;
  1346. }
  1347. /**
  1348. * Find the entry in the file information struct where the
  1349. * serialization filename matches the given name.
  1350. *
  1351. * @param pos file information to search
  1352. * @param srch filename to search for
  1353. * @return NULL if srch was not found in this subtree
  1354. */
  1355. static struct GNUNET_FS_FileInformation *
  1356. find_file_position (struct GNUNET_FS_FileInformation *pos,
  1357. const char *srch)
  1358. {
  1359. struct GNUNET_FS_FileInformation *r;
  1360. while (NULL != pos)
  1361. {
  1362. if (0 == strcmp (srch, pos->serialization))
  1363. return pos;
  1364. if ( (GNUNET_YES == pos->is_directory) &&
  1365. (NULL != (r = find_file_position (pos->data.dir.entries, srch))) )
  1366. return r;
  1367. pos = pos->next;
  1368. }
  1369. return NULL;
  1370. }
  1371. /**
  1372. * Signal the FS's progress function that we are resuming
  1373. * an upload.
  1374. *
  1375. * @param cls closure (of type `struct GNUNET_FS_PublishContext *`, for the parent (!))
  1376. * @param fi the entry in the publish-structure
  1377. * @param length length of the file or directory
  1378. * @param meta metadata for the file or directory (can be modified)
  1379. * @param uri pointer to the keywords that will be used for this entry (can be modified)
  1380. * @param bo block options (can be modified)
  1381. * @param do_index should we index?
  1382. * @param client_info pointer to client context set upon creation (can be modified)
  1383. * @return #GNUNET_OK to continue (always)
  1384. */
  1385. static int
  1386. fip_signal_resume (void *cls,
  1387. struct GNUNET_FS_FileInformation *fi,
  1388. uint64_t length,
  1389. struct GNUNET_CONTAINER_MetaData *meta,
  1390. struct GNUNET_FS_Uri **uri,
  1391. struct GNUNET_FS_BlockOptions *bo,
  1392. int *do_index,
  1393. void **client_info)
  1394. {
  1395. struct GNUNET_FS_PublishContext *pc = cls;
  1396. struct GNUNET_FS_ProgressInfo pi;
  1397. if (GNUNET_YES == pc->skip_next_fi_callback)
  1398. {
  1399. pc->skip_next_fi_callback = GNUNET_NO;
  1400. return GNUNET_OK;
  1401. }
  1402. pi.status = GNUNET_FS_STATUS_PUBLISH_RESUME;
  1403. pi.value.publish.specifics.resume.message = fi->emsg;
  1404. pi.value.publish.specifics.resume.chk_uri = fi->chk_uri;
  1405. *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0);
  1406. if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta))
  1407. {
  1408. /* process entries in directory */
  1409. pc->skip_next_fi_callback = GNUNET_YES;
  1410. GNUNET_FS_file_information_inspect (fi, &fip_signal_resume, pc);
  1411. }
  1412. return GNUNET_OK;
  1413. }
  1414. /**
  1415. * Function called with a filename of serialized publishing operation
  1416. * to deserialize.
  1417. *
  1418. * @param cls the `struct GNUNET_FS_Handle *`
  1419. * @param filename complete filename (absolute path)
  1420. * @return #GNUNET_OK (continue to iterate)
  1421. */
  1422. static int
  1423. deserialize_publish_file (void *cls,
  1424. const char *filename)
  1425. {
  1426. struct GNUNET_FS_Handle *h = cls;
  1427. struct GNUNET_BIO_ReadHandle *rh;
  1428. struct GNUNET_FS_PublishContext *pc;
  1429. int32_t options;
  1430. int32_t all_done;
  1431. int32_t have_ns;
  1432. char *fi_root;
  1433. struct GNUNET_CRYPTO_EcdsaPrivateKey ns;
  1434. char *fi_pos;
  1435. char *emsg;
  1436. pc = GNUNET_new (struct GNUNET_FS_PublishContext);
  1437. pc->h = h;
  1438. pc->serialization = get_serialization_short_name (filename);
  1439. fi_root = NULL;
  1440. fi_pos = NULL;
  1441. rh = GNUNET_BIO_read_open (filename);
  1442. if (NULL == rh)
  1443. {
  1444. GNUNET_break (0);
  1445. goto cleanup;
  1446. }
  1447. if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-nid", &pc->nid, 1024))
  1448. || (GNUNET_OK !=
  1449. GNUNET_BIO_read_string (rh, "publish-nuid", &pc->nuid, 1024)) ||
  1450. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) ||
  1451. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &all_done)) ||
  1452. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &have_ns)) ||
  1453. (GNUNET_OK !=
  1454. GNUNET_BIO_read_string (rh, "publish-firoot", &fi_root, 128)) ||
  1455. (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-fipos", &fi_pos, 128))
  1456. || ( (GNUNET_YES == have_ns) &&
  1457. (GNUNET_OK != GNUNET_BIO_read (rh, "publish-ns", &ns, sizeof (ns)))) )
  1458. {
  1459. GNUNET_break (0);
  1460. goto cleanup;
  1461. }
  1462. pc->options = options;
  1463. pc->all_done = all_done;
  1464. if (NULL == fi_root)
  1465. {
  1466. GNUNET_break (0);
  1467. goto cleanup;
  1468. }
  1469. pc->fi = deserialize_file_information (h, fi_root);
  1470. if (NULL == pc->fi)
  1471. {
  1472. GNUNET_break (0);
  1473. goto cleanup;
  1474. }
  1475. if (GNUNET_YES == have_ns)
  1476. {
  1477. pc->ns = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
  1478. *pc->ns = ns;
  1479. }
  1480. if ((0 == (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) &&
  1481. (GNUNET_YES != pc->all_done))
  1482. {
  1483. pc->dsh = GNUNET_DATASTORE_connect (h->cfg);
  1484. if (NULL == pc->dsh)
  1485. goto cleanup;
  1486. }
  1487. if (NULL != fi_pos)
  1488. {
  1489. pc->fi_pos = find_file_position (pc->fi, fi_pos);
  1490. GNUNET_free (fi_pos);
  1491. fi_pos = NULL;
  1492. if (NULL == pc->fi_pos)
  1493. {
  1494. /* failed to find position for resuming, outch! Will start from root! */
  1495. GNUNET_break (0);
  1496. if (GNUNET_YES != pc->all_done)
  1497. pc->fi_pos = pc->fi;
  1498. }
  1499. }
  1500. GNUNET_free (fi_root);
  1501. fi_root = NULL;
  1502. /* generate RESUME event(s) */
  1503. GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_resume, pc);
  1504. /* re-start publishing (if needed)... */
  1505. if (GNUNET_YES != pc->all_done)
  1506. {
  1507. GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task);
  1508. pc->upload_task =
  1509. GNUNET_SCHEDULER_add_with_priority
  1510. (GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
  1511. &GNUNET_FS_publish_main_, pc);
  1512. }
  1513. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  1514. {
  1515. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1516. _("Failure while resuming publishing operation `%s': %s\n"),
  1517. filename, emsg);
  1518. GNUNET_free (emsg);
  1519. }
  1520. pc->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, pc);
  1521. return GNUNET_OK;
  1522. cleanup:
  1523. GNUNET_free_non_null (pc->nid);
  1524. GNUNET_free_non_null (pc->nuid);
  1525. GNUNET_free_non_null (fi_root);
  1526. GNUNET_free_non_null (fi_pos);
  1527. if ((NULL != rh) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)))
  1528. {
  1529. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1530. _("Failed to resume publishing operation `%s': %s\n"), filename,
  1531. emsg);
  1532. GNUNET_free (emsg);
  1533. }
  1534. if (NULL != pc->fi)
  1535. GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL);
  1536. if (0 != UNLINK (filename))
  1537. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
  1538. GNUNET_free (pc->serialization);
  1539. GNUNET_free (pc);
  1540. return GNUNET_OK;
  1541. }
  1542. /**
  1543. * Synchronize this publishing struct with its mirror
  1544. * on disk. Note that all internal FS-operations that change
  1545. * publishing structs should already call "sync" internally,
  1546. * so this function is likely not useful for clients.
  1547. *
  1548. * @param pc the struct to sync
  1549. */
  1550. void
  1551. GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc)
  1552. {
  1553. struct GNUNET_BIO_WriteHandle *wh;
  1554. int32_t have_ns;
  1555. if (NULL == pc->serialization)
  1556. pc->serialization =
  1557. make_serialization_file_name (pc->h,
  1558. GNUNET_FS_SYNC_PATH_MASTER_PUBLISH);
  1559. if (NULL == pc->serialization)
  1560. return;
  1561. if (NULL == pc->fi)
  1562. return;
  1563. if (NULL == pc->fi->serialization)
  1564. {
  1565. GNUNET_break (0);
  1566. return;
  1567. }
  1568. wh = get_write_handle (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
  1569. pc->serialization);
  1570. if (NULL == wh)
  1571. {
  1572. GNUNET_break (0);
  1573. goto cleanup;
  1574. }
  1575. have_ns = (NULL != pc->ns) ? GNUNET_YES : GNUNET_NO;
  1576. if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pc->nid)) ||
  1577. (GNUNET_OK != GNUNET_BIO_write_string (wh, pc->nuid)) ||
  1578. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pc->options)) ||
  1579. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pc->all_done)) ||
  1580. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, have_ns)) ||
  1581. (GNUNET_OK != GNUNET_BIO_write_string (wh, pc->fi->serialization)) ||
  1582. (GNUNET_OK !=
  1583. GNUNET_BIO_write_string (wh,
  1584. (NULL == pc->fi_pos) ? NULL : pc->fi_pos->serialization)) ||
  1585. ( (NULL != pc->ns) &&
  1586. (GNUNET_OK != GNUNET_BIO_write (wh,
  1587. pc->ns,
  1588. sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)) ) ))
  1589. {
  1590. GNUNET_break (0);
  1591. goto cleanup;
  1592. }
  1593. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  1594. {
  1595. wh = NULL;
  1596. GNUNET_break (0);
  1597. goto cleanup;
  1598. }
  1599. return;
  1600. cleanup:
  1601. if (NULL != wh)
  1602. (void) GNUNET_BIO_write_close (wh);
  1603. GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
  1604. pc->serialization);
  1605. GNUNET_free (pc->serialization);
  1606. pc->serialization = NULL;
  1607. }
  1608. /**
  1609. * Synchronize this unindex struct with its mirror
  1610. * on disk. Note that all internal FS-operations that change
  1611. * publishing structs should already call "sync" internally,
  1612. * so this function is likely not useful for clients.
  1613. *
  1614. * @param uc the struct to sync
  1615. */
  1616. void
  1617. GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc)
  1618. {
  1619. struct GNUNET_BIO_WriteHandle *wh;
  1620. char *uris;
  1621. if (NULL == uc->serialization)
  1622. uc->serialization =
  1623. make_serialization_file_name (uc->h,
  1624. GNUNET_FS_SYNC_PATH_MASTER_UNINDEX);
  1625. if (NULL == uc->serialization)
  1626. return;
  1627. wh = get_write_handle (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
  1628. uc->serialization);
  1629. if (NULL == wh)
  1630. {
  1631. GNUNET_break (0);
  1632. goto cleanup;
  1633. }
  1634. if (NULL != uc->ksk_uri)
  1635. uris = GNUNET_FS_uri_to_string (uc->ksk_uri);
  1636. else
  1637. uris = NULL;
  1638. if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uc->filename)) ||
  1639. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, uc->file_size)) ||
  1640. (GNUNET_OK != write_start_time (wh, uc->start_time)) ||
  1641. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) uc->state)) ||
  1642. (GNUNET_OK !=
  1643. GNUNET_BIO_write (wh, &uc->chk, sizeof (struct ContentHashKey))) ||
  1644. (GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) ||
  1645. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) uc->ksk_offset)) ||
  1646. ((uc->state == UNINDEX_STATE_FS_NOTIFY) &&
  1647. (GNUNET_OK !=
  1648. GNUNET_BIO_write (wh, &uc->file_id, sizeof (struct GNUNET_HashCode)))) ||
  1649. ((uc->state == UNINDEX_STATE_ERROR) &&
  1650. (GNUNET_OK != GNUNET_BIO_write_string (wh, uc->emsg))))
  1651. {
  1652. GNUNET_break (0);
  1653. goto cleanup;
  1654. }
  1655. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  1656. {
  1657. wh = NULL;
  1658. GNUNET_break (0);
  1659. goto cleanup;
  1660. }
  1661. return;
  1662. cleanup:
  1663. if (NULL != wh)
  1664. (void) GNUNET_BIO_write_close (wh);
  1665. GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
  1666. uc->serialization);
  1667. GNUNET_free (uc->serialization);
  1668. uc->serialization = NULL;
  1669. }
  1670. /**
  1671. * Serialize a download request.
  1672. *
  1673. * @param wh handle for writing the download request to disk
  1674. * @param dr the the request to write to disk
  1675. * @return #GNUNET_YES on success, #GNUNET_NO on error
  1676. */
  1677. static int
  1678. write_download_request (struct GNUNET_BIO_WriteHandle *wh,
  1679. struct DownloadRequest *dr)
  1680. {
  1681. unsigned int i;
  1682. if ((GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->state)) ||
  1683. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dr->offset)) ||
  1684. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->num_children)) ||
  1685. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->depth)))
  1686. return GNUNET_NO;
  1687. if ((BRS_CHK_SET == dr->state) &&
  1688. (GNUNET_OK !=
  1689. GNUNET_BIO_write (wh, &dr->chk, sizeof (struct ContentHashKey))))
  1690. return GNUNET_NO;
  1691. for (i = 0; i < dr->num_children; i++)
  1692. if (GNUNET_NO == write_download_request (wh, dr->children[i]))
  1693. return GNUNET_NO;
  1694. return GNUNET_YES;
  1695. }
  1696. /**
  1697. * Read a download request tree.
  1698. *
  1699. * @param rh cadet to read from
  1700. * @return value the download request read from disk, NULL on error
  1701. */
  1702. static struct DownloadRequest *
  1703. read_download_request (struct GNUNET_BIO_ReadHandle *rh)
  1704. {
  1705. struct DownloadRequest *dr;
  1706. unsigned int i;
  1707. dr = GNUNET_new (struct DownloadRequest);
  1708. if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->state)) ||
  1709. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dr->offset)) ||
  1710. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->num_children)) ||
  1711. (dr->num_children > CHK_PER_INODE) ||
  1712. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->depth)) ||
  1713. ( (0 == dr->depth) &&
  1714. (dr->num_children > 0) ) ||
  1715. ((dr->depth > 0) && (0 == dr->num_children)))
  1716. {
  1717. GNUNET_break (0);
  1718. dr->num_children = 0;
  1719. goto cleanup;
  1720. }
  1721. if (dr->num_children > 0)
  1722. dr->children =
  1723. GNUNET_malloc (dr->num_children * sizeof (struct DownloadRequest *));
  1724. switch (dr->state)
  1725. {
  1726. case BRS_INIT:
  1727. case BRS_RECONSTRUCT_DOWN:
  1728. case BRS_RECONSTRUCT_META_UP:
  1729. case BRS_RECONSTRUCT_UP:
  1730. break;
  1731. case BRS_CHK_SET:
  1732. if (GNUNET_OK !=
  1733. GNUNET_BIO_read (rh, "chk", &dr->chk, sizeof (struct ContentHashKey)))
  1734. goto cleanup;
  1735. break;
  1736. case BRS_DOWNLOAD_DOWN:
  1737. case BRS_DOWNLOAD_UP:
  1738. case BRS_ERROR:
  1739. break;
  1740. default:
  1741. GNUNET_break (0);
  1742. goto cleanup;
  1743. }
  1744. for (i = 0; i < dr->num_children; i++)
  1745. {
  1746. if (NULL == (dr->children[i] = read_download_request (rh)))
  1747. goto cleanup;
  1748. dr->children[i]->parent = dr;
  1749. }
  1750. return dr;
  1751. cleanup:
  1752. GNUNET_FS_free_download_request_ (dr);
  1753. return NULL;
  1754. }
  1755. /**
  1756. * Compute the name of the sync file (or directory) for the given download
  1757. * context.
  1758. *
  1759. * @param dc download context to compute for
  1760. * @param uni unique filename to use, use "" for the directory name
  1761. * @param ext extension to use, use ".dir" for our own subdirectory
  1762. * @return the expanded file name, NULL for none
  1763. */
  1764. static char *
  1765. get_download_sync_filename (struct GNUNET_FS_DownloadContext *dc,
  1766. const char *uni,
  1767. const char *ext)
  1768. {
  1769. char *par;
  1770. char *epar;
  1771. if (dc->parent == NULL)
  1772. return get_serialization_file_name (dc->h,
  1773. (dc->search != NULL) ?
  1774. GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD :
  1775. GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
  1776. uni);
  1777. if (NULL == dc->parent->serialization)
  1778. return NULL;
  1779. par = get_download_sync_filename (dc->parent, dc->parent->serialization, "");
  1780. if (NULL == par)
  1781. return NULL;
  1782. GNUNET_asprintf (&epar, "%s.dir%s%s%s", par, DIR_SEPARATOR_STR, uni, ext);
  1783. GNUNET_free (par);
  1784. return epar;
  1785. }
  1786. /**
  1787. * Synchronize this download struct with its mirror
  1788. * on disk. Note that all internal FS-operations that change
  1789. * publishing structs should already call "sync" internally,
  1790. * so this function is likely not useful for clients.
  1791. *
  1792. * @param dc the struct to sync
  1793. */
  1794. void
  1795. GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc)
  1796. {
  1797. struct GNUNET_BIO_WriteHandle *wh;
  1798. char *uris;
  1799. char *fn;
  1800. char *dir;
  1801. if (0 != (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
  1802. return; /* we don't sync probes */
  1803. if (NULL == dc->serialization)
  1804. {
  1805. dir = get_download_sync_filename (dc, "", "");
  1806. if (NULL == dir)
  1807. return;
  1808. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dir))
  1809. {
  1810. GNUNET_free (dir);
  1811. return;
  1812. }
  1813. fn = GNUNET_DISK_mktemp (dir);
  1814. GNUNET_free (dir);
  1815. if (NULL == fn)
  1816. return;
  1817. dc->serialization = get_serialization_short_name (fn);
  1818. }
  1819. else
  1820. {
  1821. fn = get_download_sync_filename (dc, dc->serialization, "");
  1822. if (NULL == fn)
  1823. {
  1824. GNUNET_free (dc->serialization);
  1825. dc->serialization = NULL;
  1826. GNUNET_free (fn);
  1827. return;
  1828. }
  1829. }
  1830. wh = GNUNET_BIO_write_open (fn);
  1831. if (NULL == wh)
  1832. {
  1833. GNUNET_free (dc->serialization);
  1834. dc->serialization = NULL;
  1835. GNUNET_free (fn);
  1836. return;
  1837. }
  1838. GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_chk (dc->uri)) ||
  1839. (GNUNET_YES == GNUNET_FS_uri_test_loc (dc->uri)));
  1840. uris = GNUNET_FS_uri_to_string (dc->uri);
  1841. if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) ||
  1842. (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, dc->meta)) ||
  1843. (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->emsg)) ||
  1844. (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->filename)) ||
  1845. (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->temp_filename)) ||
  1846. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->old_file_size)) ||
  1847. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->offset)) ||
  1848. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->length)) ||
  1849. (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->completed)) ||
  1850. (GNUNET_OK != write_start_time (wh, dc->start_time)) ||
  1851. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dc->anonymity)) ||
  1852. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) dc->options)) ||
  1853. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) dc->has_finished)))
  1854. {
  1855. GNUNET_break (0);
  1856. goto cleanup;
  1857. }
  1858. if (NULL == dc->emsg)
  1859. {
  1860. GNUNET_assert (dc->top_request != NULL);
  1861. if (GNUNET_YES != write_download_request (wh, dc->top_request))
  1862. {
  1863. GNUNET_break (0);
  1864. goto cleanup;
  1865. }
  1866. }
  1867. GNUNET_free_non_null (uris);
  1868. uris = NULL;
  1869. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  1870. {
  1871. wh = NULL;
  1872. GNUNET_break (0);
  1873. goto cleanup;
  1874. }
  1875. GNUNET_free (fn);
  1876. return;
  1877. cleanup:
  1878. if (NULL != wh)
  1879. (void) GNUNET_BIO_write_close (wh);
  1880. GNUNET_free_non_null (uris);
  1881. if (0 != UNLINK (fn))
  1882. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
  1883. GNUNET_free (fn);
  1884. GNUNET_free (dc->serialization);
  1885. dc->serialization = NULL;
  1886. }
  1887. /**
  1888. * Synchronize this search result with its mirror
  1889. * on disk. Note that all internal FS-operations that change
  1890. * publishing structs should already call "sync" internally,
  1891. * so this function is likely not useful for clients.
  1892. *
  1893. * @param sr the struct to sync
  1894. */
  1895. void
  1896. GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr)
  1897. {
  1898. struct GNUNET_BIO_WriteHandle *wh;
  1899. char *uris;
  1900. if (NULL == sr->sc)
  1901. return;
  1902. uris = NULL;
  1903. if (NULL == sr->serialization)
  1904. sr->serialization =
  1905. make_serialization_file_name_in_dir (sr->h,
  1906. (sr->sc->psearch_result ==
  1907. NULL) ?
  1908. GNUNET_FS_SYNC_PATH_MASTER_SEARCH :
  1909. GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  1910. sr->sc->serialization);
  1911. if (NULL == sr->serialization)
  1912. return;
  1913. wh = get_write_handle_in_dir (sr->h,
  1914. (sr->sc->psearch_result ==
  1915. NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH :
  1916. GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  1917. sr->sc->serialization, sr->serialization);
  1918. if (NULL == wh)
  1919. {
  1920. GNUNET_break (0);
  1921. goto cleanup;
  1922. }
  1923. uris = GNUNET_FS_uri_to_string (sr->uri);
  1924. if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) ||
  1925. (GNUNET_OK !=
  1926. GNUNET_BIO_write_string (wh,
  1927. sr->download !=
  1928. NULL ? sr->download->serialization : NULL)) ||
  1929. (GNUNET_OK !=
  1930. GNUNET_BIO_write_string (wh,
  1931. sr->update_search !=
  1932. NULL ? sr->update_search->serialization : NULL))
  1933. || (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, sr->meta)) ||
  1934. (GNUNET_OK != GNUNET_BIO_write (wh, &sr->key, sizeof (struct GNUNET_HashCode)))
  1935. || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->mandatory_missing)) ||
  1936. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->optional_support)) ||
  1937. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->availability_success)) ||
  1938. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->availability_trials)) )
  1939. {
  1940. GNUNET_break (0);
  1941. goto cleanup;
  1942. }
  1943. if ( (NULL != sr->uri) &&
  1944. (GNUNET_FS_URI_KSK == sr->sc->uri->type) &&
  1945. (GNUNET_OK != GNUNET_BIO_write (wh, sr->keyword_bitmap,
  1946. (sr->sc->uri->data.ksk.keywordCount + 7) / 8)) )
  1947. {
  1948. GNUNET_break (0);
  1949. goto cleanup;
  1950. }
  1951. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  1952. {
  1953. wh = NULL;
  1954. GNUNET_break (0);
  1955. goto cleanup;
  1956. }
  1957. GNUNET_free_non_null (uris);
  1958. return;
  1959. cleanup:
  1960. GNUNET_free_non_null (uris);
  1961. if (NULL != wh)
  1962. (void) GNUNET_BIO_write_close (wh);
  1963. remove_sync_file_in_dir (sr->h,
  1964. (NULL == sr->sc->psearch_result)
  1965. ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
  1966. : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  1967. sr->sc->serialization, sr->serialization);
  1968. GNUNET_free (sr->serialization);
  1969. sr->serialization = NULL;
  1970. }
  1971. /**
  1972. * Synchronize this search struct with its mirror
  1973. * on disk. Note that all internal FS-operations that change
  1974. * publishing structs should already call "sync" internally,
  1975. * so this function is likely not useful for clients.
  1976. *
  1977. * @param sc the struct to sync
  1978. */
  1979. void
  1980. GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc)
  1981. {
  1982. struct GNUNET_BIO_WriteHandle *wh;
  1983. char *uris;
  1984. char in_pause;
  1985. const char *category;
  1986. category =
  1987. (NULL == sc->psearch_result)
  1988. ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
  1989. : GNUNET_FS_SYNC_PATH_CHILD_SEARCH;
  1990. if (NULL == sc->serialization)
  1991. sc->serialization = make_serialization_file_name (sc->h, category);
  1992. if (NULL == sc->serialization)
  1993. return;
  1994. uris = NULL;
  1995. wh = get_write_handle (sc->h, category, sc->serialization);
  1996. if (NULL == wh)
  1997. {
  1998. GNUNET_break (0);
  1999. goto cleanup;
  2000. }
  2001. GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_ksk (sc->uri)) ||
  2002. (GNUNET_YES == GNUNET_FS_uri_test_sks (sc->uri)));
  2003. uris = GNUNET_FS_uri_to_string (sc->uri);
  2004. in_pause = (sc->task != GNUNET_SCHEDULER_NO_TASK) ? 'r' : '\0';
  2005. if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) ||
  2006. (GNUNET_OK != write_start_time (wh, sc->start_time)) ||
  2007. (GNUNET_OK != GNUNET_BIO_write_string (wh, sc->emsg)) ||
  2008. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) sc->options)) ||
  2009. (GNUNET_OK != GNUNET_BIO_write (wh, &in_pause, sizeof (in_pause))) ||
  2010. (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sc->anonymity)))
  2011. {
  2012. GNUNET_break (0);
  2013. goto cleanup;
  2014. }
  2015. GNUNET_free (uris);
  2016. uris = NULL;
  2017. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  2018. {
  2019. wh = NULL;
  2020. GNUNET_break (0);
  2021. goto cleanup;
  2022. }
  2023. return;
  2024. cleanup:
  2025. if (NULL != wh)
  2026. (void) GNUNET_BIO_write_close (wh);
  2027. GNUNET_free_non_null (uris);
  2028. GNUNET_FS_remove_sync_file_ (sc->h, category, sc->serialization);
  2029. GNUNET_free (sc->serialization);
  2030. sc->serialization = NULL;
  2031. }
  2032. /**
  2033. * Function called with a filename of serialized unindexing operation
  2034. * to deserialize.
  2035. *
  2036. * @param cls the `struct GNUNET_FS_Handle *`
  2037. * @param filename complete filename (absolute path)
  2038. * @return #GNUNET_OK (continue to iterate)
  2039. */
  2040. static int
  2041. deserialize_unindex_file (void *cls,
  2042. const char *filename)
  2043. {
  2044. struct GNUNET_FS_Handle *h = cls;
  2045. struct GNUNET_BIO_ReadHandle *rh;
  2046. struct GNUNET_FS_UnindexContext *uc;
  2047. struct GNUNET_FS_ProgressInfo pi;
  2048. char *emsg;
  2049. char *uris;
  2050. uint32_t state;
  2051. uc = GNUNET_new (struct GNUNET_FS_UnindexContext);
  2052. uc->h = h;
  2053. uc->serialization = get_serialization_short_name (filename);
  2054. rh = GNUNET_BIO_read_open (filename);
  2055. if (NULL == rh)
  2056. {
  2057. GNUNET_break (0);
  2058. goto cleanup;
  2059. }
  2060. uris = NULL;
  2061. if ((GNUNET_OK !=
  2062. GNUNET_BIO_read_string (rh, "unindex-fn", &uc->filename, 10 * 1024)) ||
  2063. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &uc->file_size)) ||
  2064. (GNUNET_OK != read_start_time (rh, &uc->start_time)) ||
  2065. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &state)) ||
  2066. (GNUNET_OK != GNUNET_BIO_read (rh, "uri", &uc->chk, sizeof (struct ContentHashKey))) ||
  2067. (GNUNET_OK != GNUNET_BIO_read_string (rh, "unindex-kskuri", &uris, 10 * 1024)) ||
  2068. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &uc->ksk_offset)) )
  2069. {
  2070. GNUNET_free_non_null (uris);
  2071. GNUNET_break (0);
  2072. goto cleanup;
  2073. }
  2074. if (NULL != uris)
  2075. {
  2076. uc->ksk_uri = GNUNET_FS_uri_parse (uris, &emsg);
  2077. GNUNET_free (uris);
  2078. if (NULL == uc->ksk_uri)
  2079. {
  2080. GNUNET_break (0);
  2081. GNUNET_free_non_null (emsg);
  2082. goto cleanup;
  2083. }
  2084. }
  2085. if ( (uc->ksk_offset > 0) &&
  2086. ( (NULL == uc->ksk_uri) ||
  2087. (uc->ksk_offset > uc->ksk_uri->data.ksk.keywordCount) ) )
  2088. {
  2089. GNUNET_break (0);
  2090. goto cleanup;
  2091. }
  2092. uc->state = (enum UnindexState) state;
  2093. switch (state)
  2094. {
  2095. case UNINDEX_STATE_HASHING:
  2096. break;
  2097. case UNINDEX_STATE_FS_NOTIFY:
  2098. if (GNUNET_OK !=
  2099. GNUNET_BIO_read (rh, "unindex-hash", &uc->file_id,
  2100. sizeof (struct GNUNET_HashCode)))
  2101. {
  2102. GNUNET_break (0);
  2103. goto cleanup;
  2104. }
  2105. break;
  2106. case UNINDEX_STATE_DS_REMOVE:
  2107. case UNINDEX_STATE_EXTRACT_KEYWORDS:
  2108. case UNINDEX_STATE_DS_REMOVE_KBLOCKS:
  2109. break;
  2110. case UNINDEX_STATE_COMPLETE:
  2111. break;
  2112. case UNINDEX_STATE_ERROR:
  2113. if (GNUNET_OK !=
  2114. GNUNET_BIO_read_string (rh, "unindex-emsg", &uc->emsg, 10 * 1024))
  2115. {
  2116. GNUNET_break (0);
  2117. goto cleanup;
  2118. }
  2119. break;
  2120. default:
  2121. GNUNET_break (0);
  2122. goto cleanup;
  2123. }
  2124. uc->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, uc);
  2125. pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME;
  2126. pi.value.unindex.specifics.resume.message = uc->emsg;
  2127. GNUNET_FS_unindex_make_status_ (&pi, uc,
  2128. (uc->state ==
  2129. UNINDEX_STATE_COMPLETE) ? uc->file_size : 0);
  2130. switch (uc->state)
  2131. {
  2132. case UNINDEX_STATE_HASHING:
  2133. uc->fhc =
  2134. GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, uc->filename,
  2135. HASHING_BLOCKSIZE,
  2136. &GNUNET_FS_unindex_process_hash_, uc);
  2137. break;
  2138. case UNINDEX_STATE_FS_NOTIFY:
  2139. uc->state = UNINDEX_STATE_HASHING;
  2140. GNUNET_FS_unindex_process_hash_ (uc, &uc->file_id);
  2141. break;
  2142. case UNINDEX_STATE_DS_REMOVE:
  2143. GNUNET_FS_unindex_do_remove_ (uc);
  2144. break;
  2145. case UNINDEX_STATE_EXTRACT_KEYWORDS:
  2146. GNUNET_FS_unindex_do_extract_keywords_ (uc);
  2147. break;
  2148. case UNINDEX_STATE_DS_REMOVE_KBLOCKS:
  2149. GNUNET_FS_unindex_do_remove_kblocks_ (uc);
  2150. break;
  2151. case UNINDEX_STATE_COMPLETE:
  2152. case UNINDEX_STATE_ERROR:
  2153. /* no need to resume any operation, we were done */
  2154. break;
  2155. default:
  2156. break;
  2157. }
  2158. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  2159. {
  2160. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2161. _("Failure while resuming unindexing operation `%s': %s\n"),
  2162. filename, emsg);
  2163. GNUNET_free (emsg);
  2164. }
  2165. return GNUNET_OK;
  2166. cleanup:
  2167. GNUNET_free_non_null (uc->filename);
  2168. if ((NULL != rh) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)))
  2169. {
  2170. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2171. _("Failed to resume unindexing operation `%s': %s\n"),
  2172. filename,
  2173. emsg);
  2174. GNUNET_free (emsg);
  2175. }
  2176. if (NULL != uc->serialization)
  2177. GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
  2178. uc->serialization);
  2179. GNUNET_free_non_null (uc->serialization);
  2180. GNUNET_free (uc);
  2181. return GNUNET_OK;
  2182. }
  2183. /**
  2184. * Deserialize a download.
  2185. *
  2186. * @param h overall context
  2187. * @param rh file to deserialize from
  2188. * @param parent parent download
  2189. * @param search associated search
  2190. * @param serialization name under which the search was serialized
  2191. */
  2192. static void
  2193. deserialize_download (struct GNUNET_FS_Handle *h,
  2194. struct GNUNET_BIO_ReadHandle *rh,
  2195. struct GNUNET_FS_DownloadContext *parent,
  2196. struct GNUNET_FS_SearchResult *search,
  2197. const char *serialization);
  2198. /**
  2199. * Deserialize a search.
  2200. *
  2201. * @param h overall context
  2202. * @param rh file to deserialize from
  2203. * @param psearch_result parent search result
  2204. * @param serialization name under which the search was serialized
  2205. */
  2206. static struct GNUNET_FS_SearchContext *
  2207. deserialize_search (struct GNUNET_FS_Handle *h,
  2208. struct GNUNET_BIO_ReadHandle *rh,
  2209. struct GNUNET_FS_SearchResult *psearch_result,
  2210. const char *serialization);
  2211. /**
  2212. * Function called with a filename of serialized search result
  2213. * to deserialize.
  2214. *
  2215. * @param cls the `struct GNUNET_FS_SearchContext *`
  2216. * @param filename complete filename (absolute path)
  2217. * @return #GNUNET_OK (continue to iterate)
  2218. */
  2219. static int
  2220. deserialize_search_result (void *cls,
  2221. const char *filename)
  2222. {
  2223. struct GNUNET_FS_SearchContext *sc = cls;
  2224. char *ser;
  2225. char *uris;
  2226. char *emsg;
  2227. char *download;
  2228. char *update_srch;
  2229. struct GNUNET_BIO_ReadHandle *rh;
  2230. struct GNUNET_BIO_ReadHandle *drh;
  2231. struct GNUNET_FS_SearchResult *sr;
  2232. ser = get_serialization_short_name (filename);
  2233. rh = GNUNET_BIO_read_open (filename);
  2234. if (NULL == rh)
  2235. {
  2236. if (NULL != ser)
  2237. {
  2238. remove_sync_file_in_dir (sc->h,
  2239. (NULL == sc->psearch_result)
  2240. ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH
  2241. : GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  2242. sc->serialization, ser);
  2243. GNUNET_free (ser);
  2244. }
  2245. return GNUNET_OK;
  2246. }
  2247. emsg = NULL;
  2248. uris = NULL;
  2249. download = NULL;
  2250. update_srch = NULL;
  2251. sr = GNUNET_new (struct GNUNET_FS_SearchResult);
  2252. sr->h = sc->h;
  2253. sr->sc = sc;
  2254. sr->serialization = ser;
  2255. if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "result-uri", &uris, 10 * 1024))
  2256. || (NULL == (sr->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
  2257. (GNUNET_OK != GNUNET_BIO_read_string (rh, "download-lnk", &download, 16))
  2258. || (GNUNET_OK !=
  2259. GNUNET_BIO_read_string (rh, "search-lnk", &update_srch, 16)) ||
  2260. (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "result-meta", &sr->meta)) ||
  2261. (GNUNET_OK !=
  2262. GNUNET_BIO_read (rh, "result-key", &sr->key, sizeof (struct GNUNET_HashCode)))
  2263. || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->mandatory_missing)) ||
  2264. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->optional_support)) ||
  2265. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->availability_success)) ||
  2266. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->availability_trials)))
  2267. {
  2268. GNUNET_break (0);
  2269. goto cleanup;
  2270. }
  2271. if (GNUNET_FS_URI_KSK == sr->sc->uri->type)
  2272. {
  2273. sr->keyword_bitmap = GNUNET_malloc ((sr->sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */
  2274. if (GNUNET_OK != GNUNET_BIO_read (rh, "keyword-bitmap",
  2275. sr->keyword_bitmap,
  2276. (sr->sc->uri->data.ksk.keywordCount + 7) / 8))
  2277. {
  2278. GNUNET_break (0);
  2279. goto cleanup;
  2280. }
  2281. }
  2282. GNUNET_free (uris);
  2283. if (NULL != download)
  2284. {
  2285. drh = get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, download);
  2286. if (NULL != drh)
  2287. {
  2288. deserialize_download (sc->h, drh, NULL, sr, download);
  2289. if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg))
  2290. {
  2291. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2292. _("Failed to resume sub-download `%s': %s\n"),
  2293. download,
  2294. emsg);
  2295. GNUNET_free (emsg);
  2296. }
  2297. }
  2298. GNUNET_free (download);
  2299. }
  2300. if (NULL != update_srch)
  2301. {
  2302. drh =
  2303. get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_SEARCH, update_srch);
  2304. if (NULL != drh)
  2305. {
  2306. deserialize_search (sc->h, drh, sr, update_srch);
  2307. if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg))
  2308. {
  2309. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2310. _("Failed to resume sub-search `%s': %s\n"),
  2311. update_srch,
  2312. emsg);
  2313. GNUNET_free (emsg);
  2314. }
  2315. }
  2316. GNUNET_free (update_srch);
  2317. }
  2318. GNUNET_break (GNUNET_YES ==
  2319. GNUNET_CONTAINER_multihashmap_put (sc->master_result_map,
  2320. &sr->key, sr,
  2321. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
  2322. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  2323. {
  2324. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2325. _("Failure while resuming search operation `%s': %s\n"),
  2326. filename, emsg);
  2327. GNUNET_free (emsg);
  2328. }
  2329. return GNUNET_OK;
  2330. cleanup:
  2331. GNUNET_free_non_null (download);
  2332. GNUNET_free_non_null (emsg);
  2333. GNUNET_free_non_null (uris);
  2334. GNUNET_free_non_null (update_srch);
  2335. if (NULL != sr->uri)
  2336. GNUNET_FS_uri_destroy (sr->uri);
  2337. if (NULL != sr->meta)
  2338. GNUNET_CONTAINER_meta_data_destroy (sr->meta);
  2339. GNUNET_free (sr->serialization);
  2340. GNUNET_free (sr);
  2341. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  2342. {
  2343. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2344. _("Failure while resuming search operation `%s': %s\n"),
  2345. filename, emsg);
  2346. GNUNET_free (emsg);
  2347. }
  2348. return GNUNET_OK;
  2349. }
  2350. /**
  2351. * Send the 'resume' signal to the callback; also actually
  2352. * resume the download (put it in the queue). Does this
  2353. * recursively for the top-level download and all child
  2354. * downloads.
  2355. *
  2356. * @param dc download to resume
  2357. */
  2358. static void
  2359. signal_download_resume (struct GNUNET_FS_DownloadContext *dc)
  2360. {
  2361. struct GNUNET_FS_DownloadContext *dcc;
  2362. struct GNUNET_FS_ProgressInfo pi;
  2363. pi.status = GNUNET_FS_STATUS_DOWNLOAD_RESUME;
  2364. pi.value.download.specifics.resume.meta = dc->meta;
  2365. pi.value.download.specifics.resume.message = dc->emsg;
  2366. GNUNET_FS_download_make_status_ (&pi, dc);
  2367. dcc = dc->child_head;
  2368. while (NULL != dcc)
  2369. {
  2370. signal_download_resume (dcc);
  2371. dcc = dcc->next;
  2372. }
  2373. if (NULL != dc->pending_head)
  2374. GNUNET_FS_download_start_downloading_ (dc);
  2375. }
  2376. /**
  2377. * Signal resuming of a search to our clients (for the
  2378. * top level search and all sub-searches).
  2379. *
  2380. * @param sc search being resumed
  2381. */
  2382. static void
  2383. signal_search_resume (struct GNUNET_FS_SearchContext *sc);
  2384. /**
  2385. * Iterator over search results signaling resume to the client for
  2386. * each result.
  2387. *
  2388. * @param cls closure, the `struct GNUNET_FS_SearchContext *`
  2389. * @param key current key code
  2390. * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *`
  2391. * @return #GNUNET_YES (we should continue to iterate)
  2392. */
  2393. static int
  2394. signal_result_resume (void *cls,
  2395. const struct GNUNET_HashCode *key,
  2396. void *value)
  2397. {
  2398. struct GNUNET_FS_SearchContext *sc = cls;
  2399. struct GNUNET_FS_ProgressInfo pi;
  2400. struct GNUNET_FS_SearchResult *sr = value;
  2401. if (0 == sr->mandatory_missing)
  2402. {
  2403. pi.status = GNUNET_FS_STATUS_SEARCH_RESUME_RESULT;
  2404. pi.value.search.specifics.resume_result.meta = sr->meta;
  2405. pi.value.search.specifics.resume_result.uri = sr->uri;
  2406. pi.value.search.specifics.resume_result.result = sr;
  2407. pi.value.search.specifics.resume_result.availability_rank =
  2408. 2 * sr->availability_success - sr->availability_trials;
  2409. pi.value.search.specifics.resume_result.availability_certainty =
  2410. sr->availability_trials;
  2411. pi.value.search.specifics.resume_result.applicability_rank =
  2412. sr->optional_support;
  2413. sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  2414. }
  2415. if (NULL != sr->download)
  2416. {
  2417. signal_download_resume (sr->download);
  2418. }
  2419. else
  2420. {
  2421. GNUNET_FS_search_start_probe_ (sr);
  2422. }
  2423. if (NULL != sr->update_search)
  2424. signal_search_resume (sr->update_search);
  2425. return GNUNET_YES;
  2426. }
  2427. /**
  2428. * Free memory allocated by the search context and its children
  2429. *
  2430. * @param sc search context to free
  2431. */
  2432. static void
  2433. free_search_context (struct GNUNET_FS_SearchContext *sc);
  2434. /**
  2435. * Iterator over search results freeing each.
  2436. *
  2437. * @param cls closure, the `struct GNUNET_FS_SearchContext *`
  2438. * @param key current key code
  2439. * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *`
  2440. * @return #GNUNET_YES (we should continue to iterate)
  2441. */
  2442. static int
  2443. free_result (void *cls,
  2444. const struct GNUNET_HashCode *key,
  2445. void *value)
  2446. {
  2447. struct GNUNET_FS_SearchResult *sr = value;
  2448. if (NULL != sr->update_search)
  2449. {
  2450. free_search_context (sr->update_search);
  2451. GNUNET_assert (NULL == sr->update_search);
  2452. }
  2453. GNUNET_CONTAINER_meta_data_destroy (sr->meta);
  2454. GNUNET_FS_uri_destroy (sr->uri);
  2455. GNUNET_free (sr);
  2456. return GNUNET_YES;
  2457. }
  2458. /**
  2459. * Free memory allocated by the search context and its children
  2460. *
  2461. * @param sc search context to free
  2462. */
  2463. static void
  2464. free_search_context (struct GNUNET_FS_SearchContext *sc)
  2465. {
  2466. if (NULL != sc->serialization)
  2467. {
  2468. GNUNET_FS_remove_sync_file_ (sc->h,
  2469. (sc->psearch_result ==
  2470. NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH :
  2471. GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  2472. sc->serialization);
  2473. GNUNET_FS_remove_sync_dir_ (sc->h,
  2474. (sc->psearch_result ==
  2475. NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH :
  2476. GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  2477. sc->serialization);
  2478. }
  2479. GNUNET_free_non_null (sc->serialization);
  2480. GNUNET_free_non_null (sc->emsg);
  2481. if (NULL != sc->uri)
  2482. GNUNET_FS_uri_destroy (sc->uri);
  2483. if (NULL != sc->master_result_map)
  2484. {
  2485. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &free_result,
  2486. sc);
  2487. GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
  2488. }
  2489. GNUNET_free (sc);
  2490. }
  2491. /**
  2492. * Function called with a filename of serialized sub-download
  2493. * to deserialize.
  2494. *
  2495. * @param cls the `struct GNUNET_FS_DownloadContext *` (parent)
  2496. * @param filename complete filename (absolute path)
  2497. * @return #GNUNET_OK (continue to iterate)
  2498. */
  2499. static int
  2500. deserialize_subdownload (void *cls,
  2501. const char *filename)
  2502. {
  2503. struct GNUNET_FS_DownloadContext *parent = cls;
  2504. char *ser;
  2505. char *emsg;
  2506. struct GNUNET_BIO_ReadHandle *rh;
  2507. ser = get_serialization_short_name (filename);
  2508. rh = GNUNET_BIO_read_open (filename);
  2509. if (NULL == rh)
  2510. {
  2511. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2512. _("Failed to resume sub-download `%s': could not open file `%s'\n"),
  2513. ser,
  2514. filename);
  2515. GNUNET_free (ser);
  2516. return GNUNET_OK;
  2517. }
  2518. deserialize_download (parent->h, rh, parent, NULL, ser);
  2519. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  2520. {
  2521. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2522. _("Failed to resume sub-download `%s': %s\n"),
  2523. ser,
  2524. emsg);
  2525. GNUNET_free (emsg);
  2526. }
  2527. GNUNET_free (ser);
  2528. return GNUNET_OK;
  2529. }
  2530. /**
  2531. * Free this download context and all of its descendants.
  2532. * (only works during deserialization since not all possible
  2533. * state it taken care of).
  2534. *
  2535. * @param dc context to free
  2536. */
  2537. static void
  2538. free_download_context (struct GNUNET_FS_DownloadContext *dc)
  2539. {
  2540. struct GNUNET_FS_DownloadContext *dcc;
  2541. if (NULL != dc->meta)
  2542. GNUNET_CONTAINER_meta_data_destroy (dc->meta);
  2543. if (NULL != dc->uri)
  2544. GNUNET_FS_uri_destroy (dc->uri);
  2545. GNUNET_free_non_null (dc->temp_filename);
  2546. GNUNET_free_non_null (dc->emsg);
  2547. GNUNET_free_non_null (dc->filename);
  2548. GNUNET_free_non_null (dc->serialization);
  2549. while (NULL != (dcc = dc->child_head))
  2550. {
  2551. GNUNET_CONTAINER_DLL_remove (dc->child_head,
  2552. dc->child_tail,
  2553. dcc);
  2554. free_download_context (dcc);
  2555. }
  2556. GNUNET_FS_free_download_request_ (dc->top_request);
  2557. if (NULL != dc->active)
  2558. GNUNET_CONTAINER_multihashmap_destroy (dc->active);
  2559. GNUNET_free (dc);
  2560. }
  2561. /**
  2562. * Deserialize a download.
  2563. *
  2564. * @param h overall context
  2565. * @param rh file to deserialize from
  2566. * @param parent parent download
  2567. * @param search associated search
  2568. * @param serialization name under which the search was serialized
  2569. */
  2570. static void
  2571. deserialize_download (struct GNUNET_FS_Handle *h,
  2572. struct GNUNET_BIO_ReadHandle *rh,
  2573. struct GNUNET_FS_DownloadContext *parent,
  2574. struct GNUNET_FS_SearchResult *search,
  2575. const char *serialization)
  2576. {
  2577. struct GNUNET_FS_DownloadContext *dc;
  2578. char *emsg;
  2579. char *uris;
  2580. char *dn;
  2581. uint32_t options;
  2582. uint32_t status;
  2583. uris = NULL;
  2584. emsg = NULL;
  2585. dc = GNUNET_new (struct GNUNET_FS_DownloadContext);
  2586. dc->parent = parent;
  2587. dc->h = h;
  2588. dc->serialization = GNUNET_strdup (serialization);
  2589. if ((GNUNET_OK !=
  2590. GNUNET_BIO_read_string (rh, "download-uri", &uris, 10 * 1024)) ||
  2591. (NULL == (dc->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
  2592. ((GNUNET_YES != GNUNET_FS_uri_test_chk (dc->uri)) &&
  2593. (GNUNET_YES != GNUNET_FS_uri_test_loc (dc->uri))) ||
  2594. (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "download-meta", &dc->meta))
  2595. || (GNUNET_OK !=
  2596. GNUNET_BIO_read_string (rh, "download-emsg", &dc->emsg, 10 * 1024)) ||
  2597. (GNUNET_OK !=
  2598. GNUNET_BIO_read_string (rh, "download-fn", &dc->filename, 10 * 1024)) ||
  2599. (GNUNET_OK !=
  2600. GNUNET_BIO_read_string (rh, "download-tfn", &dc->temp_filename,
  2601. 10 * 1024)) ||
  2602. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->old_file_size)) ||
  2603. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->offset)) ||
  2604. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->length)) ||
  2605. (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->completed)) ||
  2606. (GNUNET_OK != read_start_time (rh, &dc->start_time)) ||
  2607. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dc->anonymity)) ||
  2608. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) ||
  2609. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &status)))
  2610. {
  2611. GNUNET_break (0);
  2612. goto cleanup;
  2613. }
  2614. dc->options = (enum GNUNET_FS_DownloadOptions) options;
  2615. dc->active =
  2616. GNUNET_CONTAINER_multihashmap_create (1 + 2 * (dc->length / DBLOCK_SIZE), GNUNET_NO);
  2617. dc->has_finished = (int) status;
  2618. dc->treedepth =
  2619. GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri));
  2620. if (GNUNET_FS_uri_test_loc (dc->uri))
  2621. GNUNET_assert (GNUNET_OK ==
  2622. GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target));
  2623. if (NULL == dc->emsg)
  2624. {
  2625. dc->top_request = read_download_request (rh);
  2626. if (NULL == dc->top_request)
  2627. {
  2628. GNUNET_break (0);
  2629. goto cleanup;
  2630. }
  2631. }
  2632. dn = get_download_sync_filename (dc, dc->serialization, ".dir");
  2633. if (NULL != dn)
  2634. {
  2635. if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES))
  2636. GNUNET_DISK_directory_scan (dn, &deserialize_subdownload, dc);
  2637. GNUNET_free (dn);
  2638. }
  2639. if (NULL != parent)
  2640. {
  2641. GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc);
  2642. }
  2643. if (NULL != search)
  2644. {
  2645. dc->search = search;
  2646. search->download = dc;
  2647. }
  2648. if ((NULL == parent) && (NULL == search))
  2649. {
  2650. dc->top =
  2651. GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc);
  2652. signal_download_resume (dc);
  2653. }
  2654. GNUNET_free (uris);
  2655. dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc);
  2656. return;
  2657. cleanup:
  2658. GNUNET_free_non_null (uris);
  2659. GNUNET_free_non_null (emsg);
  2660. free_download_context (dc);
  2661. }
  2662. /**
  2663. * Signal resuming of a search to our clients (for the
  2664. * top level search and all sub-searches).
  2665. *
  2666. * @param sc search being resumed
  2667. */
  2668. static void
  2669. signal_search_resume (struct GNUNET_FS_SearchContext *sc)
  2670. {
  2671. struct GNUNET_FS_ProgressInfo pi;
  2672. pi.status = GNUNET_FS_STATUS_SEARCH_RESUME;
  2673. pi.value.search.specifics.resume.message = sc->emsg;
  2674. pi.value.search.specifics.resume.is_paused =
  2675. (NULL == sc->client) ? GNUNET_YES : GNUNET_NO;
  2676. sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  2677. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  2678. &signal_result_resume, sc);
  2679. }
  2680. /**
  2681. * Deserialize a search.
  2682. *
  2683. * @param h overall context
  2684. * @param rh file to deserialize from
  2685. * @param psearch_result parent search result
  2686. * @param serialization name under which the search was serialized
  2687. */
  2688. static struct GNUNET_FS_SearchContext *
  2689. deserialize_search (struct GNUNET_FS_Handle *h,
  2690. struct GNUNET_BIO_ReadHandle *rh,
  2691. struct GNUNET_FS_SearchResult *psearch_result,
  2692. const char *serialization)
  2693. {
  2694. struct GNUNET_FS_SearchContext *sc;
  2695. char *emsg;
  2696. char *uris;
  2697. char *dn;
  2698. uint32_t options;
  2699. char in_pause;
  2700. if ((NULL != psearch_result) && (NULL != psearch_result->update_search))
  2701. {
  2702. GNUNET_break (0);
  2703. return NULL;
  2704. }
  2705. uris = NULL;
  2706. emsg = NULL;
  2707. sc = GNUNET_new (struct GNUNET_FS_SearchContext);
  2708. if (NULL != psearch_result)
  2709. {
  2710. sc->psearch_result = psearch_result;
  2711. psearch_result->update_search = sc;
  2712. }
  2713. sc->h = h;
  2714. sc->serialization = GNUNET_strdup (serialization);
  2715. if ((GNUNET_OK !=
  2716. GNUNET_BIO_read_string (rh, "search-uri", &uris, 10 * 1024)) ||
  2717. (NULL == (sc->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
  2718. ((GNUNET_YES != GNUNET_FS_uri_test_ksk (sc->uri)) &&
  2719. (GNUNET_YES != GNUNET_FS_uri_test_sks (sc->uri))) ||
  2720. (GNUNET_OK != read_start_time (rh, &sc->start_time)) ||
  2721. (GNUNET_OK !=
  2722. GNUNET_BIO_read_string (rh, "search-emsg", &sc->emsg, 10 * 1024)) ||
  2723. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) ||
  2724. (GNUNET_OK !=
  2725. GNUNET_BIO_read (rh, "search-pause", &in_pause, sizeof (in_pause))) ||
  2726. (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sc->anonymity)))
  2727. {
  2728. GNUNET_break (0);
  2729. goto cleanup;
  2730. }
  2731. sc->options = (enum GNUNET_FS_SearchOptions) options;
  2732. sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
  2733. dn = get_serialization_file_name_in_dir (h,
  2734. (NULL == sc->psearch_result) ?
  2735. GNUNET_FS_SYNC_PATH_MASTER_SEARCH :
  2736. GNUNET_FS_SYNC_PATH_CHILD_SEARCH,
  2737. sc->serialization, "");
  2738. if (NULL != dn)
  2739. {
  2740. if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES))
  2741. GNUNET_DISK_directory_scan (dn, &deserialize_search_result, sc);
  2742. GNUNET_free (dn);
  2743. }
  2744. if (('\0' == in_pause) &&
  2745. (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc)))
  2746. {
  2747. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2748. _("Could not resume running search, will resume as paused search\n"));
  2749. }
  2750. signal_search_resume (sc);
  2751. GNUNET_free (uris);
  2752. return sc;
  2753. cleanup:
  2754. GNUNET_free_non_null (emsg);
  2755. free_search_context (sc);
  2756. GNUNET_free_non_null (uris);
  2757. return NULL;
  2758. }
  2759. /**
  2760. * Function called with a filename of serialized search operation
  2761. * to deserialize.
  2762. *
  2763. * @param cls the `struct GNUNET_FS_Handle *`
  2764. * @param filename complete filename (absolute path)
  2765. * @return #GNUNET_OK (continue to iterate)
  2766. */
  2767. static int
  2768. deserialize_search_file (void *cls,
  2769. const char *filename)
  2770. {
  2771. struct GNUNET_FS_Handle *h = cls;
  2772. char *ser;
  2773. char *emsg;
  2774. struct GNUNET_BIO_ReadHandle *rh;
  2775. struct GNUNET_FS_SearchContext *sc;
  2776. struct stat buf;
  2777. if (0 != STAT (filename, &buf))
  2778. {
  2779. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
  2780. return GNUNET_OK;
  2781. }
  2782. if (S_ISDIR (buf.st_mode))
  2783. return GNUNET_OK; /* skip directories */
  2784. ser = get_serialization_short_name (filename);
  2785. rh = GNUNET_BIO_read_open (filename);
  2786. if (NULL == rh)
  2787. {
  2788. if (NULL != ser)
  2789. {
  2790. GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_SEARCH, ser);
  2791. GNUNET_free (ser);
  2792. }
  2793. return GNUNET_OK;
  2794. }
  2795. sc = deserialize_search (h, rh, NULL, ser);
  2796. if (NULL != sc)
  2797. sc->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, sc);
  2798. GNUNET_free (ser);
  2799. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  2800. {
  2801. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2802. _("Failure while resuming search operation `%s': %s\n"),
  2803. filename, emsg);
  2804. GNUNET_free (emsg);
  2805. }
  2806. return GNUNET_OK;
  2807. }
  2808. /**
  2809. * Function called with a filename of serialized download operation
  2810. * to deserialize.
  2811. *
  2812. * @param cls the `struct GNUNET_FS_Handle *`
  2813. * @param filename complete filename (absolute path)
  2814. * @return #GNUNET_OK (continue to iterate)
  2815. */
  2816. static int
  2817. deserialize_download_file (void *cls, const char *filename)
  2818. {
  2819. struct GNUNET_FS_Handle *h = cls;
  2820. char *ser;
  2821. char *emsg;
  2822. struct GNUNET_BIO_ReadHandle *rh;
  2823. ser = get_serialization_short_name (filename);
  2824. rh = GNUNET_BIO_read_open (filename);
  2825. if (NULL == rh)
  2826. {
  2827. if (0 != UNLINK (filename))
  2828. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
  2829. GNUNET_free (ser);
  2830. return GNUNET_OK;
  2831. }
  2832. deserialize_download (h, rh, NULL, NULL, ser);
  2833. GNUNET_free (ser);
  2834. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  2835. {
  2836. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2837. _("Failure while resuming download operation `%s': %s\n"),
  2838. filename, emsg);
  2839. GNUNET_free (emsg);
  2840. }
  2841. return GNUNET_OK;
  2842. }
  2843. /**
  2844. * Deserialize informatin about pending operations.
  2845. *
  2846. * @param master_path which master directory should be scanned
  2847. * @param proc function to call for each entry (will get 'h' for 'cls')
  2848. * @param h the 'struct GNUNET_FS_Handle*'
  2849. */
  2850. static void
  2851. deserialization_master (const char *master_path, GNUNET_FileNameCallback proc,
  2852. struct GNUNET_FS_Handle *h)
  2853. {
  2854. char *dn;
  2855. dn = get_serialization_file_name (h, master_path, "");
  2856. if (NULL == dn)
  2857. return;
  2858. if (GNUNET_YES == GNUNET_DISK_directory_test (dn, GNUNET_YES))
  2859. GNUNET_DISK_directory_scan (dn, proc, h);
  2860. GNUNET_free (dn);
  2861. }
  2862. /**
  2863. * Setup a connection to the file-sharing service.
  2864. *
  2865. * @param cfg configuration to use
  2866. * @param client_name unique identifier for this client
  2867. * @param upcb function to call to notify about FS actions
  2868. * @param upcb_cls closure for @a upcb
  2869. * @param flags specific attributes for fs-operations
  2870. * @param ... list of optional options, terminated with #GNUNET_FS_OPTIONS_END
  2871. * @return NULL on error
  2872. */
  2873. struct GNUNET_FS_Handle *
  2874. GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
  2875. const char *client_name,
  2876. GNUNET_FS_ProgressCallback upcb,
  2877. void *upcb_cls,
  2878. enum GNUNET_FS_Flags flags, ...)
  2879. {
  2880. struct GNUNET_FS_Handle *ret;
  2881. enum GNUNET_FS_OPTIONS opt;
  2882. va_list ap;
  2883. ret = GNUNET_new (struct GNUNET_FS_Handle);
  2884. ret->cfg = cfg;
  2885. ret->client_name = GNUNET_strdup (client_name);
  2886. ret->upcb = upcb;
  2887. ret->upcb_cls = upcb_cls;
  2888. ret->flags = flags;
  2889. ret->max_parallel_downloads = DEFAULT_MAX_PARALLEL_DOWNLOADS;
  2890. ret->max_parallel_requests = DEFAULT_MAX_PARALLEL_REQUESTS;
  2891. ret->avg_block_latency = GNUNET_TIME_UNIT_MINUTES; /* conservative starting point */
  2892. va_start (ap, flags);
  2893. while (GNUNET_FS_OPTIONS_END != (opt = va_arg (ap, enum GNUNET_FS_OPTIONS)))
  2894. {
  2895. switch (opt)
  2896. {
  2897. case GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM:
  2898. ret->max_parallel_downloads = va_arg (ap, unsigned int);
  2899. break;
  2900. case GNUNET_FS_OPTIONS_REQUEST_PARALLELISM:
  2901. ret->max_parallel_requests = va_arg (ap, unsigned int);
  2902. break;
  2903. default:
  2904. GNUNET_break (0);
  2905. GNUNET_free (ret->client_name);
  2906. GNUNET_free (ret);
  2907. va_end (ap);
  2908. return NULL;
  2909. }
  2910. }
  2911. va_end (ap);
  2912. if (0 != (GNUNET_FS_FLAGS_PERSISTENCE & flags))
  2913. {
  2914. deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_PUBLISH,
  2915. &deserialize_publish_file, ret);
  2916. deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
  2917. &deserialize_search_file, ret);
  2918. deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
  2919. &deserialize_download_file, ret);
  2920. deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_UNINDEX,
  2921. &deserialize_unindex_file, ret);
  2922. }
  2923. return ret;
  2924. }
  2925. /**
  2926. * Close our connection with the file-sharing service.
  2927. * The callback given to GNUNET_FS_start will no longer be
  2928. * called after this function returns.
  2929. *
  2930. * @param h handle that was returned from #GNUNET_FS_start()
  2931. */
  2932. void
  2933. GNUNET_FS_stop (struct GNUNET_FS_Handle *h)
  2934. {
  2935. while (h->top_head != NULL)
  2936. h->top_head->ssf (h->top_head->ssf_cls);
  2937. if (h->queue_job != GNUNET_SCHEDULER_NO_TASK)
  2938. GNUNET_SCHEDULER_cancel (h->queue_job);
  2939. GNUNET_free (h->client_name);
  2940. GNUNET_free (h);
  2941. }
  2942. /* end of fs_api.c */