aboutsummaryrefslogtreecommitdiff
path: root/src/fuse/gnunet-fuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fuse/gnunet-fuse.c')
-rw-r--r--src/fuse/gnunet-fuse.c302
1 files changed, 236 insertions, 66 deletions
diff --git a/src/fuse/gnunet-fuse.c b/src/fuse/gnunet-fuse.c
index a0b43de..69c226c 100644
--- a/src/fuse/gnunet-fuse.c
+++ b/src/fuse/gnunet-fuse.c
@@ -25,6 +25,7 @@
25 * @author Mauricio Günther 25 * @author Mauricio Günther
26 */ 26 */
27#include "gnunet-fuse.h" 27#include "gnunet-fuse.h"
28#include "gfs_download.h"
28 29
29/** 30/**
30 * Anonymity level to use. 31 * Anonymity level to use.
@@ -57,35 +58,181 @@ static char *source;
57static char *directory; 58static char *directory;
58 59
59/** 60/**
60 * Global mapping of paths to GNUnet URIs (and file names) for 61 * Root of the file tree.
61 * the respective entries.
62 */ 62 */
63static struct GNUNET_CONTAINER_MultiHashMap *map; 63static struct GNUNET_FUSE_PathInfo *root;
64
64 65
65/** 66/**
66 * Mutex for synchronizing access to 'map'. 67 * Function used to process entries in a directory; adds the
68 * respective entry to the parent directory.
69 *
70 * @param cls closure with the 'struct GNUNET_FUSE_PathInfo' of the parent
71 * @param filename name of the file in the directory
72 * @param uri URI of the file
73 * @param metadata metadata for the file; metadata for
74 * the directory if everything else is NULL/zero
75 * @param length length of the available data for the file
76 * (of type size_t since data must certainly fit
77 * into memory; if files are larger than size_t
78 * permits, then they will certainly not be
79 * embedded with the directory itself).
80 * @param data data available for the file (length bytes)
67 */ 81 */
68static struct GNUNET_Mutex *map_mutex; 82static void
83process_directory_entry (void *cls,
84 const char *filename,
85 const struct GNUNET_FS_Uri *
86 uri,
87 const struct
88 GNUNET_CONTAINER_MetaData *
89 meta, size_t length,
90 const void *data)
91{
92 struct GNUNET_FUSE_PathInfo *parent = cls;
93 struct GNUNET_FUSE_PathInfo *pi;
94 int is_directory;
95
96 if (NULL == filename)
97 return; /* info about the directory itself */
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
99 "Adding file `%s' to directory `%s'\n",
100 filename,
101 parent->filename);
102 is_directory = GNUNET_FS_meta_data_test_for_directory (meta);
103 if (GNUNET_SYSERR == is_directory)
104 is_directory = GNUNET_NO; /* if in doubt, say no */
105 pi = GNUNET_FUSE_path_info_create (parent, filename, uri, is_directory);
106 GNUNET_FUSE_path_info_done (pi);
107}
108
109
110/**
111 * Load and parse a directory.
112 *
113 * @param pi path to the directory
114 * @param eno where to store 'errno' on errors
115 * @return GNUNET_OK on success
116 */
117int
118GNUNET_FUSE_load_directory (struct GNUNET_FUSE_PathInfo *pi,
119 int * eno)
120{
121 size_t size;
122 void *data;
123 struct GNUNET_DISK_MapHandle *mh;
124 struct GNUNET_DISK_FileHandle *fh;
125
126 /* Need to download directory; store to temporary file */
127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
128 "Downloading directory `%s'\n",
129 pi->filename);
130 pi->tmpfile = GNUNET_DISK_mktemp ("gnunet-fuse-tempfile");
131 if (GNUNET_OK != GNUNET_FUSE_download_file (pi,
132 0,
133 GNUNET_FS_uri_chk_get_file_size (pi->uri)))
134 {
135 UNLINK (pi->tmpfile);
136 GNUNET_free (pi->tmpfile);
137 pi->tmpfile = NULL;
138 *eno = EIO; /* low level IO error */
139 return GNUNET_SYSERR;
140 }
141
142 size = (size_t) GNUNET_FS_uri_chk_get_file_size (pi->uri);
143 fh = GNUNET_DISK_file_open (pi->tmpfile,
144 GNUNET_DISK_OPEN_READ,
145 GNUNET_DISK_PERM_NONE);
146 if (NULL == fh)
147 {
148 *eno = EIO;
149 return GNUNET_SYSERR;
150 }
151 data = GNUNET_DISK_file_map (fh,
152 &mh,
153 GNUNET_DISK_MAP_TYPE_READ,
154 size);
155 if (NULL == data)
156 {
157 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
158 return - ENOMEM;
159 }
160 *eno = 0;
161 if (GNUNET_OK !=
162 GNUNET_FS_directory_list_contents (size,
163 data, 0LL,
164 &process_directory_entry,
165 pi))
166 *eno = ENOTDIR;
167 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_unmap (mh));
168 GNUNET_DISK_file_close (fh);
169 if (0 != *eno)
170 return GNUNET_SYSERR;
171 return GNUNET_OK;
172}
69 173
70 174
71/** 175/**
72 * Obtain an existing path info entry from the global map. 176 * Obtain an existing path info entry from the global map.
73 * 177 *
74 * @param path path the entry represents 178 * @param path path the entry represents
179 * @param eno where to store 'errno' on errors
75 * @return NULL if no such path entry exists 180 * @return NULL if no such path entry exists
76 */ 181 */
77struct GNUNET_FUSE_PathInfo * 182struct GNUNET_FUSE_PathInfo *
78GNUNET_FUSE_path_info_get (const char *path) 183GNUNET_FUSE_path_info_get (const char *path,
184 int *eno)
79{ 185{
186 size_t slen = strlen (path) + 1;
187 char buf[slen];
80 struct GNUNET_FUSE_PathInfo *pi; 188 struct GNUNET_FUSE_PathInfo *pi;
81 GNUNET_HashCode path_hash; 189 struct GNUNET_FUSE_PathInfo *pos;
82 190 char *tok;
83 GNUNET_CRYPTO_hash (path, strlen (path), &path_hash); 191
84 GNUNET_mutex_lock (map_mutex); 192 memcpy (buf, path, slen);
85 pi = GNUNET_CONTAINER_multihashmap_get (map, &path_hash); 193 pi = root;
86 if (NULL != pi) 194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 ++pi->rc; 195 "Looking up path `%s'\n",
88 GNUNET_mutex_unlock (map_mutex); 196 path);
197 GNUNET_mutex_lock (pi->lock);
198 for (tok = strtok (buf, "/"); NULL != tok; tok = strtok (NULL, "/"))
199 {
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
201 "Searching for token `%s'\n",
202 tok);
203 if (NULL == pi->tmpfile)
204 {
205 if (GNUNET_OK != GNUNET_FUSE_load_directory (pi, eno))
206 {
207 GNUNET_mutex_unlock (pi->lock);
208 return NULL;
209 }
210 }
211
212 pos = pi->child_head;
213 while ( (NULL != pos) &&
214 (0 != strcmp (tok,
215 pos->filename)) )
216 pos = pos->next;
217 if (NULL == pos)
218 {
219 GNUNET_mutex_unlock (pi->lock);
220 *eno = ENOENT;
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222 "No file with name `%s' in directory `%s'\n",
223 tok,
224 pi->filename);
225 return NULL;
226 }
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228 "Descending into directory `%s'\n",
229 tok);
230 GNUNET_mutex_lock (pos->lock);
231 GNUNET_mutex_unlock (pi->lock);
232 pi = pos;
233 }
234 ++pi->rc;
235 GNUNET_mutex_unlock (pi->lock);
89 return pi; 236 return pi;
90} 237}
91 238
@@ -93,36 +240,37 @@ GNUNET_FUSE_path_info_get (const char *path)
93/** 240/**
94 * Create a new path info entry in the global map. 241 * Create a new path info entry in the global map.
95 * 242 *
96 * @param path path the entry represents 243 * @param parent parent directory (can be NULL)
244 * @param filename name of the file to create
97 * @param uri URI to use for the path 245 * @param uri URI to use for the path
246 * @param is_directory GNUNET_YES if this entry is for a directory
98 * @return existing path entry if one already exists, otherwise 247 * @return existing path entry if one already exists, otherwise
99 * new path entry with the desired URI 248 * new path entry with the desired URI; in both cases
249 * the reference counter has been incremented by 1
100 */ 250 */
101struct GNUNET_FUSE_PathInfo * 251struct GNUNET_FUSE_PathInfo *
102GNUNET_FUSE_path_info_create (const char *path, 252GNUNET_FUSE_path_info_create (struct GNUNET_FUSE_PathInfo *parent,
253 const char *filename,
103 const struct GNUNET_FS_Uri *uri, 254 const struct GNUNET_FS_Uri *uri,
104 int is_directory) 255 int is_directory)
105{ 256{
106 struct GNUNET_FUSE_PathInfo *pi; 257 struct GNUNET_FUSE_PathInfo *pi;
107 GNUNET_HashCode path_hash; 258 size_t len;
108 259
109 GNUNET_CRYPTO_hash (path, strlen (path), &path_hash); 260 if (NULL != parent)
110 GNUNET_mutex_lock (map_mutex);
111 pi = GNUNET_CONTAINER_multihashmap_get (map, &path_hash);
112 if (NULL != pi)
113 { 261 {
114 GNUNET_mutex_unlock (map_mutex); 262 GNUNET_mutex_lock (parent->lock);
115 return pi;
116 } 263 }
264
117 pi = GNUNET_malloc (sizeof (struct GNUNET_FUSE_PathInfo)); 265 pi = GNUNET_malloc (sizeof (struct GNUNET_FUSE_PathInfo));
118 pi->path = GNUNET_strdup (path); 266 pi->parent = parent;
267 pi->filename = GNUNET_strdup (filename);
268 len = strlen (pi->filename);
269 if ('/' == pi->filename[len - 1])
270 pi->filename[len - 1] = '\0';
119 pi->uri = GNUNET_FS_uri_dup (uri); 271 pi->uri = GNUNET_FS_uri_dup (uri);
120 pi->lock = GNUNET_mutex_create (GNUNET_YES); 272 pi->lock = GNUNET_mutex_create (GNUNET_YES);
121 pi->rc = 1; 273 pi->rc = 1;
122 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (map,
123 &path_hash,
124 pi,
125 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
126 pi->stbuf.st_mode = (S_IRUSR | S_IRGRP | S_IROTH); /* read-only */ 274 pi->stbuf.st_mode = (S_IRUSR | S_IRGRP | S_IROTH); /* read-only */
127 if (GNUNET_YES == is_directory) 275 if (GNUNET_YES == is_directory)
128 { 276 {
@@ -133,7 +281,14 @@ GNUNET_FUSE_path_info_create (const char *path,
133 pi->stbuf.st_mode |= S_IFREG; /* regular file */ 281 pi->stbuf.st_mode |= S_IFREG; /* regular file */
134 pi->stbuf.st_size = (off_t) GNUNET_FS_uri_chk_get_file_size (uri); 282 pi->stbuf.st_size = (off_t) GNUNET_FS_uri_chk_get_file_size (uri);
135 } 283 }
136 GNUNET_mutex_unlock (map_mutex); 284
285 if (NULL != parent)
286 {
287 GNUNET_CONTAINER_DLL_insert_tail (parent->child_head,
288 parent->child_tail,
289 pi);
290 GNUNET_mutex_unlock (parent->lock);
291 }
137 return pi; 292 return pi;
138} 293}
139 294
@@ -151,14 +306,14 @@ GNUNET_FUSE_path_info_done (struct GNUNET_FUSE_PathInfo *pi)
151 (void) GNUNET_FUSE_path_info_delete (pi); 306 (void) GNUNET_FUSE_path_info_delete (pi);
152 return; 307 return;
153 } 308 }
154 GNUNET_mutex_lock (map_mutex); 309 GNUNET_mutex_lock (pi->lock);
155 --pi->rc; 310 --pi->rc;
156 GNUNET_mutex_unlock (map_mutex); 311 GNUNET_mutex_unlock (pi->lock);
157} 312}
158 313
159 314
160/** 315/**
161 * Delete a path info entry from the global map (does not actually 316 * Delete a path info entry from the tree (does not actually
162 * remove anything from the file system). Also decrements the RC. 317 * remove anything from the file system). Also decrements the RC.
163 * 318 *
164 * @param pi entry to remove 319 * @param pi entry to remove
@@ -166,19 +321,32 @@ GNUNET_FUSE_path_info_done (struct GNUNET_FUSE_PathInfo *pi)
166 */ 321 */
167int 322int
168GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi) 323GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi)
169{ 324{
170 GNUNET_HashCode path_hash; 325 struct GNUNET_FUSE_PathInfo *parent = pi->parent;
171 int ret;
172 int rc; 326 int rc;
327 int ret;
173 328
174 GNUNET_CRYPTO_hash (pi->path, strlen (pi->path), &path_hash); 329 if (NULL != parent)
175 GNUNET_mutex_lock (map_mutex); 330 {
176 ret = GNUNET_CONTAINER_multihashmap_remove (map, &path_hash, pi); 331 ret = 0;
332 GNUNET_mutex_lock (parent->lock);
333 GNUNET_mutex_lock (pi->lock);
334 GNUNET_CONTAINER_DLL_remove (parent->child_head,
335 parent->child_tail,
336 pi);
337 pi->parent = NULL;
338 GNUNET_mutex_unlock (parent->lock);
339 }
340 else
341 {
342 ret = - ENOENT;
343 GNUNET_mutex_lock (pi->lock);
344 }
177 rc = --pi->rc; 345 rc = --pi->rc;
178 GNUNET_mutex_unlock (map_mutex);
179 if (0 != rc) 346 if (0 != rc)
180 { 347 {
181 pi->delete_later = GNUNET_YES; 348 pi->delete_later = GNUNET_YES;
349 GNUNET_mutex_unlock (pi->lock);
182 } 350 }
183 else 351 else
184 { 352 {
@@ -187,33 +355,30 @@ GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi)
187 GNUNET_break (0 == UNLINK (pi->tmpfile)); 355 GNUNET_break (0 == UNLINK (pi->tmpfile));
188 GNUNET_free (pi->tmpfile); 356 GNUNET_free (pi->tmpfile);
189 } 357 }
190 GNUNET_free (pi->path); 358 GNUNET_free (pi->filename);
191 GNUNET_FS_uri_destroy (pi->uri); 359 GNUNET_FS_uri_destroy (pi->uri);
360 GNUNET_mutex_unlock (pi->lock);
192 GNUNET_mutex_destroy (pi->lock); 361 GNUNET_mutex_destroy (pi->lock);
193 GNUNET_free (pi); 362 GNUNET_free (pi);
194 } 363 }
195 if (GNUNET_YES == ret) 364 return ret;
196 return 0;
197 return - ENOENT;
198} 365}
199 366
200 367
201/** 368/**
202 * Called on each entry in our global 'map' to clean it up. 369 * Called on each node in the path info tree to clean it up.
203 * 370 *
204 * @param cls closure, NULL 371 * @param pi path info to clean up
205 * @param key current key code
206 * @param value value in the hash map, a 'struct GNUNET_FUSE_PathInfo'
207 * @return GNUNET_YES (we should continue to iterate)
208 */ 372 */
209static int 373static void
210cleanup_path_info (void *cls, const GNUNET_HashCode * key, void *value) 374cleanup_path_info (struct GNUNET_FUSE_PathInfo *pi)
211{ 375{
212 struct GNUNET_FUSE_PathInfo *pi = value; 376 struct GNUNET_FUSE_PathInfo *pos;
213 377
378 while (NULL != (pos = pi->child_head))
379 cleanup_path_info (pos);
214 ++pi->rc; 380 ++pi->rc;
215 (void) GNUNET_FUSE_path_info_delete (pi); 381 (void) GNUNET_FUSE_path_info_delete (pi);
216 return GNUNET_YES;
217} 382}
218 383
219 384
@@ -249,8 +414,7 @@ run (void *cls,
249 int argc; 414 int argc;
250 struct GNUNET_FS_Uri *uri; 415 struct GNUNET_FS_Uri *uri;
251 char *emsg; 416 char *emsg;
252 const char *path = "/"; 417 int eno;
253 struct GNUNET_FUSE_PathInfo *pi;
254 418
255 cfg = c; 419 cfg = c;
256 ret = 0; 420 ret = 0;
@@ -279,20 +443,31 @@ run (void *cls,
279 (GNUNET_YES != GNUNET_FS_uri_test_loc (uri)) ) 443 (GNUNET_YES != GNUNET_FS_uri_test_loc (uri)) )
280 { 444 {
281 fprintf (stderr, 445 fprintf (stderr,
282 _("The given URI is not for a directory and can thus not be mounted\n"), 446 _("The given URI is not for a directory and can thus not be mounted\n"));
283 emsg);
284 ret = 4; 447 ret = 4;
448 GNUNET_FS_uri_destroy (uri);
285 return; 449 return;
286 } 450 }
287 451
288 map_mutex = GNUNET_mutex_create (GNUNET_NO); 452 root = GNUNET_FUSE_path_info_create (NULL, "/", uri, GNUNET_YES);
289 map = GNUNET_CONTAINER_multihashmap_create (1024); 453 if (GNUNET_OK !=
290 pi = GNUNET_FUSE_path_info_create (path, uri, GNUNET_YES); 454 GNUNET_FUSE_load_directory (root, &eno))
455 {
456 fprintf (stderr,
457 _("Failed to mount `%s': %s\n"),
458 source,
459 STRERROR (eno));
460 ret = 5;
461 cleanup_path_info (root);
462 GNUNET_FS_uri_destroy (uri);
463 return;
464 }
291 465
292 if (GNUNET_YES == single_threaded) 466 if (GNUNET_YES == single_threaded)
293 argc = 5; 467 argc = 5;
294 else 468 else
295 argc = 2; 469 argc = 2;
470
296 { 471 {
297 char *a[argc + 1]; 472 char *a[argc + 1];
298 a[0] = "gnunet-fuse"; 473 a[0] = "gnunet-fuse";
@@ -306,12 +481,7 @@ run (void *cls,
306 a[argc] = NULL; 481 a[argc] = NULL;
307 fuse_main (argc, a, &fops, NULL); 482 fuse_main (argc, a, &fops, NULL);
308 } 483 }
309 GNUNET_FUSE_path_info_done (pi); 484 cleanup_path_info (root);
310 GNUNET_CONTAINER_multihashmap_iterate (map, &cleanup_path_info, NULL);
311 GNUNET_CONTAINER_multihashmap_destroy (map);
312 map = NULL;
313 GNUNET_mutex_destroy (map_mutex);
314 map_mutex = NULL;
315 GNUNET_FS_uri_destroy (uri); 485 GNUNET_FS_uri_destroy (uri);
316} 486}
317 487