fixing #3799: only unindex if DB operations succeeded previously in the first place...
[oweals/gnunet.git] / src / fs / fs_publish_ksk.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/fs_publish_ksk.c
23  * @brief publish a URI under a keyword in GNUnet
24  * @see https://gnunet.org/encoding and #2564
25  * @author Krista Bennett
26  * @author Christian Grothoff
27  */
28
29 #include "platform.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_fs_service.h"
34 #include "fs_api.h"
35 #include "fs_tree.h"
36 #include "fs_publish_ublock.h"
37
38 /**
39  * Context for the KSK publication.
40  */
41 struct GNUNET_FS_PublishKskContext
42 {
43
44   /**
45    * Keywords to use.
46    */
47   struct GNUNET_FS_Uri *ksk_uri;
48
49   /**
50    * URI to publish.
51    */
52   struct GNUNET_FS_Uri *uri;
53
54   /**
55    * Metadata to use.
56    */
57   struct GNUNET_CONTAINER_MetaData *meta;
58
59   /**
60    * Global FS context.
61    */
62   struct GNUNET_FS_Handle *h;
63
64   /**
65    * UBlock publishing operation that is active.
66    */
67   struct GNUNET_FS_PublishUblockContext *uc;
68
69   /**
70    * Handle to the datastore, NULL if we are just simulating.
71    */
72   struct GNUNET_DATASTORE_Handle *dsh;
73
74   /**
75    * Current task.
76    */
77   struct GNUNET_SCHEDULER_Task * ksk_task;
78
79   /**
80    * Function to call once we're done.
81    */
82   GNUNET_FS_PublishContinuation cont;
83
84   /**
85    * Closure for cont.
86    */
87   void *cont_cls;
88
89   /**
90    * When should the KBlocks expire?
91    */
92   struct GNUNET_FS_BlockOptions bo;
93
94   /**
95    * Options to use.
96    */
97   enum GNUNET_FS_PublishOptions options;
98
99   /**
100    * Keyword that we are currently processing.
101    */
102   unsigned int i;
103
104 };
105
106
107 /**
108  * Continuation of "GNUNET_FS_publish_ksk" that performs
109  * the actual publishing operation (iterating over all
110  * of the keywords).
111  *
112  * @param cls closure of type "struct PublishKskContext*"
113  * @param tc unused
114  */
115 static void
116 publish_ksk_cont (void *cls,
117                   const struct GNUNET_SCHEDULER_TaskContext *tc);
118
119
120 /**
121  * Function called by the datastore API with
122  * the result from the PUT request.
123  *
124  * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
125  * @param msg error message (or NULL)
126  */
127 static void
128 kb_put_cont (void *cls,
129              const char *msg)
130 {
131   struct GNUNET_FS_PublishKskContext *pkc = cls;
132
133   pkc->uc = NULL;
134   if (NULL != msg)
135   {
136     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
137                 "KBlock PUT operation failed: %s\n", msg);
138     pkc->cont (pkc->cont_cls, NULL, msg);
139     GNUNET_FS_publish_ksk_cancel (pkc);
140     return;
141   }
142   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
143 }
144
145
146 /**
147  * Continuation of "GNUNET_FS_publish_ksk" that performs the actual
148  * publishing operation (iterating over all of the keywords).
149  *
150  * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
151  * @param tc unused
152  */
153 static void
154 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
155 {
156   struct GNUNET_FS_PublishKskContext *pkc = cls;
157   const char *keyword;
158
159   pkc->ksk_task = NULL;
160   if ( (pkc->i == pkc->ksk_uri->data.ksk.keywordCount) ||
161        (NULL == pkc->dsh) )
162   {
163     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n");
164     pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL);
165     GNUNET_FS_publish_ksk_cancel (pkc);
166     return;
167   }
168   keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
169   pkc->uc = GNUNET_FS_publish_ublock_ (pkc->h,
170                                        pkc->dsh,
171                                        keyword + 1 /* skip '+' */,
172                                        NULL,
173                                        GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
174                                        pkc->meta,
175                                        pkc->uri,
176                                        &pkc->bo,
177                                        pkc->options,
178                                        &kb_put_cont, pkc);
179 }
180
181
182 /**
183  * Publish a CHK under various keywords on GNUnet.
184  *
185  * @param h handle to the file sharing subsystem
186  * @param ksk_uri keywords to use
187  * @param meta metadata to use
188  * @param uri URI to refer to in the KBlock
189  * @param bo per-block options
190  * @param options publication options
191  * @param cont continuation
192  * @param cont_cls closure for cont
193  * @return NULL on error ('cont' will still be called)
194  */
195 struct GNUNET_FS_PublishKskContext *
196 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
197                        const struct GNUNET_FS_Uri *ksk_uri,
198                        const struct GNUNET_CONTAINER_MetaData *meta,
199                        const struct GNUNET_FS_Uri *uri,
200                        const struct GNUNET_FS_BlockOptions *bo,
201                        enum GNUNET_FS_PublishOptions options,
202                        GNUNET_FS_PublishContinuation cont, void *cont_cls)
203 {
204   struct GNUNET_FS_PublishKskContext *pkc;
205
206   GNUNET_assert (NULL != uri);
207   pkc = GNUNET_new (struct GNUNET_FS_PublishKskContext);
208   pkc->h = h;
209   pkc->bo = *bo;
210   pkc->options = options;
211   pkc->cont = cont;
212   pkc->cont_cls = cont_cls;
213   pkc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
214   if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
215   {
216     pkc->dsh = GNUNET_DATASTORE_connect (h->cfg);
217     if (NULL == pkc->dsh)
218     {
219       cont (cont_cls, NULL, _("Could not connect to datastore."));
220       GNUNET_free (pkc);
221       return NULL;
222     }
223   }
224   pkc->uri = GNUNET_FS_uri_dup (uri);
225   pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
226   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
227   return pkc;
228 }
229
230
231 /**
232  * Abort the KSK publishing operation.
233  *
234  * @param pkc context of the operation to abort.
235  */
236 void
237 GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc)
238 {
239   if (NULL != pkc->ksk_task)
240   {
241     GNUNET_SCHEDULER_cancel (pkc->ksk_task);
242     pkc->ksk_task = NULL;
243   }
244   if (NULL != pkc->uc)
245   {
246     GNUNET_FS_publish_ublock_cancel_ (pkc->uc);
247     pkc->uc = NULL;
248   }
249   if (NULL != pkc->dsh)
250   {
251     GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
252     pkc->dsh = NULL;
253   }
254   GNUNET_CONTAINER_meta_data_destroy (pkc->meta);
255   GNUNET_FS_uri_destroy (pkc->ksk_uri);
256   GNUNET_FS_uri_destroy (pkc->uri);
257   GNUNET_free (pkc);
258 }
259
260
261 /* end of fs_publish_ksk.c */