-fix time assertion introduce in last patch
[oweals/gnunet.git] / src / topology / friends.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 Christian Grothoff
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 topology/friends.c
23  * @brief library to read and write the FRIENDS file
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_friends_lib.h"
28
29
30 /**
31  * Parse the FRIENDS file.
32  *
33  * @param cfg our configuration
34  * @param cb function to call on each friend found
35  * @param cb_cls closure for @a cb
36  * @return #GNUNET_OK on success, #GNUNET_SYSERR on parsing errors
37  */
38 int
39 GNUNET_FRIENDS_parse (const struct GNUNET_CONFIGURATION_Handle *cfg,
40                       GNUNET_FRIENDS_Callback cb,
41                       void *cb_cls)
42 {
43   char *fn;
44   char *data;
45   size_t pos;
46   size_t start;
47   struct GNUNET_PeerIdentity pid;
48   uint64_t fsize;
49
50   if (GNUNET_OK !=
51       GNUNET_CONFIGURATION_get_value_filename (cfg,
52                                                "TOPOLOGY",
53                                                "FRIENDS",
54                                                &fn))
55   {
56     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
57                                "topology", "FRIENDS");
58     return GNUNET_SYSERR;
59   }
60   if ( (GNUNET_OK != GNUNET_DISK_file_test (fn)) &&
61        (GNUNET_OK != GNUNET_DISK_fn_write (fn, NULL, 0,
62                                            GNUNET_DISK_PERM_USER_READ |
63                                            GNUNET_DISK_PERM_USER_WRITE)) )
64       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
65   if ( (GNUNET_OK !=
66         GNUNET_DISK_file_size (fn,
67                                &fsize,
68                                GNUNET_NO, GNUNET_YES)) ||
69        (0 == fsize) )
70   {
71     GNUNET_free (fn);
72     return GNUNET_OK;
73   }
74   data = GNUNET_malloc_large (fsize);
75   if (NULL == data)
76   {
77     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc");
78     GNUNET_free (fn);
79     return GNUNET_SYSERR;
80   }
81   if (fsize != GNUNET_DISK_fn_read (fn, data, fsize))
82   {
83     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "read", "fn");
84     GNUNET_free (fn);
85     GNUNET_free (data);
86     return GNUNET_SYSERR;
87   }
88   start = 0;
89   pos = 0;
90   while (pos < fsize)
91   {
92     while ((pos < fsize) && (! isspace ((int) data[pos])))
93       pos++;
94     if (GNUNET_OK !=
95         GNUNET_CRYPTO_eddsa_public_key_from_string (&data[start],
96                                                        pos - start,
97                                                        &pid.public_key))
98     {
99       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
100                   _("Syntax error in FRIENDS file at offset %llu, skipping bytes `%.*s'.\n"),
101                   (unsigned long long) pos,
102                   (int) (pos - start),
103                   &data[start]);
104       pos++;
105       start = pos;
106       continue;
107     }
108     pos++;
109     start = pos;
110     cb (cb_cls, &pid);
111   }
112   GNUNET_free (data);
113   GNUNET_free (fn);
114   return GNUNET_OK;
115 }
116
117
118 /**
119  * Handle for writing a friends file.
120  */
121 struct GNUNET_FRIENDS_Writer
122 {
123   /**
124    * Handle to the file.
125    */
126   struct GNUNET_DISK_FileHandle *fh;
127 };
128
129
130 /**
131  * Start writing a fresh FRIENDS file.  Will make a backup of the
132  * old one.
133  *
134  * @param cfg configuration to use.
135  * @return NULL on error
136  */
137 struct GNUNET_FRIENDS_Writer *
138 GNUNET_FRIENDS_write_start (const struct GNUNET_CONFIGURATION_Handle *cfg)
139 {
140   struct GNUNET_FRIENDS_Writer *w;
141   char *fn;
142
143   if (GNUNET_OK !=
144       GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn))
145   {
146     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
147                                "topology", "FRIENDS");
148     return NULL;
149   }
150   if (GNUNET_OK !=
151       GNUNET_DISK_directory_create_for_file (fn))
152   {
153     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
154                 _("Directory for file `%s' does not seem to be writable.\n"),
155                 fn);
156     return NULL;
157   }
158   if (GNUNET_OK == GNUNET_DISK_file_test (fn))
159     GNUNET_DISK_file_backup (fn);
160   w = GNUNET_new (struct GNUNET_FRIENDS_Writer);
161   w->fh = GNUNET_DISK_file_open  (fn,
162                                   GNUNET_DISK_OPEN_CREATE |
163                                   GNUNET_DISK_OPEN_WRITE |
164                                   GNUNET_DISK_OPEN_FAILIFEXISTS,
165                                   GNUNET_DISK_PERM_USER_READ);
166   GNUNET_free (fn);
167   if (NULL == w->fh)
168   {
169     GNUNET_free (w);
170     return NULL;
171   }
172   return w;
173 }
174
175
176 /**
177  * Finish writing out the friends file.
178  *
179  * @param w write handle
180  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
181  */
182 int
183 GNUNET_FRIENDS_write_stop (struct GNUNET_FRIENDS_Writer *w)
184 {
185   int ret;
186
187   ret = GNUNET_DISK_file_close (w->fh);
188   GNUNET_free (w);
189   return ret;
190 }
191
192
193 /**
194  * Add a friend to the friends file.
195  *
196  * @param w write handle
197  * @param friend_id friend to add
198  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
199  */
200 int
201 GNUNET_FRIENDS_write (struct GNUNET_FRIENDS_Writer *w,
202                       const struct GNUNET_PeerIdentity *friend_id)
203 {
204   char *buf;
205   char *ret;
206   size_t slen;
207
208   ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&friend_id->public_key);
209   GNUNET_asprintf (&buf,
210                    "%s\n",
211                    ret);
212   GNUNET_free (ret);
213   slen = strlen (buf);
214   if (slen !=
215       GNUNET_DISK_file_write (w->fh,
216                               buf,
217                               slen))
218   {
219     GNUNET_free (buf);
220     return GNUNET_SYSERR;
221   }
222   GNUNET_free (buf);
223   return GNUNET_OK;
224 }
225
226
227 /* end of friends.c */